Compare commits
5464 Commits
xo-server/
...
xo-web-v5.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecd460a991 | ||
|
|
b4d7648ffe | ||
|
|
eb3dfb0f30 | ||
|
|
2b9ba69480 | ||
|
|
8f784162ea | ||
|
|
a2ab64b142 | ||
|
|
052817ccbf | ||
|
|
48b2297bc1 | ||
|
|
e76a0ad4bd | ||
|
|
baf6d30348 | ||
|
|
7d250dd90b | ||
|
|
efaabb02e8 | ||
|
|
0c3b98d451 | ||
|
|
28d1539ea6 | ||
|
|
8ad02d2d51 | ||
|
|
1947a066e0 | ||
|
|
d99e643634 | ||
|
|
65e1ac2ef9 | ||
|
|
64a768090f | ||
|
|
488eed046e | ||
|
|
dccddd78a6 | ||
|
|
3c247abcf9 | ||
|
|
db795e91fd | ||
|
|
f060f56c93 | ||
|
|
51be573f5e | ||
|
|
4257cbb618 | ||
|
|
e25d6b712d | ||
|
|
b499d60130 | ||
|
|
68e06303a4 | ||
|
|
60085798f2 | ||
|
|
c62cab39f1 | ||
|
|
30483ab2d9 | ||
|
|
c38c716616 | ||
|
|
ded1127d64 | ||
|
|
38d6130e89 | ||
|
|
ee47e40d1a | ||
|
|
80e66415d7 | ||
|
|
81e6372070 | ||
|
|
dbfbd42d29 | ||
|
|
e0d34b1747 | ||
|
|
9a8f9dd1d7 | ||
|
|
75521f8757 | ||
|
|
11d4cb2f04 | ||
|
|
d90cb09b56 | ||
|
|
a02d393457 | ||
|
|
01a5963947 | ||
|
|
7ef314d9f4 | ||
|
|
2ff25d1f61 | ||
|
|
ede12b6732 | ||
|
|
8a010f62fd | ||
|
|
51da4a7e70 | ||
|
|
fd2580f5da | ||
|
|
c5fdab7d47 | ||
|
|
ae094438b1 | ||
|
|
3e5af9e894 | ||
|
|
10093afb91 | ||
|
|
58032738b9 | ||
|
|
89cbbaeeea | ||
|
|
5ca08eb400 | ||
|
|
fad049d2ac | ||
|
|
87466cb5bd | ||
|
|
bb69ad8019 | ||
|
|
d5373b85c7 | ||
|
|
d71e699582 | ||
|
|
f464751752 | ||
|
|
d69f355206 | ||
|
|
769c32a1b1 | ||
|
|
44075d2ad5 | ||
|
|
2b4ae3f1c2 | ||
|
|
8689b48c55 | ||
|
|
443882f4be | ||
|
|
9c3adaedf0 | ||
|
|
4ba4d383f0 | ||
|
|
947febcdaa | ||
|
|
b0a152612e | ||
|
|
c9991655cf | ||
|
|
8971d218bb | ||
|
|
8b05486945 | ||
|
|
42cd5d8e58 | ||
|
|
31f420937e | ||
|
|
952d086c5e | ||
|
|
422a04795f | ||
|
|
28a8807cfb | ||
|
|
c6327a953b | ||
|
|
cc71f2e4a3 | ||
|
|
701086ec26 | ||
|
|
20acaebb68 | ||
|
|
22997cd903 | ||
|
|
7cb720b11f | ||
|
|
8bf35b2a63 | ||
|
|
8b72690c17 | ||
|
|
a0cc768af9 | ||
|
|
9fc73e03a2 | ||
|
|
edd57f7205 | ||
|
|
8b155b62dc | ||
|
|
bf5daa1a9b | ||
|
|
4f154e33bc | ||
|
|
395bcade67 | ||
|
|
985a038482 | ||
|
|
2da04c5bb1 | ||
|
|
1baf8cfaa6 | ||
|
|
956a9a7dde | ||
|
|
d7bb457fd0 | ||
|
|
563ff38c25 | ||
|
|
05caaa0814 | ||
|
|
1f283d285a | ||
|
|
adaa7ca413 | ||
|
|
247e797d2b | ||
|
|
9c7c030b00 | ||
|
|
867c9ea66c | ||
|
|
59985adc5d | ||
|
|
fd4504f0ee | ||
|
|
6c6aacc64e | ||
|
|
678adc0726 | ||
|
|
be3b684866 | ||
|
|
179aadafa4 | ||
|
|
f9dc129601 | ||
|
|
6beea2d208 | ||
|
|
57ef84ad3b | ||
|
|
9d9fdcff1e | ||
|
|
83e82e4789 | ||
|
|
4a12e0b6a0 | ||
|
|
642118959e | ||
|
|
600011be17 | ||
|
|
6765251332 | ||
|
|
afa5b046cb | ||
|
|
138d5627b5 | ||
|
|
682d9e88ec | ||
|
|
191c531bad | ||
|
|
f026e51c54 | ||
|
|
693afc52ff | ||
|
|
b22914e88a | ||
|
|
50b081608f | ||
|
|
214528a880 | ||
|
|
4f13b32f9a | ||
|
|
8ce8f5763c | ||
|
|
1e5b2f54c3 | ||
|
|
348bc16d6d | ||
|
|
ff2c69102d | ||
|
|
9479b7dc74 | ||
|
|
39f4e13915 | ||
|
|
5ea9f26ec4 | ||
|
|
c1d9cc7e2a | ||
|
|
6b80124a35 | ||
|
|
83a3754fe5 | ||
|
|
bf9b53c4d9 | ||
|
|
2b5f7dc8de | ||
|
|
4349911076 | ||
|
|
152f68624c | ||
|
|
3770194598 | ||
|
|
2b4a7c40e1 | ||
|
|
62a9158074 | ||
|
|
354fd88028 | ||
|
|
1b191c2bc9 | ||
|
|
f94212729a | ||
|
|
43e5398d99 | ||
|
|
920107e13f | ||
|
|
d52bed9618 | ||
|
|
5ecc31b977 | ||
|
|
ed3ecc6f4e | ||
|
|
add10ea556 | ||
|
|
d627fad299 | ||
|
|
6f8b31eaa2 | ||
|
|
8d47c83117 | ||
|
|
75ddf2681e | ||
|
|
4ad72b2ef0 | ||
|
|
a7334061ef | ||
|
|
c89c7dab60 | ||
|
|
0e0e4aae69 | ||
|
|
971c039086 | ||
|
|
5e8e1968e1 | ||
|
|
76a1c827d1 | ||
|
|
a4ab028ad6 | ||
|
|
d2fdf0586c | ||
|
|
0825806093 | ||
|
|
44b1bee080 | ||
|
|
d87f54d4a4 | ||
|
|
dc12896b19 | ||
|
|
23e992de85 | ||
|
|
6f6b047537 | ||
|
|
9fc6013934 | ||
|
|
8a02d557f4 | ||
|
|
1406f1f8e5 | ||
|
|
d5f6b65861 | ||
|
|
8d2bbe86d5 | ||
|
|
1a2f553094 | ||
|
|
4d69866532 | ||
|
|
bdddea2e29 | ||
|
|
be4ca0eede | ||
|
|
495c97b44b | ||
|
|
e817b3254e | ||
|
|
dd6987efe9 | ||
|
|
d7f8d12d88 | ||
|
|
504895a730 | ||
|
|
cde92836f3 | ||
|
|
9158e33546 | ||
|
|
c787988b06 | ||
|
|
316d71b34d | ||
|
|
1b344b7d9c | ||
|
|
3df01cd0cf | ||
|
|
d2331bb62f | ||
|
|
51504cc6a3 | ||
|
|
cd03ebe49d | ||
|
|
86c7ae3693 | ||
|
|
6e3b85e764 | ||
|
|
b3bc9a2edd | ||
|
|
90369acb63 | ||
|
|
94e84ce55f | ||
|
|
68cef1aa5d | ||
|
|
2f9ecb8fa8 | ||
|
|
6281374cf3 | ||
|
|
13580923ea | ||
|
|
898434b267 | ||
|
|
6f6e760a25 | ||
|
|
38fb549709 | ||
|
|
6e44c65a07 | ||
|
|
736b00b4e2 | ||
|
|
b5a139619a | ||
|
|
03028bca50 | ||
|
|
b835c5bd40 | ||
|
|
a65b1325fc | ||
|
|
cfcd302294 | ||
|
|
a601154fc7 | ||
|
|
c8669dc88f | ||
|
|
82240979c2 | ||
|
|
db5d495105 | ||
|
|
6e8dfe8833 | ||
|
|
242d9e20c4 | ||
|
|
d4e46a0696 | ||
|
|
d5deaf72f7 | ||
|
|
f9c942d526 | ||
|
|
e446eb0cd0 | ||
|
|
b63efe579a | ||
|
|
f3410f1491 | ||
|
|
b27ac11d56 | ||
|
|
a55d73614e | ||
|
|
25cd1957c7 | ||
|
|
abd97abc24 | ||
|
|
6ddfd909f0 | ||
|
|
e054eec555 | ||
|
|
e253657770 | ||
|
|
041c32a4a7 | ||
|
|
102e629e16 | ||
|
|
2d0e3b93cc | ||
|
|
668d572549 | ||
|
|
e023809c8c | ||
|
|
0bcabb9f0d | ||
|
|
594a9d5399 | ||
|
|
242a02836c | ||
|
|
b144382831 | ||
|
|
6936f223f3 | ||
|
|
eb8dfc86ca | ||
|
|
02c715e1cc | ||
|
|
7e64e1a11e | ||
|
|
54772fad33 | ||
|
|
8cb53b0c4e | ||
|
|
892139908b | ||
|
|
ba6393165d | ||
|
|
2174a9cec7 | ||
|
|
629f68ffd7 | ||
|
|
5fe03f2934 | ||
|
|
09e7f04794 | ||
|
|
feecd51770 | ||
|
|
b5a855b2ad | ||
|
|
0b6bb65c17 | ||
|
|
d3691313e6 | ||
|
|
79ea50c829 | ||
|
|
8532d563de | ||
|
|
2e945e8349 | ||
|
|
22e3037e85 | ||
|
|
9aed4f6fba | ||
|
|
a505ded8a1 | ||
|
|
bea7b90eb2 | ||
|
|
e1eb948c54 | ||
|
|
1b42523e2d | ||
|
|
ed7a40bc73 | ||
|
|
c8dc786008 | ||
|
|
a6869638f5 | ||
|
|
3ef08d3d5e | ||
|
|
ef17cb1c6c | ||
|
|
ecc086f15d | ||
|
|
be9eb8ce91 | ||
|
|
5b7a9fe969 | ||
|
|
97d54cab11 | ||
|
|
980a1cc205 | ||
|
|
9517686e22 | ||
|
|
4905a0310a | ||
|
|
d2f88d0a02 | ||
|
|
76000d2563 | ||
|
|
bc02d51882 | ||
|
|
aada9e4a33 | ||
|
|
cf47a80676 | ||
|
|
c190067181 | ||
|
|
4490a2508b | ||
|
|
938e7704e6 | ||
|
|
18ca6b935c | ||
|
|
b3769019e5 | ||
|
|
506a6b0cf4 | ||
|
|
a18df93c4f | ||
|
|
d93eda34c9 | ||
|
|
684269321b | ||
|
|
b84ad98fd0 | ||
|
|
abf526f91a | ||
|
|
c06020745e | ||
|
|
431b85c98f | ||
|
|
299fdc19d6 | ||
|
|
7531a25588 | ||
|
|
d8f89191e8 | ||
|
|
d9ad53d954 | ||
|
|
043fc5cdfc | ||
|
|
d7eeeca268 | ||
|
|
4c21175ca7 | ||
|
|
377efcd054 | ||
|
|
072401f600 | ||
|
|
1ce7d94261 | ||
|
|
8178de8a6b | ||
|
|
eb37c7d7d8 | ||
|
|
9465459ef9 | ||
|
|
bf3f9b4ac2 | ||
|
|
52a71cec91 | ||
|
|
4c91667d2c | ||
|
|
a3fe9aff94 | ||
|
|
ed45888d7f | ||
|
|
dbadc487ae | ||
|
|
a5b80655da | ||
|
|
99d4789049 | ||
|
|
2de4163553 | ||
|
|
0fc0be19b2 | ||
|
|
3c271ffffd | ||
|
|
155422bcb5 | ||
|
|
68b6dc5985 | ||
|
|
1aa793886b | ||
|
|
46cd2f10a5 | ||
|
|
337abe2a2b | ||
|
|
0441103f0c | ||
|
|
b5829e2484 | ||
|
|
2e1b32fadc | ||
|
|
0c8f3ea824 | ||
|
|
c23be2185a | ||
|
|
c43ea11017 | ||
|
|
bd18a9270e | ||
|
|
e24cba9684 | ||
|
|
084e96be0e | ||
|
|
5dfefe8d35 | ||
|
|
bf45cdd2b8 | ||
|
|
4a6ba998d4 | ||
|
|
7f953c62af | ||
|
|
c9412b02af | ||
|
|
536a9d6e50 | ||
|
|
4ee0944037 | ||
|
|
98f5db9fbd | ||
|
|
fd47403ec9 | ||
|
|
bbefa3a009 | ||
|
|
575fe300fa | ||
|
|
137b8e7f7f | ||
|
|
4749e452c4 | ||
|
|
0881b66ab6 | ||
|
|
4a8c5a980a | ||
|
|
233aca7911 | ||
|
|
50966dce5d | ||
|
|
0e6bcefee6 | ||
|
|
41ec831df0 | ||
|
|
0178ce0a91 | ||
|
|
142233453a | ||
|
|
b12a804fb3 | ||
|
|
3fe5efbfab | ||
|
|
f33ea6c47c | ||
|
|
f419ec5702 | ||
|
|
24b7dc1c30 | ||
|
|
4619e387ad | ||
|
|
d7d2425435 | ||
|
|
2c99a4db0f | ||
|
|
d71323a67d | ||
|
|
8dd5428ef6 | ||
|
|
88d9111196 | ||
|
|
8ec30ec76d | ||
|
|
eb46711e34 | ||
|
|
748b09d8fa | ||
|
|
17e9885586 | ||
|
|
826628b18f | ||
|
|
e6a32b53fc | ||
|
|
7ce9e8a959 | ||
|
|
a49c9d646c | ||
|
|
d7e2690430 | ||
|
|
71ab2dedb9 | ||
|
|
b817cb86d0 | ||
|
|
3e1b2119c4 | ||
|
|
bfa31be3b7 | ||
|
|
9e9027d4c6 | ||
|
|
584da2f56a | ||
|
|
a43dfc62c2 | ||
|
|
6a071942a5 | ||
|
|
ac8787e930 | ||
|
|
ab60bc46cf | ||
|
|
c84f61d388 | ||
|
|
11b1ff478e | ||
|
|
ea7c44b544 | ||
|
|
b67310ae75 | ||
|
|
56cf6fba2f | ||
|
|
020618554a | ||
|
|
38ec7ac34f | ||
|
|
ef9f75514f | ||
|
|
bd4644dd4f | ||
|
|
f419cd6ac8 | ||
|
|
e714303f96 | ||
|
|
a78151c93e | ||
|
|
285b1fb36e | ||
|
|
50581c539c | ||
|
|
16e8c87cc6 | ||
|
|
6eed3f2fc7 | ||
|
|
7c5000d588 | ||
|
|
93ffb77e81 | ||
|
|
ec0dd0b174 | ||
|
|
88f6d77047 | ||
|
|
3ff63927f3 | ||
|
|
a5f55c5f92 | ||
|
|
7412a6c01b | ||
|
|
d396593d99 | ||
|
|
62b64ad0b6 | ||
|
|
5983ea32fd | ||
|
|
6f33a79644 | ||
|
|
5716130e6f | ||
|
|
67f31407d7 | ||
|
|
37f0bffcaa | ||
|
|
0e6a460332 | ||
|
|
f05d2d0063 | ||
|
|
28172607c6 | ||
|
|
682deb4b56 | ||
|
|
64fac454b5 | ||
|
|
cdd9eed3d8 | ||
|
|
e9c60bc958 | ||
|
|
7a8c0831bd | ||
|
|
0ca1af8606 | ||
|
|
34ef2700f2 | ||
|
|
e81f88e676 | ||
|
|
e96a8af9ef | ||
|
|
d8393d8500 | ||
|
|
38742d0668 | ||
|
|
0c9f6e0923 | ||
|
|
56d6347209 | ||
|
|
44b74e6135 | ||
|
|
f31417a85b | ||
|
|
1c6967594c | ||
|
|
2db582339a | ||
|
|
7f6386dd8c | ||
|
|
92e33efc04 | ||
|
|
805409cb48 | ||
|
|
93400352ca | ||
|
|
585b943a52 | ||
|
|
a0bf1bca8b | ||
|
|
738e3a0fbe | ||
|
|
05f3171910 | ||
|
|
f0771e4fed | ||
|
|
a3cd3b3fb1 | ||
|
|
323577f1ca | ||
|
|
d22619adc7 | ||
|
|
59f8a58b21 | ||
|
|
4d1f647a89 | ||
|
|
86e5206b4d | ||
|
|
d9ab8e83dc | ||
|
|
d5e783e7e6 | ||
|
|
105ede5b1d | ||
|
|
bb8a25cc9d | ||
|
|
54c3d843be | ||
|
|
4a1407786c | ||
|
|
f20604d3ad | ||
|
|
6b17e80e28 | ||
|
|
f5e3aef86c | ||
|
|
37c8a7c2b2 | ||
|
|
1a788fae7e | ||
|
|
8efc083a70 | ||
|
|
f196a9ebc4 | ||
|
|
06704ce467 | ||
|
|
8524db2903 | ||
|
|
c996b61eae | ||
|
|
60df3bc633 | ||
|
|
025cb6c6ca | ||
|
|
5014b95206 | ||
|
|
a2464fa968 | ||
|
|
033153c8b9 | ||
|
|
1715dadf8f | ||
|
|
a74a857ffe | ||
|
|
f0fe369cfd | ||
|
|
457ba5f24c | ||
|
|
d41b04313a | ||
|
|
34be34e7b3 | ||
|
|
70d75d1c69 | ||
|
|
dbc9fdcfa6 | ||
|
|
76b20f0fb6 | ||
|
|
80ca2052c2 | ||
|
|
3e5d8be507 | ||
|
|
1b76ad4252 | ||
|
|
22772a5fac | ||
|
|
3bd7798eda | ||
|
|
a6c2622f6b | ||
|
|
454412d9d4 | ||
|
|
114e5e1fa0 | ||
|
|
c38d4e275b | ||
|
|
8cc9dea9aa | ||
|
|
1037083ed2 | ||
|
|
7f87a03830 | ||
|
|
d3dcf6d305 | ||
|
|
4815af35cf | ||
|
|
f5fc17c10e | ||
|
|
06ad1dcb02 | ||
|
|
cb4276a2ee | ||
|
|
cf5f9d4080 | ||
|
|
02439bd23d | ||
|
|
f5febef10f | ||
|
|
f89d8d22a0 | ||
|
|
a9eb1f3d27 | ||
|
|
757a1e2353 | ||
|
|
9a0544c4aa | ||
|
|
31c365313b | ||
|
|
b44017ca95 | ||
|
|
08d7c189eb | ||
|
|
289112af27 | ||
|
|
4d2dc4eece | ||
|
|
5e11e87a0c | ||
|
|
712101d8d6 | ||
|
|
828ba5d448 | ||
|
|
03a2ff8e8c | ||
|
|
84d7ba5758 | ||
|
|
75487203cf | ||
|
|
6ad751f079 | ||
|
|
78ddad839e | ||
|
|
812cecdcc4 | ||
|
|
4b49da7d8f | ||
|
|
fc8c37d66c | ||
|
|
0d618e6477 | ||
|
|
d7e2b12d3d | ||
|
|
2ae4ed3999 | ||
|
|
eaaf70e52e | ||
|
|
bb4ebcd198 | ||
|
|
083f3df29d | ||
|
|
429fa1553b | ||
|
|
15809333c1 | ||
|
|
815855964e | ||
|
|
5649a10c44 | ||
|
|
a8b7431a02 | ||
|
|
a5ec70f7fa | ||
|
|
75dfdd4854 | ||
|
|
3f29dd129f | ||
|
|
075f94d438 | ||
|
|
a2b06972d0 | ||
|
|
5bb27131a3 | ||
|
|
d06aacbe25 | ||
|
|
7b19341406 | ||
|
|
838ad58946 | ||
|
|
5488a2d60a | ||
|
|
851182a92e | ||
|
|
f263097008 | ||
|
|
21fee6122f | ||
|
|
68a94da44c | ||
|
|
ec4a7325da | ||
|
|
d9a5764dda | ||
|
|
9859afe8b7 | ||
|
|
efbd588c9e | ||
|
|
e535e064fa | ||
|
|
448068178b | ||
|
|
7308d9ca96 | ||
|
|
e642f54815 | ||
|
|
ebb6cb17ea | ||
|
|
08a0aa9f98 | ||
|
|
8a933c98e3 | ||
|
|
363b22bffe | ||
|
|
a4087530c5 | ||
|
|
d5fae68b98 | ||
|
|
79a85659aa | ||
|
|
9f7c01599e | ||
|
|
9a0090570c | ||
|
|
5ef22f9921 | ||
|
|
1239f80018 | ||
|
|
49d1d060d6 | ||
|
|
eca145e113 | ||
|
|
04b75fb3b3 | ||
|
|
582e220a02 | ||
|
|
2e87abefc4 | ||
|
|
2cfa31609e | ||
|
|
64101c8337 | ||
|
|
241fed25a2 | ||
|
|
5ea19ee56f | ||
|
|
209b34e451 | ||
|
|
2ee733399e | ||
|
|
73f228c719 | ||
|
|
ba79673715 | ||
|
|
86b0962063 | ||
|
|
e2a482a6ca | ||
|
|
8924444cc1 | ||
|
|
8e83b0ffd2 | ||
|
|
451384bcdc | ||
|
|
b733164c50 | ||
|
|
72d9d8ba86 | ||
|
|
7c7646c65c | ||
|
|
b1c087451e | ||
|
|
f0f72f3bdd | ||
|
|
0ab3267541 | ||
|
|
995e76d323 | ||
|
|
62a9f805c2 | ||
|
|
84ea95a641 | ||
|
|
5e50ed15bd | ||
|
|
b0bff55dac | ||
|
|
81cad34170 | ||
|
|
c38379e229 | ||
|
|
07945ef8a6 | ||
|
|
35d7fa4a85 | ||
|
|
316de42cd9 | ||
|
|
fbb6870310 | ||
|
|
81efe25fbc | ||
|
|
63d440677b | ||
|
|
2e0df47581 | ||
|
|
a84ced70a6 | ||
|
|
4a9498e25e | ||
|
|
1978e218f4 | ||
|
|
2ab912c4f4 | ||
|
|
ca329fa2ff | ||
|
|
bc2256fc86 | ||
|
|
db122ed8c5 | ||
|
|
28d7f106b2 | ||
|
|
d6e46adfde | ||
|
|
93109fe9b8 | ||
|
|
439992d96f | ||
|
|
f94fe0b325 | ||
|
|
cc543ae33a | ||
|
|
5df1e62d53 | ||
|
|
1dff6f81fc | ||
|
|
f0d85f4c4e | ||
|
|
1801f9cb06 | ||
|
|
4be018ad15 | ||
|
|
5dcf060975 | ||
|
|
59f6b1f0c8 | ||
|
|
ae38a85b19 | ||
|
|
324dbbcfc8 | ||
|
|
ecf2d95318 | ||
|
|
a1af272180 | ||
|
|
72f0793aeb | ||
|
|
9770b77df4 | ||
|
|
0f91de389a | ||
|
|
e150be6a3e | ||
|
|
d71b13f2a2 | ||
|
|
66c88b37a4 | ||
|
|
a7198d2e83 | ||
|
|
d3584b5820 | ||
|
|
e2e6267dd7 | ||
|
|
aa5baecdc3 | ||
|
|
601b2aa6bb | ||
|
|
d09ba38dbd | ||
|
|
b847c2b7b5 | ||
|
|
30e44cb533 | ||
|
|
d43b83081b | ||
|
|
699363c548 | ||
|
|
6ea3eb4ba6 | ||
|
|
4aa20b6f6a | ||
|
|
9c8ea27238 | ||
|
|
22c515b0e7 | ||
|
|
7f5a623b37 | ||
|
|
c7cf73ff05 | ||
|
|
4aab425cef | ||
|
|
0d9666639f | ||
|
|
6c26c09685 | ||
|
|
819f650b48 | ||
|
|
353eba6365 | ||
|
|
063302b91d | ||
|
|
562b51bc2f | ||
|
|
e33a6f9a05 | ||
|
|
b9db4e7704 | ||
|
|
3270d9c3a7 | ||
|
|
6d7399f96c | ||
|
|
886ef87bc5 | ||
|
|
1e5dc9efe7 | ||
|
|
72a53c0c09 | ||
|
|
28ec66bf3b | ||
|
|
9a5a0d7a2b | ||
|
|
a18d88a3f1 | ||
|
|
9199784a23 | ||
|
|
7e2bd52f25 | ||
|
|
e65dd15edc | ||
|
|
c7e447db6f | ||
|
|
f81615f8b6 | ||
|
|
12caceb02b | ||
|
|
30f71ab444 | ||
|
|
fe04481ca3 | ||
|
|
7766e8edcd | ||
|
|
31d417c9d3 | ||
|
|
5ed29197cf | ||
|
|
ff5f3e12d3 | ||
|
|
240180405c | ||
|
|
edca6495fc | ||
|
|
8a9b753b01 | ||
|
|
445fc696c9 | ||
|
|
781ffa5574 | ||
|
|
8fe3b1a368 | ||
|
|
492e2362be | ||
|
|
1acee209be | ||
|
|
e64dc51a17 | ||
|
|
7f4df49933 | ||
|
|
2bc77ee0cd | ||
|
|
b25adf7f57 | ||
|
|
6785c48709 | ||
|
|
808e674503 | ||
|
|
6b2650282d | ||
|
|
475be2ee30 | ||
|
|
12e1da4ef2 | ||
|
|
780d072bb7 | ||
|
|
69c48e2770 | ||
|
|
aa934ad725 | ||
|
|
8596ca607d | ||
|
|
643ea9e523 | ||
|
|
ce2a08373e | ||
|
|
d9e2229335 | ||
|
|
61454e2030 | ||
|
|
6f79e8145e | ||
|
|
f7e5a5cf92 | ||
|
|
3574c8de5c | ||
|
|
b09ab4d403 | ||
|
|
60c4673992 | ||
|
|
7c597539ff | ||
|
|
8b80c12aa4 | ||
|
|
9c802c7b0c | ||
|
|
00c0ba9863 | ||
|
|
ca11656844 | ||
|
|
9d27730a4a | ||
|
|
4ce0ca702c | ||
|
|
242e28ddb9 | ||
|
|
40d20b0f9c | ||
|
|
1997f4af51 | ||
|
|
347cd063a3 | ||
|
|
c0cf6b2551 | ||
|
|
eff3221f7d | ||
|
|
74a4519a33 | ||
|
|
20acf7cfb2 | ||
|
|
be57004257 | ||
|
|
99bc34b2da | ||
|
|
f65b5e3ddd | ||
|
|
dc10492b84 | ||
|
|
6f7c10537b | ||
|
|
7f503cfc21 | ||
|
|
9dbef0c20a | ||
|
|
923166b4e3 | ||
|
|
b420128e40 | ||
|
|
7776a6ce23 | ||
|
|
8db949734a | ||
|
|
bb5bdfb9b2 | ||
|
|
730ed8bc69 | ||
|
|
26f630d9d6 | ||
|
|
7481874ba2 | ||
|
|
9fac3ecd81 | ||
|
|
52a5ce95b6 | ||
|
|
8a84cc2627 | ||
|
|
61179ec67d | ||
|
|
59fc5955ba | ||
|
|
a348585e76 | ||
|
|
e853ba6244 | ||
|
|
fb40ae7264 | ||
|
|
f629047be2 | ||
|
|
278d8adf1b | ||
|
|
87087d55aa | ||
|
|
8d135bc1fc | ||
|
|
2c00f0ffab | ||
|
|
46e95fe7eb | ||
|
|
090c9ea4d7 | ||
|
|
5e1d627834 | ||
|
|
37b23bdc47 | ||
|
|
9e1f97811e | ||
|
|
647eb7299e | ||
|
|
027652e80a | ||
|
|
185d380c36 | ||
|
|
9008b5c4e7 | ||
|
|
f5ad59803e | ||
|
|
81d1d7ba13 | ||
|
|
3328e71805 | ||
|
|
665fc2b7f9 | ||
|
|
dfd17bc96c | ||
|
|
d7e3dbac26 | ||
|
|
905182bf2e | ||
|
|
a0146290ee | ||
|
|
173aa22432 | ||
|
|
9e5b871ebe | ||
|
|
8824ce55ec | ||
|
|
155edf5533 | ||
|
|
6d06e1f89d | ||
|
|
6d1e2c47d3 | ||
|
|
8b9b0346cb | ||
|
|
0d11817e3f | ||
|
|
a8cb209717 | ||
|
|
cf45ffddf1 | ||
|
|
2e0ea51c30 | ||
|
|
0f7f8c7330 | ||
|
|
808f72409f | ||
|
|
f8e2d29372 | ||
|
|
22dec27c65 | ||
|
|
89b3806a7a | ||
|
|
b6bedf9253 | ||
|
|
0d4983043b | ||
|
|
f9ff3fe168 | ||
|
|
4a25c5323f | ||
|
|
9b4e2d3bb8 | ||
|
|
3915efcf92 | ||
|
|
4591ff8522 | ||
|
|
e3491797f3 | ||
|
|
6eee167675 | ||
|
|
16b965b28a | ||
|
|
5125410efd | ||
|
|
abf73193fd | ||
|
|
1a4da2a8de | ||
|
|
991fbaec86 | ||
|
|
fb399278b3 | ||
|
|
b868092365 | ||
|
|
80fdc6849f | ||
|
|
25ffcb952b | ||
|
|
5ae1488864 | ||
|
|
fb3ff165db | ||
|
|
cdf59bb877 | ||
|
|
b6371dde23 | ||
|
|
083ac1e2d6 | ||
|
|
5a4b553a60 | ||
|
|
b1135ef566 | ||
|
|
1928d1e00f | ||
|
|
a369f7f387 | ||
|
|
33d9801dfe | ||
|
|
8c7a031cca | ||
|
|
9484d87e76 | ||
|
|
4b6822d6e5 | ||
|
|
7241a0529b | ||
|
|
66083b4e50 | ||
|
|
f631b3cc64 | ||
|
|
8f4a43de75 | ||
|
|
e2d4a41d9a | ||
|
|
bb58d9b4d6 | ||
|
|
93ebff1055 | ||
|
|
08aec1c09a | ||
|
|
8ca98a56fe | ||
|
|
705f53e3e5 | ||
|
|
adaf069d20 | ||
|
|
d7be7d8660 | ||
|
|
faddee86b6 | ||
|
|
c4fcc65d16 | ||
|
|
890631d33b | ||
|
|
8e8145bb48 | ||
|
|
d73d6719a5 | ||
|
|
3419bee198 | ||
|
|
4368fad393 | ||
|
|
ab93fdbf10 | ||
|
|
8fd7697a45 | ||
|
|
1121a60912 | ||
|
|
d2af0152d0 | ||
|
|
e7b4bd2fe4 | ||
|
|
fcd8bdd1b3 | ||
|
|
e6f140f575 | ||
|
|
37f825ab6d | ||
|
|
bfe4c45fcf | ||
|
|
f95370124b | ||
|
|
2564343816 | ||
|
|
03734eb761 | ||
|
|
92104f4ab7 | ||
|
|
408a2498d0 | ||
|
|
29d63a9fdd | ||
|
|
ca94b236a8 | ||
|
|
fa1ec30ba5 | ||
|
|
8d473001aa | ||
|
|
ceaf0bd745 | ||
|
|
a96849bc89 | ||
|
|
2b1423aebe | ||
|
|
373332141f | ||
|
|
ecf2cf15b5 | ||
|
|
4ee0831d93 | ||
|
|
7df2a88c13 | ||
|
|
3d52556c67 | ||
|
|
437b160a3f | ||
|
|
5c87b82e0c | ||
|
|
182b7ae84d | ||
|
|
e6e254bd86 | ||
|
|
3b4e7a0bfe | ||
|
|
a0887bb5b3 | ||
|
|
5c6a592aba | ||
|
|
7f2bc79d5f | ||
|
|
837a61acf3 | ||
|
|
5971eed72a | ||
|
|
c8c0b24420 | ||
|
|
0da5d4376d | ||
|
|
1b8224030b | ||
|
|
ed3ec3fa8b | ||
|
|
aa98ca49e5 | ||
|
|
44d35c2351 | ||
|
|
df8eb7a000 | ||
|
|
ac061c8750 | ||
|
|
656d3e55ac | ||
|
|
47f3788f55 | ||
|
|
840a236e61 | ||
|
|
50641287f8 | ||
|
|
0bc072aa65 | ||
|
|
9d7d665520 | ||
|
|
819ea94e7b | ||
|
|
40753568df | ||
|
|
b07b998304 | ||
|
|
8793aed561 | ||
|
|
377a50bc09 | ||
|
|
fe5a43fbdf | ||
|
|
7f44220220 | ||
|
|
0df1610ca9 | ||
|
|
24c8b9e02d | ||
|
|
01b311f2ba | ||
|
|
a2bb3182f4 | ||
|
|
c86e15a310 | ||
|
|
862e5a95e7 | ||
|
|
73e2c7e849 | ||
|
|
0b0937e233 | ||
|
|
6bf114859f | ||
|
|
db6d67eeb7 | ||
|
|
e820b13f9f | ||
|
|
63be8afd35 | ||
|
|
1166db7834 | ||
|
|
3662f4f256 | ||
|
|
a345d89aac | ||
|
|
e8f8ebb112 | ||
|
|
b03335eb94 | ||
|
|
31e3677111 | ||
|
|
9bc1a51def | ||
|
|
d215885dab | ||
|
|
1dad5b5c3a | ||
|
|
5cc5ee4e87 | ||
|
|
68a1c93fbb | ||
|
|
9c6302fa50 | ||
|
|
d60440e512 | ||
|
|
957b9319cb | ||
|
|
9a28b9d1f1 | ||
|
|
543d061251 | ||
|
|
acba90b293 | ||
|
|
8992e9988f | ||
|
|
3ce87b9cb3 | ||
|
|
cbe7b3046c | ||
|
|
62344cb814 | ||
|
|
72d45a5fd2 | ||
|
|
c4e4dd501d | ||
|
|
e8d2b32a14 | ||
|
|
f492909e42 | ||
|
|
3d96765b1f | ||
|
|
7ea17750a1 | ||
|
|
02d052c071 | ||
|
|
4c52fe11d3 | ||
|
|
663e1f1a4b | ||
|
|
079310c67e | ||
|
|
5cf7f1f886 | ||
|
|
c70d92cf09 | ||
|
|
4590bed56e | ||
|
|
7c00d118f3 | ||
|
|
9f64af859e | ||
|
|
007aa776cb | ||
|
|
66bc092edd | ||
|
|
140a88ee12 | ||
|
|
68e37fff79 | ||
|
|
6958e71efd | ||
|
|
d0618182d1 | ||
|
|
e8891e27dd | ||
|
|
adb80933ee | ||
|
|
23b942c7da | ||
|
|
7eef7d4636 | ||
|
|
f42758938d | ||
|
|
e19fd81536 | ||
|
|
73835ded96 | ||
|
|
1ec1a8bd94 | ||
|
|
f0b6d57ba8 | ||
|
|
72baa1a786 | ||
|
|
4d72569030 | ||
|
|
f9a3ad14d1 | ||
|
|
1b86f533f7 | ||
|
|
532a368606 | ||
|
|
6c4178e107 | ||
|
|
05a68030b6 | ||
|
|
46416fb026 | ||
|
|
c5f3228ba7 | ||
|
|
54ed37c95d | ||
|
|
fd79b47d9e | ||
|
|
be8333824b | ||
|
|
db3728f9e4 | ||
|
|
ca2d3f5b48 | ||
|
|
f3a992a55f | ||
|
|
b5d1e7c459 | ||
|
|
eecd89772f | ||
|
|
02d1fb436d | ||
|
|
1c97bf9019 | ||
|
|
bfc4bb1f4c | ||
|
|
ccdce32562 | ||
|
|
87fdcf14e5 | ||
|
|
a0570f41fb | ||
|
|
5fd42bf216 | ||
|
|
55daffc791 | ||
|
|
3e55d8d9df | ||
|
|
d9f4a196d0 | ||
|
|
768ef8a316 | ||
|
|
a478d02e5d | ||
|
|
b98a7de3ae | ||
|
|
375baf7fe5 | ||
|
|
815e74c93c | ||
|
|
547d6fbc93 | ||
|
|
b45a4b9e6c | ||
|
|
3436d0256a | ||
|
|
2627cfd426 | ||
|
|
34b18c00a1 | ||
|
|
2e31ff42ed | ||
|
|
9a3b8f2b10 | ||
|
|
079790bce6 | ||
|
|
d99c4c6d14 | ||
|
|
6839b4d8a4 | ||
|
|
4c47cc6ea8 | ||
|
|
de81649a98 | ||
|
|
d31eab673e | ||
|
|
31189be2c8 | ||
|
|
45dd2c6519 | ||
|
|
5176d2000e | ||
|
|
6f606761e4 | ||
|
|
cfabadffe4 | ||
|
|
e13af7f5f0 | ||
|
|
ca08613292 | ||
|
|
4ab63591a0 | ||
|
|
5b4f98b03b | ||
|
|
f396d61633 | ||
|
|
7523cb3489 | ||
|
|
505a9d7c70 | ||
|
|
9f8c0c8cdf | ||
|
|
198777ffab | ||
|
|
29c5ca1132 | ||
|
|
05d6f3d1ed | ||
|
|
536e82de3d | ||
|
|
c59be7c315 | ||
|
|
9581764cc8 | ||
|
|
b327bb5bd0 | ||
|
|
f03493a252 | ||
|
|
22f2a05c8a | ||
|
|
a703ecc7e1 | ||
|
|
c90a687179 | ||
|
|
e08689ff0e | ||
|
|
80ffd811c9 | ||
|
|
56b583fc99 | ||
|
|
37a4e108be | ||
|
|
9ca531541d | ||
|
|
e304c554d0 | ||
|
|
a7dfa7a381 | ||
|
|
090d48b636 | ||
|
|
55567bf666 | ||
|
|
5867d84eaa | ||
|
|
4d8f1ab169 | ||
|
|
6a2963be41 | ||
|
|
b10f7b35ee | ||
|
|
dc1bb8992f | ||
|
|
5eb7119821 | ||
|
|
3fa8fc19dc | ||
|
|
a3103587f5 | ||
|
|
1bb11b574f | ||
|
|
405efe6a31 | ||
|
|
341d98e00d | ||
|
|
7eee0f4341 | ||
|
|
0b71b7862a | ||
|
|
e2893a0eba | ||
|
|
0c39a4e193 | ||
|
|
066072b22d | ||
|
|
73663c3703 | ||
|
|
d548503590 | ||
|
|
3a02fc99a2 | ||
|
|
d8ae943d8a | ||
|
|
63dae9ed70 | ||
|
|
97f57f1f2b | ||
|
|
060ba6423e | ||
|
|
f31bbcdaab | ||
|
|
2a4bae54ab | ||
|
|
95df2f66a3 | ||
|
|
c0c63f49b1 | ||
|
|
4e1bef9537 | ||
|
|
8b78727d20 | ||
|
|
4cd7025be4 | ||
|
|
015ce2690d | ||
|
|
3e7f552a63 | ||
|
|
421ee7125b | ||
|
|
1a6166b63c | ||
|
|
3828e75b7d | ||
|
|
154da142c7 | ||
|
|
312cd60dd1 | ||
|
|
6bf522f72f | ||
|
|
128b169ae2 | ||
|
|
fdd33abe91 | ||
|
|
22882b1ff2 | ||
|
|
213898987d | ||
|
|
a844f8d459 | ||
|
|
8ee206174b | ||
|
|
1a08e24a5c | ||
|
|
086cd0e038 | ||
|
|
42d123318c | ||
|
|
89f160317c | ||
|
|
9ccd1a0362 | ||
|
|
d116d014bc | ||
|
|
7956cabcf4 | ||
|
|
36c61ad357 | ||
|
|
25d60360d5 | ||
|
|
1e5579e3ad | ||
|
|
77d43b2280 | ||
|
|
33e8929e8b | ||
|
|
b79fa9cb9f | ||
|
|
a2812a85bd | ||
|
|
e8ff46a8ba | ||
|
|
351c01d642 | ||
|
|
044c9bed4c | ||
|
|
e333b1d083 | ||
|
|
5ad49de642 | ||
|
|
b45bb5c144 | ||
|
|
9402596f69 | ||
|
|
096687ae2c | ||
|
|
81062638eb | ||
|
|
210b5de992 | ||
|
|
f742fdbf1b | ||
|
|
8c0028055a | ||
|
|
e7026c522d | ||
|
|
c21fc4beda | ||
|
|
edf6fe782e | ||
|
|
3cbb6c4a98 | ||
|
|
74f060b309 | ||
|
|
12de0ca463 | ||
|
|
72ed59b65b | ||
|
|
fe369bfa18 | ||
|
|
568a50acc5 | ||
|
|
fbcb756cef | ||
|
|
81eb4ba4f9 | ||
|
|
0cc14d2ab8 | ||
|
|
116661d958 | ||
|
|
0dd70c57cd | ||
|
|
df0aa1c46d | ||
|
|
9b93a47e45 | ||
|
|
06f6912fb9 | ||
|
|
6aedadc982 | ||
|
|
a8d10dab3c | ||
|
|
1ff6ff1d7a | ||
|
|
c708fd65d7 | ||
|
|
8afe4a85dc | ||
|
|
0c497900a2 | ||
|
|
c57fbdce63 | ||
|
|
0b92ceec90 | ||
|
|
bdc0278fd1 | ||
|
|
731bcc68ef | ||
|
|
7e5131c4d2 | ||
|
|
f0554fc77c | ||
|
|
c7814b1f04 | ||
|
|
d585b47360 | ||
|
|
4530d95f48 | ||
|
|
c3ac8d0587 | ||
|
|
c7e6e72ce8 | ||
|
|
f3a5e1e97c | ||
|
|
919aa5fc43 | ||
|
|
416c98ffd2 | ||
|
|
013d4b9411 | ||
|
|
8094447183 | ||
|
|
575375d3e0 | ||
|
|
4296ae02dc | ||
|
|
0e40af0515 | ||
|
|
5d3a0e7a41 | ||
|
|
8ae2aae37a | ||
|
|
0a8fed1950 | ||
|
|
6dc4b4dc1b | ||
|
|
83b3cf406a | ||
|
|
959b8863eb | ||
|
|
1643ced4e0 | ||
|
|
b2a1840da7 | ||
|
|
b9f20d1e80 | ||
|
|
0c77781be8 | ||
|
|
83245af1e2 | ||
|
|
7db806a461 | ||
|
|
b25f418411 | ||
|
|
985a4780f5 | ||
|
|
92b15fb1e2 | ||
|
|
92a1f2c6d5 | ||
|
|
7b5182111c | ||
|
|
82b1b81999 | ||
|
|
81b9348e50 | ||
|
|
f0a430f350 | ||
|
|
90f95b7270 | ||
|
|
15e6a93fac | ||
|
|
04e7d54620 | ||
|
|
729dbe16c0 | ||
|
|
974650bc56 | ||
|
|
0899a16333 | ||
|
|
8c9ed833c3 | ||
|
|
5e86e64e18 | ||
|
|
235c789c5e | ||
|
|
3f69a22229 | ||
|
|
ab48d06967 | ||
|
|
18ca950cd2 | ||
|
|
82489b36c8 | ||
|
|
a67b6130f8 | ||
|
|
01541a2577 | ||
|
|
8c70bc0a17 | ||
|
|
9d96074604 | ||
|
|
114a4028f4 | ||
|
|
eab007db6e | ||
|
|
b342a4ba17 | ||
|
|
889eae276e | ||
|
|
2b2a72252b | ||
|
|
13e4568d3b | ||
|
|
92c4dda801 | ||
|
|
3e59ba4563 | ||
|
|
99c95626df | ||
|
|
20a9fc2497 | ||
|
|
27e0621ad8 | ||
|
|
abecff222c | ||
|
|
3f0d91101a | ||
|
|
252be59ac3 | ||
|
|
1987a8c68a | ||
|
|
5088fd0e82 | ||
|
|
2de4d36a0f | ||
|
|
fcbf037619 | ||
|
|
a8e4ab433d | ||
|
|
6613ba02ab | ||
|
|
2af7fde83f | ||
|
|
19a0d4bc98 | ||
|
|
9ed49b1f27 | ||
|
|
fb32aeeeb6 | ||
|
|
76cb4037d4 | ||
|
|
d56df30a22 | ||
|
|
64908068d9 | ||
|
|
af1530db36 | ||
|
|
9d6560aece | ||
|
|
fe69d59aeb | ||
|
|
caba246e0b | ||
|
|
731e2dc4c4 | ||
|
|
815bdf3454 | ||
|
|
b36ef9fdb1 | ||
|
|
b65e737f84 | ||
|
|
bd274fdc3c | ||
|
|
fee3f7a716 | ||
|
|
ac19249c63 | ||
|
|
2abff1fec8 | ||
|
|
dd00d6581f | ||
|
|
f4fc7acf4d | ||
|
|
f1a6cfae0d | ||
|
|
e43e90ed3c | ||
|
|
0ee88fe0dc | ||
|
|
5b8cdf06b3 | ||
|
|
682315e672 | ||
|
|
07e7f2e14d | ||
|
|
366ab95a2f | ||
|
|
ca723068a1 | ||
|
|
e424a105b3 | ||
|
|
32d2f92413 | ||
|
|
898e2ff010 | ||
|
|
e33c7fd1c1 | ||
|
|
9b3668423e | ||
|
|
7227af9aac | ||
|
|
7c8194307e | ||
|
|
36c38063f2 | ||
|
|
9b5fac9e2b | ||
|
|
47991b7d1a | ||
|
|
dfa5e76870 | ||
|
|
c93dd12fae | ||
|
|
dbb1b1e582 | ||
|
|
76388ee160 | ||
|
|
a5ea24311a | ||
|
|
3c11f0acda | ||
|
|
5ec2eee69a | ||
|
|
31875a36fe | ||
|
|
c50598b78e | ||
|
|
2f0c81d9ad | ||
|
|
c22f89c6bb | ||
|
|
568a23cd35 | ||
|
|
4a5222fa3b | ||
|
|
4294dfd8fe | ||
|
|
eb7c4c131d | ||
|
|
f0664cd2c7 | ||
|
|
570eb7bc89 | ||
|
|
1ee91b4925 | ||
|
|
e7b739bb3b | ||
|
|
baf5f7491d | ||
|
|
a2afe2fa1a | ||
|
|
8496a9bebd | ||
|
|
69fee37f00 | ||
|
|
49be66ae69 | ||
|
|
a0efe6895c | ||
|
|
8ef07e917d | ||
|
|
d3995b7bab | ||
|
|
c353e71ce7 | ||
|
|
0d6b7d6f04 | ||
|
|
59d6a51635 | ||
|
|
b4693019f7 | ||
|
|
320d7a89ca | ||
|
|
a3570a1c9f | ||
|
|
1016f5f26f | ||
|
|
9284aee3fa | ||
|
|
32726efe88 | ||
|
|
87daf0271c | ||
|
|
70e73a5a65 | ||
|
|
c593c98e6d | ||
|
|
1642798aa6 | ||
|
|
a4b5b532f2 | ||
|
|
588c369615 | ||
|
|
9aa9d4452c | ||
|
|
d7fe25c4fc | ||
|
|
990c5e9f08 | ||
|
|
6357f23aeb | ||
|
|
01d9b3bd0e | ||
|
|
7e2f2f6102 | ||
|
|
51def6535f | ||
|
|
6b428f7587 | ||
|
|
14156b0911 | ||
|
|
e2ba1fa7f8 | ||
|
|
36b589c2db | ||
|
|
f829aa76d7 | ||
|
|
cdf1a5fe47 | ||
|
|
abf146707f | ||
|
|
a72051e96f | ||
|
|
797622ba66 | ||
|
|
39342cd662 | ||
|
|
051a3ac122 | ||
|
|
f842a321ba | ||
|
|
3cd2dd65d3 | ||
|
|
5ce7e0b108 | ||
|
|
71c2058cc8 | ||
|
|
f200d39d23 | ||
|
|
7932845ac5 | ||
|
|
94bda6ac9e | ||
|
|
7a65f80406 | ||
|
|
36ab58dad9 | ||
|
|
e9be9e3761 | ||
|
|
b54645c86c | ||
|
|
c24a4009c8 | ||
|
|
7b928c4d41 | ||
|
|
4d50eae3c9 | ||
|
|
c3a5e0592d | ||
|
|
207aef7cb3 | ||
|
|
fbbd9ae249 | ||
|
|
7aa591ffbd | ||
|
|
1fd91de50d | ||
|
|
ab77d8430c | ||
|
|
8492ceee09 | ||
|
|
1f710b9b78 | ||
|
|
c6f683b532 | ||
|
|
a2604f5156 | ||
|
|
5ae7f683d6 | ||
|
|
f953c89979 | ||
|
|
bb8aab02ea | ||
|
|
b87ad2df54 | ||
|
|
af0c03ff6a | ||
|
|
8859900537 | ||
|
|
c9e2f94daf | ||
|
|
130852ab85 | ||
|
|
65fa8f96b4 | ||
|
|
0a84e9e363 | ||
|
|
163c69454b | ||
|
|
49d3fde0f3 | ||
|
|
bb67e2254e | ||
|
|
52774c7d6d | ||
|
|
6d2abc4e74 | ||
|
|
01686b8e60 | ||
|
|
0317d6a862 | ||
|
|
2a316b1ffa | ||
|
|
4875450053 | ||
|
|
19184ca8a0 | ||
|
|
654c3d324b | ||
|
|
c5b4811f16 | ||
|
|
7a9dc4fd59 | ||
|
|
9b9f0e5607 | ||
|
|
590f6cb7b3 | ||
|
|
e79096626a | ||
|
|
332d074d32 | ||
|
|
b120146cdc | ||
|
|
7587458f99 | ||
|
|
e511ecd76e | ||
|
|
d1e69f5957 | ||
|
|
bcfbd5eba9 | ||
|
|
2c35ee11b3 | ||
|
|
bd0c747d98 | ||
|
|
9fa3db395b | ||
|
|
52a41ceb04 | ||
|
|
f5fb066975 | ||
|
|
cd6a0fa678 | ||
|
|
e735420dd8 | ||
|
|
bc2f17c840 | ||
|
|
8c459cac0f | ||
|
|
878d2d9260 | ||
|
|
e65d67266d | ||
|
|
0d1045821c | ||
|
|
45d526dda2 | ||
|
|
e52f998e78 | ||
|
|
42ed3b9355 | ||
|
|
563b4cb1ec | ||
|
|
45bad231cf | ||
|
|
d76bd2484b | ||
|
|
445b60bb63 | ||
|
|
3214e0e41e | ||
|
|
c61230e145 | ||
|
|
fac6a29226 | ||
|
|
7a8f414748 | ||
|
|
9f450d282e | ||
|
|
31787067e3 | ||
|
|
1a769b23e2 | ||
|
|
ae002abafc | ||
|
|
31a25d9c16 | ||
|
|
356295c361 | ||
|
|
d10681b6d1 | ||
|
|
0602410aa8 | ||
|
|
14bca4bbf7 | ||
|
|
ea55c10c4d | ||
|
|
75cde40b0e | ||
|
|
5434b4987f | ||
|
|
1112768adc | ||
|
|
86b599df89 | ||
|
|
88f7661172 | ||
|
|
29c96c0119 | ||
|
|
d8c6e54c68 | ||
|
|
df053eb016 | ||
|
|
d1715f7711 | ||
|
|
240282c72d | ||
|
|
9e8dd6ea21 | ||
|
|
32806a20c9 | ||
|
|
34dcfbbf49 | ||
|
|
91fec43866 | ||
|
|
aa2d196a79 | ||
|
|
54befb2814 | ||
|
|
74fba76b85 | ||
|
|
2b8996e965 | ||
|
|
a9aad547b2 | ||
|
|
4673af6fd8 | ||
|
|
33ae81ce05 | ||
|
|
180ca458ad | ||
|
|
075c43ce0e | ||
|
|
10fddc51bb | ||
|
|
b32b319198 | ||
|
|
2d14fde671 | ||
|
|
98cd2746ef | ||
|
|
aa881c60e7 | ||
|
|
ea18e4129c | ||
|
|
6980e2b959 | ||
|
|
7e7ec83c12 | ||
|
|
b12fd45df1 | ||
|
|
a8340c24c3 | ||
|
|
5b6966042d | ||
|
|
dc859da0cd | ||
|
|
151eb6cbd6 | ||
|
|
16db591bbf | ||
|
|
05a55e5eb2 | ||
|
|
f49f3fb2a6 | ||
|
|
3c9ef8d199 | ||
|
|
dcd84b2b8f | ||
|
|
4a89119f0a | ||
|
|
bc1c30a7bf | ||
|
|
33cffbf28b | ||
|
|
a18b68116c | ||
|
|
d5acf15bca | ||
|
|
84f970af68 | ||
|
|
969f636bb7 | ||
|
|
6939aee20a | ||
|
|
ab2a02a555 | ||
|
|
70038e0764 | ||
|
|
e730ef5e11 | ||
|
|
835ad5aaf1 | ||
|
|
ac645c8617 | ||
|
|
669c24ebd5 | ||
|
|
b801fdbab2 | ||
|
|
bf495953e2 | ||
|
|
45b165deec | ||
|
|
09169578e8 | ||
|
|
43b2366927 | ||
|
|
f015a69eec | ||
|
|
99568508dd | ||
|
|
e8515344dd | ||
|
|
edc873a570 | ||
|
|
1a03e96ab2 | ||
|
|
89e0bb4f0a | ||
|
|
7d0fd60908 | ||
|
|
6b20523df4 | ||
|
|
e9a612647e | ||
|
|
28404ef149 | ||
|
|
a5f8230def | ||
|
|
39171de5de | ||
|
|
5aa5a0acbc | ||
|
|
a4518e630a | ||
|
|
94975f5ea6 | ||
|
|
7e98838d96 | ||
|
|
16dde5c772 | ||
|
|
e8c9c196ff | ||
|
|
db314a238f | ||
|
|
2c85a6d4ab | ||
|
|
b683e14e80 | ||
|
|
ba45095fa8 | ||
|
|
b8e5ffa9f7 | ||
|
|
b4bff9e032 | ||
|
|
0c461bc4e2 | ||
|
|
a33b2a5294 | ||
|
|
298e1c4471 | ||
|
|
1c70cdc10b | ||
|
|
160e4bb530 | ||
|
|
e69ba8dd96 | ||
|
|
e55f4c3eb2 | ||
|
|
1a3272b980 | ||
|
|
7bed5e025a | ||
|
|
29d22c0598 | ||
|
|
a38c7c34ac | ||
|
|
8d690ce4ff | ||
|
|
2569568a03 | ||
|
|
2c6ff6b5b8 | ||
|
|
1257f01027 | ||
|
|
fad6830863 | ||
|
|
66262bb20b | ||
|
|
4abb0754c7 | ||
|
|
78c53bf3ad | ||
|
|
810d666d84 | ||
|
|
67699f0bb6 | ||
|
|
46274948c0 | ||
|
|
28e3a842ef | ||
|
|
6d90f1d45d | ||
|
|
09642c347d | ||
|
|
2d0e06f785 | ||
|
|
a5bc8497cf | ||
|
|
4bcb65c518 | ||
|
|
25361fa7eb | ||
|
|
889a265000 | ||
|
|
96635a98f5 | ||
|
|
3122f6dcd5 | ||
|
|
16aa2e8085 | ||
|
|
074d51a670 | ||
|
|
2122a79132 | ||
|
|
26dbc585ba | ||
|
|
4b3cfbd424 | ||
|
|
035191a2cc | ||
|
|
06a40180a1 | ||
|
|
aaf4c5dff7 | ||
|
|
0c83bc2b0e | ||
|
|
54ef65ced9 | ||
|
|
4fb6bef04c | ||
|
|
2d412fd8db | ||
|
|
443e2bec25 | ||
|
|
d5e1323d82 | ||
|
|
7f0b77cc89 | ||
|
|
0169cff66c | ||
|
|
0fd1424a41 | ||
|
|
7d5e7f5c73 | ||
|
|
15a8b97410 | ||
|
|
874162df87 | ||
|
|
0c8b9d8539 | ||
|
|
7c6579b264 | ||
|
|
6280d56f32 | ||
|
|
9f2a77872f | ||
|
|
b571c18e9a | ||
|
|
49863d6e4d | ||
|
|
e3473721f6 | ||
|
|
28799c62a9 | ||
|
|
224a79840d | ||
|
|
c21fef7c72 | ||
|
|
99ae3e0f7f | ||
|
|
02a4161ecb | ||
|
|
1a68c3947d | ||
|
|
48cc7bb647 | ||
|
|
4ac58b3f44 | ||
|
|
a9758e6997 | ||
|
|
bb546c6bb7 | ||
|
|
442d42d8dc | ||
|
|
9501ebacfc | ||
|
|
23f9fa46f8 | ||
|
|
1bd0f37fd4 | ||
|
|
ed74ded923 | ||
|
|
d877a6f1ad | ||
|
|
ef7a563d97 | ||
|
|
df33772eba | ||
|
|
97c1cc8ed9 | ||
|
|
b732410b74 | ||
|
|
a51f2b7fcf | ||
|
|
fe12bbb60d | ||
|
|
b7f34b9da6 | ||
|
|
f82a6efda1 | ||
|
|
f869c02395 | ||
|
|
43e0217008 | ||
|
|
f89538c6f7 | ||
|
|
1ee0085c22 | ||
|
|
8882df7939 | ||
|
|
185a554cd9 | ||
|
|
d56590c6e6 | ||
|
|
556ca71c3a | ||
|
|
42be2d5031 | ||
|
|
876e22b092 | ||
|
|
f9f9c16cb0 | ||
|
|
230e0dc2a5 | ||
|
|
f63f5d0ac6 | ||
|
|
44dbbeb2a3 | ||
|
|
a881090e65 | ||
|
|
f5b69fdfdc | ||
|
|
01dc0d8f1e | ||
|
|
8035886a3c | ||
|
|
3d9fce02a4 | ||
|
|
0ab5f4b13f | ||
|
|
a1bc98def8 | ||
|
|
dea401fc7c | ||
|
|
cca21fcd32 | ||
|
|
868cf6140b | ||
|
|
4b3473f480 | ||
|
|
7bc782cc62 | ||
|
|
ab6b1e2c32 | ||
|
|
e625a53e4a | ||
|
|
b31185d96d | ||
|
|
09d75e972f | ||
|
|
59d9b3c6b4 | ||
|
|
f7b6fcf684 | ||
|
|
df3ec9a629 | ||
|
|
6bc4bf308b | ||
|
|
2ddb84f457 | ||
|
|
f33568951b | ||
|
|
8d8c442be5 | ||
|
|
6b82cc7510 | ||
|
|
2764f4d455 | ||
|
|
f890b8ea7a | ||
|
|
1b80b3929c | ||
|
|
28fecc428f | ||
|
|
4f946293f6 | ||
|
|
36788cde2b | ||
|
|
1547c99e5a | ||
|
|
5c9606dad8 | ||
|
|
fdcb1dccf5 | ||
|
|
12812b8c23 | ||
|
|
0098497255 | ||
|
|
6562d2de7f | ||
|
|
1f0e88cdb0 | ||
|
|
197da91ef3 | ||
|
|
cbd59789e2 | ||
|
|
190ecf3d74 | ||
|
|
15b8f6bca2 | ||
|
|
5b406d731b | ||
|
|
4be9e67ac4 | ||
|
|
d047421685 | ||
|
|
f6f415a421 | ||
|
|
edfaaebac0 | ||
|
|
67df22a1bf | ||
|
|
7dc59a00f6 | ||
|
|
6214fe4c2e | ||
|
|
21610c3e0a | ||
|
|
87550b0189 | ||
|
|
b7c42d0a08 | ||
|
|
c15ad299ac | ||
|
|
48c56cd602 | ||
|
|
7957f621ef | ||
|
|
8851a661c0 | ||
|
|
2d327961da | ||
|
|
38ddbfdc9c | ||
|
|
3d2aae81da | ||
|
|
2227b9d061 | ||
|
|
12aab5fa8c | ||
|
|
7323e6e117 | ||
|
|
ac6d14113a | ||
|
|
398db72b44 | ||
|
|
32777e17c4 | ||
|
|
a3da3299fa | ||
|
|
3a41efbea8 | ||
|
|
e763db7102 | ||
|
|
6f36869609 | ||
|
|
2b504ce5ab | ||
|
|
4a12419162 | ||
|
|
bf91938aa6 | ||
|
|
bd70bd2b45 | ||
|
|
bb26c8e449 | ||
|
|
93c7a01e62 | ||
|
|
9c2359e8ee | ||
|
|
5b9000012e | ||
|
|
bf00b4e8e3 | ||
|
|
ee7787f4ae | ||
|
|
0b88e743c9 | ||
|
|
f07a947580 | ||
|
|
0b8a9eedbc | ||
|
|
8d24e596ac | ||
|
|
c2378a44cd | ||
|
|
023f7fdef1 | ||
|
|
5d7a64bc28 | ||
|
|
8661957a97 | ||
|
|
7a15d265b7 | ||
|
|
2736881975 | ||
|
|
44a85f4e0c | ||
|
|
52a6e42e7e | ||
|
|
3dbe058d4e | ||
|
|
620139efc1 | ||
|
|
71464ac2e3 | ||
|
|
4a65489d39 | ||
|
|
65d7eac590 | ||
|
|
02bbc01dc4 | ||
|
|
39a16f9a7f | ||
|
|
f3ea8d012f | ||
|
|
3066237c86 | ||
|
|
53f3c0bef1 | ||
|
|
823c91b457 | ||
|
|
3bd7e20411 | ||
|
|
24d4610b04 | ||
|
|
b16097767a | ||
|
|
2ff74ffd39 | ||
|
|
f0bb464136 | ||
|
|
4767830386 | ||
|
|
ce23d4f164 | ||
|
|
c1380d1256 | ||
|
|
ed9a848858 | ||
|
|
5e4e15fc12 | ||
|
|
0dea952a2a | ||
|
|
1b9aa63096 | ||
|
|
45b8fd0100 | ||
|
|
11bde53069 | ||
|
|
f115ee18c4 | ||
|
|
162a56232c | ||
|
|
a1818dd525 | ||
|
|
659e336f66 | ||
|
|
058f7ecd9f | ||
|
|
831d9cb49f | ||
|
|
a5d059b0b1 | ||
|
|
4c3b959869 | ||
|
|
d81a169a39 | ||
|
|
0d47332526 | ||
|
|
539d136936 | ||
|
|
4c28b5775d | ||
|
|
fe6f351f84 | ||
|
|
de6f0ef8eb | ||
|
|
5dbeccf92f | ||
|
|
56bba1d84b | ||
|
|
af05d362b4 | ||
|
|
268ccf9a36 | ||
|
|
e77d4fafaa | ||
|
|
b88b99e342 | ||
|
|
f862d0df5b | ||
|
|
dac954155c | ||
|
|
cf9deceb15 | ||
|
|
72aed98088 | ||
|
|
ec92eddde8 | ||
|
|
e30b5ab6c3 | ||
|
|
0a5d26b001 | ||
|
|
cd8a92c30b | ||
|
|
10030c4959 | ||
|
|
7e4b881041 | ||
|
|
27a6af414f | ||
|
|
ba6204f811 | ||
|
|
d17b1050ad | ||
|
|
b70bc86f71 | ||
|
|
42b08633e9 | ||
|
|
bc898e1afd | ||
|
|
48d5f34ae6 | ||
|
|
67b8b15cd8 | ||
|
|
09d80afa69 | ||
|
|
c0d95304f6 | ||
|
|
5a0d67a9f6 | ||
|
|
08305b4b93 | ||
|
|
04d5612946 | ||
|
|
3dcb6f1f61 | ||
|
|
4e7684e38b | ||
|
|
a692b7571f | ||
|
|
a098618efa | ||
|
|
71381e75f1 | ||
|
|
05b345db4a | ||
|
|
f85f6eab9e | ||
|
|
b6dc8b507d | ||
|
|
831308ee05 | ||
|
|
eb5bcb759f | ||
|
|
8286570811 | ||
|
|
10b511f0ed | ||
|
|
751e335bc0 | ||
|
|
cb107521f2 | ||
|
|
e56af57b74 | ||
|
|
a2a1cbab6e | ||
|
|
306a021a8d | ||
|
|
d8c414af2f | ||
|
|
ec4c76b2e0 | ||
|
|
e23b8a6891 | ||
|
|
34006bcbf6 | ||
|
|
ed9aeabf6a | ||
|
|
799fc5089f | ||
|
|
683d510aa6 | ||
|
|
ebd7e58f61 | ||
|
|
9a498b54ac | ||
|
|
2687f45e6e | ||
|
|
ffc155c341 | ||
|
|
42ea76eb2a | ||
|
|
f79a17fcec | ||
|
|
8fd377d1e2 | ||
|
|
fda06fbd29 | ||
|
|
cee4378e6d | ||
|
|
be503f1341 | ||
|
|
6f4509c260 | ||
|
|
ab6d342886 | ||
|
|
9954c08993 | ||
|
|
3ae80aeab3 | ||
|
|
2a3534f659 | ||
|
|
fc39de0d5a | ||
|
|
64e4b79d41 | ||
|
|
b2331084d1 | ||
|
|
ab3a594884 | ||
|
|
592adcf42e | ||
|
|
978c881ab7 | ||
|
|
53887da3da | ||
|
|
7c60d68f56 | ||
|
|
2ac1b991b1 | ||
|
|
8257714cdb | ||
|
|
1b8bacbf5a | ||
|
|
1d5b84389d | ||
|
|
f7dcf52977 | ||
|
|
e26dd5147a | ||
|
|
bb8f96c2e2 | ||
|
|
95d4cc9055 | ||
|
|
cb84a85f8b | ||
|
|
0a8aa2ecf5 | ||
|
|
5941321e84 | ||
|
|
8cf62280f4 | ||
|
|
4cea142b57 | ||
|
|
64d9245bc4 | ||
|
|
2d78c0c4c3 | ||
|
|
aa585e2d25 | ||
|
|
325ab17dcc | ||
|
|
443ea44bcd | ||
|
|
07958d8efa | ||
|
|
f19affe599 | ||
|
|
f7b7c27b6c | ||
|
|
c7af5b384c | ||
|
|
436a9dfc14 | ||
|
|
1d6d8ccb28 | ||
|
|
7d0862ecfd | ||
|
|
7de059919b | ||
|
|
99727447ef | ||
|
|
e02cb56ee0 | ||
|
|
dfd1fb86cb | ||
|
|
847a92433f | ||
|
|
53af4df47b | ||
|
|
09db7c999e | ||
|
|
1b4c958aba | ||
|
|
9368d5df01 | ||
|
|
f3b5026190 | ||
|
|
19dcd81639 | ||
|
|
d38c171151 | ||
|
|
af3049925f | ||
|
|
a79825d18c | ||
|
|
c4b456b470 | ||
|
|
ccdf28767a | ||
|
|
2561f7d793 | ||
|
|
57bd8c1a49 | ||
|
|
8387e4ae04 | ||
|
|
5c02935017 | ||
|
|
726ffb9b1b | ||
|
|
5dcc3f4076 | ||
|
|
4639d7872f | ||
|
|
71cb6af8c4 | ||
|
|
52060301bd | ||
|
|
dfa3e6d8e4 | ||
|
|
f38f3fe5c9 | ||
|
|
24bf031270 | ||
|
|
eeadd72e1f | ||
|
|
e4139bab04 | ||
|
|
7c7205849b | ||
|
|
03b2b13f14 | ||
|
|
8caf9f7fde | ||
|
|
5b8a5ac6b6 | ||
|
|
4429bed1cf | ||
|
|
b9beda3484 | ||
|
|
354c9bc927 | ||
|
|
a2d88f7fbf | ||
|
|
83cad000e7 | ||
|
|
1b78791aa9 | ||
|
|
2b05fbf6a0 | ||
|
|
7b677cddaf | ||
|
|
18a8fcaa70 | ||
|
|
dd1bc757d5 | ||
|
|
27ca0fdfcc | ||
|
|
578de05a40 | ||
|
|
cd3e1d6bd4 | ||
|
|
de160bb51b | ||
|
|
14417e14c0 | ||
|
|
f2d8b4e444 | ||
|
|
b7c41fee28 | ||
|
|
4f0678d6a2 | ||
|
|
880c624935 | ||
|
|
0fa0902262 | ||
|
|
a2ab3ccaee | ||
|
|
77a0d1c2ff | ||
|
|
7fdb022819 | ||
|
|
878a630b69 | ||
|
|
fbcfc69983 | ||
|
|
a1bd327524 | ||
|
|
e62829debd | ||
|
|
d9d669964f | ||
|
|
ced17b632a | ||
|
|
0aada62a5a | ||
|
|
2fece7a8fe | ||
|
|
6680373c76 | ||
|
|
68ae43fd72 | ||
|
|
6b6f452d06 | ||
|
|
7153ff17e8 | ||
|
|
0fde5a1b3d | ||
|
|
b17fbdd19b | ||
|
|
61ae522486 | ||
|
|
bd414ae9f2 | ||
|
|
7579db5876 | ||
|
|
994ce8dab2 | ||
|
|
e8a84dce7d | ||
|
|
fdca9eda90 | ||
|
|
e007009a00 | ||
|
|
1d5cc209dd | ||
|
|
09b18e1563 | ||
|
|
363db0edea | ||
|
|
e500240a35 | ||
|
|
6694977b87 | ||
|
|
b173dc1f28 | ||
|
|
aa91f5649f | ||
|
|
74efd563ab | ||
|
|
b0b389fb4d | ||
|
|
e2d9131a07 | ||
|
|
3b1c8216b9 | ||
|
|
7f259a43cf | ||
|
|
874a504df3 | ||
|
|
6a4c6318e3 | ||
|
|
09bf2b87dc | ||
|
|
9c5c9838ae | ||
|
|
3924033d9a | ||
|
|
d81e45e456 | ||
|
|
631a762b56 | ||
|
|
a9cf79942f | ||
|
|
bd31476933 | ||
|
|
9b9e4c2ffa | ||
|
|
ec93daac7e | ||
|
|
3431b2dfb1 | ||
|
|
4270abaf1c | ||
|
|
0bd288afbd | ||
|
|
b72d5d50a1 | ||
|
|
d51889c233 | ||
|
|
332b093ee9 | ||
|
|
8be332208f | ||
|
|
85d1188628 | ||
|
|
56896996c3 | ||
|
|
896374e069 | ||
|
|
ac36505fb2 | ||
|
|
d36df1a8ae | ||
|
|
edd939c069 | ||
|
|
f80225ba54 | ||
|
|
3ccd87b369 | ||
|
|
59d3dd9255 | ||
|
|
392f08059d | ||
|
|
0d5c9a2bba | ||
|
|
f27de8015b | ||
|
|
3b7bdee814 | ||
|
|
397ed9d581 | ||
|
|
a098880669 | ||
|
|
047d4cb650 | ||
|
|
736904c579 | ||
|
|
e883c668b5 | ||
|
|
14181aa8a7 | ||
|
|
0b1ba99afa | ||
|
|
88a6215939 | ||
|
|
d5ebd33038 | ||
|
|
b2ac214c0f | ||
|
|
3dee41a511 | ||
|
|
934818c07d | ||
|
|
4dc614a58e | ||
|
|
35ea095b75 | ||
|
|
ae1a4c73b3 | ||
|
|
b58dbe89be | ||
|
|
1b4551b622 | ||
|
|
72a8f819d3 | ||
|
|
df8e16379c | ||
|
|
7dbbc7e25c | ||
|
|
1eaae70adb | ||
|
|
d4a61782c4 | ||
|
|
0e39c6f895 | ||
|
|
fcc3ede485 | ||
|
|
f001e7e713 | ||
|
|
3fb8fae821 | ||
|
|
349f3185c5 | ||
|
|
02f75fb2e1 | ||
|
|
6cced719dc | ||
|
|
b457b8409f | ||
|
|
c61e5e1ac8 | ||
|
|
45ec0b9b01 | ||
|
|
9e60f9d9fd | ||
|
|
2451ac3ade | ||
|
|
45a94fe73d | ||
|
|
a95d40078f | ||
|
|
515798bd9f | ||
|
|
e1173e6565 | ||
|
|
46f6911ef8 | ||
|
|
7629bf5be2 | ||
|
|
20b28135a3 | ||
|
|
33d2b8bbeb | ||
|
|
7c2059af2b | ||
|
|
1e0f57bd1a | ||
|
|
9484f1dbe6 | ||
|
|
658766c9e4 | ||
|
|
fb17de7988 | ||
|
|
32f4d42e59 | ||
|
|
0031c2a9b7 | ||
|
|
509e99913a | ||
|
|
c639cfcfd9 | ||
|
|
b140a2ca3e | ||
|
|
9e47d9acf1 | ||
|
|
5a1247c021 | ||
|
|
a8b7972f3c | ||
|
|
836c2127f7 | ||
|
|
6cef200aed | ||
|
|
c9c80b1d62 | ||
|
|
04328bc2d1 | ||
|
|
d909d0eeeb | ||
|
|
aa448e7a41 | ||
|
|
220750f887 | ||
|
|
80f5e913ec | ||
|
|
57eca31a9c | ||
|
|
c645fc7ad1 | ||
|
|
78b524b2e8 | ||
|
|
1ff1b6931b | ||
|
|
808cc5d8d0 | ||
|
|
29ac883616 | ||
|
|
467a147603 | ||
|
|
7b49b6304c | ||
|
|
25991027b9 | ||
|
|
fce83dfa66 | ||
|
|
8603d5d468 | ||
|
|
bd17f85140 | ||
|
|
037dddb945 | ||
|
|
dd2151e611 | ||
|
|
a1e0cdadd6 | ||
|
|
8d36efa66c | ||
|
|
b9a12a6dcc | ||
|
|
08e4fe9990 | ||
|
|
2333fec181 | ||
|
|
05676a78e3 | ||
|
|
02aaae240c | ||
|
|
158924fe3c | ||
|
|
0341b926b9 | ||
|
|
69d1f93ea4 | ||
|
|
423fb56ae0 | ||
|
|
c5fc8d437f | ||
|
|
0811addf9c | ||
|
|
e6f8108dc0 | ||
|
|
4aa4a8c75d | ||
|
|
bbe0467d16 | ||
|
|
88ca69138b | ||
|
|
6a0d9c8805 | ||
|
|
1a57f9f134 | ||
|
|
109aedd3ae | ||
|
|
bd9f9344e5 | ||
|
|
5190873e99 | ||
|
|
c5fe7eb0dd | ||
|
|
fef1b14d69 | ||
|
|
472fc02533 | ||
|
|
ed29524cf3 | ||
|
|
69f35436c2 | ||
|
|
a0ca1cddb5 | ||
|
|
be4ffd8308 | ||
|
|
8e246f08ee | ||
|
|
73eda65300 | ||
|
|
be4df02844 | ||
|
|
7de461319f | ||
|
|
970fc16aab | ||
|
|
5db2c5804d | ||
|
|
6c2924a08a | ||
|
|
32511fe6a0 | ||
|
|
94d5b0f083 | ||
|
|
0e957b9566 | ||
|
|
ec93f21f0a | ||
|
|
bbc4f3beb4 | ||
|
|
c271a25a51 | ||
|
|
c986bf0c46 | ||
|
|
6f994b75e5 | ||
|
|
a227039260 | ||
|
|
ee38c07a3f | ||
|
|
9678ebd71e | ||
|
|
82ce0d3461 | ||
|
|
8315c79ef7 | ||
|
|
69cb6d30b5 | ||
|
|
f4beef514e | ||
|
|
f002677134 | ||
|
|
6270d2d3af | ||
|
|
83625e4ba7 | ||
|
|
d039112b5b | ||
|
|
d8481af288 | ||
|
|
ea902c1073 | ||
|
|
db62c18a39 | ||
|
|
d004e2f759 | ||
|
|
1f7e457c64 | ||
|
|
4eae9398d8 | ||
|
|
4766121570 | ||
|
|
3180641e33 | ||
|
|
9273002905 | ||
|
|
3fc9c5ec90 | ||
|
|
3266cea1d6 | ||
|
|
97839c06dc | ||
|
|
304f290e42 | ||
|
|
52a241f300 | ||
|
|
1c1ea0dcc4 | ||
|
|
d998b384e8 | ||
|
|
9184afa6de | ||
|
|
3e1b4d724f | ||
|
|
5b6f50b25b | ||
|
|
b757025359 | ||
|
|
02e1a32fae | ||
|
|
d1690bda81 | ||
|
|
52e97edbd5 | ||
|
|
def88db128 | ||
|
|
d04702e5d4 | ||
|
|
f6407771b5 | ||
|
|
f6a6e125b6 | ||
|
|
2303b8a89f | ||
|
|
93f286b6ac | ||
|
|
75e5f931eb | ||
|
|
b215e89572 | ||
|
|
07a7e8cf0a | ||
|
|
52000edd7d | ||
|
|
3e4c07c86f | ||
|
|
92ce69c603 | ||
|
|
a338e0a3f1 | ||
|
|
143e09b65f | ||
|
|
e5cc5abdc9 | ||
|
|
dfc96ebb99 | ||
|
|
9397d0121d | ||
|
|
d8a1f3c73a | ||
|
|
a07cb425a4 | ||
|
|
a89b33dfdf | ||
|
|
486d33448b | ||
|
|
2299d397cb | ||
|
|
0173c4709f | ||
|
|
42fdf8b61f | ||
|
|
0253723652 | ||
|
|
5ca51d3510 | ||
|
|
466dc0127d | ||
|
|
32f610485c | ||
|
|
429e1b54ee | ||
|
|
268c037487 | ||
|
|
c146f3105e | ||
|
|
81e0c04722 | ||
|
|
5d156695d2 | ||
|
|
f71438347c | ||
|
|
a3081d607f | ||
|
|
ca81f445b9 | ||
|
|
1c22ce6d76 | ||
|
|
a0d482ba88 | ||
|
|
0c050cc053 | ||
|
|
9645d624f2 | ||
|
|
f29cb94d9f | ||
|
|
e239206626 | ||
|
|
35d1065eaf | ||
|
|
8384d6f9d7 | ||
|
|
5b3282ba51 | ||
|
|
bd1043f034 | ||
|
|
c847dcec15 | ||
|
|
f66994f0b5 | ||
|
|
eba27f1823 | ||
|
|
ad1bbb2a00 | ||
|
|
42506ab37d | ||
|
|
6bae33826d | ||
|
|
914c2b89c5 | ||
|
|
e79926cf29 | ||
|
|
1f15d2c736 | ||
|
|
fadd27fd23 | ||
|
|
d5aeb8db55 | ||
|
|
d5dbdd9986 | ||
|
|
352c977dc7 | ||
|
|
bf008eba99 | ||
|
|
76b7777fff | ||
|
|
9292d990da | ||
|
|
87fe715823 | ||
|
|
25e32e0600 | ||
|
|
41c901a05c | ||
|
|
fdaba2faf4 | ||
|
|
0c73ad4f46 | ||
|
|
36c44bc3d4 | ||
|
|
d612598bd0 | ||
|
|
2d75b6086f | ||
|
|
3345674604 | ||
|
|
1eeaeeeca5 | ||
|
|
b0bea8b3ba | ||
|
|
0e3e5edd17 | ||
|
|
ec1287a2f4 | ||
|
|
9d2c857c59 | ||
|
|
077f4f201c | ||
|
|
9a2154a2ce | ||
|
|
f4c111c1c2 | ||
|
|
9483a06e8a | ||
|
|
df2a90dc1d | ||
|
|
246c190ccd | ||
|
|
4640817a14 | ||
|
|
9c7690d39b | ||
|
|
160805af05 | ||
|
|
39e85730f0 | ||
|
|
da692e1a92 | ||
|
|
23bc60f1ac | ||
|
|
ce0f759509 | ||
|
|
1793e5943a | ||
|
|
155f2fc36c | ||
|
|
201b5db155 | ||
|
|
c588ac6777 | ||
|
|
28c01fd4e1 | ||
|
|
0715e7a31f | ||
|
|
b497c38e34 | ||
|
|
8a08dce405 | ||
|
|
a620c348bf | ||
|
|
fe750b7270 | ||
|
|
4aa9d56dfc | ||
|
|
4b2ebf2a3a | ||
|
|
6290446ea5 | ||
|
|
42f5d06960 | ||
|
|
85e8006137 | ||
|
|
7c29d4c644 | ||
|
|
7378bc852d | ||
|
|
67ed137cfa | ||
|
|
02e08e54a2 | ||
|
|
6b2dd24334 | ||
|
|
131d5becad | ||
|
|
157e0a83b1 | ||
|
|
d0d3abce3e | ||
|
|
b965c41a45 | ||
|
|
42f824e034 | ||
|
|
2768d9d49d | ||
|
|
c9a86dcae3 | ||
|
|
e1d307ea2c | ||
|
|
98ece12ae8 | ||
|
|
4cf3db7c2a | ||
|
|
7c2f79d980 | ||
|
|
fe064f8b6a | ||
|
|
2bad2f6b80 | ||
|
|
2ba9c5193f | ||
|
|
331695c10a | ||
|
|
f299193f05 | ||
|
|
de8130abc2 | ||
|
|
1cbde7f2e1 | ||
|
|
d1c796d9a7 | ||
|
|
af43061353 | ||
|
|
1b2ca8e69e | ||
|
|
a9e6679b08 | ||
|
|
9408760122 | ||
|
|
c25e804d61 | ||
|
|
b18b2262eb | ||
|
|
570440dc7d | ||
|
|
aef660fb2f | ||
|
|
17671c7282 | ||
|
|
8216ab44b4 | ||
|
|
5902d43a94 | ||
|
|
a6eb04d3f9 | ||
|
|
a71780e860 | ||
|
|
c2d815ef66 | ||
|
|
bf4679aa9b | ||
|
|
4dd74bbb16 | ||
|
|
10530146ca | ||
|
|
75d49da3d4 | ||
|
|
af026b0c52 | ||
|
|
bcd4f70d0e | ||
|
|
54cc31d1a0 | ||
|
|
3f0553861a | ||
|
|
e1b3c51d2c | ||
|
|
58a0e3fad6 | ||
|
|
6bb235650a | ||
|
|
0bf0bc4c33 | ||
|
|
3085749e92 | ||
|
|
de3abbf6b8 | ||
|
|
925469689f | ||
|
|
631e58a585 | ||
|
|
63571d06bf | ||
|
|
1979758fab | ||
|
|
6ef5a23000 | ||
|
|
ae4aa23d27 | ||
|
|
710d1f13cd | ||
|
|
57a4d366d7 | ||
|
|
8060c66c08 | ||
|
|
d5a58fbec2 | ||
|
|
059256de3e | ||
|
|
2c52d4c867 | ||
|
|
d9bfde2e47 | ||
|
|
757acd8d92 | ||
|
|
3e92252e2e | ||
|
|
ce7aeb1a27 | ||
|
|
236d2ad39a | ||
|
|
63b37714b1 | ||
|
|
dc81fd0622 | ||
|
|
ccec2bf7ee | ||
|
|
c93b93331e | ||
|
|
1f194f1680 | ||
|
|
2251123c1d | ||
|
|
1bfe1c3370 | ||
|
|
0044eeb6d1 | ||
|
|
669302d46b | ||
|
|
fce2f44197 | ||
|
|
c3dc136de4 | ||
|
|
4cbc5c4e2f | ||
|
|
68820aaf59 | ||
|
|
64db1df248 | ||
|
|
9109d55019 | ||
|
|
412e13ccd5 | ||
|
|
0c7e0528b6 | ||
|
|
ccb22a2f40 | ||
|
|
cd65bc7683 | ||
|
|
2f3e463aca | ||
|
|
c548e08aea | ||
|
|
150e0171f0 | ||
|
|
4d4a2897a5 | ||
|
|
cd73c8f82f | ||
|
|
934e67d146 | ||
|
|
4c96e44b9b | ||
|
|
189900549a | ||
|
|
6d18420a5d | ||
|
|
ab3d307393 | ||
|
|
89b2156f61 | ||
|
|
bfcaca7bc0 | ||
|
|
2f95da1892 | ||
|
|
fcb0482193 | ||
|
|
6e0956f09f | ||
|
|
714ea7c236 | ||
|
|
cc30799f0d | ||
|
|
df71259a10 | ||
|
|
9a0ae5d4b9 | ||
|
|
1191f0ba93 | ||
|
|
6534ffea26 | ||
|
|
eea4648ada | ||
|
|
2883398c2a | ||
|
|
84f6e14b89 | ||
|
|
30fb9ed65a | ||
|
|
a809f2d1f2 | ||
|
|
f9173c41d1 | ||
|
|
6b5a19983d | ||
|
|
a2faedcacb | ||
|
|
cb56b3b9d0 | ||
|
|
a61b50548c | ||
|
|
2471f447b3 | ||
|
|
75ad588e0b | ||
|
|
413e944d7a | ||
|
|
3b952819d6 | ||
|
|
2445c10c1c | ||
|
|
7e26593d04 | ||
|
|
73595c683b | ||
|
|
570f56a4cc | ||
|
|
f9e940871e | ||
|
|
c2b724a54a | ||
|
|
f52db472ed | ||
|
|
324fe98a5b | ||
|
|
2fd9833580 | ||
|
|
0ab4827d6f | ||
|
|
f0bd7d7eee | ||
|
|
8cd1209602 | ||
|
|
e2781adc81 | ||
|
|
b91ac2fe89 | ||
|
|
683a7a1851 | ||
|
|
8b05aa7b59 | ||
|
|
883f839bfd | ||
|
|
90dc00ac6b | ||
|
|
9c1cecbb7d | ||
|
|
1fce11bfba | ||
|
|
fba3ebdf49 | ||
|
|
e9585e08a4 | ||
|
|
24a89985fb | ||
|
|
33026e8281 | ||
|
|
50d9b832a9 | ||
|
|
1df82c3380 | ||
|
|
0a8db4ebbf | ||
|
|
928b19aef4 | ||
|
|
a7ec98cef6 | ||
|
|
67326a1859 | ||
|
|
631a8a5edf | ||
|
|
7e5e463ef2 | ||
|
|
add65e41da | ||
|
|
351b4571cd | ||
|
|
793258a91f | ||
|
|
ed3e1933c3 | ||
|
|
2f63b26458 | ||
|
|
f1d14da3dd | ||
|
|
4a3d90bdf3 | ||
|
|
f8f24fbc37 | ||
|
|
8f6c53e111 | ||
|
|
c23f55b1d4 | ||
|
|
306d5d8fc7 | ||
|
|
88f94f5d6f | ||
|
|
5553d5fefa | ||
|
|
9328518bbc | ||
|
|
6564edcc32 | ||
|
|
75bb7d5a2d | ||
|
|
ceab4e37cd | ||
|
|
afb6974cc0 | ||
|
|
3e99a179b7 | ||
|
|
c7271f94a5 | ||
|
|
5c0ced942c | ||
|
|
d9b07e76f9 | ||
|
|
c75793df20 | ||
|
|
1bee5121f0 | ||
|
|
932e7eb374 | ||
|
|
abdbcfe42b | ||
|
|
a62e888732 | ||
|
|
16b982b953 | ||
|
|
e92b87095b | ||
|
|
e5f1aa689b | ||
|
|
f39a05cd8d | ||
|
|
c5e22b785a | ||
|
|
11f93a125c | ||
|
|
38a9cb002d | ||
|
|
cf1a38a004 | ||
|
|
d6e823d19d | ||
|
|
a4dc965c23 | ||
|
|
8b65c280a8 | ||
|
|
763a23d9d0 | ||
|
|
f266577f2f | ||
|
|
1bb5e73668 | ||
|
|
b07bc755f6 | ||
|
|
db4b39c54b | ||
|
|
ffd95261c3 | ||
|
|
82f38040c1 | ||
|
|
7bb4f9f8e3 | ||
|
|
c2345df275 | ||
|
|
b0c341da3f | ||
|
|
b1ccc16da7 | ||
|
|
16856a5911 | ||
|
|
d4ee364349 | ||
|
|
db62ca7b4b | ||
|
|
d0b99b854d | ||
|
|
b3b13b3e01 | ||
|
|
5cb738b82b | ||
|
|
cfe3b15cbe | ||
|
|
a1bde80925 | ||
|
|
4c958dd584 | ||
|
|
a05d4d3d18 | ||
|
|
503b6dc914 | ||
|
|
141cbcd1c0 | ||
|
|
c46c0018ea | ||
|
|
e340d2d3f5 | ||
|
|
436d5a3a66 | ||
|
|
3e04fd4790 | ||
|
|
3f6d149f9d | ||
|
|
4ab24d2fe5 | ||
|
|
c70ca2ff64 | ||
|
|
649ab26da8 | ||
|
|
c921ea6eb7 | ||
|
|
58aed76aa3 | ||
|
|
e286c57ce4 | ||
|
|
977fc7832a | ||
|
|
840f0b6379 | ||
|
|
538025edd5 | ||
|
|
2e2f0e2e3d | ||
|
|
5628beee72 | ||
|
|
a88fea560b | ||
|
|
5832345b96 | ||
|
|
d3d2daa12f | ||
|
|
f6f90982f4 | ||
|
|
98323b08f0 | ||
|
|
8f3112a5e2 | ||
|
|
3408bd41ad | ||
|
|
68e12e86c1 | ||
|
|
890e0b4906 | ||
|
|
3aca7c7ae5 | ||
|
|
e8077ddbc5 | ||
|
|
6e04907357 | ||
|
|
35e8dcc3be | ||
|
|
d1600fd058 | ||
|
|
3d8c9a99fe | ||
|
|
1416fb0c71 | ||
|
|
2975db247d | ||
|
|
730768705b | ||
|
|
13f75a37ab | ||
|
|
f74c69ea6f | ||
|
|
fe7be0f518 | ||
|
|
2f0e656c45 | ||
|
|
de489b799b | ||
|
|
6250ef49b6 | ||
|
|
afdab8dcde | ||
|
|
8e1d39f37f | ||
|
|
2a8c346a65 | ||
|
|
03eaa652ce | ||
|
|
71e431e744 | ||
|
|
265cb75d70 | ||
|
|
4d0470838a | ||
|
|
d4ed3aeac0 | ||
|
|
89fa89fe98 | ||
|
|
2d663f0ac5 | ||
|
|
bc9b3f1c5c | ||
|
|
2f0a46a46d | ||
|
|
9559604d1e | ||
|
|
b779ab9bc5 | ||
|
|
481943051c | ||
|
|
cb49b7a906 | ||
|
|
090e4b3117 | ||
|
|
9a40d5f784 | ||
|
|
1485637c6d | ||
|
|
b0ec8e26e8 | ||
|
|
e4c12e08cb | ||
|
|
a1675745b5 | ||
|
|
40beb5b104 | ||
|
|
e49e2f51c2 | ||
|
|
99669f2678 | ||
|
|
9aa88b9dad | ||
|
|
10de29795a | ||
|
|
c4767e74f4 | ||
|
|
19f8666e1e | ||
|
|
2e2bbdf0d7 | ||
|
|
973bee0ffa | ||
|
|
9470cdf774 | ||
|
|
ab198ea60b | ||
|
|
c78f4bb6d2 | ||
|
|
ff054ca47f | ||
|
|
30cc804022 | ||
|
|
890d733bf8 | ||
|
|
a554a9c4a1 | ||
|
|
9ef212937d | ||
|
|
82d9c53f3e | ||
|
|
d9d91c4953 | ||
|
|
1e7d1b1628 | ||
|
|
defd42f74e | ||
|
|
dd5f5282e0 | ||
|
|
cc116defc6 | ||
|
|
90c755e120 | ||
|
|
85d1c80581 | ||
|
|
5bb04d3857 | ||
|
|
dde8404242 | ||
|
|
7940bd2dcc | ||
|
|
da48d117a0 | ||
|
|
ffc74967fc | ||
|
|
c7388d5836 | ||
|
|
aa54ab6e51 | ||
|
|
f0c28c74d8 | ||
|
|
ee4b8fc66f | ||
|
|
c73f22ca45 | ||
|
|
3e285d6131 | ||
|
|
bafa053fd1 | ||
|
|
a00406d2b3 | ||
|
|
df91e17dc6 | ||
|
|
7c6eeababc | ||
|
|
911a5067f9 | ||
|
|
bfa0fe9c51 | ||
|
|
7dafe31d51 | ||
|
|
1271ecedb4 | ||
|
|
80be18068f | ||
|
|
ecbf2c0958 | ||
|
|
cfb84b677f | ||
|
|
dfbd7a5d76 | ||
|
|
8e157f8ff7 | ||
|
|
c75580e852 | ||
|
|
e21934fd55 | ||
|
|
844f1609c8 | ||
|
|
6f7de28672 | ||
|
|
247212d768 | ||
|
|
6592b880ea | ||
|
|
e27a4bf119 | ||
|
|
dce5a83093 | ||
|
|
78c70f35a1 | ||
|
|
f4b84a0902 | ||
|
|
b16237b514 | ||
|
|
b0077539fa | ||
|
|
63602216eb | ||
|
|
2f93935009 | ||
|
|
c0a0b653c1 | ||
|
|
24d6354467 | ||
|
|
54a07469fd | ||
|
|
12f37bead1 | ||
|
|
8d76dc2511 | ||
|
|
8ef7d6defc | ||
|
|
2f2cbbe3f0 | ||
|
|
2662ac719b | ||
|
|
1b0fe6e847 | ||
|
|
9fa9e26324 | ||
|
|
cb434df099 | ||
|
|
e3cb3002fe | ||
|
|
8b2a09b522 | ||
|
|
03265d2545 | ||
|
|
9b25e07b5e | ||
|
|
60a21ca58d | ||
|
|
05172492ef | ||
|
|
a9c089a994 | ||
|
|
988d018c8e | ||
|
|
853c611fde | ||
|
|
0886f5335f | ||
|
|
024d481a4d | ||
|
|
b80de1af95 | ||
|
|
da44268f0d | ||
|
|
b921a3ed8e | ||
|
|
d2c9c824f9 | ||
|
|
21c255051c | ||
|
|
dccf09c5dd | ||
|
|
0772a17e4c | ||
|
|
644ee782d2 | ||
|
|
ea180cc415 | ||
|
|
68e3c4e6ed | ||
|
|
47b1c2d680 | ||
|
|
2e513043b7 | ||
|
|
ea942635f7 | ||
|
|
8a5f5cc673 | ||
|
|
6cc673035d | ||
|
|
02d717e5a8 | ||
|
|
77d83b06bd | ||
|
|
e3d8eabb05 | ||
|
|
0596b0106f | ||
|
|
765bbd90fc | ||
|
|
3799902a8a | ||
|
|
ca1dbb4556 | ||
|
|
df551d457c | ||
|
|
278d518d8f | ||
|
|
b06fa191f7 | ||
|
|
13d73f6f27 | ||
|
|
d59af117c0 | ||
|
|
69efd85ad6 | ||
|
|
ead51787a8 | ||
|
|
4bf0fee20d | ||
|
|
209693ee3f | ||
|
|
796d4f5b08 | ||
|
|
c96d94329e | ||
|
|
96914c9901 | ||
|
|
9e6073bf56 | ||
|
|
f8ad58159c | ||
|
|
ede4a02315 | ||
|
|
e25faba990 | ||
|
|
4ccf272e53 | ||
|
|
5ad0951db3 | ||
|
|
f72fcb76e3 | ||
|
|
8ca00c81b2 | ||
|
|
5c7f87b8ae | ||
|
|
9f4f7ec88c | ||
|
|
ba7676f778 | ||
|
|
ac248c32bb | ||
|
|
dd6a3e8535 | ||
|
|
69b538cfd6 | ||
|
|
e248c22f4b | ||
|
|
eff3c43483 | ||
|
|
1cbfc3ccd4 | ||
|
|
2fa72838f9 | ||
|
|
a559ec1fda | ||
|
|
8ddbc8b1fb | ||
|
|
c650a43d38 | ||
|
|
ab4cc20c8c | ||
|
|
30d613ff04 | ||
|
|
b93da5a281 | ||
|
|
9e2cf67a93 | ||
|
|
e87720ffdd | ||
|
|
5108ed7da5 | ||
|
|
77936d86f2 | ||
|
|
cbe8927d73 | ||
|
|
47a7e98da8 | ||
|
|
d4f27cd2e0 | ||
|
|
c355ad7a86 | ||
|
|
c8c9ec081d | ||
|
|
1289e46401 | ||
|
|
0b54292130 | ||
|
|
d1e2b91116 | ||
|
|
cd96b3e8f6 | ||
|
|
9119f4d06f | ||
|
|
4e6ccf2c81 | ||
|
|
6294e43762 | ||
|
|
feca78e55d | ||
|
|
0c86526ad2 | ||
|
|
9fd1d26067 | ||
|
|
5ec02078d1 | ||
|
|
012c6f3d41 | ||
|
|
8e89d492fc | ||
|
|
69fe2f0443 | ||
|
|
ebd7f4ae1b | ||
|
|
f9ca4f339e | ||
|
|
5919020e1c | ||
|
|
9d09c2356d | ||
|
|
3cfb597fc6 | ||
|
|
03f2da19e5 | ||
|
|
951e62d984 | ||
|
|
146039c4c5 | ||
|
|
98a216fdb9 | ||
|
|
28ea09a0c4 | ||
|
|
a98a772360 | ||
|
|
4f1da8a24b | ||
|
|
cb83e71f2b | ||
|
|
646d174616 | ||
|
|
34cf78fd33 | ||
|
|
457e1bee2f | ||
|
|
6b95c63c1e | ||
|
|
e965f222db | ||
|
|
d1591bc01c | ||
|
|
a72846be7a | ||
|
|
5072661369 | ||
|
|
5417a83662 | ||
|
|
23be006932 | ||
|
|
e28553767e | ||
|
|
c1f64c043d | ||
|
|
9e6d0183d4 | ||
|
|
8dc7f3fb9e | ||
|
|
ac7b3b9b67 | ||
|
|
af0ebba5db | ||
|
|
b454709e5e | ||
|
|
78684607bd | ||
|
|
3790cad5e5 | ||
|
|
77b7c091a8 | ||
|
|
450ad62fa9 | ||
|
|
1d138c33a4 | ||
|
|
fb2a0e4a1e | ||
|
|
da3db0b0f9 | ||
|
|
bc8aaadd90 | ||
|
|
e6054a4971 | ||
|
|
26548e1929 | ||
|
|
4424cf8190 | ||
|
|
67c1aacd54 | ||
|
|
39b046f18b | ||
|
|
627227f2f9 | ||
|
|
42cef0da88 | ||
|
|
d630f04872 | ||
|
|
35403c87bd | ||
|
|
f2b247e042 | ||
|
|
94022bd9f2 | ||
|
|
ccb2abb950 | ||
|
|
cbafc15292 | ||
|
|
e12c52294a | ||
|
|
63b529da00 | ||
|
|
06f60b7d92 | ||
|
|
e4be2fd19e | ||
|
|
269bf4feec | ||
|
|
9d4c4a1e2b | ||
|
|
2e41fdcb41 | ||
|
|
3ddb4d2b23 | ||
|
|
5a825bd459 | ||
|
|
2e48218623 | ||
|
|
8576a54056 | ||
|
|
79d924f920 | ||
|
|
305beb3af8 | ||
|
|
06fceded14 | ||
|
|
0eadfd5a58 | ||
|
|
eea34a4f6c | ||
|
|
500ec36522 | ||
|
|
ab1f08f687 | ||
|
|
2f89e3658a | ||
|
|
ca525bd08c | ||
|
|
ac2ffc4586 | ||
|
|
5781269557 | ||
|
|
e4422b9fe7 | ||
|
|
269f76d546 | ||
|
|
eac29993d3 | ||
|
|
540e3f0aaa | ||
|
|
5f64ae28e0 | ||
|
|
ece364c823 | ||
|
|
f669f64fcb | ||
|
|
2a53ed93c4 | ||
|
|
2b731fb30c | ||
|
|
be2db2dd8e | ||
|
|
09c08df1b9 | ||
|
|
9ccd3438ad | ||
|
|
393bcbcca5 | ||
|
|
7fac0958b8 | ||
|
|
c6a0874b3b | ||
|
|
9c80470185 | ||
|
|
f08ab729bd | ||
|
|
052c974369 | ||
|
|
e760e868c1 | ||
|
|
2034445f5b | ||
|
|
5e3831a1a4 | ||
|
|
99e046ddea | ||
|
|
12e0759711 | ||
|
|
da0c1cec22 | ||
|
|
fd8da5ffba | ||
|
|
e987af87f6 | ||
|
|
0074cc3933 | ||
|
|
5f2ce89316 | ||
|
|
60492c48a6 | ||
|
|
eed2d70017 | ||
|
|
b859adaa8c | ||
|
|
89a587f9ae | ||
|
|
fb56bcff80 | ||
|
|
99eb6907dd | ||
|
|
3743fad899 | ||
|
|
c1e59a7e03 | ||
|
|
b34dee1f83 | ||
|
|
6edd65ad8f | ||
|
|
d23df2ab15 | ||
|
|
dbe828097c | ||
|
|
48a0623ded | ||
|
|
0959ca6a40 | ||
|
|
1287fa2cd0 | ||
|
|
a5a07f250d | ||
|
|
089fb526f5 | ||
|
|
af58b7593a | ||
|
|
d4508b25ce | ||
|
|
9edc218eaa | ||
|
|
3790f753aa | ||
|
|
3527b86ec5 | ||
|
|
fe7a9104a8 | ||
|
|
cbfb94afcb | ||
|
|
74d8eff6d8 | ||
|
|
d7ed9ab64e | ||
|
|
3b6c5898fe | ||
|
|
ae22adc920 | ||
|
|
5dacf9c3f5 | ||
|
|
9129bfa284 | ||
|
|
82b30d8388 | ||
|
|
e9a0dc7826 | ||
|
|
96190c21d6 | ||
|
|
af2a9225b8 | ||
|
|
aa117a0ee3 | ||
|
|
39b0ea381b | ||
|
|
8ce3a4f904 | ||
|
|
021cea0b34 | ||
|
|
eaad41fe55 | ||
|
|
e25d58d70a | ||
|
|
1d42e9c348 | ||
|
|
2340a6bc37 | ||
|
|
9c0967170a | ||
|
|
be0b9c7e53 | ||
|
|
6d75cd9025 | ||
|
|
345d6f369e | ||
|
|
959ea86d85 | ||
|
|
b67a99af3d | ||
|
|
fa3b848d40 | ||
|
|
0f971e9e7d | ||
|
|
c17f76c009 | ||
|
|
bf23b5d295 | ||
|
|
09c7256d42 | ||
|
|
eaee8a2fbb | ||
|
|
3b18dd67be | ||
|
|
c3f87b4248 | ||
|
|
f6b91ad652 | ||
|
|
abd89df365 | ||
|
|
1c79edc52f | ||
|
|
fe2dfd0e8f | ||
|
|
fa6056c1b1 | ||
|
|
d5762c7ad8 | ||
|
|
d9c9dd2a4f | ||
|
|
651e4bb775 | ||
|
|
3a4d945c68 | ||
|
|
f4a364816b | ||
|
|
931bc03cab | ||
|
|
1abd4937cd | ||
|
|
0df8b51c62 | ||
|
|
7f06d6e68c | ||
|
|
e5b7190015 | ||
|
|
279b8aacf6 | ||
|
|
9eebaab2f4 | ||
|
|
16e9d60033 | ||
|
|
335b378e9a | ||
|
|
9c41bc33a3 | ||
|
|
7f7d6b4d5d | ||
|
|
cc0e3bbce0 | ||
|
|
2eead65fef | ||
|
|
e664be451f | ||
|
|
e5146f7def | ||
|
|
d9bf7c7d12 | ||
|
|
b0bf18e235 | ||
|
|
d2d8160096 | ||
|
|
3bd503c28d | ||
|
|
f001b2c68f | ||
|
|
aa1df8eb33 | ||
|
|
c1aace45ae | ||
|
|
217a60aadc | ||
|
|
5654f528ca | ||
|
|
4da036a064 | ||
|
|
2256b3d262 | ||
|
|
d84ecc307d | ||
|
|
237313d5fb | ||
|
|
7caf766bca | ||
|
|
a24de7fe3f | ||
|
|
0a3f9f5ef1 | ||
|
|
e890b8f7c1 | ||
|
|
dc4d5f0ecb | ||
|
|
a2f0980731 | ||
|
|
0a5c029f8b | ||
|
|
296141ad3d | ||
|
|
85bb79e4fb | ||
|
|
f18d1e50f8 | ||
|
|
943b10dd5d | ||
|
|
0a48e17c88 | ||
|
|
da1381e14e | ||
|
|
7abba0a69b | ||
|
|
bdffb0ee10 | ||
|
|
7bdb7d2ca8 | ||
|
|
92567561b8 | ||
|
|
335bdcd89d | ||
|
|
4c2fc13abb | ||
|
|
7f8f29daa2 | ||
|
|
8fac845ecb | ||
|
|
dee7767427 | ||
|
|
d8076e7630 | ||
|
|
b370bc27c4 | ||
|
|
334c3f4488 | ||
|
|
33822109c0 | ||
|
|
087a71367d | ||
|
|
bec2e3b4a0 | ||
|
|
b1f18b0f5b | ||
|
|
c0d6284368 | ||
|
|
16e294f6fc | ||
|
|
5f7925b2b8 | ||
|
|
2e001b0ce4 | ||
|
|
c1ca3ff5b5 | ||
|
|
1de33cd4ca | ||
|
|
274884ef4d | ||
|
|
77b773388f | ||
|
|
d3f52cdd1a | ||
|
|
3e668ee439 | ||
|
|
0d3ea9af36 | ||
|
|
0d81bc8056 | ||
|
|
e4b532a34d | ||
|
|
61f86c0ac3 | ||
|
|
66fad37116 | ||
|
|
c7bbd8c823 | ||
|
|
dc6f8baf1e | ||
|
|
0e76e65d65 | ||
|
|
877dbed999 | ||
|
|
668fd05fae | ||
|
|
3e49998f41 | ||
|
|
99b183ac17 | ||
|
|
cb97e37c15 | ||
|
|
bb04cddc48 | ||
|
|
ba3f095dd8 | ||
|
|
f8438421c8 | ||
|
|
334361860b | ||
|
|
23bd211758 | ||
|
|
4cc8fb9891 | ||
|
|
ed3cd690fe | ||
|
|
3013fa86b6 | ||
|
|
9a40c7cdc6 | ||
|
|
ae4c9ce819 | ||
|
|
2f8bae1356 | ||
|
|
2593743746 | ||
|
|
ab6bd56006 | ||
|
|
2dfcd5b7ef | ||
|
|
739926f64e | ||
|
|
a18dde07de | ||
|
|
6480017a91 | ||
|
|
4467ec52f7 | ||
|
|
072d82a10e | ||
|
|
b50b759f4f | ||
|
|
c1477ad45f | ||
|
|
679d45399b | ||
|
|
0e15a789ff | ||
|
|
dff5b3f497 | ||
|
|
483e49a6ae | ||
|
|
a689b5b917 | ||
|
|
1363d98280 | ||
|
|
405f3dcbdd | ||
|
|
4b48408bc9 | ||
|
|
d6f1e2d7e2 | ||
|
|
c04c8e3aa4 | ||
|
|
ff5a08d3b0 | ||
|
|
d2049c759e | ||
|
|
f940cb0ace | ||
|
|
507f2f4af4 | ||
|
|
deca7099f3 | ||
|
|
46a741825a | ||
|
|
14fdcd3052 | ||
|
|
c76b01608a | ||
|
|
be709d6601 | ||
|
|
7dc8fac198 | ||
|
|
29ae7d57fd | ||
|
|
1bf9ce872b | ||
|
|
0071c9504f | ||
|
|
594a872c84 | ||
|
|
0d1f78e82e | ||
|
|
a12de51897 | ||
|
|
74fa084dd0 | ||
|
|
a1ee258da5 | ||
|
|
c1af171c5d | ||
|
|
e36c9560fa | ||
|
|
5cd19ddc8d | ||
|
|
ac243e5d11 | ||
|
|
b480d019f6 | ||
|
|
cc13ab97d6 | ||
|
|
fee1d2ed04 | ||
|
|
4144d5faa6 | ||
|
|
38a23c0bee | ||
|
|
8fcfebe170 | ||
|
|
f917fa8138 | ||
|
|
f60b611304 | ||
|
|
a54624e5c8 | ||
|
|
e02b8522d6 | ||
|
|
8cf74c88ce | ||
|
|
4095d6dcf6 | ||
|
|
cd4221e4f2 | ||
|
|
e4e65e4576 | ||
|
|
72e93786df | ||
|
|
548754821e | ||
|
|
77f85579e3 | ||
|
|
370b14b82e | ||
|
|
88205adeb2 | ||
|
|
351ce995d9 | ||
|
|
a9aa92de90 | ||
|
|
9ea665dea2 | ||
|
|
30b52527e7 | ||
|
|
bb4125153b | ||
|
|
f0d5b2b1da | ||
|
|
30c4048e4a | ||
|
|
93770ca9ce | ||
|
|
e788783d12 | ||
|
|
e3ec03794a | ||
|
|
1314444d7c | ||
|
|
2a14664d34 | ||
|
|
05c325d686 | ||
|
|
cf9472eb56 | ||
|
|
bb2085436e | ||
|
|
07a03940a0 | ||
|
|
d882a4249a | ||
|
|
a2420e4288 | ||
|
|
5f2f6fff56 | ||
|
|
353548660c | ||
|
|
912f07225c | ||
|
|
a23b7eeff1 | ||
|
|
574f0d71b2 | ||
|
|
a368312035 | ||
|
|
2f88b1ab65 | ||
|
|
f85f97e061 | ||
|
|
30dec13903 | ||
|
|
3687a230e1 | ||
|
|
c274486057 | ||
|
|
94e9bbfd63 | ||
|
|
adb71ad174 | ||
|
|
4a95f5cd9d | ||
|
|
f3b368fae4 | ||
|
|
20919a8a39 | ||
|
|
3057e5c997 | ||
|
|
f2e86efc4d | ||
|
|
98b27d647e | ||
|
|
6c413eb1ba | ||
|
|
dcdd9132e2 | ||
|
|
7a884d1f87 | ||
|
|
d21f5f427c | ||
|
|
9ba2a6628d | ||
|
|
d9b1c36055 | ||
|
|
a593a247d7 | ||
|
|
155debc864 | ||
|
|
a5975ac38b | ||
|
|
739641b857 | ||
|
|
d02a110f99 | ||
|
|
204f1cfd6b | ||
|
|
9120db2dc6 | ||
|
|
2d22e043a0 | ||
|
|
c26cacaf4e | ||
|
|
f0048544e2 | ||
|
|
cf227dbfa2 | ||
|
|
a5f8bdbe61 | ||
|
|
e442553c6f | ||
|
|
7134acfcd6 | ||
|
|
82439f444e | ||
|
|
1a17908488 | ||
|
|
9af30e99f8 | ||
|
|
bf586d0837 | ||
|
|
ed45a9b156 | ||
|
|
6f942c3417 | ||
|
|
57083c90cd | ||
|
|
e28bcdd978 | ||
|
|
f4ea39b602 | ||
|
|
0b4a5ab2eb | ||
|
|
034704a330 | ||
|
|
5c60eaf6ab | ||
|
|
f5709eac2c | ||
|
|
a6dca12bad | ||
|
|
e40411ef91 | ||
|
|
fd20c21243 | ||
|
|
5c0474ef96 | ||
|
|
73d1de75f9 | ||
|
|
8ea6989ea4 | ||
|
|
5a5e714aca | ||
|
|
747d48e4d9 | ||
|
|
07a0200f30 | ||
|
|
1c5313f2d9 | ||
|
|
05e08719fb | ||
|
|
ca0e616f88 | ||
|
|
a8d20caba4 | ||
|
|
0d4bbb0a48 | ||
|
|
b9cc219530 | ||
|
|
e204ab5871 | ||
|
|
16d0c05b4b | ||
|
|
6f8329d191 | ||
|
|
d751463b26 | ||
|
|
d3b66eff59 | ||
|
|
16a9f44d4d | ||
|
|
4257d0332a | ||
|
|
ccbcaa94fe | ||
|
|
b80442c061 | ||
|
|
3a0f6820ad | ||
|
|
1bc92f5363 | ||
|
|
818ddcf01e | ||
|
|
618ba361c7 | ||
|
|
599160a325 | ||
|
|
35fba6f4ed | ||
|
|
a14aad75fd | ||
|
|
3513e85b0b | ||
|
|
66c0390fc7 | ||
|
|
a6549ccb08 | ||
|
|
15d2878014 | ||
|
|
d271be8723 | ||
|
|
6f9d2d99dd | ||
|
|
5d62664ee3 | ||
|
|
7124d9f2f8 | ||
|
|
f26fc9a0f0 | ||
|
|
3fd637b3c7 | ||
|
|
ea605383d5 | ||
|
|
a4fa670dc5 | ||
|
|
56f99b2129 | ||
|
|
ccb508705b | ||
|
|
6f8fa96150 | ||
|
|
72e1632499 | ||
|
|
0459744771 | ||
|
|
417544b781 | ||
|
|
f9028cb366 | ||
|
|
7d7cc56527 | ||
|
|
85d0271b86 | ||
|
|
749d5e22bb | ||
|
|
0ffa9d4225 | ||
|
|
61c61adea1 | ||
|
|
9a264719a9 | ||
|
|
96c213dcc4 | ||
|
|
dec1a8e204 | ||
|
|
a17fd697e2 | ||
|
|
a6ab66e799 | ||
|
|
17095ec3c6 | ||
|
|
82687147b8 | ||
|
|
ba76422c1f | ||
|
|
083b3c4ece | ||
|
|
5ecfdf38a8 | ||
|
|
dd1acf3c2a | ||
|
|
76e9c2d196 | ||
|
|
15f046959d | ||
|
|
bf3ba04624 | ||
|
|
d997894d9a | ||
|
|
c1059db6e5 | ||
|
|
8ad29a2836 | ||
|
|
93a454b835 | ||
|
|
c8a6fd19a7 | ||
|
|
0b143b580a | ||
|
|
da899386ec | ||
|
|
05d22903ea | ||
|
|
33945520f1 | ||
|
|
ed69fedc0a | ||
|
|
8098464f58 | ||
|
|
ea0db57388 | ||
|
|
6fcc148105 | ||
|
|
3485cb4ec4 | ||
|
|
40284809cf | ||
|
|
efc18aaaec | ||
|
|
348441b046 | ||
|
|
66601b2e7c | ||
|
|
724c5e4b73 | ||
|
|
7eff29bc65 | ||
|
|
ca002003c2 | ||
|
|
f0675f1f3c | ||
|
|
976186c525 | ||
|
|
89d5777e52 | ||
|
|
e6ef6ccccf | ||
|
|
4826e14cad | ||
|
|
5515f90147 | ||
|
|
2193c26acb | ||
|
|
1974a2c0e4 | ||
|
|
84fbe9ee06 | ||
|
|
8dbb69809c | ||
|
|
b8e2cfc47f | ||
|
|
7348bd5d15 | ||
|
|
9a46a466f7 | ||
|
|
fafc5c8553 | ||
|
|
553fc6f5d9 | ||
|
|
f5d790b264 | ||
|
|
641e13496e | ||
|
|
a6e18819d4 | ||
|
|
faf5ff6aa4 | ||
|
|
ae20ca5558 | ||
|
|
22bd87c965 | ||
|
|
2129645f39 | ||
|
|
93a07b6207 | ||
|
|
4ffdfaa506 | ||
|
|
e3989840ee | ||
|
|
b3e6f531a1 | ||
|
|
4f6ee34592 | ||
|
|
3ae58a323e | ||
|
|
26b958c270 | ||
|
|
12a4af5900 | ||
|
|
69479d538c | ||
|
|
829397dd5a | ||
|
|
2bc89026db | ||
|
|
ebbc44d181 | ||
|
|
2228a1e36b | ||
|
|
a8cbf3e8ff | ||
|
|
fa32e3d734 | ||
|
|
0d17148ff0 | ||
|
|
aa38411cf7 | ||
|
|
4913c8699d | ||
|
|
1035a11487 | ||
|
|
15c2efe706 | ||
|
|
d7fd71bb62 | ||
|
|
b11ee993fa | ||
|
|
614aa7873c | ||
|
|
1adf31fe15 | ||
|
|
824ffd7b5b | ||
|
|
c31c6fdebb | ||
|
|
83f3276429 | ||
|
|
d21f68ce54 | ||
|
|
18b1e1b133 | ||
|
|
b2a51bd658 | ||
|
|
e5ab1dc154 | ||
|
|
6274969635 | ||
|
|
069c430346 | ||
|
|
0edaa40052 | ||
|
|
627077c8f3 | ||
|
|
a897b1798d | ||
|
|
cbcc4dd21d | ||
|
|
50e39993bf | ||
|
|
5e397dd01e | ||
|
|
f57ff5d5e0 | ||
|
|
5c3e40917c | ||
|
|
90a2dc4581 | ||
|
|
b64243fdd6 | ||
|
|
42db87d305 | ||
|
|
e7ab1b589a | ||
|
|
e9979c9887 | ||
|
|
3bb9bb56f0 | ||
|
|
5a99474c55 | ||
|
|
182ee6c25f | ||
|
|
4d3f0a06db | ||
|
|
0e182c519b | ||
|
|
b1ee30ce7d | ||
|
|
93ba764e23 | ||
|
|
433e17bb81 | ||
|
|
61c09083ad | ||
|
|
018377e724 | ||
|
|
b76f9513ba | ||
|
|
40ebb7ba75 | ||
|
|
a9e52e8954 | ||
|
|
3c8876cac7 | ||
|
|
b7e005f9c7 | ||
|
|
e6fe0a19fa | ||
|
|
fba11b6a44 | ||
|
|
c270e7f5dd | ||
|
|
b4cdf4d277 | ||
|
|
716d7bfcf6 | ||
|
|
b45a169a2f | ||
|
|
9ee00d345e | ||
|
|
0379fbc4eb | ||
|
|
9748a3ae91 | ||
|
|
1881944748 | ||
|
|
3721fa194c | ||
|
|
8c3fcad20b | ||
|
|
decf373d0b | ||
|
|
ff1d50f993 | ||
|
|
ef34204b59 | ||
|
|
270b636d80 | ||
|
|
ac01da2ae9 | ||
|
|
0136310c54 | ||
|
|
ecf4cf852e | ||
|
|
c66384adfb | ||
|
|
98bdda629d | ||
|
|
a8286f9cba | ||
|
|
fa3db4fcf6 | ||
|
|
ddac0cfee1 | ||
|
|
9368673459 | ||
|
|
43dc999ab5 | ||
|
|
3b7333e866 | ||
|
|
bc0ddbaf16 | ||
|
|
45f0ae7e1c | ||
|
|
a521c4ae01 | ||
|
|
8e5dee79e0 | ||
|
|
5b8238adeb | ||
|
|
ec330474fa | ||
|
|
ece28904a8 | ||
|
|
4f1c495afb | ||
|
|
5fdd27b7e6 | ||
|
|
91f449af9a | ||
|
|
efc0a0dfe3 | ||
|
|
fee47baa66 | ||
|
|
9abd9d20ec | ||
|
|
d98a457271 | ||
|
|
ef3a0d881f | ||
|
|
669a9e5cc3 | ||
|
|
5eb58ae6cc | ||
|
|
7fa1923400 | ||
|
|
4c165bd620 | ||
|
|
7c04a455b4 | ||
|
|
06b6061518 | ||
|
|
3821ee3dcd | ||
|
|
03a33646d6 | ||
|
|
791183553e | ||
|
|
de6ef49043 | ||
|
|
0ad7bfc7e7 | ||
|
|
bd64143ae1 | ||
|
|
ec982ba9a3 | ||
|
|
6280f6ff98 | ||
|
|
35d20390a9 | ||
|
|
720b9ef999 | ||
|
|
9b9e4dddfc | ||
|
|
7434e0352f | ||
|
|
26d61af902 | ||
|
|
5bd12c5f9e | ||
|
|
e07fae4290 | ||
|
|
c487c5042f | ||
|
|
28bf7ee90b | ||
|
|
4d1ca7ede4 | ||
|
|
f3b46515c5 | ||
|
|
0aa5e7ba63 | ||
|
|
8d8bf43b46 | ||
|
|
9983407c8b | ||
|
|
2471ad4215 | ||
|
|
f266982560 | ||
|
|
c059a416f7 | ||
|
|
82dc0c0593 | ||
|
|
5faad3db92 | ||
|
|
099db6792a | ||
|
|
aaf7927aa2 | ||
|
|
3c677f3d21 | ||
|
|
94eb76b3a6 | ||
|
|
74a31f3301 | ||
|
|
f88c0b9b67 | ||
|
|
61ef313b1c | ||
|
|
a921cb2d0d | ||
|
|
f3aaa363d8 | ||
|
|
45a79e1920 | ||
|
|
6fd9b2a453 | ||
|
|
01d8e89a71 | ||
|
|
c89fa63910 | ||
|
|
9fc5c49dbf | ||
|
|
7dfc269df9 | ||
|
|
76d0b397db | ||
|
|
5413f887af | ||
|
|
048cea19b7 | ||
|
|
3e77c76c34 | ||
|
|
9b6c5d2ea3 | ||
|
|
b3d0c61f0e | ||
|
|
4ce0441d68 | ||
|
|
72be34e18d | ||
|
|
d2961b7650 | ||
|
|
fdca1bbf72 | ||
|
|
ab7a2f9dee | ||
|
|
7b72857a3b | ||
|
|
4787146658 | ||
|
|
430f9356c3 | ||
|
|
70a3b3518f | ||
|
|
c0944c17e0 | ||
|
|
da1b2a91e7 | ||
|
|
2fa081a4ba | ||
|
|
aa27492713 | ||
|
|
afe589dec3 | ||
|
|
5b9a3ca1cb | ||
|
|
bf7c56a269 | ||
|
|
d33af742dd | ||
|
|
978d140c8f | ||
|
|
2ce213b62c | ||
|
|
7748266078 | ||
|
|
823879e9f9 | ||
|
|
98eb285e14 | ||
|
|
37fd2e1103 | ||
|
|
56db5dc341 | ||
|
|
d48fa235b1 | ||
|
|
06a111495b | ||
|
|
f3fb0797bf | ||
|
|
561b8f4eed | ||
|
|
8cfc6f0b1d | ||
|
|
7e04f26f78 | ||
|
|
348c30b61e | ||
|
|
83783d07a1 | ||
|
|
49a1f2c7c5 | ||
|
|
ad1e60e137 | ||
|
|
97e0a983f1 | ||
|
|
ddfc0151fc | ||
|
|
81c508e13c | ||
|
|
45681e645b | ||
|
|
7195cfc3cf | ||
|
|
93fe5e2cf7 | ||
|
|
a2bf795d12 | ||
|
|
c8d78f39e0 | ||
|
|
a4e9f1a683 | ||
|
|
f8c74daef5 | ||
|
|
b3a593afd7 | ||
|
|
d45461bc47 | ||
|
|
d9ab8a1c8b | ||
|
|
5125ad4889 | ||
|
|
951e85b04b | ||
|
|
711d922695 | ||
|
|
58aa2b6a49 | ||
|
|
fb06905c86 | ||
|
|
4a2911557d | ||
|
|
3692ffcde7 | ||
|
|
99caa5dddc | ||
|
|
86b42a3716 | ||
|
|
12c4680501 | ||
|
|
b049420c59 | ||
|
|
b7e05c236f | ||
|
|
241103c369 | ||
|
|
2128367113 | ||
|
|
f555c8190d | ||
|
|
d5df633def | ||
|
|
fe7dc859e3 | ||
|
|
569c5046c6 | ||
|
|
e0210ae2d8 | ||
|
|
f85dc3b7e7 | ||
|
|
92d4363120 | ||
|
|
6c69220de2 | ||
|
|
3a1229b072 | ||
|
|
45538c9f62 | ||
|
|
0c173fde53 | ||
|
|
77db2bbfec | ||
|
|
2987185a9d | ||
|
|
7a7baf7175 | ||
|
|
5645cc0af2 | ||
|
|
63a6756fed | ||
|
|
9f408c98a6 | ||
|
|
26d6998d82 | ||
|
|
6bee44acb7 | ||
|
|
441992cf37 | ||
|
|
490c224ac3 | ||
|
|
f5c55048de | ||
|
|
8139e124c2 | ||
|
|
cba73a5139 | ||
|
|
de0c9367e5 | ||
|
|
630060860c | ||
|
|
dccd11fb7b | ||
|
|
b8a4b2cf16 | ||
|
|
e52f55bfba | ||
|
|
1cb99e02a9 | ||
|
|
c9c5c35e56 | ||
|
|
bc7c9f9c01 | ||
|
|
e4bfc4cb8d | ||
|
|
e304395179 | ||
|
|
6b83130853 | ||
|
|
9565718699 | ||
|
|
d64995c4a1 | ||
|
|
2952ea7404 | ||
|
|
f34c807a2c | ||
|
|
b1f9704055 | ||
|
|
9382829ba5 | ||
|
|
373a6ea912 | ||
|
|
72eb4e7b3b | ||
|
|
315c0870ed | ||
|
|
200fa621bf | ||
|
|
80348c1980 | ||
|
|
856dd8403c | ||
|
|
0bb9acd4c1 | ||
|
|
047a80917f | ||
|
|
e6e8fe4763 | ||
|
|
6cd212398e | ||
|
|
44ad6d4247 | ||
|
|
7302782853 | ||
|
|
7fa1aba6b8 | ||
|
|
2fed4e3e8b | ||
|
|
0f03208aa1 | ||
|
|
bd343c51a3 | ||
|
|
8a05f06efa | ||
|
|
27b049eada | ||
|
|
2d1afb5291 | ||
|
|
63c17a3abf | ||
|
|
94f9bc5fca | ||
|
|
ab273430d2 | ||
|
|
0b3dc315ad | ||
|
|
f26a2d2f13 | ||
|
|
d58add18fc | ||
|
|
8edf9bf508 | ||
|
|
415381cebd | ||
|
|
59accec1c0 | ||
|
|
dd2699fcc1 | ||
|
|
3a0413d8bb | ||
|
|
0986a5f985 | ||
|
|
9122f9b291 | ||
|
|
d279db2a0e | ||
|
|
fa77229b72 | ||
|
|
78b5080c9a | ||
|
|
c6657b9619 | ||
|
|
80d8388eb6 | ||
|
|
0641da786c | ||
|
|
3291f3bb3c | ||
|
|
b1ee4bdc09 | ||
|
|
a0cfef8bda | ||
|
|
4d033f4a03 | ||
|
|
ac11885379 | ||
|
|
277669a13c | ||
|
|
fcbc476462 | ||
|
|
4944b415c7 | ||
|
|
5da7312d2d | ||
|
|
562820180c | ||
|
|
954d19fe50 | ||
|
|
addd86f5d2 | ||
|
|
a29832207e | ||
|
|
2afd549826 | ||
|
|
8a71b2c6dd | ||
|
|
1b90223210 | ||
|
|
95989ff63b | ||
|
|
d633d2691d | ||
|
|
f9b1608fd2 | ||
|
|
4d8ed3f00e | ||
|
|
799f758dce | ||
|
|
359e7d0543 | ||
|
|
07bf93e022 | ||
|
|
57e27da0c4 | ||
|
|
9ecbf62d25 | ||
|
|
48ffa591ca | ||
|
|
b7dd617bb1 | ||
|
|
392f9d0775 | ||
|
|
4361b11c68 | ||
|
|
28bccad010 | ||
|
|
29d31a0deb | ||
|
|
5b782993fd | ||
|
|
138e60e77c | ||
|
|
9771402c54 | ||
|
|
30dcb4d8d2 | ||
|
|
1d9960d349 | ||
|
|
2747b241ab | ||
|
|
6b8035b116 | ||
|
|
33ad5f4d45 | ||
|
|
af7ad9251a | ||
|
|
c418c766d8 | ||
|
|
334d843955 | ||
|
|
2e5169eb46 | ||
|
|
3cdc1c03c3 | ||
|
|
733c619b1f | ||
|
|
2021b644c0 | ||
|
|
f55ed13bd2 | ||
|
|
14b7072b5b | ||
|
|
98395abc17 | ||
|
|
5db5c4e52c | ||
|
|
4ec9975aa3 | ||
|
|
c6b0841583 | ||
|
|
9312435076 | ||
|
|
49427f1c54 | ||
|
|
82e7e06dc4 | ||
|
|
76cf82bb19 | ||
|
|
4f8ad2962e | ||
|
|
fe4be48bff | ||
|
|
66fc0b421b | ||
|
|
c0b4867659 | ||
|
|
95253fbc76 | ||
|
|
b31f55063d | ||
|
|
71e77ad45a | ||
|
|
25873e0e02 | ||
|
|
22638a8147 | ||
|
|
df519b3042 | ||
|
|
9ed963ef70 | ||
|
|
1dd7993e7a | ||
|
|
386b33b65d | ||
|
|
416deb8711 | ||
|
|
3c7fdac55e | ||
|
|
392a6af47f | ||
|
|
6b03e3f603 | ||
|
|
9397f6beda | ||
|
|
d17b386fd6 | ||
|
|
f6d2e1a447 | ||
|
|
bd95ef5db6 | ||
|
|
6e76c621b8 | ||
|
|
3e58bee0eb | ||
|
|
8c2ed1f581 | ||
|
|
500dd3bfaf | ||
|
|
bc7bacd654 | ||
|
|
fa16b990b6 | ||
|
|
9d5e9dd9e5 | ||
|
|
e075f1c08b | ||
|
|
4046f9dde1 | ||
|
|
fcd82ada14 | ||
|
|
7e0aa719b4 | ||
|
|
ce7bc9f438 | ||
|
|
43a362d0eb | ||
|
|
7d7e6e10b9 | ||
|
|
73821b0f12 | ||
|
|
d616da7f67 | ||
|
|
0c81202bbb | ||
|
|
2071a7d308 | ||
|
|
c439daadad | ||
|
|
083f325076 | ||
|
|
6284bd3f17 | ||
|
|
7adc9d94b4 | ||
|
|
ee53433dcc | ||
|
|
ad10d13a75 | ||
|
|
73e030d2f5 | ||
|
|
3a3b45aa04 | ||
|
|
81c19e9964 | ||
|
|
df856bc4a0 | ||
|
|
8558dc7ee4 | ||
|
|
087d5f6e58 | ||
|
|
9540bc350a | ||
|
|
09153c6c30 | ||
|
|
f66d81f147 | ||
|
|
75925143b6 | ||
|
|
e7dc00991e | ||
|
|
dd9da82ed3 | ||
|
|
c995b8fa81 | ||
|
|
e7c2994ea3 | ||
|
|
106997b26c | ||
|
|
fa842c1566 | ||
|
|
be03dd82f9 | ||
|
|
39c46995e1 | ||
|
|
97adc01e8d | ||
|
|
36be881741 | ||
|
|
955cc6dff5 | ||
|
|
2be1399eda | ||
|
|
ef5d2a7654 | ||
|
|
1cd00cab62 | ||
|
|
7652c231f6 | ||
|
|
e17cdf0ca7 | ||
|
|
3317791e68 | ||
|
|
c3871bc2ec | ||
|
|
ebba86f741 | ||
|
|
5ac84a6a02 | ||
|
|
cf3e9704e8 | ||
|
|
37eac8afcf | ||
|
|
692a0535ff | ||
|
|
0f0d804052 | ||
|
|
d189e6b53d | ||
|
|
5da31691a9 | ||
|
|
4059a4fd9a | ||
|
|
e56da71856 | ||
|
|
91e10f627f | ||
|
|
338c686e8d | ||
|
|
0007e9ea2b | ||
|
|
1e09e9b322 | ||
|
|
43c358119a | ||
|
|
7a0f251ebd | ||
|
|
e989321c5f | ||
|
|
56f27e6aaa | ||
|
|
7c4e5aa667 | ||
|
|
d253d826bb | ||
|
|
4fd9639457 | ||
|
|
2f2ee1f431 | ||
|
|
888fa20ca3 | ||
|
|
598dbb2b7a | ||
|
|
71eb1eab14 | ||
|
|
62a6bd99e8 | ||
|
|
174cdf2149 | ||
|
|
5267fbce7b | ||
|
|
dd814e7e95 | ||
|
|
f806b45d3d | ||
|
|
8575e9eabe | ||
|
|
6ff9e22049 | ||
|
|
caa86fdab7 | ||
|
|
48246716cc | ||
|
|
6e07429e8a | ||
|
|
1a271c32b6 | ||
|
|
3fddec8f20 | ||
|
|
ac3944aece | ||
|
|
958cc2a50c | ||
|
|
058dfcfa9f | ||
|
|
9dbb1ca386 | ||
|
|
4d1def6e9d | ||
|
|
ad06c8147f | ||
|
|
ff763b0278 | ||
|
|
74f611e0fd | ||
|
|
a2f5f1cb0e | ||
|
|
1fbe7d92eb | ||
|
|
760974c7c7 | ||
|
|
e1587d11b1 | ||
|
|
0595360808 | ||
|
|
1a8149e456 | ||
|
|
61f8be1c60 | ||
|
|
96b18dab00 | ||
|
|
0a21b239bc | ||
|
|
9c3589aea4 | ||
|
|
2433485d13 | ||
|
|
6b5f254e0a | ||
|
|
e1b41b1e26 | ||
|
|
bd7a265df0 | ||
|
|
039cca9529 | ||
|
|
963347dbc2 | ||
|
|
697cc9f758 | ||
|
|
3892225584 | ||
|
|
a7880a0ef5 | ||
|
|
dd574830f5 | ||
|
|
71a0d15c35 | ||
|
|
8a33c4f09a | ||
|
|
d223ce062a | ||
|
|
39c8f12963 | ||
|
|
bd4ba8c826 | ||
|
|
3d38c8e088 | ||
|
|
ce58c80c6d | ||
|
|
19b3a0781c | ||
|
|
b42c1971b9 | ||
|
|
02440941e0 | ||
|
|
cd2f986c50 | ||
|
|
e7cbd6b31f | ||
|
|
a7f6d5eebd | ||
|
|
4f3b8c0906 | ||
|
|
7126c71943 | ||
|
|
489cf16af8 | ||
|
|
b012f44259 | ||
|
|
fd6f92f6b5 | ||
|
|
ddf7226ba8 | ||
|
|
5ce765bd27 | ||
|
|
a1cd95752a | ||
|
|
d131a26a41 | ||
|
|
10a7c75001 | ||
|
|
1f454ababf | ||
|
|
2450edd070 | ||
|
|
fc2a61835c | ||
|
|
d06d73d5f7 | ||
|
|
4ee352fdb2 | ||
|
|
2c10996bb3 | ||
|
|
96ea3ded4a | ||
|
|
8bbc6e9ff5 | ||
|
|
b9c85bb1bf | ||
|
|
f436afb9aa | ||
|
|
750efe4152 | ||
|
|
99cee95cd5 | ||
|
|
ec10b84fa6 | ||
|
|
f0442fe2ce | ||
|
|
7907969696 | ||
|
|
8dbab73d2b | ||
|
|
ade8acb4e2 | ||
|
|
9cb78e6954 | ||
|
|
af7029812c | ||
|
|
e9127bdbb3 | ||
|
|
84c9532456 | ||
|
|
aa7c9bca46 | ||
|
|
3d00b4ffbe | ||
|
|
9b750bc756 | ||
|
|
c3349e8cc7 | ||
|
|
f4d7c7f739 | ||
|
|
19d51cb1a4 | ||
|
|
cc9983aa16 | ||
|
|
81f8467f66 | ||
|
|
df6b23e3c7 | ||
|
|
4dd81e7d59 | ||
|
|
54ce7067b4 | ||
|
|
2673f790e6 | ||
|
|
69bea2ec9b | ||
|
|
37037cf797 | ||
|
|
c517b59138 | ||
|
|
2a1586aab3 | ||
|
|
915281d138 | ||
|
|
b53a179ea0 | ||
|
|
7077e8b50e | ||
|
|
d9181277d9 | ||
|
|
810c2d6a1a | ||
|
|
f31113fb90 | ||
|
|
1702b9dd37 | ||
|
|
f8e61c713c | ||
|
|
0304d6079d | ||
|
|
ae41e64999 | ||
|
|
8c9f32c927 | ||
|
|
5485e8a322 | ||
|
|
b4c612ff6d | ||
|
|
e708268067 | ||
|
|
643132754a | ||
|
|
4f0a131bd2 | ||
|
|
52aa0350cf | ||
|
|
c9884f32fe | ||
|
|
aea3ae3d37 | ||
|
|
10f7c3045f | ||
|
|
bf4e158c30 | ||
|
|
4a3155ed22 | ||
|
|
29f1c89fa5 | ||
|
|
4a92e8a99f | ||
|
|
c6cffb1156 | ||
|
|
f6e4e59905 | ||
|
|
3a0736c4bf | ||
|
|
47455b2029 | ||
|
|
05eb7d765f | ||
|
|
5e786686d0 | ||
|
|
5cb8e3a7c3 | ||
|
|
e61873f335 | ||
|
|
6c3719b9b8 | ||
|
|
84bd077eac | ||
|
|
db39b27119 | ||
|
|
8c9ea7885a | ||
|
|
f2d2b35543 | ||
|
|
5dfd5766f2 | ||
|
|
0e4c3e1e92 | ||
|
|
221f42606c | ||
|
|
742f092ed3 | ||
|
|
36bffa1475 | ||
|
|
2540ac34b3 | ||
|
|
76e5d41a34 | ||
|
|
936abc1b1a | ||
|
|
584bdd545f | ||
|
|
99debc18d7 | ||
|
|
56b896eda0 | ||
|
|
cab102528d | ||
|
|
1875cdcda2 | ||
|
|
386dcc8d43 | ||
|
|
e6d59a47b1 | ||
|
|
2659393f33 | ||
|
|
916b2363d9 | ||
|
|
bb513790b5 | ||
|
|
e5ab15a727 | ||
|
|
bbaa750fda | ||
|
|
a46e19210a | ||
|
|
9d6772edd1 | ||
|
|
3aeaa564a2 | ||
|
|
8baad494e3 | ||
|
|
fb04753d52 | ||
|
|
ea37c4ccd8 | ||
|
|
80f02b52e1 | ||
|
|
55464845d6 | ||
|
|
8aef4bb455 | ||
|
|
d8a2adbca2 | ||
|
|
02e56da08a | ||
|
|
9d9f857e73 | ||
|
|
b140c1e65f | ||
|
|
81ff03462e | ||
|
|
2ea7c09c84 | ||
|
|
4163ed212c | ||
|
|
c83722c2df | ||
|
|
700db655e6 | ||
|
|
226428f631 | ||
|
|
e2b293e49b | ||
|
|
1f6e9d4660 | ||
|
|
ecf2ee888f | ||
|
|
1e8eeadb1d | ||
|
|
e7ceccdd83 | ||
|
|
5390b4a4b3 | ||
|
|
f25ec34bc3 | ||
|
|
53ece86816 | ||
|
|
9b128cdfcc | ||
|
|
c047386755 | ||
|
|
b0ffb272b3 | ||
|
|
956e21c8db | ||
|
|
95057a2b09 | ||
|
|
788aa24a80 | ||
|
|
0a72ef91cc | ||
|
|
f0f4e0985a | ||
|
|
a6bedea4b6 | ||
|
|
055316e1ca | ||
|
|
25fece5947 | ||
|
|
5ec3cdbcc5 | ||
|
|
b530ab2ef6 | ||
|
|
5164f60c98 | ||
|
|
19ba3015f7 | ||
|
|
fb00b2672c | ||
|
|
3e0f936d2a | ||
|
|
f5be146dbb | ||
|
|
95431a0874 | ||
|
|
f76b130ca4 | ||
|
|
d19f8259d0 | ||
|
|
68cd62d756 | ||
|
|
ea4a55d3dd | ||
|
|
788bdcd35b | ||
|
|
ebd7e24830 | ||
|
|
0b7fbffa0a | ||
|
|
2afda9a055 | ||
|
|
28dd275bd8 | ||
|
|
9a3cf182ac | ||
|
|
dd278c28be | ||
|
|
37572122b0 | ||
|
|
5348f75b5e | ||
|
|
2c32a4e912 | ||
|
|
c66f7235b6 | ||
|
|
6b8873d385 | ||
|
|
8db18d87e5 | ||
|
|
444920d15c | ||
|
|
8aa2fab603 | ||
|
|
9ded4386cc | ||
|
|
cc6b1b5aa1 | ||
|
|
74f20da82f | ||
|
|
4c9c838b70 | ||
|
|
9a9d27d37a | ||
|
|
0347d4cec4 | ||
|
|
b1b189288e | ||
|
|
b3220f981b | ||
|
|
20cbf0c710 | ||
|
|
a5573e62c6 | ||
|
|
5444381f7d | ||
|
|
dc44679031 | ||
|
|
2cbd17b745 | ||
|
|
c4ccee8df6 | ||
|
|
fbcf803d06 | ||
|
|
5247b7a9af | ||
|
|
dc218cc992 | ||
|
|
c21761d9d4 | ||
|
|
36c0bf06d7 | ||
|
|
ccdab2b083 | ||
|
|
8de2066634 | ||
|
|
dfc312c092 | ||
|
|
ce15dbf31b | ||
|
|
15a8a56807 | ||
|
|
385d42281b | ||
|
|
b0dc933021 | ||
|
|
9ef13696d8 | ||
|
|
c3f635fd12 | ||
|
|
e3d1380435 | ||
|
|
f83737b538 | ||
|
|
bb1ea4e4d0 | ||
|
|
9cb4de2ea8 | ||
|
|
048cbf60ec | ||
|
|
36f40b4188 | ||
|
|
ea1afb260a | ||
|
|
b73ee1f638 | ||
|
|
51c2a54179 | ||
|
|
a3bba92063 | ||
|
|
ebcc6c9341 | ||
|
|
95f765055e | ||
|
|
49aa5ffccc | ||
|
|
d09d3fa80b | ||
|
|
4c8cd50643 | ||
|
|
eee72f4f27 | ||
|
|
45f6a7cb4d | ||
|
|
8866bd8663 | ||
|
|
3f9c515f1d | ||
|
|
e9e0fdae37 | ||
|
|
124f7f43ab | ||
|
|
27df44bf44 | ||
|
|
b934a7de6a | ||
|
|
d521c75085 | ||
|
|
5e18b6b878 | ||
|
|
3183ca02b3 | ||
|
|
60a278490f | ||
|
|
b78e74cdf6 | ||
|
|
f61a16074b | ||
|
|
82766d1645 | ||
|
|
2d71a916a2 | ||
|
|
5f9cf47003 | ||
|
|
16b39185dc | ||
|
|
6f0410f26e | ||
|
|
0b86845852 | ||
|
|
d5f914bd2f | ||
|
|
663c65e42e | ||
|
|
b9de86f96c | ||
|
|
bd9c0ffb25 | ||
|
|
9d763773cf | ||
|
|
540f977146 | ||
|
|
d16b09d3fc | ||
|
|
6f8a8d3b90 | ||
|
|
00ef4166c7 | ||
|
|
b88414735e | ||
|
|
af092fae9b | ||
|
|
b889efc913 | ||
|
|
877dd68a6b | ||
|
|
2805a1c7bc | ||
|
|
c5c000ea6f | ||
|
|
673f1072bf | ||
|
|
d0e93b9b9f | ||
|
|
f239088bcb | ||
|
|
32642f105c | ||
|
|
4adaf6d355 | ||
|
|
291e2a5e40 | ||
|
|
05bdb56203 | ||
|
|
cb71df8345 | ||
|
|
c6c5f5188b | ||
|
|
a7b6ca0914 | ||
|
|
30ba062695 | ||
|
|
a595af7b3f | ||
|
|
b2ee3172d8 | ||
|
|
73992ee8e9 | ||
|
|
78885fd00a | ||
|
|
ce55ac6ccb | ||
|
|
8ce0951e5f | ||
|
|
7788fa9d3e | ||
|
|
7f36552c71 | ||
|
|
16f9437b29 | ||
|
|
0beaff718e | ||
|
|
9b6f37b5d0 | ||
|
|
3d6d4aea6a | ||
|
|
2356a21e54 | ||
|
|
a55e7ed34f | ||
|
|
e355e4d35d | ||
|
|
6dcaf80f3f | ||
|
|
a465114d36 | ||
|
|
07fbcb3488 | ||
|
|
534fbe1b6e | ||
|
|
f5c9c1ba0e | ||
|
|
5d5485f569 | ||
|
|
3d3fa5d18a | ||
|
|
312c41f229 | ||
|
|
2df1dc9028 | ||
|
|
222f245e63 | ||
|
|
2aa7702aed | ||
|
|
0b185c35c2 | ||
|
|
48dcec3cc3 | ||
|
|
8567179fa3 | ||
|
|
79d15ecd7e | ||
|
|
837c7e4bc7 | ||
|
|
2ae7e9920d | ||
|
|
8cf955b674 | ||
|
|
33f897d43e | ||
|
|
ddb0946a0d | ||
|
|
0f5beac4a8 | ||
|
|
974e2f71f9 | ||
|
|
3c427d7e28 | ||
|
|
0f10c8f5df | ||
|
|
7840b51f5c | ||
|
|
6578855182 | ||
|
|
58d68497a4 | ||
|
|
bddcf42a54 | ||
|
|
6318f4e7ac | ||
|
|
0c6cced7ee | ||
|
|
725f471a6a | ||
|
|
0b01a79d9d | ||
|
|
2653ff6536 | ||
|
|
0f30cc8e59 | ||
|
|
e3879cd4d1 | ||
|
|
7a4cdf8688 | ||
|
|
925bf47c9e | ||
|
|
8472b991ff | ||
|
|
ed59c32d96 | ||
|
|
b1981d7499 | ||
|
|
8983dfea57 | ||
|
|
5231b9b22b | ||
|
|
55846a2314 | ||
|
|
1c94f5749d | ||
|
|
90bacd9d31 | ||
|
|
0053cbf782 | ||
|
|
5d120a79e8 | ||
|
|
3389569ea0 | ||
|
|
f546606de0 | ||
|
|
fef95b3aae | ||
|
|
5ba2b72439 | ||
|
|
4bb849f7c9 | ||
|
|
21b5e7e701 | ||
|
|
34a1965497 | ||
|
|
1701682636 | ||
|
|
5d826972f1 | ||
|
|
c92567d4fa | ||
|
|
2467b336e5 | ||
|
|
1839bf938a | ||
|
|
4f78414c7f | ||
|
|
4532714bae | ||
|
|
352c23b0ba | ||
|
|
8e432ee818 | ||
|
|
47bb2d24f5 | ||
|
|
f3fd4c607d | ||
|
|
44d4096a79 | ||
|
|
0610ceafdf | ||
|
|
41280c9d38 | ||
|
|
032fcdce40 | ||
|
|
636bacd637 | ||
|
|
df3c76fa72 | ||
|
|
cea4157402 | ||
|
|
3f3fbd8bbc | ||
|
|
955e88b4fb | ||
|
|
5954b552c9 | ||
|
|
aaad4c5d20 | ||
|
|
a24c8526ea | ||
|
|
a533535520 | ||
|
|
badded3aa4 | ||
|
|
3055e612d4 | ||
|
|
525cb1a2b6 | ||
|
|
4dd70abc3b | ||
|
|
2ea4c214df | ||
|
|
0a0174a79d | ||
|
|
3db031be1b | ||
|
|
7c54adec9d | ||
|
|
68abd91fc2 | ||
|
|
4d2e42d244 | ||
|
|
6d3a87fe7d | ||
|
|
8cfd2cdd79 | ||
|
|
9e874e076f | ||
|
|
28192bf184 | ||
|
|
5a87a6c502 | ||
|
|
a54957b4de | ||
|
|
f4b1a076b7 | ||
|
|
d8ca15ceb3 | ||
|
|
a17f718517 | ||
|
|
3589dda8ee | ||
|
|
21f8e4d55b | ||
|
|
811e0123c9 | ||
|
|
47c4516060 | ||
|
|
27a3296d6e | ||
|
|
1aaaee128f | ||
|
|
15a16a2c35 | ||
|
|
db23fe5a58 | ||
|
|
620c88b615 | ||
|
|
29ce3bd05e | ||
|
|
b3d58f4f0c | ||
|
|
99f2fb9764 | ||
|
|
d5a3e67dbd | ||
|
|
55ef81f3e7 | ||
|
|
41699fab1e | ||
|
|
32a1195157 | ||
|
|
f53db2ddfa | ||
|
|
e060f9172b | ||
|
|
4adef88e61 | ||
|
|
d734f2cf89 | ||
|
|
3e81d14bd8 | ||
|
|
e88a94d9e0 | ||
|
|
f4f16e4e87 | ||
|
|
6268f3a3d9 | ||
|
|
06e7c8d19a | ||
|
|
32395232ea | ||
|
|
65d6ef91ff | ||
|
|
4aecc875d1 | ||
|
|
0e649a626c | ||
|
|
5fa249b0f3 | ||
|
|
24ca86aad3 | ||
|
|
8a4f413289 | ||
|
|
6dbad4501d | ||
|
|
9ab6490fee | ||
|
|
a413efa550 | ||
|
|
cd337d444c | ||
|
|
45e1ce0a42 | ||
|
|
e5ef1e6efe | ||
|
|
b1ce3be3d2 | ||
|
|
e13ab73a29 | ||
|
|
aede952b12 | ||
|
|
acc1476b29 | ||
|
|
138bf56624 | ||
|
|
c608de4183 | ||
|
|
ccb6c02c31 | ||
|
|
5cc457b28c | ||
|
|
a353b3d40d | ||
|
|
6f7aca8e5b | ||
|
|
13913334b6 | ||
|
|
7f60725c88 | ||
|
|
d55fb36182 | ||
|
|
41205aef20 | ||
|
|
aeadbc1d58 | ||
|
|
bd12ade426 | ||
|
|
92b0d4561e | ||
|
|
f9c26089cd | ||
|
|
7ddb57078c | ||
|
|
ef8b8346dc | ||
|
|
058058a015 | ||
|
|
3e7f1275d8 | ||
|
|
e963938016 | ||
|
|
fddba7315a | ||
|
|
a5e964ea19 | ||
|
|
3d2152e559 | ||
|
|
50f9c68c26 | ||
|
|
b40207b367 | ||
|
|
6c9305d2b1 | ||
|
|
9fda3c911d | ||
|
|
473c3601ef | ||
|
|
fde8a3720d | ||
|
|
13a6d6b458 | ||
|
|
312fcea5f1 | ||
|
|
29d9ba0446 | ||
|
|
9d05653f5b | ||
|
|
644ebd0a4f | ||
|
|
1033bfcfe5 | ||
|
|
71e271774e | ||
|
|
c9db49e255 | ||
|
|
22f35f0e86 | ||
|
|
d93d234c71 | ||
|
|
7fe9ae8a04 | ||
|
|
375f3ac3ac | ||
|
|
87cf1ed7cb | ||
|
|
a0ba5c8a57 | ||
|
|
b60a02bc34 | ||
|
|
d7208a15d9 | ||
|
|
debde0c67a | ||
|
|
5a4d821c98 | ||
|
|
cd0305c71d | ||
|
|
371459ff5e | ||
|
|
5a8a7c6a0f | ||
|
|
69db541300 | ||
|
|
94949866ee | ||
|
|
97db55156a | ||
|
|
9d3477d465 | ||
|
|
c22b3e7449 | ||
|
|
096dde922b | ||
|
|
00f26d854f | ||
|
|
6c8ff1717e | ||
|
|
c7288c1d8a | ||
|
|
2e52fe369d | ||
|
|
df3430add5 | ||
|
|
7af848c94b | ||
|
|
f57c462b5f | ||
|
|
6018035908 | ||
|
|
c8b0351786 | ||
|
|
26cc812f82 | ||
|
|
67f98950e6 | ||
|
|
8ba8537b9f | ||
|
|
a7f05a68e0 | ||
|
|
a0db228154 | ||
|
|
eec6fabe58 | ||
|
|
501c038f97 | ||
|
|
e0a0f717fd | ||
|
|
4dd3f7487c | ||
|
|
99d1cddaa5 | ||
|
|
2158e1a47e | ||
|
|
059238759a | ||
|
|
031af000e6 | ||
|
|
0512fac3aa | ||
|
|
8d3ea7548a | ||
|
|
221b411b63 | ||
|
|
4272e8196a | ||
|
|
140f9d05df | ||
|
|
9222733243 | ||
|
|
5838c56c4e | ||
|
|
e2c173990f | ||
|
|
a609a8d5d6 | ||
|
|
1814e0a260 | ||
|
|
711c5781e6 | ||
|
|
a688310b95 | ||
|
|
c5c2afddc2 | ||
|
|
409d87f210 | ||
|
|
e3ffc8784e | ||
|
|
bb35fc3801 | ||
|
|
c804630576 | ||
|
|
e5f3ca1623 | ||
|
|
0880787d68 | ||
|
|
cd582e2e3a | ||
|
|
aebd9319f5 | ||
|
|
de6cbb0f45 | ||
|
|
e14dcd0184 | ||
|
|
17ef653903 | ||
|
|
f5d5b5efc0 | ||
|
|
59dbee8f28 | ||
|
|
4db6971cc4 | ||
|
|
71482bd06c | ||
|
|
c3acf8341b | ||
|
|
1bc48fbf96 | ||
|
|
d45348c167 | ||
|
|
22caa0ee66 | ||
|
|
e6e8ccc855 | ||
|
|
d78522f5e1 | ||
|
|
3da2a618b9 | ||
|
|
047fa5b2db | ||
|
|
c763794ef3 | ||
|
|
7a4dcd52c4 | ||
|
|
e8e7a92131 | ||
|
|
7e8c2211d8 | ||
|
|
99694161e1 | ||
|
|
78baa4b01e | ||
|
|
b41c66c4af | ||
|
|
d6b7388c2e | ||
|
|
b0dc681d48 | ||
|
|
c20b460f2d | ||
|
|
cd0a46fd7f | ||
|
|
0a9c868678 | ||
|
|
027d1e8cb1 | ||
|
|
a5c9880318 | ||
|
|
f0858b7d93 | ||
|
|
3af6c28ab0 | ||
|
|
5c31c7f14c | ||
|
|
e09988e1d7 | ||
|
|
21a1629dfa | ||
|
|
7644c626c8 | ||
|
|
2c91b73016 | ||
|
|
2610a9c777 | ||
|
|
58cf611497 | ||
|
|
ae54b8eba8 | ||
|
|
00f944f3f4 | ||
|
|
1269411771 | ||
|
|
d4d8ea6cf2 | ||
|
|
160522c520 | ||
|
|
7024b5ec1b | ||
|
|
5b020035d6 | ||
|
|
fcea7fd4bf | ||
|
|
37e5bcad61 | ||
|
|
20679a62fd | ||
|
|
bb5a5bf2ed | ||
|
|
c1db993b92 | ||
|
|
61631e405b | ||
|
|
c19916ff1c | ||
|
|
6fa2e79c1c | ||
|
|
185e0849b1 | ||
|
|
f48b9d364b | ||
|
|
e4f1a7d4c1 | ||
|
|
e02f19ff67 | ||
|
|
72a2110845 | ||
|
|
9baa415249 | ||
|
|
22b840af14 | ||
|
|
61f32d89ca | ||
|
|
3c7da93dfc | ||
|
|
5831616fac | ||
|
|
d7b6d9f124 | ||
|
|
6e7588e9fc | ||
|
|
03cc8248bc | ||
|
|
068df6f2b1 | ||
|
|
0966ba909b | ||
|
|
47bcaa8659 | ||
|
|
245978e2b3 | ||
|
|
3aae60bde9 | ||
|
|
73dc6fb050 | ||
|
|
7941a24d51 | ||
|
|
a4ced510c6 | ||
|
|
91d36122eb | ||
|
|
e004ba63f8 | ||
|
|
40d9fe873c | ||
|
|
d06fe4a7c7 | ||
|
|
36c1e2cc73 | ||
|
|
4a0a09ba3e | ||
|
|
52d71e5c4a | ||
|
|
1f30a19566 | ||
|
|
51f4578a41 | ||
|
|
bd3954a5f1 | ||
|
|
94967add7c | ||
|
|
d86c2b64f2 | ||
|
|
783ab0b611 | ||
|
|
84449f4e2e | ||
|
|
04b44cff2b | ||
|
|
8309755ee3 | ||
|
|
41a75d404c | ||
|
|
8eb63de201 | ||
|
|
1dec134a6b | ||
|
|
6f6a8e4bb1 | ||
|
|
87d216c578 | ||
|
|
bb0ee61870 | ||
|
|
653a9526f5 | ||
|
|
34ac4b25af | ||
|
|
c7b7f9236f | ||
|
|
881779744f | ||
|
|
ddf3356b5d | ||
|
|
94e8f3e2c1 | ||
|
|
2c4a7f48d1 | ||
|
|
af47c23ca1 | ||
|
|
326a001c57 | ||
|
|
fe9e548e89 | ||
|
|
e58ef1f436 | ||
|
|
f249fa6f65 | ||
|
|
68c6b63c9c | ||
|
|
a249597225 | ||
|
|
4906c677af | ||
|
|
2534a9f14a | ||
|
|
5488c2bdeb | ||
|
|
835dbac81a | ||
|
|
e072ff2d77 | ||
|
|
41dfbc2709 | ||
|
|
964e461597 | ||
|
|
ef2eec4c4a | ||
|
|
bf1d76d853 | ||
|
|
0682cbd554 | ||
|
|
f5191cdd42 | ||
|
|
4d190b91a5 | ||
|
|
c4cddca84a | ||
|
|
b1c73208c5 | ||
|
|
ab221a465b | ||
|
|
bfe9598ce4 | ||
|
|
4ecfa0477d | ||
|
|
bab2de36ad | ||
|
|
3421222c2f | ||
|
|
3ca95feb7c | ||
|
|
903bc364ba | ||
|
|
16fd498c29 | ||
|
|
ca45776739 | ||
|
|
c849f06ce8 | ||
|
|
77aa74e9c3 | ||
|
|
8dc0a92c52 | ||
|
|
30b7cfb53d | ||
|
|
0caeb71603 | ||
|
|
a40ad2eab9 | ||
|
|
1fba0cd31f | ||
|
|
e6ce672bc5 | ||
|
|
1418f0b697 | ||
|
|
81aa972108 | ||
|
|
c36ac49cca | ||
|
|
5bf069f307 | ||
|
|
f479e914bb | ||
|
|
45441653f6 | ||
|
|
0303558ae1 | ||
|
|
b70e0e3e2b | ||
|
|
5e0c4d7b7a | ||
|
|
6c83308451 | ||
|
|
eeb898179e | ||
|
|
0ea662d8fe | ||
|
|
ea3219fa10 | ||
|
|
fb9203d396 | ||
|
|
23e7542871 | ||
|
|
a40832dffd | ||
|
|
5ba7493613 | ||
|
|
e7b406c127 | ||
|
|
dd1d16f91c | ||
|
|
82e2a19749 | ||
|
|
b73126e6c1 | ||
|
|
cbd93f450e | ||
|
|
35c64be3d7 | ||
|
|
1837d3d291 | ||
|
|
96ea70c027 | ||
|
|
ea277d0579 | ||
|
|
10d7cd1520 | ||
|
|
9051322338 | ||
|
|
d26b6103b5 | ||
|
|
f2e7963e1f | ||
|
|
8fe3a788d7 | ||
|
|
a3d7e541d3 | ||
|
|
4617025bd4 | ||
|
|
0693e19605 | ||
|
|
62618acfed | ||
|
|
1feaa43d2e | ||
|
|
92d7d61926 | ||
|
|
265d77d776 | ||
|
|
c622f9a295 | ||
|
|
48d9fde3b6 | ||
|
|
ba72a48e02 | ||
|
|
b1bd74c5b7 | ||
|
|
a9ea1a02ed | ||
|
|
8f3a5780a9 | ||
|
|
177143b57c | ||
|
|
36dcfc1517 | ||
|
|
19cd5c8881 | ||
|
|
cdb9c661bd | ||
|
|
c3a01c240b | ||
|
|
50d8cb0b5d | ||
|
|
e2f748e63d | ||
|
|
c7845c4009 | ||
|
|
4ab23e4303 | ||
|
|
2b42a44bc4 | ||
|
|
225d7501d3 | ||
|
|
ab7af6a254 | ||
|
|
968f1027a7 | ||
|
|
46258d5481 | ||
|
|
250eff22b5 | ||
|
|
ec73dca5c4 | ||
|
|
e66e11d9e8 | ||
|
|
61d4f740b0 | ||
|
|
f93d756190 | ||
|
|
e93a9ba7ba | ||
|
|
5e90912b0c | ||
|
|
64a0e2d951 | ||
|
|
76e41067da | ||
|
|
906a9bda11 | ||
|
|
340ab06825 | ||
|
|
2fd0a76142 | ||
|
|
e457d95b7e | ||
|
|
274f401d92 | ||
|
|
e60f009ea2 | ||
|
|
cc2b660dfc | ||
|
|
b3e264aa33 | ||
|
|
857bd4d932 | ||
|
|
f784162da8 | ||
|
|
52fa4f11ac | ||
|
|
bfcabd30c5 | ||
|
|
095ea470a1 | ||
|
|
c9b502c72b | ||
|
|
9390eacb7c | ||
|
|
f193ce87bf | ||
|
|
f6b3f898de | ||
|
|
de5ba5d0d3 | ||
|
|
6030de647e | ||
|
|
0b09d672d2 | ||
|
|
d045b1af9b | ||
|
|
b3a2e21bc8 | ||
|
|
328ade2f0a | ||
|
|
1dd1a25b31 | ||
|
|
6458c0dde9 | ||
|
|
4bdcefca8f | ||
|
|
62399f78b9 | ||
|
|
26e364a5d6 | ||
|
|
de011857be | ||
|
|
8bc9880951 | ||
|
|
a51cd95c60 | ||
|
|
013ae0e254 | ||
|
|
90acba21ab | ||
|
|
130024c18d | ||
|
|
02f7e77b48 | ||
|
|
a97cd91950 | ||
|
|
fd543ca614 | ||
|
|
6330eac5f8 | ||
|
|
39bc6bff2f | ||
|
|
5012adf8f9 | ||
|
|
a27f91d8f2 | ||
|
|
39c206be91 | ||
|
|
d19d297ea4 | ||
|
|
cfc8cbd08b | ||
|
|
c539dd5570 | ||
|
|
de76afea99 | ||
|
|
32cd323b54 | ||
|
|
1d3616ae71 | ||
|
|
d76cb440f9 | ||
|
|
7c89d658f7 | ||
|
|
292c929117 | ||
|
|
e0af48955a | ||
|
|
08a334812b | ||
|
|
daf42b63c8 | ||
|
|
07da03618f | ||
|
|
56fc278c73 | ||
|
|
d52f168e09 | ||
|
|
dda51f2801 | ||
|
|
25472bcfa6 | ||
|
|
3c9026ce83 | ||
|
|
67577d8ec5 | ||
|
|
edc5fd9500 | ||
|
|
8af0272588 | ||
|
|
c6ec04bcf6 | ||
|
|
7ef41adc26 | ||
|
|
a161b63663 | ||
|
|
5b65a31d24 | ||
|
|
6f4115d160 | ||
|
|
b5de07de9d | ||
|
|
5bec09cfdc | ||
|
|
c3a8a89c61 | ||
|
|
e1a0988440 | ||
|
|
115dfb58f6 | ||
|
|
8e689e9e9e | ||
|
|
ff0e79536a | ||
|
|
34c53f5ba4 | ||
|
|
15c5fc7e4b | ||
|
|
fe7c8679b9 | ||
|
|
75840445c5 | ||
|
|
2aa7448f76 | ||
|
|
0f7a0f77f2 | ||
|
|
0771ffeb71 | ||
|
|
f410403107 | ||
|
|
74e9c86b61 | ||
|
|
712ea98e41 | ||
|
|
849f5bcd0e | ||
|
|
22a36dc6a8 | ||
|
|
f02c19f637 | ||
|
|
cafc82c3a5 | ||
|
|
9bc2f4100f | ||
|
|
c9735c034f | ||
|
|
a455af71af | ||
|
|
c5a90545c8 | ||
|
|
7da7904093 | ||
|
|
bd7653f682 | ||
|
|
30335a1ce9 | ||
|
|
c6f1250abc | ||
|
|
4c495f3828 | ||
|
|
6ff17d16f0 | ||
|
|
06b7116692 | ||
|
|
3c3ea0f3e1 | ||
|
|
c31fbc723d | ||
|
|
60e11055d2 | ||
|
|
fbbc765460 | ||
|
|
db4d6511d6 | ||
|
|
6e42a67268 | ||
|
|
fd066e5eef | ||
|
|
3dd0c44410 | ||
|
|
12b42854e4 | ||
|
|
2fcb6d0c7c | ||
|
|
68e863723a | ||
|
|
4e759eaa92 | ||
|
|
60e6dfb8e5 | ||
|
|
cf33726652 | ||
|
|
d0b37d0f9a | ||
|
|
a0a1353445 | ||
|
|
eb87c7c591 | ||
|
|
902d137d8e | ||
|
|
0a04d43514 | ||
|
|
07e0a68249 | ||
|
|
5ede3e18fb | ||
|
|
c1e8e0c84c | ||
|
|
dbb980cd45 | ||
|
|
aab7c5c398 | ||
|
|
8916b5db54 | ||
|
|
ed2ce4b999 | ||
|
|
0cfbc31241 | ||
|
|
6725cc6f61 | ||
|
|
7e9639052b | ||
|
|
21bd5ba376 | ||
|
|
28d5fb1822 | ||
|
|
cd3c031df1 | ||
|
|
a6db0f6fd9 | ||
|
|
c80f6e8285 | ||
|
|
c6d779853a | ||
|
|
1368b747be | ||
|
|
1b720a504c | ||
|
|
72f8854a7a | ||
|
|
097d195f00 | ||
|
|
807da8f696 | ||
|
|
a8ca6b6fcb | ||
|
|
85e2e14c81 | ||
|
|
92d44f4061 | ||
|
|
f280717cb3 | ||
|
|
fdb3ff0afd | ||
|
|
5ae45ddd55 | ||
|
|
66dde2fb36 | ||
|
|
7ffcd3282b | ||
|
|
4e0a3da01e | ||
|
|
541a99bbc5 | ||
|
|
f0a3fb4cbb | ||
|
|
416417dfc6 | ||
|
|
f62008aba4 | ||
|
|
74f7415f84 | ||
|
|
1e1e079b65 | ||
|
|
0b4f808b2d | ||
|
|
ae4af99c59 | ||
|
|
0b17556fa4 | ||
|
|
e6ebc347e5 | ||
|
|
f2323a9d19 | ||
|
|
ce53fe5e31 | ||
|
|
f1d359b3e7 | ||
|
|
da99f3bc2a | ||
|
|
acc4130347 | ||
|
|
fec8dd74af | ||
|
|
69cf3c99f4 | ||
|
|
f598e0d0d5 | ||
|
|
656d2494b0 | ||
|
|
6d07d58f37 | ||
|
|
3c11444302 | ||
|
|
dd5270f620 | ||
|
|
216f895953 | ||
|
|
6acb87b7ea | ||
|
|
acdccd697c | ||
|
|
cecc4b1f6d | ||
|
|
f93f115e13 | ||
|
|
dd32ded29b | ||
|
|
effa95fb31 | ||
|
|
dc46475e4e | ||
|
|
debcf086b5 | ||
|
|
c6db974962 | ||
|
|
e9b0b0c42e | ||
|
|
ebee1a02fd | ||
|
|
8b81de1141 | ||
|
|
cf0fcad340 | ||
|
|
a769906330 | ||
|
|
d49a935598 | ||
|
|
522d02d529 | ||
|
|
7246e48428 | ||
|
|
3a847c9115 | ||
|
|
db3006acaf | ||
|
|
03a7de8fe7 | ||
|
|
67e0c5af02 | ||
|
|
6658077bda | ||
|
|
929fce6adb | ||
|
|
cd1fc7308e | ||
|
|
c0a5e9fdcc | ||
|
|
a3e6a580d9 | ||
|
|
5d01c9f56a | ||
|
|
9cf291f5a3 | ||
|
|
d8738ae581 | ||
|
|
4a4effe5cf | ||
|
|
a2a2f5541f | ||
|
|
499e3c3456 | ||
|
|
b66187a24f | ||
|
|
f2615e93b7 | ||
|
|
c722dc9328 | ||
|
|
27a45d6b8c | ||
|
|
46849590c5 | ||
|
|
c9e7e4af8f | ||
|
|
28887d68c2 | ||
|
|
3322a90320 | ||
|
|
3d679d3810 | ||
|
|
b52269ab34 | ||
|
|
8632cc2ff0 | ||
|
|
f42faf8e97 | ||
|
|
567de44508 | ||
|
|
a6d2505211 | ||
|
|
e3d641b999 | ||
|
|
d0f88db388 | ||
|
|
14de6b0075 | ||
|
|
0092edc16f | ||
|
|
04de57cf9f | ||
|
|
d15a46bd15 | ||
|
|
2e992dca67 | ||
|
|
57dbbaad78 | ||
|
|
3ec6cd7fee | ||
|
|
049e5ac6ac | ||
|
|
2ead2465c8 | ||
|
|
e3ce6c05bb | ||
|
|
730c9fcec8 | ||
|
|
85925c027a | ||
|
|
9256e5c3ea | ||
|
|
44f4c3a22d | ||
|
|
fa390f4374 | ||
|
|
a282acd137 | ||
|
|
8bd167033f | ||
|
|
4afcf4900a | ||
|
|
4a8c47dffb | ||
|
|
fada93bae3 | ||
|
|
5d6ae5ce5e | ||
|
|
db42fcc583 | ||
|
|
e904714202 | ||
|
|
0ca59704f9 | ||
|
|
c7865613e1 | ||
|
|
eb4dfd9dde | ||
|
|
28eb595a56 | ||
|
|
037091f155 | ||
|
|
eecffb1782 | ||
|
|
912f5294d6 | ||
|
|
f6e410e461 | ||
|
|
ddddebfe27 | ||
|
|
57930e2c90 | ||
|
|
81238c78fe | ||
|
|
7e511313a3 | ||
|
|
56f4f1ca03 | ||
|
|
b25ef4bcc3 | ||
|
|
aaeac9c6eb | ||
|
|
8bccb82f5d | ||
|
|
b7437d6a74 | ||
|
|
fbd2f519e6 | ||
|
|
e1b3e67b7a | ||
|
|
dd9374fd50 | ||
|
|
c1f3b53ed7 | ||
|
|
627b11abde | ||
|
|
d68caf85d0 | ||
|
|
79857a0ed4 | ||
|
|
1688adbcbe | ||
|
|
096e722a74 | ||
|
|
9f361e441c | ||
|
|
47a5d39354 | ||
|
|
ec92b79a3d | ||
|
|
a55b6055c2 | ||
|
|
de8ad9e08a | ||
|
|
9bd662d6d1 | ||
|
|
c855fb8c6a | ||
|
|
07d5c85886 | ||
|
|
c9424f2f54 | ||
|
|
cdc0887895 | ||
|
|
6b15e866f8 | ||
|
|
5192358dce | ||
|
|
5758e1c550 | ||
|
|
2b5857affe | ||
|
|
556fadc9f5 | ||
|
|
1d04d33981 | ||
|
|
52b81ccb16 | ||
|
|
58e841e5c7 | ||
|
|
30beb81d9a | ||
|
|
8da6ac7cfb | ||
|
|
4b7effe3ee | ||
|
|
ea1ca34644 | ||
|
|
b1dbb47890 | ||
|
|
80d9cd8fa2 | ||
|
|
b50ed96f2e | ||
|
|
32f45e9ab7 | ||
|
|
2b2e07e767 | ||
|
|
bdb40f801e | ||
|
|
644a54d6fe | ||
|
|
28bbe17822 | ||
|
|
79344c2793 | ||
|
|
da6c18e45b | ||
|
|
de05139dfc | ||
|
|
f0de0514bf | ||
|
|
c48429888e | ||
|
|
e96486e130 | ||
|
|
3058e37d45 | ||
|
|
e88d0579b0 | ||
|
|
169241875b | ||
|
|
cc0f9acccd | ||
|
|
b36c2f1729 | ||
|
|
ea6df8b653 | ||
|
|
5564e4daa2 | ||
|
|
4742cd4a03 | ||
|
|
99985f4fab | ||
|
|
42bb3b5aca | ||
|
|
70bedaf8dd | ||
|
|
e720f6449d | ||
|
|
38683a7fea | ||
|
|
ae1a68500c | ||
|
|
578f842eed | ||
|
|
a7dea95f90 | ||
|
|
1080562d96 | ||
|
|
b8cf5a2347 | ||
|
|
e9706d605a | ||
|
|
4b338c56b5 | ||
|
|
abb2039312 | ||
|
|
7e69c0b7be | ||
|
|
379c1bbd3d | ||
|
|
6fd41b15dc | ||
|
|
b240562356 | ||
|
|
44fd81773d | ||
|
|
6d529a7498 | ||
|
|
c5e7e0b3fb | ||
|
|
576bfed15f | ||
|
|
2471b4b155 | ||
|
|
238339373b | ||
|
|
da0218a3ce | ||
|
|
e44072e5a7 | ||
|
|
5d2bbb61f8 | ||
|
|
96dcd90005 | ||
|
|
b749122076 | ||
|
|
ccde455de1 | ||
|
|
a980513cba | ||
|
|
7d5cd8b00f | ||
|
|
a7c70b0b50 | ||
|
|
b5a995656d | ||
|
|
8b4c7ff521 | ||
|
|
c243fbc011 | ||
|
|
493e4497c8 | ||
|
|
84967b717c | ||
|
|
21493424fe | ||
|
|
2f73d528f8 | ||
|
|
b91f6314bd | ||
|
|
92aefa79e3 | ||
|
|
411e5dc35a | ||
|
|
0159fffab9 | ||
|
|
c98c2f93e2 | ||
|
|
1d2cacbb02 | ||
|
|
2d57958f6f | ||
|
|
88c36aa272 | ||
|
|
05ae37cb4d | ||
|
|
96fdaff82a | ||
|
|
07b64465c6 | ||
|
|
366e9be4de | ||
|
|
261c9e2240 | ||
|
|
c03973867c | ||
|
|
ca6984f4a5 | ||
|
|
4fbc2680ba | ||
|
|
9a5b0a8104 | ||
|
|
ad998f7a63 | ||
|
|
91043e4b52 | ||
|
|
8f3bd0145b | ||
|
|
ace0051147 | ||
|
|
83720c6673 | ||
|
|
f1ce4de1eb | ||
|
|
013b23c918 | ||
|
|
d03debf59c | ||
|
|
00b55d893a | ||
|
|
085b92df9c | ||
|
|
8516ff7cb3 | ||
|
|
56d64d8adc | ||
|
|
5d68e48312 | ||
|
|
8b0be0a8c5 | ||
|
|
d6e4d6d927 | ||
|
|
bbfe60ffd2 | ||
|
|
c9cc0b5ce3 | ||
|
|
f0bf19f286 | ||
|
|
6492e55954 | ||
|
|
c9fd1d5833 | ||
|
|
e8f73cae6c | ||
|
|
7d436b40d0 | ||
|
|
55cd6d2a74 | ||
|
|
01a2585edf | ||
|
|
2974a96e96 | ||
|
|
ab7fd3d019 | ||
|
|
54c5659496 | ||
|
|
8c0811885f | ||
|
|
291570dfd7 | ||
|
|
f6b9b4cc19 | ||
|
|
a06403ab7c | ||
|
|
e64a95d1d7 | ||
|
|
6939e49643 | ||
|
|
bb18586484 | ||
|
|
09b39a4bf9 | ||
|
|
1d7d639654 | ||
|
|
42ec509574 | ||
|
|
dcef864c1c | ||
|
|
e8cb4f90f4 | ||
|
|
4e0b2e4f77 | ||
|
|
a2bcadeb7c | ||
|
|
84a4242e27 | ||
|
|
6373d667d9 | ||
|
|
7840d601e1 | ||
|
|
1893061c0d | ||
|
|
0289cc3ee5 | ||
|
|
bb329b73ef | ||
|
|
9b4008f39c | ||
|
|
ef52f20993 | ||
|
|
f2a207e790 | ||
|
|
40f502492b | ||
|
|
c5f1cf94ac | ||
|
|
2e286d4a50 | ||
|
|
94a27fa79e | ||
|
|
0adec1dbe2 | ||
|
|
c38c53957d | ||
|
|
a35c9d2d9e | ||
|
|
7f739a1371 | ||
|
|
62df78f329 | ||
|
|
498eb0134e | ||
|
|
d34f9182c2 | ||
|
|
324f21cf3d | ||
|
|
200c0110fd | ||
|
|
5694b0054b | ||
|
|
8825fdcdaf | ||
|
|
7805bc172e | ||
|
|
aa321b4b22 | ||
|
|
c74df7abc5 | ||
|
|
c6ffe8978d | ||
|
|
6761e0df15 | ||
|
|
cc47225f24 | ||
|
|
58c47a325f | ||
|
|
706f7f3b7b | ||
|
|
4d67f8bd0b | ||
|
|
d5227e00ff | ||
|
|
62fa1d570c | ||
|
|
be4511d95b | ||
|
|
b17e6058d1 | ||
|
|
899b4ab29a | ||
|
|
a2801f0b7b | ||
|
|
84694fedef | ||
|
|
99c28a184f | ||
|
|
7ed9adaf49 | ||
|
|
c0005741bd | ||
|
|
150a341510 | ||
|
|
c3ef051657 | ||
|
|
ba149efa4a | ||
|
|
e30a7b3849 | ||
|
|
97ad0483ec | ||
|
|
3981c772a2 | ||
|
|
e762002560 | ||
|
|
061d8dc94f | ||
|
|
e486713026 | ||
|
|
0201dfa8e3 | ||
|
|
78269a1b7b | ||
|
|
d1bf60ab17 | ||
|
|
6c368dc8cb | ||
|
|
10ac67c1e0 | ||
|
|
ba3b38d941 | ||
|
|
47044d93d3 | ||
|
|
423ac4ea04 | ||
|
|
b114b40f88 | ||
|
|
030ce18d65 | ||
|
|
44116b3559 | ||
|
|
78332c7bfd | ||
|
|
dd8ac28240 | ||
|
|
81818222e5 | ||
|
|
4a25af03f4 | ||
|
|
6515d73534 | ||
|
|
006fc9acd3 | ||
|
|
1aa878b3a6 | ||
|
|
23dc475905 | ||
|
|
84e6228f90 | ||
|
|
a827ab6ffd | ||
|
|
f55784ce6a | ||
|
|
f7110ac472 | ||
|
|
52a94e0f47 | ||
|
|
c25eb678a8 | ||
|
|
5128efbbf4 | ||
|
|
c73ee3c531 | ||
|
|
54ba67f882 | ||
|
|
395bfe6eb5 | ||
|
|
e0ecf65aac | ||
|
|
a7c651c98c | ||
|
|
ed473f457a | ||
|
|
a572c1132d | ||
|
|
ba314c7135 | ||
|
|
a0788ab050 | ||
|
|
8885f0be10 | ||
|
|
9d433ed1d0 | ||
|
|
0125c9445e | ||
|
|
a3454d4143 | ||
|
|
ad3c224b10 | ||
|
|
43d186d464 | ||
|
|
a3671e776d | ||
|
|
862ce07f8d | ||
|
|
a78bc7d195 | ||
|
|
b0ce4404ea | ||
|
|
cd5641d2f3 | ||
|
|
51dd9f0419 | ||
|
|
6d0a76756d | ||
|
|
6e8342fbf4 | ||
|
|
8d227724d7 | ||
|
|
eab91ffa83 | ||
|
|
6488198a06 | ||
|
|
07b4c67b5c | ||
|
|
70077a1eac | ||
|
|
03763a6556 | ||
|
|
3cb8d77977 | ||
|
|
c8d7940451 | ||
|
|
2253aa1229 | ||
|
|
d5a16855fb | ||
|
|
1aec909c10 | ||
|
|
7b60980959 | ||
|
|
097424e2ee | ||
|
|
a99b17d240 | ||
|
|
7526230b69 | ||
|
|
6b8f9a6319 | ||
|
|
8e74556613 | ||
|
|
26a3086b81 | ||
|
|
6dd70137db | ||
|
|
94ab475a31 | ||
|
|
e77b6f3b85 | ||
|
|
4000b44d90 | ||
|
|
ad09d98d81 | ||
|
|
567d5e7676 | ||
|
|
123b0a331e | ||
|
|
11f1f3d132 | ||
|
|
a44ce0c538 | ||
|
|
301cc22985 | ||
|
|
23348c5d8c | ||
|
|
176c6524a2 | ||
|
|
29398b9869 | ||
|
|
6765b0218a | ||
|
|
b7fd209987 | ||
|
|
e11f0595d8 | ||
|
|
8b65a75235 | ||
|
|
a01410f287 | ||
|
|
6e53682854 | ||
|
|
313f7e8173 | ||
|
|
d9e615e696 | ||
|
|
b526067eeb | ||
|
|
e5a19d73e1 | ||
|
|
42d72a7786 | ||
|
|
30a29b179b | ||
|
|
6a7ae710c5 | ||
|
|
7622fa88cb | ||
|
|
2f7aee02cc | ||
|
|
75848f0d6e | ||
|
|
c81c4ffc97 | ||
|
|
5bbd8e7102 | ||
|
|
f8fb69ac03 | ||
|
|
a2b703d450 | ||
|
|
25739d9f6f | ||
|
|
1b12be55b2 | ||
|
|
ae7bfa6ee2 | ||
|
|
c012149b63 | ||
|
|
0210d87573 | ||
|
|
35b8cf3769 | ||
|
|
a1bd76d5fd | ||
|
|
c0551eb5dc | ||
|
|
f9e6118bfa | ||
|
|
69052c1de9 | ||
|
|
050dd7b47c | ||
|
|
7d5e1009cb | ||
|
|
9b3b0d22f8 | ||
|
|
d2035a0609 | ||
|
|
4dcd9e3066 | ||
|
|
744cf692aa | ||
|
|
eb2a85ff1a | ||
|
|
5eaf40b84e | ||
|
|
9dc12b4b8e | ||
|
|
2a3e6a9599 | ||
|
|
3ad7d6dfed | ||
|
|
28f82e2572 | ||
|
|
89274268ea | ||
|
|
116048d7a2 | ||
|
|
9f3c97c9bc | ||
|
|
79e7c56419 | ||
|
|
d00c390e03 | ||
|
|
ce39ee7b29 | ||
|
|
df1596b785 | ||
|
|
12aaf86a8e | ||
|
|
62bca19beb | ||
|
|
5551fa6612 | ||
|
|
73ef8c8c09 | ||
|
|
da695dffb3 | ||
|
|
efad2c3461 | ||
|
|
b5cb8d3c16 | ||
|
|
e9f81a8a50 | ||
|
|
4d75cce22a | ||
|
|
4c5f4dd443 | ||
|
|
ddb8d1d8f6 | ||
|
|
0da59a8339 | ||
|
|
4323bc8c11 | ||
|
|
90a69bd063 | ||
|
|
d55332d999 | ||
|
|
aac3a02a89 | ||
|
|
6c79b74657 | ||
|
|
bf79f13689 | ||
|
|
fa3cb5d725 | ||
|
|
b48e40e5ab | ||
|
|
f4d5b30e85 | ||
|
|
2fcf590355 | ||
|
|
6f29ee74da | ||
|
|
70ed981957 | ||
|
|
04dbcb05bd | ||
|
|
b649d507df | ||
|
|
803abf4448 | ||
|
|
de92dbdbdd | ||
|
|
be28fdcd9f | ||
|
|
5b840b41fe | ||
|
|
678064baba | ||
|
|
526efcae14 | ||
|
|
b2b5d95046 | ||
|
|
ce3661e4c9 | ||
|
|
920ea27d26 | ||
|
|
29b32f60a4 | ||
|
|
c13297b409 | ||
|
|
35d75399a9 | ||
|
|
68cdd46f37 | ||
|
|
742fda31e6 | ||
|
|
4a99f13c4a | ||
|
|
7627c6f7c6 | ||
|
|
1609cdaf31 | ||
|
|
c71848d07b | ||
|
|
467681160d | ||
|
|
920e2a733e | ||
|
|
cf38c70023 | ||
|
|
38bcb13f80 | ||
|
|
0b03b19e4c | ||
|
|
db89dc55a4 | ||
|
|
6bdf474195 | ||
|
|
5f750837ee | ||
|
|
95581faaef | ||
|
|
e2a5dbc8f0 | ||
|
|
4c875eaac9 | ||
|
|
61958fb540 | ||
|
|
41e578f0fd | ||
|
|
7138819927 | ||
|
|
7c35b589a8 | ||
|
|
20212a9b89 | ||
|
|
a574de754d | ||
|
|
b870131a8d | ||
|
|
e0bf5ca7cc | ||
|
|
631cc3d9e6 | ||
|
|
d0d9ca9838 | ||
|
|
8225c31a54 | ||
|
|
df9274be2e | ||
|
|
5244820133 | ||
|
|
dca0f10c45 | ||
|
|
f5cafb08da | ||
|
|
7dce0bbecb | ||
|
|
4f4a675d06 | ||
|
|
71b34010bb | ||
|
|
0a838f0448 | ||
|
|
3d98b9f36c | ||
|
|
3f0a010964 | ||
|
|
a3ac80b264 | ||
|
|
15501d8d3c | ||
|
|
5b8fca23a3 | ||
|
|
3387001f35 | ||
|
|
5644d71422 | ||
|
|
c6f069181c | ||
|
|
533e55e4c7 | ||
|
|
2e288991dc | ||
|
|
4e1e2970ad | ||
|
|
c4bd53ce58 | ||
|
|
2b6dfbf69b | ||
|
|
ebec5ff54b | ||
|
|
19f14416fb | ||
|
|
373aa488b3 | ||
|
|
2eaa3985c7 | ||
|
|
86e8d7d145 | ||
|
|
84c88ad2e1 | ||
|
|
b16a4e0e49 | ||
|
|
7d2a70dd13 | ||
|
|
7dca624418 | ||
|
|
6aa712d7f4 | ||
|
|
19c4ff83af | ||
|
|
1514ae2f33 | ||
|
|
de455cc6a7 | ||
|
|
48f0e91098 | ||
|
|
7c01c46a50 | ||
|
|
4335a67113 | ||
|
|
0ea96ca2e8 | ||
|
|
d039bd4caa | ||
|
|
210de2a440 | ||
|
|
c1cfd4d6db | ||
|
|
1f1f7610db | ||
|
|
09fef67aca | ||
|
|
d17a163570 | ||
|
|
6eca471b0d | ||
|
|
2b16bdce33 | ||
|
|
5fe6610cd9 | ||
|
|
6460d5cf6b | ||
|
|
6785cdc494 | ||
|
|
39bf7f3d0f | ||
|
|
475750074a | ||
|
|
9cee41675d | ||
|
|
f66bd0f390 | ||
|
|
ba35049897 | ||
|
|
ff3315573f | ||
|
|
0469992ae8 | ||
|
|
c3d3ad57c2 | ||
|
|
942dd3d240 | ||
|
|
c8a00a76b8 | ||
|
|
ed5b099893 | ||
|
|
612271d2d0 | ||
|
|
f8b2623dc8 | ||
|
|
4a6664d9a1 | ||
|
|
66149581dc | ||
|
|
b1df71d2d8 | ||
|
|
afb807b66b | ||
|
|
9c8ffcb1f8 | ||
|
|
42957b1e59 | ||
|
|
4002ad87ea | ||
|
|
adcd799253 | ||
|
|
c9d91a5232 | ||
|
|
d10957709a | ||
|
|
c4fb4c2d7c | ||
|
|
d01fb34df0 | ||
|
|
a8b5d64213 | ||
|
|
586bedd484 | ||
|
|
2359c5a7d4 | ||
|
|
823691c26b | ||
|
|
1dd83dbc37 | ||
|
|
24f4627161 | ||
|
|
3d9849e813 | ||
|
|
aaee585af5 | ||
|
|
e13e48012d | ||
|
|
532627f4c9 | ||
|
|
48dd80eb83 | ||
|
|
54e65708d1 | ||
|
|
752b3704c3 | ||
|
|
5538fc1659 | ||
|
|
c563e03731 | ||
|
|
5b9bb0f0cb | ||
|
|
8c3dd547ac | ||
|
|
f638daa773 | ||
|
|
527e3aa505 | ||
|
|
961b632908 | ||
|
|
470da11d72 | ||
|
|
09024a50e7 | ||
|
|
9cd3418d1a | ||
|
|
3f6bcff7b8 | ||
|
|
53a544d064 | ||
|
|
d1260a9310 | ||
|
|
60f6115072 | ||
|
|
825163b22f | ||
|
|
010e36444c | ||
|
|
eb1bc60d27 | ||
|
|
32dc2b198b | ||
|
|
41060bf4f3 | ||
|
|
daf58b422a | ||
|
|
d2e3f9c1ca | ||
|
|
c5479c8c4f | ||
|
|
487f4c94f4 | ||
|
|
7fa6172d71 | ||
|
|
cf5ca9f2c7 | ||
|
|
dfc5a0505d | ||
|
|
5ceaaf6b43 | ||
|
|
67d1295b41 | ||
|
|
4ce80145c0 | ||
|
|
2c8383a0aa | ||
|
|
a1b2008729 | ||
|
|
75a6d2cfaf | ||
|
|
70425d877f | ||
|
|
a31b509859 | ||
|
|
24a6187de7 | ||
|
|
5a93982533 | ||
|
|
af324ca9a8 | ||
|
|
da1927d0bc | ||
|
|
bea995fecf | ||
|
|
b10536c3fc | ||
|
|
7da25155f4 | ||
|
|
d4e4c1b2f5 | ||
|
|
7ff13332af | ||
|
|
009d451b07 | ||
|
|
5c1f593a12 | ||
|
|
5f676becf1 | ||
|
|
2d2c22a321 | ||
|
|
bf3855f04c | ||
|
|
15e87bb2da | ||
|
|
1a13c13b07 | ||
|
|
b12702cd39 | ||
|
|
e9eac2ac0f | ||
|
|
962e39faa3 | ||
|
|
6d5b9e39dc | ||
|
|
f83d586784 | ||
|
|
a1faff191d | ||
|
|
e0234b5ec7 | ||
|
|
d285121c76 | ||
|
|
d7e5cbc7c9 | ||
|
|
7cfa8ba793 | ||
|
|
3652795524 | ||
|
|
f8601a0e06 | ||
|
|
92455c2524 | ||
|
|
eee3d443fb | ||
|
|
b09b1093b6 | ||
|
|
0f10988d3e | ||
|
|
2d296a3597 | ||
|
|
8cb18c7cc6 | ||
|
|
7a7dd14abf | ||
|
|
ad65f23bc1 | ||
|
|
8de4ae9409 | ||
|
|
e6210b3c63 | ||
|
|
5de91699e6 | ||
|
|
436c98fe38 | ||
|
|
21324efdaf | ||
|
|
2d77dae6e5 | ||
|
|
4acd28eb8e | ||
|
|
2d0b51c08c | ||
|
|
b5e87ea4ba | ||
|
|
b1ab4430dd | ||
|
|
e9706207fb | ||
|
|
7f70b16b49 | ||
|
|
ca9bd9f6a7 | ||
|
|
45f633acb1 | ||
|
|
24e279886a | ||
|
|
afb4b5fcb7 | ||
|
|
4eb23a1b79 | ||
|
|
bf388787e7 | ||
|
|
7ee49cdc8d | ||
|
|
0229db584c | ||
|
|
e21455912e | ||
|
|
577ff28387 | ||
|
|
06654d2e4f | ||
|
|
6337e1685a | ||
|
|
c900e1d32f | ||
|
|
5f299aaf90 | ||
|
|
9cb8af44e0 | ||
|
|
c617f16861 | ||
|
|
32a5c74194 | ||
|
|
c7ab0719d9 | ||
|
|
efd0b7ceab | ||
|
|
004fd5e936 | ||
|
|
4a4c82bd40 | ||
|
|
cc0f0ef769 | ||
|
|
c178689927 | ||
|
|
00a628b235 | ||
|
|
76228059bf | ||
|
|
ee57492f3f | ||
|
|
4d91460bf5 | ||
|
|
c60fb54bc3 | ||
|
|
732eec5d64 | ||
|
|
bc943aecfd | ||
|
|
b8bff3e777 | ||
|
|
8480d1c91f | ||
|
|
6351ed9413 | ||
|
|
5671ca1e47 | ||
|
|
82a29c8abf | ||
|
|
fd7d2fe530 | ||
|
|
70cc26e7e5 | ||
|
|
c4bafa43b2 | ||
|
|
54899f48a4 | ||
|
|
9d1a85f315 | ||
|
|
754c27f8c8 | ||
|
|
0119d0f05e | ||
|
|
13abf00fc6 | ||
|
|
ead5103ab8 | ||
|
|
7fa9c1d228 | ||
|
|
f8e3fab5d5 | ||
|
|
cbfc40a2d8 | ||
|
|
84dcb4fc1e | ||
|
|
76a919b7bf | ||
|
|
dab9a9ed15 | ||
|
|
27094fa7ee | ||
|
|
ba8588aee0 | ||
|
|
4bd7b07f06 | ||
|
|
d95da7ae61 | ||
|
|
d79de8cead | ||
|
|
264ea26238 | ||
|
|
c8f0edd368 | ||
|
|
6acd68d8fe | ||
|
|
b5964e3bff | ||
|
|
cf6ab6b204 | ||
|
|
b042e260f9 | ||
|
|
188f602acc | ||
|
|
a987dfc422 | ||
|
|
d775606cb9 | ||
|
|
6477c0eaee | ||
|
|
9f91447c49 | ||
|
|
228040f611 | ||
|
|
40e919712c | ||
|
|
10cda83f43 | ||
|
|
48553ea909 | ||
|
|
355e3946b6 | ||
|
|
3491c111b8 | ||
|
|
6b73eda23f | ||
|
|
67516c7ab0 | ||
|
|
668c027961 | ||
|
|
d123939993 | ||
|
|
9481afc79b | ||
|
|
567ace697f | ||
|
|
34f341b8a1 | ||
|
|
8c05a78f0f | ||
|
|
48eab1985b | ||
|
|
5c30647807 | ||
|
|
64825f2f07 | ||
|
|
8d99c32e0c | ||
|
|
83124dff9f | ||
|
|
576ad5d84a | ||
|
|
4ff4aba405 | ||
|
|
41185dd64b | ||
|
|
ac91b8c513 | ||
|
|
6a8534f0e9 | ||
|
|
1d2ba4a1d4 | ||
|
|
34ff816208 | ||
|
|
3f4bfcfe36 | ||
|
|
2dc42c1503 | ||
|
|
0ef0786054 | ||
|
|
96323809cd | ||
|
|
6f0db1c54e | ||
|
|
28f8c416d7 | ||
|
|
c9f09befb7 | ||
|
|
d56ef76d85 | ||
|
|
b804550f29 | ||
|
|
b2355f9920 | ||
|
|
f2b6507d9e | ||
|
|
daafa2b478 | ||
|
|
5366479410 | ||
|
|
3fd980613d | ||
|
|
76fcd51d00 | ||
|
|
0176743587 | ||
|
|
5eb516434d | ||
|
|
2feab38403 | ||
|
|
7c0287b289 | ||
|
|
998c80ec61 | ||
|
|
af1d97732b | ||
|
|
7449b086aa | ||
|
|
e36b94b3a0 | ||
|
|
b8e1514464 | ||
|
|
239f0c8b24 | ||
|
|
fd29ae7291 | ||
|
|
fb6f85d9f4 | ||
|
|
149d2e32e9 | ||
|
|
ba52a38ae2 | ||
|
|
5b55e15287 | ||
|
|
6433e5f42e | ||
|
|
43bba98042 | ||
|
|
4bd2624db5 | ||
|
|
993fe6636b | ||
|
|
3808de66d1 | ||
|
|
73aef9e41b | ||
|
|
7bbd7b4c10 | ||
|
|
328e3b7856 | ||
|
|
909fab7622 | ||
|
|
6c6a79d660 | ||
|
|
176a59f87e | ||
|
|
096b1e4a63 | ||
|
|
1d2e3e1656 | ||
|
|
4c1df4452e | ||
|
|
6ed5680f8f | ||
|
|
193e16c59e | ||
|
|
99afaa5820 | ||
|
|
5b2b100101 | ||
|
|
bc13712414 | ||
|
|
a69be6f652 | ||
|
|
e9e8e788aa | ||
|
|
4e9a2ec277 | ||
|
|
e9e03b223f | ||
|
|
a49b68d63f | ||
|
|
98ef52baa9 | ||
|
|
39b52fe04a | ||
|
|
1f4d737765 | ||
|
|
efdc725022 | ||
|
|
8899d705c4 | ||
|
|
77f4fc32ce | ||
|
|
bf296502bc | ||
|
|
67916cff5c | ||
|
|
3fd93658e8 | ||
|
|
0e2696ad23 | ||
|
|
7143ef9a2a | ||
|
|
139a187cb7 | ||
|
|
82b645cf61 | ||
|
|
e88c09887a | ||
|
|
a4039e99c1 | ||
|
|
850cf95d3b | ||
|
|
8ecc6482b2 | ||
|
|
ec2b60ee27 | ||
|
|
d3976fd64a | ||
|
|
1efd7a73e6 | ||
|
|
b06d1edc5f | ||
|
|
b7a00941b4 | ||
|
|
f326de8c3b | ||
|
|
c39a0c983c | ||
|
|
060872cacb | ||
|
|
fda02aea84 | ||
|
|
451e96e848 | ||
|
|
45d4c7b20c | ||
|
|
cd2cdd3692 | ||
|
|
0c13928109 | ||
|
|
6be05423d8 | ||
|
|
aa5fa39d7a | ||
|
|
ebb3336da0 | ||
|
|
2792315d39 | ||
|
|
0162842b97 | ||
|
|
97812a24b4 | ||
|
|
830d7fbdb0 | ||
|
|
5f877b77ea | ||
|
|
2fa669f9c6 | ||
|
|
fc714f7d43 | ||
|
|
428dc5ff07 | ||
|
|
a0d651a5b8 | ||
|
|
84e6f71416 | ||
|
|
b38ed38297 | ||
|
|
58765763e2 | ||
|
|
3618e84c17 | ||
|
|
c29dcb9053 | ||
|
|
c4a4d95e3c | ||
|
|
21befdeb0e | ||
|
|
79ddafb594 | ||
|
|
8e060c8ae4 | ||
|
|
01321b0cf6 | ||
|
|
b57b6ac69c | ||
|
|
0de22f10c0 | ||
|
|
2e8c931fb6 | ||
|
|
0436bd1b41 | ||
|
|
7238f99d19 | ||
|
|
2d7cd2fe4e | ||
|
|
9a586c397f | ||
|
|
6f4289b3a0 | ||
|
|
382e368f2a | ||
|
|
f3e7cb3972 | ||
|
|
4530db087a | ||
|
|
7f08163eda | ||
|
|
ea79adb277 | ||
|
|
f32d42f38a | ||
|
|
565e4bdc9e | ||
|
|
f26d79dabd | ||
|
|
9e0c36d0ff | ||
|
|
74b3b6eb7d | ||
|
|
ac24219449 | ||
|
|
c6771ca2d3 | ||
|
|
0b739f1c39 | ||
|
|
5c08323321 | ||
|
|
c8f01b2b1f | ||
|
|
b04d5b4feb | ||
|
|
aa90079225 | ||
|
|
717e1d67b4 | ||
|
|
5dff96f951 | ||
|
|
fb8605216c | ||
|
|
f74167fc9c | ||
|
|
a49840e87f | ||
|
|
56d3536bc0 | ||
|
|
af45b81c28 | ||
|
|
fe2aa3e030 | ||
|
|
bd263b1413 | ||
|
|
513ac603c5 | ||
|
|
c96a7ca308 | ||
|
|
b00064ca9b | ||
|
|
983ec963ea | ||
|
|
88bb4fbb26 | ||
|
|
20ad59514e | ||
|
|
079e737567 | ||
|
|
e05b60ef75 | ||
|
|
cb1ff82a33 | ||
|
|
20d6e258b0 | ||
|
|
0b580f6d30 | ||
|
|
5d59616d01 | ||
|
|
2d483150e6 | ||
|
|
f51b8cc8b3 | ||
|
|
486c7a933e | ||
|
|
48cd65cb31 | ||
|
|
944f2b0bc4 | ||
|
|
752fcb57ae | ||
|
|
6658f92b5e | ||
|
|
f096056637 | ||
|
|
6749694729 | ||
|
|
f4faa478c9 | ||
|
|
8423121f9b | ||
|
|
5cbf775614 | ||
|
|
b2bfd4e411 | ||
|
|
17c2815bf2 | ||
|
|
91f38af97e | ||
|
|
1b6ae84a8a | ||
|
|
d383aa86a3 | ||
|
|
e9dde6f963 | ||
|
|
f1d4275e52 | ||
|
|
03f0ab50c0 | ||
|
|
615c2e530d | ||
|
|
aa3e2962cb | ||
|
|
19b460f1e3 | ||
|
|
7a174aded6 | ||
|
|
2066b5f7b0 | ||
|
|
456734a4cd | ||
|
|
d967bb690c | ||
|
|
b8d3f8f7c1 | ||
|
|
f8dabca6ca | ||
|
|
1034d284a8 | ||
|
|
d60b3c5652 | ||
|
|
38a2fa9cd1 | ||
|
|
1b83a15b25 | ||
|
|
019f4a4beb | ||
|
|
5ac8bf7b9b | ||
|
|
ac4235126f | ||
|
|
029fa5e724 | ||
|
|
c4748250c9 |
@@ -11,7 +11,7 @@ root = true
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespaces = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# CoffeeScript
|
||||
#
|
||||
@@ -28,12 +28,12 @@ indent_style = space
|
||||
# Package.json
|
||||
#
|
||||
# This indentation style is the one used by npm.
|
||||
[/package.json]
|
||||
[package.json]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# Jade
|
||||
[*.jade]
|
||||
# Pug (Jade)
|
||||
[*.{jade,pug}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
@@ -41,7 +41,7 @@ indent_style = space
|
||||
#
|
||||
# Two spaces seems to be the standard most common style, at least in
|
||||
# Node.js (http://nodeguide.com/style.html#tabs-vs-spaces).
|
||||
[*.js]
|
||||
[*.{js,jsx,ts,tsx}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
|
||||
18
.eslintrc.js
Normal file
18
.eslintrc.js
Normal file
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
extends: ['standard', 'standard-jsx'],
|
||||
globals: {
|
||||
__DEV__: true,
|
||||
$Diff: true,
|
||||
$Exact: true,
|
||||
$Keys: true,
|
||||
$Shape: true,
|
||||
},
|
||||
parser: 'babel-eslint',
|
||||
rules: {
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'no-var': 'error',
|
||||
'node/no-extraneous-import': 'error',
|
||||
'node/no-extraneous-require': 'error',
|
||||
'prefer-const': 'error',
|
||||
},
|
||||
}
|
||||
15
.flowconfig
Normal file
15
.flowconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
[ignore]
|
||||
<PROJECT_ROOT>/node_modules/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
|
||||
[lints]
|
||||
|
||||
[options]
|
||||
esproposal.decorators=ignore
|
||||
include_warnings=true
|
||||
module.use_strict=true
|
||||
|
||||
[strict]
|
||||
31
.gitignore
vendored
31
.gitignore
vendored
@@ -1,11 +1,28 @@
|
||||
/.nyc_output/
|
||||
/dist/
|
||||
/coverage/
|
||||
/node_modules/
|
||||
/src/api/index.js
|
||||
/src/xapi/mixins/index.js
|
||||
/src/xo-mixins/index.js
|
||||
/lerna-debug.log
|
||||
/lerna-debug.log.*
|
||||
|
||||
/@xen-orchestra/*/dist/
|
||||
/@xen-orchestra/*/node_modules/
|
||||
/packages/*/dist/
|
||||
/packages/*/node_modules/
|
||||
|
||||
/packages/xen-api/plot.dat
|
||||
|
||||
/packages/xo-server/.xo-server.*
|
||||
/packages/xo-server/src/api/index.js
|
||||
/packages/xo-server/src/xapi/mixins/index.js
|
||||
/packages/xo-server/src/xo-mixins/index.js
|
||||
|
||||
/packages/xo-server-auth-ldap/ldap.cache.conf
|
||||
|
||||
/packages/xo-web/src/common/intl/locales/index.js
|
||||
/packages/xo-web/src/common/themes/index.js
|
||||
|
||||
npm-debug.log
|
||||
npm-debug.log.*
|
||||
|
||||
.xo-server.*
|
||||
pnpm-debug.log
|
||||
pnpm-debug.log.*
|
||||
yarn-error.log
|
||||
yarn-error.log.*
|
||||
|
||||
4
.prettierrc.js
Normal file
4
.prettierrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- stable
|
||||
- 8
|
||||
- 6
|
||||
- 4
|
||||
|
||||
# Use containers.
|
||||
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
||||
sudo: false
|
||||
|
||||
before_install:
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
- export PATH="$HOME/.yarn/bin:$PATH"
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
|
||||
47
@xen-orchestra/babel-config/index.js
Normal file
47
@xen-orchestra/babel-config/index.js
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict'
|
||||
|
||||
const PLUGINS_RE = /^(?:@babel\/plugin-.+|babel-plugin-lodash)$/
|
||||
const PRESETS_RE = /^@babel\/preset-.+$/
|
||||
|
||||
const NODE_ENV = process.env.NODE_ENV || 'development'
|
||||
const __PROD__ = NODE_ENV === 'production'
|
||||
const __TEST__ = NODE_ENV === 'test'
|
||||
|
||||
module.exports = function (pkg, plugins, presets) {
|
||||
plugins === undefined && (plugins = {})
|
||||
|
||||
presets === undefined && (presets = {})
|
||||
presets['@babel/preset-env'] = {
|
||||
debug: !__TEST__,
|
||||
loose: true,
|
||||
shippedProposals: true,
|
||||
targets: __PROD__
|
||||
? (() => {
|
||||
let node = (pkg.engines || {}).node
|
||||
if (node !== undefined) {
|
||||
const trimChars = '^=>~'
|
||||
while (trimChars.includes(node[0])) {
|
||||
node = node.slice(1)
|
||||
}
|
||||
return { node: node }
|
||||
}
|
||||
})()
|
||||
: { browsers: '', node: 'current' },
|
||||
useBuiltIns: '@babel/polyfill' in (pkg.dependencies || {}) && 'usage',
|
||||
}
|
||||
|
||||
Object.keys(pkg.devDependencies || {}).forEach(name => {
|
||||
if (!(name in presets) && PLUGINS_RE.test(name)) {
|
||||
plugins[name] = {}
|
||||
} else if (!(name in presets) && PRESETS_RE.test(name)) {
|
||||
presets[name] = {}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
comments: !__PROD__,
|
||||
ignore: __TEST__ ? undefined : [/\.spec\.js$/],
|
||||
plugins: Object.keys(plugins).map(plugin => [plugin, plugins[plugin]]),
|
||||
presets: Object.keys(presets).map(preset => [preset, presets[preset]]),
|
||||
}
|
||||
}
|
||||
11
@xen-orchestra/babel-config/package.json
Normal file
11
@xen-orchestra/babel-config/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@xen-orchestra/babel-config",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/@xen-orchestra/babel-config",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
}
|
||||
}
|
||||
3
@xen-orchestra/cron/.babelrc.js
Normal file
3
@xen-orchestra/cron/.babelrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = require('../../@xen-orchestra/babel-config')(
|
||||
require('./package.json')
|
||||
)
|
||||
24
@xen-orchestra/cron/.npmignore
Normal file
24
@xen-orchestra/cron/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
145
@xen-orchestra/cron/README.md
Normal file
145
@xen-orchestra/cron/README.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# @xen-orchestra/cron [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> Focused, well maintained, cron parser/scheduler
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/cron):
|
||||
|
||||
```
|
||||
> npm install --save @xen-orchestra/cron
|
||||
```
|
||||
|
||||
### Pattern syntax
|
||||
|
||||
```
|
||||
<minute> <hour> <day of month> <month> <day of week>
|
||||
```
|
||||
|
||||
|
||||
Each entry can be:
|
||||
|
||||
- a single value
|
||||
- a range (`0-23` or `*/2`)
|
||||
- a list of values/ranges (`1,8-12`)
|
||||
|
||||
A wildcard (`*`) can be used as a shortcut for the whole range
|
||||
(`first-last`).
|
||||
|
||||
Step values can be used in conjunctions with ranges. For instance,
|
||||
`1-7/2` is the same as `1,3,5,7`.
|
||||
|
||||
| Field | Allowed values |
|
||||
|------------------|----------------|
|
||||
| minute | 0-59 |
|
||||
| hour | 0-23 |
|
||||
| day of the month | 1-31 or 3-letter names (`jan`, `feb`, …) |
|
||||
| month | 0-11 |
|
||||
| day of week | 0-7 (0 and 7 both mean Sunday) or 3-letter names (`mon`, `tue`, …) |
|
||||
|
||||
> Note: the month range is 0-11 to be compatible with
|
||||
> [cron](https://github.com/kelektiv/node-cron), it does not appear to
|
||||
> be very standard though.
|
||||
|
||||
### API
|
||||
|
||||
`createSchedule(pattern: string, zone: string = 'utc'): Schedule`
|
||||
|
||||
> Create a new schedule.
|
||||
|
||||
- `pattern`: the pattern to use, see [the syntax](#pattern-syntax)
|
||||
- `zone`: the timezone to use, use `'local'` for the local timezone
|
||||
|
||||
```js
|
||||
import { createSchedule } from '@xen-orchestra/cron'
|
||||
|
||||
const schedule = createSchedule('0 0 * * sun', 'America/New_York')
|
||||
```
|
||||
|
||||
`Schedule#createJob(fn: Function): Job`
|
||||
|
||||
> Create a new job from this schedule.
|
||||
|
||||
- `fn`: function to execute, if it returns a promise, it will be
|
||||
awaited before scheduling the next run.
|
||||
|
||||
```js
|
||||
const job = schedule.createJob(() => {
|
||||
console.log(new Date())
|
||||
})
|
||||
```
|
||||
|
||||
`Schedule#next(n: number): Array<Date>`
|
||||
|
||||
> Returns the next dates matching this schedule.
|
||||
|
||||
- `n`: number of dates to return
|
||||
|
||||
```js
|
||||
schedule.next(2)
|
||||
// [ 2018-02-11T05:00:00.000Z, 2018-02-18T05:00:00.000Z ]
|
||||
```
|
||||
|
||||
`Schedule#startJob(fn: Function): () => void`
|
||||
|
||||
> Start a new job from this schedule and return a function to stop it.
|
||||
|
||||
- `fn`: function to execute, if it returns a promise, it will be
|
||||
awaited before scheduling the next run.
|
||||
|
||||
```js
|
||||
const stopJob = schedule.startJob(() => {
|
||||
console.log(new Date())
|
||||
})
|
||||
stopJob()
|
||||
```
|
||||
|
||||
`Job#start(): void`
|
||||
|
||||
> Start this job.
|
||||
|
||||
```js
|
||||
job.start()
|
||||
```
|
||||
|
||||
`Job#stop(): void`
|
||||
|
||||
> Stop this job.
|
||||
|
||||
```js
|
||||
job.stop()
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> yarn
|
||||
|
||||
# Run the tests
|
||||
> yarn test
|
||||
|
||||
# Continuously compile
|
||||
> yarn dev
|
||||
|
||||
# Continuously run the tests
|
||||
> yarn dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> yarn build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Vates SAS](https://vates.fr)
|
||||
59
@xen-orchestra/cron/package.json
Normal file
59
@xen-orchestra/cron/package.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "@xen-orchestra/cron",
|
||||
"version": "1.0.2",
|
||||
"license": "ISC",
|
||||
"description": "Focused, well maintained, cron parser/scheduler",
|
||||
"keywords": [
|
||||
"cron",
|
||||
"cronjob",
|
||||
"crontab",
|
||||
"job",
|
||||
"parser",
|
||||
"pattern",
|
||||
"schedule",
|
||||
"scheduling",
|
||||
"task"
|
||||
],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/@xen-orchestra/cron",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@isonoe.net"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"browserslist": [
|
||||
">2%"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.4",
|
||||
"moment-timezone": "^0.5.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.0.0-beta.40",
|
||||
"@babel/core": "7.0.0-beta.40",
|
||||
"@babel/preset-env": "7.0.0-beta.40",
|
||||
"@babel/preset-flow": "7.0.0-beta.40",
|
||||
"cross-env": "^5.1.3",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"clean": "rimraf dist/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run clean",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
}
|
||||
76
@xen-orchestra/cron/src/index.js
Normal file
76
@xen-orchestra/cron/src/index.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import moment from 'moment-timezone'
|
||||
|
||||
import next from './next'
|
||||
import parse from './parse'
|
||||
|
||||
const MAX_DELAY = 2 ** 31 - 1
|
||||
|
||||
class Job {
|
||||
constructor (schedule, fn) {
|
||||
const wrapper = () => {
|
||||
const result = fn()
|
||||
let then
|
||||
if (result != null && typeof (then = result.then) === 'function') {
|
||||
then.call(result, scheduleNext, scheduleNext)
|
||||
} else {
|
||||
scheduleNext()
|
||||
}
|
||||
}
|
||||
const scheduleNext = () => {
|
||||
const delay = schedule._nextDelay()
|
||||
this._timeout =
|
||||
delay < MAX_DELAY
|
||||
? setTimeout(wrapper, delay)
|
||||
: setTimeout(scheduleNext, MAX_DELAY)
|
||||
}
|
||||
|
||||
this._scheduleNext = scheduleNext
|
||||
this._timeout = undefined
|
||||
}
|
||||
|
||||
start () {
|
||||
this.stop()
|
||||
this._scheduleNext()
|
||||
}
|
||||
|
||||
stop () {
|
||||
clearTimeout(this._timeout)
|
||||
}
|
||||
}
|
||||
|
||||
class Schedule {
|
||||
constructor (pattern, zone = 'utc') {
|
||||
this._schedule = parse(pattern)
|
||||
this._createDate =
|
||||
zone.toLowerCase() === 'utc'
|
||||
? moment.utc
|
||||
: zone === 'local' ? moment : () => moment.tz(zone)
|
||||
}
|
||||
|
||||
createJob (fn) {
|
||||
return new Job(this, fn)
|
||||
}
|
||||
|
||||
next (n) {
|
||||
const dates = new Array(n)
|
||||
const schedule = this._schedule
|
||||
let date = this._createDate()
|
||||
for (let i = 0; i < n; ++i) {
|
||||
dates[i] = (date = next(schedule, date)).toDate()
|
||||
}
|
||||
return dates
|
||||
}
|
||||
|
||||
_nextDelay () {
|
||||
const now = this._createDate()
|
||||
return next(this._schedule, now) - now
|
||||
}
|
||||
|
||||
startJob (fn) {
|
||||
const job = this.createJob(fn)
|
||||
job.start()
|
||||
return job.stop.bind(job)
|
||||
}
|
||||
}
|
||||
|
||||
export const createSchedule = (...args) => new Schedule(...args)
|
||||
89
@xen-orchestra/cron/src/next.js
Normal file
89
@xen-orchestra/cron/src/next.js
Normal file
@@ -0,0 +1,89 @@
|
||||
import moment from 'moment-timezone'
|
||||
import sortedIndex from 'lodash/sortedIndex'
|
||||
|
||||
const NEXT_MAPPING = {
|
||||
month: { year: 1 },
|
||||
date: { month: 1 },
|
||||
day: { week: 1 },
|
||||
hour: { day: 1 },
|
||||
minute: { hour: 1 },
|
||||
}
|
||||
|
||||
const getFirst = values => (values !== undefined ? values[0] : 0)
|
||||
|
||||
const setFirstAvailable = (date, unit, values) => {
|
||||
if (values === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const curr = date.get(unit)
|
||||
const next = values[sortedIndex(values, curr) % values.length]
|
||||
if (curr === next) {
|
||||
return
|
||||
}
|
||||
|
||||
const timestamp = +date
|
||||
date.set(unit, next)
|
||||
if (timestamp > +date) {
|
||||
date.add(NEXT_MAPPING[unit])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// returns the next run, after the passed date
|
||||
export default (schedule, fromDate) => {
|
||||
let date = moment(fromDate)
|
||||
.set({
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
})
|
||||
.add({ minute: 1 })
|
||||
|
||||
const { minute, hour, dayOfMonth, month, dayOfWeek } = schedule
|
||||
setFirstAvailable(date, 'minute', minute)
|
||||
|
||||
if (setFirstAvailable(date, 'hour', hour)) {
|
||||
date.set('minute', getFirst(minute))
|
||||
}
|
||||
|
||||
let loop
|
||||
let i = 0
|
||||
do {
|
||||
loop = false
|
||||
|
||||
if (setFirstAvailable(date, 'month', month)) {
|
||||
date.set({
|
||||
date: 1,
|
||||
hour: getFirst(hour),
|
||||
minute: getFirst(minute),
|
||||
})
|
||||
}
|
||||
|
||||
let newDate = date.clone()
|
||||
if (dayOfMonth === undefined) {
|
||||
if (dayOfWeek !== undefined) {
|
||||
setFirstAvailable(newDate, 'day', dayOfWeek)
|
||||
}
|
||||
} else if (dayOfWeek === undefined) {
|
||||
setFirstAvailable(newDate, 'date', dayOfMonth)
|
||||
} else {
|
||||
const dateDay = newDate.clone()
|
||||
setFirstAvailable(dateDay, 'date', dayOfMonth)
|
||||
setFirstAvailable(newDate, 'day', dayOfWeek)
|
||||
newDate = moment.min(dateDay, newDate)
|
||||
}
|
||||
if (+date !== +newDate) {
|
||||
loop = date.month() !== newDate.month()
|
||||
date = newDate.set({
|
||||
hour: getFirst(hour),
|
||||
minute: getFirst(minute),
|
||||
})
|
||||
}
|
||||
} while (loop && ++i < 5)
|
||||
|
||||
if (loop) {
|
||||
throw new Error('no solutions found for this schedule')
|
||||
}
|
||||
|
||||
return date
|
||||
}
|
||||
44
@xen-orchestra/cron/src/next.spec.js
Normal file
44
@xen-orchestra/cron/src/next.spec.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import mapValues from 'lodash/mapValues'
|
||||
import moment from 'moment-timezone'
|
||||
|
||||
import next from './next'
|
||||
import parse from './parse'
|
||||
|
||||
const N = (pattern, fromDate = '2018-04-09T06:25') => {
|
||||
const iso = next(parse(pattern), moment.utc(fromDate)).toISOString()
|
||||
return iso.slice(0, iso.lastIndexOf(':'))
|
||||
}
|
||||
|
||||
describe('next()', () => {
|
||||
mapValues(
|
||||
{
|
||||
minutely: ['* * * * *', '2018-04-09T06:26'],
|
||||
hourly: ['@hourly', '2018-04-09T07:00'],
|
||||
daily: ['@daily', '2018-04-10T00:00'],
|
||||
monthly: ['@monthly', '2018-05-01T00:00'],
|
||||
yearly: ['@yearly', '2019-01-01T00:00'],
|
||||
weekly: ['@weekly', '2018-04-15T00:00'],
|
||||
},
|
||||
([pattern, result], title) =>
|
||||
it(title, () => {
|
||||
expect(N(pattern)).toBe(result)
|
||||
})
|
||||
)
|
||||
|
||||
it('select first between month-day and week-day', () => {
|
||||
expect(N('* * 10 * wen')).toBe('2018-04-10T00:00')
|
||||
expect(N('* * 12 * wen')).toBe('2018-04-11T00:00')
|
||||
})
|
||||
|
||||
it('select the last available day of a month', () => {
|
||||
expect(N('* * 29 feb *')).toBe('2020-02-29T00:00')
|
||||
})
|
||||
|
||||
it('fails when no solutions has been found', () => {
|
||||
expect(() => N('0 0 30 feb *')).toThrow(
|
||||
'no solutions found for this schedule'
|
||||
)
|
||||
})
|
||||
})
|
||||
193
@xen-orchestra/cron/src/parse.js
Normal file
193
@xen-orchestra/cron/src/parse.js
Normal file
@@ -0,0 +1,193 @@
|
||||
const compareNumbers = (a, b) => a - b
|
||||
|
||||
const createParser = ({ fields: [...fields], presets: { ...presets } }) => {
|
||||
const m = fields.length
|
||||
|
||||
for (let j = 0; j < m; ++j) {
|
||||
const field = fields[j]
|
||||
let { aliases } = field
|
||||
if (aliases !== undefined) {
|
||||
let symbols = aliases
|
||||
|
||||
if (Array.isArray(aliases)) {
|
||||
aliases = {}
|
||||
const [start] = field.range
|
||||
symbols.forEach((alias, i) => {
|
||||
aliases[alias] = start + i
|
||||
})
|
||||
} else {
|
||||
symbols = Object.keys(aliases)
|
||||
}
|
||||
|
||||
fields[j] = {
|
||||
...field,
|
||||
aliases,
|
||||
aliasesRegExp: new RegExp(symbols.join('|'), 'y'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let field, i, n, pattern, schedule, values
|
||||
|
||||
const isDigit = c => c >= '0' && c <= '9'
|
||||
const match = c => pattern[i] === c && (++i, true)
|
||||
|
||||
const consumeWhitespaces = () => {
|
||||
let c
|
||||
while ((c = pattern[i]) === ' ' || c === '\t') {
|
||||
++i
|
||||
}
|
||||
}
|
||||
|
||||
const parseInteger = () => {
|
||||
let c
|
||||
const digits = []
|
||||
while (isDigit((c = pattern[i]))) {
|
||||
++i
|
||||
digits.push(c)
|
||||
}
|
||||
if (digits.length === 0) {
|
||||
throw new SyntaxError(`${field.name}: missing integer at character ${i}`)
|
||||
}
|
||||
return Number.parseInt(digits.join(''), 10)
|
||||
}
|
||||
|
||||
const parseValue = () => {
|
||||
let value
|
||||
|
||||
const { aliasesRegExp } = field
|
||||
if (aliasesRegExp === undefined || isDigit(pattern[i])) {
|
||||
value = parseInteger()
|
||||
const { post } = field
|
||||
if (post !== undefined) {
|
||||
value = post(value)
|
||||
}
|
||||
} else {
|
||||
aliasesRegExp.lastIndex = i
|
||||
const matches = aliasesRegExp.exec(pattern)
|
||||
if (matches === null) {
|
||||
throw new SyntaxError(
|
||||
`${field.name}: missing alias or integer at character ${i}`
|
||||
)
|
||||
}
|
||||
const [alias] = matches
|
||||
i += alias.length
|
||||
value = field.aliases[alias]
|
||||
}
|
||||
|
||||
const { range } = field
|
||||
if (value < range[0] || value > range[1]) {
|
||||
throw new SyntaxError(
|
||||
`${field.name}: ${value} is not between ${range[0]} and ${range[1]}`
|
||||
)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
const parseRange = () => {
|
||||
let end, start, step
|
||||
if (match('*')) {
|
||||
if (!match('/')) {
|
||||
return
|
||||
}
|
||||
;[start, end] = field.range
|
||||
step = parseInteger()
|
||||
} else {
|
||||
start = parseValue()
|
||||
if (!match('-')) {
|
||||
values.add(start)
|
||||
return
|
||||
}
|
||||
end = parseValue()
|
||||
step = match('/') ? parseInteger() : 1
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i += step) {
|
||||
values.add(i)
|
||||
}
|
||||
}
|
||||
|
||||
const parseSequence = () => {
|
||||
do {
|
||||
parseRange()
|
||||
} while (match(','))
|
||||
}
|
||||
|
||||
const parse = p => {
|
||||
{
|
||||
const schedule = presets[p]
|
||||
if (schedule !== undefined) {
|
||||
return typeof schedule === 'string'
|
||||
? (presets[p] = parse(schedule))
|
||||
: schedule
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
i = 0
|
||||
n = p.length
|
||||
pattern = p
|
||||
schedule = {}
|
||||
|
||||
for (let j = 0; j < m; ++j) {
|
||||
consumeWhitespaces()
|
||||
|
||||
field = fields[j]
|
||||
values = new Set()
|
||||
parseSequence()
|
||||
if (values.size !== 0) {
|
||||
schedule[field.name] = Array.from(values).sort(compareNumbers)
|
||||
}
|
||||
}
|
||||
|
||||
consumeWhitespaces()
|
||||
if (i !== n) {
|
||||
throw new SyntaxError(
|
||||
`unexpected character at offset ${i}, expected end`
|
||||
)
|
||||
}
|
||||
|
||||
return schedule
|
||||
} finally {
|
||||
field = pattern = schedule = values = undefined
|
||||
}
|
||||
}
|
||||
|
||||
return parse
|
||||
}
|
||||
|
||||
export default createParser({
|
||||
fields: [
|
||||
{
|
||||
name: 'minute',
|
||||
range: [0, 59],
|
||||
},
|
||||
{
|
||||
name: 'hour',
|
||||
range: [0, 23],
|
||||
},
|
||||
{
|
||||
name: 'dayOfMonth',
|
||||
range: [1, 31],
|
||||
},
|
||||
{
|
||||
aliases: 'jan feb mar apr may jun jul aug sep oct nov dec'.split(' '),
|
||||
name: 'month',
|
||||
range: [0, 11],
|
||||
},
|
||||
{
|
||||
aliases: 'mon tue wen thu fri sat sun'.split(' '),
|
||||
name: 'dayOfWeek',
|
||||
post: value => (value === 0 ? 7 : value),
|
||||
range: [1, 7],
|
||||
},
|
||||
],
|
||||
presets: {
|
||||
'@annually': '0 0 1 jan *',
|
||||
'@daily': '0 0 * * *',
|
||||
'@hourly': '0 * * * *',
|
||||
'@monthly': '0 0 1 * *',
|
||||
'@weekly': '0 0 * * sun',
|
||||
'@yearly': '0 0 1 jan *',
|
||||
},
|
||||
})
|
||||
49
@xen-orchestra/cron/src/parse.spec.js
Normal file
49
@xen-orchestra/cron/src/parse.spec.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import parse from './parse'
|
||||
|
||||
describe('parse()', () => {
|
||||
it('works', () => {
|
||||
expect(parse('0 0-10 */10 jan,2,4-11/3 *')).toEqual({
|
||||
minute: [0],
|
||||
hour: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
dayOfMonth: [1, 11, 21, 31],
|
||||
month: [0, 2, 4, 7, 10],
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly parse months', () => {
|
||||
expect(parse('* * * 0,11 *')).toEqual({
|
||||
month: [0, 11],
|
||||
})
|
||||
expect(parse('* * * jan,dec *')).toEqual({
|
||||
month: [0, 11],
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly parse days', () => {
|
||||
expect(parse('* * * * mon,sun')).toEqual({
|
||||
dayOfWeek: [1, 7],
|
||||
})
|
||||
})
|
||||
|
||||
it('reports missing integer', () => {
|
||||
expect(() => parse('*/a')).toThrow('minute: missing integer at character 2')
|
||||
expect(() => parse('*')).toThrow('hour: missing integer at character 1')
|
||||
})
|
||||
|
||||
it('reports invalid aliases', () => {
|
||||
expect(() => parse('* * * jan-foo *')).toThrow(
|
||||
'month: missing alias or integer at character 10'
|
||||
)
|
||||
})
|
||||
|
||||
it('dayOfWeek: 0 and 7 bind to sunday', () => {
|
||||
expect(parse('* * * * 0')).toEqual({
|
||||
dayOfWeek: [7],
|
||||
})
|
||||
expect(parse('* * * * 7')).toEqual({
|
||||
dayOfWeek: [7],
|
||||
})
|
||||
})
|
||||
})
|
||||
1483
CHANGELOG.md
Normal file
1483
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,27 @@
|
||||
# ALL ISSUES SHOULD BE CREATED IN XO-WEB'S TRACKER!
|
||||
<!--
|
||||
Welcome to the issue section of Xen Orchestra!
|
||||
|
||||
https://github.com/vatesfr/xo-web/issues
|
||||
Here you can:
|
||||
- report an issue
|
||||
- propose an enhancement
|
||||
- ask a question
|
||||
|
||||
Please, respect this template as much as possible, it helps us sort
|
||||
the issues :)
|
||||
-->
|
||||
|
||||
### Context
|
||||
|
||||
- **XO origin**: the sources / XO Appliance
|
||||
- **Versions**:
|
||||
- Node: **FILL HERE**
|
||||
- xo-web: **FILL HERE**
|
||||
- xo-server: **FILL HERE**
|
||||
|
||||
### Expected behavior
|
||||
|
||||
<!-- What you expect to happen -->
|
||||
|
||||
### Current behavior
|
||||
|
||||
<!-- What is actually happening -->
|
||||
|
||||
39
README.md
39
README.md
@@ -1,40 +1,11 @@
|
||||
# Xen Orchestra Server
|
||||
# Xen Orchestra [](https://go.crisp.im/chat/embed/?website_id=-JzqzzwddSV7bKGtEyAQ) [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||

|
||||
|
||||
XO-Server is part of [Xen Orchestra](https://github.com/vatesfr/xo), a web interface for XenServer or XAPI enabled hosts.
|
||||
|
||||
It contains all the logic of XO and handles:
|
||||
|
||||
- connections to all XAPI servers/pools;
|
||||
- a cache system to provide the best response time possible;
|
||||
- users authentication and authorizations (work in progress);
|
||||
- a JSON-RPC based interface for XO clients (i.e. [XO-Web](https://github.com/vatesfr/xo-web)).
|
||||
|
||||
[](https://travis-ci.org/vatesfr/xo-server)
|
||||
[](https://david-dm.org/vatesfr/xo-server)
|
||||
[](https://david-dm.org/vatesfr/xo-server#info=devDependencies)
|
||||
|
||||
___
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
Manual install procedure is [available here](https://xen-orchestra.com/docs/from_the_sources.html).
|
||||
XOA or manual install procedure is [available here](https://xen-orchestra.com/docs/installation.html)
|
||||
|
||||
## Compilation
|
||||
## License
|
||||
|
||||
Production build:
|
||||
|
||||
```
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
Development build:
|
||||
|
||||
```
|
||||
$ npm run dev
|
||||
```
|
||||
|
||||
## How to report a bug?
|
||||
|
||||
All bug reports should go into the [bugtracker of xo-web](https://github.com/vatesfr/xo-web/issues).
|
||||
AGPL3 © [Vates SAS](http://vates.fr)
|
||||
|
||||
40
config.json
40
config.json
@@ -1,40 +0,0 @@
|
||||
// Vendor config: DO NOT TOUCH!
|
||||
//
|
||||
// See sample.config.yaml to override.
|
||||
{
|
||||
"http": {
|
||||
"listen": [
|
||||
{
|
||||
"port": 80
|
||||
}
|
||||
],
|
||||
"mounts": {},
|
||||
|
||||
// Ciphers to use.
|
||||
//
|
||||
// These are the default ciphers in Node 4.2.6, we are setting
|
||||
// them explicitly for older Node versions.
|
||||
"ciphers": "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA",
|
||||
|
||||
// Tell Node to respect the cipher order.
|
||||
"honorCipherOrder": true,
|
||||
|
||||
// Specify to use at least TLSv1.1.
|
||||
// See: https://github.com/certsimple/minimum-tls-version
|
||||
"secureOptions": 117440512
|
||||
},
|
||||
"datadir": "/var/lib/xo-server/data",
|
||||
|
||||
// Should users be created on first sign in?
|
||||
//
|
||||
// Necessary for external authentication providers.
|
||||
"createUserOnFirstSignin": true,
|
||||
|
||||
// Whether API logs should contains the full request/response on
|
||||
// errors.
|
||||
//
|
||||
// This is disabled by default for performance (lots of data) and
|
||||
// security concerns (avoiding sensitive data in the logs) but can
|
||||
// be turned for investigation by the administrator.
|
||||
"verboseApiLogsOnErrors": false
|
||||
}
|
||||
70
gulpfile.js
70
gulpfile.js
@@ -1,70 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
var gulp = require('gulp')
|
||||
|
||||
var babel = require('gulp-babel')
|
||||
var coffee = require('gulp-coffee')
|
||||
var plumber = require('gulp-plumber')
|
||||
var rimraf = require('rimraf')
|
||||
var sourceMaps = require('gulp-sourcemaps')
|
||||
var watch = require('gulp-watch')
|
||||
|
||||
var join = require('path').join
|
||||
|
||||
// ===================================================================
|
||||
|
||||
var SRC_DIR = join(__dirname, 'src')
|
||||
var DIST_DIR = join(__dirname, 'dist')
|
||||
|
||||
var PRODUCTION = process.argv.indexOf('--production') !== -1
|
||||
|
||||
// ===================================================================
|
||||
|
||||
function src (patterns) {
|
||||
return PRODUCTION
|
||||
? gulp.src(patterns, {
|
||||
base: SRC_DIR,
|
||||
cwd: SRC_DIR
|
||||
})
|
||||
: watch(patterns, {
|
||||
base: SRC_DIR,
|
||||
cwd: SRC_DIR,
|
||||
ignoreInitial: false,
|
||||
verbose: true
|
||||
})
|
||||
.pipe(plumber())
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
gulp.task(function clean (cb) {
|
||||
rimraf(DIST_DIR, cb)
|
||||
})
|
||||
|
||||
gulp.task(function buildCoffee () {
|
||||
return src('**/*.coffee')
|
||||
.pipe(sourceMaps.init())
|
||||
.pipe(coffee({
|
||||
bare: true
|
||||
}))
|
||||
|
||||
// Necessary to correctly compile generators.
|
||||
.pipe(babel())
|
||||
|
||||
.pipe(sourceMaps.write('.'))
|
||||
.pipe(gulp.dest(DIST_DIR))
|
||||
})
|
||||
|
||||
gulp.task(function buildEs6 () {
|
||||
return src([ '**/*.js', '!*.spec.js' ])
|
||||
.pipe(sourceMaps.init())
|
||||
.pipe(babel())
|
||||
.pipe(sourceMaps.write('.'))
|
||||
.pipe(gulp.dest(DIST_DIR))
|
||||
})
|
||||
|
||||
// ===================================================================
|
||||
|
||||
gulp.task('build', gulp.series('clean', gulp.parallel('buildCoffee', 'buildEs6')))
|
||||
232
package.json
232
package.json
@@ -1,183 +1,65 @@
|
||||
{
|
||||
"name": "xo-server",
|
||||
"version": "5.11.0",
|
||||
"license": "AGPL-3.0",
|
||||
"description": "Server part of Xen-Orchestra",
|
||||
"keywords": [
|
||||
"xen",
|
||||
"orchestra",
|
||||
"xen-orchestra",
|
||||
"server"
|
||||
],
|
||||
"homepage": "http://github.com/vatesfr/xo-server/",
|
||||
"bugs": {
|
||||
"url": "https://github.com/vatesfr/xo-web/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/vatesfr/xo-server.git"
|
||||
},
|
||||
"author": "Julien Fontanet <julien.fontanet@vates.fr>",
|
||||
"preferGlobal": true,
|
||||
"files": [
|
||||
"better-stacks.js",
|
||||
"bin/",
|
||||
"dist/",
|
||||
"config.json",
|
||||
"index.js",
|
||||
"signin.pug"
|
||||
],
|
||||
"directories": {
|
||||
"bin": "bin"
|
||||
"devDependencies": {
|
||||
"@babel/register": "^7.0.0-beta.40",
|
||||
"babel-7-jest": "^21.3.2",
|
||||
"babel-eslint": "^8.1.2",
|
||||
"benchmark": "^2.1.4",
|
||||
"eslint": "^4.14.0",
|
||||
"eslint-config-standard": "^11.0.0-beta.0",
|
||||
"eslint-config-standard-jsx": "^4.0.2",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-node": "^6.0.0",
|
||||
"eslint-plugin-promise": "^3.6.0",
|
||||
"eslint-plugin-react": "^7.6.1",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"exec-promise": "^0.7.0",
|
||||
"flow-bin": "^0.66.0",
|
||||
"globby": "^8.0.0",
|
||||
"husky": "^0.14.3",
|
||||
"jest": "^22.0.4",
|
||||
"lodash": "^4.17.4",
|
||||
"prettier": "^1.10.2",
|
||||
"promise-toolbox": "^0.9.5",
|
||||
"sorted-object": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@marsaud/smb2-promise": "^0.2.1",
|
||||
"@nraynaud/struct-fu": "^1.0.1",
|
||||
"ajv": "^5.2.2",
|
||||
"app-conf": "^0.5.0",
|
||||
"archiver": "^2.0.0",
|
||||
"arp-a": "^0.5.1",
|
||||
"babel-runtime": "^6.23.0",
|
||||
"base64url": "^2.0.0",
|
||||
"bind-property-descriptor": "^1.0.0",
|
||||
"blocked": "^1.2.1",
|
||||
"bluebird": "^3.5.0",
|
||||
"body-parser": "^1.17.1",
|
||||
"connect-flash": "^0.1.1",
|
||||
"cookie": "^0.3.1",
|
||||
"cookie-parser": "^1.4.3",
|
||||
"cron": "^1.2.1",
|
||||
"d3-time-format": "^2.0.5",
|
||||
"debug": "^2.6.7",
|
||||
"decorator-synchronized": "^0.3.0",
|
||||
"deptree": "^1.0.0",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"event-to-promise": "^0.8.0",
|
||||
"exec-promise": "^0.7.0",
|
||||
"execa": "^0.7.0",
|
||||
"express": "^4.15.2",
|
||||
"express-session": "^1.15.4",
|
||||
"fatfs": "^0.10.4",
|
||||
"from2": "^2.3.0",
|
||||
"fs-extra": "^4.0.0",
|
||||
"golike-defer": "^0.3.0",
|
||||
"hashy": "^0.6.2",
|
||||
"helmet": "^3.8.0",
|
||||
"highland": "^2.11.1",
|
||||
"http-proxy": "^1.16.2",
|
||||
"http-request-plus": "^0.4.0",
|
||||
"http-server-plus": "^0.8.0",
|
||||
"human-format": "^0.8.0",
|
||||
"is-redirect": "^1.0.0",
|
||||
"js-yaml": "^3.9.0",
|
||||
"json-rpc-peer": "^0.14.0",
|
||||
"json5": "^0.5.1",
|
||||
"julien-f-source-map-support": "0.0.0",
|
||||
"julien-f-unzip": "^0.2.1",
|
||||
"kindof": "^2.0.0",
|
||||
"level": "^1.6.0",
|
||||
"level-party": "^3.0.4",
|
||||
"level-sublevel": "^6.6.1",
|
||||
"leveldown": "^1.6.0",
|
||||
"lodash": "^4.17.4",
|
||||
"make-error": "^1",
|
||||
"micromatch": "^3.0.4",
|
||||
"minimist": "^1.2.0",
|
||||
"moment-timezone": "^0.5.13",
|
||||
"ms": "^2.0.0",
|
||||
"multikey-hash": "^1.0.4",
|
||||
"ndjson": "^1.5.0",
|
||||
"parse-pairs": "^0.2.2",
|
||||
"partial-stream": "0.0.0",
|
||||
"passport": "^0.3.2",
|
||||
"passport-local": "^1.0.0",
|
||||
"pretty-format": "^20.0.1",
|
||||
"promise-toolbox": "^0.9.5",
|
||||
"proxy-agent": "^2.1.0",
|
||||
"pug": "^2.0.0-rc.2",
|
||||
"pw": "^0.0.4",
|
||||
"redis": "^2.7.1",
|
||||
"schema-inspector": "^1.6.8",
|
||||
"semver": "^5.4.1",
|
||||
"serve-static": "^1.12.3",
|
||||
"split-lines": "^1.1.0",
|
||||
"stack-chain": "^1.3.7",
|
||||
"tar-stream": "^1.5.4",
|
||||
"through2": "^2.0.3",
|
||||
"tmp": "^0.0.31",
|
||||
"uuid": "^3.0.1",
|
||||
"ws": "^3.0.0",
|
||||
"xen-api": "^0.14.0",
|
||||
"xml2js": "~0.4.17",
|
||||
"xo-acl-resolver": "^0.2.3",
|
||||
"xo-collection": "^0.4.1",
|
||||
"xo-common": "^0.1.1",
|
||||
"xo-remote-parser": "^0.3",
|
||||
"xo-vmdk-to-vhd": "0.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-plugin-lodash": "^3.2.11",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"dependency-check": "^2.8.0",
|
||||
"gulp": "git://github.com/gulpjs/gulp#4.0",
|
||||
"gulp-babel": "^6",
|
||||
"gulp-coffee": "^2.3.4",
|
||||
"gulp-plumber": "^1.1.0",
|
||||
"gulp-sourcemaps": "^2.6.0",
|
||||
"gulp-watch": "^4.3.11",
|
||||
"husky": "^0.14.3",
|
||||
"index-modules": "^0.3.0",
|
||||
"jest": "^20.0.1",
|
||||
"rimraf": "^2.6.1",
|
||||
"standard": "^10.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp build --production",
|
||||
"commitmsg": "npm test",
|
||||
"dev": "gulp build",
|
||||
"dev-test": "jest --bail --watch",
|
||||
"posttest": "standard && dependency-check -i constant-stream ./package.json",
|
||||
"prebuild": "index-modules src/api src/xapi/mixins src/xo-mixins",
|
||||
"predev": "npm run prebuild",
|
||||
"prepublish": "npm run build",
|
||||
"start": "node bin/xo-server",
|
||||
"test": "jest"
|
||||
},
|
||||
"babel": {
|
||||
"plugins": [
|
||||
"lodash",
|
||||
"transform-decorators-legacy",
|
||||
"transform-runtime"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-0"
|
||||
]
|
||||
"yarn": "^1.2.1"
|
||||
},
|
||||
"jest": {
|
||||
"roots": [
|
||||
"<rootDir>/src"
|
||||
"collectCoverage": true,
|
||||
"projects": [
|
||||
"<rootDir>",
|
||||
"<rootDir>/packages/xo-web"
|
||||
],
|
||||
"testRegex": "\\.spec\\.js$"
|
||||
"testEnvironment": "node",
|
||||
"testPathIgnorePatterns": [
|
||||
"/dist/",
|
||||
"/xo-vmdk-to-vhd/",
|
||||
"/xo-web/"
|
||||
],
|
||||
"testRegex": "\\.spec\\.js$",
|
||||
"transform": {
|
||||
"/@xen-orchestra/cron/.+\\.jsx?$": "babel-7-jest",
|
||||
"/packages/complex-matcher/.+\\.jsx?$": "babel-7-jest",
|
||||
"/packages/value-matcher/.+\\.jsx?$": "babel-7-jest",
|
||||
"/packages/xo-cli/.+\\.jsx?$": "babel-7-jest",
|
||||
"\\.jsx?$": "babel-jest"
|
||||
}
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"dist"
|
||||
],
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "scripts/run-script --parallel build",
|
||||
"clean": "scripts/run-script --parallel clean",
|
||||
"dev": "scripts/run-script --parallel dev",
|
||||
"dev-test": "jest --bail --watch",
|
||||
"posttest": "scripts/run-script test",
|
||||
"precommit": "scripts/lint-staged",
|
||||
"prepare": "scripts/run-script prepare",
|
||||
"pretest": "eslint --ignore-path .gitignore .",
|
||||
"test": "jest"
|
||||
},
|
||||
"workspaces": [
|
||||
"@xen-orchestra/*",
|
||||
"packages/*"
|
||||
]
|
||||
}
|
||||
|
||||
3
packages/complex-matcher/.babelrc.js
Normal file
3
packages/complex-matcher/.babelrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = require('../../@xen-orchestra/babel-config')(
|
||||
require('./package.json')
|
||||
)
|
||||
24
packages/complex-matcher/.npmignore
Normal file
24
packages/complex-matcher/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
66
packages/complex-matcher/README.md
Normal file
66
packages/complex-matcher/README.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# complex-matcher [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> ${pkg.description}
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/complex-matcher):
|
||||
|
||||
```
|
||||
> npm install --save complex-matcher
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import * as CM from 'complex-matcher'
|
||||
|
||||
const characters = [
|
||||
{ name: 'Catwoman', costumeColor: 'black' },
|
||||
{ name: 'Superman', costumeColor: 'blue', hasCape: true },
|
||||
{ name: 'Wonder Woman', costumeColor: 'blue' },
|
||||
]
|
||||
|
||||
const predicate = CM.parse('costumeColor:blue hasCape?').createPredicate()
|
||||
|
||||
characters.filter(predicate)
|
||||
// [
|
||||
// { name: 'Superman', costumeColor: 'blue', hasCape: true },
|
||||
// ]
|
||||
|
||||
new CM.String('foo').createPredicate()
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> yarn
|
||||
|
||||
# Run the tests
|
||||
> yarn test
|
||||
|
||||
# Continuously compile
|
||||
> yarn dev
|
||||
|
||||
# Continuously run the tests
|
||||
> yarn dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> yarn build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Vates SAS](https://vates.fr)
|
||||
48
packages/complex-matcher/package.json
Normal file
48
packages/complex-matcher/package.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "complex-matcher",
|
||||
"version": "0.3.0",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/complex-matcher",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@isonoe.net"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"browserslist": [
|
||||
">2%"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.0.0-beta.40",
|
||||
"@babel/core": "7.0.0-beta.40",
|
||||
"@babel/preset-env": "7.0.0-beta.40",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"cross-env": "^5.1.1",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"clean": "rimraf dist/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
}
|
||||
12
packages/complex-matcher/src/index.bench.js
Normal file
12
packages/complex-matcher/src/index.bench.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { parse } from './'
|
||||
import { ast, pattern } from './index.fixtures'
|
||||
|
||||
export default ({ benchmark }) => {
|
||||
benchmark('parse', () => {
|
||||
parse(pattern)
|
||||
})
|
||||
|
||||
benchmark('toString', () => {
|
||||
ast.toString()
|
||||
})
|
||||
}
|
||||
15
packages/complex-matcher/src/index.fixtures.js
Normal file
15
packages/complex-matcher/src/index.fixtures.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as CM from './'
|
||||
|
||||
export const pattern =
|
||||
'foo !"\\\\ \\"" name:|(wonderwoman batman) hasCape? age:32'
|
||||
|
||||
export const ast = new CM.And([
|
||||
new CM.String('foo'),
|
||||
new CM.Not(new CM.String('\\ "')),
|
||||
new CM.Property(
|
||||
'name',
|
||||
new CM.Or([new CM.String('wonderwoman'), new CM.String('batman')])
|
||||
),
|
||||
new CM.TruthyProperty('hasCape'),
|
||||
new CM.Property('age', new CM.Number(32)),
|
||||
])
|
||||
531
packages/complex-matcher/src/index.js
Normal file
531
packages/complex-matcher/src/index.js
Normal file
@@ -0,0 +1,531 @@
|
||||
import { isPlainObject, some } from 'lodash'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const RAW_STRING_CHARS = (() => {
|
||||
const chars = { __proto__: null }
|
||||
const add = (a, b = a) => {
|
||||
let i = a.charCodeAt(0)
|
||||
const j = b.charCodeAt(0)
|
||||
while (i <= j) {
|
||||
chars[String.fromCharCode(i++)] = true
|
||||
}
|
||||
}
|
||||
add('$')
|
||||
add('-')
|
||||
add('.')
|
||||
add('0', '9')
|
||||
add('_')
|
||||
add('A', 'Z')
|
||||
add('a', 'z')
|
||||
return chars
|
||||
})()
|
||||
const isRawString = string => {
|
||||
const { length } = string
|
||||
for (let i = 0; i < length; ++i) {
|
||||
if (!(string[i] in RAW_STRING_CHARS)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class Node {
|
||||
createPredicate () {
|
||||
return value => this.match(value)
|
||||
}
|
||||
}
|
||||
|
||||
export class Null extends Node {
|
||||
match () {
|
||||
return true
|
||||
}
|
||||
|
||||
toString () {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const formatTerms = terms => terms.map(term => term.toString(true)).join(' ')
|
||||
|
||||
export class And extends Node {
|
||||
constructor (children) {
|
||||
super()
|
||||
|
||||
if (children.length === 1) {
|
||||
return children[0]
|
||||
}
|
||||
this.children = children
|
||||
}
|
||||
|
||||
match (value) {
|
||||
return this.children.every(child => child.match(value))
|
||||
}
|
||||
|
||||
toString (isNested) {
|
||||
const terms = formatTerms(this.children)
|
||||
return isNested ? `(${terms})` : terms
|
||||
}
|
||||
}
|
||||
|
||||
export class Comparison extends Node {
|
||||
constructor (operator, value) {
|
||||
super()
|
||||
this._comparator = Comparison.comparators[operator]
|
||||
this._operator = operator
|
||||
this._value = value
|
||||
}
|
||||
|
||||
match (value) {
|
||||
return typeof value === 'number' && this._comparator(value, this._value)
|
||||
}
|
||||
|
||||
toString () {
|
||||
return this._operator + String(this._value)
|
||||
}
|
||||
}
|
||||
Comparison.comparators = {
|
||||
'>': (a, b) => a > b,
|
||||
'>=': (a, b) => a >= b,
|
||||
'<': (a, b) => a < b,
|
||||
'<=': (a, b) => a <= b,
|
||||
}
|
||||
|
||||
export class Or extends Node {
|
||||
constructor (children) {
|
||||
super()
|
||||
|
||||
if (children.length === 1) {
|
||||
return children[0]
|
||||
}
|
||||
this.children = children
|
||||
}
|
||||
|
||||
match (value) {
|
||||
return this.children.some(child => child.match(value))
|
||||
}
|
||||
|
||||
toString () {
|
||||
return `|(${formatTerms(this.children)})`
|
||||
}
|
||||
}
|
||||
|
||||
export class Not extends Node {
|
||||
constructor (child) {
|
||||
super()
|
||||
|
||||
this.child = child
|
||||
}
|
||||
|
||||
match (value) {
|
||||
return !this.child.match(value)
|
||||
}
|
||||
|
||||
toString () {
|
||||
return '!' + this.child.toString(true)
|
||||
}
|
||||
}
|
||||
|
||||
export class NumberNode extends Node {
|
||||
constructor (value) {
|
||||
super()
|
||||
|
||||
this.value = value
|
||||
|
||||
// should not be enumerable for the tests
|
||||
Object.defineProperty(this, 'match', {
|
||||
value: this.match.bind(this),
|
||||
})
|
||||
}
|
||||
|
||||
match (value) {
|
||||
return (
|
||||
value === this.value ||
|
||||
(value !== null && typeof value === 'object' && some(value, this.match))
|
||||
)
|
||||
}
|
||||
|
||||
toString () {
|
||||
return String(this.value)
|
||||
}
|
||||
}
|
||||
export { NumberNode as Number }
|
||||
|
||||
export class Property extends Node {
|
||||
constructor (name, child) {
|
||||
super()
|
||||
|
||||
this.name = name
|
||||
this.child = child
|
||||
}
|
||||
|
||||
match (value) {
|
||||
return value != null && this.child.match(value[this.name])
|
||||
}
|
||||
|
||||
toString () {
|
||||
return `${formatString(this.name)}:${this.child.toString(true)}`
|
||||
}
|
||||
}
|
||||
|
||||
const escapeChar = char => '\\' + char
|
||||
const formatString = value =>
|
||||
Number.isNaN(+value)
|
||||
? isRawString(value) ? value : `"${value.replace(/\\|"/g, escapeChar)}"`
|
||||
: `"${value}"`
|
||||
|
||||
export class StringNode extends Node {
|
||||
constructor (value) {
|
||||
super()
|
||||
|
||||
this.lcValue = value.toLowerCase()
|
||||
this.value = value
|
||||
|
||||
// should not be enumerable for the tests
|
||||
Object.defineProperty(this, 'match', {
|
||||
value: this.match.bind(this),
|
||||
})
|
||||
}
|
||||
|
||||
match (value) {
|
||||
if (typeof value === 'string') {
|
||||
return value.toLowerCase().indexOf(this.lcValue) !== -1
|
||||
}
|
||||
|
||||
if (Array.isArray(value) || isPlainObject(value)) {
|
||||
return some(value, this.match)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
toString () {
|
||||
return formatString(this.value)
|
||||
}
|
||||
}
|
||||
export { StringNode as String }
|
||||
|
||||
export class TruthyProperty extends Node {
|
||||
constructor (name) {
|
||||
super()
|
||||
|
||||
this.name = name
|
||||
}
|
||||
|
||||
match (value) {
|
||||
return value != null && !!value[this.name]
|
||||
}
|
||||
|
||||
toString () {
|
||||
return formatString(this.name) + '?'
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// https://gist.github.com/yelouafi/556e5159e869952335e01f6b473c4ec1
|
||||
|
||||
class Failure {
|
||||
constructor (pos, expected) {
|
||||
this.expected = expected
|
||||
this.pos = pos
|
||||
}
|
||||
|
||||
get value () {
|
||||
throw new Error(
|
||||
`parse error: expected ${this.expected} at position ${this.pos}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Success {
|
||||
constructor (pos, value) {
|
||||
this.pos = pos
|
||||
this.value = value
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class P {
|
||||
static alt (...parsers) {
|
||||
const { length } = parsers
|
||||
return new P((input, pos, end) => {
|
||||
for (let i = 0; i < length; ++i) {
|
||||
const result = parsers[i]._parse(input, pos, end)
|
||||
if (result instanceof Success) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return new Failure(pos, 'alt')
|
||||
})
|
||||
}
|
||||
|
||||
static grammar (rules) {
|
||||
const grammar = {}
|
||||
Object.keys(rules).forEach(k => {
|
||||
const rule = rules[k]
|
||||
grammar[k] = rule instanceof P ? rule : P.lazy(rule, grammar)
|
||||
})
|
||||
return grammar
|
||||
}
|
||||
|
||||
static lazy (parserCreator, arg) {
|
||||
const parser = new P((input, pos, end) =>
|
||||
(parser._parse = parserCreator(arg)._parse)(input, pos, end)
|
||||
)
|
||||
return parser
|
||||
}
|
||||
|
||||
static regex (regex) {
|
||||
regex = new RegExp(regex.source, 'y')
|
||||
return new P((input, pos) => {
|
||||
regex.lastIndex = pos
|
||||
const matches = regex.exec(input)
|
||||
return matches !== null
|
||||
? new Success(regex.lastIndex, matches[0])
|
||||
: new Failure(pos, regex)
|
||||
})
|
||||
}
|
||||
|
||||
static seq (...parsers) {
|
||||
const { length } = parsers
|
||||
return new P((input, pos, end) => {
|
||||
const values = new Array(length)
|
||||
for (let i = 0; i < length; ++i) {
|
||||
const result = parsers[i]._parse(input, pos, end)
|
||||
if (result instanceof Failure) {
|
||||
return result
|
||||
}
|
||||
pos = result.pos
|
||||
values[i] = result.value
|
||||
}
|
||||
return new Success(pos, values)
|
||||
})
|
||||
}
|
||||
|
||||
static text (text) {
|
||||
const { length } = text
|
||||
return new P(
|
||||
(input, pos) =>
|
||||
input.startsWith(text, pos)
|
||||
? new Success(pos + length, text)
|
||||
: new Failure(pos, `'${text}'`)
|
||||
)
|
||||
}
|
||||
|
||||
constructor (parse) {
|
||||
this._parse = parse
|
||||
}
|
||||
|
||||
map (fn) {
|
||||
return new P((input, pos, end) => {
|
||||
const result = this._parse(input, pos, end)
|
||||
if (result instanceof Success) {
|
||||
result.value = fn(result.value)
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
parse (input, pos = 0, end = input.length) {
|
||||
return this._parse(input, pos, end).value
|
||||
}
|
||||
|
||||
repeat (min = 0, max = Infinity) {
|
||||
return new P((input, pos, end) => {
|
||||
const value = []
|
||||
let result
|
||||
let i = 0
|
||||
while (i < min) {
|
||||
++i
|
||||
result = this._parse(input, pos, end)
|
||||
if (result instanceof Failure) {
|
||||
return result
|
||||
}
|
||||
value.push(result.value)
|
||||
pos = result.pos
|
||||
}
|
||||
while (
|
||||
i < max &&
|
||||
(result = this._parse(input, pos, end)) instanceof Success
|
||||
) {
|
||||
++i
|
||||
value.push(result.value)
|
||||
pos = result.pos
|
||||
}
|
||||
return new Success(pos, value)
|
||||
})
|
||||
}
|
||||
|
||||
skip (otherParser) {
|
||||
return new P((input, pos, end) => {
|
||||
const result = this._parse(input, pos, end)
|
||||
if (result instanceof Failure) {
|
||||
return result
|
||||
}
|
||||
const otherResult = otherParser._parse(input, result.pos, end)
|
||||
if (otherResult instanceof Failure) {
|
||||
return otherResult
|
||||
}
|
||||
result.pos = otherResult.pos
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
P.eof = new P(
|
||||
(input, pos, end) =>
|
||||
pos < end ? new Failure(pos, 'end of input') : new Success(pos)
|
||||
)
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const parser = P.grammar({
|
||||
default: r =>
|
||||
P.seq(r.ws, r.term.repeat(), P.eof).map(
|
||||
([, terms]) => (terms.length === 0 ? new Null() : new And(terms))
|
||||
),
|
||||
quotedString: new P((input, pos, end) => {
|
||||
if (input[pos] !== '"') {
|
||||
return new Failure(pos, '"')
|
||||
}
|
||||
++pos
|
||||
|
||||
const value = []
|
||||
let char
|
||||
while (pos < end && (char = input[pos++]) !== '"') {
|
||||
if (char === '\\') {
|
||||
char = input[pos++]
|
||||
}
|
||||
value.push(char)
|
||||
}
|
||||
|
||||
return new Success(pos, value.join(''))
|
||||
}),
|
||||
rawString: new P((input, pos, end) => {
|
||||
let value = ''
|
||||
let c
|
||||
while (pos < end && RAW_STRING_CHARS[(c = input[pos])]) {
|
||||
++pos
|
||||
value += c
|
||||
}
|
||||
return value.length === 0
|
||||
? new Failure(pos, 'a raw string')
|
||||
: new Success(pos, value)
|
||||
}),
|
||||
string: r => P.alt(r.quotedString, r.rawString),
|
||||
term: r =>
|
||||
P.alt(
|
||||
P.seq(P.text('('), r.ws, r.term.repeat(1), P.text(')')).map(
|
||||
_ => new And(_[2])
|
||||
),
|
||||
P.seq(
|
||||
P.text('|'),
|
||||
r.ws,
|
||||
P.text('('),
|
||||
r.ws,
|
||||
r.term.repeat(1),
|
||||
P.text(')')
|
||||
).map(_ => new Or(_[4])),
|
||||
P.seq(P.text('!'), r.ws, r.term).map(_ => new Not(_[2])),
|
||||
P.seq(P.regex(/[<>]=?/), r.rawString).map(([op, val]) => {
|
||||
val = +val
|
||||
if (Number.isNaN(val)) {
|
||||
throw new TypeError('value must be a number')
|
||||
}
|
||||
return new Comparison(op, val)
|
||||
}),
|
||||
P.seq(r.string, r.ws, P.text(':'), r.ws, r.term).map(
|
||||
_ => new Property(_[0], _[4])
|
||||
),
|
||||
P.seq(r.string, P.text('?')).map(_ => new TruthyProperty(_[0])),
|
||||
P.alt(
|
||||
r.quotedString.map(_ => new StringNode(_)),
|
||||
r.rawString.map(str => {
|
||||
const asNum = +str
|
||||
return Number.isNaN(asNum)
|
||||
? new StringNode(str)
|
||||
: new NumberNode(asNum)
|
||||
})
|
||||
)
|
||||
).skip(r.ws),
|
||||
ws: P.regex(/\s*/),
|
||||
}).default
|
||||
export const parse = parser.parse.bind(parser)
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const _getPropertyClauseStrings = ({ child }) => {
|
||||
if (child instanceof Or) {
|
||||
const strings = []
|
||||
child.children.forEach(child => {
|
||||
if (child instanceof StringNode) {
|
||||
strings.push(child.value)
|
||||
}
|
||||
})
|
||||
return strings
|
||||
}
|
||||
|
||||
if (child instanceof StringNode) {
|
||||
return [child.value]
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
// Find possible values for property clauses in a and clause.
|
||||
export const getPropertyClausesStrings = node => {
|
||||
if (!node) {
|
||||
return {}
|
||||
}
|
||||
|
||||
if (node instanceof Property) {
|
||||
return {
|
||||
[node.name]: _getPropertyClauseStrings(node),
|
||||
}
|
||||
}
|
||||
|
||||
if (node instanceof And) {
|
||||
const strings = {}
|
||||
node.children.forEach(node => {
|
||||
if (node instanceof Property) {
|
||||
const { name } = node
|
||||
const values = strings[name]
|
||||
if (values) {
|
||||
values.push.apply(values, _getPropertyClauseStrings(node))
|
||||
} else {
|
||||
strings[name] = _getPropertyClauseStrings(node)
|
||||
}
|
||||
}
|
||||
})
|
||||
return strings
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
export const setPropertyClause = (node, name, child) => {
|
||||
const property =
|
||||
child &&
|
||||
new Property(
|
||||
name,
|
||||
typeof child === 'string' ? new StringNode(child) : child
|
||||
)
|
||||
|
||||
if (node === undefined) {
|
||||
return property
|
||||
}
|
||||
|
||||
const children = (node instanceof And ? node.children : [node]).filter(
|
||||
child => !(child instanceof Property && child.name === name)
|
||||
)
|
||||
if (property !== undefined) {
|
||||
children.push(property)
|
||||
}
|
||||
return new And(children)
|
||||
}
|
||||
86
packages/complex-matcher/src/index.spec.js
Normal file
86
packages/complex-matcher/src/index.spec.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import { ast, pattern } from './index.fixtures'
|
||||
import {
|
||||
getPropertyClausesStrings,
|
||||
Null,
|
||||
NumberNode,
|
||||
parse,
|
||||
setPropertyClause,
|
||||
} from './'
|
||||
|
||||
it('getPropertyClausesStrings', () => {
|
||||
const tmp = getPropertyClausesStrings(parse('foo bar:baz baz:|(foo bar)'))
|
||||
expect(tmp).toEqual({
|
||||
bar: ['baz'],
|
||||
baz: ['foo', 'bar'],
|
||||
})
|
||||
})
|
||||
|
||||
describe('parse', () => {
|
||||
it('analyses a string and returns a node/tree', () => {
|
||||
expect(parse(pattern)).toEqual(ast)
|
||||
})
|
||||
|
||||
it('supports an empty string', () => {
|
||||
expect(parse('')).toEqual(new Null())
|
||||
})
|
||||
|
||||
it('differentiate between numbers and numbers in strings', () => {
|
||||
let node
|
||||
|
||||
node = parse('32')
|
||||
expect(node.match(32)).toBe(true)
|
||||
expect(node.match('32')).toBe(false)
|
||||
expect(node.toString()).toBe('32')
|
||||
|
||||
node = parse('"32"')
|
||||
expect(node.match(32)).toBe(false)
|
||||
expect(node.match('32')).toBe(true)
|
||||
expect(node.toString()).toBe('"32"')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Number', () => {
|
||||
it('match a number recursively', () => {
|
||||
expect(new NumberNode(3).match([{ foo: 3 }])).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('setPropertyClause', () => {
|
||||
it('creates a node if none passed', () => {
|
||||
expect(setPropertyClause(undefined, 'foo', 'bar').toString()).toBe(
|
||||
'foo:bar'
|
||||
)
|
||||
})
|
||||
|
||||
it('adds a property clause if there was none', () => {
|
||||
expect(setPropertyClause(parse('baz'), 'foo', 'bar').toString()).toBe(
|
||||
'baz foo:bar'
|
||||
)
|
||||
})
|
||||
|
||||
it('replaces the property clause if there was one', () => {
|
||||
expect(
|
||||
setPropertyClause(parse('plip foo:baz plop'), 'foo', 'bar').toString()
|
||||
).toBe('plip plop foo:bar')
|
||||
|
||||
expect(
|
||||
setPropertyClause(parse('foo:|(baz plop)'), 'foo', 'bar').toString()
|
||||
).toBe('foo:bar')
|
||||
})
|
||||
|
||||
it('removes the property clause if no chid is passed', () => {
|
||||
expect(
|
||||
setPropertyClause(parse('foo bar:baz qux'), 'bar', undefined).toString()
|
||||
).toBe('foo qux')
|
||||
|
||||
expect(
|
||||
setPropertyClause(parse('foo bar:baz qux'), 'baz', undefined).toString()
|
||||
).toBe('foo bar:baz qux')
|
||||
})
|
||||
})
|
||||
|
||||
it('toString', () => {
|
||||
expect(pattern).toBe(ast.toString())
|
||||
})
|
||||
3
packages/value-matcher/.babelrc.js
Normal file
3
packages/value-matcher/.babelrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = require('../../@xen-orchestra/babel-config')(
|
||||
require('./package.json')
|
||||
)
|
||||
24
packages/value-matcher/.npmignore
Normal file
24
packages/value-matcher/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
66
packages/value-matcher/README.md
Normal file
66
packages/value-matcher/README.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# value-matcher [](https://travis-ci.org/vatefr/xen-orchestra)
|
||||
|
||||
> ${pkg.description}
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/value-matcher):
|
||||
|
||||
```
|
||||
> npm install --save value-matcher
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import { createPredicate } from 'value-matcher'
|
||||
|
||||
[
|
||||
{ user: 'sam', age: 65, active: false },
|
||||
{ user: 'barney', age: 36, active: true },
|
||||
{ user: 'fred', age: 40, active: false },
|
||||
].filter(createPredicate({
|
||||
__or: [
|
||||
{ user: 'sam' },
|
||||
{ active: true },
|
||||
],
|
||||
}))
|
||||
// [
|
||||
// { user: 'sam', age: 65, active: false },
|
||||
// { user: 'barney', age: 36, active: true },
|
||||
// ]
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> yarn
|
||||
|
||||
# Run the tests
|
||||
> yarn test
|
||||
|
||||
# Continuously compile
|
||||
> yarn dev
|
||||
|
||||
# Continuously run the tests
|
||||
> yarn dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> yarn build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Vates SAS](https://vates.fr)
|
||||
47
packages/value-matcher/package.json
Normal file
47
packages/value-matcher/package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "value-matcher",
|
||||
"version": "0.2.0",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/value-matcher",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@isonoe.net"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"browserslist": [
|
||||
">2%"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.0.0-beta.40",
|
||||
"@babel/core": "7.0.0-beta.40",
|
||||
"@babel/preset-env": "7.0.0-beta.40",
|
||||
"@babel/preset-flow": "7.0.0-beta.40",
|
||||
"cross-env": "^5.1.3",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"clean": "rimraf dist/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepare": "yarn run build",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
}
|
||||
81
packages/value-matcher/src/index.js
Normal file
81
packages/value-matcher/src/index.js
Normal file
@@ -0,0 +1,81 @@
|
||||
// @flow
|
||||
|
||||
/* eslint-disable no-use-before-define */
|
||||
export type Pattern =
|
||||
| AndPattern
|
||||
| OrPattern
|
||||
| NotPattern
|
||||
| ObjectPattern
|
||||
| ArrayPattern
|
||||
| ValuePattern
|
||||
/* eslint-enable no-use-before-define */
|
||||
|
||||
// all patterns must match
|
||||
type AndPattern = {| __and: Array<Pattern> |}
|
||||
|
||||
// one of the pattern must match
|
||||
type OrPattern = {| __or: Array<Pattern> |}
|
||||
|
||||
// the pattern must not match
|
||||
type NotPattern = {| __not: Pattern |}
|
||||
|
||||
// value is an object with properties matching the patterns
|
||||
type ObjectPattern = { [string]: Pattern }
|
||||
|
||||
// value is an array and each patterns must match a different item
|
||||
type ArrayPattern = Array<Pattern>
|
||||
|
||||
// value equals the pattern
|
||||
type ValuePattern = boolean | number | string
|
||||
|
||||
const match = (pattern: Pattern, value: any) => {
|
||||
if (Array.isArray(pattern)) {
|
||||
return (
|
||||
Array.isArray(value) &&
|
||||
pattern.every((subpattern, i) =>
|
||||
// FIXME: subpatterns should match different subvalues
|
||||
value.some(subvalue => match(subpattern, subvalue))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (pattern !== null && typeof pattern === 'object') {
|
||||
const keys = Object.keys(pattern)
|
||||
const { length } = keys
|
||||
|
||||
if (length === 1) {
|
||||
const [key] = keys
|
||||
if (key === '__and') {
|
||||
const andPattern: AndPattern = (pattern: any)
|
||||
return andPattern.__and.every(subpattern => match(subpattern, value))
|
||||
}
|
||||
if (key === '__or') {
|
||||
const orPattern: OrPattern = (pattern: any)
|
||||
return orPattern.__or.some(subpattern => match(subpattern, value))
|
||||
}
|
||||
if (key === '__not') {
|
||||
const notPattern: NotPattern = (pattern: any)
|
||||
return !match(notPattern.__not, value)
|
||||
}
|
||||
}
|
||||
|
||||
if (value === null || typeof value !== 'object') {
|
||||
return false
|
||||
}
|
||||
|
||||
const objectPattern: ObjectPattern = (pattern: any)
|
||||
for (let i = 0; i < length; ++i) {
|
||||
const key = keys[i]
|
||||
const subvalue = value[key]
|
||||
if (subvalue === undefined || !match(objectPattern[key], subvalue)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return pattern === value
|
||||
}
|
||||
|
||||
export const createPredicate = (pattern: Pattern) => (value: any) =>
|
||||
match(pattern, value)
|
||||
24
packages/vhd-cli/.npmignore
Normal file
24
packages/vhd-cli/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
51
packages/vhd-cli/README.md
Normal file
51
packages/vhd-cli/README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# vhd-cli [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> ${pkg.description}
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/vhd-cli):
|
||||
|
||||
```
|
||||
> npm install --global vhd-cli
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
> vhd-cli <VHD file>
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> npm install
|
||||
|
||||
# Run the tests
|
||||
> npm test
|
||||
|
||||
# Continuously compile
|
||||
> npm run dev
|
||||
|
||||
# Continuously run the tests
|
||||
> npm run dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> npm run build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Vates SAS](https://vates.fr)
|
||||
67
packages/vhd-cli/package.json
Normal file
67
packages/vhd-cli/package.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "vhd-cli",
|
||||
"version": "0.0.0",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/vhd-cli",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@isonoe.net"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {
|
||||
"vhd-cli": "dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nraynaud/struct-fu": "^1.0.1",
|
||||
"@nraynaud/xo-fs": "^0.0.5",
|
||||
"babel-runtime": "^6.22.0",
|
||||
"exec-promise": "^0.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.5.2",
|
||||
"babel-preset-stage-3": "^6.24.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"rimraf": "^2.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
},
|
||||
"babel": {
|
||||
"plugins": [
|
||||
"lodash",
|
||||
"transform-runtime"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-3"
|
||||
]
|
||||
}
|
||||
}
|
||||
19
packages/vhd-cli/src/index.js
Executable file
19
packages/vhd-cli/src/index.js
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import execPromise from 'exec-promise'
|
||||
import { RemoteHandlerLocal } from '@nraynaud/xo-fs'
|
||||
import { resolve } from 'path'
|
||||
|
||||
import Vhd from './vhd'
|
||||
|
||||
execPromise(async args => {
|
||||
const vhd = new Vhd(
|
||||
new RemoteHandlerLocal({ url: 'file:///' }),
|
||||
resolve(args[0])
|
||||
)
|
||||
|
||||
await vhd.readHeaderAndFooter()
|
||||
|
||||
console.log(vhd._header)
|
||||
console.log(vhd._footer)
|
||||
})
|
||||
461
packages/vhd-cli/src/vhd.js
Normal file
461
packages/vhd-cli/src/vhd.js
Normal file
@@ -0,0 +1,461 @@
|
||||
import assert from 'assert'
|
||||
import fu from '@nraynaud/struct-fu'
|
||||
import { dirname } from 'path'
|
||||
|
||||
// ===================================================================
|
||||
//
|
||||
// Spec:
|
||||
// https://www.microsoft.com/en-us/download/details.aspx?id=23850
|
||||
//
|
||||
// C implementation:
|
||||
// https://github.com/rubiojr/vhd-util-convert
|
||||
//
|
||||
// ===================================================================
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
const HARD_DISK_TYPE_DIFFERENCING = 4
|
||||
const HARD_DISK_TYPE_DYNAMIC = 3
|
||||
const HARD_DISK_TYPE_FIXED = 2
|
||||
const PLATFORM_CODE_NONE = 0
|
||||
export const SECTOR_SIZE = 512
|
||||
|
||||
/* eslint-enable no-unused vars */
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const fuFooter = fu.struct([
|
||||
fu.char('cookie', 8), // 0
|
||||
fu.uint32('features'), // 8
|
||||
fu.uint32('fileFormatVersion'), // 12
|
||||
fu.struct('dataOffset', [
|
||||
fu.uint32('high'), // 16
|
||||
fu.uint32('low'), // 20
|
||||
]),
|
||||
fu.uint32('timestamp'), // 24
|
||||
fu.char('creatorApplication', 4), // 28
|
||||
fu.uint32('creatorVersion'), // 32
|
||||
fu.uint32('creatorHostOs'), // 36
|
||||
fu.struct('originalSize', [
|
||||
// At the creation, current size of the hard disk.
|
||||
fu.uint32('high'), // 40
|
||||
fu.uint32('low'), // 44
|
||||
]),
|
||||
fu.struct('currentSize', [
|
||||
// Current size of the virtual disk. At the creation: currentSize = originalSize.
|
||||
fu.uint32('high'), // 48
|
||||
fu.uint32('low'), // 52
|
||||
]),
|
||||
fu.struct('diskGeometry', [
|
||||
fu.uint16('cylinders'), // 56
|
||||
fu.uint8('heads'), // 58
|
||||
fu.uint8('sectorsPerTrackCylinder'), // 59
|
||||
]),
|
||||
fu.uint32('diskType'), // 60 Disk type, must be equal to HARD_DISK_TYPE_DYNAMIC/HARD_DISK_TYPE_DIFFERENCING.
|
||||
fu.uint32('checksum'), // 64
|
||||
fu.uint8('uuid', 16), // 68
|
||||
fu.char('saved'), // 84
|
||||
fu.char('hidden'), // 85
|
||||
fu.byte('reserved', 426), // 86
|
||||
])
|
||||
const FOOTER_SIZE = fuFooter.size
|
||||
|
||||
const fuHeader = fu.struct([
|
||||
fu.char('cookie', 8),
|
||||
fu.struct('dataOffset', [fu.uint32('high'), fu.uint32('low')]),
|
||||
fu.struct('tableOffset', [
|
||||
// Absolute byte offset of the Block Allocation Table.
|
||||
fu.uint32('high'),
|
||||
fu.uint32('low'),
|
||||
]),
|
||||
fu.uint32('headerVersion'),
|
||||
fu.uint32('maxTableEntries'), // Max entries in the Block Allocation Table.
|
||||
fu.uint32('blockSize'), // Block size (without bitmap) in bytes.
|
||||
fu.uint32('checksum'),
|
||||
fu.uint8('parentUuid', 16),
|
||||
fu.uint32('parentTimestamp'),
|
||||
fu.byte('reserved1', 4),
|
||||
fu.char16be('parentUnicodeName', 512),
|
||||
fu.struct(
|
||||
'parentLocatorEntry',
|
||||
[
|
||||
fu.uint32('platformCode'),
|
||||
fu.uint32('platformDataSpace'),
|
||||
fu.uint32('platformDataLength'),
|
||||
fu.uint32('reserved'),
|
||||
fu.struct('platformDataOffset', [
|
||||
// Absolute byte offset of the locator data.
|
||||
fu.uint32('high'),
|
||||
fu.uint32('low'),
|
||||
]),
|
||||
],
|
||||
8
|
||||
),
|
||||
fu.byte('reserved2', 256),
|
||||
])
|
||||
const HEADER_SIZE = fuHeader.size
|
||||
|
||||
// ===================================================================
|
||||
// Helpers
|
||||
// ===================================================================
|
||||
|
||||
const SIZE_OF_32_BITS = Math.pow(2, 32)
|
||||
const uint32ToUint64 = fu => fu.high * SIZE_OF_32_BITS + fu.low
|
||||
|
||||
// Returns a 32 bits integer corresponding to a Vhd version.
|
||||
const getVhdVersion = (major, minor) => (major << 16) | (minor & 0x0000ffff)
|
||||
|
||||
// bytes[] bit manipulation
|
||||
const testBit = (map, bit) => map[bit >> 3] & (1 << (bit & 7))
|
||||
const setBit = (map, bit) => {
|
||||
map[bit >> 3] |= 1 << (bit & 7)
|
||||
}
|
||||
const unsetBit = (map, bit) => {
|
||||
map[bit >> 3] &= ~(1 << (bit & 7))
|
||||
}
|
||||
|
||||
const addOffsets = (...offsets) =>
|
||||
offsets.reduce(
|
||||
(a, b) =>
|
||||
b == null
|
||||
? a
|
||||
: typeof b === 'object'
|
||||
? { bytes: a.bytes + b.bytes, bits: a.bits + b.bits }
|
||||
: { bytes: a.bytes + b, bits: a.bits },
|
||||
{ bytes: 0, bits: 0 }
|
||||
)
|
||||
|
||||
const pack = (field, value, buf, offset) => {
|
||||
field.pack(value, buf, addOffsets(field.offset, offset))
|
||||
}
|
||||
|
||||
const unpack = (field, buf, offset) =>
|
||||
field.unpack(buf, addOffsets(field.offset, offset))
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const streamToNewBuffer = stream =>
|
||||
new Promise((resolve, reject) => {
|
||||
const chunks = []
|
||||
let length = 0
|
||||
|
||||
const onData = chunk => {
|
||||
chunks.push(chunk)
|
||||
length += chunk.length
|
||||
}
|
||||
stream.on('data', onData)
|
||||
|
||||
const clean = () => {
|
||||
stream.removeListener('data', onData)
|
||||
stream.removeListener('end', onEnd)
|
||||
stream.removeListener('error', onError)
|
||||
}
|
||||
const onEnd = () => {
|
||||
resolve(Buffer.concat(chunks, length))
|
||||
clean()
|
||||
}
|
||||
stream.on('end', onEnd)
|
||||
const onError = error => {
|
||||
reject(error)
|
||||
clean()
|
||||
}
|
||||
stream.on('error', onError)
|
||||
})
|
||||
|
||||
const streamToExistingBuffer = (
|
||||
stream,
|
||||
buffer,
|
||||
offset = 0,
|
||||
end = buffer.length
|
||||
) =>
|
||||
new Promise((resolve, reject) => {
|
||||
assert(offset >= 0)
|
||||
assert(end > offset)
|
||||
assert(end <= buffer.length)
|
||||
|
||||
let i = offset
|
||||
|
||||
const onData = chunk => {
|
||||
const prev = i
|
||||
i += chunk.length
|
||||
|
||||
if (i > end) {
|
||||
return onError(new Error('too much data'))
|
||||
}
|
||||
|
||||
chunk.copy(buffer, prev)
|
||||
}
|
||||
stream.on('data', onData)
|
||||
|
||||
const clean = () => {
|
||||
stream.removeListener('data', onData)
|
||||
stream.removeListener('end', onEnd)
|
||||
stream.removeListener('error', onError)
|
||||
}
|
||||
const onEnd = () => {
|
||||
resolve(i - offset)
|
||||
clean()
|
||||
}
|
||||
stream.on('end', onEnd)
|
||||
const onError = error => {
|
||||
reject(error)
|
||||
clean()
|
||||
}
|
||||
stream.on('error', onError)
|
||||
})
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// Returns the checksum of a raw struct.
|
||||
const computeChecksum = (struct, buf, offset = 0) => {
|
||||
let sum = 0
|
||||
|
||||
// Do not use the stored checksum to compute the new checksum.
|
||||
const checksumField = struct.fields.checksum
|
||||
const checksumOffset = offset + checksumField.offset
|
||||
for (let i = offset, n = checksumOffset; i < n; ++i) {
|
||||
sum += buf[i]
|
||||
}
|
||||
for (
|
||||
let i = checksumOffset + checksumField.size, n = offset + struct.size;
|
||||
i < n;
|
||||
++i
|
||||
) {
|
||||
sum += buf[i]
|
||||
}
|
||||
|
||||
return ~sum >>> 0
|
||||
}
|
||||
|
||||
const verifyChecksum = (struct, buf, offset) =>
|
||||
unpack(struct.fields.checksum, buf, offset) ===
|
||||
computeChecksum(struct, buf, offset)
|
||||
|
||||
const getParentLocatorSize = parentLocatorEntry => {
|
||||
const { platformDataSpace } = parentLocatorEntry
|
||||
|
||||
if (platformDataSpace < SECTOR_SIZE) {
|
||||
return platformDataSpace * SECTOR_SIZE
|
||||
}
|
||||
|
||||
return platformDataSpace % SECTOR_SIZE === 0 ? platformDataSpace : 0
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// Euclidean division, returns the quotient and the remainder of a / b.
|
||||
const div = (a, b) => [Math.floor(a / b), a % b]
|
||||
|
||||
export default class Vhd {
|
||||
constructor (handler, path) {
|
||||
this._handler = handler
|
||||
this._path = path
|
||||
|
||||
this._blockAllocationTable = null
|
||||
this._blockBitmapSize = null
|
||||
this._footer = null
|
||||
this._header = null
|
||||
this._parent = null
|
||||
this._sectorsPerBlock = null
|
||||
}
|
||||
|
||||
// Read `length` bytes starting from `begin`.
|
||||
//
|
||||
// - if `buffer`: it is filled starting from `offset`, and the
|
||||
// number of written bytes is returned;
|
||||
// - otherwise: a new buffer is allocated and returned.
|
||||
_read (begin, length, buf, offset) {
|
||||
assert(begin >= 0)
|
||||
assert(length > 0)
|
||||
|
||||
return this._handler
|
||||
.createReadStream(this._path, {
|
||||
end: begin + length - 1,
|
||||
start: begin,
|
||||
})
|
||||
.then(
|
||||
buf
|
||||
? stream =>
|
||||
streamToExistingBuffer(
|
||||
stream,
|
||||
buf,
|
||||
offset,
|
||||
(offset || 0) + length
|
||||
)
|
||||
: streamToNewBuffer
|
||||
)
|
||||
}
|
||||
|
||||
// - if `buffer`: it is filled with 0 starting from `offset`, and
|
||||
// the number of written bytes is returned;
|
||||
// - otherwise: a new buffer is allocated and returned.
|
||||
_zeroes (length, buf, offset = 0) {
|
||||
if (buf) {
|
||||
assert(offset >= 0)
|
||||
assert(length > 0)
|
||||
|
||||
const end = offset + length
|
||||
assert(end <= buf.length)
|
||||
|
||||
buf.fill(0, offset, end)
|
||||
return Promise.resolve(length)
|
||||
}
|
||||
|
||||
return Promise.resolve(Buffer.alloc(length))
|
||||
}
|
||||
|
||||
// Return the position of a block in the VHD or undefined if not found.
|
||||
_getBlockAddress (block) {
|
||||
assert(block >= 0)
|
||||
assert(block < this._header.maxTableEntries)
|
||||
|
||||
const blockAddr = this._blockAllocationTable[block]
|
||||
if (blockAddr !== 0xffffffff) {
|
||||
return blockAddr * SECTOR_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
async readHeaderAndFooter () {
|
||||
const buf = await this._read(0, FOOTER_SIZE + HEADER_SIZE)
|
||||
|
||||
if (!verifyChecksum(fuFooter, buf)) {
|
||||
throw new Error('footer checksum does not match')
|
||||
}
|
||||
|
||||
if (!verifyChecksum(fuHeader, buf, FOOTER_SIZE)) {
|
||||
throw new Error('header checksum does not match')
|
||||
}
|
||||
|
||||
return this._initMetadata(
|
||||
unpack(fuHeader, buf, FOOTER_SIZE),
|
||||
unpack(fuFooter, buf)
|
||||
)
|
||||
}
|
||||
|
||||
async _initMetadata (header, footer) {
|
||||
const sectorsPerBlock = header.blockSize / SECTOR_SIZE
|
||||
assert(sectorsPerBlock % 1 === 0)
|
||||
|
||||
// 1 bit per sector, rounded up to full sectors
|
||||
this._blockBitmapSize =
|
||||
Math.ceil(sectorsPerBlock / 8 / SECTOR_SIZE) * SECTOR_SIZE
|
||||
assert(this._blockBitmapSize === SECTOR_SIZE)
|
||||
|
||||
this._footer = footer
|
||||
this._header = header
|
||||
this.size = uint32ToUint64(this._footer.currentSize)
|
||||
|
||||
if (footer.diskType === HARD_DISK_TYPE_DIFFERENCING) {
|
||||
const parent = new Vhd(
|
||||
this._handler,
|
||||
`${dirname(this._path)}/${header.parentUnicodeName}`
|
||||
)
|
||||
await parent.readHeaderAndFooter()
|
||||
await parent.readBlockAllocationTable()
|
||||
|
||||
this._parent = parent
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
async readBlockAllocationTable () {
|
||||
const { maxTableEntries, tableOffset } = this._header
|
||||
const fuTable = fu.uint32(maxTableEntries)
|
||||
|
||||
this._blockAllocationTable = unpack(
|
||||
fuTable,
|
||||
await this._read(uint32ToUint64(tableOffset), fuTable.size)
|
||||
)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// read a single sector in a block
|
||||
async _readBlockSector (block, sector, begin, length, buf, offset) {
|
||||
assert(begin >= 0)
|
||||
assert(length > 0)
|
||||
assert(begin + length <= SECTOR_SIZE)
|
||||
|
||||
const blockAddr = this._getBlockAddress(block)
|
||||
const blockBitmapSize = this._blockBitmapSize
|
||||
const parent = this._parent
|
||||
|
||||
if (
|
||||
blockAddr &&
|
||||
(!parent || testBit(await this._read(blockAddr, blockBitmapSize), sector))
|
||||
) {
|
||||
return this._read(
|
||||
blockAddr + blockBitmapSize + sector * SECTOR_SIZE + begin,
|
||||
length,
|
||||
buf,
|
||||
offset
|
||||
)
|
||||
}
|
||||
|
||||
return parent
|
||||
? parent._readBlockSector(block, sector, begin, length, buf, offset)
|
||||
: this._zeroes(length, buf, offset)
|
||||
}
|
||||
|
||||
_readBlock (block, begin, length, buf, offset) {
|
||||
assert(begin >= 0)
|
||||
assert(length > 0)
|
||||
|
||||
const { blockSize } = this._header
|
||||
assert(begin + length <= blockSize)
|
||||
|
||||
const blockAddr = this._getBlockAddress(block)
|
||||
const parent = this._parent
|
||||
|
||||
if (!blockAddr) {
|
||||
return parent
|
||||
? parent._readBlock(block, begin, length, buf, offset)
|
||||
: this._zeroes(length, buf, offset)
|
||||
}
|
||||
|
||||
if (!parent) {
|
||||
return this._read(
|
||||
blockAddr + this._blockBitmapSize + begin,
|
||||
length,
|
||||
buf,
|
||||
offset
|
||||
)
|
||||
}
|
||||
|
||||
// FIXME: we should read as many sectors in a single pass as
|
||||
// possible for maximum perf.
|
||||
const [sector, beginInSector] = div(begin, SECTOR_SIZE)
|
||||
return this._readBlockSector(
|
||||
block,
|
||||
sector,
|
||||
beginInSector,
|
||||
Math.min(length, SECTOR_SIZE - beginInSector),
|
||||
buf,
|
||||
offset
|
||||
)
|
||||
}
|
||||
|
||||
read (buf, begin, length = buf.length, offset) {
|
||||
assert(Buffer.isBuffer(buf))
|
||||
assert(begin >= 0)
|
||||
|
||||
const { size } = this
|
||||
if (begin >= size) {
|
||||
return Promise.resolve(0)
|
||||
}
|
||||
|
||||
const { blockSize } = this._header
|
||||
const [block, beginInBlock] = div(begin, blockSize)
|
||||
|
||||
return this._readBlock(
|
||||
block,
|
||||
beginInBlock,
|
||||
Math.min(length, blockSize - beginInBlock, size - begin),
|
||||
buf,
|
||||
offset
|
||||
)
|
||||
}
|
||||
}
|
||||
24
packages/xen-api/.npmignore
Normal file
24
packages/xen-api/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
130
packages/xen-api/README.md
Normal file
130
packages/xen-api/README.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# xen-api [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> Connector to the Xen API
|
||||
|
||||
Tested with:
|
||||
|
||||
- XenServer 7.3
|
||||
- XenServer 7.2
|
||||
- XenServer 7.1
|
||||
- XenServer 7
|
||||
- XenServer 6.5
|
||||
- XenServer 6.2
|
||||
- XenServer 5.6
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/xen-api):
|
||||
|
||||
```
|
||||
> npm install --save xen-api
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Library
|
||||
|
||||
```javascript
|
||||
const { createClient } = require('xen-api')
|
||||
|
||||
const xapi = createClient({
|
||||
url: 'https://xen1.company.net',
|
||||
allowUnauthorized: false,
|
||||
auth: {
|
||||
user: 'root',
|
||||
password: 'important secret password'
|
||||
},
|
||||
readOnly: false
|
||||
})
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
- `url`: address of a host in the pool we are trying to connect to
|
||||
- `allowUnauthorized`: whether to accept self-signed certificates
|
||||
- `auth`: credentials used to sign in (can also be specified in the URL)
|
||||
- `readOnly = false`: if true, no methods with side-effects can be called
|
||||
|
||||
```js
|
||||
// Force connection.
|
||||
xapi.connect().catch(error => {
|
||||
console.error(error)
|
||||
})
|
||||
|
||||
// Watch objects.
|
||||
xapi.objects.on('add', objects => {
|
||||
console.log('new objects:', objects)
|
||||
})
|
||||
```
|
||||
|
||||
> Note: all objects are frozen and cannot be altered!
|
||||
|
||||
Custom fields on objects (hidden − ie. non enumerable):
|
||||
- `$type`: the type of the object (`VM`, `task`, …);
|
||||
- `$ref`: the (opaque) reference of the object;
|
||||
- `$id`: the identifier of this object (its UUID if any, otherwise its reference);
|
||||
- `$pool`: the pool object this object belongs to.
|
||||
|
||||
Furthermore, any field containing a reference (or references if an
|
||||
array) can be resolved by prepending the field name with a `$`:
|
||||
|
||||
```javascript
|
||||
console.log(xapi.pool.$master.$resident_VMs[0].name_label)
|
||||
// vm1
|
||||
```
|
||||
|
||||
### CLI
|
||||
|
||||
A CLI is provided to help exploration and discovery of the XAPI.
|
||||
|
||||
```
|
||||
> xen-api https://xen1.company.net root
|
||||
Password: ******
|
||||
root@xen1.company.net> xapi.status
|
||||
'connected'
|
||||
root@xen1.company.net> xapi.pool.master
|
||||
'OpaqueRef:ec7c5147-8aee-990f-c70b-0de916a8e993'
|
||||
root@xen1.company.net> xapi.pool.$master.name_label
|
||||
'xen1'
|
||||
```
|
||||
|
||||
To ease searches, `find()` and `findAll()` functions are available:
|
||||
|
||||
```
|
||||
root@xen1.company.net> findAll({ $type: 'vm' }).length
|
||||
183
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> npm install
|
||||
|
||||
# Run the tests
|
||||
> npm test
|
||||
|
||||
# Continuously compile
|
||||
> npm run dev
|
||||
|
||||
# Continuously run the tests
|
||||
> npm run dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> npm run build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/xen-api/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Julien Fontanet](https://github.com/julien-f)
|
||||
50
packages/xen-api/examples/export-vdi
Executable file
50
packages/xen-api/examples/export-vdi
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
const pump = require('pump')
|
||||
const { fromCallback } = require('promise-toolbox')
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createOutputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
let raw = false
|
||||
if (args[0] === '--raw') {
|
||||
raw = true
|
||||
args.shift()
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
return console.log('Usage: export-vdi [--raw] <XS URL> <VDI identifier> [<VHD file>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/snapshots.html#downloading-a-disk-or-snapshot
|
||||
const exportStream = await xapi.getResource('/export_raw_vdi/', {
|
||||
query: {
|
||||
format: raw ? 'raw' : 'vhd',
|
||||
vdi: await resolveRef(xapi, 'VDI', args[1])
|
||||
}
|
||||
})
|
||||
|
||||
console.warn('Export task:', exportStream.headers['task-id'])
|
||||
|
||||
await fromCallback(cb => pump(
|
||||
exportStream,
|
||||
createOutputStream(args[2]),
|
||||
cb
|
||||
))
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
44
packages/xen-api/examples/export-vm
Executable file
44
packages/xen-api/examples/export-vm
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
const pump = require('pump')
|
||||
const { fromCallback } = require('promise-toolbox')
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createOutputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
if (args.length < 2) {
|
||||
return console.log('Usage: export-vm <XS URL> <VM identifier> [<XVA file>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/importexport.html
|
||||
const exportStream = await xapi.getResource('/export/', {
|
||||
query: {
|
||||
ref: await resolveRef(xapi, 'VM', args[1]),
|
||||
use_compression: 'true'
|
||||
}
|
||||
})
|
||||
|
||||
console.warn('Export task:', exportStream.headers['task-id'])
|
||||
|
||||
await fromCallback(cb => pump(
|
||||
exportStream,
|
||||
createOutputStream(args[2]),
|
||||
cb
|
||||
))
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
40
packages/xen-api/examples/import-vdi
Executable file
40
packages/xen-api/examples/import-vdi
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createInputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
let raw = false
|
||||
if (args[0] === '--raw') {
|
||||
raw = true
|
||||
args.shift()
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
return console.log('Usage: import-vdi [--raw] <XS URL> <VDI identifier> [<VHD file>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/snapshots.html#uploading-a-disk-or-snapshot
|
||||
await xapi.putResource(createInputStream(args[2]), '/import_raw_vdi/', {
|
||||
query: {
|
||||
format: raw ? 'raw' : 'vhd',
|
||||
vdi: await resolveRef(xapi, 'VDI', args[1])
|
||||
}
|
||||
})
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
31
packages/xen-api/examples/import-vm
Executable file
31
packages/xen-api/examples/import-vm
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createInputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
if (args.length < 1) {
|
||||
return console.log('Usage: import-vm <XS URL> [<XVA file>] [<SR identifier>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/importexport.html
|
||||
await xapi.putResource(createInputStream(args[1]), '/import/', {
|
||||
query: args[2] && { sr_id: await resolveRef(xapi, 'SR', args[2]) }
|
||||
})
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
57
packages/xen-api/examples/log-events
Executable file
57
packages/xen-api/examples/log-events
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('source-map-support').install()
|
||||
|
||||
const { forEach, size } = require('lodash')
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
// ===================================================================
|
||||
|
||||
if (process.argv.length < 3) {
|
||||
return console.log('Usage: log-events <XS URL>')
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Creation
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: process.argv[2]
|
||||
})
|
||||
|
||||
// ===================================================================
|
||||
// Method call
|
||||
|
||||
xapi.connect().then(() => {
|
||||
xapi.call('VM.get_all_records')
|
||||
.then(function (vms) {
|
||||
console.log('%s VMs fetched', size(vms))
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error)
|
||||
})
|
||||
})
|
||||
|
||||
// ===================================================================
|
||||
// Objects
|
||||
|
||||
const objects = xapi.objects
|
||||
|
||||
objects.on('add', objects => {
|
||||
forEach(objects, object => {
|
||||
console.log('+ %s: %s', object.$type, object.$id)
|
||||
})
|
||||
})
|
||||
|
||||
objects.on('update', objects => {
|
||||
forEach(objects, object => {
|
||||
console.log('± %s: %s', object.$type, object.$id)
|
||||
})
|
||||
})
|
||||
|
||||
objects.on('remove', objects => {
|
||||
forEach(objects, (value, id) => {
|
||||
console.log('- %s', id)
|
||||
})
|
||||
})
|
||||
6
packages/xen-api/examples/package.json
Normal file
6
packages/xen-api/examples/package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"golike-defer": "^0.1.0",
|
||||
"pump": "^1.0.2"
|
||||
}
|
||||
}
|
||||
43
packages/xen-api/examples/utils.js
Normal file
43
packages/xen-api/examples/utils.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const { createReadStream, createWriteStream, statSync } = require('fs')
|
||||
const { PassThrough } = require('stream')
|
||||
|
||||
const { isOpaqueRef } = require('../')
|
||||
|
||||
exports.createInputStream = path => {
|
||||
if (path === undefined || path === '-') {
|
||||
return process.stdin
|
||||
}
|
||||
|
||||
const { size } = statSync(path)
|
||||
|
||||
const stream = createReadStream(path)
|
||||
stream.length = size
|
||||
return stream
|
||||
}
|
||||
|
||||
exports.createOutputStream = path => {
|
||||
if (path !== undefined && path !== '-') {
|
||||
return createWriteStream(path)
|
||||
}
|
||||
|
||||
// introduce a through stream because stdout is not a normal stream!
|
||||
const stream = new PassThrough()
|
||||
stream.pipe(process.stdout)
|
||||
return stream
|
||||
}
|
||||
|
||||
exports.resolveRef = (xapi, type, refOrUuidOrNameLabel) =>
|
||||
isOpaqueRef(refOrUuidOrNameLabel)
|
||||
? refOrUuidOrNameLabel
|
||||
: xapi.call(`${type}.get_by_uuid`, refOrUuidOrNameLabel).catch(() =>
|
||||
xapi
|
||||
.call(`${type}.get_by_name_label`, refOrUuidOrNameLabel)
|
||||
.then(refs => {
|
||||
if (refs.length === 1) {
|
||||
return refs[0]
|
||||
}
|
||||
throw new Error(
|
||||
`no single match for ${type} with name label ${refOrUuidOrNameLabel}`
|
||||
)
|
||||
})
|
||||
)
|
||||
4
packages/xen-api/memory-test.gnu
Normal file
4
packages/xen-api/memory-test.gnu
Normal file
@@ -0,0 +1,4 @@
|
||||
set yrange [ 0 : ]
|
||||
set grid
|
||||
|
||||
plot for [i=2:4] "plot.dat" using 1:i with lines
|
||||
89
packages/xen-api/package.json
Normal file
89
packages/xen-api/package.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"name": "xen-api",
|
||||
"version": "0.16.6",
|
||||
"license": "ISC",
|
||||
"description": "Connector to the Xen API",
|
||||
"keywords": [
|
||||
"xen",
|
||||
"api",
|
||||
"xen-api",
|
||||
"xenapi",
|
||||
"xapi"
|
||||
],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/xen-api",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@vates.fr"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {
|
||||
"xen-api": "dist/cli.js"
|
||||
},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"blocked": "^1.2.1",
|
||||
"debug": "^3.1.0",
|
||||
"event-to-promise": "^0.8.0",
|
||||
"exec-promise": "^0.7.0",
|
||||
"http-request-plus": "^0.5.0",
|
||||
"iterable-backoff": "^0.0.0",
|
||||
"json-rpc-protocol": "^0.11.2",
|
||||
"kindof": "^2.0.0",
|
||||
"lodash": "^4.17.4",
|
||||
"make-error": "^1.3.0",
|
||||
"minimist": "^1.2.0",
|
||||
"ms": "^2.1.1",
|
||||
"promise-toolbox": "^0.9.5",
|
||||
"pw": "0.0.4",
|
||||
"xmlrpc": "^1.3.2",
|
||||
"xo-collection": "^0.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-function-bind": "^6.22.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-stage-3": "^6.24.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"rimraf": "^2.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"plot": "gnuplot -p memory-test.gnu",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
},
|
||||
"babel": {
|
||||
"plugins": [
|
||||
"lodash",
|
||||
"transform-decorators-legacy",
|
||||
"transform-function-bind"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-3"
|
||||
]
|
||||
}
|
||||
}
|
||||
106
packages/xen-api/src/cli.js
Executable file
106
packages/xen-api/src/cli.js
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import 'babel-polyfill'
|
||||
|
||||
import blocked from 'blocked'
|
||||
import createDebug from 'debug'
|
||||
import eventToPromise from 'event-to-promise'
|
||||
import execPromise from 'exec-promise'
|
||||
import minimist from 'minimist'
|
||||
import pw from 'pw'
|
||||
import { asCallback, fromCallback } from 'promise-toolbox'
|
||||
import { filter, find, isArray } from 'lodash'
|
||||
import { start as createRepl } from 'repl'
|
||||
|
||||
import { createClient } from './'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
function askPassword (prompt = 'Password: ') {
|
||||
if (prompt) {
|
||||
process.stdout.write(prompt)
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
pw(resolve)
|
||||
})
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const usage = 'Usage: xen-api <url> [<user> [<password>]]'
|
||||
|
||||
const main = async args => {
|
||||
const opts = minimist(args, {
|
||||
boolean: ['allow-unauthorized', 'help', 'read-only', 'verbose'],
|
||||
|
||||
alias: {
|
||||
'allow-unauthorized': 'au',
|
||||
debounce: 'd',
|
||||
help: 'h',
|
||||
'read-only': 'ro',
|
||||
verbose: 'v',
|
||||
},
|
||||
})
|
||||
|
||||
if (opts.help) {
|
||||
return usage
|
||||
}
|
||||
|
||||
if (opts.verbose) {
|
||||
// Does not work perfectly.
|
||||
//
|
||||
// https://github.com/visionmedia/debug/pull/156
|
||||
createDebug.enable('xen-api,xen-api:*')
|
||||
}
|
||||
|
||||
let auth
|
||||
if (opts._.length > 1) {
|
||||
const [, user, password = await askPassword()] = opts._
|
||||
auth = { user, password }
|
||||
}
|
||||
|
||||
{
|
||||
const debug = createDebug('xen-api:perf')
|
||||
blocked(ms => {
|
||||
debug('blocked for %sms', ms | 0)
|
||||
})
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
url: opts._[0],
|
||||
allowUnauthorized: opts.au,
|
||||
auth,
|
||||
debounce: opts.debounce != null ? +opts.debounce : null,
|
||||
readOnly: opts.ro,
|
||||
})
|
||||
await xapi.connect()
|
||||
|
||||
const repl = createRepl({
|
||||
prompt: `${xapi._humanId}> `,
|
||||
})
|
||||
repl.context.xapi = xapi
|
||||
|
||||
repl.context.find = predicate => find(xapi.objects.all, predicate)
|
||||
repl.context.findAll = predicate => filter(xapi.objects.all, predicate)
|
||||
|
||||
// Make the REPL waits for promise completion.
|
||||
repl.eval = (evaluate => (cmd, context, filename, cb) => {
|
||||
;fromCallback(cb => {
|
||||
evaluate.call(repl, cmd, context, filename, cb)
|
||||
})
|
||||
.then(value => (isArray(value) ? Promise.all(value) : value))
|
||||
::asCallback(cb)
|
||||
})(repl.eval)
|
||||
|
||||
await eventToPromise(repl, 'exit')
|
||||
|
||||
try {
|
||||
await xapi.disconnect()
|
||||
} catch (error) {}
|
||||
}
|
||||
export default main
|
||||
|
||||
if (!module.parent) {
|
||||
execPromise(main)
|
||||
}
|
||||
1060
packages/xen-api/src/index.js
Normal file
1060
packages/xen-api/src/index.js
Normal file
File diff suppressed because it is too large
Load Diff
32
packages/xen-api/src/inject-events.js
Executable file
32
packages/xen-api/src/inject-events.js
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { delay as pDelay } from 'promise-toolbox'
|
||||
|
||||
import { createClient } from './'
|
||||
|
||||
const xapi = (() => {
|
||||
const [, , url, user, password] = process.argv
|
||||
|
||||
return createClient({
|
||||
auth: { user, password },
|
||||
url,
|
||||
watchEvents: false,
|
||||
})
|
||||
})()
|
||||
|
||||
xapi
|
||||
.connect()
|
||||
|
||||
// Get the pool record's ref.
|
||||
.then(() => xapi.call('pool.get_all'))
|
||||
|
||||
// Injects lots of events.
|
||||
.then(([poolRef]) => {
|
||||
const loop = () =>
|
||||
xapi
|
||||
.call('event.inject', 'pool', poolRef)
|
||||
::pDelay(10) // A small delay is required to avoid overloading the Xen API.
|
||||
.then(loop)
|
||||
|
||||
return loop()
|
||||
})
|
||||
22
packages/xen-api/src/memory-test.js
Executable file
22
packages/xen-api/src/memory-test.js
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { createClient } from './'
|
||||
|
||||
let i = 0
|
||||
setInterval(() => {
|
||||
const usage = process.memoryUsage()
|
||||
console.log(
|
||||
'%s %s %s %s',
|
||||
i++,
|
||||
Math.round(usage.rss / 1e6),
|
||||
Math.round(usage.heapTotal / 1e6),
|
||||
Math.round(usage.heapUsed / 1e6)
|
||||
)
|
||||
}, 1e2)
|
||||
|
||||
const [, , url, user, password] = process.argv
|
||||
createClient({
|
||||
auth: { user, password },
|
||||
readOnly: true,
|
||||
url,
|
||||
}).connect()
|
||||
3
packages/xen-api/src/transports/_utils.js
Normal file
3
packages/xen-api/src/transports/_utils.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import makeError from 'make-error'
|
||||
|
||||
export const UnsupportedTransport = makeError('UnsupportedTransport')
|
||||
36
packages/xen-api/src/transports/auto.js
Normal file
36
packages/xen-api/src/transports/auto.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import jsonRpc from './json-rpc'
|
||||
import xmlRpc from './xml-rpc'
|
||||
import xmlRpcJson from './xml-rpc-json'
|
||||
import { UnsupportedTransport } from './_utils'
|
||||
|
||||
const factories = [jsonRpc, xmlRpcJson, xmlRpc]
|
||||
const { length } = factories
|
||||
|
||||
export default opts => {
|
||||
let i = 0
|
||||
|
||||
let call
|
||||
function create () {
|
||||
const current = factories[i++](opts)
|
||||
if (i < length) {
|
||||
const currentI = i
|
||||
call = (method, args) =>
|
||||
current(method, args).catch(error => {
|
||||
if (error instanceof UnsupportedTransport) {
|
||||
if (currentI === i) {
|
||||
// not changed yet
|
||||
create()
|
||||
}
|
||||
return call(method, args)
|
||||
}
|
||||
|
||||
throw error
|
||||
})
|
||||
} else {
|
||||
call = current
|
||||
}
|
||||
}
|
||||
create()
|
||||
|
||||
return (method, args) => call(method, args)
|
||||
}
|
||||
43
packages/xen-api/src/transports/json-rpc.js
Normal file
43
packages/xen-api/src/transports/json-rpc.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import httpRequestPlus from 'http-request-plus'
|
||||
import { format, parse } from 'json-rpc-protocol'
|
||||
|
||||
import { UnsupportedTransport } from './_utils'
|
||||
|
||||
export default ({ allowUnauthorized, url }) => {
|
||||
return (method, args) =>
|
||||
httpRequestPlus
|
||||
.post(url, {
|
||||
rejectUnauthorized: !allowUnauthorized,
|
||||
body: format.request(0, method, args),
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
path: '/jsonrpc',
|
||||
})
|
||||
.readAll('utf8')
|
||||
.then(
|
||||
text => {
|
||||
let response
|
||||
try {
|
||||
response = parse(text)
|
||||
} catch (error) {
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
if (response.type === 'response') {
|
||||
return response.result
|
||||
}
|
||||
|
||||
throw response.error
|
||||
},
|
||||
error => {
|
||||
if (error.response !== undefined) {
|
||||
// HTTP error
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
)
|
||||
}
|
||||
87
packages/xen-api/src/transports/xml-rpc-json.js
Normal file
87
packages/xen-api/src/transports/xml-rpc-json.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import { createClient, createSecureClient } from 'xmlrpc'
|
||||
import { promisify } from 'promise-toolbox'
|
||||
|
||||
import { UnsupportedTransport } from './_utils'
|
||||
|
||||
const logError = error => {
|
||||
if (error.res) {
|
||||
console.error(
|
||||
'XML-RPC Error: %s (response status %s)',
|
||||
error.message,
|
||||
error.res.statusCode
|
||||
)
|
||||
console.error('%s', error.body)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
|
||||
const SPECIAL_CHARS = {
|
||||
'\r': '\\r',
|
||||
'\t': '\\t',
|
||||
}
|
||||
const SPECIAL_CHARS_RE = new RegExp(Object.keys(SPECIAL_CHARS).join('|'), 'g')
|
||||
|
||||
const parseResult = result => {
|
||||
const status = result.Status
|
||||
|
||||
// Return the plain result if it does not have a valid XAPI
|
||||
// format.
|
||||
if (status === undefined) {
|
||||
return result
|
||||
}
|
||||
|
||||
if (status !== 'Success') {
|
||||
throw result.ErrorDescription
|
||||
}
|
||||
|
||||
const value = result.Value
|
||||
|
||||
// XAPI returns an empty string (invalid JSON) for an empty
|
||||
// result.
|
||||
if (value === '') {
|
||||
return ''
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch (error) {
|
||||
// XAPI JSON sometimes contains invalid characters.
|
||||
if (!(error instanceof SyntaxError)) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
let replaced = false
|
||||
const fixedValue = value.replace(SPECIAL_CHARS_RE, match => {
|
||||
replaced = true
|
||||
return SPECIAL_CHARS[match]
|
||||
})
|
||||
|
||||
if (replaced) {
|
||||
try {
|
||||
return JSON.parse(fixedValue)
|
||||
} catch (error) {
|
||||
if (!(error instanceof SyntaxError)) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
export default ({
|
||||
allowUnauthorized,
|
||||
url: { hostname, path, port, protocol },
|
||||
}) => {
|
||||
const client = (protocol === 'https:' ? createSecureClient : createClient)({
|
||||
host: hostname,
|
||||
path: '/json',
|
||||
port,
|
||||
rejectUnauthorized: !allowUnauthorized,
|
||||
})
|
||||
const call = promisify(client.methodCall, client)
|
||||
|
||||
return (method, args) => call(method, args).then(parseResult, logError)
|
||||
}
|
||||
45
packages/xen-api/src/transports/xml-rpc.js
Normal file
45
packages/xen-api/src/transports/xml-rpc.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import { createClient, createSecureClient } from 'xmlrpc'
|
||||
import { promisify } from 'promise-toolbox'
|
||||
|
||||
const logError = error => {
|
||||
if (error.res) {
|
||||
console.error(
|
||||
'XML-RPC Error: %s (response status %s)',
|
||||
error.message,
|
||||
error.res.statusCode
|
||||
)
|
||||
console.error('%s', error.body)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
|
||||
const parseResult = result => {
|
||||
const status = result.Status
|
||||
|
||||
// Return the plain result if it does not have a valid XAPI
|
||||
// format.
|
||||
if (status === undefined) {
|
||||
return result
|
||||
}
|
||||
|
||||
if (status !== 'Success') {
|
||||
throw result.ErrorDescription
|
||||
}
|
||||
|
||||
return result.Value
|
||||
}
|
||||
|
||||
export default ({
|
||||
allowUnauthorized,
|
||||
url: { hostname, path, port, protocol },
|
||||
}) => {
|
||||
const client = (protocol === 'https:' ? createSecureClient : createClient)({
|
||||
host: hostname,
|
||||
port,
|
||||
rejectUnauthorized: !allowUnauthorized,
|
||||
})
|
||||
const call = promisify(client.methodCall, client)
|
||||
|
||||
return (method, args) => call(method, args).then(parseResult, logError)
|
||||
}
|
||||
13
packages/xo-acl-resolver/.babelrc
Normal file
13
packages/xo-acl-resolver/.babelrc
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"comments": false,
|
||||
"compact": true,
|
||||
"presets": [
|
||||
[
|
||||
"env", {
|
||||
"targets": {
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
74
packages/xo-acl-resolver/README.md
Normal file
74
packages/xo-acl-resolver/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# xo-acl-resolver [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> [Xen-Orchestra](http://xen-orchestra.com/) internal: do ACLs resolution.
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/xo-acl-resolver):
|
||||
|
||||
```
|
||||
> npm install --save xo-acl-resolver
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import check from 'xo-acl-resolver'
|
||||
|
||||
// This object contains a list of permissions returned from
|
||||
// xo-server's acl.getCurrentPermissions.
|
||||
const permissions = { /* ... */ }
|
||||
|
||||
// This function should returns synchronously an object from an id.
|
||||
const getObject = id => { /* ... */ }
|
||||
|
||||
// For a single object:
|
||||
if (check(permissions, getObject, objectId, permission)) {
|
||||
console.log(`${permission} set for object ${objectId}`)
|
||||
}
|
||||
|
||||
// For multiple objects/permissions:
|
||||
if (check(permissions, getObject, [
|
||||
[ object1Id, permission1 ],
|
||||
[ object12d, permission2 ],
|
||||
])) {
|
||||
console.log('all permissions checked')
|
||||
}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Installing dependencies
|
||||
|
||||
```
|
||||
> npm install
|
||||
```
|
||||
|
||||
### Compilation
|
||||
|
||||
The sources files are watched and automatically recompiled on changes.
|
||||
|
||||
```
|
||||
> npm run dev
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
```
|
||||
> npm run test-dev
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Vates SAS](https://vates.fr)
|
||||
35
packages/xo-acl-resolver/package.json
Normal file
35
packages/xo-acl-resolver/package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "xo-acl-resolver",
|
||||
"version": "0.2.3",
|
||||
"license": "ISC",
|
||||
"description": "Xen-Orchestra internal: do ACLs resolution",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/xo-acl-resolver",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@vates.fr"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-preset-env": "^1.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
}
|
||||
125
packages/xo-acl-resolver/src/index.js
Normal file
125
packages/xo-acl-resolver/src/index.js
Normal file
@@ -0,0 +1,125 @@
|
||||
// These global variables are not a problem because the algorithm is
|
||||
// synchronous.
|
||||
let permissionsByObject
|
||||
let getObject
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const authorized = () => true // eslint-disable-line no-unused-vars
|
||||
const forbiddden = () => false // eslint-disable-line no-unused-vars
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const and = (...checkers) => (object, permission) => {
|
||||
for (const checker of checkers) {
|
||||
if (!checker(object, permission)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const or = (...checkers) => (object, permission) => {
|
||||
for (const checker of checkers) {
|
||||
if (checker(object, permission)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const checkMember = memberName => (object, permission) => {
|
||||
const member = object[memberName]
|
||||
return member !== object.id && checkAuthorization(member, permission)
|
||||
}
|
||||
|
||||
const checkSelf = ({ id }, permission) => {
|
||||
const permissionsForObject = permissionsByObject[id]
|
||||
|
||||
return permissionsForObject && permissionsForObject[permission]
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const checkAuthorizationByTypes = {
|
||||
host: or(checkSelf, checkMember('$pool')),
|
||||
|
||||
message: checkMember('$object'),
|
||||
|
||||
network: or(checkSelf, checkMember('$pool')),
|
||||
|
||||
SR: or(checkSelf, checkMember('$pool')),
|
||||
|
||||
task: checkMember('$host'),
|
||||
|
||||
VBD: checkMember('VDI'),
|
||||
|
||||
// Access to a VDI is granted if the user has access to the
|
||||
// containing SR or to a linked VM.
|
||||
VDI (vdi, permission) {
|
||||
// Check authorization for the containing SR.
|
||||
if (checkAuthorization(vdi.$SR, permission)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check authorization for each of the connected VMs.
|
||||
for (const vbdId of vdi.$VBDs) {
|
||||
if (checkAuthorization(getObject(vbdId).VM, permission)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
|
||||
'VDI-snapshot': checkMember('$snapshot_of'),
|
||||
|
||||
VIF: or(checkMember('$network'), checkMember('$VM')),
|
||||
|
||||
VM: or(checkSelf, checkMember('$container')),
|
||||
|
||||
'VM-controller': checkMember('$container'),
|
||||
|
||||
'VM-snapshot': checkMember('$snapshot_of'),
|
||||
|
||||
'VM-template': or(checkSelf, checkMember('$pool')),
|
||||
}
|
||||
|
||||
// Hoisting is important for this function.
|
||||
function checkAuthorization (objectId, permission) {
|
||||
const object = getObject(objectId)
|
||||
if (!object) {
|
||||
return false
|
||||
}
|
||||
|
||||
const checker = checkAuthorizationByTypes[object.type] || checkSelf
|
||||
|
||||
return checker(object, permission)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
export default (permissionsByObject_, getObject_, permissions, permission) => {
|
||||
// Assign global variables.
|
||||
permissionsByObject = permissionsByObject_
|
||||
getObject = getObject_
|
||||
|
||||
try {
|
||||
if (permission) {
|
||||
return checkAuthorization(permissions, permission)
|
||||
} else {
|
||||
for (const [objectId, permission] of permissions) {
|
||||
if (!checkAuthorization(objectId, permission)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
} finally {
|
||||
// Free the global variables.
|
||||
permissionsByObject = getObject = null
|
||||
}
|
||||
}
|
||||
3
packages/xo-cli/.babelrc.js
Normal file
3
packages/xo-cli/.babelrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = require('../../@xen-orchestra/babel-config')(
|
||||
require('./package.json')
|
||||
)
|
||||
24
packages/xo-cli/.npmignore
Normal file
24
packages/xo-cli/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
159
packages/xo-cli/README.md
Normal file
159
packages/xo-cli/README.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# XO-CLI
|
||||
[](http://travis-ci.org/vatesfr/xen-orchestra)
|
||||
[](https://david-dm.org/vatesfr/xo-cli)
|
||||
[](https://david-dm.org/vatesfr/xo-cli#info=devDependencies)
|
||||
|
||||
> Basic CLI for Xen-Orchestra
|
||||
|
||||
## Install
|
||||
|
||||
#### [npm](https://npmjs.org/package/xo-cli)
|
||||
|
||||
```
|
||||
npm install -g xo-cli
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
> xo-cli --help
|
||||
Usage:
|
||||
|
||||
xo-cli --register [--expiresIn duration] <XO-Server URL> <username> [<password>]
|
||||
Registers the XO instance to use.
|
||||
|
||||
--expiresIn duration
|
||||
Can be used to change the validity duration of the
|
||||
authorization token (default: one month).
|
||||
|
||||
xo-cli --unregister
|
||||
Remove stored credentials.
|
||||
|
||||
xo-cli --list-commands [--json] [<pattern>]...
|
||||
Returns the list of available commands on the current XO instance.
|
||||
|
||||
The patterns can be used to filter on command names.
|
||||
|
||||
xo-cli --list-objects [--<property>]… [<property>=<value>]...
|
||||
Returns a list of XO objects.
|
||||
|
||||
--<property>
|
||||
Restricts displayed properties to those listed.
|
||||
|
||||
<property>=<value>
|
||||
Restricted displayed objects to those matching the patterns.
|
||||
|
||||
xo-cli <command> [<name>=<value>]...
|
||||
Executes a command on the current XO instance.
|
||||
```
|
||||
|
||||
#### Register your XO instance
|
||||
|
||||
```
|
||||
> xo-cli --register http://xo.my-company.net admin@admin.net admin
|
||||
Successfully logged with admin@admin.net
|
||||
```
|
||||
|
||||
Note: only a token will be saved in the configuration file.
|
||||
|
||||
#### List available objects
|
||||
|
||||
Prints all objects:
|
||||
|
||||
```
|
||||
> xo-cli --list-objects
|
||||
```
|
||||
|
||||
It is possible to filter on object properties, for instance to prints
|
||||
all VM templates:
|
||||
|
||||
```
|
||||
> xo-cli --list-objects type=VM-template
|
||||
```
|
||||
|
||||
#### List available commands
|
||||
|
||||
```
|
||||
> xo-cli --list-commands
|
||||
```
|
||||
|
||||
Commands can be filtered using patterns:
|
||||
|
||||
```
|
||||
> xo-cli --list-commands '{user,group}.*'
|
||||
```
|
||||
|
||||
#### Execute a command
|
||||
|
||||
The same syntax is used for all commands: `xo-cli <command> <param
|
||||
name>=<value>...`
|
||||
|
||||
E.g., adding a new server:
|
||||
|
||||
```
|
||||
> xo-cli server.add host=my.server.net username=root password=secret-password
|
||||
42
|
||||
```
|
||||
|
||||
The return value is the identifier of this new server in XO.
|
||||
|
||||
Parameters (except `true` and `false` which are correctly parsed as
|
||||
booleans) are assumed to be strings, for other types, you may use JSON
|
||||
encoding by prefixing with `json:`:
|
||||
|
||||
```
|
||||
> xo-cli foo.bar baz='json:[1, 2, 3]'
|
||||
```
|
||||
|
||||
##### Configuration export
|
||||
|
||||
```
|
||||
> xo-cli xo.exportConfig @=config.json
|
||||
```
|
||||
|
||||
##### VM export
|
||||
|
||||
```
|
||||
> xo-cli vm.export vm=a01667e0-8e29-49fc-a550-17be4226783c @=vm.xva
|
||||
```
|
||||
|
||||
##### VM import
|
||||
|
||||
```
|
||||
> xo-cli vm.import host=60a6939e-8b0a-4352-9954-5bde44bcdf7d @=vm.xva
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> yarn
|
||||
|
||||
# Run the tests
|
||||
> yarn test
|
||||
|
||||
# Continuously compile
|
||||
> yarn dev
|
||||
|
||||
# Continuously run the tests
|
||||
> yarn dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> yarn build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
XO-CLI is released under the [AGPL
|
||||
v3](http://www.gnu.org/licenses/agpl-3.0-standalone.html).
|
||||
67
packages/xo-cli/package.json
Normal file
67
packages/xo-cli/package.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "xo-cli",
|
||||
"version": "0.10.1",
|
||||
"license": "AGPL-3.0",
|
||||
"description": "Basic CLI for Xen-Orchestra",
|
||||
"keywords": [
|
||||
"xo",
|
||||
"xen-orchestra",
|
||||
"xen",
|
||||
"orchestra"
|
||||
],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/xo-cli",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": "Julien Fontanet <julien.fontanet@vates.fr>",
|
||||
"preferGlobal": true,
|
||||
"main": "dist/",
|
||||
"bin": {
|
||||
"xo-cli": "dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "7.0.0-beta.40",
|
||||
"bluebird": "^3.5.1",
|
||||
"chalk": "^2.2.0",
|
||||
"event-to-promise": "^0.8.0",
|
||||
"exec-promise": "^0.7.0",
|
||||
"fs-promise": "^2.0.3",
|
||||
"got": "^8.0.1",
|
||||
"human-format": "^0.10.0",
|
||||
"l33teral": "^3.0.3",
|
||||
"lodash": "^4.17.4",
|
||||
"micromatch": "^3.1.3",
|
||||
"mkdirp": "^0.5.1",
|
||||
"nice-pipe": "0.0.0",
|
||||
"pretty-ms": "^3.0.1",
|
||||
"progress-stream": "^2.0.0",
|
||||
"pw": "^0.0.4",
|
||||
"strip-indent": "^2.0.0",
|
||||
"xdg-basedir": "^3.0.0",
|
||||
"xo-lib": "^0.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.0.0-beta.40",
|
||||
"@babel/core": "7.0.0-beta.40",
|
||||
"@babel/preset-env": "7.0.0-beta.40",
|
||||
"@babel/preset-flow": "7.0.0-beta.40",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"cross-env": "^5.1.3",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
}
|
||||
56
packages/xo-cli/src/config.js
Normal file
56
packages/xo-cli/src/config.js
Normal file
@@ -0,0 +1,56 @@
|
||||
'use strict'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const promisify = require('bluebird').promisify
|
||||
|
||||
const readFile = promisify(require('fs').readFile)
|
||||
const writeFile = promisify(require('fs').writeFile)
|
||||
|
||||
const assign = require('lodash/assign')
|
||||
const l33t = require('l33teral')
|
||||
const mkdirp = promisify(require('mkdirp'))
|
||||
const xdgBasedir = require('xdg-basedir')
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const configPath = xdgBasedir.config + '/xo-cli'
|
||||
const configFile = configPath + '/config.json'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const load = (exports.load = function () {
|
||||
return readFile(configFile)
|
||||
.then(JSON.parse)
|
||||
.catch(function () {
|
||||
return {}
|
||||
})
|
||||
})
|
||||
|
||||
exports.get = function (path) {
|
||||
return load().then(function (config) {
|
||||
return l33t(config).tap(path)
|
||||
})
|
||||
}
|
||||
|
||||
const save = (exports.save = function (config) {
|
||||
return mkdirp(configPath).then(function () {
|
||||
return writeFile(configFile, JSON.stringify(config))
|
||||
})
|
||||
})
|
||||
|
||||
exports.set = function (data) {
|
||||
return load().then(function (config) {
|
||||
return save(assign(config, data))
|
||||
})
|
||||
}
|
||||
|
||||
exports.unset = function (paths) {
|
||||
return load().then(function (config) {
|
||||
const l33tConfig = l33t(config)
|
||||
;[].concat(paths).forEach(function (path) {
|
||||
l33tConfig.purge(path, true)
|
||||
})
|
||||
return save(config)
|
||||
})
|
||||
}
|
||||
420
packages/xo-cli/src/index.js
Executable file
420
packages/xo-cli/src/index.js
Executable file
@@ -0,0 +1,420 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
const Bluebird = require('bluebird')
|
||||
Bluebird.longStackTraces()
|
||||
|
||||
const createReadStream = require('fs').createReadStream
|
||||
const createWriteStream = require('fs').createWriteStream
|
||||
const resolveUrl = require('url').resolve
|
||||
const stat = require('fs-promise').stat
|
||||
|
||||
const chalk = require('chalk')
|
||||
const eventToPromise = require('event-to-promise')
|
||||
const forEach = require('lodash/forEach')
|
||||
const getKeys = require('lodash/keys')
|
||||
const got = require('got')
|
||||
const humanFormat = require('human-format')
|
||||
const identity = require('lodash/identity')
|
||||
const isArray = require('lodash/isArray')
|
||||
const isObject = require('lodash/isObject')
|
||||
const micromatch = require('micromatch')
|
||||
const nicePipe = require('nice-pipe')
|
||||
const pairs = require('lodash/toPairs')
|
||||
const pick = require('lodash/pick')
|
||||
const startsWith = require('lodash/startsWith')
|
||||
const prettyMs = require('pretty-ms')
|
||||
const progressStream = require('progress-stream')
|
||||
const pw = require('pw')
|
||||
const Xo = require('xo-lib').default
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const config = require('./config')
|
||||
|
||||
// ===================================================================
|
||||
|
||||
async function connect () {
|
||||
const { server, token } = await config.load()
|
||||
if (server === undefined) {
|
||||
throw new Error('no server to connect to!')
|
||||
}
|
||||
|
||||
if (token === undefined) {
|
||||
throw new Error('no token available')
|
||||
}
|
||||
|
||||
const xo = new Xo({ url: server })
|
||||
await xo.open()
|
||||
await xo.signIn({ token })
|
||||
return xo
|
||||
}
|
||||
|
||||
const FLAG_RE = /^--([^=]+)(?:=([^]*))?$/
|
||||
function extractFlags (args) {
|
||||
const flags = {}
|
||||
|
||||
let i = 0
|
||||
const n = args.length
|
||||
let matches
|
||||
while (i < n && (matches = args[i].match(FLAG_RE))) {
|
||||
const value = matches[2]
|
||||
|
||||
flags[matches[1]] = value === undefined ? true : value
|
||||
++i
|
||||
}
|
||||
args.splice(0, i)
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
const PARAM_RE = /^([^=]+)=([^]*)$/
|
||||
function parseParameters (args) {
|
||||
const params = {}
|
||||
forEach(args, function (arg) {
|
||||
let matches
|
||||
if (!(matches = arg.match(PARAM_RE))) {
|
||||
throw new Error('invalid arg: ' + arg)
|
||||
}
|
||||
const name = matches[1]
|
||||
let value = matches[2]
|
||||
|
||||
if (startsWith(value, 'json:')) {
|
||||
value = JSON.parse(value.slice(5))
|
||||
}
|
||||
|
||||
if (name === '@') {
|
||||
params['@'] = value
|
||||
return
|
||||
}
|
||||
|
||||
if (value === 'true') {
|
||||
value = true
|
||||
} else if (value === 'false') {
|
||||
value = false
|
||||
}
|
||||
|
||||
params[name] = value
|
||||
})
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
const humanFormatOpts = {
|
||||
unit: 'B',
|
||||
scale: 'binary',
|
||||
}
|
||||
|
||||
function printProgress (progress) {
|
||||
if (progress.length) {
|
||||
console.warn(
|
||||
'%s% of %s @ %s/s - ETA %s',
|
||||
Math.round(progress.percentage),
|
||||
humanFormat(progress.length, humanFormatOpts),
|
||||
humanFormat(progress.speed, humanFormatOpts),
|
||||
prettyMs(progress.eta * 1e3)
|
||||
)
|
||||
} else {
|
||||
console.warn(
|
||||
'%s @ %s/s',
|
||||
humanFormat(progress.transferred, humanFormatOpts),
|
||||
humanFormat(progress.speed, humanFormatOpts)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function wrap (val) {
|
||||
return function wrappedValue () {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const help = wrap(
|
||||
(function (pkg) {
|
||||
return require('strip-indent')(
|
||||
`
|
||||
Usage:
|
||||
|
||||
$name --register [--expiresIn duration] <XO-Server URL> <username> [<password>]
|
||||
Registers the XO instance to use.
|
||||
|
||||
--expiresIn duration
|
||||
Can be used to change the validity duration of the
|
||||
authorization token (default: one month).
|
||||
|
||||
$name --unregister
|
||||
Remove stored credentials.
|
||||
|
||||
$name --list-commands [--json] [<pattern>]...
|
||||
Returns the list of available commands on the current XO instance.
|
||||
|
||||
The patterns can be used to filter on command names.
|
||||
|
||||
$name --list-objects [--<property>]… [<property>=<value>]...
|
||||
Returns a list of XO objects.
|
||||
|
||||
--<property>
|
||||
Restricts displayed properties to those listed.
|
||||
|
||||
<property>=<value>
|
||||
Restricted displayed objects to those matching the patterns.
|
||||
|
||||
$name <command> [<name>=<value>]...
|
||||
Executes a command on the current XO instance.
|
||||
|
||||
$name v$version
|
||||
`
|
||||
).replace(/<([^>]+)>|\$(\w+)/g, function (_, arg, key) {
|
||||
if (arg) {
|
||||
return '<' + chalk.yellow(arg) + '>'
|
||||
}
|
||||
|
||||
if (key === 'name') {
|
||||
return chalk.bold(pkg[key])
|
||||
}
|
||||
|
||||
return pkg[key]
|
||||
})
|
||||
})(require('../package'))
|
||||
)
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
function main (args) {
|
||||
if (!args || !args.length || args[0] === '-h') {
|
||||
return help()
|
||||
}
|
||||
|
||||
const fnName = args[0].replace(/^--|-\w/g, function (match) {
|
||||
if (match === '--') {
|
||||
return ''
|
||||
}
|
||||
|
||||
return match[1].toUpperCase()
|
||||
})
|
||||
if (fnName in exports) {
|
||||
return exports[fnName](args.slice(1))
|
||||
}
|
||||
|
||||
return exports.call(args)
|
||||
}
|
||||
exports = module.exports = main
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
exports.help = help
|
||||
|
||||
async function register (args) {
|
||||
let expiresIn
|
||||
if (args[0] === '--expiresIn') {
|
||||
expiresIn = args[1]
|
||||
args = args.slice(2)
|
||||
}
|
||||
|
||||
const [
|
||||
url,
|
||||
email,
|
||||
password = await new Promise(function (resolve) {
|
||||
process.stdout.write('Password: ')
|
||||
pw(resolve)
|
||||
}),
|
||||
] = args
|
||||
|
||||
const xo = new Xo({ url })
|
||||
await xo.open()
|
||||
await xo.signIn({ email, password })
|
||||
console.log('Successfully logged with', xo.user.email)
|
||||
|
||||
await config.set({
|
||||
server: url,
|
||||
token: await xo.call('token.create', { expiresIn }),
|
||||
})
|
||||
}
|
||||
exports.register = register
|
||||
|
||||
function unregister () {
|
||||
return config.unset(['server', 'token'])
|
||||
}
|
||||
exports.unregister = unregister
|
||||
|
||||
async function listCommands (args) {
|
||||
const xo = await connect()
|
||||
let methods = await xo.call('system.getMethodsInfo')
|
||||
|
||||
let json = false
|
||||
const patterns = []
|
||||
forEach(args, function (arg) {
|
||||
if (arg === '--json') {
|
||||
json = true
|
||||
} else {
|
||||
patterns.push(arg)
|
||||
}
|
||||
})
|
||||
|
||||
if (patterns.length) {
|
||||
methods = pick(methods, micromatch(Object.keys(methods), patterns))
|
||||
}
|
||||
|
||||
if (json) {
|
||||
return methods
|
||||
}
|
||||
|
||||
methods = pairs(methods)
|
||||
methods.sort(function (a, b) {
|
||||
a = a[0]
|
||||
b = b[0]
|
||||
if (a < b) {
|
||||
return -1
|
||||
}
|
||||
return +(a > b)
|
||||
})
|
||||
|
||||
const str = []
|
||||
forEach(methods, function (method) {
|
||||
const name = method[0]
|
||||
const info = method[1]
|
||||
str.push(chalk.bold.blue(name))
|
||||
forEach(info.params || [], function (info, name) {
|
||||
str.push(' ')
|
||||
if (info.optional) {
|
||||
str.push('[')
|
||||
}
|
||||
|
||||
const type = info.type
|
||||
str.push(
|
||||
name,
|
||||
'=<',
|
||||
type == null ? 'unknown type' : isArray(type) ? type.join('|') : type,
|
||||
'>'
|
||||
)
|
||||
|
||||
if (info.optional) {
|
||||
str.push(']')
|
||||
}
|
||||
})
|
||||
str.push('\n')
|
||||
if (info.description) {
|
||||
str.push(' ', info.description, '\n')
|
||||
}
|
||||
})
|
||||
return str.join('')
|
||||
}
|
||||
exports.listCommands = listCommands
|
||||
|
||||
async function listObjects (args) {
|
||||
const properties = getKeys(extractFlags(args))
|
||||
const filterProperties = properties.length
|
||||
? function (object) {
|
||||
return pick(object, properties)
|
||||
}
|
||||
: identity
|
||||
|
||||
const filter = args.length ? parseParameters(args) : undefined
|
||||
|
||||
const xo = await connect()
|
||||
const objects = await xo.call('xo.getAllObjects', { filter })
|
||||
|
||||
const stdout = process.stdout
|
||||
stdout.write('[\n')
|
||||
const keys = Object.keys(objects)
|
||||
for (let i = 0, n = keys.length; i < n;) {
|
||||
stdout.write(JSON.stringify(filterProperties(objects[keys[i]]), null, 2))
|
||||
stdout.write(++i < n ? ',\n' : '\n')
|
||||
}
|
||||
stdout.write(']\n')
|
||||
}
|
||||
exports.listObjects = listObjects
|
||||
|
||||
function ensurePathParam (method, value) {
|
||||
if (typeof value !== 'string') {
|
||||
const error =
|
||||
method +
|
||||
' requires the @ parameter to be a path (e.g. @=/tmp/config.json)'
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function call (args) {
|
||||
if (!args.length) {
|
||||
throw new Error('missing command name')
|
||||
}
|
||||
|
||||
const method = args.shift()
|
||||
const params = parseParameters(args)
|
||||
|
||||
const file = params['@']
|
||||
delete params['@']
|
||||
|
||||
const xo = await connect()
|
||||
|
||||
// FIXME: do not use private properties.
|
||||
const baseUrl = xo._url.replace(/^ws/, 'http')
|
||||
|
||||
const result = await xo.call(method, params)
|
||||
let keys, key, url
|
||||
if (isObject(result) && (keys = getKeys(result)).length === 1) {
|
||||
key = keys[0]
|
||||
|
||||
if (key === '$getFrom') {
|
||||
ensurePathParam(method, file)
|
||||
url = resolveUrl(baseUrl, result[key])
|
||||
const output = createWriteStream(file)
|
||||
|
||||
const progress = progressStream({ time: 1e3 }, printProgress)
|
||||
|
||||
return eventToPromise(
|
||||
nicePipe([
|
||||
got.stream(url).on('response', function (response) {
|
||||
const length = response.headers['content-length']
|
||||
if (length !== undefined) {
|
||||
progress.length(length)
|
||||
}
|
||||
}),
|
||||
progress,
|
||||
output,
|
||||
]),
|
||||
'finish'
|
||||
)
|
||||
}
|
||||
|
||||
if (key === '$sendTo') {
|
||||
ensurePathParam(method, file)
|
||||
url = resolveUrl(baseUrl, result[key])
|
||||
|
||||
const stats = await stat(file)
|
||||
const length = stats.size
|
||||
|
||||
const input = nicePipe([
|
||||
createReadStream(file),
|
||||
progressStream(
|
||||
{
|
||||
length: length,
|
||||
time: 1e3,
|
||||
},
|
||||
printProgress
|
||||
),
|
||||
])
|
||||
|
||||
const response = await got.post(url, {
|
||||
body: input,
|
||||
headers: {
|
||||
'content-length': length,
|
||||
},
|
||||
method: 'POST',
|
||||
})
|
||||
return response.body
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
exports.call = call
|
||||
|
||||
// ===================================================================
|
||||
|
||||
if (!module.parent) {
|
||||
require('exec-promise')(exports)
|
||||
}
|
||||
24
packages/xo-collection/.npmignore
Normal file
24
packages/xo-collection/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
662
packages/xo-collection/LICENSE
Normal file
662
packages/xo-collection/LICENSE
Normal file
@@ -0,0 +1,662 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
265
packages/xo-collection/README.md
Normal file
265
packages/xo-collection/README.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# xo-collection [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> Generic in-memory collection with events
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/xo-collection):
|
||||
|
||||
```
|
||||
> npm install --save xo-collection
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
var Collection = require('xo-collection')
|
||||
```
|
||||
|
||||
### Creation
|
||||
|
||||
```javascript
|
||||
// Creates a new collection.
|
||||
var col = new Collection()
|
||||
```
|
||||
|
||||
### Manipulation
|
||||
|
||||
**Inserting a new item**
|
||||
|
||||
```javascript
|
||||
col.add('foo', true)
|
||||
```
|
||||
|
||||
- **Throws** `DuplicateItem` if the item is already in the collection.
|
||||
|
||||
**Updating an existing item**
|
||||
|
||||
```javascript
|
||||
col.update('foo', false)
|
||||
```
|
||||
|
||||
- **Throws** `NoSuchItem` if the item is not in the collection.
|
||||
|
||||
**Inserting or updating an item**
|
||||
|
||||
```javascript
|
||||
col.set('bar', true)
|
||||
```
|
||||
|
||||
**Notifying an external update**
|
||||
|
||||
> If an item is an object, it can be updated directly without using
|
||||
> the `set`/`update` methods.
|
||||
>
|
||||
> To make sure the collection stays in sync and the correct events are
|
||||
> sent, the `touch` method can be used to notify the change.
|
||||
|
||||
```javascript
|
||||
var baz = {}
|
||||
|
||||
col.add('baz', baz)
|
||||
|
||||
baz.prop = true
|
||||
col.touch('baz')
|
||||
```
|
||||
|
||||
> Because this is a much used pattern, `touch` returns the item to
|
||||
> allow its direct modification.
|
||||
|
||||
```javascript
|
||||
col.touch('baz').prop = false
|
||||
```
|
||||
|
||||
- **Throws** `NoSuchItem` if the item is not in the collection.
|
||||
- **Throws** `IllegalTouch` if the item is not an object.
|
||||
|
||||
**Removing an existing item**
|
||||
|
||||
```javascript
|
||||
col.remove('bar')
|
||||
```
|
||||
|
||||
- **Throws** `NoSuchItem` if the item is not in the collection.
|
||||
|
||||
**Removing an item without error**
|
||||
|
||||
This is the symmetric method of `set()`: it removes the item if it
|
||||
exists otherwise does nothing.
|
||||
|
||||
```javascript
|
||||
col.unset('bar')
|
||||
```
|
||||
|
||||
**Removing all items**
|
||||
|
||||
```javascript
|
||||
col.clear()
|
||||
```
|
||||
|
||||
### Query
|
||||
|
||||
**Checking the existence of an item**
|
||||
|
||||
```javascript
|
||||
var hasBar = col.has('bar')
|
||||
```
|
||||
|
||||
**Getting an existing item**
|
||||
|
||||
```javascript
|
||||
var foo = col.get('foo')
|
||||
|
||||
// The second parameter can be used to specify a fallback in case the
|
||||
// item does not exist.
|
||||
var bar = col.get('bar', 6.28)
|
||||
```
|
||||
|
||||
- **Throws** `NoSuchItem` if the item is not in the collection and no
|
||||
fallback has been passed.
|
||||
|
||||
**Getting a read-only view of the collection**
|
||||
|
||||
> This property is useful for example to iterate over the collection
|
||||
> or to make advanced queries with the help of utility libraries such
|
||||
> as lodash.
|
||||
|
||||
```javascript
|
||||
var _ = require('lodash')
|
||||
|
||||
// Prints all the items.
|
||||
_.forEach(col.all, function (value, key) {
|
||||
console.log('- %s: %j', key, value)
|
||||
})
|
||||
|
||||
// Finds all the items which are objects and have a property
|
||||
// `active` which equals `true`.
|
||||
var results = _.where(col.all, { active: true })
|
||||
```
|
||||
|
||||
**Getting the number of items**
|
||||
|
||||
```javascript
|
||||
var size = col.size
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
> The events are emitted asynchronously (at the next turn/tick of the
|
||||
> event loop) and are deduplicated which means, for instance, that an
|
||||
> addition followed by an update will result only in a single
|
||||
> addition.
|
||||
|
||||
**New items**
|
||||
|
||||
```javascript
|
||||
col.on('add', (added) => {
|
||||
forEach(added, (value, key) => {
|
||||
console.log('+ %s: %j', key, value)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
**Updated items**
|
||||
|
||||
```javascript
|
||||
col.on('update', (updated) => {
|
||||
forEach(updated, (value, key) => {
|
||||
console.log('± %s: %j', key, value)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
**Removed items**
|
||||
|
||||
```javascript
|
||||
col.on('remove', (removed) => {
|
||||
// For consistency, `removed` is also a map but contrary to `added`
|
||||
// and `updated`, the values associated to the keys are not
|
||||
// significant since the items have already be removed.
|
||||
|
||||
forEach(removed, (value, key) => {
|
||||
console.log('- %s', key)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
**End of update**
|
||||
|
||||
> Emitted when all the update process is finished and all the update
|
||||
> events has been emitted.
|
||||
|
||||
```javascript
|
||||
col.on('finish', () => {
|
||||
console.log('the collection has been updated')
|
||||
})
|
||||
```
|
||||
|
||||
### Iteration
|
||||
|
||||
```javascript
|
||||
for (const [key, value] of col) {
|
||||
console.log('- %s: %j', key, value)
|
||||
}
|
||||
|
||||
for (const key of col.keys()) {
|
||||
console.log('- %s', key)
|
||||
}
|
||||
|
||||
for (const value of col.values()) {
|
||||
console.log('- %j', value)
|
||||
}
|
||||
```
|
||||
|
||||
### Views
|
||||
|
||||
```javascript
|
||||
const View = require('xo-collection/view')
|
||||
```
|
||||
|
||||
> A view is a read-only collection which contains only the items of a
|
||||
> parent collection which satisfy a predicate.
|
||||
>
|
||||
> It is updated at most once per turn of the event loop and therefore
|
||||
> can be briefly invalid.
|
||||
|
||||
```javascript
|
||||
const myView = new View(parentCollection, function predicate (value, key) {
|
||||
// This function should return a boolean indicating whether the
|
||||
// current item should be in this view.
|
||||
})
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> npm install
|
||||
|
||||
# Run the tests
|
||||
> npm test
|
||||
|
||||
# Continuously compile
|
||||
> npm run dev
|
||||
|
||||
# Continuously run the tests
|
||||
> npm run dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> npm run build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Vates SAS](http://vates.fr)
|
||||
1
packages/xo-collection/index.js
Normal file
1
packages/xo-collection/index.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./dist/index')
|
||||
67
packages/xo-collection/package.json
Normal file
67
packages/xo-collection/package.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "xo-collection",
|
||||
"version": "0.4.1",
|
||||
"license": "ISC",
|
||||
"description": "Generic in-memory collection with events",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/xo-collection",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Fabrice Marsaud",
|
||||
"email": "fabrice.marsaud@vates.fr"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/collection",
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/",
|
||||
"*.js"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-runtime": "^6.18.0",
|
||||
"kindof": "^2.0.0",
|
||||
"lodash": "^4.17.2",
|
||||
"make-error": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.5.2",
|
||||
"babel-preset-stage-3": "^6.24.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"event-to-promise": "^0.8.0",
|
||||
"rimraf": "^2.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
},
|
||||
"babel": {
|
||||
"plugins": [
|
||||
"lodash",
|
||||
"transform-runtime"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-3"
|
||||
]
|
||||
}
|
||||
}
|
||||
5
packages/xo-collection/src/clear-object.js
Normal file
5
packages/xo-collection/src/clear-object.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export default function clearObject (object) {
|
||||
for (const key in object) {
|
||||
delete object[key]
|
||||
}
|
||||
}
|
||||
361
packages/xo-collection/src/collection.js
Normal file
361
packages/xo-collection/src/collection.js
Normal file
@@ -0,0 +1,361 @@
|
||||
import kindOf from 'kindof'
|
||||
import { BaseError } from 'make-error'
|
||||
import { EventEmitter } from 'events'
|
||||
import { forEach } from 'lodash'
|
||||
|
||||
import isEmpty from './is-empty'
|
||||
import isObject from './is-object'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const { create: createObject, prototype: { hasOwnProperty } } = Object
|
||||
|
||||
export const ACTION_ADD = 'add'
|
||||
export const ACTION_UPDATE = 'update'
|
||||
export const ACTION_REMOVE = 'remove'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
export class BufferAlreadyFlushed extends BaseError {
|
||||
constructor () {
|
||||
super('buffer flush already requested')
|
||||
}
|
||||
}
|
||||
|
||||
export class DuplicateIndex extends BaseError {
|
||||
constructor (name) {
|
||||
super('there is already an index with the name ' + name)
|
||||
}
|
||||
}
|
||||
|
||||
export class DuplicateItem extends BaseError {
|
||||
constructor (key) {
|
||||
super('there is already a item with the key ' + key)
|
||||
}
|
||||
}
|
||||
|
||||
export class IllegalTouch extends BaseError {
|
||||
constructor (value) {
|
||||
super('only an object value can be touched (found a ' + kindOf(value) + ')')
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidKey extends BaseError {
|
||||
constructor (key) {
|
||||
super('invalid key of type ' + kindOf(key))
|
||||
}
|
||||
}
|
||||
|
||||
export class NoSuchIndex extends BaseError {
|
||||
constructor (name) {
|
||||
super('there is no index with the name ' + name)
|
||||
}
|
||||
}
|
||||
|
||||
export class NoSuchItem extends BaseError {
|
||||
constructor (key) {
|
||||
super('there is no item with the key ' + key)
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
export default class Collection extends EventEmitter {
|
||||
constructor () {
|
||||
super()
|
||||
|
||||
this._buffer = createObject(null)
|
||||
this._buffering = 0
|
||||
this._indexes = createObject(null)
|
||||
this._indexedItems = createObject(null)
|
||||
this._items = {} // createObject(null)
|
||||
this._size = 0
|
||||
}
|
||||
|
||||
// Overridable method used to compute the key of an item when
|
||||
// unspecified.
|
||||
//
|
||||
// Default implementation returns the `id` property.
|
||||
getKey (value) {
|
||||
return value && value.id
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Properties
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
get all () {
|
||||
return this._items
|
||||
}
|
||||
|
||||
get indexes () {
|
||||
return this._indexedItems
|
||||
}
|
||||
|
||||
get size () {
|
||||
return this._size
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Manipulation
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
add (keyOrObjectWithId, valueIfKey = undefined) {
|
||||
const [key, value] = this._resolveItem(keyOrObjectWithId, valueIfKey)
|
||||
this._assertHasNot(key)
|
||||
|
||||
this._items[key] = value
|
||||
this._size++
|
||||
this._touch(ACTION_ADD, key)
|
||||
}
|
||||
|
||||
clear () {
|
||||
forEach(this._items, (_, key) => this._remove(key))
|
||||
}
|
||||
|
||||
remove (keyOrObjectWithId) {
|
||||
const [key] = this._resolveItem(keyOrObjectWithId)
|
||||
this._assertHas(key)
|
||||
|
||||
this._remove(key)
|
||||
}
|
||||
|
||||
set (keyOrObjectWithId, valueIfKey = undefined) {
|
||||
const [key, value] = this._resolveItem(keyOrObjectWithId, valueIfKey)
|
||||
|
||||
const action = this.has(key) ? ACTION_UPDATE : ACTION_ADD
|
||||
this._items[key] = value
|
||||
if (action === ACTION_ADD) {
|
||||
this._size++
|
||||
}
|
||||
this._touch(action, key)
|
||||
}
|
||||
|
||||
touch (keyOrObjectWithId) {
|
||||
const [key] = this._resolveItem(keyOrObjectWithId)
|
||||
this._assertHas(key)
|
||||
const value = this.get(key)
|
||||
if (!isObject(value)) {
|
||||
throw new IllegalTouch(value)
|
||||
}
|
||||
|
||||
this._touch(ACTION_UPDATE, key)
|
||||
|
||||
return this.get(key)
|
||||
}
|
||||
|
||||
unset (keyOrObjectWithId) {
|
||||
const [key] = this._resolveItem(keyOrObjectWithId)
|
||||
|
||||
if (this.has(key)) {
|
||||
this._remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
update (keyOrObjectWithId, valueIfKey = undefined) {
|
||||
const [key, value] = this._resolveItem(keyOrObjectWithId, valueIfKey)
|
||||
this._assertHas(key)
|
||||
|
||||
this._items[key] = value
|
||||
this._touch(ACTION_UPDATE, key)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Query
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
get (key, defaultValue) {
|
||||
if (this.has(key)) {
|
||||
return this._items[key]
|
||||
}
|
||||
|
||||
if (arguments.length > 1) {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// Throws a NoSuchItem.
|
||||
this._assertHas(key)
|
||||
}
|
||||
|
||||
has (key) {
|
||||
return hasOwnProperty.call(this._items, key)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Indexes
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
createIndex (name, index) {
|
||||
const { _indexes: indexes } = this
|
||||
if (hasOwnProperty.call(indexes, name)) {
|
||||
throw new DuplicateIndex(name)
|
||||
}
|
||||
|
||||
indexes[name] = index
|
||||
this._indexedItems[name] = index.items
|
||||
|
||||
index._attachCollection(this)
|
||||
}
|
||||
|
||||
deleteIndex (name) {
|
||||
const { _indexes: indexes } = this
|
||||
if (!hasOwnProperty.call(indexes, name)) {
|
||||
throw new NoSuchIndex(name)
|
||||
}
|
||||
|
||||
const index = indexes[name]
|
||||
delete indexes[name]
|
||||
delete this._indexedItems[name]
|
||||
|
||||
index._detachCollection(this)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Iteration
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
* [Symbol.iterator] () {
|
||||
const { _items: items } = this
|
||||
|
||||
for (const key in items) {
|
||||
yield [key, items[key]]
|
||||
}
|
||||
}
|
||||
|
||||
* keys () {
|
||||
const { _items: items } = this
|
||||
|
||||
for (const key in items) {
|
||||
yield key
|
||||
}
|
||||
}
|
||||
|
||||
* values () {
|
||||
const { _items: items } = this
|
||||
|
||||
for (const key in items) {
|
||||
yield items[key]
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Events buffering
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
bufferEvents () {
|
||||
++this._buffering
|
||||
|
||||
let called = false
|
||||
return () => {
|
||||
if (called) {
|
||||
throw new BufferAlreadyFlushed()
|
||||
}
|
||||
called = true
|
||||
|
||||
if (--this._buffering) {
|
||||
return
|
||||
}
|
||||
|
||||
const { _buffer: buffer } = this
|
||||
|
||||
// Due to deduplication there could be nothing in the buffer.
|
||||
if (isEmpty(buffer)) {
|
||||
return
|
||||
}
|
||||
|
||||
const data = {
|
||||
add: createObject(null),
|
||||
remove: createObject(null),
|
||||
update: createObject(null),
|
||||
}
|
||||
|
||||
for (const key in this._buffer) {
|
||||
data[buffer[key]][key] = this._items[key]
|
||||
}
|
||||
|
||||
forEach(data, (items, action) => {
|
||||
if (!isEmpty(items)) {
|
||||
this.emit(action, items)
|
||||
}
|
||||
})
|
||||
|
||||
// Indicates the end of the update.
|
||||
//
|
||||
// This name has been chosen because it is used in Node writable
|
||||
// streams when the data has been successfully committed.
|
||||
this.emit('finish')
|
||||
|
||||
this._buffer = createObject(null)
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
_assertHas (key) {
|
||||
if (!this.has(key)) {
|
||||
throw new NoSuchItem(key)
|
||||
}
|
||||
}
|
||||
|
||||
_assertHasNot (key) {
|
||||
if (this.has(key)) {
|
||||
throw new DuplicateItem(key)
|
||||
}
|
||||
}
|
||||
|
||||
_assertValidKey (key) {
|
||||
if (!this._isValidKey(key)) {
|
||||
throw new InvalidKey(key)
|
||||
}
|
||||
}
|
||||
|
||||
_isValidKey (key) {
|
||||
return typeof key === 'number' || typeof key === 'string'
|
||||
}
|
||||
|
||||
_remove (key) {
|
||||
delete this._items[key]
|
||||
this._size--
|
||||
this._touch(ACTION_REMOVE, key)
|
||||
}
|
||||
|
||||
_resolveItem (keyOrObjectWithId, valueIfKey = undefined) {
|
||||
if (valueIfKey !== undefined) {
|
||||
this._assertValidKey(keyOrObjectWithId)
|
||||
|
||||
return [keyOrObjectWithId, valueIfKey]
|
||||
}
|
||||
|
||||
if (this._isValidKey(keyOrObjectWithId)) {
|
||||
return [keyOrObjectWithId]
|
||||
}
|
||||
|
||||
const key = this.getKey(keyOrObjectWithId)
|
||||
this._assertValidKey(key)
|
||||
|
||||
return [key, keyOrObjectWithId]
|
||||
}
|
||||
|
||||
_touch (action, key) {
|
||||
if (this._buffering === 0) {
|
||||
const flush = this.bufferEvents()
|
||||
|
||||
process.nextTick(flush)
|
||||
}
|
||||
|
||||
if (action === ACTION_ADD) {
|
||||
this._buffer[key] = this._buffer[key] ? ACTION_UPDATE : ACTION_ADD
|
||||
} else if (action === ACTION_REMOVE) {
|
||||
if (this._buffer[key] === ACTION_ADD) {
|
||||
delete this._buffer[key]
|
||||
} else {
|
||||
this._buffer[key] = ACTION_REMOVE
|
||||
}
|
||||
} else {
|
||||
// update
|
||||
if (!this._buffer[key]) {
|
||||
this._buffer[key] = ACTION_UPDATE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
325
packages/xo-collection/src/collection.spec.js
Normal file
325
packages/xo-collection/src/collection.spec.js
Normal file
@@ -0,0 +1,325 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import eventToPromise from 'event-to-promise'
|
||||
import { forEach } from 'lodash'
|
||||
|
||||
import Collection, { DuplicateItem, NoSuchItem } from './collection'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
function waitTicks (n = 2) {
|
||||
const { nextTick } = process
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
;(function waitNextTick () {
|
||||
// The first tick is handled by Promise#then()
|
||||
if (--n) {
|
||||
nextTick(waitNextTick)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})()
|
||||
})
|
||||
}
|
||||
|
||||
describe('Collection', function () {
|
||||
let col
|
||||
beforeEach(function () {
|
||||
col = new Collection()
|
||||
col.add('bar', 0)
|
||||
|
||||
return waitTicks()
|
||||
})
|
||||
|
||||
it('is iterable', function () {
|
||||
const iterator = col[Symbol.iterator]()
|
||||
|
||||
expect(iterator.next()).toEqual({ done: false, value: ['bar', 0] })
|
||||
expect(iterator.next()).toEqual({ done: true, value: undefined })
|
||||
})
|
||||
|
||||
describe('#keys()', function () {
|
||||
it('returns an iterator over the keys', function () {
|
||||
const iterator = col.keys()
|
||||
|
||||
expect(iterator.next()).toEqual({ done: false, value: 'bar' })
|
||||
expect(iterator.next()).toEqual({ done: true, value: undefined })
|
||||
})
|
||||
})
|
||||
|
||||
describe('#values()', function () {
|
||||
it('returns an iterator over the values', function () {
|
||||
const iterator = col.values()
|
||||
|
||||
expect(iterator.next()).toEqual({ done: false, value: 0 })
|
||||
expect(iterator.next()).toEqual({ done: true, value: undefined })
|
||||
})
|
||||
})
|
||||
|
||||
describe('#add()', function () {
|
||||
it('adds item to the collection', function () {
|
||||
const spy = jest.fn()
|
||||
col.on('add', spy)
|
||||
|
||||
col.add('foo', true)
|
||||
|
||||
expect(col.get('foo')).toBe(true)
|
||||
|
||||
// No sync events.
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
|
||||
// Async event.
|
||||
return eventToPromise(col, 'add').then(function (added) {
|
||||
expect(Object.keys(added)).toEqual(['foo'])
|
||||
expect(added.foo).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws an exception if the item already exists', function () {
|
||||
expect(() => col.add('bar', true)).toThrowError(DuplicateItem)
|
||||
})
|
||||
|
||||
it('accepts an object with an id property', function () {
|
||||
const foo = { id: 'foo' }
|
||||
|
||||
col.add(foo)
|
||||
|
||||
expect(col.get(foo.id)).toBe(foo)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#update()', function () {
|
||||
it('updates an item of the collection', function () {
|
||||
const spy = jest.fn()
|
||||
col.on('update', spy)
|
||||
|
||||
col.update('bar', 1)
|
||||
expect(col.get('bar')).toBe(1) // Will be forgotten by de-duplication
|
||||
col.update('bar', 2)
|
||||
expect(col.get('bar')).toBe(2)
|
||||
|
||||
// No sync events.
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
|
||||
// Async event.
|
||||
return eventToPromise(col, 'update').then(function (updated) {
|
||||
expect(Object.keys(updated)).toEqual(['bar'])
|
||||
expect(updated.bar).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws an exception if the item does not exist', function () {
|
||||
expect(() => col.update('baz', true)).toThrowError(NoSuchItem)
|
||||
})
|
||||
|
||||
it('accepts an object with an id property', function () {
|
||||
const bar = { id: 'bar' }
|
||||
|
||||
col.update(bar)
|
||||
|
||||
expect(col.get(bar.id)).toBe(bar)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#remove()', function () {
|
||||
it('removes an item of the collection', function () {
|
||||
const spy = jest.fn()
|
||||
col.on('remove', spy)
|
||||
|
||||
col.update('bar', 1)
|
||||
expect(col.get('bar')).toBe(1) // Will be forgotten by de-duplication
|
||||
col.remove('bar')
|
||||
|
||||
// No sync events.
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
|
||||
// Async event.
|
||||
return eventToPromise(col, 'remove').then(function (removed) {
|
||||
expect(Object.keys(removed)).toEqual(['bar'])
|
||||
expect(removed.bar).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
it('throws an exception if the item does not exist', function () {
|
||||
expect(() => col.remove('baz', true)).toThrowError(NoSuchItem)
|
||||
})
|
||||
|
||||
it('accepts an object with an id property', function () {
|
||||
const bar = { id: 'bar' }
|
||||
|
||||
col.remove(bar)
|
||||
|
||||
expect(col.has(bar.id)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#set()', function () {
|
||||
it('adds item if collection has not key', function () {
|
||||
const spy = jest.fn()
|
||||
col.on('add', spy)
|
||||
|
||||
col.set('foo', true)
|
||||
|
||||
expect(col.get('foo')).toBe(true)
|
||||
|
||||
// No sync events.
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
|
||||
// Async events.
|
||||
return eventToPromise(col, 'add').then(function (added) {
|
||||
expect(Object.keys(added)).toEqual(['foo'])
|
||||
expect(added.foo).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('updates item if collection has key', function () {
|
||||
const spy = jest.fn()
|
||||
col.on('udpate', spy)
|
||||
|
||||
col.set('bar', 1)
|
||||
|
||||
expect(col.get('bar')).toBe(1)
|
||||
|
||||
// No sync events.
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
|
||||
// Async events.
|
||||
return eventToPromise(col, 'update').then(function (updated) {
|
||||
expect(Object.keys(updated)).toEqual(['bar'])
|
||||
expect(updated.bar).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('accepts an object with an id property', function () {
|
||||
const foo = { id: 'foo' }
|
||||
|
||||
col.set(foo)
|
||||
|
||||
expect(col.get(foo.id)).toBe(foo)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#unset()', function () {
|
||||
it('removes an existing item', function () {
|
||||
col.unset('bar')
|
||||
|
||||
expect(col.has('bar')).toBe(false)
|
||||
|
||||
return eventToPromise(col, 'remove').then(function (removed) {
|
||||
expect(Object.keys(removed)).toEqual(['bar'])
|
||||
expect(removed.bar).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
it('does not throw if the item does not exists', function () {
|
||||
col.unset('foo')
|
||||
})
|
||||
|
||||
it('accepts an object with an id property', function () {
|
||||
col.unset({ id: 'bar' })
|
||||
|
||||
expect(col.has('bar')).toBe(false)
|
||||
|
||||
return eventToPromise(col, 'remove').then(function (removed) {
|
||||
expect(Object.keys(removed)).toEqual(['bar'])
|
||||
expect(removed.bar).toBeUndefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('touch()', function () {
|
||||
it('can be used to signal an indirect update', function () {
|
||||
const foo = { id: 'foo' }
|
||||
col.add(foo)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
col.touch(foo)
|
||||
|
||||
return eventToPromise(col, 'update', items => {
|
||||
expect(Object.keys(items)).toEqual(['foo'])
|
||||
expect(items.foo).toBe(foo)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('clear()', function () {
|
||||
it('removes all items from the collection', function () {
|
||||
col.clear()
|
||||
|
||||
expect(col.size).toBe(0)
|
||||
|
||||
return eventToPromise(col, 'remove').then(items => {
|
||||
expect(Object.keys(items)).toEqual(['bar'])
|
||||
expect(items.bar).toBeUndefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('deduplicates events', function () {
|
||||
forEach(
|
||||
{
|
||||
'add & update → add': [
|
||||
[['add', 'foo', 0], ['update', 'foo', 1]],
|
||||
{
|
||||
add: {
|
||||
foo: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
'add & remove → ∅': [[['add', 'foo', 0], ['remove', 'foo']], {}],
|
||||
|
||||
'update & update → update': [
|
||||
[['update', 'bar', 1], ['update', 'bar', 2]],
|
||||
{
|
||||
update: {
|
||||
bar: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
'update & remove → remove': [
|
||||
[['update', 'bar', 1], ['remove', 'bar']],
|
||||
{
|
||||
remove: {
|
||||
bar: undefined,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
'remove & add → update': [
|
||||
[['remove', 'bar'], ['add', 'bar', 0]],
|
||||
{
|
||||
update: {
|
||||
bar: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
([operations, results], label) => {
|
||||
it(label, function () {
|
||||
forEach(operations, ([method, ...args]) => {
|
||||
col[method](...args)
|
||||
})
|
||||
|
||||
const spies = Object.create(null)
|
||||
forEach(['add', 'update', 'remove'], event => {
|
||||
col.on(event, (spies[event] = jest.fn()))
|
||||
})
|
||||
|
||||
return waitTicks().then(() => {
|
||||
forEach(spies, (spy, event) => {
|
||||
const items = results[event]
|
||||
if (items) {
|
||||
expect(spy.mock.calls).toEqual([[items]])
|
||||
} else {
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
136
packages/xo-collection/src/index.js
Normal file
136
packages/xo-collection/src/index.js
Normal file
@@ -0,0 +1,136 @@
|
||||
import { bind, iteratee } from 'lodash'
|
||||
|
||||
import clearObject from './clear-object'
|
||||
import isEmpty from './is-empty'
|
||||
import NotImplemented from './not-implemented'
|
||||
import { ACTION_ADD, ACTION_UPDATE, ACTION_REMOVE } from './collection'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
export default class Index {
|
||||
constructor (computeHash) {
|
||||
if (computeHash) {
|
||||
this.computeHash = iteratee(computeHash)
|
||||
}
|
||||
|
||||
this._itemsByHash = Object.create(null)
|
||||
this._keysToHash = Object.create(null)
|
||||
|
||||
// Bound versions of listeners.
|
||||
this._onAdd = bind(this._onAdd, this)
|
||||
this._onUpdate = bind(this._onUpdate, this)
|
||||
this._onRemove = bind(this._onRemove, this)
|
||||
}
|
||||
|
||||
// This method is used to compute the hash under which an item must
|
||||
// be saved.
|
||||
computeHash (value, key) {
|
||||
throw new NotImplemented('this method must be overridden')
|
||||
}
|
||||
|
||||
// Remove empty items lists.
|
||||
sweep () {
|
||||
const { _itemsByHash: itemsByHash } = this
|
||||
for (const hash in itemsByHash) {
|
||||
if (isEmpty(itemsByHash[hash])) {
|
||||
delete itemsByHash[hash]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
get items () {
|
||||
return this._itemsByHash
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
_attachCollection (collection) {
|
||||
// Add existing entries.
|
||||
//
|
||||
// FIXME: I think there may be a race condition if the `add` event
|
||||
// has not been emitted yet.
|
||||
this._onAdd(collection.all)
|
||||
|
||||
collection.on(ACTION_ADD, this._onAdd)
|
||||
collection.on(ACTION_UPDATE, this._onUpdate)
|
||||
collection.on(ACTION_REMOVE, this._onRemove)
|
||||
}
|
||||
|
||||
_detachCollection (collection) {
|
||||
collection.removeListener(ACTION_ADD, this._onAdd)
|
||||
collection.removeListener(ACTION_UPDATE, this._onUpdate)
|
||||
collection.removeListener(ACTION_REMOVE, this._onRemove)
|
||||
|
||||
clearObject(this._itemsByHash)
|
||||
clearObject(this._keysToHash)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
_onAdd (items) {
|
||||
const {
|
||||
computeHash,
|
||||
_itemsByHash: itemsByHash,
|
||||
_keysToHash: keysToHash,
|
||||
} = this
|
||||
|
||||
for (const key in items) {
|
||||
const value = items[key]
|
||||
|
||||
const hash = computeHash(value, key)
|
||||
|
||||
if (hash != null) {
|
||||
;(itemsByHash[hash] ||
|
||||
// FIXME: We do not use objects without prototype for now
|
||||
// because it breaks Angular in xo-web, change it back when
|
||||
// this is fixed.
|
||||
(itemsByHash[hash] = {}))[key] = value
|
||||
|
||||
keysToHash[key] = hash
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onUpdate (items) {
|
||||
const {
|
||||
computeHash,
|
||||
_itemsByHash: itemsByHash,
|
||||
_keysToHash: keysToHash,
|
||||
} = this
|
||||
|
||||
for (const key in items) {
|
||||
const value = items[key]
|
||||
|
||||
const prev = keysToHash[key]
|
||||
const hash = computeHash(value, key)
|
||||
|
||||
// Removes item from the previous hash's list if any.
|
||||
if (prev != null) delete itemsByHash[prev][key]
|
||||
|
||||
// Inserts item into the new hash's list if any.
|
||||
if (hash != null) {
|
||||
;(itemsByHash[hash] ||
|
||||
// FIXME: idem: change back to Object.create(null)
|
||||
(itemsByHash[hash] = {}))[key] = value
|
||||
|
||||
keysToHash[key] = hash
|
||||
} else {
|
||||
delete keysToHash[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onRemove (items) {
|
||||
const { _itemsByHash: itemsByHash, _keysToHash: keysToHash } = this
|
||||
|
||||
for (const key in items) {
|
||||
const prev = keysToHash[key]
|
||||
if (prev != null) {
|
||||
delete itemsByHash[prev][key]
|
||||
delete keysToHash[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
180
packages/xo-collection/src/index.spec.js
Normal file
180
packages/xo-collection/src/index.spec.js
Normal file
@@ -0,0 +1,180 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import eventToPromise from 'event-to-promise'
|
||||
import { forEach } from 'lodash'
|
||||
|
||||
import Collection from './collection'
|
||||
import Index from './index'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const waitTicks = (n = 2) => {
|
||||
const { nextTick } = process
|
||||
|
||||
return new Promise(resolve => {
|
||||
;(function waitNextTick () {
|
||||
// The first tick is handled by Promise#then()
|
||||
if (--n) {
|
||||
nextTick(waitNextTick)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})()
|
||||
})
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
describe('Index', function () {
|
||||
let col, byGroup
|
||||
const item1 = {
|
||||
id: '2ccb8a72-dc65-48e4-88fe-45ef541f2cba',
|
||||
group: 'foo',
|
||||
}
|
||||
const item2 = {
|
||||
id: '7d21dc51-4da8-4538-a2e9-dd6f4784eb76',
|
||||
group: 'bar',
|
||||
}
|
||||
const item3 = {
|
||||
id: '668c1274-4442-44a6-b99a-512188e0bb09',
|
||||
group: 'foo',
|
||||
}
|
||||
const item4 = {
|
||||
id: 'd90b7335-e540-4a44-ad22-c4baae9cd0a9',
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
col = new Collection()
|
||||
forEach([item1, item2, item3, item4], item => {
|
||||
col.add(item)
|
||||
})
|
||||
|
||||
byGroup = new Index('group')
|
||||
|
||||
col.createIndex('byGroup', byGroup)
|
||||
|
||||
return waitTicks()
|
||||
})
|
||||
|
||||
it('works with existing items', function () {
|
||||
expect(col.indexes).toEqual({
|
||||
byGroup: {
|
||||
foo: {
|
||||
[item1.id]: item1,
|
||||
[item3.id]: item3,
|
||||
},
|
||||
bar: {
|
||||
[item2.id]: item2,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('works with added items', function () {
|
||||
const item5 = {
|
||||
id: '823b56c4-4b96-4f3a-9533-5d08177167ac',
|
||||
group: 'baz',
|
||||
}
|
||||
|
||||
col.add(item5)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byGroup: {
|
||||
foo: {
|
||||
[item1.id]: item1,
|
||||
[item3.id]: item3,
|
||||
},
|
||||
bar: {
|
||||
[item2.id]: item2,
|
||||
},
|
||||
baz: {
|
||||
[item5.id]: item5,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('works with updated items', function () {
|
||||
const item1bis = {
|
||||
id: item1.id,
|
||||
group: 'bar',
|
||||
}
|
||||
|
||||
col.update(item1bis)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byGroup: {
|
||||
foo: {
|
||||
[item3.id]: item3,
|
||||
},
|
||||
bar: {
|
||||
[item1.id]: item1bis,
|
||||
[item2.id]: item2,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('works with removed items', function () {
|
||||
col.remove(item2)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byGroup: {
|
||||
foo: {
|
||||
[item1.id]: item1,
|
||||
[item3.id]: item3,
|
||||
},
|
||||
bar: {},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly updates the value even the same object has the same hash', function () {
|
||||
const item1bis = {
|
||||
id: item1.id,
|
||||
group: item1.group,
|
||||
newProp: true,
|
||||
}
|
||||
|
||||
col.update(item1bis)
|
||||
|
||||
return eventToPromise(col, 'finish').then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byGroup: {
|
||||
foo: {
|
||||
[item1.id]: item1bis,
|
||||
[item3.id]: item3,
|
||||
},
|
||||
bar: {
|
||||
[item2.id]: item2,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#sweep()', function () {
|
||||
it('removes empty items lists', function () {
|
||||
col.remove(item2)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
byGroup.sweep()
|
||||
|
||||
expect(col.indexes).toEqual({
|
||||
byGroup: {
|
||||
foo: {
|
||||
[item1.id]: item1,
|
||||
[item3.id]: item3,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
7
packages/xo-collection/src/is-empty.js
Normal file
7
packages/xo-collection/src/is-empty.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function isEmpty (object) {
|
||||
/* eslint no-unused-vars: 0 */
|
||||
for (const key in object) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
3
packages/xo-collection/src/is-object.js
Normal file
3
packages/xo-collection/src/is-object.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function isObject (value) {
|
||||
return value !== null && typeof value === 'object'
|
||||
}
|
||||
7
packages/xo-collection/src/not-implemented.js
Normal file
7
packages/xo-collection/src/not-implemented.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { BaseError } from 'make-error'
|
||||
|
||||
export default class NotImplemented extends BaseError {
|
||||
constructor (message) {
|
||||
super(message || 'this method is not implemented')
|
||||
}
|
||||
}
|
||||
117
packages/xo-collection/src/unique-index.js
Normal file
117
packages/xo-collection/src/unique-index.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import { bind, iteratee } from 'lodash'
|
||||
|
||||
import clearObject from './clear-object'
|
||||
import NotImplemented from './not-implemented'
|
||||
import { ACTION_ADD, ACTION_UPDATE, ACTION_REMOVE } from './collection'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
export default class UniqueIndex {
|
||||
constructor (computeHash) {
|
||||
if (computeHash) {
|
||||
this.computeHash = iteratee(computeHash)
|
||||
}
|
||||
|
||||
this._itemByHash = Object.create(null)
|
||||
this._keysToHash = Object.create(null)
|
||||
|
||||
// Bound versions of listeners.
|
||||
this._onAdd = bind(this._onAdd, this)
|
||||
this._onUpdate = bind(this._onUpdate, this)
|
||||
this._onRemove = bind(this._onRemove, this)
|
||||
}
|
||||
|
||||
// This method is used to compute the hash under which an item must
|
||||
// be saved.
|
||||
computeHash (value, key) {
|
||||
throw new NotImplemented('this method must be overridden')
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
get items () {
|
||||
return this._itemByHash
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
_attachCollection (collection) {
|
||||
// Add existing entries.
|
||||
//
|
||||
// FIXME: I think there may be a race condition if the `add` event
|
||||
// has not been emitted yet.
|
||||
this._onAdd(collection.all)
|
||||
|
||||
collection.on(ACTION_ADD, this._onAdd)
|
||||
collection.on(ACTION_UPDATE, this._onUpdate)
|
||||
collection.on(ACTION_REMOVE, this._onRemove)
|
||||
}
|
||||
|
||||
_detachCollection (collection) {
|
||||
collection.removeListener(ACTION_ADD, this._onAdd)
|
||||
collection.removeListener(ACTION_UPDATE, this._onUpdate)
|
||||
collection.removeListener(ACTION_REMOVE, this._onRemove)
|
||||
|
||||
clearObject(this._itemByHash)
|
||||
clearObject(this._keysToHash)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
_onAdd (items) {
|
||||
const {
|
||||
computeHash,
|
||||
_itemByHash: itemByHash,
|
||||
_keysToHash: keysToHash,
|
||||
} = this
|
||||
|
||||
for (const key in items) {
|
||||
const value = items[key]
|
||||
|
||||
const hash = computeHash(value, key)
|
||||
|
||||
if (hash != null) {
|
||||
itemByHash[hash] = value
|
||||
keysToHash[key] = hash
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onUpdate (items) {
|
||||
const {
|
||||
computeHash,
|
||||
_itemByHash: itemByHash,
|
||||
_keysToHash: keysToHash,
|
||||
} = this
|
||||
|
||||
for (const key in items) {
|
||||
const value = items[key]
|
||||
|
||||
const prev = keysToHash[key]
|
||||
const hash = computeHash(value, key)
|
||||
|
||||
// Removes item from the previous hash's list if any.
|
||||
if (prev != null) delete itemByHash[prev]
|
||||
|
||||
// Inserts item into the new hash's list if any.
|
||||
if (hash != null) {
|
||||
itemByHash[hash] = value
|
||||
keysToHash[key] = hash
|
||||
} else {
|
||||
delete keysToHash[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onRemove (items) {
|
||||
const { _itemByHash: itemByHash, _keysToHash: keysToHash } = this
|
||||
|
||||
for (const key in items) {
|
||||
const prev = keysToHash[key]
|
||||
if (prev != null) {
|
||||
delete itemByHash[prev]
|
||||
delete keysToHash[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
131
packages/xo-collection/src/unique-index.spec.js
Normal file
131
packages/xo-collection/src/unique-index.spec.js
Normal file
@@ -0,0 +1,131 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import eventToPromise from 'event-to-promise'
|
||||
import { forEach } from 'lodash'
|
||||
|
||||
import Collection from './collection'
|
||||
import Index from './unique-index'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const waitTicks = (n = 2) => {
|
||||
const { nextTick } = process
|
||||
|
||||
return new Promise(resolve => {
|
||||
;(function waitNextTick () {
|
||||
// The first tick is handled by Promise#then()
|
||||
if (--n) {
|
||||
nextTick(waitNextTick)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})()
|
||||
})
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
describe('UniqueIndex', function () {
|
||||
let col, byKey
|
||||
const item1 = {
|
||||
id: '2ccb8a72-dc65-48e4-88fe-45ef541f2cba',
|
||||
key: '036dee1b-9a3b-4fb5-be8a-4f535b355581',
|
||||
}
|
||||
const item2 = {
|
||||
id: '7d21dc51-4da8-4538-a2e9-dd6f4784eb76',
|
||||
key: '103cd893-d2cc-4d37-96fd-c259ad04c0d4',
|
||||
}
|
||||
const item3 = {
|
||||
id: '668c1274-4442-44a6-b99a-512188e0bb09',
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
col = new Collection()
|
||||
forEach([item1, item2, item3], item => {
|
||||
col.add(item)
|
||||
})
|
||||
|
||||
byKey = new Index('key')
|
||||
|
||||
col.createIndex('byKey', byKey)
|
||||
|
||||
return waitTicks()
|
||||
})
|
||||
|
||||
it('works with existing items', function () {
|
||||
expect(col.indexes).toEqual({
|
||||
byKey: {
|
||||
[item1.key]: item1,
|
||||
[item2.key]: item2,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('works with added items', function () {
|
||||
const item4 = {
|
||||
id: '823b56c4-4b96-4f3a-9533-5d08177167ac',
|
||||
key: '1437af14-429a-40db-8a51-8a2f5ed03201',
|
||||
}
|
||||
|
||||
col.add(item4)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byKey: {
|
||||
[item1.key]: item1,
|
||||
[item2.key]: item2,
|
||||
[item4.key]: item4,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('works with updated items', function () {
|
||||
const item1bis = {
|
||||
id: item1.id,
|
||||
key: 'e03d4a3a-0331-4aca-97a2-016bbd43a29b',
|
||||
}
|
||||
|
||||
col.update(item1bis)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byKey: {
|
||||
[item1bis.key]: item1bis,
|
||||
[item2.key]: item2,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('works with removed items', function () {
|
||||
col.remove(item2)
|
||||
|
||||
return waitTicks().then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byKey: {
|
||||
[item1.key]: item1,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly updates the value even the same object has the same hash', function () {
|
||||
const item1bis = {
|
||||
id: item1.id,
|
||||
key: item1.key,
|
||||
newProp: true,
|
||||
}
|
||||
|
||||
col.update(item1bis)
|
||||
|
||||
return eventToPromise(col, 'finish').then(() => {
|
||||
expect(col.indexes).toEqual({
|
||||
byKey: {
|
||||
[item1.key]: item1bis,
|
||||
[item2.key]: item2,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
56
packages/xo-collection/src/view.example.js
Normal file
56
packages/xo-collection/src/view.example.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { forEach } from 'lodash'
|
||||
|
||||
import Collection from './collection'
|
||||
import View from './view'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// Create the collection.
|
||||
const users = new Collection()
|
||||
users.getKey = user => user.name
|
||||
|
||||
// Inserts some data.
|
||||
users.add({
|
||||
name: 'bob',
|
||||
})
|
||||
users.add({
|
||||
name: 'clara',
|
||||
active: true,
|
||||
})
|
||||
users.add({
|
||||
name: 'ophelia',
|
||||
})
|
||||
users.add({
|
||||
name: 'Steve',
|
||||
active: true,
|
||||
})
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Create the view.
|
||||
const activeUsers = new View(users, 'active')
|
||||
|
||||
// Register some event listeners to see the changes.
|
||||
activeUsers.on('add', users => {
|
||||
forEach(users, (_, id) => {
|
||||
console.log('+ active user:', id)
|
||||
})
|
||||
})
|
||||
activeUsers.on('remove', users => {
|
||||
forEach(users, (_, id) => {
|
||||
console.log('- active user:', id)
|
||||
})
|
||||
})
|
||||
|
||||
// Make some changes in the future.
|
||||
setTimeout(function () {
|
||||
console.log('-----')
|
||||
|
||||
users.set({
|
||||
name: 'ophelia',
|
||||
active: true,
|
||||
})
|
||||
users.set({
|
||||
name: 'Steve',
|
||||
})
|
||||
}, 10)
|
||||
88
packages/xo-collection/src/view.js
Normal file
88
packages/xo-collection/src/view.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import { bind, forEach, iteratee as createCallback } from 'lodash'
|
||||
|
||||
import Collection, {
|
||||
ACTION_ADD,
|
||||
ACTION_UPDATE,
|
||||
ACTION_REMOVE,
|
||||
} from './collection'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
export default class View extends Collection {
|
||||
constructor (collection, predicate) {
|
||||
super()
|
||||
|
||||
this._collection = collection
|
||||
this._predicate = createCallback(predicate)
|
||||
|
||||
// Handles initial items.
|
||||
this._onAdd(this._collection.all)
|
||||
|
||||
// Bound versions of listeners.
|
||||
this._onAdd = bind(this._onAdd, this)
|
||||
this._onUpdate = bind(this._onUpdate, this)
|
||||
this._onRemove = bind(this._onRemove, this)
|
||||
|
||||
// Register listeners.
|
||||
this._collection.on(ACTION_ADD, this._onAdd)
|
||||
this._collection.on(ACTION_UPDATE, this._onUpdate)
|
||||
this._collection.on(ACTION_REMOVE, this._onRemove)
|
||||
}
|
||||
|
||||
// This method is necessary to free the memory of the view if its
|
||||
// life span is shorter than the collection.
|
||||
destroy () {
|
||||
this._collection.removeListener(ACTION_ADD, this._onAdd)
|
||||
this._collection.removeListener(ACTION_UPDATE, this._onUpdate)
|
||||
this._collection.removeListener(ACTION_REMOVE, this._onRemove)
|
||||
}
|
||||
|
||||
add () {
|
||||
throw new Error('a view is read only')
|
||||
}
|
||||
|
||||
clear () {
|
||||
throw new Error('a view is read only')
|
||||
}
|
||||
|
||||
set () {
|
||||
throw new Error('a view is read only')
|
||||
}
|
||||
|
||||
update () {
|
||||
throw new Error('a view is read only')
|
||||
}
|
||||
|
||||
_onAdd (items) {
|
||||
const { _predicate: predicate } = this
|
||||
|
||||
forEach(items, (value, key) => {
|
||||
if (predicate(value, key, this)) {
|
||||
// super.add() cannot be used because the item may already be
|
||||
// in the view if it was already present at the creation of
|
||||
// the view and its event not already emitted.
|
||||
super.set(key, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_onUpdate (items) {
|
||||
const { _predicate: predicate } = this
|
||||
|
||||
forEach(items, (value, key) => {
|
||||
if (predicate(value, key, this)) {
|
||||
super.set(key, value)
|
||||
} else if (super.has(key)) {
|
||||
super.remove(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_onRemove (items) {
|
||||
forEach(items, (value, key) => {
|
||||
if (super.has(key)) {
|
||||
super.remove(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
1
packages/xo-collection/unique-index.js
Normal file
1
packages/xo-collection/unique-index.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./dist/unique-index')
|
||||
1
packages/xo-collection/view.js
Normal file
1
packages/xo-collection/view.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./dist/view')
|
||||
10
packages/xo-common/.npmignore
Normal file
10
packages/xo-common/.npmignore
Normal file
@@ -0,0 +1,10 @@
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
49
packages/xo-common/README.md
Normal file
49
packages/xo-common/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# xo-common [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> Code shared between [XO](https://xen-orchestra.com) server and clients
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/xo-common):
|
||||
|
||||
```
|
||||
> npm install --save xo-common
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
**TODO**
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> npm install
|
||||
|
||||
# Run the tests
|
||||
> npm test
|
||||
|
||||
# Continuously compile
|
||||
> npm run dev
|
||||
|
||||
# Continuously run the tests
|
||||
> npm run dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> npm run build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
AGPL3 © [Vates SAS](https://vates.fr)
|
||||
1
packages/xo-common/api-errors.js
Normal file
1
packages/xo-common/api-errors.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./dist/api-errors')
|
||||
65
packages/xo-common/package.json
Normal file
65
packages/xo-common/package.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "xo-common",
|
||||
"version": "0.1.1",
|
||||
"license": "AGPL-3.0",
|
||||
"description": "Code shared between [XO](https://xen-orchestra.com) server and clients",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/xo-common",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@isonoe.net"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/",
|
||||
"*.js"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-runtime": "^6.18.0",
|
||||
"lodash": "^4.16.6",
|
||||
"make-error": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.5.2",
|
||||
"babel-preset-stage-3": "^6.24.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"rimraf": "^2.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"clean": "rimraf dist/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
},
|
||||
"babel": {
|
||||
"plugins": [
|
||||
"lodash"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"browsers": "> 1%",
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-3"
|
||||
]
|
||||
}
|
||||
}
|
||||
166
packages/xo-common/src/api-errors.js
Normal file
166
packages/xo-common/src/api-errors.js
Normal file
@@ -0,0 +1,166 @@
|
||||
import { BaseError } from 'make-error'
|
||||
import { isArray, iteratee } from 'lodash'
|
||||
|
||||
class XoError extends BaseError {
|
||||
constructor ({ code, message, data }) {
|
||||
super(message)
|
||||
this.code = code
|
||||
this.data = data
|
||||
}
|
||||
|
||||
toJsonRpcError () {
|
||||
return {
|
||||
message: this.message,
|
||||
code: this.code,
|
||||
data: this.data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const create = (code, getProps) => {
|
||||
const factory = (...args) => new XoError({ ...getProps(...args), code })
|
||||
factory.is = (error, predicate) =>
|
||||
error.code === code && iteratee(predicate)(error)
|
||||
|
||||
return factory
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
export const notImplemented = create(0, () => ({
|
||||
message: 'not implemented',
|
||||
}))
|
||||
|
||||
export const noSuchObject = create(1, (id, type) => ({
|
||||
data: { id, type },
|
||||
message: 'no such object',
|
||||
}))
|
||||
|
||||
export const unauthorized = create(2, () => ({
|
||||
message: 'not authenticated or not enough permissions',
|
||||
}))
|
||||
|
||||
export const invalidCredentials = create(3, () => ({
|
||||
message: 'invalid credentials',
|
||||
}))
|
||||
|
||||
// Deprecated alreadyAuthenticated (4)
|
||||
|
||||
export const forbiddenOperation = create(5, (operation, reason) => ({
|
||||
data: { operation, reason },
|
||||
message: `forbidden operation: ${operation}`,
|
||||
}))
|
||||
|
||||
// Deprecated GenericError (6)
|
||||
|
||||
export const noHostsAvailable = create(7, () => ({
|
||||
message: 'no hosts available',
|
||||
}))
|
||||
|
||||
export const authenticationFailed = create(8, () => ({
|
||||
message: 'authentication failed',
|
||||
}))
|
||||
|
||||
export const serverUnreachable = create(9, objectId => ({
|
||||
data: {
|
||||
objectId,
|
||||
},
|
||||
message: 'server unreachable',
|
||||
}))
|
||||
|
||||
export const invalidParameters = create(10, (message, errors) => {
|
||||
if (isArray(message)) {
|
||||
errors = message
|
||||
message = undefined
|
||||
}
|
||||
|
||||
return {
|
||||
data: { errors },
|
||||
message: message || 'invalid parameters',
|
||||
}
|
||||
})
|
||||
|
||||
export const vmMissingPvDrivers = create(11, ({ vm }) => ({
|
||||
data: {
|
||||
objectId: vm,
|
||||
},
|
||||
message: 'missing PV drivers',
|
||||
}))
|
||||
|
||||
export const vmIsTemplate = create(12, ({ vm }) => ({
|
||||
data: {
|
||||
objectId: vm,
|
||||
},
|
||||
message: 'VM is a template',
|
||||
}))
|
||||
|
||||
// TODO: We should probably create a more generic error which gathers all incorrect state errors.
|
||||
// e.g.:
|
||||
// incorrectState {
|
||||
// data: {
|
||||
// objectId: 'af43e227-3deb-4822-a79b-968825de72eb',
|
||||
// property: 'power_state',
|
||||
// actual: 'Running',
|
||||
// expected: 'Halted'
|
||||
// },
|
||||
// message: 'incorrect state'
|
||||
// }
|
||||
export const vmBadPowerState = create(13, ({ vm, expected, actual }) => ({
|
||||
data: {
|
||||
objectId: vm,
|
||||
expected,
|
||||
actual,
|
||||
},
|
||||
message: `VM state is ${actual} but should be ${expected}`,
|
||||
}))
|
||||
|
||||
export const vmLacksFeature = create(14, ({ vm, feature }) => ({
|
||||
data: {
|
||||
objectId: vm,
|
||||
feature,
|
||||
},
|
||||
message: `VM lacks feature ${feature || ''}`,
|
||||
}))
|
||||
|
||||
export const notSupportedDuringUpgrade = create(15, () => ({
|
||||
message: 'not supported during upgrade',
|
||||
}))
|
||||
|
||||
export const objectAlreadyExists = create(16, ({ objectId, objectType }) => ({
|
||||
data: {
|
||||
objectId,
|
||||
objectType,
|
||||
},
|
||||
message: `${objectType || 'object'} already exists`,
|
||||
}))
|
||||
|
||||
export const vdiInUse = create(17, ({ vdi, operation }) => ({
|
||||
data: {
|
||||
objectId: vdi,
|
||||
operation,
|
||||
},
|
||||
message: 'VDI in use',
|
||||
}))
|
||||
|
||||
export const hostOffline = create(18, ({ host }) => ({
|
||||
data: {
|
||||
objectId: host,
|
||||
},
|
||||
message: 'host offline',
|
||||
}))
|
||||
|
||||
export const operationBlocked = create(19, ({ objectId, code }) => ({
|
||||
data: {
|
||||
objectId,
|
||||
code,
|
||||
},
|
||||
message: 'operation blocked',
|
||||
}))
|
||||
|
||||
export const patchPrecheckFailed = create(20, ({ errorType, patch }) => ({
|
||||
data: {
|
||||
objectId: patch,
|
||||
errorType,
|
||||
},
|
||||
message: `patch precheck failed: ${errorType}`,
|
||||
}))
|
||||
24
packages/xo-lib/.npmignore
Normal file
24
packages/xo-lib/.npmignore
Normal file
@@ -0,0 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
168
packages/xo-lib/README.md
Normal file
168
packages/xo-lib/README.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# xo-lib [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||
> Library to connect to XO-Server.
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/xo-lib):
|
||||
|
||||
```
|
||||
npm install --save xo-lib
|
||||
```
|
||||
|
||||
Then require the package:
|
||||
|
||||
```javascript
|
||||
import Xo from 'xo-lib'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
> If the URL is not provided and the current environment is a web
|
||||
> browser, the location of the current page will be used.
|
||||
|
||||
```javascript
|
||||
// Connect to XO.
|
||||
const xo = new Xo({ url: 'https://xo.company.tld' })
|
||||
|
||||
// Let's start by opening the connection.
|
||||
await xo.open()
|
||||
|
||||
// Must sign in before being able to call any methods (all calls will
|
||||
// be buffered until signed in).
|
||||
await xo.signIn({
|
||||
email: 'admin@admin.net',
|
||||
password: 'admin'
|
||||
})
|
||||
|
||||
console('signed as', xo.user)
|
||||
```
|
||||
|
||||
The credentials can also be passed directly to the constructor:
|
||||
|
||||
```javascript
|
||||
const xo = Xo({
|
||||
url: 'https://xo.company.tld',
|
||||
credentials: {
|
||||
email: 'admin@admin.net',
|
||||
password: 'admin',
|
||||
}
|
||||
})
|
||||
|
||||
xo.open()
|
||||
|
||||
xo.on('authenticated', () => {
|
||||
console.log(xo.user)
|
||||
})
|
||||
```
|
||||
|
||||
> If the URL is not provided and the current environment is a web
|
||||
> browser, the location of the current page will be used.
|
||||
|
||||
### Connection
|
||||
|
||||
```javascript
|
||||
await xo.open()
|
||||
|
||||
console.log('connected')
|
||||
```
|
||||
|
||||
### Disconnection
|
||||
|
||||
```javascript
|
||||
xo.close()
|
||||
|
||||
console.log('disconnected')
|
||||
```
|
||||
|
||||
### Method call
|
||||
|
||||
```javascript
|
||||
const token = await xo.call('token.create')
|
||||
|
||||
console.log('Token created', token)
|
||||
```
|
||||
|
||||
### Status
|
||||
|
||||
The connection status is available through the status property which
|
||||
is *open*, *connecting* or *closed*.
|
||||
|
||||
```javascript
|
||||
console.log('%s to xo-server', xo.status)
|
||||
```
|
||||
|
||||
### Current user
|
||||
|
||||
Information about the user account used to sign in is available
|
||||
through the `user` property.
|
||||
|
||||
```javascript
|
||||
console.log('Current user is', xo.user)
|
||||
```
|
||||
|
||||
> This property is null when the status is not connected.
|
||||
|
||||
### Events
|
||||
|
||||
```javascript
|
||||
xo.on('open', () => {
|
||||
console.log('connected')
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
xo.on('closed', () => {
|
||||
console.log('disconnected')
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
xo.on('notification', function (notif) {
|
||||
console.log('notification:', notif.method, notif.params)
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
xo.on('authenticated', () => {
|
||||
console.log('authenticated as', xo.user)
|
||||
})
|
||||
|
||||
xo.on('authenticationFailure', () => {
|
||||
console.log('failed to authenticate')
|
||||
})
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> npm install
|
||||
|
||||
# Run the tests
|
||||
> npm test
|
||||
|
||||
# Continuously compile
|
||||
> npm run dev
|
||||
|
||||
# Continuously run the tests
|
||||
> npm run dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> npm run build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
ISC © [Vates SAS](http://vates.fr)
|
||||
62
packages/xo-lib/example.js
Normal file
62
packages/xo-lib/example.js
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict'
|
||||
|
||||
process.on('unhandledRejection', function (error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
const Xo = require('./').default
|
||||
|
||||
const xo = new Xo({
|
||||
url: 'localhost:9000',
|
||||
})
|
||||
|
||||
xo
|
||||
.open()
|
||||
.then(function () {
|
||||
return xo
|
||||
.call('acl.get', {})
|
||||
.then(function (result) {
|
||||
console.log('success:', result)
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('failure:', error)
|
||||
})
|
||||
})
|
||||
.then(function () {
|
||||
return xo
|
||||
.signIn({
|
||||
email: 'admin@admin.net',
|
||||
password: 'admin',
|
||||
})
|
||||
.then(function () {
|
||||
console.log('connected as ', xo.user)
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('failure:', error)
|
||||
})
|
||||
})
|
||||
.then(function () {
|
||||
return xo
|
||||
.signIn({
|
||||
email: 'tom',
|
||||
password: 'tom',
|
||||
})
|
||||
.then(function () {
|
||||
console.log('connected as', xo.user)
|
||||
|
||||
return xo
|
||||
.call('acl.get', {})
|
||||
.then(function (result) {
|
||||
console.log('success:', result)
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('failure:', error)
|
||||
})
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('failure', error)
|
||||
})
|
||||
})
|
||||
.then(function () {
|
||||
return xo.close()
|
||||
})
|
||||
73
packages/xo-lib/package.json
Normal file
73
packages/xo-lib/package.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "xo-lib",
|
||||
"version": "0.9.0",
|
||||
"license": "ISC",
|
||||
"description": "Library to connect to XO-Server",
|
||||
"keywords": [
|
||||
"xen",
|
||||
"orchestra",
|
||||
"xen-orchestra"
|
||||
],
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/xo-lib",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@vates.fr"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonrpc-websocket-client": "^0.3.0",
|
||||
"lodash": "^4.17.2",
|
||||
"make-error": "^1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"babel-preset-env": "^1.5.2",
|
||||
"babel-preset-stage-3": "^6.24.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"rimraf": "^2.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
},
|
||||
"babel": {
|
||||
"env": {
|
||||
"test": {
|
||||
"ignore": null
|
||||
}
|
||||
},
|
||||
"ignore": "*.spec.js",
|
||||
"plugins": [
|
||||
"lodash"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"browsers": "> 2%",
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-3"
|
||||
]
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user