Compare commits
1133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2aa919b444 | |||
| 408987ee30 | |||
| fe04ad9940 | |||
| 1b03e750a2 | |||
| 3ff781139e | |||
| 2ea3ba492e | |||
| 89d3228077 | |||
| 7946f5ee81 | |||
| 44f62eac9a | |||
| 47725e57b0 | |||
| aac2aaa999 | |||
| 6ac1160bf2 | |||
| 70fae41042 | |||
| 07f5bfe3dc | |||
| 93a88a22b9 | |||
| 792faa1176 | |||
| 66900d594f | |||
| 9555f3c853 | |||
| 9ed2fa734a | |||
| db83508920 | |||
| d72a6585d4 | |||
| 74fc8c9cf7 | |||
| f3440f3c01 | |||
| b01799c606 | |||
| 3cbb4e3f43 | |||
| 36299acbfb | |||
| acc20af2d9 | |||
| 077ce5b521 | |||
| 1efe82dda2 | |||
| f283618209 | |||
| fe6baf8dba | |||
| b742dc51fb | |||
| c8ea649afc | |||
| a27e94f694 | |||
| 25f9e7829f | |||
| 85be7acab2 | |||
| 36c23227e5 | |||
| 0b6f68e190 | |||
| 6c90fc2764 | |||
| 4fd1e55ae8 | |||
| 9672f7e3da | |||
| 50d29f8ef0 | |||
| 6ffa00026e | |||
| c4677505ac | |||
| bac6d7cf3c | |||
| 85ea91e0e3 | |||
| 09b09086ce | |||
| 8fbfa86a7f | |||
| 6224e942dc | |||
| ab5edbdd41 | |||
| 7825d10f18 | |||
| 8c1988e480 | |||
| 8403b811d8 | |||
| 1c797505ae | |||
| 466086b509 | |||
| 221f7247e6 | |||
| 624bc88f74 | |||
| d6ca4458e4 | |||
| 1fe3e60468 | |||
| aa65b2b97c | |||
| 6dea2475c7 | |||
| a666cb00eb | |||
| f0fac9165c | |||
| e51eb8a9c1 | |||
| 4822984e34 | |||
| 4a558a7f65 | |||
| 48d4935c7d | |||
| 506accfe9b | |||
| c15aba47f5 | |||
| fdafa8adf6 | |||
| 23e15581f3 | |||
| 1621f866a8 | |||
| f03fe33b1f | |||
| 6ec2a5ea35 | |||
| 0ae4d323f7 | |||
| 930404e482 | |||
| 92257afdab | |||
| 300ff09a47 | |||
| 14dd1103eb | |||
| ff07eb1de0 | |||
| b81f45bf47 | |||
| eb3232e049 | |||
| 752f653f82 | |||
| ed90dbe7b7 | |||
| e1e0f2944b | |||
| 2269f15b66 | |||
| 5c0a53e02a | |||
| 8810439ffc | |||
| 9d61270937 | |||
| b602a9d15d | |||
| bb0ab03ad9 | |||
| d674dcaeef | |||
| a738ddb917 | |||
| 935c92b507 | |||
| 10d1a2d8e4 | |||
| cf6d64646a | |||
| c570e8b6fe | |||
| 849b9e0c80 | |||
| 8f8aa31304 | |||
| a1fe79c876 | |||
| 7c9654a541 | |||
| a86df7cdbf | |||
| 3d5cdd659b | |||
| 7a2a5d3846 | |||
| 62fb0acb3c | |||
| c4dfe8a723 | |||
| 4af4df9288 | |||
| 25b0e18ceb | |||
| c4aec8dfa6 | |||
| 4056a3da43 | |||
| 2027f8052b | |||
| 96bb293c1f | |||
| fd73b28d66 | |||
| aafa698776 | |||
| a99d31535c | |||
| fda8791d5a | |||
| 9e2ac31a08 | |||
| 758b32a61c | |||
| 62b392e555 | |||
| a4c99fd361 | |||
| 8823656d70 | |||
| b82f5da112 | |||
| 729f51b779 | |||
| 1c1171e8a7 | |||
| 44df319ff6 | |||
| 84dec337f0 | |||
| 2e60a9d43c | |||
| 4474766526 | |||
| ddc1d8117d | |||
| 609bae4f1a | |||
| ff16a4334f | |||
| 739e308c0e | |||
| 6b29f57e1d | |||
| 21981829fd | |||
| b6e00a3107 | |||
| 8b8b137cad | |||
| 1ba1286df0 | |||
| 0417a82f83 | |||
| 4cc01a2152 | |||
| c7d434a091 | |||
| 3e1e704a7f | |||
| 12a9dcaa76 | |||
| fc2dd148c5 | |||
| ede6f36913 | |||
| f85143fb7b | |||
| bbf3043fc3 | |||
| bbd73d361a | |||
| 7d44c87aff | |||
| 7e81041b87 | |||
| e30698459b | |||
| 42399469a7 | |||
| 8ccc7bb734 | |||
| 38a7c222a8 | |||
| 9ea21606e5 | |||
| c809119d57 | |||
| b8ca009e69 | |||
| 1e37d7da7d | |||
| 9df90e4edc | |||
| 4576e93deb | |||
| ea5e0b28da | |||
| 19c8a01969 | |||
| ebab88e7aa | |||
| b4248acd9a | |||
| c303174f0b | |||
| 91cf6465df | |||
| 426d2aab09 | |||
| 8c44e558a8 | |||
| 6a08e08d7c | |||
| 2796ad12fe | |||
| 45d40297bf | |||
| 57ac37c210 | |||
| 8eee0b809c | |||
| 5387054000 | |||
| e08f072d95 | |||
| 44db2ca02a | |||
| dc8564d18e | |||
| 3b8bc9fdab | |||
| c5d65fa030 | |||
| 0252b08c8f | |||
| 8f29b7a91f | |||
| 19e1bbdc1c | |||
| cd2baf105f | |||
| 3366acde58 | |||
| 775f6eff0b | |||
| 52d501dae8 | |||
| eb24baf2c1 | |||
| 7fd0ef51b5 | |||
| 173acc5226 | |||
| 6643b825ee | |||
| a56f20584f | |||
| 22664bea62 | |||
| f80bf65076 | |||
| 28634c59c8 | |||
| 993377a40b | |||
| 9633733bc4 | |||
| 6b4893b854 | |||
| 09f7c35dac | |||
| 0fc4169b0b | |||
| 78746be0f5 | |||
| 2287a550d7 | |||
| d6eb6d3318 | |||
| db2d36eaa1 | |||
| 151d20341e | |||
| 2c51bc17f1 | |||
| 0448ad49ed | |||
| 2d4129f8f7 | |||
| c42aa7c806 | |||
| debeb8dfd8 | |||
| 2227e1dd4b | |||
| 1d7e73c162 | |||
| 3f451856a0 | |||
| fdd0483c9f | |||
| c1a49a52e8 | |||
| d8394392c9 | |||
| eb7a037f94 | |||
| eb905aab86 | |||
| 55892097d7 | |||
| 6bfcda9fdc | |||
| 02dcbb9a52 | |||
| 0c6a6e4173 | |||
| e044251df4 | |||
| 26d27a3f6a | |||
| c5b9fccedb | |||
| 0153e5212c | |||
| 92835a5270 | |||
| 5f41c78305 | |||
| 1726b89dea | |||
| 2506e69cdc | |||
| 88bc30bbea | |||
| 2835d1bd87 | |||
| e590896f01 | |||
| dfb0836446 | |||
| 88fdd1f562 | |||
| ae07c7934e | |||
| 9515a060ab | |||
| c550416c9d | |||
| 712883373a | |||
| 50930ee609 | |||
| 78bffad99f | |||
| b3760a961d | |||
| 813d92ce32 | |||
| b02570e679 | |||
| b7d1979d0d | |||
| 6e6846835a | |||
| d899935b56 | |||
| 2a07c063ab | |||
| 3ab9d77930 | |||
| 5537507646 | |||
| 215dd03751 | |||
| 3fe73ba198 | |||
| 6bc7edea67 | |||
| c44e69c396 | |||
| f6ad697755 | |||
| 2abca93333 | |||
| 788e7c40e9 | |||
| dca43f3e57 | |||
| f95a98d3ee | |||
| 11fe3dc492 | |||
| 4277244150 | |||
| 8458bcf10e | |||
| 6c8c7751fd | |||
| d6096d04d9 | |||
| bffe6327a0 | |||
| 28845d6f33 | |||
| 6ec7da9071 | |||
| 5dbe564afb | |||
| 4794791167 | |||
| 7b2ae2c457 | |||
| f0093c5e4f | |||
| 96117216ee | |||
| 9982557909 | |||
| 530331f9ee | |||
| 23018abdf6 | |||
| 23b72620a1 | |||
| a80c21d77f | |||
| 765307ddef | |||
| 9a859629bc | |||
| cc7b203f93 | |||
| 8744eadca0 | |||
| 76eaee5b1a | |||
| 7adde2a880 | |||
| c02eced029 | |||
| ad5ca50273 | |||
| 767756ba9b | |||
| c3cf5ff84c | |||
| a82c790855 | |||
| 4b22e3e0a8 | |||
| 2039a143ac | |||
| 84473dc10d | |||
| 5695da1d86 | |||
| 30583cce21 | |||
| 27c7c0438f | |||
| b67d5eec3d | |||
| 7c2ea6288c | |||
| 9a1d71face | |||
| 8e346bf676 | |||
| 53a00a8d76 | |||
| ea1e556197 | |||
| 402d75bfe0 | |||
| a444b61edf | |||
| ce41af14db | |||
| d52d606088 | |||
| 475311f63a | |||
| 5509089c49 | |||
| 3698220b8f | |||
| b22dba00a2 | |||
| 3d8ec5531c | |||
| 7df0ae0ba3 | |||
| 05d37cc6c6 | |||
| df03f783f8 | |||
| cd9263711f | |||
| 48c3372c33 | |||
| 5d1ff97bf3 | |||
| 1decfe8063 | |||
| a3d0ffb7de | |||
| 59a54f8683 | |||
| 83e2bd6ade | |||
| a59aca10ec | |||
| 9ac6e65087 | |||
| deb8e117ad | |||
| 9c3cae5eca | |||
| 1fbbeba5bc | |||
| 8317972078 | |||
| 0a9947dbb9 | |||
| 51521926e7 | |||
| 8e08ac2ce1 | |||
| fec82d127e | |||
| ceb0770ea0 | |||
| 34eadebe00 | |||
| e7f614cdf3 | |||
| 18507f79b1 | |||
| ee1c7dbf03 | |||
| 868af95ff2 | |||
| 01f59d39e0 | |||
| 0226a5603d | |||
| 1629be3788 | |||
| 480bc630da | |||
| 165cc279de | |||
| 2ec5a2acff | |||
| 6914e83dde | |||
| 263762c0bc | |||
| f8b8a574a6 | |||
| 79c80b351d | |||
| 2c86fb17fc | |||
| e205ffafdf | |||
| 2680b415c6 | |||
| 62d8b35545 | |||
| 2b578efdd6 | |||
| a7f37df34d | |||
| 3edb119422 | |||
| 07d4d5051a | |||
| 0b8e5a75f1 | |||
| f263c73df7 | |||
| f89f201764 | |||
| 9f8dcdf8ea | |||
| f3baf31dcd | |||
| a9400785ca | |||
| 7c76ad2088 | |||
| 6a5839d8cd | |||
| 744f39623f | |||
| 97e57c74e4 | |||
| ff0d6b658b | |||
| 1c946a438d | |||
| 9b047a1927 | |||
| 3fc6141d57 | |||
| daf7e2313b | |||
| 75642d785e | |||
| 2621b5c047 | |||
| 57cb9a1d0b | |||
| 6318ae046c | |||
| 57a41cde9d | |||
| ac86b7a954 | |||
| 0bc500e34f | |||
| a60e065e43 | |||
| 5563b6a786 | |||
| 0345c52aba | |||
| 05c858df9e | |||
| 0b4ef21762 | |||
| 64a58921a8 | |||
| b96098b909 | |||
| b1dbb2c408 | |||
| 3b1a08c67e | |||
| 07d37e133f | |||
| 161eb8bef9 | |||
| eb518c673c | |||
| 6f32a0d6de | |||
| b0684ce29c | |||
| b2c8a4d8ef | |||
| d09ac5bcc6 | |||
| c25c3e9daa | |||
| c1cb5c36a1 | |||
| 20118f941e | |||
| f40eee4577 | |||
| bee05afc87 | |||
| efdc533849 | |||
| 1f7c6d59c1 | |||
| 981622f414 | |||
| 347c8a8716 | |||
| 4542564709 | |||
| cb889ce06d | |||
| db54a305b0 | |||
| 8ccf17543a | |||
| 72e99885aa | |||
| 18d2a9cab6 | |||
| 9c57702afc | |||
| b708eb94d2 | |||
| 82c5531d04 | |||
| e6f49b2d3b | |||
| 8ac97e2c8f | |||
| db7174b0f3 | |||
| a47911048c | |||
| 5a2bdbf966 | |||
| aa562228ef | |||
| 98a70aedf2 | |||
| 9b9da5664b | |||
| 2f2314d2f8 | |||
| 715ebf0747 | |||
| bb0443b967 | |||
| 2cf0b528f0 | |||
| 6a95d481f0 | |||
| d281b21832 | |||
| 1d5cf43e68 | |||
| 6d6b2300a8 | |||
| 640ee55772 | |||
| 7ec12f487b | |||
| 63b42d64b1 | |||
| 667506172a | |||
| 518bb74fbf | |||
| 9038538718 | |||
| 5234f50453 | |||
| 6eabf73ece | |||
| 651d01564d | |||
| 52cdec8d3c | |||
| 998c9bdeb7 | |||
| 318ee89e89 | |||
| 031d7a1f18 | |||
| 7424a226c9 | |||
| 30a1997fd9 | |||
| 778ea0b720 | |||
| 353517f9c6 | |||
| e651b2ee13 | |||
| 018b3a876f | |||
| 1b9586011e | |||
| cb856ce2bb | |||
| 8d3c1c9f9e | |||
| 1ec0f67b29 | |||
| 093491c5b4 | |||
| 56191d0cd9 | |||
| 7342268eb8 | |||
| 3a09cbf42b | |||
| b268368e3d | |||
| 59c8211c41 | |||
| 14560fff0a | |||
| adf3172ebb | |||
| 4ead9cbf6a | |||
| 0863dc785f | |||
| 342538358d | |||
| a8b79055ef | |||
| ec3be4c36a | |||
| 0a2ef0e041 | |||
| e7b623ea16 | |||
| 87777017a0 | |||
| bf2c7a18d1 | |||
| b5505bcd87 | |||
| bdf9fbae71 | |||
| 04c1afc9ce | |||
| 458c51bdaa | |||
| 90a736ba43 | |||
| 661ce4fc1d | |||
| b764f1c861 | |||
| 182949d8d2 | |||
| a879bdeb47 | |||
| 9c66a4ef4e | |||
| d2d75b8e41 | |||
| e36c15f770 | |||
| 8dc6da2b7a | |||
| d3ae252740 | |||
| 29f48bcba6 | |||
| e6fe5adca7 | |||
| 82a96ec91d | |||
| db02cbb575 | |||
| 749dd20704 | |||
| b9db6040f4 | |||
| c9628c0f75 | |||
| 979af88a40 | |||
| 98b4cd330f | |||
| 5ab390c3db | |||
| 71eaf9966f | |||
| 9653d07ae2 | |||
| f1663d0fbf | |||
| 38cb2201a9 | |||
| fa04bea64b | |||
| 2bc66af55d | |||
| db5892d0ae | |||
| 59c7c1e302 | |||
| 48f63ec761 | |||
| 4051e34e20 | |||
| 428bd43d60 | |||
| 67415ff715 | |||
| fbc494abc9 | |||
| 0816af3cf1 | |||
| bb575fff5b | |||
| cbe632839c | |||
| 7c972758af | |||
| 236f66f56f | |||
| a485df2f79 | |||
| 54b9154457 | |||
| 37aabcee4f | |||
| b2d18560be | |||
| 1429aa1edc | |||
| 5d4f942d46 | |||
| 30ea7e854d | |||
| 907f82338e | |||
| dcb0160b64 | |||
| fccd7fa438 | |||
| c39711a87e | |||
| a8de003cf0 | |||
| 6db54fc3b5 | |||
| d058536011 | |||
| 02ad4ba98d | |||
| a68a76112c | |||
| 975c545081 | |||
| fcfee9082b | |||
| e6ad14f8d4 | |||
| 1670f15732 | |||
| 5cd696792b | |||
| fbc399f5fa | |||
| 3d6413ae05 | |||
| 97120a6b04 | |||
| 226162ee57 | |||
| a888ec265f | |||
| 6fb7555f01 | |||
| a8d0e25866 | |||
| 970f7fe69b | |||
| c507df902e | |||
| 7fa5ef8165 | |||
| 92cb768c4b | |||
| 8ec406c2e0 | |||
| 9473c108f0 | |||
| 14c43d9f7e | |||
| ce9a03a5a8 | |||
| 04e8b14fc4 | |||
| 43b747676c | |||
| bd40cf9947 | |||
| 203b31d81f | |||
| 0430fb2772 | |||
| d3746d6859 | |||
| d8dfa89f87 | |||
| cbdb90d06b | |||
| 63e040ea79 | |||
| fd1a0f3b0a | |||
| abaf8a676c | |||
| 0b96fc4701 | |||
| 400e210d37 | |||
| ea0c697ad3 | |||
| edf8c32a0f | |||
| ccef5da7d9 | |||
| ddf213aec4 | |||
| 8bd9237951 | |||
| ae488312a1 | |||
| 1ed45656e4 | |||
| 07edcc5f94 | |||
| 1783059fd4 | |||
| aab766e8ff | |||
| 158514f334 | |||
| 77d29c3728 | |||
| 3c3383ac03 | |||
| 6e46240fd7 | |||
| d01c46bfee | |||
| 1e5007ec8b | |||
| deed95e9a9 | |||
| 082323511a | |||
| c07224cab5 | |||
| 1604a96f41 | |||
| 50963f00c0 | |||
| 699db93b18 | |||
| 85e467581c | |||
| 42e4588e9c | |||
| 93c194cff7 | |||
| 00450dc048 | |||
| c319fd5862 | |||
| 5048b5b585 | |||
| e7f24084af | |||
| c57b9b4fa3 | |||
| ac5b7a4469 | |||
| 884faa0e27 | |||
| 50b4b7bb92 | |||
| cf259ace47 | |||
| 270389a18c | |||
| a340eea769 | |||
| 22589e7103 | |||
| 2b6423d3b7 | |||
| 50bf193fd1 | |||
| c2ba059ced | |||
| 856ed0c765 | |||
| a73681ce8b | |||
| 1426ed952b | |||
| d6bf6eb0a0 | |||
| 97b24079f7 | |||
| 707f84839e | |||
| 643d2f3fad | |||
| 92660e037d | |||
| 2e6a0411fb | |||
| 5d57a5fabb | |||
| cb90ad803b | |||
| 937e8ce1ed | |||
| c1976d5b13 | |||
| 8070e88564 | |||
| 15c0c691ff | |||
| f68912b466 | |||
| dfa4e20a8f | |||
| ee1a194305 | |||
| 0fa88855e5 | |||
| eda3d5c143 | |||
| b450efe5c2 | |||
| ca76626d55 | |||
| ed887953b6 | |||
| 04debe3ea3 | |||
| 4312096dd2 | |||
| 94b079fa7b | |||
| 0373d86349 | |||
| 0f5c290785 | |||
| c79f43bb27 | |||
| 184ad3bc4e | |||
| aa0a4ae3e9 | |||
| ff9c4b407f | |||
| c3b01d477e | |||
| 3c0641745b | |||
| 7186a0c41b | |||
| 4c3bc7450e | |||
| 02f04e2d33 | |||
| 97b6e4c672 | |||
| 2fd1caa2aa | |||
| cb25217c48 | |||
| ab70bc663d | |||
| 0cfe931cd1 | |||
| 29bddb5fcb | |||
| cb7d160346 | |||
| 507c8b8786 | |||
| 60107147c2 | |||
| be2afec86b | |||
| d316d216db | |||
| dd53d0d575 | |||
| 0f6c0a2ccd | |||
| 937a165711 | |||
| 22c402ca3d | |||
| eddbd4fddc | |||
| 0e43ca31a3 | |||
| 9c90a20b4d | |||
| 764e7e7d1f | |||
| 0e8cb00233 | |||
| 0a1a011338 | |||
| 3dfcd9324d | |||
| 3e4ac4a0ca | |||
| be1795d50d | |||
| 0b0b06baa9 | |||
| b789cd2af0 | |||
| 0871403c0a | |||
| 53a34d9352 | |||
| fe23551b04 | |||
| 484b6477d3 | |||
| 8ebe04c2ff | |||
| 672d6b0856 | |||
| 0c066fafa2 | |||
| 6c574ead94 | |||
| 31a62313bb | |||
| 4dacf7064f | |||
| e900e4de77 | |||
| 4ce6939b79 | |||
| 8430fd1473 | |||
| ac7c54e273 | |||
| 6c9a3b530d | |||
| 2f2c70d1df | |||
| a78c991330 | |||
| 8f9349ec53 | |||
| bc6be6a9ad | |||
| a9b7c2795a | |||
| cd81cc8cb8 | |||
| 473b35d807 | |||
| 0c04d5bfc8 | |||
| eed460f435 | |||
| d742982973 | |||
| c8263077a2 | |||
| eae01bdbd9 | |||
| 1ebafbbc20 | |||
| a525bb0257 | |||
| cf5cf9e42f | |||
| 7969dff043 | |||
| d73f7304b3 | |||
| 4400b0117a | |||
| 739c91b1c6 | |||
| 510115ade9 | |||
| 8c2d79b75e | |||
| 1a31fb78e5 | |||
| 97f4d5e3ac | |||
| d0b17f7e7b | |||
| eb74aaff3b | |||
| 9108b665a8 | |||
| e449147ed4 | |||
| 53e82876dd | |||
| dd4a4518b3 | |||
| a9e46c64b1 | |||
| fb85770fd3 | |||
| 9e9e651714 | |||
| 314da7ace8 | |||
| 54103ca120 | |||
| be86a3022f | |||
| 91ecab08da | |||
| cae445556e | |||
| 8c2af87857 | |||
| 2d44e356d3 | |||
| dec1931f07 | |||
| 46473c3756 | |||
| cd893edfcf | |||
| 84302c1739 | |||
| d6f6b4bfe5 | |||
| 8c6531b6fb | |||
| f4993a7e58 | |||
| cc812c2177 | |||
| e11dc028d1 | |||
| e314910a76 | |||
| ee9140c365 | |||
| ce4ccc21dd | |||
| 6108fcf17b | |||
| cd3fb77033 | |||
| 0697274311 | |||
| 11f5aaaf3b | |||
| 8f0b66bd98 | |||
| 3be660dcd9 | |||
| 3bb82d5e68 | |||
| 3f9f1480d3 | |||
| 948c446362 | |||
| 25f888e0d8 | |||
| 98661de24e | |||
| a833ceb737 | |||
| b41d0379f0 | |||
| df6da7dd1c | |||
| 24ca5bc990 | |||
| e3e62b8407 | |||
| 0c98e6f4ca | |||
| 6034121695 | |||
| afe837e30a | |||
| f3cf640e21 | |||
| 8d98cefcca | |||
| bdf57a5c0a | |||
| 37f108d9f7 | |||
| 091663afe0 | |||
| a77918bef9 | |||
| f167714ea1 | |||
| 1cab172169 | |||
| 35c3df5a18 | |||
| b9a6f46543 | |||
| 12b1909c7a | |||
| 5bd57b6dbd | |||
| 961220be3f | |||
| 4db703aeb1 | |||
| cec1cc7086 | |||
| 2bacbe6701 | |||
| 3c65d88c65 | |||
| 726a1c37cc | |||
| 63f2bbb253 | |||
| 7f11cc0daf | |||
| f32884b3b2 | |||
| 97465c1bd8 | |||
| ce0a1ce38a | |||
| f5060a0d4f | |||
| bb34c8a242 | |||
| 34fd733bb7 | |||
| 19b65460ff | |||
| edf277fcaf | |||
| 9db334c2a4 | |||
| 1039d9c95e | |||
| 37c8b2b57f | |||
| 461fb0144e | |||
| 60a9c60f40 | |||
| 869a6b5a51 | |||
| 133e101f83 | |||
| 6ecadb2308 | |||
| 0d3ff81d6c | |||
| e938886629 | |||
| aa32055aa8 | |||
| 59481c37bc | |||
| 0b868dad2d | |||
| 3c063a2263 | |||
| f9750e237a | |||
| 908bb75fdc | |||
| a273827166 | |||
| 0cb96f4b03 | |||
| af7764253d | |||
| af9652f7c8 | |||
| e741ca9216 | |||
| e3950c2fb0 | |||
| 3eae49139c | |||
| 97f17916f9 | |||
| ee0a25962b | |||
| 55fb3b3b55 | |||
| a58d9d1497 | |||
| 801dbc9705 | |||
| e3897c4c34 | |||
| 04dd8914cd | |||
| c2651fd8f8 | |||
| 27f760fdbf | |||
| a74cf0b064 | |||
| e09d2db7e6 | |||
| 28f183f450 | |||
| 5126b605f2 | |||
| aaebdda9d6 | |||
| af29a3f498 | |||
| 55b6773d88 | |||
| 239ec86c4a | |||
| 13adca00d6 | |||
| a76631ee3d | |||
| 7ac99f16cd | |||
| 3b6ca1c59d | |||
| 3f55064c47 | |||
| 917bc2a88c | |||
| 85dfa1ccad | |||
| 606828da1d | |||
| a182d78566 | |||
| 0f294531d3 | |||
| 9189532b83 | |||
| c031253bd4 | |||
| 11ae5d4832 | |||
| 3251dc3d73 | |||
| a671e6acf7 | |||
| 5ce658125c | |||
| 1d88a935a5 | |||
| 8da07a16b9 | |||
| 7ce045ae51 | |||
| a3e253436e | |||
| 08955ce5a4 | |||
| 57a4fa2d38 | |||
| 548e652ba2 | |||
| e92cfae4d9 | |||
| ed1320c937 | |||
| abccffd05f | |||
| c1106aa32e | |||
| a94f5daac9 | |||
| 9d9f16e948 | |||
| 0b5bd0b4cd | |||
| caa59dd9a9 | |||
| 423958dd0e | |||
| 6a90cf5102 | |||
| 2d820a3005 | |||
| 7fff55a1ed | |||
| 52d1d47030 | |||
| 7df1d388f0 | |||
| a34f5f13da | |||
| bcc1e5f79c | |||
| 44d32ea281 | |||
| 63e16c9bb8 | |||
| 528be0e4c0 | |||
| 0660a924b7 | |||
| 6f29d5f3f6 | |||
| 9903004af5 | |||
| 0c2b250901 | |||
| 00f8e96dd2 | |||
| 267fa79164 | |||
| 1528aa9d0c | |||
| 0cd6f7f2e7 | |||
| f05967d871 | |||
| 26087e1580 | |||
| 9275c4fbfd | |||
| a2e03ccf7a | |||
| 6605a38eab | |||
| 0a09d89684 | |||
| c0d4100dd1 | |||
| 791f5af3e0 | |||
| ed57e701bc | |||
| c678a9b6d7 | |||
| 07b428f051 | |||
| a1ab8b6aa8 | |||
| a07848164c | |||
| 1b1d4ee431 | |||
| f8e5668c5c | |||
| d8719626d9 | |||
| 3a06797de0 | |||
| b9d7149dbb | |||
| 72bbb4ec68 | |||
| d9ec1be9b6 | |||
| ecddb6977a | |||
| 77220038a1 | |||
| 016f194271 | |||
| e34fecee5e | |||
| 7448dc5ec5 | |||
| bfd25a08c2 | |||
| 8861e61bdf | |||
| 049c2fca8a | |||
| 63df9df913 | |||
| 05b6740e07 | |||
| 46aac0288c | |||
| 4ec0fbd33c | |||
| 7a24d5fdfa | |||
| 3f082ccace | |||
| a37fc3093a | |||
| 4541940a76 | |||
| 3017fe0c95 | |||
| d3bf9a2478 | |||
| 7107672358 | |||
| 8519d6665e | |||
| 774c9e435e | |||
| e1f35a8d9f | |||
| 67136e418c | |||
| 924cc997aa | |||
| 12eda5f507 | |||
| 96bb979abf | |||
| f74ad0323c | |||
| 62fd73f1b1 | |||
| 44f027eb04 | |||
| c9cf6d610b | |||
| 16d4d28046 | |||
| 2280008029 | |||
| a36439314d | |||
| 290b44fbb7 | |||
| 404c280595 | |||
| b0f8370a31 | |||
| 6abcf4ec3c | |||
| db6d7bcefb | |||
| 0e1913b0b4 | |||
| cc6b097dc5 | |||
| c4f7a0c857 | |||
| 34187d76b6 | |||
| 87e7e9fa07 | |||
| 8643fbb65c | |||
| 6a2846afeb | |||
| 7bfa23e2b1 | |||
| bcd55972cd | |||
| d75e1d04b3 | |||
| 02ef77398a | |||
| b0b19053a7 | |||
| 5cc298555a | |||
| f2a0dcca31 | |||
| c274e60868 | |||
| bde6ef8797 | |||
| df15f63424 | |||
| 1bd4a0aa8e | |||
| f068ce4e85 | |||
| 20093c581c | |||
| 814d7bafa8 | |||
| e07fac0335 | |||
| 39730c71ce | |||
| 8565130166 | |||
| 9acde7fe86 | |||
| 63e43e8d20 | |||
| 10a3af8e5e | |||
| 14536febaf | |||
| 75b597418c | |||
| 435730470b | |||
| 689ddf6875 | |||
| fa550f57b3 | |||
| b9b84b661a | |||
| b7573f449f | |||
| 69f6895bd6 | |||
| 72a1e0d5ca | |||
| 4eb80eedc0 | |||
| 32e6931b46 | |||
| f60258ed71 | |||
| 32454ba64a | |||
| de212f49c2 | |||
| c308bd90cb | |||
| 593bde9d92 | |||
| a16bd7030a | |||
| 4d248bce39 | |||
| e236264848 | |||
| 20e9877fe9 | |||
| b0c4021d17 | |||
| 01bfd84853 | |||
| a0dbcc9bb3 | |||
| bbe351161f | |||
| 968f515679 | |||
| cbb5cb3702 | |||
| 82ed1881ea | |||
| 4d13d309d3 | |||
| 75eae0d8ec | |||
| c329541708 | |||
| 10b8e93713 | |||
| 963b1d60b5 | |||
| 158271de14 | |||
| baba63889d | |||
| d52273a516 | |||
| 1b7556443f | |||
| 9575a1158a | |||
| 8ebcc2f8af | |||
| 8d6de76fa0 | |||
| 0ad813cc8d | |||
| 63ae9a90cf | |||
| 551912145e | |||
| 611f54c237 | |||
| 60c9f49b44 | |||
| 9f66003755 | |||
| 862e1d94be | |||
| 8196f76847 | |||
| 09f1bb4653 | |||
| f626a1f0b7 | |||
| fd609d3e19 | |||
| 977e83cc22 | |||
| 59b3cabf7e | |||
| 4d85c36c16 | |||
| b762f80812 | |||
| 4e0791eb22 | |||
| 392e6d1c98 | |||
| 5a49a555ad | |||
| d59cb63188 | |||
| 1d0f87f408 | |||
| a26264e8ce | |||
| ed716d7569 | |||
| f85fca1720 | |||
| ed2539cbfc | |||
| 5405338d20 | |||
| f8ad2fdc11 | |||
| a618f2b523 | |||
| 8b5a88ba5e | |||
| db9e3b44a1 | |||
| 634408d3a3 | |||
| 529a668db3 | |||
| c0f01da1cd | |||
| 4cbab59fdb | |||
| ec9c9fb0f5 | |||
| 286d634756 | |||
| ca2457bfcb | |||
| 459cafdf56 | |||
| b9d6c8f8bb | |||
| 2da019556b | |||
| cbd28bc12f | |||
| 4332f60cc4 | |||
| 950179ee1c | |||
| 803eb4760e | |||
| 32a41e6c1c | |||
| de195c461b | |||
| 5003a8ea4d | |||
| caa41b0022 | |||
| c7151d2b8d | |||
| 0929ae1a4c | |||
| 0c79c42c10 | |||
| 028b24db03 | |||
| bce3d3f664 | |||
| 828d6f6cc8 | |||
| 0a026cc143 | |||
| 3bc9a87933 | |||
| 769f9adc9d | |||
| b5f53d921e | |||
| 105e9e7825 | |||
| c8cf050156 | |||
| b7baafbbe6 | |||
| 85dde71ec3 | |||
| 2970b086a3 | |||
| 5910709008 | |||
| 2b6ce4f813 | |||
| 451c697fb7 | |||
| 09149318b1 | |||
| d2d8eb9485 | |||
| 91265613a9 | |||
| 31c414bbe1 | |||
| e2a3654ed7 | |||
| 96d7283534 | |||
| 256a7e322b | |||
| e5b78337ac | |||
| 67ba5aa1c5 | |||
| 848a617f98 | |||
| 1fc7efef0d | |||
| 576f6eafbb | |||
| 2caf73b5e3 | |||
| 56abb68e0c | |||
| 7aaac5a48a | |||
| 8326587886 | |||
| 466b3f4784 | |||
| bccdf548a8 | |||
| fa4b1b3d5b | |||
| 9d47fd198f | |||
| 5966ee6800 | |||
| 2d20e3c13d | |||
| 2172f8532d | |||
| 9dc4318152 | |||
| e1a92e7127 | |||
| 767b31caa2 | |||
| c2232936e0 | |||
| 4f1bbfd9e3 | |||
| caf57e37dc | |||
| 64b8e4ad6c | |||
| c9d3907124 | |||
| bf6bea800b | |||
| 26f1673d47 | |||
| 08153454a2 | |||
| efc26ab587 | |||
| e24e0a7e87 | |||
| 23bc267c46 | |||
| 35cc592d61 | |||
| 512f6a1166 | |||
| 3160ffec3f | |||
| c543d4517f | |||
| d7334b991b | |||
| 2b355f6ee4 | |||
| cd6af57a6e | |||
| 674028ee77 | |||
| f51c2e7b61 | |||
| 182085d3f8 | |||
| b8e70f1160 | |||
| c624c04e9d | |||
| 666badfa38 | |||
| 21b9843083 | |||
| f3b53a22f5 | |||
| f850235b3a | |||
| f555cfddd0 | |||
| 1c9052f085 | |||
| 6a450b7190 | |||
| 75194525fb | |||
| 9d57c81505 | |||
| 8af587b6d9 | |||
| c1cb2eda00 | |||
| 90c867da82 | |||
| d97268dfa7 | |||
| c3ce6ef9f0 | |||
| eb3d6fe5f1 | |||
| e39e7d4898 | |||
| b282375ac7 | |||
| 8deb28f8eb | |||
| e91833dcf2 | |||
| ca9781c279 | |||
| 2d8412a629 | |||
| e4b253da22 | |||
| 6edad6b986 | |||
| 7b7e94d3d6 | |||
| bc164281db | |||
| f94380b2dd | |||
| a2241a4e47 | |||
| 7e5afcfe6a | |||
| 7c926cc051 | |||
| 16f43e3eac | |||
| 456577a166 | |||
| 7166604fc0 | |||
| 0ae8d1ed4d | |||
| 4388aee70d | |||
| 13e4ceff44 |
+3
-3
@@ -1,6 +1,6 @@
|
||||
# Skip files when using git archive
|
||||
# following files are skipped when exporting using git archive
|
||||
test export-ignore
|
||||
docs export-ignore
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
/scripts export-ignore
|
||||
test export-ignore
|
||||
|
||||
|
||||
+2
-9
@@ -1,13 +1,6 @@
|
||||
dist/
|
||||
node_modules/
|
||||
coverage/
|
||||
docs/
|
||||
webadmin/dist/
|
||||
setup/splash/website/
|
||||
|
||||
# vim swam files
|
||||
# vim swap files
|
||||
*.swp
|
||||
|
||||
# supervisor
|
||||
supervisord.pid
|
||||
supervisord.log
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"unused": true,
|
||||
"globalstrict": true,
|
||||
"predef": [ "angular", "$" ]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
The Cloudron Subscription license
|
||||
Copyright (c) 2019 Cloudron UG
|
||||
|
||||
With regard to the Cloudron Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the Cloudron Subscription Terms of Service, available
|
||||
at https://cloudron.io/legal/terms.html (the “Subscription Terms”), or other
|
||||
agreement governing the use of the Software, as agreed by you and Cloudron,
|
||||
and otherwise have a valid Cloudron Subscription. Subject to the foregoing sentence,
|
||||
you are free to modify this Software and publish patches to the Software. You agree
|
||||
that Subscription and/or its licensors (as applicable) retain all right, title and
|
||||
interest in and to all such modifications and/or patches, and all such modifications
|
||||
and/or patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid Cloudron subscription. Notwithstanding the foregoing, you may copy
|
||||
and modify the Software for development and testing purposes, without requiring a
|
||||
subscription. You agree that Cloudron and/or its licensors (as applicable) retain
|
||||
all right, title and interest in and to all such modifications. You are not
|
||||
granted any other rights beyond what is expressly stated herein. Subject to the
|
||||
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the Cloudron Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
||||
|
||||
@@ -1,11 +1,64 @@
|
||||
The Box
|
||||
=======
|
||||
# Cloudron Dashboard
|
||||
|
||||
Development setup
|
||||
-----------------
|
||||
* sudo useradd -m yellowtent
|
||||
** This dummy user is required for supervisor 'box' configs
|
||||
** Add admin-localhost as 127.0.0.1 in /etc/hosts
|
||||
** All apps will be installed as hypened-subdomains of localhost. You should add
|
||||
hyphened-subdomains of your apps into /etc/hosts
|
||||
[Cloudron](https://cloudron.io) is the best way to run apps on your server.
|
||||
|
||||
Web applications like email, contacts, blog, chat are the backbone of the modern
|
||||
internet. Yet, we live in a world where hosting these essential applications is
|
||||
a complex task.
|
||||
|
||||
We are building the ultimate platform for self-hosting web apps. The Cloudron allows
|
||||
anyone to effortlessly host web applications on their server on their own terms.
|
||||
|
||||
## Features
|
||||
|
||||
* Single click install for apps. Check out the [App Store](https://cloudron.io/appstore.html).
|
||||
|
||||
* Per-app encrypted backups and restores.
|
||||
|
||||
* App updates delivered via the App Store.
|
||||
|
||||
* Secure - Cloudron manages the firewall. All apps are secured with HTTPS. Certificates are
|
||||
installed and renewed automatically.
|
||||
|
||||
* Centralized User & Group management. Control who can access which app.
|
||||
|
||||
* Single Sign On. Use same credentials across all apps.
|
||||
|
||||
* Automatic updates for the Cloudron platform.
|
||||
|
||||
* Trivially migrate to another server keeping your apps and data (for example, switch your
|
||||
infrastructure provider or move to a bigger server).
|
||||
|
||||
* Comprehensive [REST API](https://cloudron.io/developer/api/).
|
||||
|
||||
* [CLI](https://cloudron.io/documentation/cli/) to configure apps.
|
||||
|
||||
* Alerts, audit logs, graphs, dns management ... and much more
|
||||
|
||||
## Demo
|
||||
|
||||
Try our demo at https://my.demo.cloudron.io (username: cloudron password: cloudron).
|
||||
|
||||
## Installing
|
||||
|
||||
You can install the Cloudron platform on your own server or get a managed server
|
||||
from cloudron.io. In either case, the Cloudron platform will keep your server and
|
||||
apps up-to-date and secure.
|
||||
|
||||
* [Selfhosting](https://cloudron.io/documentation/installation/) - [Pricing](https://cloudron.io/pricing.html)
|
||||
* [Managed Hosting](https://cloudron.io/managed.html)
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Documentation](https://cloudron.io/documentation/)
|
||||
|
||||
## Related repos
|
||||
|
||||
The [base image repo](https://git.cloudron.io/cloudron/docker-base-image) is the parent image of all
|
||||
the containers in the Cloudron.
|
||||
|
||||
## Community
|
||||
|
||||
* [Forum](https://forum.cloudron.io/)
|
||||
* [Support](mailto:support@cloudron.io)
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
require('supererror')({ splatchError: true });
|
||||
|
||||
var server = require('./src/server.js'),
|
||||
ldap = require('./src/ldap.js'),
|
||||
config = require('./src/config.js');
|
||||
|
||||
console.log();
|
||||
console.log('==========================================');
|
||||
console.log(' Cloudron will use the following settings ');
|
||||
console.log('==========================================');
|
||||
console.log();
|
||||
console.log(' Environment: ', config.CLOUDRON ? 'CLOUDRON' : 'TEST');
|
||||
console.log(' Version: ', config.version());
|
||||
console.log(' Admin Origin: ', config.adminOrigin());
|
||||
console.log(' Appstore token: ', config.token());
|
||||
console.log(' Appstore API server origin: ', config.apiServerOrigin());
|
||||
console.log(' Appstore Web server origin: ', config.webServerOrigin());
|
||||
console.log();
|
||||
console.log('==========================================');
|
||||
console.log();
|
||||
|
||||
server.start(function (err) {
|
||||
if (err) {
|
||||
console.error('Error starting server', err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('Server listening on port ' + config.get('port'));
|
||||
|
||||
ldap.start(function (error) {
|
||||
if (error) {
|
||||
console.error('Error LDAP starting server', err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('LDAP server listen on port ' + config.get('ldapPort'));
|
||||
});
|
||||
});
|
||||
|
||||
var NOOP_CALLBACK = function () { };
|
||||
|
||||
process.on('SIGINT', function () { server.stop(NOOP_CALLBACK); });
|
||||
process.on('SIGTERM', function () { server.stop(NOOP_CALLBACK); });
|
||||
@@ -1,147 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
require('supererror')({ splatchError: true });
|
||||
|
||||
var appdb = require('./src/appdb.js'),
|
||||
assert = require('assert'),
|
||||
async = require('async'),
|
||||
database = require('./src/database.js'),
|
||||
DatabaseError = require('./src/databaseerror.js'),
|
||||
debug = require('debug')('box:apphealthtask'),
|
||||
docker = require('./src/docker.js'),
|
||||
mailer = require('./src/mailer.js'),
|
||||
superagent = require('superagent'),
|
||||
util = require('util');
|
||||
|
||||
exports = module.exports = {
|
||||
run: run
|
||||
};
|
||||
|
||||
var HEALTHCHECK_INTERVAL = 10 * 1000; // every 10 seconds. this needs to be small since the UI makes only healthy apps clickable
|
||||
var UNHEALTHY_THRESHOLD = 3 * 60 * 1000; // 3 minutes
|
||||
var gHealthInfo = { }; // { time, emailSent }
|
||||
|
||||
function debugApp(app, args) {
|
||||
assert(!app || typeof app === 'object');
|
||||
|
||||
var prefix = app ? app.location : '(no app)';
|
||||
debug(prefix + ' ' + util.format.apply(util, Array.prototype.slice.call(arguments, 1)));
|
||||
}
|
||||
|
||||
function initialize(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
async.series([
|
||||
database.initialize,
|
||||
mailer.initialize
|
||||
], callback);
|
||||
}
|
||||
|
||||
function setHealth(app, health, callback) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof health, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
var now = new Date();
|
||||
|
||||
if (!(app.id in gHealthInfo)) { // add new apps to list
|
||||
gHealthInfo[app.id] = { time: now, emailSent: false };
|
||||
}
|
||||
|
||||
if (health === appdb.HEALTH_HEALTHY) {
|
||||
gHealthInfo[app.id].time = now;
|
||||
} else if (Math.abs(now - gHealthInfo[app.id].time) > UNHEALTHY_THRESHOLD) {
|
||||
if (gHealthInfo[app.id].emailSent) return callback(null);
|
||||
|
||||
debugApp(app, 'marking as unhealthy since not seen for more than %s minutes', UNHEALTHY_THRESHOLD/(60 * 1000));
|
||||
|
||||
mailer.appDied(app);
|
||||
gHealthInfo[app.id].emailSent = true;
|
||||
} else {
|
||||
debugApp(app, 'waiting for sometime to update the app health');
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
appdb.setHealth(app.id, health, function (error) {
|
||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(null); // app uninstalled?
|
||||
if (error) return callback(error);
|
||||
|
||||
app.health = health;
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// callback is called with error for fatal errors and not if health check failed
|
||||
function checkAppHealth(app, callback) {
|
||||
if (app.installationState !== appdb.ISTATE_INSTALLED || app.runState !== appdb.RSTATE_RUNNING) {
|
||||
debugApp(app, 'skipped. istate:%s rstate:%s', app.installationState, app.runState);
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
var container = docker.getContainer(app.containerId),
|
||||
manifest = app.manifest;
|
||||
|
||||
container.inspect(function (err, data) {
|
||||
if (err || !data || !data.State) {
|
||||
debugApp(app, 'Error inspecting container');
|
||||
return setHealth(app, appdb.HEALTH_ERROR, callback);
|
||||
}
|
||||
|
||||
if (data.State.Running !== true) {
|
||||
debugApp(app, 'exited');
|
||||
return setHealth(app, appdb.HEALTH_DEAD, callback);
|
||||
}
|
||||
|
||||
// poll through docker network instead of nginx to bypass any potential oauth proxy
|
||||
var healthCheckUrl = 'http://127.0.0.1:' + app.httpPort + manifest.healthCheckPath;
|
||||
superagent
|
||||
.get(healthCheckUrl)
|
||||
.redirects(0)
|
||||
.timeout(HEALTHCHECK_INTERVAL)
|
||||
.end(function (error, res) {
|
||||
|
||||
if (error || res.status >= 400) { // 2xx and 3xx are ok
|
||||
debugApp(app, 'not alive : %s', error || res.status);
|
||||
setHealth(app, appdb.HEALTH_UNHEALTHY, callback);
|
||||
} else {
|
||||
debugApp(app, 'alive');
|
||||
setHealth(app, appdb.HEALTH_HEALTHY, callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function processApps(callback) {
|
||||
appdb.getAll(function (error, apps) {
|
||||
if (error) return callback(error);
|
||||
|
||||
async.each(apps, checkAppHealth, function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function run() {
|
||||
processApps(function (error) {
|
||||
if (error) console.error(error);
|
||||
|
||||
setTimeout(run, HEALTHCHECK_INTERVAL);
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
initialize(function (error) {
|
||||
if (error) {
|
||||
console.error('apphealth task exiting with error', error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
run();
|
||||
});
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,53 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
// WARNING This is a supervisor eventlistener!
|
||||
// The communication happens via stdin/stdout
|
||||
// !! No console.log() allowed
|
||||
// !! Do not set DEBUG
|
||||
|
||||
var assert = require('assert'),
|
||||
mailer = require('./src/mailer.js'),
|
||||
safe = require('safetydance'),
|
||||
supervisor = require('supervisord-eventlistener'),
|
||||
path = require('path'),
|
||||
util = require('util');
|
||||
|
||||
var gLastNotifyTime = {};
|
||||
var gCooldownTime = 1000 * 60 * 5; // 5 min
|
||||
var COLLECT_LOGS_CMD = path.join(__dirname, 'src/scripts/collectlogs.sh');
|
||||
|
||||
function collectLogs(program, callback) {
|
||||
assert.strictEqual(typeof program, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
var logs = safe.child_process.execSync('sudo ' + COLLECT_LOGS_CMD + ' ' + program, { encoding: 'utf8' });
|
||||
callback(null, logs);
|
||||
}
|
||||
|
||||
supervisor.on('PROCESS_STATE_EXITED', function (headers, data) {
|
||||
if (data.expected === '1') return console.error('Normal app %s exit', data.processname);
|
||||
|
||||
console.error('%s exited unexpectedly', data.processname);
|
||||
|
||||
collectLogs(data.processname, function (error, result) {
|
||||
if (error) {
|
||||
console.error('Failed to collect logs.', error);
|
||||
result = util.format('Failed to collect logs.', error);
|
||||
}
|
||||
|
||||
if (!gLastNotifyTime[data.processname] || gLastNotifyTime[data.processname] < Date.now() - gCooldownTime) {
|
||||
console.error('Send mail.');
|
||||
mailer.sendCrashNotification(data.processname, result);
|
||||
gLastNotifyTime[data.processname] = Date.now();
|
||||
} else {
|
||||
console.error('Do not send mail, already sent one recently.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mailer.initialize(function () {
|
||||
supervisor.listen(process.stdin, process.stdout);
|
||||
console.error('Crashnotifier listening...');
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
./node_modules/.bin/apidoc -i src/routes -o docs
|
||||
+153
-93
@@ -2,158 +2,218 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var ejs = require('gulp-ejs'),
|
||||
gulp = require('gulp'),
|
||||
del = require('del'),
|
||||
concat = require('gulp-concat'),
|
||||
uglify = require('gulp-uglify'),
|
||||
serve = require('gulp-serve'),
|
||||
sass = require('gulp-sass'),
|
||||
sourcemaps = require('gulp-sourcemaps'),
|
||||
minifyCSS = require('gulp-minify-css'),
|
||||
var argv = require('yargs').argv,
|
||||
autoprefixer = require('gulp-autoprefixer'),
|
||||
argv = require('yargs').argv;
|
||||
concat = require('gulp-concat'),
|
||||
cssnano = require('gulp-cssnano'),
|
||||
ejs = require('gulp-ejs'),
|
||||
gulp = require('gulp'),
|
||||
rimraf = require('rimraf'),
|
||||
sass = require('gulp-sass'),
|
||||
serve = require('gulp-serve'),
|
||||
sourcemaps = require('gulp-sourcemaps');
|
||||
|
||||
gulp.task('3rdparty', function () {
|
||||
gulp.src([
|
||||
'webadmin/src/3rdparty/**/*.js',
|
||||
'webadmin/src/3rdparty/**/*.map',
|
||||
'webadmin/src/3rdparty/**/*.css',
|
||||
'webadmin/src/3rdparty/**/*.otf',
|
||||
'webadmin/src/3rdparty/**/*.eot',
|
||||
'webadmin/src/3rdparty/**/*.svg',
|
||||
'webadmin/src/3rdparty/**/*.ttf',
|
||||
'webadmin/src/3rdparty/**/*.woff',
|
||||
'webadmin/src/3rdparty/**/*.woff2'
|
||||
])
|
||||
.pipe(gulp.dest('webadmin/dist/3rdparty/'))
|
||||
.pipe(gulp.dest('setup/splash/website/3rdparty'));
|
||||
if (argv.help || argv.h) {
|
||||
console.log('Supported arguments for "gulp develop":');
|
||||
console.log(' --client-id <clientId>');
|
||||
console.log(' --client-secret <clientSecret>');
|
||||
console.log(' --api-origin <cloudron api uri>');
|
||||
console.log(' --revision <revision>');
|
||||
console.log(' --appstore-web-origin <appstore web uri>');
|
||||
console.log(' --appstore-api-origin <appstore api uri>');
|
||||
|
||||
gulp.src('node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js')
|
||||
.pipe(gulp.dest('webadmin/dist/3rdparty/js'))
|
||||
.pipe(gulp.dest('setup/splash/website/3rdparty/js'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var oauth = {
|
||||
clientId: argv.clientId || 'cid-webadmin',
|
||||
clientSecret: argv.clientSecret || 'unused',
|
||||
apiOrigin: argv.apiOrigin || '',
|
||||
};
|
||||
|
||||
var revision = argv.revision || '';
|
||||
|
||||
var appstore = {
|
||||
webOrigin: argv.appstoreWebOrigin || '',
|
||||
apiOrigin: argv.appstoreApiOrigin || ''
|
||||
}
|
||||
|
||||
console.log();
|
||||
console.log('Using OAuth credentials:');
|
||||
console.log(' ClientId: %s', oauth.clientId);
|
||||
console.log(' ClientSecret: %s', oauth.clientSecret);
|
||||
console.log(' Cloudron API: %s', oauth.apiOrigin || 'default');
|
||||
console.log();
|
||||
console.log('Building for revision: %s', revision);
|
||||
console.log();
|
||||
console.log('Overriding appstore origin:');
|
||||
console.log(' Website: %s', appstore.webOrigin || 'no');
|
||||
console.log(' Api: %s', appstore.apiOrigin || 'no');
|
||||
console.log();
|
||||
|
||||
gulp.task('fontawesome', function () {
|
||||
return gulp.src([
|
||||
'node_modules/@fortawesome/fontawesome-free/*css*/all.min.css',
|
||||
'node_modules/@fortawesome/fontawesome-free/*webfonts*/*.eot',
|
||||
'node_modules/@fortawesome/fontawesome-free/*webfonts*/*.svg',
|
||||
'node_modules/@fortawesome/fontawesome-free/*webfonts*/*.ttf',
|
||||
'node_modules/@fortawesome/fontawesome-free/*webfonts*/*.woff',
|
||||
'node_modules/@fortawesome/fontawesome-free/*webfonts*/*.woff2'
|
||||
]).pipe(gulp.dest('dist/3rdparty/fontawesome/'));
|
||||
});
|
||||
|
||||
gulp.task('bootstrap', function () {
|
||||
return gulp.src('node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js')
|
||||
.pipe(gulp.dest('dist/3rdparty/js'));
|
||||
});
|
||||
|
||||
gulp.task('3rdparty-copy', function () {
|
||||
return gulp.src([
|
||||
'src/3rdparty/**/*.js',
|
||||
'src/3rdparty/**/*.map',
|
||||
'src/3rdparty/**/*.css',
|
||||
'src/3rdparty/**/*.otf',
|
||||
'src/3rdparty/**/*.eot',
|
||||
'src/3rdparty/**/*.svg',
|
||||
'src/3rdparty/**/*.gif',
|
||||
'src/3rdparty/**/*.ttf'
|
||||
])
|
||||
.pipe(gulp.dest('dist/3rdparty/'));
|
||||
});
|
||||
|
||||
gulp.task('3rdparty', gulp.series(['3rdparty-copy', 'bootstrap', 'fontawesome']));
|
||||
|
||||
// --------------
|
||||
// JavaScript
|
||||
// --------------
|
||||
|
||||
gulp.task('js', ['js-index', 'js-setup', 'js-update', 'js-error'], function () {});
|
||||
|
||||
var oauth = {
|
||||
clientId: argv.clientId || 'cid-webadmin',
|
||||
clientSecret: argv.clientSecret || 'unused',
|
||||
apiOrigin: argv.apiOrigin || ''
|
||||
};
|
||||
|
||||
console.log();
|
||||
console.log('Using OAuth credentials:');
|
||||
console.log(' ClientId: %s', oauth.clientId);
|
||||
console.log(' ClientSecret: %s', oauth.clientSecret);
|
||||
console.log(' Cloudron API: %s', oauth.apiOrigin || 'default');
|
||||
console.log();
|
||||
|
||||
gulp.task('js-index', function () {
|
||||
gulp.src([
|
||||
'webadmin/src/js/index.js',
|
||||
'webadmin/src/js/client.js',
|
||||
'webadmin/src/js/appstore.js',
|
||||
'webadmin/src/js/main.js',
|
||||
'webadmin/src/views/*.js'
|
||||
return gulp.src([
|
||||
'src/js/index.js',
|
||||
'src/js/client.js',
|
||||
'src/js/main.js',
|
||||
'src/views/*.js'
|
||||
])
|
||||
.pipe(ejs({ oauth: oauth }, { ext: '.js' }))
|
||||
.pipe(ejs({ oauth: oauth, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('index.js', { newLine: ';' }))
|
||||
.pipe(uglify())
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('webadmin/dist/js'));
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-logs', function () {
|
||||
return gulp.src(['src/js/logs.js', 'src/js/client.js'])
|
||||
.pipe(ejs({ oauth: oauth, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('logs.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-terminal', function () {
|
||||
return gulp.src(['src/js/terminal.js', 'src/js/client.js'])
|
||||
.pipe(ejs({ oauth: oauth, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('terminal.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-setup', function () {
|
||||
gulp.src(['webadmin/src/js/setup.js', 'webadmin/src/js/client.js'])
|
||||
.pipe(ejs({ oauth: oauth }, { ext: '.js' }))
|
||||
return gulp.src(['src/js/setup.js', 'src/js/client.js'])
|
||||
.pipe(ejs({ oauth: oauth, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('setup.js', { newLine: ';' }))
|
||||
.pipe(uglify())
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('webadmin/dist/js'));
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-error', function () {
|
||||
gulp.src(['webadmin/src/js/error.js'])
|
||||
gulp.task('js-setupdns', function () {
|
||||
return gulp.src(['src/js/setupdns.js', 'src/js/client.js'])
|
||||
.pipe(ejs({ oauth: oauth, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(uglify())
|
||||
.pipe(concat('setupdns.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('webadmin/dist/js'));
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-update', function () {
|
||||
gulp.src(['webadmin/src/js/update.js'])
|
||||
gulp.task('js-restore', function () {
|
||||
return gulp.src(['src/js/restore.js', 'src/js/client.js'])
|
||||
.pipe(ejs({ oauth: oauth, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(uglify())
|
||||
.pipe(concat('restore.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('webadmin/dist/js'))
|
||||
.pipe(gulp.dest('setup/splash/website/js'));
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js', gulp.series([ 'js-index', 'js-logs', 'js-terminal', 'js-setup', 'js-setupdns', 'js-restore' ]));
|
||||
|
||||
// --------------
|
||||
// HTML
|
||||
// --------------
|
||||
|
||||
gulp.task('html', ['html-views', 'html-update'], function () {
|
||||
return gulp.src('webadmin/src/*.html').pipe(gulp.dest('webadmin/dist'));
|
||||
});
|
||||
|
||||
gulp.task('html-update', function () {
|
||||
return gulp.src(['webadmin/src/update.html']).pipe(gulp.dest('setup/splash/website'));
|
||||
});
|
||||
|
||||
gulp.task('html-views', function () {
|
||||
return gulp.src('webadmin/src/views/**/*.html').pipe(gulp.dest('webadmin/dist/views'));
|
||||
return gulp.src('src/views/**/*.html').pipe(gulp.dest('dist/views'));
|
||||
});
|
||||
|
||||
gulp.task('html-templates', function () {
|
||||
return gulp.src('src/templates/**/*.html').pipe(gulp.dest('dist/templates'));
|
||||
});
|
||||
|
||||
gulp.task('html-raw', function () {
|
||||
return gulp.src('src/*.html').pipe(ejs({ revision: revision }, {}, { ext: '.html' })).pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('html', gulp.series(['html-views', 'html-templates', 'html-raw']));
|
||||
|
||||
// --------------
|
||||
// CSS
|
||||
// --------------
|
||||
|
||||
gulp.task('css', function () {
|
||||
return gulp.src('webadmin/src/*.scss')
|
||||
return gulp.src('src/*.scss')
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(sass({ includePaths: ['node_modules/bootstrap-sass/assets/stylesheets/'] }).on('error', sass.logError))
|
||||
.pipe(autoprefixer())
|
||||
.pipe(minifyCSS())
|
||||
.pipe(cssnano())
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('webadmin/dist'))
|
||||
.pipe(gulp.dest('setup/splash/website'));
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('images', function () {
|
||||
return gulp.src('webadmin/src/img/**')
|
||||
.pipe(gulp.dest('webadmin/dist/img'));
|
||||
return gulp.src('src/img/**')
|
||||
.pipe(gulp.dest('dist/img'));
|
||||
});
|
||||
|
||||
|
||||
// --------------
|
||||
// Utilities
|
||||
// --------------
|
||||
|
||||
gulp.task('watch', ['default'], function () {
|
||||
gulp.watch(['webadmin/src/*.scss'], ['css']);
|
||||
gulp.watch(['webadmin/src/img/*'], ['images']);
|
||||
gulp.watch(['webadmin/src/**/*.html'], ['html']);
|
||||
gulp.watch(['webadmin/src/views/*.html'], ['html-views']);
|
||||
gulp.watch(['webadmin/src/js/update.js'], ['js-update']);
|
||||
gulp.watch(['webadmin/src/js/error.js'], ['js-error']);
|
||||
gulp.watch(['webadmin/src/js/setup.js', 'webadmin/src/js/client.js'], ['js-setup']);
|
||||
gulp.watch(['webadmin/src/js/index.js', 'webadmin/src/js/client.js', 'webadmin/src/js/appstore.js', 'webadmin/src/js/main.js', 'webadmin/src/views/*.js'], ['js-index']);
|
||||
gulp.watch(['webadmin/src/3rdparty/**/*'], ['3rdparty']);
|
||||
gulp.task('clean', function (done) {
|
||||
rimraf.sync('dist');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('clean', function () {
|
||||
del.sync(['webadmin/dist', 'setup/splash/website']);
|
||||
gulp.task('default', gulp.series(['clean', 'html', 'js', '3rdparty', 'images', 'css']));
|
||||
|
||||
gulp.task('watch', function (done) {
|
||||
gulp.watch(['src/*.scss'], gulp.series(['css']));
|
||||
gulp.watch(['src/img/*'], gulp.series(['images']));
|
||||
gulp.watch(['src/**/*.html'], gulp.series(['html']));
|
||||
gulp.watch(['src/views/*.html'], gulp.series(['html-views']));
|
||||
gulp.watch(['src/templates/*.html'], gulp.series(['html-templates']));
|
||||
gulp.watch(['src/js/setup.js', 'src/js/client.js'], gulp.series(['js-setup']));
|
||||
gulp.watch(['src/js/setupdns.js', 'src/js/client.js'], gulp.series(['js-setupdns']));
|
||||
gulp.watch(['src/js/restore.js', 'src/js/client.js'], gulp.series(['js-restore']));
|
||||
gulp.watch(['src/js/logs.js', 'src/js/client.js'], gulp.series(['js-logs']));
|
||||
gulp.watch(['src/js/terminal.js', 'src/js/client.js'], gulp.series(['js-terminal']));
|
||||
gulp.watch(['src/js/index.js', 'src/js/client.js', 'src/js/main.js', 'src/views/*.js'], gulp.series(['js-index']));
|
||||
gulp.watch(['src/3rdparty/**/*'], gulp.series(['3rdparty']));
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('default', ['clean', 'html', 'js', '3rdparty', 'images', 'css'], function () {});
|
||||
gulp.task('serve', serve({ root: 'dist', port: 4000 }));
|
||||
|
||||
gulp.task('develop', gulp.series(['default', 'watch', 'serve']));
|
||||
|
||||
gulp.task('develop', ['watch'], serve({ root: 'webadmin/dist', port: 4000 }));
|
||||
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
require('supererror')({ splatchError: true });
|
||||
|
||||
var assert = require('assert'),
|
||||
debug = require('debug')('box:janitor'),
|
||||
async = require('async'),
|
||||
tokendb = require('./src/tokendb.js'),
|
||||
authcodedb = require('./src/authcodedb.js'),
|
||||
database = require('./src/database.js');
|
||||
|
||||
var TOKEN_CLEANUP_INTERVAL = 30000;
|
||||
|
||||
function initialize(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
async.series([
|
||||
database.initialize
|
||||
], callback);
|
||||
}
|
||||
|
||||
function cleanupExpiredTokens(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
tokendb.delExpired(function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
debug('Cleaned up %s expired tokens.', result);
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupExpiredAuthCodes(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
authcodedb.delExpired(function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
debug('Cleaned up %s expired authcodes.', result);
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function run() {
|
||||
cleanupExpiredTokens(function (error) {
|
||||
if (error) console.error(error);
|
||||
|
||||
cleanupExpiredAuthCodes(function (error) {
|
||||
if (error) console.error(error);
|
||||
|
||||
setTimeout(run, TOKEN_CLEANUP_INTERVAL);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
initialize(function (error) {
|
||||
if (error) {
|
||||
console.error('janitor task exiting with error', error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
run();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
var dbm = require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
var url = require('url');
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
var dbName = url.parse(process.env.DATABASE_URL).path.substr(1); // remove slash
|
||||
|
||||
// by default, mysql collates case insensitively. 'utf8_general_cs' is not available
|
||||
db.runSql('ALTER DATABASE ' + dbName + ' DEFAULT CHARACTER SET=utf8 DEFAULT COLLATE utf8_bin', callback);
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
callback();
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
var dbm = require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
var fs = require('fs'),
|
||||
async = require('async'),
|
||||
path = require('path');
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
var schema = fs.readFileSync(path.join(__dirname, 'initial-schema.sql')).toString('utf8');
|
||||
var statements = schema.split(';');
|
||||
async.eachSeries(statements, function (statement, callback) {
|
||||
if (statement.trim().length === 0) return callback(null);
|
||||
db.runSql(statement, callback);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('DROP TABLE users, tokens, clients, apps, appPortBindings, authcodes, settings', callback);
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE users ADD COLUMN resetToken VARCHAR(128) DEFAULT ""', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE users DROP COLUMN resetToken', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('DELETE FROM tokens', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
|
||||
db.runSql('ALTER TABLE tokens MODIFY expires BIGINT', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE tokens MODIFY expires VARCHAR(512)', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE authcodes ADD COLUMN expiresAt BIGINT NOT NULL', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE authcodes DROP COLUMN expiresAt', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE appPortBindings ADD COLUMN environmentVariable VARCHAR(128) NOT NULL', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE appPortBindings DROP COLUMN environmentVariable', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE appPortBindings DROP COLUMN containerPort', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE appPortBindings ADD COLUMN containerPort VARCHAR(5) NOT NULL', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('DELETE FROM tokens', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
|
||||
db.runSql('ALTER TABLE tokens CHANGE userId identifier VARCHAR(128) NOT NULL', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE tokens CHANGE identifier userId VARCHAR(128) NOT NULL', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps DROP COLUMN version', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps ADD COLUMN version VARCHAR(32)', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps DROP COLUMN healthy, ADD COLUMN health VARCHAR(128)', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps DROP COLUMN health, ADD COLUMN healthy INTEGER', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps ADD COLUMN lastBackupId VARCHAR(128)', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps DROP COLUMN lastBackupId', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps ADD COLUMN createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps DROP COLUMN createdAt', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
// everyday at 1am
|
||||
db.runSql('INSERT settings (name, value) VALUES("autoupdate_pattern", ?)', [ '00 00 1 * * *' ], callback);
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('DELETE * FROM settings WHERE name="autoupdate_pattern"', [ ], callback);
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var safe = require('safetydance');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
var tz = safe.fs.readFileSync('/etc/timezone', 'utf8');
|
||||
tz = tz ? tz.trim() : 'America/Los_Angeles';
|
||||
|
||||
db.runSql('INSERT settings (name, value) VALUES("time_zone", ?)', [ tz ], callback);
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('DELETE * FROM settings WHERE name="time_zone"', [ ], callback);
|
||||
};
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
var async = require('async');
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
|
||||
// http://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address
|
||||
|
||||
async.series([
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(254)'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users ADD CONSTRAINT users_username UNIQUE (username)'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(254)'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users ADD CONSTRAINT users_email UNIQUE (email)'),
|
||||
], callback);
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
async.series([
|
||||
db.runSql.bind(db, 'ALTER TABLE users DROP INDEX users_username'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(512)'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users DROP INDEX users_email'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(512)'),
|
||||
], callback);
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
var async = require('async');
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
async.series([
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(254) NOT NULL'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(254) NOT NULL'),
|
||||
], callback);
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
async.series([
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(254)'),
|
||||
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(254)'),
|
||||
], callback);
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps ADD COLUMN lastManifestJson VARCHAR(2048)', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps DROP COLUMN lastManifestJson', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
var dbm = global.dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps CHANGE lastManifestJson lastBackupConfigJson VARCHAR(2048)', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps CHANGE lastBackupConfigJson lastManifestJson VARCHAR(2048)', [], function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
dbm = dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps ADD COLUMN oldConfigJson VARCHAR(2048)', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
db.runSql('ALTER TABLE apps DROP COLUMN oldConfigJson', function (error) {
|
||||
if (error) console.error(error);
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
var dbm = global.dbm || require('db-migrate');
|
||||
var type = dbm.dataType;
|
||||
|
||||
exports.up = function(db, callback) {
|
||||
db.runSql('DELETE FROM settings', [ ], callback);
|
||||
};
|
||||
|
||||
exports.down = function(db, callback) {
|
||||
callback();
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS users(
|
||||
id VARCHAR(128) NOT NULL UNIQUE,
|
||||
username VARCHAR(512) NOT NULL,
|
||||
email VARCHAR(512) NOT NULL,
|
||||
password VARCHAR(1024) NOT NULL,
|
||||
salt VARCHAR(512) NOT NULL,
|
||||
createdAt VARCHAR(512) NOT NULL,
|
||||
modifiedAt VARCHAR(512) NOT NULL,
|
||||
admin INTEGER NOT NULL,
|
||||
PRIMARY KEY(id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tokens(
|
||||
accessToken VARCHAR(128) NOT NULL UNIQUE,
|
||||
userId VARCHAR(128) NOT NULL,
|
||||
clientId VARCHAR(128),
|
||||
scope VARCHAR(512) NOT NULL,
|
||||
expires VARCHAR(512) NOT NULL,
|
||||
PRIMARY KEY(accessToken));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS clients(
|
||||
id VARCHAR(128) NOT NULL UNIQUE,
|
||||
appId VARCHAR(128) NOT NULL,
|
||||
clientSecret VARCHAR(512) NOT NULL,
|
||||
redirectURI VARCHAR(512) NOT NULL,
|
||||
scope VARCHAR(512) NOT NULL,
|
||||
PRIMARY KEY(id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS apps(
|
||||
id VARCHAR(128) NOT NULL UNIQUE,
|
||||
appStoreId VARCHAR(128) NOT NULL,
|
||||
version VARCHAR(32),
|
||||
installationState VARCHAR(512) NOT NULL,
|
||||
installationProgress VARCHAR(512),
|
||||
runState VARCHAR(512),
|
||||
healthy INTEGER,
|
||||
containerId VARCHAR(128),
|
||||
manifestJson VARCHAR(2048),
|
||||
httpPort INTEGER,
|
||||
location VARCHAR(128) NOT NULL UNIQUE,
|
||||
dnsRecordId VARCHAR(512),
|
||||
accessRestriction VARCHAR(512),
|
||||
PRIMARY KEY(id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS appPortBindings(
|
||||
hostPort INTEGER NOT NULL UNIQUE,
|
||||
containerPort VARCHAR(5) NOT NULL,
|
||||
appId VARCHAR(128) NOT NULL,
|
||||
FOREIGN KEY(appId) REFERENCES apps(id),
|
||||
PRIMARY KEY(hostPort));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS authcodes(
|
||||
authCode VARCHAR(128) NOT NULL UNIQUE,
|
||||
userId VARCHAR(128) NOT NULL,
|
||||
clientId VARCHAR(128) NOT NULL,
|
||||
PRIMARY KEY(authCode));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS settings(
|
||||
name VARCHAR(128) NOT NULL UNIQUE,
|
||||
value VARCHAR(512),
|
||||
PRIMARY KEY(name));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS appAddonConfigs(
|
||||
appId VARCHAR(128) NOT NULL,
|
||||
addonId VARCHAR(32) NOT NULL,
|
||||
value VARCHAR(512) NOT NULL,
|
||||
FOREIGN KEY(appId) REFERENCES apps(id));
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#### WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
#### This file is not used by any code and is here to document the latest schema
|
||||
|
||||
#### General ideas
|
||||
#### Default char set is utf8 and DEFAULT COLLATE is utf8_bin. Collate affects comparisons in WHERE and ORDER
|
||||
#### Strict mode is enabled
|
||||
#### VARCHAR - stored as part of table row (use for strings)
|
||||
#### TEXT - stored offline from table row (use for strings)
|
||||
#### BLOB - stored offline from table row (use for binary data)
|
||||
#### https://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users(
|
||||
id VARCHAR(128) NOT NULL UNIQUE,
|
||||
username VARCHAR(254) NOT NULL UNIQUE,
|
||||
email VARCHAR(254) NOT NULL UNIQUE,
|
||||
password VARCHAR(1024) NOT NULL,
|
||||
salt VARCHAR(512) NOT NULL,
|
||||
createdAt VARCHAR(512) NOT NULL,
|
||||
modifiedAt VARCHAR(512) NOT NULL,
|
||||
admin INTEGER NOT NULL,
|
||||
PRIMARY KEY(id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tokens(
|
||||
accessToken VARCHAR(128) NOT NULL UNIQUE,
|
||||
identifier VARCHAR(128) NOT NULL,
|
||||
clientId VARCHAR(128),
|
||||
scope VARCHAR(512) NOT NULL,
|
||||
expires BIGINT NOT NULL,
|
||||
PRIMARY KEY(accessToken));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS clients(
|
||||
id VARCHAR(128) NOT NULL UNIQUE,
|
||||
appId VARCHAR(128) NOT NULL,
|
||||
clientSecret VARCHAR(512) NOT NULL,
|
||||
redirectURI VARCHAR(512) NOT NULL,
|
||||
scope VARCHAR(512) NOT NULL,
|
||||
PRIMARY KEY(id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS apps(
|
||||
id VARCHAR(128) NOT NULL UNIQUE,
|
||||
appStoreId VARCHAR(128) NOT NULL,
|
||||
installationState VARCHAR(512) NOT NULL,
|
||||
installationProgress VARCHAR(512),
|
||||
runState VARCHAR(512),
|
||||
health VARCHAR(128),
|
||||
containerId VARCHAR(128),
|
||||
manifestJson VARCHAR(2048),
|
||||
httpPort INTEGER, // this is the nginx proxy port and not manifest.httpPort
|
||||
location VARCHAR(128) NOT NULL UNIQUE,
|
||||
dnsRecordId VARCHAR(512),
|
||||
accessRestriction VARCHAR(512),
|
||||
createdAt TIMESTAMP(2) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
lastBackupId VARCHAR(128),
|
||||
lastBackupConfigJson VARCHAR(2048), // used for appstore and non-appstore installs. it's here so it's easy to do REST validation
|
||||
PRIMARY KEY(id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS appPortBindings(
|
||||
hostPort INTEGER NOT NULL UNIQUE,
|
||||
environmentVariable VARCHAR(128) NOT NULL,
|
||||
appId VARCHAR(128) NOT NULL,
|
||||
FOREIGN KEY(appId) REFERENCES apps(id),
|
||||
PRIMARY KEY(hostPort));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS authcodes(
|
||||
authCode VARCHAR(128) NOT NULL UNIQUE,
|
||||
userId VARCHAR(128) NOT NULL,
|
||||
clientId VARCHAR(128) NOT NULL,
|
||||
expiresAt BIGINT NOT NULL,
|
||||
PRIMARY KEY(authCode));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS settings(
|
||||
name VARCHAR(128) NOT NULL UNIQUE,
|
||||
value VARCHAR(512),
|
||||
PRIMARY KEY(name));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS appAddonConfigs(
|
||||
appId VARCHAR(128) NOT NULL,
|
||||
addonId VARCHAR(32) NOT NULL,
|
||||
value VARCHAR(512) NOT NULL,
|
||||
FOREIGN KEY(appId) REFERENCES apps(id));
|
||||
|
||||
Generated
-2447
File diff suppressed because it is too large
Load Diff
-185
@@ -1,185 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
require('supererror')({ splatchError: true });
|
||||
|
||||
var express = require('express'),
|
||||
url = require('url'),
|
||||
uuid = require('node-uuid'),
|
||||
async = require('async'),
|
||||
superagent = require('superagent'),
|
||||
assert = require('assert'),
|
||||
debug = require('debug')('box:proxy'),
|
||||
proxy = require('proxy-middleware'),
|
||||
session = require('cookie-session'),
|
||||
database = require('./src/database.js'),
|
||||
appdb = require('./src/appdb.js'),
|
||||
clientdb = require('./src/clientdb.js'),
|
||||
config = require('./src/config.js'),
|
||||
http = require('http');
|
||||
|
||||
// Allow self signed certs!
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
|
||||
var gSessions = {};
|
||||
var gProxyMiddlewareCache = {};
|
||||
var gApp = express();
|
||||
var gHttpServer = http.createServer(gApp);
|
||||
|
||||
var CALLBACK_URI = '/callback';
|
||||
var PORT = 4000;
|
||||
|
||||
function startServer(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
gHttpServer.on('error', console.error);
|
||||
|
||||
gApp.use(session({
|
||||
keys: ['blue', 'cheese', 'is', 'something']
|
||||
}));
|
||||
|
||||
// ensure we have a in memory store for the session to cache client information
|
||||
gApp.use(function (req, res, next) {
|
||||
assert.strictEqual(typeof req.session, 'object');
|
||||
|
||||
if (!req.session.id || !gSessions[req.session.id]) {
|
||||
req.session.id = uuid.v4();
|
||||
gSessions[req.session.id] = {};
|
||||
}
|
||||
|
||||
// attach the session data to the requeset
|
||||
req.sessionData = gSessions[req.session.id];
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
gApp.use(function verifySession(req, res, next) {
|
||||
assert.strictEqual(typeof req.sessionData, 'object');
|
||||
|
||||
if (!req.sessionData.accessToken) {
|
||||
req.authenticated = false;
|
||||
return next();
|
||||
}
|
||||
|
||||
superagent.get(config.adminOrigin() + '/api/v1/profile').query({ access_token: req.sessionData.accessToken}).end(function (error, result) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
req.authenticated = false;
|
||||
} else if (result.statusCode !== 200) {
|
||||
req.sessionData.accessToken = null;
|
||||
req.authenticated = false;
|
||||
} else {
|
||||
req.authenticated = true;
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
gApp.use(function (req, res, next) {
|
||||
// proceed if we are authenticated
|
||||
if (req.authenticated) return next();
|
||||
|
||||
if (req.path === CALLBACK_URI && req.sessionData.returnTo) {
|
||||
// exchange auth code for an access token
|
||||
var query = {
|
||||
response_type: 'token',
|
||||
client_id: req.sessionData.clientId
|
||||
};
|
||||
|
||||
var data = {
|
||||
grant_type: 'authorization_code',
|
||||
code: req.query.code,
|
||||
redirect_uri: req.sessionData.returnTo,
|
||||
client_id: req.sessionData.clientId,
|
||||
client_secret: req.sessionData.clientSecret
|
||||
};
|
||||
|
||||
superagent.post(config.adminOrigin() + '/api/v1/oauth/token').query(query).send(data).end(function (error, result) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return res.send(500, 'Unable to contact the oauth server.');
|
||||
}
|
||||
if (result.statusCode !== 200) {
|
||||
console.error('Failed to exchange auth code for a token.', result.statusCode, result.body);
|
||||
return res.send(500, 'Failed to exchange auth code for a token.');
|
||||
}
|
||||
|
||||
req.sessionData.accessToken = result.body.access_token;
|
||||
|
||||
debug('user verified.');
|
||||
|
||||
// now redirect to the actual initially requested URL
|
||||
res.redirect(req.sessionData.returnTo);
|
||||
});
|
||||
} else {
|
||||
var port = parseInt(req.headers['x-cloudron-proxy-port'], 10);
|
||||
|
||||
if (!Number.isFinite(port)) {
|
||||
console.error('Failed to parse nginx proxy header to get app port.');
|
||||
return res.send(500, 'Routing error. No forwarded port.');
|
||||
}
|
||||
|
||||
debug('begin verifying user for app on port %s.', port);
|
||||
|
||||
appdb.getByHttpPort(port, function (error, result) {
|
||||
if (error) {
|
||||
console.error('Unknown app.', error);
|
||||
return res.send(500, 'Unknown app.');
|
||||
}
|
||||
|
||||
clientdb.getByAppId('proxy-' + result.id, function (error, result) {
|
||||
if (error) {
|
||||
console.error('Unkonwn OAuth client.', error);
|
||||
return res.send(500, 'Unknown OAuth client.');
|
||||
}
|
||||
|
||||
req.sessionData.port = port;
|
||||
req.sessionData.returnTo = result.redirectURI + req.path;
|
||||
req.sessionData.clientId = result.id;
|
||||
req.sessionData.clientSecret = result.clientSecret;
|
||||
|
||||
var callbackUrl = result.redirectURI + CALLBACK_URI;
|
||||
var scope = 'profile,roleUser';
|
||||
var oauthLogin = config.adminOrigin() + '/api/v1/oauth/dialog/authorize?response_type=code&client_id=' + result.id + '&redirect_uri=' + callbackUrl + '&scope=' + scope;
|
||||
|
||||
debug('begin OAuth flow for client %s.', result.name);
|
||||
|
||||
// begin the OAuth flow
|
||||
res.redirect(oauthLogin);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
gApp.use(function (req, res, next) {
|
||||
var port = req.sessionData.port;
|
||||
|
||||
debug('proxy request for port %s with path %s.', port, req.path);
|
||||
|
||||
var proxyMiddleware = gProxyMiddlewareCache[port];
|
||||
if (!proxyMiddleware) {
|
||||
console.log('Adding proxy middleware for port %d', port);
|
||||
|
||||
proxyMiddleware = proxy(url.parse('http://127.0.0.1:' + port));
|
||||
gProxyMiddlewareCache[port] = proxyMiddleware;
|
||||
}
|
||||
|
||||
proxyMiddleware(req, res, next);
|
||||
});
|
||||
|
||||
gHttpServer.listen(PORT, callback);
|
||||
}
|
||||
|
||||
async.series([
|
||||
database.initialize,
|
||||
startServer
|
||||
], function (error) {
|
||||
if (error) {
|
||||
console.error('Failed to start proxy server.', error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('Proxy server listening...');
|
||||
});
|
||||
Generated
+7008
File diff suppressed because it is too large
Load Diff
+25
-94
@@ -1,102 +1,33 @@
|
||||
{
|
||||
"name": "Cloudron",
|
||||
"description": "Main code for a cloudron",
|
||||
"version": "0.0.1",
|
||||
"private": "true",
|
||||
"author": {
|
||||
"name": "Cloudron authors"
|
||||
"name": "dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "[Cloudron](https://cloudron.io) is the best way to run apps on your server.",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git"
|
||||
},
|
||||
"engines": [
|
||||
"node >= 0.12.0"
|
||||
],
|
||||
"bin": {
|
||||
"cloudron": "./app.js"
|
||||
"type": "git",
|
||||
"url": "ssh://git@git.cloudron.io:6000/cloudron/dashboard.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"dependencies": {
|
||||
"async": "^1.2.1",
|
||||
"body-parser": "^1.13.1",
|
||||
"cloudron-manifestformat": "^1.6.0",
|
||||
"connect-ensure-login": "^0.1.1",
|
||||
"connect-lastmile": "0.0.13",
|
||||
"connect-timeout": "^1.5.0",
|
||||
"cookie-parser": "^1.3.5",
|
||||
"cookie-session": "^1.1.0",
|
||||
"cron": "^1.0.9",
|
||||
"csurf": "^1.6.6",
|
||||
"db-migrate": "^0.9.2",
|
||||
"debug": "^2.2.0",
|
||||
"dockerode": "^2.2.2",
|
||||
"ejs": "^2.2.4",
|
||||
"ejs-cli": "^1.0.1",
|
||||
"express": "^4.12.4",
|
||||
"express-session": "^1.11.3",
|
||||
"hat": "0.0.3",
|
||||
"json": "^9.0.3",
|
||||
"ldapjs": "^0.7.1",
|
||||
"memorystream": "^0.3.0",
|
||||
"mime": "^1.3.4",
|
||||
"morgan": "^1.6.0",
|
||||
"multiparty": "^4.1.2",
|
||||
"mysql": "^2.7.0",
|
||||
"native-dns": "^0.7.0",
|
||||
"node-uuid": "^1.4.3",
|
||||
"nodemailer": "^1.3.0",
|
||||
"nodemailer-smtp-transport": "^1.0.3",
|
||||
"oauth2orize": "^1.0.1",
|
||||
"once": "^1.3.2",
|
||||
"passport": "^0.2.2",
|
||||
"passport-http": "^0.2.2",
|
||||
"passport-http-bearer": "^1.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-oauth2-client-password": "^0.1.2",
|
||||
"password-generator": "^1.0.0",
|
||||
"proxy-middleware": "^0.13.0",
|
||||
"safetydance": "0.0.19",
|
||||
"semver": "^4.3.6",
|
||||
"serve-favicon": "^2.2.0",
|
||||
"split": "^1.0.0",
|
||||
"superagent": "~0.21.0",
|
||||
"supererror": "^0.7.0",
|
||||
"supervisord-eventlistener": "^0.1.0",
|
||||
"tail-stream": "https://registry.npmjs.org/tail-stream/-/tail-stream-0.2.1.tgz",
|
||||
"underscore": "^1.7.0",
|
||||
"valid-url": "^1.0.9",
|
||||
"validator": "^3.30.0"
|
||||
"@fortawesome/fontawesome-free": "^5.5.0",
|
||||
"bootstrap-sass": "^3.4.1",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-autoprefixer": "^5.0.0",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-cssnano": "^2.1.3",
|
||||
"gulp-ejs": "^3.3.0",
|
||||
"gulp-sass": "^4.0.2",
|
||||
"gulp-serve": "^1.4.0",
|
||||
"gulp-sourcemaps": "^2.6.5",
|
||||
"rimraf": "^2.6.2",
|
||||
"yargs": "^11.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"apidoc": "*",
|
||||
"aws-sdk": "^2.1.10",
|
||||
"bootstrap-sass": "^3.3.3",
|
||||
"del": "^1.1.1",
|
||||
"expect.js": "*",
|
||||
"gulp": "^3.8.11",
|
||||
"gulp-autoprefixer": "^2.3.0",
|
||||
"gulp-concat": "^2.4.3",
|
||||
"gulp-ejs": "^1.0.0",
|
||||
"gulp-minify-css": "^1.1.3",
|
||||
"gulp-sass": "^2.0.1",
|
||||
"gulp-serve": "^1.0.0",
|
||||
"gulp-sourcemaps": "^1.5.2",
|
||||
"gulp-uglify": "^1.1.0",
|
||||
"hock": "~1.2.0",
|
||||
"istanbul": "*",
|
||||
"mocha": "*",
|
||||
"nock": "^2.6.0",
|
||||
"node-sass": "^3.0.0-alpha.0",
|
||||
"redis": "^0.12.1",
|
||||
"sinon": "^1.12.2",
|
||||
"yargs": "^3.15.0"
|
||||
},
|
||||
"scripts": {
|
||||
"migrate_local": "DATABASE_URL=mysql://root:@localhost/box node_modules/.bin/db-migrate up",
|
||||
"migrate_test": "BOX_ENV=test DATABASE_URL=mysql://root:@localhost/boxtest node_modules/.bin/db-migrate up",
|
||||
"test": "npm run migrate_test && src/test/setupTest && BOX_ENV=test ./node_modules/istanbul/lib/cli.js test $1 ./node_modules/mocha/bin/_mocha -- -R spec ./src/test ./src/routes/test",
|
||||
"postmerge": "/bin/true",
|
||||
"precommit": "/bin/true",
|
||||
"prepush": "npm test",
|
||||
"webadmin": "node_modules/.bin/gulp"
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
"browser": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
This document gives the design of this setup code.
|
||||
|
||||
box code should be delivered in the form of a (docker) container.
|
||||
This is not the case currently but we want to do structure the code
|
||||
in spirit that way.
|
||||
|
||||
### container.sh
|
||||
This contains code that essential goes into Dockerfile.
|
||||
|
||||
This file contains static configuration over a base image. Currently,
|
||||
the yellowtent user is created in the installer base image but it
|
||||
could very well be placed here.
|
||||
|
||||
The idea is that the installer would simply remove the old box container
|
||||
and replace it with a new one for an update.
|
||||
|
||||
Because we do not package things as Docker yet, we should be careful
|
||||
about the code here. We have to expect remains of an older setup code.
|
||||
For example, older supervisor or nginx configs might be around.
|
||||
|
||||
The config directory is _part_ of the container and is not a VOLUME.
|
||||
Which is to say that the files will be nuked from one update to the next.
|
||||
|
||||
The data directory is a VOLUME. Contents of this directory are expected
|
||||
to survive an update. This is a good place to place config files that
|
||||
are "dynamic" and need to survive restarts. For example, the infra
|
||||
version (see below) or the mysql/postgresql data etc.
|
||||
|
||||
### start.sh
|
||||
* It is called in 3 modes - new, update, restore.
|
||||
|
||||
* The first thing this does is to do the static container.sh setup.
|
||||
|
||||
* It then downloads any box restore data and restores the box db from the
|
||||
backup.
|
||||
|
||||
* It then proceeds to call the db-migrate script.
|
||||
|
||||
* It then does dynamic configuration like setting up nginx, collectd.
|
||||
|
||||
* It then setups up the cloud infra (setup_infra.sh) and creates cloudron.conf.
|
||||
|
||||
* supervisor is then started
|
||||
|
||||
setup_infra.sh
|
||||
This setups containers like graphite, mail and the addons containers.
|
||||
|
||||
Containers are relaunched based on the INFRA_VERSION. The script compares
|
||||
the version here with the version in the file DATA_DIR/INFRA_VERSION.
|
||||
|
||||
If they match, the containers are not recreated and nothing is to be done.
|
||||
nginx, collectd configs are part of data already and containers are running.
|
||||
|
||||
If they do not match, it deletes all containers (including app containers) and starts
|
||||
them all afresh. Important thing here is that, DATA_DIR is never removed across
|
||||
updates. So, it is only the containers being recreated and not the data.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# If you change the infra version, be sure to put a warning
|
||||
# in the change log
|
||||
|
||||
INFRA_VERSION=8
|
||||
|
||||
# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
# These constants are used in the installer script as well
|
||||
BASE_IMAGE=cloudron/base:0.3.1
|
||||
MYSQL_IMAGE=cloudron/mysql:0.3.2
|
||||
POSTGRESQL_IMAGE=cloudron/postgresql:0.3.1
|
||||
MONGODB_IMAGE=cloudron/mongodb:0.3.1
|
||||
REDIS_IMAGE=cloudron/redis:0.3.1 # if you change this, fix src/addons.js as well
|
||||
MAIL_IMAGE=cloudron/mail:0.3.1
|
||||
GRAPHITE_IMAGE=cloudron/graphite:0.3.3
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
json="${script_dir}/../node_modules/.bin/json"
|
||||
|
||||
# IMPORTANT: Fix cloudron.js:doUpdate if you add/remove any arg. keep these sorted for readability
|
||||
arg_api_server_origin=""
|
||||
arg_box_versions_url=""
|
||||
arg_fqdn=""
|
||||
arg_is_custom_domain="false"
|
||||
arg_restore_key=""
|
||||
arg_restore_url=""
|
||||
arg_retire="false"
|
||||
arg_tls_cert=""
|
||||
arg_tls_key=""
|
||||
arg_token=""
|
||||
arg_version=""
|
||||
arg_web_server_origin=""
|
||||
|
||||
args=$(getopt -o "" -l "data:,retire" -n "$0" -- "$@")
|
||||
eval set -- "${args}"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
--retire)
|
||||
arg_retire="true"
|
||||
shift
|
||||
;;
|
||||
--data)
|
||||
# only read mandatory non-empty parameters here
|
||||
read -r arg_api_server_origin arg_web_server_origin arg_fqdn arg_token arg_is_custom_domain arg_box_versions_url arg_version <<EOF
|
||||
$(echo "$2" | $json apiServerOrigin webServerOrigin fqdn token isCustomDomain boxVersionsUrl version | tr '\n' ' ')
|
||||
EOF
|
||||
# read possibly empty parameters here
|
||||
arg_tls_cert=$(echo "$2" | $json tlsCert)
|
||||
arg_tls_key=$(echo "$2" | $json tlsKey)
|
||||
|
||||
arg_restore_url=$(echo "$2" | $json restoreUrl)
|
||||
[[ "${arg_restore_url}" == "null" ]] && arg_restore_url=""
|
||||
|
||||
arg_restore_key=$(echo "$2" | $json restoreKey)
|
||||
[[ "${arg_restore_key}" == "null" ]] && arg_restore_key=""
|
||||
|
||||
shift 2
|
||||
;;
|
||||
--) break;;
|
||||
*) echo "Unknown option $1"; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Parsed arguments:"
|
||||
echo "api server: ${arg_api_server_origin}"
|
||||
echo "box versions url: ${arg_box_versions_url}"
|
||||
echo "fqdn: ${arg_fqdn}"
|
||||
echo "custom domain: ${arg_is_custom_domain}"
|
||||
echo "restore key: ${arg_restore_key}"
|
||||
echo "restore url: ${arg_restore_url}"
|
||||
echo "tls cert: ${arg_tls_cert}"
|
||||
echo "tls key: ${arg_tls_key}"
|
||||
echo "token: ${arg_token}"
|
||||
echo "version: ${arg_version}"
|
||||
echo "web server: ${arg_web_server_origin}"
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
# This file can be used in Dockerfile
|
||||
|
||||
readonly container_files="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/container"
|
||||
|
||||
readonly CONFIG_DIR="/home/yellowtent/configs"
|
||||
readonly DATA_DIR="/home/yellowtent/data"
|
||||
|
||||
########## create config directory
|
||||
rm -rf "${CONFIG_DIR}"
|
||||
sudo -u yellowtent mkdir "${CONFIG_DIR}"
|
||||
|
||||
########## logrotate (default ubuntu runs this daily)
|
||||
rm -rf /etc/logrotate.d/*
|
||||
cp -r "${container_files}/logrotate/." /etc/logrotate.d/
|
||||
|
||||
########## supervisor
|
||||
rm -rf /etc/supervisor/*
|
||||
cp -r "${container_files}/supervisor/." /etc/supervisor/
|
||||
|
||||
########## sudoers
|
||||
rm /etc/sudoers.d/*
|
||||
cp "${container_files}/sudoers" /etc/sudoers.d/yellowtent
|
||||
|
||||
########## collectd
|
||||
rm -rf /etc/collectd
|
||||
ln -sfF "${DATA_DIR}/collectd" /etc/collectd
|
||||
|
||||
########## nginx
|
||||
# link nginx config to system config
|
||||
unlink /etc/nginx 2>/dev/null || rm -rf /etc/nginx
|
||||
ln -s "${DATA_DIR}/nginx" /etc/nginx
|
||||
|
||||
########## mysql
|
||||
cp "${container_files}/mysql.cnf" /etc/mysql/mysql.cnf
|
||||
|
||||
########## Enable services
|
||||
update-rc.d -f collectd defaults
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/var/log/cloudron/*log {
|
||||
missingok
|
||||
notifempty
|
||||
size 100k
|
||||
nocompress
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
/var/log/supervisor/*log {
|
||||
missingok
|
||||
copytruncate
|
||||
notifempty
|
||||
size 100k
|
||||
nocompress
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
!includedir /etc/mysql/conf.d/
|
||||
!includedir /etc/mysql/mysql.conf.d/
|
||||
|
||||
# http://bugs.mysql.com/bug.php?id=68514
|
||||
[mysqld]
|
||||
performance_schema=OFF
|
||||
max_connection=50
|
||||
@@ -1,29 +0,0 @@
|
||||
Defaults!/home/yellowtent/box/src/scripts/createappdir.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/createappdir.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/rmappdir.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/rmappdir.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/reloadnginx.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/reloadnginx.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/backupbox.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/backupbox.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/backupapp.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/backupapp.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/restoreapp.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/restoreapp.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/reboot.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/reboot.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/reloadcollectd.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/reloadcollectd.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/backupswap.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/backupswap.sh
|
||||
|
||||
Defaults!/home/yellowtent/box/src/scripts/collectlogs.sh env_keep="HOME BOX_ENV"
|
||||
yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/collectlogs.sh
|
||||
@@ -1,10 +0,0 @@
|
||||
[program:apphealthtask]
|
||||
command=/usr/bin/node "/home/yellowtent/box/apphealthtask.js"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/log/supervisor/apphealthtask.log
|
||||
stdout_logfile_maxbytes=50MB
|
||||
stdout_logfile_backups=2
|
||||
user=yellowtent
|
||||
environment=HOME="/home/yellowtent",USER="yellowtent",DEBUG="box*",BOX_ENV="cloudron",NODE_ENV="production"
|
||||
@@ -1,10 +0,0 @@
|
||||
[program:box]
|
||||
command=/usr/bin/node "/home/yellowtent/box/app.js"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/log/supervisor/box.log
|
||||
stdout_logfile_maxbytes=50MB
|
||||
stdout_logfile_backups=2
|
||||
user=yellowtent
|
||||
environment=HOME="/home/yellowtent",USER="yellowtent",DEBUG="box*,connect-lastmile",BOX_ENV="cloudron",NODE_ENV="production"
|
||||
@@ -1,11 +0,0 @@
|
||||
[eventlistener:crashnotifier]
|
||||
command=/usr/bin/node "/home/yellowtent/box/crashnotifier.js"
|
||||
events=PROCESS_STATE
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=false
|
||||
stderr_logfile=/var/log/supervisor/crashnotifier.log
|
||||
stderr_logfile_maxbytes=50MB
|
||||
stderr_logfile_backups=2
|
||||
user=yellowtent
|
||||
environment=HOME="/home/yellowtent",USER="yellowtent",BOX_ENV="cloudron",NODE_ENV="production"
|
||||
@@ -1,10 +0,0 @@
|
||||
[program:janitor]
|
||||
command=/usr/bin/node "/home/yellowtent/box/janitor.js"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/log/supervisor/janitor.log
|
||||
stdout_logfile_maxbytes=50MB
|
||||
stdout_logfile_backups=2
|
||||
user=yellowtent
|
||||
environment=HOME="/home/yellowtent",USER="yellowtent",DEBUG="box*",BOX_ENV="cloudron",NODE_ENV="production"
|
||||
@@ -1,10 +0,0 @@
|
||||
[program:oauthproxy]
|
||||
command=/usr/bin/node "/home/yellowtent/box/oauthproxy.js"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/log/supervisor/oauthproxy.log
|
||||
stdout_logfile_maxbytes=50MB
|
||||
stdout_logfile_backups=2
|
||||
user=yellowtent
|
||||
environment=HOME="/home/yellowtent",USER="yellowtent",DEBUG="box*",BOX_ENV="cloudron",NODE_ENV="production"
|
||||
@@ -1,33 +0,0 @@
|
||||
; supervisor config file
|
||||
|
||||
; http://coffeeonthekeyboard.com/using-supervisorctl-with-linux-permissions-but-without-root-or-sudo-977/
|
||||
[inet_http_server]
|
||||
port = 127.0.0.1:9001
|
||||
|
||||
[supervisord]
|
||||
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
|
||||
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
|
||||
logfile_maxbytes = 50MB
|
||||
logfile_backups=10
|
||||
loglevel = info
|
||||
nodaemon = false
|
||||
childlogdir = /var/log/supervisor/
|
||||
|
||||
; the below section must remain in the config file for RPC
|
||||
; (supervisorctl/web interface) to work, additional interfaces may be
|
||||
; added by defining them in separate rpcinterface: sections
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=http://127.0.0.1:9001
|
||||
|
||||
; The [include] section can just contain the "files" setting. This
|
||||
; setting can list multiple files (separated by whitespace or
|
||||
; newlines). It can also contain wildcards. The filenames are
|
||||
; interpreted as relative to this file. Included files *cannot*
|
||||
; include files themselves.
|
||||
|
||||
[include]
|
||||
files = conf.d/*.conf
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
readonly SETUP_WEBSITE_DIR="/home/yellowtent/setup/website"
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
readonly BOX_SRC_DIR="/home/yellowtent/box"
|
||||
readonly DATA_DIR="/home/yellowtent/data"
|
||||
readonly ADMIN_LOCATION="my" # keep this in sync with constants.js
|
||||
|
||||
source "${script_dir}/INFRA_VERSION" # this injects INFRA_VERSION
|
||||
|
||||
echo "Setting up nginx update page"
|
||||
|
||||
source "${script_dir}/argparser.sh" "$@" # this injects the arg_* variables used below
|
||||
|
||||
# keep this is sync with config.js appFqdn()
|
||||
admin_fqdn=$([[ "${arg_is_custom_domain}" == "true" ]] && echo "${ADMIN_LOCATION}.${arg_fqdn}" || echo "${ADMIN_LOCATION}-${arg_fqdn}")
|
||||
admin_origin="https://${admin_fqdn}"
|
||||
|
||||
# copy the website
|
||||
rm -rf "${SETUP_WEBSITE_DIR}" && mkdir -p "${SETUP_WEBSITE_DIR}"
|
||||
cp -r "${script_dir}/splash/website/"* "${SETUP_WEBSITE_DIR}"
|
||||
|
||||
# create nginx config
|
||||
infra_version="none"
|
||||
[[ -f "${DATA_DIR}/INFRA_VERSION" ]] && infra_version=$(cat "${DATA_DIR}/INFRA_VERSION")
|
||||
if [[ "${arg_retire}" == "true" || "${infra_version}" != "${INFRA_VERSION}" ]]; then
|
||||
rm -f ${DATA_DIR}/nginx/applications/*
|
||||
${BOX_SRC_DIR}/node_modules/.bin/ejs-cli -f "${script_dir}/start/nginx/appconfig.ejs" \
|
||||
-O "{ \"vhost\": \"~^(.+)\$\", \"adminOrigin\": \"${admin_origin}\", \"endpoint\": \"splash\", \"sourceDir\": \"${SETUP_WEBSITE_DIR}\" }" > "${DATA_DIR}/nginx/applications/admin.conf"
|
||||
else
|
||||
${BOX_SRC_DIR}/node_modules/.bin/ejs-cli -f "${script_dir}/start/nginx/appconfig.ejs" \
|
||||
-O "{ \"vhost\": \"${admin_fqdn}\", \"adminOrigin\": \"${admin_origin}\", \"endpoint\": \"splash\", \"sourceDir\": \"${SETUP_WEBSITE_DIR}\" }" > "${DATA_DIR}/nginx/applications/admin.conf"
|
||||
fi
|
||||
|
||||
echo '{ "update": { "percent": "10", "message": "Updating cloudron software" }, "backup": null }' > "${SETUP_WEBSITE_DIR}/progress.json"
|
||||
|
||||
nginx -s reload
|
||||
-187
@@ -1,187 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
echo "==== Cloudron Start ===="
|
||||
|
||||
readonly USER="yellowtent"
|
||||
readonly BOX_SRC_DIR="/home/${USER}/box"
|
||||
readonly DATA_DIR="/home/${USER}/data"
|
||||
readonly CONFIG_DIR="/home/${USER}/configs"
|
||||
readonly SETUP_PROGRESS_JSON="/home/yellowtent/setup/website/progress.json"
|
||||
readonly ADMIN_LOCATION="my" # keep this in sync with constants.js
|
||||
|
||||
readonly curl="curl --fail --connect-timeout 20 --retry 10 --retry-delay 2 --max-time 2400"
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "${script_dir}/argparser.sh" "$@" # this injects the arg_* variables used below
|
||||
|
||||
# keep this is sync with config.js appFqdn()
|
||||
admin_fqdn=$([[ "${arg_is_custom_domain}" == "true" ]] && echo "${ADMIN_LOCATION}.${arg_fqdn}" || echo "${ADMIN_LOCATION}-${arg_fqdn}")
|
||||
admin_origin="https://${admin_fqdn}"
|
||||
|
||||
readonly is_update=$([[ -d "${DATA_DIR}/box" ]] && echo "true" || echo "false")
|
||||
|
||||
set_progress() {
|
||||
local percent="$1"
|
||||
local message="$2"
|
||||
|
||||
echo "==== ${percent} - ${message} ===="
|
||||
(echo "{ \"update\": { \"percent\": \"${percent}\", \"message\": \"${message}\" }, \"backup\": {} }" > "${SETUP_PROGRESS_JSON}") 2> /dev/null || true # as this will fail in non-update mode
|
||||
}
|
||||
|
||||
set_progress "1" "Create container"
|
||||
$script_dir/container.sh
|
||||
|
||||
set_progress "10" "Ensuring directories"
|
||||
# keep these in sync with paths.js
|
||||
[[ "${is_update}" == "false" ]] && btrfs subvolume create "${DATA_DIR}/box"
|
||||
mkdir -p "${DATA_DIR}/box/appicons"
|
||||
mkdir -p "${DATA_DIR}/box/mail"
|
||||
mkdir -p "${DATA_DIR}/graphite"
|
||||
|
||||
mkdir -p "${DATA_DIR}/mysql"
|
||||
mkdir -p "${DATA_DIR}/postgresql"
|
||||
mkdir -p "${DATA_DIR}/mongodb"
|
||||
mkdir -p "${DATA_DIR}/snapshots"
|
||||
mkdir -p "${DATA_DIR}/addons"
|
||||
mkdir -p "${DATA_DIR}/collectd/collectd.conf.d"
|
||||
|
||||
# bookkeep the version as part of data
|
||||
echo "{ \"version\": \"${arg_version}\", \"boxVersionsUrl\": \"${arg_box_versions_url}\" }" > "${DATA_DIR}/box/version"
|
||||
|
||||
# remove old snapshots. if we do want to keep this around, we will have to fix the chown -R below
|
||||
# which currently fails because these are readonly fs
|
||||
echo "Cleaning up snapshots"
|
||||
find "${DATA_DIR}/snapshots" -mindepth 1 -maxdepth 1 | xargs --no-run-if-empty btrfs subvolume delete
|
||||
|
||||
# restart mysql to make sure it has latest config
|
||||
service mysql restart
|
||||
|
||||
readonly mysql_root_password="password"
|
||||
mysqladmin -u root -ppassword password password # reset default root password
|
||||
mysql -u root -p${mysql_root_password} -e 'CREATE DATABASE IF NOT EXISTS box'
|
||||
|
||||
if [[ -n "${arg_restore_url}" ]]; then
|
||||
set_progress "15" "Downloading restore data"
|
||||
|
||||
echo "Downloading backup: ${arg_restore_url} and key: ${arg_restore_key}"
|
||||
|
||||
while true; do
|
||||
if $curl -L "${arg_restore_url}" | openssl aes-256-cbc -d -pass "pass:${arg_restore_key}" | tar -zxf - -C "${DATA_DIR}/box"; then break; fi
|
||||
echo "Failed to download data, trying again"
|
||||
done
|
||||
|
||||
set_progress "21" "Setting up MySQL"
|
||||
if [[ -f "${DATA_DIR}/box/box.mysqldump" ]]; then
|
||||
echo "Importing existing database into MySQL"
|
||||
mysql -u root -p${mysql_root_password} box < "${DATA_DIR}/box/box.mysqldump"
|
||||
fi
|
||||
fi
|
||||
|
||||
set_progress "25" "Migrating data"
|
||||
sudo -u "${USER}" -H bash <<EOF
|
||||
set -eu
|
||||
cd "${BOX_SRC_DIR}"
|
||||
BOX_ENV=cloudron DATABASE_URL=mysql://root:${mysql_root_password}@localhost/box "${BOX_SRC_DIR}/node_modules/.bin/db-migrate" up
|
||||
EOF
|
||||
|
||||
set_progress "28" "Setup collectd"
|
||||
cp "${script_dir}/start/collectd.conf" "${DATA_DIR}/collectd/collectd.conf"
|
||||
# collectd 5.4.1 has some bug where we simply cannot get it to create df-vda1
|
||||
mkdir -p "${DATA_DIR}/graphite/whisper/collectd/localhost/"
|
||||
vda1_id=$(blkid -s UUID -o value /dev/vda1)
|
||||
ln -sfF "df-disk_by-uuid_${vda1_id}" "${DATA_DIR}/graphite/whisper/collectd/localhost/df-vda1"
|
||||
service collectd restart
|
||||
|
||||
set_progress "30" "Setup nginx"
|
||||
# setup naked domain to use admin by default. app restoration will overwrite this config
|
||||
mkdir -p "${DATA_DIR}/nginx/applications"
|
||||
cp "${script_dir}/start/nginx/mime.types" "${DATA_DIR}/nginx/mime.types"
|
||||
|
||||
# generate the main nginx config file
|
||||
${BOX_SRC_DIR}/node_modules/.bin/ejs-cli -f "${script_dir}/start/nginx/nginx.ejs" \
|
||||
-O "{ \"sourceDir\": \"${BOX_SRC_DIR}\" }" > "${DATA_DIR}/nginx/nginx.conf"
|
||||
|
||||
# generate these for update code paths as well to overwrite splash
|
||||
${BOX_SRC_DIR}/node_modules/.bin/ejs-cli -f "${script_dir}/start/nginx/appconfig.ejs" \
|
||||
-O "{ \"vhost\": \"${admin_fqdn}\", \"adminOrigin\": \"${admin_origin}\", \"endpoint\": \"admin\", \"sourceDir\": \"${BOX_SRC_DIR}\" }" > "${DATA_DIR}/nginx/applications/admin.conf"
|
||||
|
||||
mkdir -p "${DATA_DIR}/nginx/cert"
|
||||
echo "${arg_tls_cert}" > ${DATA_DIR}/nginx/cert/host.cert
|
||||
echo "${arg_tls_key}" > ${DATA_DIR}/nginx/cert/host.key
|
||||
|
||||
set_progress "33" "Changing ownership"
|
||||
chown "${USER}:${USER}" -R "${DATA_DIR}/box" "${DATA_DIR}/nginx" "${DATA_DIR}/collectd" "${DATA_DIR}/addons"
|
||||
|
||||
set_progress "40" "Setting up infra"
|
||||
${script_dir}/start/setup_infra.sh "${arg_fqdn}"
|
||||
|
||||
set_progress "65" "Creating cloudron.conf"
|
||||
sudo -u yellowtent -H bash <<EOF
|
||||
set -eu
|
||||
echo "Creating cloudron.conf"
|
||||
cat > "${CONFIG_DIR}/cloudron.conf" <<CONF_END
|
||||
{
|
||||
"version": "${arg_version}",
|
||||
"token": "${arg_token}",
|
||||
"apiServerOrigin": "${arg_api_server_origin}",
|
||||
"webServerOrigin": "${arg_web_server_origin}",
|
||||
"fqdn": "${arg_fqdn}",
|
||||
"isCustomDomain": ${arg_is_custom_domain},
|
||||
"boxVersionsUrl": "${arg_box_versions_url}",
|
||||
"adminEmail": "admin@${arg_fqdn}",
|
||||
"database": {
|
||||
"hostname": "localhost",
|
||||
"username": "root",
|
||||
"password": "${mysql_root_password}",
|
||||
"port": 3306,
|
||||
"name": "box"
|
||||
}
|
||||
}
|
||||
CONF_END
|
||||
|
||||
echo "Creating config.json for webadmin"
|
||||
cat > "${BOX_SRC_DIR}/webadmin/dist/config.json" <<CONF_END
|
||||
{
|
||||
"webServerOrigin": "${arg_web_server_origin}"
|
||||
}
|
||||
CONF_END
|
||||
EOF
|
||||
|
||||
# Add webadmin oauth client
|
||||
# The domain might have changed, therefor we have to update the record
|
||||
# !!! This needs to be in sync with the webadmin, specifically login_callback.js
|
||||
echo "Add webadmin oauth cient"
|
||||
ADMIN_SCOPES="root,developer,profile,users,apps,settings,roleUser"
|
||||
mysql -u root -p${mysql_root_password} \
|
||||
-e "REPLACE INTO clients (id, appId, clientSecret, redirectURI, scope) VALUES (\"cid-webadmin\", \"webadmin\", \"secret-webadmin\", \"${admin_origin}\", \"${ADMIN_SCOPES}\")" box
|
||||
|
||||
echo "Add localhost test oauth cient"
|
||||
ADMIN_SCOPES="root,developer,profile,users,apps,settings,roleUser"
|
||||
mysql -u root -p${mysql_root_password} \
|
||||
-e "REPLACE INTO clients (id, appId, clientSecret, redirectURI, scope) VALUES (\"cid-test\", \"test\", \"secret-test\", \"http://127.0.0.1:5000\", \"${ADMIN_SCOPES}\")" box
|
||||
|
||||
set_progress "80" "Reloading supervisor"
|
||||
# looks like restarting supervisor completely is the only way to reload it
|
||||
service supervisor stop || true
|
||||
|
||||
echo -n "Waiting for supervisord to stop"
|
||||
while test -e "/var/run/supervisord.pid" && kill -0 `cat /var/run/supervisord.pid`; do
|
||||
echo -n "."
|
||||
sleep 1
|
||||
done
|
||||
echo ""
|
||||
|
||||
echo "Starting supervisor"
|
||||
|
||||
service supervisor start
|
||||
|
||||
sleep 2 # give supervisor sometime to start the processes
|
||||
|
||||
set_progress "85" "Reloading nginx"
|
||||
nginx -s reload
|
||||
|
||||
set_progress "100" "Done"
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
# Config file for collectd(1).
|
||||
#
|
||||
# Some plugins need additional configuration and are disabled by default.
|
||||
# Please read collectd.conf(5) for details.
|
||||
#
|
||||
# You should also read /usr/share/doc/collectd-core/README.Debian.plugins
|
||||
# before enabling any more plugins.
|
||||
|
||||
##############################################################################
|
||||
# Global #
|
||||
#----------------------------------------------------------------------------#
|
||||
# Global settings for the daemon. #
|
||||
##############################################################################
|
||||
|
||||
Hostname "localhost"
|
||||
#FQDNLookup true
|
||||
#BaseDir "/var/lib/collectd"
|
||||
#PluginDir "/usr/lib/collectd"
|
||||
#TypesDB "/usr/share/collectd/types.db" "/etc/collectd/my_types.db"
|
||||
|
||||
#----------------------------------------------------------------------------#
|
||||
# When enabled, plugins are loaded automatically with the default options #
|
||||
# when an appropriate <Plugin ...> block is encountered. #
|
||||
# Disabled by default. #
|
||||
#----------------------------------------------------------------------------#
|
||||
#AutoLoadPlugin false
|
||||
|
||||
#----------------------------------------------------------------------------#
|
||||
# Interval at which to query values. This may be overwritten on a per-plugin #
|
||||
# base by using the 'Interval' option of the LoadPlugin block: #
|
||||
# <LoadPlugin foo> #
|
||||
# Interval 60 #
|
||||
# </LoadPlugin> #
|
||||
#----------------------------------------------------------------------------#
|
||||
# IMPORTANT: changing this value requires a change in whisper schema as well
|
||||
Interval 20
|
||||
|
||||
#Timeout 2
|
||||
#ReadThreads 5
|
||||
#WriteThreads 5
|
||||
|
||||
# Limit the size of the write queue. Default is no limit. Setting up a limit
|
||||
# is recommended for servers handling a high volume of traffic.
|
||||
#WriteQueueLimitHigh 1000000
|
||||
#WriteQueueLimitLow 800000
|
||||
|
||||
##############################################################################
|
||||
# Logging #
|
||||
#----------------------------------------------------------------------------#
|
||||
# Plugins which provide logging functions should be loaded first, so log #
|
||||
# messages generated when loading or configuring other plugins can be #
|
||||
# accessed. #
|
||||
##############################################################################
|
||||
|
||||
LoadPlugin logfile
|
||||
#LoadPlugin syslog
|
||||
|
||||
<Plugin logfile>
|
||||
LogLevel "info"
|
||||
File "/var/log/collectd.log"
|
||||
Timestamp true
|
||||
PrintSeverity false
|
||||
</Plugin>
|
||||
|
||||
#<Plugin syslog>
|
||||
# LogLevel info
|
||||
#</Plugin>
|
||||
|
||||
##############################################################################
|
||||
# LoadPlugin section #
|
||||
#----------------------------------------------------------------------------#
|
||||
# Specify what features to activate. #
|
||||
##############################################################################
|
||||
|
||||
LoadPlugin aggregation
|
||||
#LoadPlugin amqp
|
||||
#LoadPlugin apache
|
||||
#LoadPlugin apcups
|
||||
#LoadPlugin ascent
|
||||
#LoadPlugin battery
|
||||
#LoadPlugin bind
|
||||
#LoadPlugin cgroups
|
||||
#LoadPlugin conntrack
|
||||
#LoadPlugin contextswitch
|
||||
LoadPlugin cpu
|
||||
#LoadPlugin cpufreq
|
||||
#LoadPlugin csv
|
||||
#LoadPlugin curl
|
||||
#LoadPlugin curl_json
|
||||
#LoadPlugin curl_xml
|
||||
#LoadPlugin dbi
|
||||
LoadPlugin df
|
||||
#LoadPlugin disk
|
||||
#LoadPlugin dns
|
||||
#LoadPlugin email
|
||||
#LoadPlugin entropy
|
||||
#LoadPlugin ethstat
|
||||
#LoadPlugin exec
|
||||
#LoadPlugin filecount
|
||||
#LoadPlugin fscache
|
||||
#LoadPlugin gmond
|
||||
#LoadPlugin hddtemp
|
||||
LoadPlugin interface
|
||||
#LoadPlugin ipmi
|
||||
#LoadPlugin iptables
|
||||
#LoadPlugin ipvs
|
||||
#LoadPlugin irq
|
||||
#LoadPlugin java
|
||||
#LoadPlugin libvirt
|
||||
LoadPlugin load
|
||||
#LoadPlugin lvm
|
||||
#LoadPlugin madwifi
|
||||
#LoadPlugin mbmon
|
||||
#LoadPlugin md
|
||||
#LoadPlugin memcachec
|
||||
#LoadPlugin memcached
|
||||
LoadPlugin memory
|
||||
#LoadPlugin modbus
|
||||
#LoadPlugin multimeter
|
||||
#LoadPlugin mysql
|
||||
#LoadPlugin netlink
|
||||
#LoadPlugin network
|
||||
#LoadPlugin nfs
|
||||
LoadPlugin nginx
|
||||
#LoadPlugin notify_desktop
|
||||
#LoadPlugin notify_email
|
||||
#LoadPlugin ntpd
|
||||
#LoadPlugin numa
|
||||
#LoadPlugin nut
|
||||
#LoadPlugin olsrd
|
||||
#LoadPlugin openvpn
|
||||
#<LoadPlugin perl>
|
||||
# Globals true
|
||||
#</LoadPlugin>
|
||||
#LoadPlugin pinba
|
||||
LoadPlugin ping
|
||||
#LoadPlugin postgresql
|
||||
#LoadPlugin powerdns
|
||||
LoadPlugin processes
|
||||
#LoadPlugin protocols
|
||||
#<LoadPlugin python>
|
||||
# Globals true
|
||||
#</LoadPlugin>
|
||||
#LoadPlugin rrdcached
|
||||
#LoadPlugin rrdtool
|
||||
#LoadPlugin sensors
|
||||
#LoadPlugin serial
|
||||
#LoadPlugin snmp
|
||||
#LoadPlugin statsd
|
||||
LoadPlugin swap
|
||||
#LoadPlugin table
|
||||
LoadPlugin tail
|
||||
#LoadPlugin tail_csv
|
||||
#LoadPlugin tcpconns
|
||||
#LoadPlugin teamspeak2
|
||||
#LoadPlugin ted
|
||||
#LoadPlugin thermal
|
||||
#LoadPlugin tokyotyrant
|
||||
#LoadPlugin unixsock
|
||||
#LoadPlugin uptime
|
||||
#LoadPlugin users
|
||||
#LoadPlugin uuid
|
||||
#LoadPlugin varnish
|
||||
LoadPlugin vmem
|
||||
#LoadPlugin vserver
|
||||
#LoadPlugin wireless
|
||||
LoadPlugin write_graphite
|
||||
#LoadPlugin write_http
|
||||
#LoadPlugin write_riemann
|
||||
|
||||
##############################################################################
|
||||
# Plugin configuration #
|
||||
#----------------------------------------------------------------------------#
|
||||
# In this section configuration stubs for each plugin are provided. A desc- #
|
||||
# ription of those options is available in the collectd.conf(5) manual page. #
|
||||
##############################################################################
|
||||
|
||||
<Plugin "aggregation">
|
||||
<Aggregation>
|
||||
Plugin "cpu"
|
||||
Type "cpu"
|
||||
|
||||
GroupBy "Host"
|
||||
GroupBy "TypeInstance"
|
||||
|
||||
CalculateNum false
|
||||
CalculateSum true
|
||||
CalculateAverage true
|
||||
CalculateMinimum false
|
||||
CalculateMaximum true
|
||||
CalculateStddev false
|
||||
</Aggregation>
|
||||
</Plugin>
|
||||
|
||||
<Plugin df>
|
||||
FSType "tmpfs"
|
||||
MountPoint "/dev"
|
||||
|
||||
ReportByDevice true
|
||||
IgnoreSelected true
|
||||
|
||||
ValuesAbsolute true
|
||||
ValuesPercentage true
|
||||
</Plugin>
|
||||
|
||||
<Plugin interface>
|
||||
Interface "eth0"
|
||||
IgnoreSelected false
|
||||
</Plugin>
|
||||
|
||||
<Plugin nginx>
|
||||
URL "http://127.0.0.1/nginx_status"
|
||||
</Plugin>
|
||||
|
||||
<Plugin ping>
|
||||
Host "google.com"
|
||||
Interval 1.0
|
||||
Timeout 0.9
|
||||
TTL 255
|
||||
</Plugin>
|
||||
|
||||
<Plugin processes>
|
||||
ProcessMatch "app" "node app.js"
|
||||
</Plugin>
|
||||
|
||||
<Plugin swap>
|
||||
ReportByDevice false
|
||||
ReportBytes true
|
||||
</Plugin>
|
||||
|
||||
<Plugin "tail">
|
||||
<File "/var/log/nginx/error.log">
|
||||
Instance "nginx"
|
||||
<Match>
|
||||
Regex ".*"
|
||||
DSType "CounterInc"
|
||||
Type counter
|
||||
Instance "errors"
|
||||
</Match>
|
||||
</File>
|
||||
<File "/var/log/nginx/access.log">
|
||||
Instance "nginx"
|
||||
<Match>
|
||||
Regex ".*"
|
||||
DSType "CounterInc"
|
||||
Type counter
|
||||
Instance "requests"
|
||||
</Match>
|
||||
<Match>
|
||||
Regex " \".*\" [0-9]+ [0-9]+ ([0-9]+)"
|
||||
DSType GaugeAverage
|
||||
Type delay
|
||||
Instance "response"
|
||||
</Match>
|
||||
</File>
|
||||
</Plugin>
|
||||
|
||||
<Plugin vmem>
|
||||
Verbose false
|
||||
</Plugin>
|
||||
|
||||
<Plugin write_graphite>
|
||||
<Node "graphing">
|
||||
Host "localhost"
|
||||
Port "2003"
|
||||
Protocol "tcp"
|
||||
LogSendErrors true
|
||||
Prefix "collectd."
|
||||
StoreRates true
|
||||
AlwaysAppendDS false
|
||||
EscapeCharacter "_"
|
||||
</Node>
|
||||
</Plugin>
|
||||
|
||||
<Include "/etc/collectd/collectd.conf.d">
|
||||
Filter "*.conf"
|
||||
</Include>
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
# http://nginx.org/en/docs/http/websocket.html
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443;
|
||||
server_name <%= vhost %>;
|
||||
|
||||
ssl on;
|
||||
# paths are relative to prefix and not to this file
|
||||
ssl_certificate cert/host.cert;
|
||||
ssl_certificate_key cert/host.key;
|
||||
ssl_session_timeout 5m;
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
|
||||
# https://bettercrypto.org/static/applied-crypto-hardening.pdf
|
||||
# https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
||||
# https://cipherli.st/
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # don't use SSLv3 ref: POODLE
|
||||
ssl_ciphers 'AES128+EECDH:AES128+EDH';
|
||||
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_intercept_errors on;
|
||||
proxy_read_timeout 3500;
|
||||
proxy_connect_timeout 3250;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
|
||||
# upgrade is a hop-by-hop header (http://nginx.org/en/docs/http/websocket.html)
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
error_page 500 502 503 504 @appstatus;
|
||||
location @appstatus {
|
||||
return 307 <%= adminOrigin %>/appstatus.html?referrer=https://$host$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
# increase the proxy buffer sizes to not run into buffer issues (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffers)
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
proxy_busy_buffers_size 256k;
|
||||
|
||||
# Disable check to allow unlimited body sizes
|
||||
client_max_body_size 0;
|
||||
|
||||
<% if ( endpoint === 'admin' ) { %>
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
client_max_body_size 1m;
|
||||
}
|
||||
|
||||
# graphite paths
|
||||
location ~ ^/(graphite|content|metrics|dashboard|render|browser|composer)/ {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
client_max_body_size 1m;
|
||||
}
|
||||
|
||||
location / {
|
||||
root <%= sourceDir %>/webadmin/dist;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
<% } else if ( endpoint === 'oauthproxy' ) { %>
|
||||
proxy_pass http://127.0.0.1:4000;
|
||||
proxy_set_header X-Cloudron-Proxy-Port <%= port %>;
|
||||
<% } else if ( endpoint === 'app' ) { %>
|
||||
proxy_pass http://127.0.0.1:<%= port %>;
|
||||
<% } else if ( endpoint === 'splash' ) { %>
|
||||
root <%= sourceDir %>;
|
||||
|
||||
error_page 503 /update.html;
|
||||
|
||||
location /update.html {
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
||||
|
||||
location /theme.css {
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
||||
|
||||
location /3rdparty/ {
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
||||
|
||||
location /js/ {
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
||||
|
||||
location /progress.json {
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
||||
|
||||
location /api/v1/cloudron/progress {
|
||||
add_header Cache-Control no-cache;
|
||||
default_type application/json;
|
||||
alias <%= sourceDir %>/progress.json;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 503;
|
||||
}
|
||||
<% } %>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/x-javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
image/svg+xml svg svgz;
|
||||
image/webp webp;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream eot;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
user www-data;
|
||||
|
||||
worker_processes 1;
|
||||
|
||||
pid /run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# the collectd config depends on this log format
|
||||
log_format combined2 '$remote_addr - [$time_local] '
|
||||
'"$request" $status $body_bytes_sent $request_time '
|
||||
'"$http_referer" "$http_user_agent"';
|
||||
|
||||
# required for long host names
|
||||
server_names_hash_bucket_size 128;
|
||||
|
||||
access_log access.log combined2;
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
# HTTP server
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
# collectd
|
||||
location /nginx_status {
|
||||
stub_status on;
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
}
|
||||
|
||||
location / {
|
||||
# redirect everything to HTTPS
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# We have to enable https for nginx to read in the vhost in http request
|
||||
# and send a 404. This is a side-effect of using wildcard DNS
|
||||
server {
|
||||
listen 443 default_server;
|
||||
ssl on;
|
||||
ssl_certificate cert/host.cert;
|
||||
ssl_certificate_key cert/host.key;
|
||||
|
||||
error_page 404 = @fallback;
|
||||
location @fallback {
|
||||
internal;
|
||||
root <%= sourceDir %>/webadmin/dist;
|
||||
rewrite ^/$ /nakeddomain.html break;
|
||||
}
|
||||
|
||||
return 404;
|
||||
}
|
||||
|
||||
include applications/*.conf;
|
||||
}
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
readonly DATA_DIR="/home/yellowtent/data"
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${script_dir}/../INFRA_VERSION" # this injects INFRA_VERSION
|
||||
|
||||
arg_fqdn="$1"
|
||||
|
||||
# removing containers ensures containers are launched with latest config updates
|
||||
# restore code in appatask does not delete old containers
|
||||
infra_version="none"
|
||||
[[ -f "${DATA_DIR}/INFRA_VERSION" ]] && infra_version=$(cat "${DATA_DIR}/INFRA_VERSION")
|
||||
if [[ "${infra_version}" == "${INFRA_VERSION}" ]]; then
|
||||
echo "Infrastructure is upto date"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Upgrading infrastructure from ${infra_version} to ${INFRA_VERSION}"
|
||||
|
||||
existing_containers=$(docker ps -qa)
|
||||
echo "Remove containers: ${existing_containers}"
|
||||
if [[ -n "${existing_containers}" ]]; then
|
||||
echo "${existing_containers}" | xargs docker rm -f
|
||||
fi
|
||||
|
||||
# graphite
|
||||
graphite_container_id=$(docker run --restart=always -d --name="graphite" \
|
||||
-p 127.0.0.1:2003:2003 \
|
||||
-p 127.0.0.1:2004:2004 \
|
||||
-p 127.0.0.1:8000:8000 \
|
||||
-v "${DATA_DIR}/graphite:/app/data" \
|
||||
"${GRAPHITE_IMAGE}")
|
||||
echo "Graphite container id: ${graphite_container_id}"
|
||||
|
||||
# mail
|
||||
mail_container_id=$(docker run --restart=always -d --name="mail" \
|
||||
-p 127.0.0.1:25:25 \
|
||||
-h "${arg_fqdn}" \
|
||||
-e "DOMAIN_NAME=${arg_fqdn}" \
|
||||
-v "${DATA_DIR}/box/mail:/app/data" \
|
||||
"${MAIL_IMAGE}")
|
||||
echo "Mail container id: ${mail_container_id}"
|
||||
|
||||
# mysql
|
||||
mysql_addon_root_password=$(pwgen -1 -s)
|
||||
docker0_ip=$(/sbin/ifconfig docker0 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}')
|
||||
cat > "${DATA_DIR}/addons/mysql_vars.sh" <<EOF
|
||||
readonly MYSQL_ROOT_PASSWORD='${mysql_addon_root_password}'
|
||||
readonly MYSQL_ROOT_HOST='${docker0_ip}'
|
||||
EOF
|
||||
mysql_container_id=$(docker run --restart=always -d --name="mysql" \
|
||||
-h "${arg_fqdn}" \
|
||||
-v "${DATA_DIR}/mysql:/var/lib/mysql" \
|
||||
-v "${DATA_DIR}/addons/mysql_vars.sh:/etc/mysql/mysql_vars.sh:ro" \
|
||||
"${MYSQL_IMAGE}")
|
||||
echo "MySQL container id: ${mysql_container_id}"
|
||||
|
||||
# postgresql
|
||||
postgresql_addon_root_password=$(pwgen -1 -s)
|
||||
cat > "${DATA_DIR}/addons/postgresql_vars.sh" <<EOF
|
||||
readonly POSTGRESQL_ROOT_PASSWORD='${postgresql_addon_root_password}'
|
||||
EOF
|
||||
postgresql_container_id=$(docker run --restart=always -d --name="postgresql" \
|
||||
-h "${arg_fqdn}" \
|
||||
-v "${DATA_DIR}/postgresql:/var/lib/postgresql" \
|
||||
-v "${DATA_DIR}/addons/postgresql_vars.sh:/etc/postgresql/postgresql_vars.sh:ro" \
|
||||
"${POSTGRESQL_IMAGE}")
|
||||
echo "PostgreSQL container id: ${postgresql_container_id}"
|
||||
|
||||
# mongodb
|
||||
mongodb_addon_root_password=$(pwgen -1 -s)
|
||||
cat > "${DATA_DIR}/addons/mongodb_vars.sh" <<EOF
|
||||
readonly MONGODB_ROOT_PASSWORD='${mongodb_addon_root_password}'
|
||||
EOF
|
||||
mongodb_container_id=$(docker run --restart=always -d --name="mongodb" \
|
||||
-h "${arg_fqdn}" \
|
||||
-v "${DATA_DIR}/mongodb:/var/lib/mongodb" \
|
||||
-v "${DATA_DIR}/addons/mongodb_vars.sh:/etc/mongodb_vars.sh:ro" \
|
||||
"${MONGODB_IMAGE}")
|
||||
echo "Mongodb container id: ${mongodb_container_id}"
|
||||
|
||||
if [[ "${infra_version}" == "none" ]]; then
|
||||
# if no existing infra was found (for new and restoring cloudons), download app backups
|
||||
echo "Marking installed apps for restore"
|
||||
mysql -u root -ppassword -e 'UPDATE apps SET installationState = "pending_restore" WHERE installationState = "installed"' box
|
||||
else
|
||||
# if existing infra was found, just mark apps for reconfiguration
|
||||
mysql -u root -ppassword -e 'UPDATE apps SET installationState = "pending_configure" WHERE installationState = "installed"' box
|
||||
fi
|
||||
|
||||
echo -n "${INFRA_VERSION}" > "${DATA_DIR}/INFRA_VERSION"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
echo "Stopping box code"
|
||||
|
||||
service supervisor stop || true
|
||||
|
||||
echo -n "Waiting for supervisord to stop"
|
||||
while test -e "/var/run/supervisord.pid" && kill -0 `cat /var/run/supervisord.pid`; do
|
||||
echo -n "."
|
||||
sleep 1
|
||||
done
|
||||
echo ""
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* angular-ui-notification - Angular.js service providing simple notifications using Bootstrap 3 styles with css transitions for animating
|
||||
* @author Alex_Crack
|
||||
* @version v0.3.6
|
||||
* @link https://github.com/alexcrack/angular-ui-notification
|
||||
* @license MIT
|
||||
*/
|
||||
.ui-notification
|
||||
{
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
|
||||
width: 300px;
|
||||
|
||||
-webkit-transition: all ease .5s;
|
||||
-o-transition: all ease .5s;
|
||||
transition: all ease .5s;
|
||||
|
||||
color: #fff;
|
||||
border-radius: 0;
|
||||
background: #337ab7;
|
||||
box-shadow: 5px 5px 10px rgba(0, 0, 0, .3);
|
||||
}
|
||||
.ui-notification.clickable
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-notification.clickable:hover
|
||||
{
|
||||
opacity: .7;
|
||||
}
|
||||
.ui-notification.killed
|
||||
{
|
||||
-webkit-transition: opacity ease 1s;
|
||||
-o-transition: opacity ease 1s;
|
||||
transition: opacity ease 1s;
|
||||
|
||||
opacity: 0;
|
||||
}
|
||||
.ui-notification > h3
|
||||
{
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
|
||||
display: block;
|
||||
|
||||
margin: 10px 10px 0 10px;
|
||||
padding: 0 0 5px 0;
|
||||
|
||||
text-align: left;
|
||||
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .3);
|
||||
}
|
||||
.ui-notification a
|
||||
{
|
||||
color: #fff;
|
||||
}
|
||||
.ui-notification a:hover
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
.ui-notification > .message
|
||||
{
|
||||
margin: 10px 10px 10px 10px;
|
||||
}
|
||||
.ui-notification.warning
|
||||
{
|
||||
color: #fff;
|
||||
background: #f0ad4e;
|
||||
}
|
||||
.ui-notification.error
|
||||
{
|
||||
color: #fff;
|
||||
background: #d9534f;
|
||||
}
|
||||
.ui-notification.success
|
||||
{
|
||||
color: #fff;
|
||||
background: #5cb85c;
|
||||
}
|
||||
.ui-notification.info
|
||||
{
|
||||
color: #fff;
|
||||
background: #5bc0de;
|
||||
}
|
||||
Vendored
+6
File diff suppressed because one or more lines are too long
+255
@@ -0,0 +1,255 @@
|
||||
/*! =======================================================
|
||||
VERSION 6.0.12
|
||||
========================================================= */
|
||||
/*! =========================================================
|
||||
* bootstrap-slider.js
|
||||
*
|
||||
* Maintainers:
|
||||
* Kyle Kemp
|
||||
* - Twitter: @seiyria
|
||||
* - Github: seiyria
|
||||
* Rohit Kalkur
|
||||
* - Twitter: @Rovolutionary
|
||||
* - Github: rovolution
|
||||
*
|
||||
* =========================================================
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================= */
|
||||
.slider {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
}
|
||||
.slider.slider-horizontal {
|
||||
width: 210px;
|
||||
height: 20px;
|
||||
}
|
||||
.slider.slider-horizontal .slider-track {
|
||||
height: 10px;
|
||||
width: 100%;
|
||||
margin-top: -5px;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
}
|
||||
.slider.slider-horizontal .slider-selection,
|
||||
.slider.slider-horizontal .slider-track-low,
|
||||
.slider.slider-horizontal .slider-track-high {
|
||||
height: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.slider.slider-horizontal .slider-tick,
|
||||
.slider.slider-horizontal .slider-handle {
|
||||
margin-left: -10px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
.slider.slider-horizontal .slider-tick.triangle,
|
||||
.slider.slider-horizontal .slider-handle.triangle {
|
||||
border-width: 0 10px 10px 10px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom-color: #0480be;
|
||||
margin-top: 0;
|
||||
}
|
||||
.slider.slider-horizontal .slider-tick-label-container {
|
||||
white-space: nowrap;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.slider.slider-horizontal .slider-tick-label-container .slider-tick-label {
|
||||
padding-top: 4px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.slider.slider-vertical {
|
||||
height: 210px;
|
||||
width: 20px;
|
||||
}
|
||||
.slider.slider-vertical .slider-track {
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
margin-left: -5px;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
}
|
||||
.slider.slider-vertical .slider-selection {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.slider.slider-vertical .slider-track-low,
|
||||
.slider.slider-vertical .slider-track-high {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.slider.slider-vertical .slider-tick,
|
||||
.slider.slider-vertical .slider-handle {
|
||||
margin-left: -5px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.slider.slider-vertical .slider-tick.triangle,
|
||||
.slider.slider-vertical .slider-handle.triangle {
|
||||
border-width: 10px 0 10px 10px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border-left-color: #0480be;
|
||||
margin-left: 0;
|
||||
}
|
||||
.slider.slider-vertical .slider-tick-label-container {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.slider.slider-vertical .slider-tick-label-container .slider-tick-label {
|
||||
padding-left: 4px;
|
||||
}
|
||||
.slider.slider-disabled .slider-handle {
|
||||
background-image: -webkit-linear-gradient(top, #dfdfdf 0%, #bebebe 100%);
|
||||
background-image: -o-linear-gradient(top, #dfdfdf 0%, #bebebe 100%);
|
||||
background-image: linear-gradient(to bottom, #dfdfdf 0%, #bebebe 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdfdfdf', endColorstr='#ffbebebe', GradientType=0);
|
||||
}
|
||||
.slider.slider-disabled .slider-track {
|
||||
background-image: -webkit-linear-gradient(top, #e5e5e5 0%, #e9e9e9 100%);
|
||||
background-image: -o-linear-gradient(top, #e5e5e5 0%, #e9e9e9 100%);
|
||||
background-image: linear-gradient(to bottom, #e5e5e5 0%, #e9e9e9 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe5e5e5', endColorstr='#ffe9e9e9', GradientType=0);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.slider input {
|
||||
display: none;
|
||||
}
|
||||
.slider .tooltip.top {
|
||||
margin-top: -36px;
|
||||
}
|
||||
.slider .tooltip-inner {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.slider .hide {
|
||||
display: none;
|
||||
}
|
||||
.slider-track {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #f9f9f9 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #f9f9f9 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #f9f9f9 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.slider-selection {
|
||||
position: absolute;
|
||||
background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.slider-selection.tick-slider-selection {
|
||||
background-image: -webkit-linear-gradient(top, #89cdef 0%, #81bfde 100%);
|
||||
background-image: -o-linear-gradient(top, #89cdef 0%, #81bfde 100%);
|
||||
background-image: linear-gradient(to bottom, #89cdef 0%, #81bfde 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff89cdef', endColorstr='#ff81bfde', GradientType=0);
|
||||
}
|
||||
.slider-track-low,
|
||||
.slider-track-high {
|
||||
position: absolute;
|
||||
background: transparent;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.slider-handle {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #337ab7;
|
||||
background-image: -webkit-linear-gradient(top, #149bdf 0%, #0480be 100%);
|
||||
background-image: -o-linear-gradient(top, #149bdf 0%, #0480be 100%);
|
||||
background-image: linear-gradient(to bottom, #149bdf 0%, #0480be 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
|
||||
filter: none;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||
border: 0px solid transparent;
|
||||
}
|
||||
.slider-handle.round {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.slider-handle.triangle {
|
||||
background: transparent none;
|
||||
}
|
||||
.slider-handle.custom {
|
||||
background: transparent none;
|
||||
}
|
||||
.slider-handle.custom::before {
|
||||
line-height: 20px;
|
||||
font-size: 20px;
|
||||
content: '\2605';
|
||||
color: #726204;
|
||||
}
|
||||
.slider-tick {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
filter: none;
|
||||
opacity: 0.8;
|
||||
border: 0px solid transparent;
|
||||
}
|
||||
.slider-tick.round {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.slider-tick.triangle {
|
||||
background: transparent none;
|
||||
}
|
||||
.slider-tick.custom {
|
||||
background: transparent none;
|
||||
}
|
||||
.slider-tick.custom::before {
|
||||
line-height: 20px;
|
||||
font-size: 20px;
|
||||
content: '\2605';
|
||||
color: #726204;
|
||||
}
|
||||
.slider-tick.in-selection {
|
||||
background-image: -webkit-linear-gradient(top, #89cdef 0%, #81bfde 100%);
|
||||
background-image: -o-linear-gradient(top, #89cdef 0%, #81bfde 100%);
|
||||
background-image: linear-gradient(to bottom, #89cdef 0%, #81bfde 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff89cdef', endColorstr='#ff81bfde', GradientType=0);
|
||||
opacity: 1;
|
||||
}
|
||||
+1562
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+232
@@ -0,0 +1,232 @@
|
||||
(function(factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['angular', 'bootstrap-slider'], factory);
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory(require('angular'), require('bootstrap-slider'));
|
||||
} else if (window) {
|
||||
factory(window.angular, window.Slider);
|
||||
}
|
||||
})(function (angular, Slider) {
|
||||
|
||||
angular.module('ui.bootstrap-slider', [])
|
||||
.directive('slider', ['$parse', '$timeout', '$rootScope', function ($parse, $timeout, $rootScope) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: true,
|
||||
template: '<div><input class="slider-input" type="text" style="width:100%" /></div>',
|
||||
require: 'ngModel',
|
||||
scope: {
|
||||
max: "=",
|
||||
min: "=",
|
||||
step: "=",
|
||||
value: "=",
|
||||
ngModel: '=',
|
||||
ngDisabled: '=',
|
||||
range: '=',
|
||||
sliderid: '=',
|
||||
ticks: '=',
|
||||
ticksLabels: '=',
|
||||
ticksSnapBounds: '=',
|
||||
ticksPositions: '=',
|
||||
scale: '=',
|
||||
focus: '=',
|
||||
formatter: '&',
|
||||
onStartSlide: '&',
|
||||
onStopSlide: '&',
|
||||
onSlide: '&'
|
||||
},
|
||||
link: function ($scope, element, attrs, ngModelCtrl, $compile) {
|
||||
var ngModelDeregisterFn, ngDisabledDeregisterFn;
|
||||
|
||||
var slider = initSlider();
|
||||
|
||||
function initSlider() {
|
||||
var options = {};
|
||||
|
||||
function setOption(key, value, defaultValue) {
|
||||
options[key] = value || defaultValue;
|
||||
}
|
||||
|
||||
function setFloatOption(key, value, defaultValue) {
|
||||
options[key] = value || value === 0 ? parseFloat(value) : defaultValue;
|
||||
}
|
||||
|
||||
function setBooleanOption(key, value, defaultValue) {
|
||||
options[key] = value ? value + '' === 'true' : defaultValue;
|
||||
}
|
||||
|
||||
function getArrayOrValue(value) {
|
||||
return (angular.isString(value) && value.indexOf("[") === 0) ? angular.fromJson(value) : value;
|
||||
}
|
||||
|
||||
setOption('id', $scope.sliderid);
|
||||
setOption('orientation', attrs.orientation, 'horizontal');
|
||||
setOption('selection', attrs.selection, 'before');
|
||||
setOption('handle', attrs.handle, 'round');
|
||||
setOption('tooltip', attrs.sliderTooltip || attrs.tooltip, 'show');
|
||||
setOption('tooltip_position', attrs.sliderTooltipPosition, 'top');
|
||||
setOption('tooltipseparator', attrs.tooltipseparator, ':');
|
||||
setOption('ticks', $scope.ticks);
|
||||
setOption('ticks_labels', $scope.ticksLabels);
|
||||
setOption('ticks_snap_bounds', $scope.ticksSnapBounds);
|
||||
setOption('ticks_positions', $scope.ticksPositions);
|
||||
setOption('scale', $scope.scale, 'linear');
|
||||
setOption('focus', $scope.focus);
|
||||
|
||||
setFloatOption('min', $scope.min, 0);
|
||||
setFloatOption('max', $scope.max, 10);
|
||||
setFloatOption('step', $scope.step, 1);
|
||||
var strNbr = options.step + '';
|
||||
var dotPos = strNbr.search(/[^.,]*$/);
|
||||
var decimals = strNbr.substring(dotPos);
|
||||
setFloatOption('precision', attrs.precision, decimals.length);
|
||||
|
||||
setBooleanOption('tooltip_split', attrs.tooltipsplit, false);
|
||||
setBooleanOption('enabled', attrs.enabled, true);
|
||||
setBooleanOption('naturalarrowkeys', attrs.naturalarrowkeys, false);
|
||||
setBooleanOption('reversed', attrs.reversed, false);
|
||||
|
||||
setBooleanOption('range', $scope.range, false);
|
||||
if (options.range) {
|
||||
if (angular.isArray($scope.value)) {
|
||||
options.value = $scope.value;
|
||||
}
|
||||
else if (angular.isString($scope.value)) {
|
||||
options.value = getArrayOrValue($scope.value);
|
||||
if (!angular.isArray(options.value)) {
|
||||
var value = parseFloat($scope.value);
|
||||
if (isNaN(value)) value = 5;
|
||||
|
||||
if (value < $scope.min) {
|
||||
value = $scope.min;
|
||||
options.value = [value, options.max];
|
||||
}
|
||||
else if (value > $scope.max) {
|
||||
value = $scope.max;
|
||||
options.value = [options.min, value];
|
||||
}
|
||||
else {
|
||||
options.value = [options.min, options.max];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
options.value = [options.min, options.max]; // This is needed, because of value defined at $.fn.slider.defaults - default value 5 prevents creating range slider
|
||||
}
|
||||
$scope.ngModel = options.value; // needed, otherwise turns value into [null, ##]
|
||||
}
|
||||
else {
|
||||
setFloatOption('value', $scope.value, 5);
|
||||
}
|
||||
|
||||
if (attrs.formatter) {
|
||||
options.formatter = function(value) {
|
||||
return $scope.formatter({value: value});
|
||||
}
|
||||
}
|
||||
|
||||
// check if slider jQuery plugin exists
|
||||
if ('$' in window && $.fn.slider) {
|
||||
// adding methods to jQuery slider plugin prototype
|
||||
$.fn.slider.constructor.prototype.disable = function () {
|
||||
this.picker.off();
|
||||
};
|
||||
$.fn.slider.constructor.prototype.enable = function () {
|
||||
this.picker.on();
|
||||
};
|
||||
}
|
||||
|
||||
// destroy previous slider to reset all options
|
||||
if (element[0].__slider)
|
||||
element[0].__slider.destroy();
|
||||
|
||||
var slider = new Slider(element[0].getElementsByClassName('slider-input')[0], options);
|
||||
element[0].__slider = slider;
|
||||
|
||||
// everything that needs slider element
|
||||
var updateEvent = getArrayOrValue(attrs.updateevent);
|
||||
if (angular.isString(updateEvent)) {
|
||||
// if only single event name in string
|
||||
updateEvent = [updateEvent];
|
||||
}
|
||||
else {
|
||||
// default to slide event
|
||||
updateEvent = ['slide'];
|
||||
}
|
||||
angular.forEach(updateEvent, function (sliderEvent) {
|
||||
slider.on(sliderEvent, function (ev) {
|
||||
ngModelCtrl.$setViewValue(ev);
|
||||
});
|
||||
});
|
||||
slider.on('change', function (ev) {
|
||||
ngModelCtrl.$setViewValue(ev.newValue);
|
||||
});
|
||||
|
||||
|
||||
// Event listeners
|
||||
var sliderEvents = {
|
||||
slideStart: 'onStartSlide',
|
||||
slide: 'onSlide',
|
||||
slideStop: 'onStopSlide'
|
||||
};
|
||||
angular.forEach(sliderEvents, function (sliderEventAttr, sliderEvent) {
|
||||
var fn = $parse(attrs[sliderEventAttr]);
|
||||
slider.on(sliderEvent, function (ev) {
|
||||
if ($scope[sliderEventAttr]) {
|
||||
$scope.$apply(function () {
|
||||
fn($scope.$parent, { $event: ev, value: ev });
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// deregister ngDisabled watcher to prevent memory leaks
|
||||
if (angular.isFunction(ngDisabledDeregisterFn)) {
|
||||
ngDisabledDeregisterFn();
|
||||
ngDisabledDeregisterFn = null;
|
||||
}
|
||||
|
||||
ngDisabledDeregisterFn = $scope.$watch('ngDisabled', function (value) {
|
||||
if (value) {
|
||||
slider.disable();
|
||||
}
|
||||
else {
|
||||
slider.enable();
|
||||
}
|
||||
});
|
||||
|
||||
// deregister ngModel watcher to prevent memory leaks
|
||||
if (angular.isFunction(ngModelDeregisterFn)) ngModelDeregisterFn();
|
||||
ngModelDeregisterFn = $scope.$watch('ngModel', function (value) {
|
||||
if($scope.range){
|
||||
slider.setValue(value);
|
||||
}else{
|
||||
slider.setValue(parseFloat(value));
|
||||
}
|
||||
slider.relayout();
|
||||
}, true);
|
||||
|
||||
return slider;
|
||||
}
|
||||
|
||||
|
||||
var watchers = ['min', 'max', 'step', 'range', 'scale', 'ticksLabels', 'ticks'];
|
||||
angular.forEach(watchers, function (prop) {
|
||||
$scope.$watch(prop, function () {
|
||||
slider = initSlider();
|
||||
});
|
||||
});
|
||||
|
||||
var globalEvents = ['relayout', 'refresh', 'resize'];
|
||||
angular.forEach(globalEvents, function(event) {
|
||||
if(angular.isFunction(slider[event])) {
|
||||
$scope.$on('slider:' + event, function () {
|
||||
slider[event]();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}])
|
||||
;
|
||||
});
|
||||
Vendored
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Vendored
Vendored
+10
File diff suppressed because one or more lines are too long
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
AngularJS v1.5.8
|
||||
(c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(R,B){'use strict';function Da(a,b,c){if(!a)throw Ma("areq",b||"?",c||"required");return a}function Ea(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;Y(a)&&(a=a.join(" "));Y(b)&&(b=b.join(" "));return a+" "+b}function Na(a){var b={};a&&(a.to||a.from)&&(b.to=a.to,b.from=a.from);return b}function Z(a,b,c){var d="";a=Y(a)?a:a&&G(a)&&a.length?a.split(/\s+/):[];s(a,function(a,l){a&&0<a.length&&(d+=0<l?" ":"",d+=c?b+a:a+b)});return d}function Oa(a){if(a instanceof F)switch(a.length){case 0:return a;
|
||||
case 1:if(1===a[0].nodeType)return a;break;default:return F(ta(a))}if(1===a.nodeType)return F(a)}function ta(a){if(!a[0])return a;for(var b=0;b<a.length;b++){var c=a[b];if(1==c.nodeType)return c}}function Pa(a,b,c){s(b,function(b){a.addClass(b,c)})}function Qa(a,b,c){s(b,function(b){a.removeClass(b,c)})}function V(a){return function(b,c){c.addClass&&(Pa(a,b,c.addClass),c.addClass=null);c.removeClass&&(Qa(a,b,c.removeClass),c.removeClass=null)}}function oa(a){a=a||{};if(!a.$$prepared){var b=a.domOperation||
|
||||
P;a.domOperation=function(){a.$$domOperationFired=!0;b();b=P};a.$$prepared=!0}return a}function ha(a,b){Fa(a,b);Ga(a,b)}function Fa(a,b){b.from&&(a.css(b.from),b.from=null)}function Ga(a,b){b.to&&(a.css(b.to),b.to=null)}function W(a,b,c){var d=b.options||{};c=c.options||{};var e=(d.addClass||"")+" "+(c.addClass||""),l=(d.removeClass||"")+" "+(c.removeClass||"");a=Ra(a.attr("class"),e,l);c.preparationClasses&&(d.preparationClasses=$(c.preparationClasses,d.preparationClasses),delete c.preparationClasses);
|
||||
e=d.domOperation!==P?d.domOperation:null;ua(d,c);e&&(d.domOperation=e);d.addClass=a.addClass?a.addClass:null;d.removeClass=a.removeClass?a.removeClass:null;b.addClass=d.addClass;b.removeClass=d.removeClass;return d}function Ra(a,b,c){function d(a){G(a)&&(a=a.split(" "));var b={};s(a,function(a){a.length&&(b[a]=!0)});return b}var e={};a=d(a);b=d(b);s(b,function(a,b){e[b]=1});c=d(c);s(c,function(a,b){e[b]=1===e[b]?null:-1});var l={addClass:"",removeClass:""};s(e,function(b,c){var d,e;1===b?(d="addClass",
|
||||
e=!a[c]||a[c+"-remove"]):-1===b&&(d="removeClass",e=a[c]||a[c+"-add"]);e&&(l[d].length&&(l[d]+=" "),l[d]+=c)});return l}function y(a){return a instanceof F?a[0]:a}function Sa(a,b,c){var d="";b&&(d=Z(b,"ng-",!0));c.addClass&&(d=$(d,Z(c.addClass,"-add")));c.removeClass&&(d=$(d,Z(c.removeClass,"-remove")));d.length&&(c.preparationClasses=d,a.addClass(d))}function pa(a,b){var c=b?"-"+b+"s":"";la(a,[ma,c]);return[ma,c]}function va(a,b){var c=b?"paused":"",d=aa+"PlayState";la(a,[d,c]);return[d,c]}function la(a,
|
||||
b){a.style[b[0]]=b[1]}function $(a,b){return a?b?a+" "+b:a:b}function Ha(a,b,c){var d=Object.create(null),e=a.getComputedStyle(b)||{};s(c,function(a,b){var c=e[a];if(c){var g=c.charAt(0);if("-"===g||"+"===g||0<=g)c=Ta(c);0===c&&(c=null);d[b]=c}});return d}function Ta(a){var b=0;a=a.split(/\s*,\s*/);s(a,function(a){"s"==a.charAt(a.length-1)&&(a=a.substring(0,a.length-1));a=parseFloat(a)||0;b=b?Math.max(a,b):a});return b}function wa(a){return 0===a||null!=a}function Ia(a,b){var c=S,d=a+"s";b?c+="Duration":
|
||||
d+=" linear all";return[c,d]}function Ja(){var a=Object.create(null);return{flush:function(){a=Object.create(null)},count:function(b){return(b=a[b])?b.total:0},get:function(b){return(b=a[b])&&b.value},put:function(b,c){a[b]?a[b].total++:a[b]={total:1,value:c}}}}function Ka(a,b,c){s(c,function(c){a[c]=xa(a[c])?a[c]:b.style.getPropertyValue(c)})}var S,ya,aa,za;void 0===R.ontransitionend&&void 0!==R.onwebkittransitionend?(S="WebkitTransition",ya="webkitTransitionEnd transitionend"):(S="transition",ya=
|
||||
"transitionend");void 0===R.onanimationend&&void 0!==R.onwebkitanimationend?(aa="WebkitAnimation",za="webkitAnimationEnd animationend"):(aa="animation",za="animationend");var qa=aa+"Delay",Aa=aa+"Duration",ma=S+"Delay",La=S+"Duration",Ma=B.$$minErr("ng"),Ua={transitionDuration:La,transitionDelay:ma,transitionProperty:S+"Property",animationDuration:Aa,animationDelay:qa,animationIterationCount:aa+"IterationCount"},Va={transitionDuration:La,transitionDelay:ma,animationDuration:Aa,animationDelay:qa},
|
||||
Ba,ua,s,Y,xa,ea,Ca,ba,G,J,F,P;B.module("ngAnimate",[],function(){P=B.noop;Ba=B.copy;ua=B.extend;F=B.element;s=B.forEach;Y=B.isArray;G=B.isString;ba=B.isObject;J=B.isUndefined;xa=B.isDefined;Ca=B.isFunction;ea=B.isElement}).directive("ngAnimateSwap",["$animate","$rootScope",function(a,b){return{restrict:"A",transclude:"element",terminal:!0,priority:600,link:function(b,d,e,l,n){var I,g;b.$watchCollection(e.ngAnimateSwap||e["for"],function(e){I&&a.leave(I);g&&(g.$destroy(),g=null);if(e||0===e)g=b.$new(),
|
||||
n(g,function(b){I=b;a.enter(b,null,d)})})}}}]).directive("ngAnimateChildren",["$interpolate",function(a){return{link:function(b,c,d){function e(a){c.data("$$ngAnimateChildren","on"===a||"true"===a)}var l=d.ngAnimateChildren;G(l)&&0===l.length?c.data("$$ngAnimateChildren",!0):(e(a(l)(b)),d.$observe("ngAnimateChildren",e))}}}]).factory("$$rAFScheduler",["$$rAF",function(a){function b(a){d=d.concat(a);c()}function c(){if(d.length){for(var b=d.shift(),n=0;n<b.length;n++)b[n]();e||a(function(){e||c()})}}
|
||||
var d,e;d=b.queue=[];b.waitUntilQuiet=function(b){e&&e();e=a(function(){e=null;b();c()})};return b}]).provider("$$animateQueue",["$animateProvider",function(a){function b(a){if(!a)return null;a=a.split(" ");var b=Object.create(null);s(a,function(a){b[a]=!0});return b}function c(a,c){if(a&&c){var d=b(c);return a.split(" ").some(function(a){return d[a]})}}function d(a,b,c,d){return l[a].some(function(a){return a(b,c,d)})}function e(a,b){var c=0<(a.addClass||"").length,d=0<(a.removeClass||"").length;
|
||||
return b?c&&d:c||d}var l=this.rules={skip:[],cancel:[],join:[]};l.join.push(function(a,b,c){return!b.structural&&e(b)});l.skip.push(function(a,b,c){return!b.structural&&!e(b)});l.skip.push(function(a,b,c){return"leave"==c.event&&b.structural});l.skip.push(function(a,b,c){return c.structural&&2===c.state&&!b.structural});l.cancel.push(function(a,b,c){return c.structural&&b.structural});l.cancel.push(function(a,b,c){return 2===c.state&&b.structural});l.cancel.push(function(a,b,d){if(d.structural)return!1;
|
||||
a=b.addClass;b=b.removeClass;var e=d.addClass;d=d.removeClass;return J(a)&&J(b)||J(e)&&J(d)?!1:c(a,d)||c(b,e)});this.$get=["$$rAF","$rootScope","$rootElement","$document","$$HashMap","$$animation","$$AnimateRunner","$templateRequest","$$jqLite","$$forceReflow",function(b,c,g,l,C,Wa,Q,t,H,T){function O(){var a=!1;return function(b){a?b():c.$$postDigest(function(){a=!0;b()})}}function x(a,b,c){var f=y(b),d=y(a),N=[];(a=h[c])&&s(a,function(a){w.call(a.node,f)?N.push(a.callback):"leave"===c&&w.call(a.node,
|
||||
d)&&N.push(a.callback)});return N}function r(a,b,c){var f=ta(b);return a.filter(function(a){return!(a.node===f&&(!c||a.callback===c))})}function p(a,h,v){function r(c,f,d,h){sa(function(){var c=x(T,a,f);c.length?b(function(){s(c,function(b){b(a,d,h)});"close"!==d||a[0].parentNode||ra.off(a)}):"close"!==d||a[0].parentNode||ra.off(a)});c.progress(f,d,h)}function k(b){var c=a,f=m;f.preparationClasses&&(c.removeClass(f.preparationClasses),f.preparationClasses=null);f.activeClasses&&(c.removeClass(f.activeClasses),
|
||||
f.activeClasses=null);E(a,m);ha(a,m);m.domOperation();A.complete(!b)}var m=Ba(v),p,T;if(a=Oa(a))p=y(a),T=a.parent();var m=oa(m),A=new Q,sa=O();Y(m.addClass)&&(m.addClass=m.addClass.join(" "));m.addClass&&!G(m.addClass)&&(m.addClass=null);Y(m.removeClass)&&(m.removeClass=m.removeClass.join(" "));m.removeClass&&!G(m.removeClass)&&(m.removeClass=null);m.from&&!ba(m.from)&&(m.from=null);m.to&&!ba(m.to)&&(m.to=null);if(!p)return k(),A;v=[p.className,m.addClass,m.removeClass].join(" ");if(!Xa(v))return k(),
|
||||
A;var g=0<=["enter","move","leave"].indexOf(h),w=l[0].hidden,t=!f||w||N.get(p);v=!t&&z.get(p)||{};var H=!!v.state;t||H&&1==v.state||(t=!M(a,T,h));if(t)return w&&r(A,h,"start"),k(),w&&r(A,h,"close"),A;g&&K(a);w={structural:g,element:a,event:h,addClass:m.addClass,removeClass:m.removeClass,close:k,options:m,runner:A};if(H){if(d("skip",a,w,v)){if(2===v.state)return k(),A;W(a,v,w);return v.runner}if(d("cancel",a,w,v))if(2===v.state)v.runner.end();else if(v.structural)v.close();else return W(a,v,w),v.runner;
|
||||
else if(d("join",a,w,v))if(2===v.state)W(a,w,{});else return Sa(a,g?h:null,m),h=w.event=v.event,m=W(a,v,w),v.runner}else W(a,w,{});(H=w.structural)||(H="animate"===w.event&&0<Object.keys(w.options.to||{}).length||e(w));if(!H)return k(),ka(a),A;var C=(v.counter||0)+1;w.counter=C;L(a,1,w);c.$$postDigest(function(){var b=z.get(p),c=!b,b=b||{},f=0<(a.parent()||[]).length&&("animate"===b.event||b.structural||e(b));if(c||b.counter!==C||!f){c&&(E(a,m),ha(a,m));if(c||g&&b.event!==h)m.domOperation(),A.end();
|
||||
f||ka(a)}else h=!b.structural&&e(b,!0)?"setClass":b.event,L(a,2),b=Wa(a,h,b.options),A.setHost(b),r(A,h,"start",{}),b.done(function(b){k(!b);(b=z.get(p))&&b.counter===C&&ka(y(a));r(A,h,"close",{})})});return A}function K(a){a=y(a).querySelectorAll("[data-ng-animate]");s(a,function(a){var b=parseInt(a.getAttribute("data-ng-animate")),c=z.get(a);if(c)switch(b){case 2:c.runner.end();case 1:z.remove(a)}})}function ka(a){a=y(a);a.removeAttribute("data-ng-animate");z.remove(a)}function k(a,b){return y(a)===
|
||||
y(b)}function M(a,b,c){c=F(l[0].body);var f=k(a,c)||"HTML"===a[0].nodeName,d=k(a,g),h=!1,r,e=N.get(y(a));(a=F.data(a[0],"$ngAnimatePin"))&&(b=a);for(b=y(b);b;){d||(d=k(b,g));if(1!==b.nodeType)break;a=z.get(b)||{};if(!h){var p=N.get(b);if(!0===p&&!1!==e){e=!0;break}else!1===p&&(e=!1);h=a.structural}if(J(r)||!0===r)a=F.data(b,"$$ngAnimateChildren"),xa(a)&&(r=a);if(h&&!1===r)break;f||(f=k(b,c));if(f&&d)break;if(!d&&(a=F.data(b,"$ngAnimatePin"))){b=y(a);continue}b=b.parentNode}return(!h||r)&&!0!==e&&
|
||||
d&&f}function L(a,b,c){c=c||{};c.state=b;a=y(a);a.setAttribute("data-ng-animate",b);c=(b=z.get(a))?ua(b,c):c;z.put(a,c)}var z=new C,N=new C,f=null,A=c.$watch(function(){return 0===t.totalPendingRequests},function(a){a&&(A(),c.$$postDigest(function(){c.$$postDigest(function(){null===f&&(f=!0)})}))}),h=Object.create(null),sa=a.classNameFilter(),Xa=sa?function(a){return sa.test(a)}:function(){return!0},E=V(H),w=R.Node.prototype.contains||function(a){return this===a||!!(this.compareDocumentPosition(a)&
|
||||
16)},ra={on:function(a,b,c){var f=ta(b);h[a]=h[a]||[];h[a].push({node:f,callback:c});F(b).on("$destroy",function(){z.get(f)||ra.off(a,b,c)})},off:function(a,b,c){if(1!==arguments.length||G(arguments[0])){var f=h[a];f&&(h[a]=1===arguments.length?null:r(f,b,c))}else for(f in b=arguments[0],h)h[f]=r(h[f],b)},pin:function(a,b){Da(ea(a),"element","not an element");Da(ea(b),"parentElement","not an element");a.data("$ngAnimatePin",b)},push:function(a,b,c,f){c=c||{};c.domOperation=f;return p(a,b,c)},enabled:function(a,
|
||||
b){var c=arguments.length;if(0===c)b=!!f;else if(ea(a)){var d=y(a);1===c?b=!N.get(d):N.put(d,!b)}else b=f=!!a;return b}};return ra}]}]).provider("$$animation",["$animateProvider",function(a){var b=this.drivers=[];this.$get=["$$jqLite","$rootScope","$injector","$$AnimateRunner","$$HashMap","$$rAFScheduler",function(a,d,e,l,n,I){function g(a){function b(a){if(a.processed)return a;a.processed=!0;var d=a.domNode,p=d.parentNode;e.put(d,a);for(var K;p;){if(K=e.get(p)){K.processed||(K=b(K));break}p=p.parentNode}(K||
|
||||
c).children.push(a);return a}var c={children:[]},d,e=new n;for(d=0;d<a.length;d++){var g=a[d];e.put(g.domNode,a[d]={domNode:g.domNode,fn:g.fn,children:[]})}for(d=0;d<a.length;d++)b(a[d]);return function(a){var b=[],c=[],d;for(d=0;d<a.children.length;d++)c.push(a.children[d]);a=c.length;var e=0,k=[];for(d=0;d<c.length;d++){var g=c[d];0>=a&&(a=e,e=0,b.push(k),k=[]);k.push(g.fn);g.children.forEach(function(a){e++;c.push(a)});a--}k.length&&b.push(k);return b}(c)}var u=[],C=V(a);return function(n,Q,t){function H(a){a=
|
||||
a.hasAttribute("ng-animate-ref")?[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];s(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function T(a){var b=[],c={};s(a,function(a,d){var h=y(a.element),e=0<=["enter","move"].indexOf(a.event),h=a.structural?H(h):[];if(h.length){var k=e?"to":"from";s(h,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][k]={animationID:d,element:F(a)}})}else b.push(a)});var d={},e={};s(c,function(c,k){var r=c.from,
|
||||
p=c.to;if(r&&p){var z=a[r.animationID],g=a[p.animationID],A=r.animationID.toString();if(!e[A]){var n=e[A]={structural:!0,beforeStart:function(){z.beforeStart();g.beforeStart()},close:function(){z.close();g.close()},classes:O(z.classes,g.classes),from:z,to:g,anchors:[]};n.classes.length?b.push(n):(b.push(z),b.push(g))}e[A].anchors.push({out:r.element,"in":p.element})}else r=r?r.animationID:p.animationID,p=r.toString(),d[p]||(d[p]=!0,b.push(a[r]))});return b}function O(a,b){a=a.split(" ");b=b.split(" ");
|
||||
for(var c=[],d=0;d<a.length;d++){var e=a[d];if("ng-"!==e.substring(0,3))for(var r=0;r<b.length;r++)if(e===b[r]){c.push(e);break}}return c.join(" ")}function x(a){for(var c=b.length-1;0<=c;c--){var d=e.get(b[c])(a);if(d)return d}}function r(a,b){function c(a){(a=a.data("$$animationRunner"))&&a.setHost(b)}a.from&&a.to?(c(a.from.element),c(a.to.element)):c(a.element)}function p(){var a=n.data("$$animationRunner");!a||"leave"===Q&&t.$$domOperationFired||a.end()}function K(b){n.off("$destroy",p);n.removeData("$$animationRunner");
|
||||
C(n,t);ha(n,t);t.domOperation();L&&a.removeClass(n,L);n.removeClass("ng-animate");k.complete(!b)}t=oa(t);var ka=0<=["enter","move","leave"].indexOf(Q),k=new l({end:function(){K()},cancel:function(){K(!0)}});if(!b.length)return K(),k;n.data("$$animationRunner",k);var M=Ea(n.attr("class"),Ea(t.addClass,t.removeClass)),L=t.tempClasses;L&&(M+=" "+L,t.tempClasses=null);var z;ka&&(z="ng-"+Q+"-prepare",a.addClass(n,z));u.push({element:n,classes:M,event:Q,structural:ka,options:t,beforeStart:function(){n.addClass("ng-animate");
|
||||
L&&a.addClass(n,L);z&&(a.removeClass(n,z),z=null)},close:K});n.on("$destroy",p);if(1<u.length)return k;d.$$postDigest(function(){var a=[];s(u,function(b){b.element.data("$$animationRunner")?a.push(b):b.close()});u.length=0;var b=T(a),c=[];s(b,function(a){c.push({domNode:y(a.from?a.from.element:a.element),fn:function(){a.beforeStart();var b,c=a.close;if((a.anchors?a.from.element||a.to.element:a.element).data("$$animationRunner")){var d=x(a);d&&(b=d.start)}b?(b=b(),b.done(function(a){c(!a)}),r(a,b)):
|
||||
c()}})});I(g(c))});return k}}]}]).provider("$animateCss",["$animateProvider",function(a){var b=Ja(),c=Ja();this.$get=["$window","$$jqLite","$$AnimateRunner","$timeout","$$forceReflow","$sniffer","$$rAFScheduler","$$animateQueue",function(a,e,l,n,I,g,u,C){function B(a,b){var c=a.parentNode;return(c.$$ngAnimateParentKey||(c.$$ngAnimateParentKey=++O))+"-"+a.getAttribute("class")+"-"+b}function Q(r,p,g,n){var k;0<b.count(g)&&(k=c.get(g),k||(p=Z(p,"-stagger"),e.addClass(r,p),k=Ha(a,r,n),k.animationDuration=
|
||||
Math.max(k.animationDuration,0),k.transitionDuration=Math.max(k.transitionDuration,0),e.removeClass(r,p),c.put(g,k)));return k||{}}function t(a){x.push(a);u.waitUntilQuiet(function(){b.flush();c.flush();for(var a=I(),d=0;d<x.length;d++)x[d](a);x.length=0})}function H(c,e,g){e=b.get(g);e||(e=Ha(a,c,Ua),"infinite"===e.animationIterationCount&&(e.animationIterationCount=1));b.put(g,e);c=e;g=c.animationDelay;e=c.transitionDelay;c.maxDelay=g&&e?Math.max(g,e):g||e;c.maxDuration=Math.max(c.animationDuration*
|
||||
c.animationIterationCount,c.transitionDuration);return c}var T=V(e),O=0,x=[];return function(a,c){function d(){k()}function u(){k(!0)}function k(b){if(!(w||F&&O)){w=!0;O=!1;f.$$skipPreparationClasses||e.removeClass(a,ga);e.removeClass(a,ea);va(h,!1);pa(h,!1);s(x,function(a){h.style[a[0]]=""});T(a,f);ha(a,f);Object.keys(A).length&&s(A,function(a,b){a?h.style.setProperty(b,a):h.style.removeProperty(b)});if(f.onDone)f.onDone();fa&&fa.length&&a.off(fa.join(" "),z);var c=a.data("$$animateCss");c&&(n.cancel(c[0].timer),
|
||||
a.removeData("$$animateCss"));G&&G.complete(!b)}}function M(a){q.blockTransition&&pa(h,a);q.blockKeyframeAnimation&&va(h,!!a)}function L(){G=new l({end:d,cancel:u});t(P);k();return{$$willAnimate:!1,start:function(){return G},end:d}}function z(a){a.stopPropagation();var b=a.originalEvent||a;a=b.$manualTimeStamp||Date.now();b=parseFloat(b.elapsedTime.toFixed(3));Math.max(a-W,0)>=R&&b>=m&&(F=!0,k())}function N(){function b(){if(!w){M(!1);s(x,function(a){h.style[a[0]]=a[1]});T(a,f);e.addClass(a,ea);if(q.recalculateTimingStyles){na=
|
||||
h.className+" "+ga;ia=B(h,na);D=H(h,na,ia);ca=D.maxDelay;J=Math.max(ca,0);m=D.maxDuration;if(0===m){k();return}q.hasTransitions=0<D.transitionDuration;q.hasAnimations=0<D.animationDuration}q.applyAnimationDelay&&(ca="boolean"!==typeof f.delay&&wa(f.delay)?parseFloat(f.delay):ca,J=Math.max(ca,0),D.animationDelay=ca,da=[qa,ca+"s"],x.push(da),h.style[da[0]]=da[1]);R=1E3*J;V=1E3*m;if(f.easing){var d,g=f.easing;q.hasTransitions&&(d=S+"TimingFunction",x.push([d,g]),h.style[d]=g);q.hasAnimations&&(d=aa+
|
||||
"TimingFunction",x.push([d,g]),h.style[d]=g)}D.transitionDuration&&fa.push(ya);D.animationDuration&&fa.push(za);W=Date.now();var p=R+1.5*V;d=W+p;var g=a.data("$$animateCss")||[],N=!0;if(g.length){var l=g[0];(N=d>l.expectedEndTime)?n.cancel(l.timer):g.push(k)}N&&(p=n(c,p,!1),g[0]={timer:p,expectedEndTime:d},g.push(k),a.data("$$animateCss",g));if(fa.length)a.on(fa.join(" "),z);f.to&&(f.cleanupStyles&&Ka(A,h,Object.keys(f.to)),Ga(a,f))}}function c(){var b=a.data("$$animateCss");if(b){for(var d=1;d<b.length;d++)b[d]();
|
||||
a.removeData("$$animateCss")}}if(!w)if(h.parentNode){var d=function(a){if(F)O&&a&&(O=!1,k());else if(O=!a,D.animationDuration)if(a=va(h,O),O)x.push(a);else{var b=x,c=b.indexOf(a);0<=a&&b.splice(c,1)}},g=0<ba&&(D.transitionDuration&&0===X.transitionDuration||D.animationDuration&&0===X.animationDuration)&&Math.max(X.animationDelay,X.transitionDelay);g?n(b,Math.floor(g*ba*1E3),!1):b();v.resume=function(){d(!0)};v.pause=function(){d(!1)}}else k()}var f=c||{};f.$$prepared||(f=oa(Ba(f)));var A={},h=y(a);
|
||||
if(!h||!h.parentNode||!C.enabled())return L();var x=[],I=a.attr("class"),E=Na(f),w,O,F,G,v,J,R,m,V,W,fa=[];if(0===f.duration||!g.animations&&!g.transitions)return L();var ja=f.event&&Y(f.event)?f.event.join(" "):f.event,$="",U="";ja&&f.structural?$=Z(ja,"ng-",!0):ja&&($=ja);f.addClass&&(U+=Z(f.addClass,"-add"));f.removeClass&&(U.length&&(U+=" "),U+=Z(f.removeClass,"-remove"));f.applyClassesEarly&&U.length&&T(a,f);var ga=[$,U].join(" ").trim(),na=I+" "+ga,ea=Z(ga,"-active"),I=E.to&&0<Object.keys(E.to).length;
|
||||
if(!(0<(f.keyframeStyle||"").length||I||ga))return L();var ia,X;0<f.stagger?(E=parseFloat(f.stagger),X={transitionDelay:E,animationDelay:E,transitionDuration:0,animationDuration:0}):(ia=B(h,na),X=Q(h,ga,ia,Va));f.$$skipPreparationClasses||e.addClass(a,ga);f.transitionStyle&&(E=[S,f.transitionStyle],la(h,E),x.push(E));0<=f.duration&&(E=0<h.style[S].length,E=Ia(f.duration,E),la(h,E),x.push(E));f.keyframeStyle&&(E=[aa,f.keyframeStyle],la(h,E),x.push(E));var ba=X?0<=f.staggerIndex?f.staggerIndex:b.count(ia):
|
||||
0;(ja=0===ba)&&!f.skipBlocking&&pa(h,9999);var D=H(h,na,ia),ca=D.maxDelay;J=Math.max(ca,0);m=D.maxDuration;var q={};q.hasTransitions=0<D.transitionDuration;q.hasAnimations=0<D.animationDuration;q.hasTransitionAll=q.hasTransitions&&"all"==D.transitionProperty;q.applyTransitionDuration=I&&(q.hasTransitions&&!q.hasTransitionAll||q.hasAnimations&&!q.hasTransitions);q.applyAnimationDuration=f.duration&&q.hasAnimations;q.applyTransitionDelay=wa(f.delay)&&(q.applyTransitionDuration||q.hasTransitions);q.applyAnimationDelay=
|
||||
wa(f.delay)&&q.hasAnimations;q.recalculateTimingStyles=0<U.length;if(q.applyTransitionDuration||q.applyAnimationDuration)m=f.duration?parseFloat(f.duration):m,q.applyTransitionDuration&&(q.hasTransitions=!0,D.transitionDuration=m,E=0<h.style[S+"Property"].length,x.push(Ia(m,E))),q.applyAnimationDuration&&(q.hasAnimations=!0,D.animationDuration=m,x.push([Aa,m+"s"]));if(0===m&&!q.recalculateTimingStyles)return L();if(null!=f.delay){var da;"boolean"!==typeof f.delay&&(da=parseFloat(f.delay),J=Math.max(da,
|
||||
0));q.applyTransitionDelay&&x.push([ma,da+"s"]);q.applyAnimationDelay&&x.push([qa,da+"s"])}null==f.duration&&0<D.transitionDuration&&(q.recalculateTimingStyles=q.recalculateTimingStyles||ja);R=1E3*J;V=1E3*m;f.skipBlocking||(q.blockTransition=0<D.transitionDuration,q.blockKeyframeAnimation=0<D.animationDuration&&0<X.animationDelay&&0===X.animationDuration);f.from&&(f.cleanupStyles&&Ka(A,h,Object.keys(f.from)),Fa(a,f));q.blockTransition||q.blockKeyframeAnimation?M(m):f.skipBlocking||pa(h,!1);return{$$willAnimate:!0,
|
||||
end:d,start:function(){if(!w)return v={end:d,cancel:u,resume:null,pause:null},G=new l(v),t(N),G}}}}]}]).provider("$$animateCssDriver",["$$animationProvider",function(a){a.drivers.push("$$animateCssDriver");this.$get=["$animateCss","$rootScope","$$AnimateRunner","$rootElement","$sniffer","$$jqLite","$document",function(a,c,d,e,l,n,I){function g(a){return a.replace(/\bng-\S+\b/g,"")}function u(a,b){G(a)&&(a=a.split(" "));G(b)&&(b=b.split(" "));return a.filter(function(a){return-1===b.indexOf(a)}).join(" ")}
|
||||
function C(c,e,n){function l(a){var b={},c=y(a).getBoundingClientRect();s(["width","height","top","left"],function(a){var d=c[a];switch(a){case "top":d+=t.scrollTop;break;case "left":d+=t.scrollLeft}b[a]=Math.floor(d)+"px"});return b}function p(){var c=g(n.attr("class")||""),d=u(c,k),c=u(k,c),d=a(C,{to:l(n),addClass:"ng-anchor-in "+d,removeClass:"ng-anchor-out "+c,delay:!0});return d.$$willAnimate?d:null}function I(){C.remove();e.removeClass("ng-animate-shim");n.removeClass("ng-animate-shim")}var C=
|
||||
F(y(e).cloneNode(!0)),k=g(C.attr("class")||"");e.addClass("ng-animate-shim");n.addClass("ng-animate-shim");C.addClass("ng-anchor");H.append(C);var M;c=function(){var c=a(C,{addClass:"ng-anchor-out",delay:!0,from:l(e)});return c.$$willAnimate?c:null}();if(!c&&(M=p(),!M))return I();var L=c||M;return{start:function(){function a(){c&&c.end()}var b,c=L.start();c.done(function(){c=null;if(!M&&(M=p()))return c=M.start(),c.done(function(){c=null;I();b.complete()}),c;I();b.complete()});return b=new d({end:a,
|
||||
cancel:a})}}}function B(a,b,c,e){var g=Q(a,P),n=Q(b,P),l=[];s(e,function(a){(a=C(c,a.out,a["in"]))&&l.push(a)});if(g||n||0!==l.length)return{start:function(){function a(){s(b,function(a){a.end()})}var b=[];g&&b.push(g.start());n&&b.push(n.start());s(l,function(a){b.push(a.start())});var c=new d({end:a,cancel:a});d.all(b,function(a){c.complete(a)});return c}}}function Q(c){var d=c.element,e=c.options||{};c.structural&&(e.event=c.event,e.structural=!0,e.applyClassesEarly=!0,"leave"===c.event&&(e.onDone=
|
||||
e.domOperation));e.preparationClasses&&(e.event=$(e.event,e.preparationClasses));c=a(d,e);return c.$$willAnimate?c:null}if(!l.animations&&!l.transitions)return P;var t=I[0].body;c=y(e);var H=F(c.parentNode&&11===c.parentNode.nodeType||t.contains(c)?c:t);V(n);return function(a){return a.from&&a.to?B(a.from,a.to,a.classes,a.anchors):Q(a)}}]}]).provider("$$animateJs",["$animateProvider",function(a){this.$get=["$injector","$$AnimateRunner","$$jqLite",function(b,c,d){function e(c){c=Y(c)?c:c.split(" ");
|
||||
for(var d=[],e={},l=0;l<c.length;l++){var s=c[l],B=a.$$registeredAnimations[s];B&&!e[s]&&(d.push(b.get(B)),e[s]=!0)}return d}var l=V(d);return function(a,b,d,u){function C(){u.domOperation();l(a,u)}function B(a,b,d,e,f){switch(d){case "animate":b=[b,e.from,e.to,f];break;case "setClass":b=[b,F,G,f];break;case "addClass":b=[b,F,f];break;case "removeClass":b=[b,G,f];break;default:b=[b,f]}b.push(e);if(a=a.apply(a,b))if(Ca(a.start)&&(a=a.start()),a instanceof c)a.done(f);else if(Ca(a))return a;return P}
|
||||
function y(a,b,d,e,f){var g=[];s(e,function(e){var k=e[f];k&&g.push(function(){var e,f,g=!1,h=function(a){g||(g=!0,(f||P)(a),e.complete(!a))};e=new c({end:function(){h()},cancel:function(){h(!0)}});f=B(k,a,b,d,function(a){h(!1===a)});return e})});return g}function t(a,b,d,e,f){var g=y(a,b,d,e,f);if(0===g.length){var h,k;"beforeSetClass"===f?(h=y(a,"removeClass",d,e,"beforeRemoveClass"),k=y(a,"addClass",d,e,"beforeAddClass")):"setClass"===f&&(h=y(a,"removeClass",d,e,"removeClass"),k=y(a,"addClass",
|
||||
d,e,"addClass"));h&&(g=g.concat(h));k&&(g=g.concat(k))}if(0!==g.length)return function(a){var b=[];g.length&&s(g,function(a){b.push(a())});b.length?c.all(b,a):a();return function(a){s(b,function(b){a?b.cancel():b.end()})}}}var H=!1;3===arguments.length&&ba(d)&&(u=d,d=null);u=oa(u);d||(d=a.attr("class")||"",u.addClass&&(d+=" "+u.addClass),u.removeClass&&(d+=" "+u.removeClass));var F=u.addClass,G=u.removeClass,x=e(d),r,p;if(x.length){var K,J;"leave"==b?(J="leave",K="afterLeave"):(J="before"+b.charAt(0).toUpperCase()+
|
||||
b.substr(1),K=b);"enter"!==b&&"move"!==b&&(r=t(a,b,u,x,J));p=t(a,b,u,x,K)}if(r||p){var k;return{$$willAnimate:!0,end:function(){k?k.end():(H=!0,C(),ha(a,u),k=new c,k.complete(!0));return k},start:function(){function b(c){H=!0;C();ha(a,u);k.complete(c)}if(k)return k;k=new c;var d,e=[];r&&e.push(function(a){d=r(a)});e.length?e.push(function(a){C();a(!0)}):C();p&&e.push(function(a){d=p(a)});k.setHost({end:function(){H||((d||P)(void 0),b(void 0))},cancel:function(){H||((d||P)(!0),b(!0))}});c.chain(e,
|
||||
b);return k}}}}}]}]).provider("$$animateJsDriver",["$$animationProvider",function(a){a.drivers.push("$$animateJsDriver");this.$get=["$$animateJs","$$AnimateRunner",function(a,c){function d(c){return a(c.element,c.event,c.classes,c.options)}return function(a){if(a.from&&a.to){var b=d(a.from),n=d(a.to);if(b||n)return{start:function(){function a(){return function(){s(d,function(a){a.end()})}}var d=[];b&&d.push(b.start());n&&d.push(n.start());c.all(d,function(a){e.complete(a)});var e=new c({end:a(),cancel:a()});
|
||||
return e}}}else return d(a)}}]}])})(window,window.angular);
|
||||
//# sourceMappingURL=angular-animate.min.js.map
|
||||
+8
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
!function(){"use strict";angular.module("base64",[]).constant("$base64",function(){function a(a,b){var c=f.indexOf(a.charAt(b));if(-1==c)throw"Cannot decode base64";return c}function b(b){b=""+b;var c,d,f,g=b.length;if(0==g)return b;if(0!=g%4)throw"Cannot decode base64";c=0,b.charAt(g-1)==e&&(c=1,b.charAt(g-2)==e&&(c=2),g-=4);var h=[];for(d=0;g>d;d+=4)f=a(b,d)<<18|a(b,d+1)<<12|a(b,d+2)<<6|a(b,d+3),h.push(String.fromCharCode(f>>16,255&f>>8,255&f));switch(c){case 1:f=a(b,d)<<18|a(b,d+1)<<12|a(b,d+2)<<6,h.push(String.fromCharCode(f>>16,255&f>>8));break;case 2:f=a(b,d)<<18|a(b,d+1)<<12,h.push(String.fromCharCode(f>>16))}return h.join("")}function c(a,b){var c=a.charCodeAt(b);if(c>255)throw"INVALID_CHARACTER_ERR: DOM Exception 5";return c}function d(a){if(1!=arguments.length)throw"SyntaxError: Not enough arguments";var b,d,g=[];a=""+a;var h=a.length-a.length%3;if(0==a.length)return a;for(b=0;h>b;b+=3)d=c(a,b)<<16|c(a,b+1)<<8|c(a,b+2),g.push(f.charAt(d>>18)),g.push(f.charAt(63&d>>12)),g.push(f.charAt(63&d>>6)),g.push(f.charAt(63&d));switch(a.length-h){case 1:d=c(a,b)<<16,g.push(f.charAt(d>>18)+f.charAt(63&d>>12)+e+e);break;case 2:d=c(a,b)<<16|c(a,b+1)<<8,g.push(f.charAt(d>>18)+f.charAt(63&d>>12)+f.charAt(63&d>>6)+e)}return g.join("")}var e="=",f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";return{encode:d,decode:b}}())}();
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
"use strict";
|
||||
|
||||
angular.module("ui.multiselect", ["multiselect.tpl.html"])
|
||||
//from bootstrap-ui typeahead parser
|
||||
.factory("optionParser", ["$parse", function($parse) {
|
||||
// 00000111000000000000022200000000000000003333333333333330000000000044000
|
||||
var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/;
|
||||
|
||||
return {
|
||||
parse: function(input) {
|
||||
|
||||
var match = input.match(TYPEAHEAD_REGEXP);
|
||||
if(!match) {
|
||||
throw new Error("Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_'" + " but got '" + input + "'.");
|
||||
}
|
||||
|
||||
return {
|
||||
itemName : match[3],
|
||||
source : $parse(match[4]),
|
||||
viewMapper : $parse(match[2] || match[1]),
|
||||
modelMapper: $parse(match[1])
|
||||
};
|
||||
}
|
||||
};
|
||||
}])
|
||||
.directive("multiselect", ["$parse", "$document", "$compile", "$interpolate", "optionParser", function($parse, $document, $compile, $interpolate, optionParser) {
|
||||
return {
|
||||
restrict: "E",
|
||||
require : "ngModel",
|
||||
link : function(originalScope, element, attrs, modelCtrl) {
|
||||
|
||||
var exp = attrs.options;
|
||||
var parsedResult = optionParser.parse(exp);
|
||||
var isMultiple = attrs.multiple ? true : false;
|
||||
var compareByKey = attrs.compareBy;
|
||||
var headerKey = attrs.headerKey;
|
||||
var dividerKey = attrs.dividerKey;
|
||||
var scrollAfterRows = attrs.scrollAfterRows;
|
||||
var tabindex = attrs.tabindex;
|
||||
var maxWidth = attrs.maxWidth;
|
||||
var required = false;
|
||||
var scope = originalScope.$new();
|
||||
scope.filterAfterRows = attrs.filterAfterRows;
|
||||
var changeHandler = attrs.change || angular.noop;
|
||||
|
||||
scope.items = [];
|
||||
scope.header = "Select";
|
||||
scope.multiple = isMultiple;
|
||||
scope.disabled = false;
|
||||
|
||||
scope.ulStyle = {};
|
||||
if(scrollAfterRows !== undefined && parseInt(scrollAfterRows).toString() === scrollAfterRows) {
|
||||
scope.ulStyle = {"max-height": (scrollAfterRows*26+14)+"px", "overflow-y": "auto", "overflow-x": "hidden"};
|
||||
}
|
||||
if(tabindex !== undefined && parseInt(tabindex).toString() === tabindex) {
|
||||
scope.tabindex = tabindex;
|
||||
}
|
||||
if(maxWidth !== undefined && parseInt(maxWidth).toString() === maxWidth) {
|
||||
scope.maxWidth = {"max-width": maxWidth + "px"};
|
||||
}
|
||||
|
||||
originalScope.$on("$destroy", function() {
|
||||
scope.$destroy();
|
||||
});
|
||||
|
||||
var popUpEl = angular.element("<multiselect-popup></multiselect-popup>");
|
||||
|
||||
//required validator
|
||||
if(attrs.required || attrs.ngRequired) {
|
||||
required = true;
|
||||
}
|
||||
attrs.$observe("required", function(newVal) {
|
||||
required = newVal;
|
||||
});
|
||||
|
||||
//watch disabled state
|
||||
scope.$watch(function() {
|
||||
return $parse(attrs.ngDisabled)(originalScope);
|
||||
}, function(newVal) {
|
||||
scope.disabled = newVal;
|
||||
});
|
||||
|
||||
//watch single/multiple state for dynamically change single to multiple
|
||||
scope.$watch(function() {
|
||||
return $parse(attrs.multiple)(originalScope);
|
||||
}, function(newVal) {
|
||||
isMultiple = newVal || false;
|
||||
});
|
||||
|
||||
//watch option changes for options that are populated dynamically
|
||||
scope.$watch(function() {
|
||||
return parsedResult.source(originalScope);
|
||||
}, function(newVal) {
|
||||
if(angular.isDefined(newVal)) {
|
||||
parseModel();
|
||||
}
|
||||
}, true);
|
||||
|
||||
//watch model change
|
||||
scope.$watch(function() {
|
||||
return modelCtrl.$modelValue;
|
||||
}, function(newVal, oldVal) {
|
||||
//when directive initialize, newVal usually undefined. Also, if model value already set in the controller
|
||||
//for preselected list then we need to mark checked in our scope item. But we don't want to do this every time
|
||||
//model changes. We need to do this only if it is done outside directive scope, from controller, for example.
|
||||
if(angular.isDefined(newVal)) {
|
||||
markChecked(newVal);
|
||||
scope.$eval(changeHandler);
|
||||
}
|
||||
getHeaderText();
|
||||
modelCtrl.$setValidity("required", scope.valid());
|
||||
});
|
||||
|
||||
function parseModel() {
|
||||
scope.items.length = 0;
|
||||
var model = parsedResult.source(originalScope);
|
||||
if(!angular.isDefined(model) || model === null) {
|
||||
return;
|
||||
}
|
||||
for(var i = 0; i < model.length; i++) {
|
||||
var local = {};
|
||||
local[parsedResult.itemName] = model[i];
|
||||
|
||||
// calculate checked status of the option
|
||||
// https://github.com/sebastianha/angular-bootstrap-multiselect/pull/4/files
|
||||
var id = model[i];
|
||||
var checked = false;
|
||||
var modelValue = modelCtrl.$modelValue;
|
||||
if (modelValue) {
|
||||
if (angular.isArray(modelValue)) {
|
||||
for (var j = 0; j < modelValue.length; j++)
|
||||
if (modelValue[j] == id) {
|
||||
checked = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
checked = modelValue == id;
|
||||
}
|
||||
}
|
||||
|
||||
scope.items.push({
|
||||
label : parsedResult.viewMapper(local),
|
||||
model : model[i],
|
||||
checked: checked,
|
||||
header : model[i][headerKey],
|
||||
divider : model[i][dividerKey]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
parseModel();
|
||||
|
||||
element.append($compile(popUpEl)(scope));
|
||||
|
||||
function getHeaderText() {
|
||||
if(isEmpty(modelCtrl.$modelValue)) {
|
||||
scope.header = attrs.msHeader || "Select";
|
||||
return scope.header;
|
||||
}
|
||||
|
||||
if(isMultiple) {
|
||||
if(attrs.msSelected) {
|
||||
scope.header = $interpolate(attrs.msSelected)(scope);
|
||||
} else {
|
||||
scope.header = modelCtrl.$modelValue.length + " " + "selected";
|
||||
}
|
||||
} else {
|
||||
var local = {};
|
||||
local[parsedResult.itemName] = modelCtrl.$modelValue;
|
||||
scope.header = parsedResult.viewMapper(local);
|
||||
}
|
||||
}
|
||||
|
||||
function isEmpty(obj) {
|
||||
if(obj === true || obj === false) {
|
||||
return false;
|
||||
}
|
||||
if(!obj) {
|
||||
return true;
|
||||
}
|
||||
if(obj.length && obj.length > 0) {
|
||||
return false;
|
||||
}
|
||||
for(var prop in obj) {
|
||||
if(obj[prop]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(compareByKey !== undefined && obj[compareByKey] !== undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
scope.valid = function validModel() {
|
||||
if(!required) {
|
||||
return true;
|
||||
}
|
||||
var value = modelCtrl.$modelValue;
|
||||
return (angular.isArray(value) && value.length > 0) || (!angular.isArray(value) && value !== null);
|
||||
};
|
||||
|
||||
function selectSingle(item) {
|
||||
if(!item.checked) {
|
||||
scope.uncheckAll();
|
||||
item.checked = !item.checked;
|
||||
}
|
||||
setModelValue(false);
|
||||
}
|
||||
|
||||
function selectMultiple(item) {
|
||||
item.checked = !item.checked;
|
||||
setModelValue(true);
|
||||
}
|
||||
|
||||
function setModelValue(isMultiple) {
|
||||
var value;
|
||||
|
||||
if(isMultiple) {
|
||||
value = [];
|
||||
angular.forEach(scope.items, function(item) {
|
||||
if(item.checked) {
|
||||
value.push(item.model);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
angular.forEach(scope.items, function(item) {
|
||||
if(item.checked) {
|
||||
value = item.model;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
modelCtrl.$setViewValue(value);
|
||||
}
|
||||
|
||||
function markChecked(newVal) {
|
||||
if(!angular.isArray(newVal)) {
|
||||
angular.forEach(scope.items, function(item) {
|
||||
item.checked = false;
|
||||
if(compareByKey === undefined && angular.equals(item.model, newVal)) {
|
||||
item.checked = true;
|
||||
} else if(compareByKey !== undefined && newVal !== null && item.model[compareByKey] !== undefined && angular.equals(item.model[compareByKey], newVal[compareByKey])) {
|
||||
item.checked = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
angular.forEach(scope.items, function(item) {
|
||||
item.checked = false;
|
||||
angular.forEach(newVal, function(i) {
|
||||
if(compareByKey === undefined && angular.equals(item.model, i)) {
|
||||
item.checked = true;
|
||||
} else if(compareByKey !== undefined && item.model[compareByKey] !== undefined && angular.equals(item.model[compareByKey], i[compareByKey])) {
|
||||
item.checked = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
scope.checkAll = function() {
|
||||
if(!isMultiple) {
|
||||
return;
|
||||
}
|
||||
angular.forEach(scope.items, function(item) {
|
||||
item.checked = true;
|
||||
});
|
||||
setModelValue(true);
|
||||
};
|
||||
|
||||
scope.uncheckAll = function() {
|
||||
angular.forEach(scope.items, function(item) {
|
||||
item.checked = false;
|
||||
});
|
||||
setModelValue(true);
|
||||
};
|
||||
|
||||
scope.select = function(event, item) {
|
||||
if(isMultiple === false) {
|
||||
selectSingle(item);
|
||||
scope.toggleSelect();
|
||||
} else {
|
||||
event.stopPropagation();
|
||||
selectMultiple(item);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}])
|
||||
.directive("multiselectPopup", ["$document", function($document) {
|
||||
return {
|
||||
restrict : "E",
|
||||
scope : false,
|
||||
replace : true,
|
||||
templateUrl: "multiselect.tpl.html",
|
||||
link : function(scope, element, attrs) {
|
||||
|
||||
scope.isVisible = false;
|
||||
|
||||
scope.toggleSelect = function() {
|
||||
if(element.hasClass("open")) {
|
||||
scope.filter = "";
|
||||
element.removeClass("open");
|
||||
$document.unbind("click", clickHandler);
|
||||
} else {
|
||||
scope.filter = "";
|
||||
element.addClass("open");
|
||||
$document.bind("click", clickHandler);
|
||||
}
|
||||
};
|
||||
|
||||
// $("ul.dropdown-menu").on("click", "[data-stopPropagation]", function(e) {
|
||||
// e.stopPropagation();
|
||||
// });
|
||||
|
||||
function clickHandler(event) {
|
||||
if(elementMatchesAnyInArray(event.target, element.find(event.target.tagName))) {
|
||||
return;
|
||||
}
|
||||
element.removeClass("open");
|
||||
$document.unbind("click", clickHandler);
|
||||
scope.$apply();
|
||||
}
|
||||
|
||||
var elementMatchesAnyInArray = function(element, elementArray) {
|
||||
for(var i = 0; i < elementArray.length; i++) {
|
||||
if(element === elementArray[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
angular.module("multiselect.tpl.html", []).run(["$templateCache", function($templateCache) {
|
||||
$templateCache.put("multiselect.tpl.html",
|
||||
"<div class=\"btn-group\">\n" +
|
||||
" <button tabindex=\"{{tabindex}}\" title=\"{{header}}\" type=\"button\" class=\"btn btn-default dropdown-toggle\" ng-click=\"toggleSelect()\" ng-disabled=\"disabled\" ng-class=\"{'error': !valid()}\">\n" +
|
||||
" <div ng-style=\"maxWidth\" style=\"padding-right: 13px; overflow: hidden; text-overflow: ellipsis;\">{{header}}</div><span class=\"caret\" style=\"position:absolute;right:10px;top:14px;\"></span>\n" +
|
||||
" </button>\n" +
|
||||
" <ul class=\"dropdown-menu\" style=\"margin-bottom:30px;padding-left:5px;padding-right:5px;\" ng-style=\"ulStyle\">\n" +
|
||||
" <input ng-show=\"items.length > filterAfterRows\" ng-model=\"filter\" style=\"padding: 0px 3px;margin-right: 15px; margin-bottom: 4px;\" placeholder=\"Type to filter options\">" +
|
||||
" <li data-stopPropagation=\"true\" ng-repeat=\"i in items | filter:filter\" ng-class=\"{'dropdown-header': i.header, 'divider': i.divider}\">\n" +
|
||||
" <a ng-if=\"!i.header && !i.divider\" ng-click=\"select($event, i)\" style=\"padding:3px 10px;cursor:pointer;\">\n" +
|
||||
" <i class=\"fa\" ng-class=\"{'fa-check': i.checked, 'empty': !i.checked}\"></i> {{i.label}}" +
|
||||
" </a>\n" +
|
||||
" <span ng-if=\"i.header\">{{i.label}}</span>" +
|
||||
" </li>\n" +
|
||||
" </ul>\n" +
|
||||
"</div>");
|
||||
}]);
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(t,e,i,n){"use strict";i.module("ngFitText",[]).value("fitTextDefaultConfig",{debounce:!1,delay:250,loadDelay:10,compressor:1,min:0,max:Number.POSITIVE_INFINITY}).directive("fittext",["$timeout","fitTextDefaultConfig","fitTextConfig",function(e,n,o){return{restrict:"A",scope:!0,link:function(f,a,l){function r(){var t=T*h/s.offsetWidth/h;return Math.max(Math.min((c[0].offsetWidth-6)*t*p,parseFloat(y)),parseFloat(m))}function u(){s.offsetHeight*s.offsetWidth!==0&&(d.fontSize=T+"px",d.lineHeight="1",d.display="inline-block",d.fontSize=r()+"px",d.lineHeight=b,d.display=v)}i.extend(n,o.config);var c=a.parent(),s=a[0],d=s.style,x=t.getComputedStyle(a[0],null),h=a.children().length||1,g=l.fittextLoadDelay||n.loadDelay,p=l.fittext||n.compressor,m=("inherit"===l.fittextMin?x["font-size"]:l.fittextMin)||n.min,y=("inherit"===l.fittextMax?x["font-size"]:l.fittextMax)||n.max,b=x["line-height"],v=x.display,T=10;e(function(){u()},g),f.$watch(l.ngBind,function(){u()}),n.debounce?i.element(t).bind("resize",n.debounce(function(){f.$apply(u)},n.delay)):i.element(t).bind("resize",function(){f.$apply(u)})}}}]).provider("fitTextConfig",function(){var t=this;return this.config={},this.$get=function(){var e={};return e.config=t.config,e},this})}(window,document,angular);
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
AngularJS v1.5.8
|
||||
(c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(){'use strict';function d(b){return function(){var a=arguments[0],e;e="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.5.8/"+(b?b+"/":"")+a;for(a=1;a<arguments.length;a++){e=e+(1==a?"?":"&")+"p"+(a-1)+"=";var d=encodeURIComponent,c;c=arguments[a];c="function"==typeof c?c.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof c?"undefined":"string"!=typeof c?JSON.stringify(c):c;e+=d(c)}return Error(e)}}(function(b){function a(c,a,b){return c[a]||(c[a]=b())}var e=d("$injector"),n=d("ng");
|
||||
b=a(b,"angular",Object);b.$$minErr=b.$$minErr||d;return a(b,"module",function(){var c={};return function(b,d,h){if("hasOwnProperty"===b)throw n("badname","module");d&&c.hasOwnProperty(b)&&(c[b]=null);return a(c,b,function(){function c(a,b,d,e){e||(e=f);return function(){e[d||"push"]([a,b,arguments]);return g}}function a(c,e){return function(a,d){d&&"function"===typeof d&&(d.$$moduleName=b);f.push([c,e,arguments]);return g}}if(!d)throw e("nomod",b);var f=[],k=[],l=[],m=c("$injector","invoke","push",
|
||||
k),g={_invokeQueue:f,_configBlocks:k,_runBlocks:l,requires:d,name:b,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:c("$provide","value"),constant:c("$provide","constant","unshift"),decorator:a("$provide","decorator"),animation:a("$animateProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),component:a("$compileProvider","component"),config:m,run:function(a){l.push(a);
|
||||
return this}};h&&m(h);return g})}})})(window)})(window);
|
||||
//# sourceMappingURL=angular-loader.min.js.map
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version":3,
|
||||
"file":"angular-loader.min.js",
|
||||
"lineCount":9,
|
||||
"mappings":"A;;;;;aAMC,SAAQ,EAAG,CA6DZA,QAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,MAAAA,SAAAA,EAAAA,CAAAA,IAAAA,EAAAA,SAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,GAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,EAAAA,EAAAA,CAAAA,CAAAA,sCAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,EAAAA,EAAAA,CAAAA,KAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,SAAAA,OAAAA,CAAAA,CAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,EAAAA,CAAAA,CAAAA,GAAAA,CAAAA,GAAAA,EAAAA,GAAAA,EAAAA,CAAAA,CAAAA,CAAAA,EAAAA,GAAAA,KAAAA,EAAAA,kBAAAA,CAAAA,CAAAA,EAAAA,CAAAA,SAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,UAAAA,EAAAA,MAAAA,EAAAA,CAAAA,CAAAA,SAAAA,EAAAA,QAAAA,CAAAA,aAAAA,CAAAA,EAAAA,CAAAA,CAAAA,WAAAA,EAAAA,MAAAA,EAAAA,CAAAA,WAAAA,CAAAA,QAAAA,EAAAA,MAAAA,EAAAA,CAAAA,IAAAA,UAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,MAAAA,MAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CA2CAC,SAA0B,CAACC,CAAD,CAAS,CAKjCC,QAASA,EAAM,CAACC,CAAD,CAAMC,CAAN,CAAYC,CAAZ,CAAqB,CAClC,MAAOF,EAAA,CAAIC,CAAJ,CAAP,GAAqBD,CAAA,CAAIC,CAAJ,CAArB,CAAiCC,CAAA,EAAjC,CADkC,CAHpC,IAAIC,EAAkBP,CAAA,CAAO,WAAP,CAAtB,CACIQ,EAAWR,CAAA,CAAO,IAAP,CAMXS;CAAAA,CAAUN,CAAA,CAAOD,CAAP,CAAe,SAAf,CAA0BQ,MAA1B,CAGdD,EAAAE,SAAA,CAAmBF,CAAAE,SAAnB,EAAuCX,CAEvC,OAAOG,EAAA,CAAOM,CAAP,CAAgB,QAAhB,CAA0B,QAAQ,EAAG,CAE1C,IAAIG,EAAU,EAqDd,OAAOC,SAAe,CAACR,CAAD,CAAOS,CAAP,CAAiBC,CAAjB,CAA2B,CAE7C,GAAa,gBAAb,GAKsBV,CALtB,CACE,KAAMG,EAAA,CAAS,SAAT,CAIoBQ,QAJpB,CAAN,CAKAF,CAAJ,EAAgBF,CAAAK,eAAA,CAAuBZ,CAAvB,CAAhB,GACEO,CAAA,CAAQP,CAAR,CADF,CACkB,IADlB,CAGA,OAAOF,EAAA,CAAOS,CAAP,CAAgBP,CAAhB,CAAsB,QAAQ,EAAG,CAuPtCa,QAASA,EAAW,CAACC,CAAD,CAAWC,CAAX,CAAmBC,CAAnB,CAAiCC,CAAjC,CAAwC,CACrDA,CAAL,GAAYA,CAAZ,CAAoBC,CAApB,CACA,OAAO,SAAQ,EAAG,CAChBD,CAAA,CAAMD,CAAN,EAAsB,MAAtB,CAAA,CAA8B,CAACF,CAAD,CAAWC,CAAX,CAAmBI,SAAnB,CAA9B,CACA,OAAOC,EAFS,CAFwC,CAa5DC,QAASA,EAA2B,CAACP,CAAD,CAAWC,CAAX,CAAmB,CACrD,MAAO,SAAQ,CAACO,CAAD,CAAaC,CAAb,CAA8B,CACvCA,CAAJ,EA7b4C,UA6b5C,GA7b2B,MA6bOA,EAAlC,GAAoDA,CAAAC,aAApD,CAAmFxB,CAAnF,CACAkB,EAAAO,KAAA,CAAiB,CAACX,CAAD,CAAWC,CAAX,CAAmBI,SAAnB,CAAjB,CACA,OAAOC,EAHoC,CADQ,CAnQvD,GAAKX,CAAAA,CAAL,CACE,KAAMP,EAAA,CAAgB,OAAhB,CAEiDF,CAFjD,CAAN,CAMF,IAAIkB,EAAc,EAAlB,CAGIQ,EAAe,EAHnB,CAMIC,EAAY,EANhB,CAQIC,EAASf,CAAA,CAAY,WAAZ,CAAyB,QAAzB,CAAmC,MAAnC;AAA2Ca,CAA3C,CARb,CAWIN,EAAiB,CAEnBS,aAAcX,CAFK,CAGnBY,cAAeJ,CAHI,CAInBK,WAAYJ,CAJO,CAenBlB,SAAUA,CAfS,CAyBnBT,KAAMA,CAzBa,CAsCnBc,SAAUO,CAAA,CAA4B,UAA5B,CAAwC,UAAxC,CAtCS,CAiDnBpB,QAASoB,CAAA,CAA4B,UAA5B,CAAwC,SAAxC,CAjDU,CA4DnBW,QAASX,CAAA,CAA4B,UAA5B,CAAwC,SAAxC,CA5DU,CAuEnBY,MAAOpB,CAAA,CAAY,UAAZ,CAAwB,OAAxB,CAvEY,CAmFnBqB,SAAUrB,CAAA,CAAY,UAAZ,CAAwB,UAAxB,CAAoC,SAApC,CAnFS,CA+FnBsB,UAAWd,CAAA,CAA4B,UAA5B,CAAwC,WAAxC,CA/FQ,CAiInBe,UAAWf,CAAA,CAA4B,kBAA5B,CAAgD,UAAhD,CAjIQ,CAmJnBgB,OAAQhB,CAAA,CAA4B,iBAA5B,CAA+C,UAA/C,CAnJW,CA+JnBiB,WAAYjB,CAAA,CAA4B,qBAA5B,CAAmD,UAAnD,CA/JO,CA4KnBkB,UAAWlB,CAAA,CAA4B,kBAA5B,CAAgD,WAAhD,CA5KQ,CAyLnBmB,UAAWnB,CAAA,CAA4B,kBAA5B,CAAgD,WAAhD,CAzLQ,CAsMnBO,OAAQA,CAtMW,CAkNnBa,IAAKA,QAAQ,CAACC,CAAD,CAAQ,CACnBf,CAAAF,KAAA,CAAeiB,CAAf,CACA;MAAO,KAFY,CAlNF,CAwNjBhC,EAAJ,EACEkB,CAAA,CAAOlB,CAAP,CAGF,OAAOU,EA/O+B,CAAjC,CAXwC,CAvDP,CAArC,CAd0B,CAAnCxB,CAiWA,CAAkBC,MAAlB,CAzcY,CAAX,CAAD,CA0cGA,MA1cH;",
|
||||
"sources":["angular-loader.js"],
|
||||
"names":["minErr","setupModuleLoader","window","ensure","obj","name","factory","$injectorMinErr","ngMinErr","angular","Object","$$minErr","modules","module","requires","configFn","context","hasOwnProperty","invokeLater","provider","method","insertMethod","queue","invokeQueue","arguments","moduleInstance","invokeLaterAndSetModuleName","recipeName","factoryFunction","$$moduleName","push","configBlocks","runBlocks","config","_invokeQueue","_configBlocks","_runBlocks","service","value","constant","decorator","animation","filter","controller","directive","component","run","block"]
|
||||
}
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
AngularJS v1.5.8
|
||||
(c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(E,d){'use strict';function y(t,l,g){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(b,e,a,c,k){function p(){m&&(g.cancel(m),m=null);h&&(h.$destroy(),h=null);n&&(m=g.leave(n),m.then(function(){m=null}),n=null)}function B(){var a=t.current&&t.current.locals;if(d.isDefined(a&&a.$template)){var a=b.$new(),c=t.current;n=k(a,function(a){g.enter(a,null,n||e).then(function(){!d.isDefined(A)||A&&!b.$eval(A)||l()});p()});h=c.scope=a;h.$emit("$viewContentLoaded");
|
||||
h.$eval(s)}else p()}var h,n,m,A=a.autoscroll,s=a.onload||"";b.$on("$routeChangeSuccess",B);B()}}}function w(d,l,g){return{restrict:"ECA",priority:-400,link:function(b,e){var a=g.current,c=a.locals;e.html(c.$template);var k=d(e.contents());if(a.controller){c.$scope=b;var p=l(a.controller,c);a.controllerAs&&(b[a.controllerAs]=p);e.data("$ngControllerController",p);e.children().data("$ngControllerController",p)}b[a.resolveAs||"$resolve"]=c;k(b)}}}var x,C,s=d.module("ngRoute",["ng"]).provider("$route",
|
||||
function(){function t(b,e){return d.extend(Object.create(b),e)}function l(b,d){var a=d.caseInsensitiveMatch,c={originalPath:b,regexp:b},g=c.keys=[];b=b.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[\?\*])?/g,function(b,a,d,c){b="?"===c||"*?"===c?"?":null;c="*"===c||"*?"===c?"*":null;g.push({name:d,optional:!!b});a=a||"";return""+(b?"":a)+"(?:"+(b?a:"")+(c&&"(.+?)"||"([^/]+)")+(b||"")+")"+(b||"")}).replace(/([\/$\*])/g,"\\$1");c.regexp=new RegExp("^"+b+"$",a?"i":"");return c}x=d.isArray;C=
|
||||
d.isObject;var g={};this.when=function(b,e){var a;a=void 0;if(x(e)){a=a||[];for(var c=0,k=e.length;c<k;c++)a[c]=e[c]}else if(C(e))for(c in a=a||{},e)if("$"!==c.charAt(0)||"$"!==c.charAt(1))a[c]=e[c];a=a||e;d.isUndefined(a.reloadOnSearch)&&(a.reloadOnSearch=!0);d.isUndefined(a.caseInsensitiveMatch)&&(a.caseInsensitiveMatch=this.caseInsensitiveMatch);g[b]=d.extend(a,b&&l(b,a));b&&(c="/"==b[b.length-1]?b.substr(0,b.length-1):b+"/",g[c]=d.extend({redirectTo:b},l(c,a)));return this};this.caseInsensitiveMatch=
|
||||
!1;this.otherwise=function(b){"string"===typeof b&&(b={redirectTo:b});this.when(null,b);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$templateRequest","$sce",function(b,e,a,c,k,p,l){function h(a){var f=v.current;(x=(r=y())&&f&&r.$$route===f.$$route&&d.equals(r.pathParams,f.pathParams)&&!r.reloadOnSearch&&!z)||!f&&!r||b.$broadcast("$routeChangeStart",r,f).defaultPrevented&&a&&a.preventDefault()}function n(){var u=v.current,f=r;if(x)u.params=f.params,d.copy(u.params,
|
||||
a),b.$broadcast("$routeUpdate",u);else if(f||u)z=!1,(v.current=f)&&f.redirectTo&&(d.isString(f.redirectTo)?e.path(w(f.redirectTo,f.params)).search(f.params).replace():e.url(f.redirectTo(f.pathParams,e.path(),e.search())).replace()),c.when(f).then(m).then(function(c){f==v.current&&(f&&(f.locals=c,d.copy(f.params,a)),b.$broadcast("$routeChangeSuccess",f,u))},function(a){f==v.current&&b.$broadcast("$routeChangeError",f,u,a)})}function m(a){if(a){var b=d.extend({},a.resolve);d.forEach(b,function(a,c){b[c]=
|
||||
d.isString(a)?k.get(a):k.invoke(a,null,null,c)});a=s(a);d.isDefined(a)&&(b.$template=a);return c.all(b)}}function s(a){var b,c;d.isDefined(b=a.template)?d.isFunction(b)&&(b=b(a.params)):d.isDefined(c=a.templateUrl)&&(d.isFunction(c)&&(c=c(a.params)),d.isDefined(c)&&(a.loadedTemplateUrl=l.valueOf(c),b=p(c)));return b}function y(){var a,b;d.forEach(g,function(c,g){var q;if(q=!b){var h=e.path();q=c.keys;var l={};if(c.regexp)if(h=c.regexp.exec(h)){for(var k=1,p=h.length;k<p;++k){var m=q[k-1],n=h[k];m&&
|
||||
n&&(l[m.name]=n)}q=l}else q=null;else q=null;q=a=q}q&&(b=t(c,{params:d.extend({},e.search(),a),pathParams:a}),b.$$route=c)});return b||g[null]&&t(g[null],{params:{},pathParams:{}})}function w(a,b){var c=[];d.forEach((a||"").split(":"),function(a,d){if(0===d)c.push(a);else{var e=a.match(/(\w+)(?:[?*])?(.*)/),g=e[1];c.push(b[g]);c.push(e[2]||"");delete b[g]}});return c.join("")}var z=!1,r,x,v={routes:g,reload:function(){z=!0;var a={defaultPrevented:!1,preventDefault:function(){this.defaultPrevented=
|
||||
!0;z=!1}};b.$evalAsync(function(){h(a);a.defaultPrevented||n()})},updateParams:function(a){if(this.current&&this.current.$$route)a=d.extend({},this.current.params,a),e.path(w(this.current.$$route.originalPath,a)),e.search(a);else throw D("norout");}};b.$on("$locationChangeStart",h);b.$on("$locationChangeSuccess",n);return v}]}),D=d.$$minErr("ngRoute");s.provider("$routeParams",function(){this.$get=function(){return{}}});s.directive("ngView",y);s.directive("ngView",w);y.$inject=["$route","$anchorScroll",
|
||||
"$animate"];w.$inject=["$compile","$controller","$route"]})(window,window.angular);
|
||||
//# sourceMappingURL=angular-route.min.js.map
|
||||
+8
File diff suppressed because one or more lines are too long
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
AngularJS v1.5.8
|
||||
(c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(s,g){'use strict';function H(g){var l=[];t(l,A).chars(g);return l.join("")}var B=g.$$minErr("$sanitize"),C,l,D,E,q,A,F,t;g.module("ngSanitize",[]).provider("$sanitize",function(){function k(a,e){var b={},c=a.split(","),h;for(h=0;h<c.length;h++)b[e?q(c[h]):c[h]]=!0;return b}function I(a){for(var e={},b=0,c=a.length;b<c;b++){var h=a[b];e[h.name]=h.value}return e}function G(a){return a.replace(/&/g,"&").replace(J,function(a){var b=a.charCodeAt(0);a=a.charCodeAt(1);return"&#"+(1024*(b-55296)+
|
||||
(a-56320)+65536)+";"}).replace(K,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"<").replace(/>/g,">")}function u(a){if(a.nodeType===s.Node.ELEMENT_NODE)for(var e=a.attributes,b=0,c=e.length;b<c;b++){var h=e[b],d=h.name.toLowerCase();if("xmlns:ns1"===d||0===d.lastIndexOf("ns1:",0))a.removeAttributeNode(h),b--,c--}(e=a.firstChild)&&u(e);(e=a.nextSibling)&&u(e)}var v=!1;this.$get=["$$sanitizeUri",function(a){v&&l(w,x);return function(e){var b=[];F(e,t(b,function(b,h){return!/^unsafe:/.test(a(b,
|
||||
h))}));return b.join("")}}];this.enableSvg=function(a){return E(a)?(v=a,this):v};C=g.bind;l=g.extend;D=g.forEach;E=g.isDefined;q=g.lowercase;A=g.noop;F=function(a,e){null===a||void 0===a?a="":"string"!==typeof a&&(a=""+a);f.innerHTML=a;var b=5;do{if(0===b)throw B("uinput");b--;s.document.documentMode&&u(f);a=f.innerHTML;f.innerHTML=a}while(a!==f.innerHTML);for(b=f.firstChild;b;){switch(b.nodeType){case 1:e.start(b.nodeName.toLowerCase(),I(b.attributes));break;case 3:e.chars(b.textContent)}var c;if(!(c=
|
||||
b.firstChild)&&(1==b.nodeType&&e.end(b.nodeName.toLowerCase()),c=b.nextSibling,!c))for(;null==c;){b=b.parentNode;if(b===f)break;c=b.nextSibling;1==b.nodeType&&e.end(b.nodeName.toLowerCase())}b=c}for(;b=f.firstChild;)f.removeChild(b)};t=function(a,e){var b=!1,c=C(a,a.push);return{start:function(a,d){a=q(a);!b&&z[a]&&(b=a);b||!0!==w[a]||(c("<"),c(a),D(d,function(b,d){var f=q(d),g="img"===a&&"src"===f||"background"===f;!0!==m[f]||!0===n[f]&&!e(b,g)||(c(" "),c(d),c('="'),c(G(b)),c('"'))}),c(">"))},end:function(a){a=
|
||||
q(a);b||!0!==w[a]||!0===y[a]||(c("</"),c(a),c(">"));a==b&&(b=!1)},chars:function(a){b||c(G(a))}}};var J=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,K=/([^\#-~ |!])/g,y=k("area,br,col,hr,img,wbr"),d=k("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),r=k("rp,rt"),p=l({},r,d),d=l({},d,k("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul")),r=l({},r,k("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")),
|
||||
x=k("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan"),z=k("script,style"),w=l({},y,d,r,p),n=k("background,cite,href,longdesc,src,xlink:href"),p=k("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width"),
|
||||
r=k("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
|
||||
!0),m=l({},n,r,p),f;(function(a){if(a.document&&a.document.implementation)a=a.document.implementation.createHTMLDocument("inert");else throw B("noinert");var e=(a.documentElement||a.getDocumentElement()).getElementsByTagName("body");1===e.length?f=e[0]:(e=a.createElement("html"),f=a.createElement("body"),e.appendChild(f),a.appendChild(e))})(s)});g.module("ngSanitize").filter("linky",["$sanitize",function(k){var l=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
|
||||
q=/^mailto:/i,u=g.$$minErr("linky"),v=g.isDefined,s=g.isFunction,t=g.isObject,y=g.isString;return function(d,g,p){function x(a){a&&m.push(H(a))}function z(a,b){var c,d=w(a);m.push("<a ");for(c in d)m.push(c+'="'+d[c]+'" ');!v(g)||"target"in d||m.push('target="',g,'" ');m.push('href="',a.replace(/"/g,"""),'">');x(b);m.push("</a>")}if(null==d||""===d)return d;if(!y(d))throw u("notstring",d);for(var w=s(p)?p:t(p)?function(){return p}:function(){return{}},n=d,m=[],f,a;d=n.match(l);)f=d[0],d[2]||
|
||||
d[4]||(f=(d[3]?"http://":"mailto:")+f),a=d.index,x(n.substr(0,a)),z(f,d[0].replace(q,"")),n=n.substring(a+d[0].length);x(n);return k(m.join(""))}}])})(window,window.angular);
|
||||
//# sourceMappingURL=angular-sanitize.min.js.map
|
||||
+8
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user