From a44c1d7a11b1bb352a0bea3a3c74cc7b99a85d7d Mon Sep 17 00:00:00 2001 From: removeif Date: Tue, 21 Jan 2025 08:37:35 +0000 Subject: [PATCH] =?UTF-8?q?Update=20=E5=8D=9A=E5=AE=A2=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E5=88=86=E4=BA=AB.md=20UTC=202025-01-21=20Tuesday=2008:37:35?= =?UTF-8?q?=20Updated=20By=20Github=20Actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 404.html | 181 + about/index.html | 306 + ads.txt | 1 + album/index.html | 221 + algorithm/leetcode-1-Two-Sum.html | 184 + algorithm/leetcode-2-Add-Two-Numbers.html | 182 + ...4\346\200\235\346\203\263-leetcode35.html" | 314 + ...\346\263\225\350\257\246\350\247\243.html" | 288 + ...7\344\271\213\350\267\257leetcode1-4.html" | 234 + ...344\271\213\350\267\257leetcode11-12.html" | 195 + ...344\271\213\350\267\257leetcode13-14.html" | 251 + ...344\271\213\350\267\257leetcode15-16.html" | 191 + ...344\271\213\350\267\257leetcode17-18.html" | 193 + ...344\271\213\350\267\257leetcode19-20.html" | 210 + ...344\271\213\350\267\257leetcode21-22.html" | 188 + ...7\344\271\213\350\267\257leetcode5-6.html" | 189 + ...7\344\271\213\350\267\257leetcode7-8.html" | 200 + ...\344\271\213\350\267\257leetcode9-10.html" | 193 + ...\346\236\220\347\244\272\344\276\213.html" | 279 + anniversary.html | 495 + archives/2018/11/index.html | 233 + archives/2018/11/page/2/index.html | 233 + archives/2018/12/index.html | 233 + archives/2018/index.html | 233 + archives/2018/page/2/index.html | 233 + archives/2019/01/index.html | 233 + archives/2019/02/index.html | 233 + archives/2019/04/index.html | 233 + archives/2019/05/index.html | 233 + archives/2019/06/index.html | 233 + archives/2019/07/index.html | 233 + archives/2019/08/index.html | 233 + archives/2019/08/page/2/index.html | 233 + archives/2019/09/index.html | 233 + archives/2019/10/index.html | 233 + archives/2019/11/index.html | 233 + archives/2019/12/index.html | 233 + archives/2019/12/page/2/index.html | 233 + archives/2019/index.html | 233 + archives/2019/page/2/index.html | 233 + archives/2019/page/3/index.html | 233 + archives/2019/page/4/index.html | 233 + archives/2019/page/5/index.html | 233 + archives/2019/page/6/index.html | 233 + archives/2019/page/7/index.html | 233 + archives/2020/01/index.html | 233 + archives/2020/02/index.html | 233 + archives/2020/02/page/2/index.html | 233 + archives/2020/03/index.html | 233 + archives/2020/03/page/2/index.html | 233 + archives/2020/07/index.html | 233 + archives/2020/12/index.html | 233 + archives/2020/index.html | 233 + archives/2020/page/2/index.html | 233 + archives/2020/page/3/index.html | 233 + archives/2020/page/4/index.html | 233 + archives/2023/04/index.html | 233 + archives/2023/index.html | 233 + archives/2024/12/index.html | 233 + archives/2024/index.html | 233 + archives/2025/01/index.html | 233 + archives/2025/index.html | 233 + archives/index.html | 233 + archives/page/10/index.html | 233 + archives/page/11/index.html | 233 + archives/page/12/index.html | 233 + archives/page/13/index.html | 233 + archives/page/2/index.html | 233 + archives/page/3/index.html | 233 + archives/page/4/index.html | 233 + archives/page/5/index.html | 233 + archives/page/6/index.html | 233 + archives/page/7/index.html | 233 + archives/page/8/index.html | 233 + archives/page/9/index.html | 233 + assets/algolia/algoliasearch.js | 7190 +++++++++ assets/algolia/algoliasearch.min.js | 4 + assets/algolia/algoliasearchLite.js | 4453 ++++++ assets/algolia/algoliasearchLite.min.js | 3 + atom.xml | 562 + ...\346\226\207\350\247\243\350\257\264.html" | 293 + categories/English/grammar/index.html | 199 + categories/English/index.html | 199 + categories/algorithm/index.html | 167 + categories/develop/git/index.html | 160 + categories/develop/index.html | 160 + categories/health/index.html | 160 + categories/index.html | 160 + categories/ios/index.html | 160 + categories/java/JVM/index.html | 162 + categories/java/elasticsearch6/index.html | 168 + categories/java/index.html | 230 + .../java\345\237\272\347\241\200/index.html" | 184 + categories/java/spring/index.html | 161 + categories/java/springboot/index.html | 165 + .../java/\345\271\266\345\217\221/index.html" | 162 + .../java/\346\241\206\346\236\266/index.html" | 162 + .../index.html" | 186 + .../index.html" | 160 + categories/marathon/index.html | 162 + categories/private/index.html | 164 + categories/python3/index.html | 161 + categories/think/index.html | 173 + categories/travel/index.html | 160 + .../index.html" | 160 + .../Git/index.html" | 164 + .../Vim/index.html" | 162 + .../docker/index.html" | 160 + .../index.html" | 168 + .../\346\255\243\345\210\231/index.html" | 162 + .../index.html" | 177 + .../index.html" | 173 + .../index.html" | 164 + .../index.html" | 185 + .../mybatis/index.html" | 162 + .../mysql/index.html" | 181 + .../redis/index.html" | 162 + .../index.html" | 162 + .../Kafka/index.html" | 160 + .../\346\236\266\346\236\204/index.html" | 164 + .../\350\256\276\350\256\241/index.html" | 164 + .../\346\263\225\345\276\213/index.html" | 206 + .../\347\247\221\346\231\256/index.html" | 162 + .../index.html" | 162 + .../index.html" | 160 + clock.html | 25 + content.json | 1 + css/DPlayer.min.css | 4 + css/clock.css | 131 + css/cyberpunk.css | 13252 ++++++++++++++++ css/default.css | 12605 +++++++++++++++ css/fonts/fontello.eot | Bin 0 -> 5456 bytes css/fonts/fontello.svg | 16 + css/fonts/fontello.ttf | Bin 0 -> 5288 bytes css/fonts/fontello.woff | Bin 0 -> 3136 bytes css/global_gray.css | 8 + css/meplayer.min.css | 665 + css/style.css | 12605 +++++++++++++++ ...\345\256\236\347\216\260\346\240\210.html" | 235 + ...\347\272\247\347\274\223\345\255\230.html" | 350 + ...mysql-b-Tree\347\264\242\345\274\225.html" | 296 + ...\350\257\242\344\274\230\345\214\226.html" | 226 + ...\345\272\246\351\205\215\347\275\256.html" | 224 + ...\345\274\225\350\247\243\346\236\220.html" | 334 + ...\345\214\226\346\226\271\346\241\210.html" | 338 + ...\350\214\203\346\226\271\346\263\225.html" | 364 + ...350\256\260-\350\275\254\350\275\275.html" | 183 + ...\346\237\245\350\277\207\347\250\213.html" | 340 + ...\347\225\245\351\227\256\351\242\230.html" | 229 + ...\347\232\204\345\256\236\347\216\260.html" | 236 + ...\350\257\257\345\206\231\346\263\225.html" | 275 + ...\345\217\212\345\216\237\347\220\206.html" | 319 + ...\345\205\263\350\256\276\350\256\241.html" | 284 + ...\345\205\263\351\227\256\351\242\230.html" | 377 + ...350\256\241-\350\275\254\350\275\275.html" | 284 + ...6\222\221\347\231\276\344\270\207QPS.html" | 252 + ...\344\276\213\345\260\217\347\273\223.html" | 252 + ...\351\200\200\344\273\243\347\240\201.html" | 241 + ...\351\227\250\346\223\215\344\275\234.html" | 371 + .../github-gpg-failed-to-sign-the-data.html | 201 + ...257\225\344\273\243\347\240\201debug.html" | 311 + ...\347\247\260\344\273\243\350\257\215.html" | 229 + ...346\263\225-\344\273\213\350\257\215.html" | 351 + ...\347\263\273\344\273\216\345\217\245.html" | 355 + ...346\263\225-\345\211\257\350\257\215.html" | 307 + ...\345\212\250\345\220\215\350\257\215.html" | 289 + ...\344\270\215\345\256\232\345\274\217.html" | 314 + ...\345\255\220\347\256\200\345\214\226.html" | 225 + ...\345\255\220\347\261\273\345\236\213.html" | 216 + ...\350\257\215\344\273\216\345\217\245.html" | 221 + ...\345\255\220\347\273\223\346\236\204.html" | 239 + ...\346\234\254\350\257\255\346\263\225.html" | 672 + ...\345\256\214\346\210\220\346\227\266.html" | 321 + ...\350\277\233\350\241\214\346\227\266.html" | 227 + ...\350\257\255\344\273\216\345\217\245.html" | 341 + ...242\345\256\271\350\257\215adjective.html" | 308 + ...\350\257\255\344\273\216\345\217\245.html" | 375 + ...\345\212\250\350\257\255\346\200\201.html" | 275 + ...351\231\220\345\256\232\350\257\2151.html" | 213 + ...351\231\220\345\256\232\350\257\2152.html" | 238 + friend/index.html | 193 + ...\346\241\210\345\256\236\347\216\260.html" | 358 + ...\346\205\216\351\243\237\347\224\250.html" | 199 + images/avatar.jpg | Bin 0 -> 20321 bytes images/chat.svg | 6 + images/tuzi.jpg | Bin 0 -> 20321 bytes img/avatar.png | Bin 0 -> 17955 bytes img/background.png | Bin 0 -> 15653 bytes img/favicon.svg | 6 + img/links/nopic.jpg | Bin 0 -> 14644 bytes img/logo.svg | 9 + img/og_image.png | Bin 0 -> 57197 bytes img/razor-bottom-black.svg | 3 + img/razor-top-black.svg | 3 + index.html | 181 + ...\346\213\237\351\227\250\347\246\201.html" | 193 + ...350\261\241-\346\250\241\345\274\217.html" | 212 + ...\344\270\216\344\275\277\347\224\250.html" | 211 + ...\345\234\276\345\233\236\346\224\266.html" | 274 + ...\345\231\250\351\233\206\345\220\210.html" | 468 + ...\347\237\245\350\257\206\347\202\271.html" | 606 + ...\347\224\250\346\226\271\346\263\225.html" | 273 + ...\345\274\217\350\257\264\346\230\216.html" | 402 + ...34\260\345\235\200\346\263\225rehash.html" | 260 + ...\344\271\246\347\254\224\350\256\260.html" | 246 + ...\345\205\263\351\224\256\345\255\227.html" | 205 + ...\345\205\263\351\224\256\345\255\227.html" | 230 + ...\346\230\216\345\256\236\344\276\213.html" | 240 + ...\347\237\245\350\257\206\347\202\271.html" | 261 + ...\347\220\206\346\250\241\345\274\217.html" | 236 + ...\344\276\213\346\250\241\345\274\217.html" | 217 + ...\344\273\244\346\250\241\345\274\217.html" | 210 + ...\345\216\202\346\250\241\345\274\217.html" | 225 + ...\350\200\205\346\250\241\345\274\217.html" | 223 + ...\350\200\205\346\250\241\345\274\217.html" | 223 + ...\345\231\250\346\250\241\345\274\217.html" | 232 + java/design-mode/java-strategy-pattern.html | 212 + ...7\224\250\345\267\245\345\205\267api.html" | 373 + ...\351\241\271\346\237\245\350\257\242.html" | 210 + ...\345\222\214\345\210\206\350\257\215.html" | 395 + ...\351\242\230\346\216\222\346\237\245.html" | 206 + ...\347\216\257\344\276\235\350\265\226.html" | 236 + ...\346\225\260\351\252\214\350\257\201.html" | 340 + ...\345\221\275\345\221\250\346\234\237.html" | 227 + ...\346\227\266\344\273\273\345\212\241.html" | 221 + .../frame/springboot-dubbo-nacos-example.html | 211 + ...tful-swagger\345\256\236\346\210\230.html" | 400 + ...\240\201demo\347\244\272\344\276\213.html" | 204 + ...\346\255\242\346\234\215\345\212\241.html" | 215 + js/APlayer.min.js | 2 + js/DPlayer.min.js | 2 + js/about-me.js | 34 + js/algolia.js | 102 + js/animation.js | 45 + js/back_to_top.js | 154 + js/banner.js | 149 + js/column.js | 12 + js/comment-issue-data.js | 358 + js/echarts.min.js | 22 + js/friend.js | 72 + js/gitalk.min.js | 35 + js/gitalk_self.min.js | 35 + js/globalUtils.js | 141 + js/google_cse.js | 44 + js/insight.js | 354 + js/main.js | 170 + js/md5.min.js | 1 + js/meplayer.js | 639 + js/music.js | 120 + js/theme-setting.js | 69 + js/toc.js | 80 + json_data/banner.json | 1 + json_data/friend.json | 1 + json_data/music.json | 1 + json_data/record.json | 1 + json_data/video.json | 1 + ...\350\257\211\350\256\274\346\263\225.html" | 1084 ++ ...\345\212\263\345\212\250\346\263\225.html" | 438 + ...\345\233\275\346\227\227\346\263\225.html" | 252 + ...\345\251\232\345\247\273\346\263\225.html" | 297 + ...\345\233\275\345\256\252\346\263\225.html" | 567 + ...\344\277\235\346\212\244\346\263\225.html" | 344 + ...\345\256\211\345\205\250\346\263\225.html" | 334 + ...250\213-2017\344\277\256\346\224\271.html" | 358 + live2d/autoload.js | 15 + live2d/flat-ui-icons-regular.eot | Bin 0 -> 25912 bytes live2d/flat-ui-icons-regular.svg | 126 + live2d/flat-ui-icons-regular.ttf | Bin 0 -> 25708 bytes live2d/flat-ui-icons-regular.woff | Bin 0 -> 17844 bytes live2d/live2d.js | 4231 +++++ live2d/waifu-tips.js | 405 + live2d/waifu-tips.json | 1 + live2d/waifu.css | 290 + manifest.json | 1 + ...\351\251\254\346\213\211\346\235\276.html" | 210 + media/index.html | 215 + message/index.html | 179 + music/index.html | 184 + page/10/index.html | 180 + page/11/index.html | 184 + page/12/index.html | 192 + page/13/index.html | 164 + page/2/index.html | 182 + page/3/index.html | 177 + page/4/index.html | 170 + page/5/index.html | 171 + page/6/index.html | 169 + page/7/index.html | 181 + page/8/index.html | 177 + page/9/index.html | 198 + ...46\210\220\351\225\277\350\256\26001.html" | 229 + ...3\276\345\255\246\344\274\232python3.html" | 183 + ...\346\236\204\345\273\272\345\231\250.html" | 211 + robots.txt | 15 + self-talking/index.html | 197 + tags/Effective-Java/index.html | 160 + tags/English/index.html | 182 + tags/English/page/2/index.html | 177 + tags/Git/index.html | 164 + tags/Kafka/index.html | 160 + tags/Schedule/index.html | 160 + tags/Valid/index.html | 160 + .../index.html" | 160 + tags/b-tree/index.html | 165 + tags/bean/index.html | 161 + tags/debug/index.html | 160 + tags/docker/index.html | 160 + tags/dp/index.html | 162 + tags/dubbo/index.html | 161 + tags/elasticsearch6/index.html | 166 + tags/feign/index.html | 161 + tags/git/index.html | 160 + tags/gpg-sign/index.html | 160 + tags/grammar/index.html | 182 + tags/grammar/page/2/index.html | 177 + .../hash\345\206\262\347\252\201/index.html" | 161 + tags/health/index.html | 160 + tags/hexo-blog/index.html | 163 + tags/hexo-theme/index.html | 163 + tags/hexo/index.html | 163 + .../hexo\344\270\273\351\242\230/index.html" | 164 + .../index.html" | 164 + tags/index.html | 160 + tags/ios/index.html | 160 + tags/java/index.html | 180 + tags/java/page/2/index.html | 194 + tags/like/index.html | 161 + .../like\344\274\230\345\214\226/index.html" | 161 + tags/marathon/index.html | 162 + tags/mybatis/index.html | 162 + tags/mysql/index.html | 174 + tags/nacos/index.html | 161 + tags/nfc/index.html | 160 + .../index.html" | 161 + tags/query/index.html | 164 + tags/rebase/index.html | 161 + tags/redis/index.html | 162 + tags/rehash/index.html | 161 + tags/restful-api/index.html | 162 + tags/spring-cloud/index.html | 161 + tags/spring/index.html | 161 + tags/springboot/index.html | 166 + tags/sql/index.html | 162 + "tags/sql\344\274\230\345\214\226/index.html" | 162 + tags/strategy/index.html | 164 + tags/swagger/index.html | 164 + tags/think/index.html | 177 + tags/vim/index.html | 162 + tags/websocket-server/index.html | 161 + tags/websocket/index.html | 161 + .../index.html" | 160 + .../index.html" | 162 + "tags/\345\205\232\347\253\240/index.html" | 165 + "tags/\345\210\206\346\262\273/index.html" | 160 + .../index.html" | 161 + .../index.html" | 160 + .../index.html" | 162 + .../index.html" | 164 + .../index.html" | 160 + .../index.html" | 160 + .../index.html" | 162 + .../index.html" | 161 + .../index.html" | 160 + .../index.html" | 169 + .../index.html" | 162 + "tags/\345\271\266\345\217\221/index.html" | 162 + "tags/\346\205\242sql/index.html" | 160 + .../index.html" | 162 + .../index.html" | 162 + .../index.html" | 162 + "tags/\346\227\205\350\241\214/index.html" | 160 + .../index.html" | 161 + .../index.html" | 160 + "tags/\346\240\210/index.html" | 160 + .../index.html" | 161 + .../index.html" | 162 + .../index.html" | 162 + "tags/\346\263\225\345\276\213/index.html" | 206 + .../index.html" | 161 + "tags/\347\247\221\346\231\256/index.html" | 162 + .../index.html" | 160 + "tags/\347\264\242\345\274\225/index.html" | 162 + .../index.html" | 162 + .../index.html" | 162 + .../index.html" | 165 + .../index.html" | 160 + "tags/\350\245\277\345\256\211/index.html" | 160 + .../index.html" | 186 + .../index.html" | 160 + .../index.html" | 160 + .../index.html" | 161 + "tags/\351\200\222\345\275\222/index.html" | 160 + .../index.html" | 160 + "tags/\351\223\276\350\241\250/index.html" | 160 + "tags/\351\225\277\345\256\211/index.html" | 160 + "tags/\351\233\206\345\220\210/index.html" | 162 + ...\275\262Hexo\345\215\232\345\256\242.html" | 185 + ...\347\232\204\345\272\224\347\224\250.html" | 208 + ...\345\214\226\345\212\240\351\200\237.html" | 199 + ...\350\247\201\351\227\256\351\242\230.html" | 217 + ...\347\232\204\350\216\267\345\217\226.html" | 321 + ...\344\274\240\344\275\277\347\224\250.html" | 217 + ...\345\274\217\346\200\235\350\267\257.html" | 203 + ...\347\240\201\345\210\206\344\272\253.html" | 292 + ...\344\270\255\346\226\207\347\211\210.html" | 233 + ...\347\273\210\346\200\273\347\273\223.html" | 182 + think/Hello-blog.html | 186 + think/hello-world.html | 252 + ...\347\273\255\350\256\241\345\210\222.html" | 183 + ...\351\225\277\347\273\217\345\216\206.html" | 269 + ...\344\270\216\344\275\277\347\224\250.html" | 348 + ...347\225\2453\346\227\245\346\270\270.html" | 293 + 412 files changed, 134343 insertions(+) create mode 100644 404.html create mode 100644 about/index.html create mode 100644 ads.txt create mode 100644 album/index.html create mode 100644 algorithm/leetcode-1-Two-Sum.html create mode 100644 algorithm/leetcode-2-Add-Two-Numbers.html create mode 100644 "algorithm/\344\272\214\345\210\206\346\237\245\346\211\276\346\263\225\346\250\241\346\235\277\347\232\204\345\237\272\346\234\254\346\200\235\346\203\263-leetcode35.html" create mode 100644 "algorithm/\345\212\250\346\200\201\350\247\204\345\210\222DP\347\256\227\346\263\225\350\257\246\350\247\243.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode1-4.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode11-12.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode13-14.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode15-16.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode17-18.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode19-20.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode21-22.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode5-6.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode7-8.html" create mode 100644 "algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode9-10.html" create mode 100644 "algorithm/\350\264\252\345\277\203\347\256\227\346\263\225\350\247\243\346\236\220\347\244\272\344\276\213.html" create mode 100644 anniversary.html create mode 100644 archives/2018/11/index.html create mode 100644 archives/2018/11/page/2/index.html create mode 100644 archives/2018/12/index.html create mode 100644 archives/2018/index.html create mode 100644 archives/2018/page/2/index.html create mode 100644 archives/2019/01/index.html create mode 100644 archives/2019/02/index.html create mode 100644 archives/2019/04/index.html create mode 100644 archives/2019/05/index.html create mode 100644 archives/2019/06/index.html create mode 100644 archives/2019/07/index.html create mode 100644 archives/2019/08/index.html create mode 100644 archives/2019/08/page/2/index.html create mode 100644 archives/2019/09/index.html create mode 100644 archives/2019/10/index.html create mode 100644 archives/2019/11/index.html create mode 100644 archives/2019/12/index.html create mode 100644 archives/2019/12/page/2/index.html create mode 100644 archives/2019/index.html create mode 100644 archives/2019/page/2/index.html create mode 100644 archives/2019/page/3/index.html create mode 100644 archives/2019/page/4/index.html create mode 100644 archives/2019/page/5/index.html create mode 100644 archives/2019/page/6/index.html create mode 100644 archives/2019/page/7/index.html create mode 100644 archives/2020/01/index.html create mode 100644 archives/2020/02/index.html create mode 100644 archives/2020/02/page/2/index.html create mode 100644 archives/2020/03/index.html create mode 100644 archives/2020/03/page/2/index.html create mode 100644 archives/2020/07/index.html create mode 100644 archives/2020/12/index.html create mode 100644 archives/2020/index.html create mode 100644 archives/2020/page/2/index.html create mode 100644 archives/2020/page/3/index.html create mode 100644 archives/2020/page/4/index.html create mode 100644 archives/2023/04/index.html create mode 100644 archives/2023/index.html create mode 100644 archives/2024/12/index.html create mode 100644 archives/2024/index.html create mode 100644 archives/2025/01/index.html create mode 100644 archives/2025/index.html create mode 100644 archives/index.html create mode 100644 archives/page/10/index.html create mode 100644 archives/page/11/index.html create mode 100644 archives/page/12/index.html create mode 100644 archives/page/13/index.html create mode 100644 archives/page/2/index.html create mode 100644 archives/page/3/index.html create mode 100644 archives/page/4/index.html create mode 100644 archives/page/5/index.html create mode 100644 archives/page/6/index.html create mode 100644 archives/page/7/index.html create mode 100644 archives/page/8/index.html create mode 100644 archives/page/9/index.html create mode 100644 assets/algolia/algoliasearch.js create mode 100644 assets/algolia/algoliasearch.min.js create mode 100644 assets/algolia/algoliasearchLite.js create mode 100644 assets/algolia/algoliasearchLite.min.js create mode 100644 atom.xml create mode 100644 "breaking-news/2019\345\271\264\345\233\275\345\272\20670\345\221\250\345\271\264\351\230\205\345\205\265\345\256\214\346\225\264\345\233\276\346\226\207\350\247\243\350\257\264.html" create mode 100644 categories/English/grammar/index.html create mode 100644 categories/English/index.html create mode 100644 categories/algorithm/index.html create mode 100644 categories/develop/git/index.html create mode 100644 categories/develop/index.html create mode 100644 categories/health/index.html create mode 100644 categories/index.html create mode 100644 categories/ios/index.html create mode 100644 categories/java/JVM/index.html create mode 100644 categories/java/elasticsearch6/index.html create mode 100644 categories/java/index.html create mode 100644 "categories/java/java\345\237\272\347\241\200/index.html" create mode 100644 categories/java/spring/index.html create mode 100644 categories/java/springboot/index.html create mode 100644 "categories/java/\345\271\266\345\217\221/index.html" create mode 100644 "categories/java/\346\241\206\346\236\266/index.html" create mode 100644 "categories/java/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" create mode 100644 "categories/java/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" create mode 100644 categories/marathon/index.html create mode 100644 categories/private/index.html create mode 100644 categories/python3/index.html create mode 100644 categories/think/index.html create mode 100644 categories/travel/index.html create mode 100644 "categories/\345\211\215\347\253\257\346\212\200\346\234\257/index.html" create mode 100644 "categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Git/index.html" create mode 100644 "categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Vim/index.html" create mode 100644 "categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/docker/index.html" create mode 100644 "categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/index.html" create mode 100644 "categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/\346\255\243\345\210\231/index.html" create mode 100644 "categories/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" create mode 100644 "categories/\345\267\245\345\205\267\346\225\231\347\250\213/\344\270\273\351\242\230\345\267\245\345\205\267/index.html" create mode 100644 "categories/\345\267\245\345\205\267\346\225\231\347\250\213/\345\215\232\345\256\242\347\273\237\350\256\241\346\217\222\344\273\266/index.html" create mode 100644 "categories/\346\225\260\346\215\256\345\272\223/index.html" create mode 100644 "categories/\346\225\260\346\215\256\345\272\223/mybatis/index.html" create mode 100644 "categories/\346\225\260\346\215\256\345\272\223/mysql/index.html" create mode 100644 "categories/\346\225\260\346\215\256\345\272\223/redis/index.html" create mode 100644 "categories/\346\225\260\346\215\256\347\273\223\346\236\204/index.html" create mode 100644 "categories/\346\236\266\346\236\204/Kafka/index.html" create mode 100644 "categories/\346\236\266\346\236\204/index.html" create mode 100644 "categories/\346\236\266\346\236\204/\350\256\276\350\256\241/index.html" create mode 100644 "categories/\346\263\225\345\276\213/index.html" create mode 100644 "categories/\347\247\221\346\231\256/index.html" create mode 100644 "categories/\347\273\217\351\252\214\346\210\220\351\225\277/index.html" create mode 100644 "categories/\350\207\252\345\212\250\351\203\250\347\275\262Hexo\345\215\232\345\256\242\357\274\214Github-Action/index.html" create mode 100644 clock.html create mode 100644 content.json create mode 100644 css/DPlayer.min.css create mode 100644 css/clock.css create mode 100644 css/cyberpunk.css create mode 100644 css/default.css create mode 100644 css/fonts/fontello.eot create mode 100644 css/fonts/fontello.svg create mode 100644 css/fonts/fontello.ttf create mode 100644 css/fonts/fontello.woff create mode 100644 css/global_gray.css create mode 100644 css/meplayer.min.css create mode 100644 css/style.css create mode 100644 "data-structure/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227-\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.html" create mode 100644 "database/mysql/MyBatis\344\272\214\347\272\247\347\274\223\345\255\230.html" create mode 100644 "database/mysql/mysql-b-Tree\347\264\242\345\274\225.html" create mode 100644 "database/mysql/mysql-like\346\250\241\347\263\212\346\237\245\350\257\242\344\274\230\345\214\226.html" create mode 100644 "database/mysql/mysql\345\205\201\350\256\270\346\234\200\345\244\247sql\350\257\255\345\217\245\351\225\277\345\272\246\351\205\215\347\275\256.html" create mode 100644 "database/mysql/mysql\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225\350\247\243\346\236\220.html" create mode 100644 "database/mysql/mysql\347\264\242\345\274\225\344\274\230\345\214\226\346\226\271\346\241\210.html" create mode 100644 "database/mysql/mysql\351\253\230\346\200\247\350\203\275\344\274\230\345\214\226\350\247\204\350\214\203\346\226\271\346\263\225.html" create mode 100644 "database/mysql/\344\270\200\345\215\203\350\241\214-MySQL-\345\255\246\344\271\240\347\254\224\350\256\260-\350\275\254\350\275\275.html" create mode 100644 "database/mysql/\344\270\200\346\254\241\346\225\260\346\215\256\345\272\223\347\232\204\346\255\273\351\224\201\351\227\256\351\242\230\346\216\222\346\237\245\350\277\207\347\250\213.html" create mode 100644 "database/redis/Redis\347\232\204\345\206\205\345\255\230\346\267\230\346\261\260\347\255\226\347\225\245\351\227\256\351\242\230.html" create mode 100644 "database/redis/redis\345\210\206\345\270\203\345\274\217\351\224\201Redlock\347\232\204\345\256\236\347\216\260.html" create mode 100644 "database/\345\270\270\350\247\201sql\351\224\231\350\257\257\345\206\231\346\263\225.html" create mode 100644 "design-architecture/Kafka\345\237\272\346\234\254\346\236\266\346\236\204\345\217\212\345\216\237\347\220\206.html" create mode 100644 "design-architecture/restful-api-\350\256\276\350\256\241\344\273\245\345\217\212\345\271\202\347\255\211\346\200\247\347\233\270\345\205\263\350\256\276\350\256\241.html" create mode 100644 "design-architecture/\345\271\266\345\217\221\346\211\243\346\254\276\347\233\270\345\205\263\351\227\256\351\242\230.html" create mode 100644 "design-architecture/\346\224\257\344\273\230\347\263\273\347\273\237\350\256\276\350\256\241-\350\275\254\350\275\275.html" create mode 100644 "design-architecture/\347\247\222\346\235\200\347\263\273\347\273\237\345\246\202\344\275\225\346\224\257\346\222\221\347\231\276\344\270\207QPS.html" create mode 100644 "develop/Git-rebase-\347\224\250\346\263\225\347\244\272\344\276\213\345\260\217\347\273\223.html" create mode 100644 "develop/Git\345\246\202\344\275\225\344\274\230\351\233\205\345\234\260\345\233\236\351\200\200\344\273\243\347\240\201.html" create mode 100644 "develop/Vim\345\237\272\346\234\254\345\205\245\351\227\250\346\223\215\344\275\234.html" create mode 100644 develop/github-gpg-failed-to-sign-the-data.html create mode 100644 "develop/intellj-idea-\350\257\246\347\273\206\350\260\203\350\257\225\344\273\243\347\240\201debug.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\344\272\272\347\247\260\344\273\243\350\257\215.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\344\273\213\350\257\215.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\205\263\347\263\273\344\273\216\345\217\245.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\211\257\350\257\215.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\212\250\345\220\215\350\257\215.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\212\250\350\257\215\344\270\215\345\256\232\345\274\217.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\217\245\345\255\220\347\256\200\345\214\226.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\217\245\345\255\220\347\261\273\345\236\213.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\220\215\350\257\215\344\273\216\345\217\245.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\237\272\346\234\254\345\217\245\345\255\220\347\273\223\346\236\204.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\237\272\346\234\254\350\257\255\346\263\225.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\256\214\346\210\220\346\227\266.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\256\214\346\210\220\350\277\233\350\241\214\346\227\266.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\256\232\350\257\255\344\273\216\345\217\245.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\345\275\242\345\256\271\350\257\215adjective.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\347\212\266\350\257\255\344\273\216\345\217\245.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\350\242\253\345\212\250\350\257\255\346\200\201.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\351\231\220\345\256\232\350\257\2151.html" create mode 100644 "english-learn/\350\213\261\350\257\255\350\257\255\346\263\225-\351\231\220\345\256\232\350\257\2152.html" create mode 100644 friend/index.html create mode 100644 "front/\346\233\277\344\273\243web-cookie\345\255\230\345\202\250\346\226\271\346\241\210\345\256\236\347\216\260.html" create mode 100644 "health/\345\270\270\350\247\201\351\232\224\345\244\234\350\217\234\350\260\250\346\205\216\351\243\237\347\224\250.html" create mode 100644 images/avatar.jpg create mode 100644 images/chat.svg create mode 100644 images/tuzi.jpg create mode 100644 img/avatar.png create mode 100644 img/background.png create mode 100644 img/favicon.svg create mode 100644 img/links/nopic.jpg create mode 100644 img/logo.svg create mode 100644 img/og_image.png create mode 100644 img/razor-bottom-black.svg create mode 100644 img/razor-top-black.svg create mode 100644 index.html create mode 100644 "ios/\350\213\271\346\236\2346s-ios12-nfc-\346\250\241\346\213\237\351\227\250\347\246\201.html" create mode 100644 "java/basic/Immutable-Object-\344\270\215\345\217\257\345\217\230\345\257\271\350\261\241-\346\250\241\345\274\217.html" create mode 100644 "java/basic/Java-BIO-NIO-AIO\345\214\272\345\210\253\344\270\216\344\275\277\347\224\250.html" create mode 100644 "java/basic/Java-\345\236\203\345\234\276\345\233\236\346\224\266.html" create mode 100644 "java/basic/Java\345\256\271\345\231\250\351\233\206\345\220\210.html" create mode 100644 "java/basic/Java\345\271\266\345\217\221\347\233\270\345\205\263\347\237\245\350\257\206\347\202\271.html" create mode 100644 "java/basic/Java\346\227\245\345\277\227\347\232\204\346\255\243\347\241\256\344\275\277\347\224\250\346\226\271\346\263\225.html" create mode 100644 "java/basic/Java\347\211\210\345\270\270\347\224\250\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\350\257\264\346\230\216.html" create mode 100644 "java/basic/hash\345\206\262\347\252\201\345\274\200\346\224\276\345\234\260\345\235\200\346\263\225rehash.html" create mode 100644 "java/basic/java-8\351\203\250\345\210\206\350\257\273\344\271\246\347\254\224\350\256\260.html" create mode 100644 "java/basic/java\345\237\272\347\241\200-final\345\205\263\351\224\256\345\255\227.html" create mode 100644 "java/basic/java\345\237\272\347\241\200-static\345\205\263\351\224\256\345\255\227.html" create mode 100644 "java/basic/java\346\263\250\350\247\243Annotation\350\257\264\346\230\216\345\256\236\344\276\213.html" create mode 100644 "java/basic/\345\216\237\347\240\201\350\241\245\347\240\201\345\274\202\346\210\226\344\270\216\344\275\215\350\277\220\347\256\227\347\247\273\344\275\215\347\237\245\350\257\206\347\202\271.html" create mode 100644 "java/design-mode/Java\350\256\276\350\256\241\346\250\241\345\274\217\344\271\213\344\273\243\347\220\206\346\250\241\345\274\217.html" create mode 100644 "java/design-mode/Java\350\256\276\350\256\241\346\250\241\345\274\217\344\271\213\345\215\225\344\276\213\346\250\241\345\274\217.html" create mode 100644 "java/design-mode/Java\350\256\276\350\256\241\346\250\241\345\274\217\344\271\213\345\221\275\344\273\244\346\250\241\345\274\217.html" create mode 100644 "java/design-mode/Java\350\256\276\350\256\241\346\250\241\345\274\217\344\271\213\345\267\245\345\216\202\346\250\241\345\274\217.html" create mode 100644 "java/design-mode/Java\350\256\276\350\256\241\346\250\241\345\274\217\344\271\213\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217.html" create mode 100644 "java/design-mode/Java\350\256\276\350\256\241\346\250\241\345\274\217\344\271\213\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.html" create mode 100644 "java/design-mode/Java\350\256\276\350\256\241\346\250\241\345\274\217\344\271\213\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217.html" create mode 100644 java/design-mode/java-strategy-pattern.html create mode 100644 "java/elasticsearch/Elasticsearch\345\270\270\347\224\250\345\267\245\345\205\267api.html" create mode 100644 "java/elasticsearch/elasticsearch6-query-\345\205\250\346\226\207\346\237\245\350\257\242\344\270\216\350\257\215\351\241\271\346\237\245\350\257\242.html" create mode 100644 "java/elasticsearch/elasticsearch6-x\345\200\222\346\216\222\347\264\242\345\274\225\345\222\214\345\210\206\350\257\215.html" create mode 100644 "java/frame/Spring-cloud-feign\351\207\215\350\257\225\351\227\256\351\242\230\346\216\222\346\237\245.html" create mode 100644 "java/frame/Spring-\345\246\202\344\275\225\350\247\243\345\206\263\345\276\252\347\216\257\344\276\235\350\265\226.html" create mode 100644 "java/frame/SpringBoot-Valid\346\263\250\350\247\243\344\273\245\345\217\212\345\205\250\345\261\200\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250\344\274\230\351\233\205\345\244\204\347\220\206\345\217\202\346\225\260\351\252\214\350\257\201.html" create mode 100644 "java/frame/Spring\347\232\204Bean\347\224\237\345\221\275\345\221\250\346\234\237.html" create mode 100644 "java/frame/spring-boot\345\256\236\347\216\260\345\212\250\346\200\201\345\242\236\345\210\240\345\220\257\345\201\234\345\256\232\346\227\266\344\273\273\345\212\241.html" create mode 100644 java/frame/springboot-dubbo-nacos-example.html create mode 100644 "java/frame/springboot-restful-swagger\345\256\236\346\210\230.html" create mode 100644 "java/frame/springboot-websocket-server\344\273\243\347\240\201demo\347\244\272\344\276\213.html" create mode 100644 "java/frame/springboot\344\274\230\351\233\205\347\232\204\345\201\234\346\255\242\346\234\215\345\212\241.html" create mode 100644 js/APlayer.min.js create mode 100644 js/DPlayer.min.js create mode 100644 js/about-me.js create mode 100644 js/algolia.js create mode 100644 js/animation.js create mode 100644 js/back_to_top.js create mode 100644 js/banner.js create mode 100644 js/column.js create mode 100644 js/comment-issue-data.js create mode 100644 js/echarts.min.js create mode 100644 js/friend.js create mode 100644 js/gitalk.min.js create mode 100644 js/gitalk_self.min.js create mode 100644 js/globalUtils.js create mode 100644 js/google_cse.js create mode 100644 js/insight.js create mode 100644 js/main.js create mode 100644 js/md5.min.js create mode 100644 js/meplayer.js create mode 100644 js/music.js create mode 100644 js/theme-setting.js create mode 100644 js/toc.js create mode 100644 json_data/banner.json create mode 100644 json_data/friend.json create mode 100644 json_data/music.json create mode 100644 json_data/record.json create mode 100644 json_data/video.json create mode 100644 "law/\344\270\255\345\215\216\344\272\272\346\260\221\345\205\261\345\222\214\345\233\275\345\210\221\344\272\213\350\257\211\350\256\274\346\263\225.html" create mode 100644 "law/\344\270\255\345\215\216\344\272\272\346\260\221\345\205\261\345\222\214\345\233\275\345\212\263\345\212\250\346\263\225.html" create mode 100644 "law/\344\270\255\345\215\216\344\272\272\346\260\221\345\205\261\345\222\214\345\233\275\345\233\275\346\227\227\346\263\225.html" create mode 100644 "law/\344\270\255\345\215\216\344\272\272\346\260\221\345\205\261\345\222\214\345\233\275\345\251\232\345\247\273\346\263\225.html" create mode 100644 "law/\344\270\255\345\215\216\344\272\272\346\260\221\345\205\261\345\222\214\345\233\275\345\256\252\346\263\225.html" create mode 100644 "law/\344\270\255\345\215\216\344\272\272\346\260\221\345\205\261\345\222\214\345\233\275\346\266\210\350\264\271\350\200\205\346\235\203\347\233\212\344\277\235\346\212\244\346\263\225.html" create mode 100644 "law/\344\270\255\345\215\216\344\272\272\346\260\221\345\205\261\345\222\214\345\233\275\347\275\221\347\273\234\345\256\211\345\205\250\346\263\225.html" create mode 100644 "law/\344\270\255\345\233\275\345\205\261\344\272\247\345\205\232\347\253\240\347\250\213-2017\344\277\256\346\224\271.html" create mode 100644 live2d/autoload.js create mode 100644 live2d/flat-ui-icons-regular.eot create mode 100644 live2d/flat-ui-icons-regular.svg create mode 100644 live2d/flat-ui-icons-regular.ttf create mode 100644 live2d/flat-ui-icons-regular.woff create mode 100644 live2d/live2d.js create mode 100644 live2d/waifu-tips.js create mode 100644 live2d/waifu-tips.json create mode 100644 live2d/waifu.css create mode 100644 manifest.json create mode 100644 "marathon/\351\251\254\346\213\211\346\235\276-2019\350\245\277\346\230\214\346\234\200\347\276\216\350\265\233\351\201\223\351\202\233\346\265\267\351\251\254\346\213\211\346\235\276.html" create mode 100644 media/index.html create mode 100644 message/index.html create mode 100644 music/index.html create mode 100644 page/10/index.html create mode 100644 page/11/index.html create mode 100644 page/12/index.html create mode 100644 page/13/index.html create mode 100644 page/2/index.html create mode 100644 page/3/index.html create mode 100644 page/4/index.html create mode 100644 page/5/index.html create mode 100644 page/6/index.html create mode 100644 page/7/index.html create mode 100644 page/8/index.html create mode 100644 page/9/index.html create mode 100644 "private/2019\346\210\220\351\225\277\350\256\26001.html" create mode 100644 "python/\344\270\200\345\274\240\345\233\276\345\255\246\344\274\232python3.html" create mode 100644 "read-record/Effective-Java-2-\351\201\207\345\210\260\345\244\232\344\270\252\346\236\204\351\200\240\345\231\250\345\217\202\346\225\260\346\227\266\350\200\203\350\231\221\347\224\250\346\236\204\345\273\272\345\231\250.html" create mode 100644 robots.txt create mode 100644 self-talking/index.html create mode 100644 tags/Effective-Java/index.html create mode 100644 tags/English/index.html create mode 100644 tags/English/page/2/index.html create mode 100644 tags/Git/index.html create mode 100644 tags/Kafka/index.html create mode 100644 tags/Schedule/index.html create mode 100644 tags/Valid/index.html create mode 100644 "tags/Z\345\255\227\345\217\230\346\215\242/index.html" create mode 100644 tags/b-tree/index.html create mode 100644 tags/bean/index.html create mode 100644 tags/debug/index.html create mode 100644 tags/docker/index.html create mode 100644 tags/dp/index.html create mode 100644 tags/dubbo/index.html create mode 100644 tags/elasticsearch6/index.html create mode 100644 tags/feign/index.html create mode 100644 tags/git/index.html create mode 100644 tags/gpg-sign/index.html create mode 100644 tags/grammar/index.html create mode 100644 tags/grammar/page/2/index.html create mode 100644 "tags/hash\345\206\262\347\252\201/index.html" create mode 100644 tags/health/index.html create mode 100644 tags/hexo-blog/index.html create mode 100644 tags/hexo-theme/index.html create mode 100644 tags/hexo/index.html create mode 100644 "tags/hexo\344\270\273\351\242\230/index.html" create mode 100644 "tags/icarus\344\270\273\351\242\230\351\205\215\347\275\256/index.html" create mode 100644 tags/index.html create mode 100644 tags/ios/index.html create mode 100644 tags/java/index.html create mode 100644 tags/java/page/2/index.html create mode 100644 tags/like/index.html create mode 100644 "tags/like\344\274\230\345\214\226/index.html" create mode 100644 tags/marathon/index.html create mode 100644 tags/mybatis/index.html create mode 100644 tags/mysql/index.html create mode 100644 tags/nacos/index.html create mode 100644 tags/nfc/index.html create mode 100644 "tags/python3\345\237\272\347\241\200/index.html" create mode 100644 tags/query/index.html create mode 100644 tags/rebase/index.html create mode 100644 tags/redis/index.html create mode 100644 tags/rehash/index.html create mode 100644 tags/restful-api/index.html create mode 100644 tags/spring-cloud/index.html create mode 100644 tags/spring/index.html create mode 100644 tags/springboot/index.html create mode 100644 tags/sql/index.html create mode 100644 "tags/sql\344\274\230\345\214\226/index.html" create mode 100644 tags/strategy/index.html create mode 100644 tags/swagger/index.html create mode 100644 tags/think/index.html create mode 100644 tags/vim/index.html create mode 100644 tags/websocket-server/index.html create mode 100644 tags/websocket/index.html create mode 100644 "tags/\344\270\255\345\277\203\346\211\251\345\261\225/index.html" create mode 100644 "tags/\344\272\214\345\210\206\346\237\245\346\211\276/index.html" create mode 100644 "tags/\345\205\232\347\253\240/index.html" create mode 100644 "tags/\345\210\206\346\262\273/index.html" create mode 100644 "tags/\345\210\206\346\262\273\347\256\227\346\263\225/index.html" create mode 100644 "tags/\345\211\215\347\253\257\346\212\200\346\234\257/index.html" create mode 100644 "tags/\345\212\250\346\200\201\350\247\204\345\210\222/index.html" create mode 100644 "tags/\345\215\232\345\256\242\347\273\237\350\256\241\346\217\222\344\273\266/index.html" create mode 100644 "tags/\345\217\214\346\214\207\351\222\210/index.html" create mode 100644 "tags/\345\217\215\350\275\254\346\225\264\346\225\260/index.html" create mode 100644 "tags/\345\244\232\347\272\277\347\250\213/index.html" create mode 100644 "tags/\345\255\227\347\254\246\344\270\262/index.html" create mode 100644 "tags/\345\255\227\347\254\246\344\270\262\350\275\254\346\225\264\346\225\260/index.html" create mode 100644 "tags/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" create mode 100644 "tags/\345\271\202\347\255\211\346\200\247/index.html" create mode 100644 "tags/\345\271\266\345\217\221/index.html" create mode 100644 "tags/\346\205\242sql/index.html" create mode 100644 "tags/\346\224\257\344\273\230\346\236\266\346\236\204/index.html" create mode 100644 "tags/\346\224\257\344\273\230\347\263\273\347\273\237/index.html" create mode 100644 "tags/\346\225\260\346\215\256\347\273\223\346\236\204/index.html" create mode 100644 "tags/\346\227\205\350\241\214/index.html" create mode 100644 "tags/\346\234\200\344\274\230\350\247\243/index.html" create mode 100644 "tags/\346\234\200\351\225\277\345\233\236\346\226\207/index.html" create mode 100644 "tags/\346\240\210/index.html" create mode 100644 "tags/\346\250\241\347\263\212\346\237\245\350\257\242/index.html" create mode 100644 "tags/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217/index.html" create mode 100644 "tags/\346\255\273\351\224\201\346\216\222\346\237\245/index.html" create mode 100644 "tags/\346\263\225\345\276\213/index.html" create mode 100644 "tags/\346\273\221\345\212\250\347\252\227\345\217\243/index.html" create mode 100644 "tags/\347\247\221\346\231\256/index.html" create mode 100644 "tags/\347\247\222\346\235\200\347\263\273\347\273\237\357\274\214\346\224\257\344\273\230\350\256\276\350\256\241/index.html" create mode 100644 "tags/\347\264\242\345\274\225/index.html" create mode 100644 "tags/\347\264\242\345\274\225\345\210\206\350\257\215/index.html" create mode 100644 "tags/\347\273\217\351\252\214\346\210\220\351\225\277/index.html" create mode 100644 "tags/\350\201\232\347\260\207\347\264\242\345\274\225/index.html" create mode 100644 "tags/\350\207\252\345\212\250\351\203\250\347\275\262Hexo\345\215\232\345\256\242/index.html" create mode 100644 "tags/\350\245\277\345\256\211/index.html" create mode 100644 "tags/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" create mode 100644 "tags/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" create mode 100644 "tags/\350\260\203\350\257\225\344\273\243\347\240\201/index.html" create mode 100644 "tags/\350\264\252\345\277\203\347\256\227\346\263\225/index.html" create mode 100644 "tags/\351\200\222\345\275\222/index.html" create mode 100644 "tags/\351\200\222\345\275\222\345\233\236\346\272\257/index.html" create mode 100644 "tags/\351\223\276\350\241\250/index.html" create mode 100644 "tags/\351\225\277\345\256\211/index.html" create mode 100644 "tags/\351\233\206\345\220\210/index.html" create mode 100644 "theme/Github-Action\350\207\252\345\212\250\351\203\250\347\275\262Hexo\345\215\232\345\256\242.html" create mode 100644 "theme/github-Issue-\344\275\234\344\270\272\345\215\232\345\256\242\345\276\256\345\236\213\346\225\260\346\215\256\345\272\223\347\232\204\345\272\224\347\224\250.html" create mode 100644 "theme/github-page\347\275\221\347\253\231cdn\344\274\230\345\214\226\345\212\240\351\200\237.html" create mode 100644 "theme/\344\270\215\350\222\234\345\255\220\347\273\237\350\256\241\345\270\270\350\247\201\351\227\256\351\242\230.html" create mode 100644 "theme/\345\215\232\345\256\242\344\270\255gitalk\346\234\200\346\226\260\350\257\204\350\256\272\347\232\204\350\216\267\345\217\226.html" create mode 100644 "theme/\345\215\232\345\256\242\345\233\276\347\211\207\344\270\212\344\274\240picgo\345\267\245\345\205\267github\345\233\276\344\274\240\344\275\277\347\224\250.html" create mode 100644 "theme/\345\215\232\345\256\242\346\215\242\350\202\244\347\232\204\344\270\200\347\247\215\345\256\236\347\216\260\346\226\271\345\274\217\346\200\235\350\267\257.html" create mode 100644 "theme/\345\215\232\345\256\242\346\272\220\347\240\201\345\210\206\344\272\253.html" create mode 100644 "theme/\345\256\211\350\243\205\343\200\201\351\203\250\345\210\206\351\205\215\347\275\256icarus\344\270\273\351\242\230\344\270\255\346\226\207\347\211\210.html" create mode 100644 "think/2019\345\271\264\347\273\210\346\200\273\347\273\223.html" create mode 100644 think/Hello-blog.html create mode 100644 think/hello-world.html create mode 100644 "think/\345\220\216\347\273\255\350\256\241\345\210\222.html" create mode 100644 "think/\351\230\277\351\207\214\344\270\200\345\271\264\347\232\204\346\210\220\351\225\277\347\273\217\345\216\206.html" create mode 100644 "tools/docker\345\256\211\350\243\205\344\270\216\344\275\277\347\224\250.html" create mode 100644 "travel/\350\245\277\345\256\211\346\227\205\346\270\270\346\224\273\347\225\2453\346\227\245\346\270\270.html" diff --git a/404.html b/404.html new file mode 100644 index 0000000000..31c290b7f2 --- /dev/null +++ b/404.html @@ -0,0 +1,181 @@ + +辣椒の酱 + +

+ + +
评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...

\ No newline at end of file diff --git a/about/index.html b/about/index.html new file mode 100644 index 0000000000..323aa50518 --- /dev/null +++ b/about/index.html @@ -0,0 +1,306 @@ + +辣椒の酱 + +
https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2020/20201030172650.png

个人简介


+

分享很喜欢的老罗的一段话:

+
+

每一个生命来到世间都注定改变世界,别无选择。要么变得好一点,要么变得坏一点。你如果走进社会为了生存为了什么不要脸的理由,变成了一个恶心的成年人社会中的一员,那你就把这个世界变得恶心了一点点。如果你一生刚正不阿,如果你一生耿直,没有做任何恶心的事情,没做对别人有害的事情,一辈子拼了老命勉强把自己身边的几个人照顾好了,没有成名没有发财,没有成就伟大的事业,然后耿着脖子一生正直,到了七八十岁耿着脖子去世了。你这一生是不是没有改变世界?你还是改变世界了,你把这个世界变得美好了一点点。因为世界上又多了一个好人。

+
+

善恶终有报,天道好轮回。不信抬头看,苍天饶过谁。
无论何时何地,我们都要保持一颗积极乐观、善良感恩的心。
但行好事莫问前程,永远年轻,永远热内盈眶,永远保持正能量
💪💪💪💪💪💪冲鸭!!!!

+

->>>>>>>>>>>>>>>>>>>>
个人信息:
计算机科学与技术专业
从事JAVA后端开发
码畜一枚
坚信代码改变世界

+
+ +

博客信息


+
    +
  • 网站采用的Icarus主题
  • +
  • 追求尽可能的简洁,清晰,易用。
  • +
  • 在Icarus主题之上进行了部分修改。
  • +
+

更新日志:
2023.04.28:升级gitalk插件
2020.03.18:加入pjax支持
2020.03.01:独立出主题仓库hexo-theme-amazing
2020.01.18:适配icarus3.0代码
2019.11.17:增加深色主题开关
2019.10.30:去图,精简卡片
2019.10.22:改版部分显示,优化速度
2019.10.16:文章列表加上评论数显示
2019.10.13:改版评论
2019.09.25:图片、资源接入CDN免费jsDelivr、文章加入置顶
2019.09.19:开源博客代码
2019.09.19:修改布局,拉伸布局,更宽的展示
2019.09.18:修改友链ui为一行三个,并适配移动端,暗黑模式文章增加评论链接,增加留言链接
2019.09.14:增加精简next主题
2019.09.14:利用中秋节放假,重做了首页的热门推荐、加个widget最新评论框、归档页加入文章贡献概览面板

+
+ +

本站推荐索引


+

博客主题相关

+ +

技术知识点

+ +

法律法规

+ +

其他

+ +

捐赠

+

感觉博客不错、对你有帮助的话,欢迎捐赠,支持以下3种一次性捐赠,感谢!

+
+ +

支付宝捐赠 微信捐赠

+
+ +

点击浏览以下广告捐赠

+
+ + + +
+
+ +

计划

2021计划

+
+

2021.01.02

+
+

2021-GOALS

+
    +
  • 跑两三场马拉松,平时定期每周至少运动一次
  • +
  • 多学习,多写博文,至少沉淀10篇
  • +
  • 多读书,平均每天1h,年底至少300h
  • +
  • 去一次2-3天的旅行
  • +
  • 多交朋友,多交流沟通
  • +
+
+

2020计划

+
+

2019.12.31->更新于2021.01.02

+
+

2020-GOALS

+
    +
  • 跑两三场马拉松 ->100% 1全,1半
  • +
  • 多学习,多写博文,年终达到150篇 ->20% 年终119篇,差太远!!!
  • +
  • 多读书,平均每天1h,年底至少300h ->95% 280h
  • +
  • 晚上多跑步,一周至少两次,体重减少10斤 ->50%
  • +
  • 去一次2-3天的旅行 ->0% 因为疫情等原因一次也没外出
    额外
  • +
  • 换了工作
    总结
  • +
  • 这一年经历了很多事情,看明白了很多事情,看清了自己的定位以及自身情况,确定了一些未来的计划以及目标,明白了当下重点该做的事情,以及交际中一些处事原则,生活礼仪,2021加油!
  • +
+
+

2019计划

+
+

2018.12.31/21:59:00->更新于2019.12.31

+
+

2019-GOALS

+
    +
  • 购买的专业书籍至少看完一遍(并发、重构、设计模式…)-> 95%
  • +
  • 微信读书每天一个小时(目前时长:95h,年终总计300小时) -> 100%,405h
  • +
  • 坚持每周去两次健身房(多练肚子、力量、学会蝶泳) -> 50%,蝶泳90%,其余30%左右
  • +
  • 至少完成一项 前后端分离项目 -> 20%,烂尾
  • +
  • 完成一项 微服务项目(类似公司使用相关技术) -> 20%,烂尾
  • +
  • 不辞职 -> 100%
  • +
  • 多交朋友、多换位思考、多与朋友交流沟通 -> 70%
  • +
  • 居安思危,多思考关注相关专业前景,生活环境 -> 50%
  • +
  • Java基础技能强化 -> 50%
  • +
  • 多买书 -> 100% (新增哈利波特1-4汉英版)
  • +
  • 学习更多的新菜(至少三项) -> 60%
  • +
  • 少买电子产品,少网购,少逛数码产品 -> 60%(新增华米运动手表2二手,一加2二手,小米电纸书)
  • +
  • 学英语记单词、学数学、多看视频教程 -> 20%
  • +
  • 少玩游戏 -2019.06卸载游戏 -> 80%
    额外:
  • +
  • 追了很多剧
  • +
  • 写了好些博客文章,修改开源了博客源码
  • +
  • 年末去了一趟西安旅行,看了一场移动的演出《驼铃传奇》,强烈安利!
  • +
  • 入坑马拉松,跑了3场半程马拉松,一场全程马拉松
    总结:
  • +
  • 有优点有缺点,没坚持下来的还是太多,追了太多剧。以后多学习,多思考!
  • +
+
+
+ +

时间轴记录


+
+
    +
    + +
    +
    +

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git a/ads.txt b/ads.txt new file mode 100644 index 0000000000..7806ad6741 --- /dev/null +++ b/ads.txt @@ -0,0 +1 @@ +google.com, pub-6343805421927634, DIRECT, f08c47fec0942fa0 \ No newline at end of file diff --git a/album/index.html b/album/index.html new file mode 100644 index 0000000000..6df8cf1ec6 --- /dev/null +++ b/album/index.html @@ -0,0 +1,221 @@ + +辣椒の酱 + +
    https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2020/20201030170940.png

    🎈🎈微笑墙🎈🎈

    +

    彭小苒

    +
    + + +
    + +
    +

    唐艺昕

    +
    + + + +
    + +
    +

    李一桐

    +
    + + +
    + +
    +

    gakki

    +
    + + +
    + +
    +

    图片搜集于互联网,侵权请留言,马上处理😊。

    +
    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git a/algorithm/leetcode-1-Two-Sum.html b/algorithm/leetcode-1-Two-Sum.html new file mode 100644 index 0000000000..97d1e25fb1 --- /dev/null +++ b/algorithm/leetcode-1-Two-Sum.html @@ -0,0 +1,184 @@ + +leetcode-1-Two Sum - 辣椒の酱 + +
    leetcode-1-Two Sum

    leetcode-1-Two Sum

    description

    +

    Given an array of integers, return indices of the two numbers such that they add up to a specific target.
    You may assume that each input would have exactly one solution, and you may not use the same element twice.
    Example:
    Given nums = [2, 7, 11, 15], target = 9,
    Because nums[0] + nums[1] = 2 + 7 = 9,
    return [0, 1].

    +
    +

    common method

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Solution {
    public int[] twoSum(int[] nums, int target) {
    int[] ret = new int[2];
    for(int i =0; i<nums.length-1 ;i++){
    for (int j = i+1 ;j < nums.length ;j++ ){
    if (nums[i] + nums[j] == target){
    ret = new int[]{i, j};
    return ret;
    }
    }
    }
    return ret ;
    }
    }
    + +

    best method

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class Solution {
    public int[] twoSum(int[] nums, int target) {
    int len=nums.length;
    HashMap<Integer, Integer> map=new HashMap<>();
    map.put(nums[0], 0);
    for(int i=1;i<len;i++){
    if(map.containsKey(target-nums[i])){
    int[] returnArray={map.get(target-nums[i]),i};
    return returnArray;
    } else{
    map.put(nums[i], i);
    }
    }
    int[] returnArray={0,0};
    return returnArray;
    }
    }
    +
    发布于

    2018-11-11

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git a/algorithm/leetcode-2-Add-Two-Numbers.html b/algorithm/leetcode-2-Add-Two-Numbers.html new file mode 100644 index 0000000000..3c2d8f8d87 --- /dev/null +++ b/algorithm/leetcode-2-Add-Two-Numbers.html @@ -0,0 +1,182 @@ + +leetcode-2-Add Two Numbers - 辣椒の酱 + +
    leetcode-2-Add Two Numbers

    leetcode-2-Add Two Numbers

    Add Two Numbers

    +

    You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
    You may assume the two numbers do not contain any leading zero, except the number 0 itself.

    Example:
    Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
    Output: 7 -> 0 -> 8
    Explanation: 342 + 465 = 807.

    +
    +

    common

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    /**
    * Definition for singly-linked list.
    * public class ListNode {
    * int val;
    * ListNode next;
    * ListNode(int x) { val = x; }
    * }
    */
    class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    ListNode dummyHead = new ListNode(0); // 一点要赋值一个节点,进行操作
    ListNode p = l1, q = l2, curr = dummyHead;
    int carry = 0;
    while (p != null || q != null) {
    int x = (p != null) ? p.val : 0;
    int y = (q != null) ? q.val : 0;
    int sum = carry + x + y;
    carry = sum / 10;
    curr.next = new ListNode(sum % 10);
    curr = curr.next;
    if (p != null) p = p.next;
    if (q != null) q = q.next;
    }
    if (carry > 0) {
    curr.next = new ListNode(carry);
    }
    return dummyHead.next;
    }
    }
    +

    best

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    /**
    * Definition for singly-linked list.
    * public class ListNode {
    * int val;
    * ListNode next;
    * ListNode(int x) { val = x; }
    * }
    */
    class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    ListNode head = new ListNode(0);
    int carry = 0;
    while(l1!=null||l2!=null||carry>0)
    {
    ListNode itr = head;
    while(itr.next!=null)
    itr = itr.next; // 寻找最后一个节点
    int sum = ( (l1==null ? 0 : l1.val) + (l2==null ? 0 : l2.val) + carry);
    carry = sum/10;
    ListNode temp = new ListNode(sum%10);
    itr.next = temp;
    if(l1!=null)
    l1 = l1.next;
    if(l2!=null)
    l2 = l2.next;
    }

    return head.next;
    }
    }
    发布于

    2018-11-16

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\344\272\214\345\210\206\346\237\245\346\211\276\346\263\225\346\250\241\346\235\277\347\232\204\345\237\272\346\234\254\346\200\235\346\203\263-leetcode35.html" "b/algorithm/\344\272\214\345\210\206\346\237\245\346\211\276\346\263\225\346\250\241\346\235\277\347\232\204\345\237\272\346\234\254\346\200\235\346\203\263-leetcode35.html" new file mode 100644 index 0000000000..c157bf9556 --- /dev/null +++ "b/algorithm/\344\272\214\345\210\206\346\237\245\346\211\276\346\263\225\346\250\241\346\235\277\347\232\204\345\237\272\346\234\254\346\200\235\346\203\263-leetcode35.html" @@ -0,0 +1,314 @@ + +二分查找法模板的基本思想-leetcode35 - 辣椒の酱 + +
    二分查找法模板的基本思想-leetcode35

    二分查找法模板的基本思想-leetcode35

    leetcode35

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

    +

    你可以假设数组中无重复元素。

    + + +

    示例 1:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    输入: [1,3,5,6], 5
    输出: 2
    示例 2:

    输入: [1,3,5,6], 2
    输出: 1
    示例 3:

    输入: [1,3,5,6], 7
    输出: 4
    示例 4:

    输入: [1,3,5,6], 0
    输出: 0

    + +

    传统解法:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    public class Solution3 {

    public int searchInsert(int[] nums, int target) {
    int len = nums.length;
    if (nums[len - 1] < target) {
    return len;
    }

    int left = 0;
    int right = len - 1;

    while (left <= right) {
    int mid = (left + right) / 2;
    // 等于的情况最简单,我们应该放在第 1 个分支进行判断
    if (nums[mid] == target) {
    return mid;
    } else if (nums[mid] < target) {
    // 题目要我们返回大于或者等于目标值的第 1 个数的索引
    // 此时 mid 一定不是所求的左边界,
    // 此时左边界更新为 mid + 1
    left = mid + 1;
    } else {
    // 既然不会等于,此时 nums[mid] > target
    // mid 也一定不是所求的右边界
    // 此时右边界更新为 mid - 1
    right = mid - 1;
    }
    }
    // 注意:一定得返回左边界 left,
    // 如果返回右边界 right 提交代码不会通过
    // 【注意】下面我尝试说明一下理由,如果你不太理解下面我说的,那是我表达的问题
    // 但我建议你不要纠结这个问题,因为我将要介绍的二分查找法模板,可以避免对返回 left 和 right 的讨论

    // 理由是对于 [1,3,5,6],target = 2,返回大于等于 target 的第 1 个数的索引,此时应该返回 1
    // 在上面的 while (left <= right) 退出循环以后,right < left,right = 0 ,left = 1
    // 根据题意应该返回 left,
    // 如果题目要求你返回小于等于 target 的所有数里最大的那个索引值,应该返回 right

    return left;
    }
    }
    + +

    说明

    +

    a、当把二分查找法的循环可以进行的条件写成 while (left <= right) 时,在写最后一句 return 的时候,如果不假思索,把左边界 left 返回回去,虽然写对了,但可以思考一下为什么不返回右边界 right 呢?

    +

    b、但是事实上,返回 left 是有一定道理的,如果题目换一种问法,你可能就要返回右边界 right,这句话不太理解没有关系,我也不打算讲得很清楚(在上面代码的注释中我已经解释了原因),因为实在太绕了,这不是我要说的重点。

    +

    二分查找法模板的基本思想

    1、首先把循环可以进行的条件写成 while(left < right),在退出循环的时候,一定有 left == right 成立,此时返回 left 或者 right 都可以
    或许你会问:退出循环的时候还有一个数没有看啊(退出循环之前索引 left 或 索引 right 上的值)?
    没有关系,我们就等到退出循环以后来看,甚至经过分析,有时都不用看,就能确定它是目标数值。

    +

    (什么时候需要看最后剩下的那个数,什么时候不需要,会在后面介绍。)

    +

    更深层次的思想是“夹逼法”或者称为“排除法”。

    +

    2、“神奇的”二分查找法模板的基本思想(特别重要)
    “排除法”即:在每一轮循环中排除一半以上的元素,于是在对数级别的时间复杂度内,就可以把区间“夹逼” 只剩下 1 个数,而这个数是不是我们要找的数,单独做一次判断就可以了。

    +

    “夹逼法”或者“排除法”是二分查找算法的基本思想,“二分”是手段,在目标元素不确定的情况下,“二分” 也是“最大熵原理”告诉我们的选择。

    +

    还是 LeetCode 第 35 题,下面给出使用 while (left < right) 模板写法的 2 段参考代码,以下代码的细节部分在后文中会讲到,因此一些地方不太明白没有关系,暂时跳过即可。

    +

    参考代码 1:重点理解为什么候选区间的索引范围是 [0, size]。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    from typing import List

    class Solution:

    def searchInsert(self, nums: List[int], target: int) -> int:
    # 返回大于等于 target 的索引,有可能是最后一个
    size = len(nums)
    # 特判
    if size == 0:
    return 0

    left = 0
    # 如果 target 比 nums里所有的数都大,则最后一个数的索引 + 1 就是候选值,因此,右边界应该是数组的长度
    right = size
    # 二分的逻辑一定要写对,否则会出现死循环或者数组下标越界
    while left < right:
    mid = left + (right - left) // 2
    if nums[mid] < target:
    left = mid + 1
    else:
    assert nums[mid] >= target
    # [1,5,7] 2
    right = mid
    # 调试语句
    # print('left = {}, right = {}, mid = {}'.format(left, right, mid))
    return left


    + +

    参考代码 2:对于是否接在原有序数组后面单独判断,不满足的时候,再在候选区间的索引范围 [0, size - 1] 内使用二分查找法进行搜索。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    from typing import List


    class Solution:

    def searchInsert(self, nums: List[int], target: int) -> int:
    # 返回大于等于 target 的索引,有可能是最后一个
    size = len(nums)
    # 特判 1
    if size == 0:
    return 0
    # 特判 2:如果比最后一个数字还要大,直接接在它后面就可以了
    if target > nums[-1]:
    return size

    left = 0
    right = size - 1
    # 二分的逻辑一定要写对,否则会出现死循环或者数组下标越界
    while left < right:
    mid = left + (right - left) // 2
    if nums[mid] < target:
    left = mid + 1
    else:
    assert nums[mid] >= target
    right = mid
    return left
    + +

    细节、注意事项、调试方法

    1、前提:思考左、右边界,如果左、右边界不包括目标数值,会导致错误结果
    例:LeetCode 第 69 题:x 的平方根

    +

    实现 int sqrt(int x) 函数。

    +

    计算并返回 x 的平方根,其中 x 是非负整数。

    +

    由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

    +

    分析:一个非负整数的平方根最小可能是 0 ,最大可能是它自己。
    因此左边界可以取 0 ,右边界可以取 x。
    可以分析得再细一点,但这道题没有必要,因为二分查找法会帮你排除掉不符合的区间元素。

    +

    例:LeetCode 第 287 题:寻找重复数

    +

    给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

    +

    分析:题目告诉我们“其数字都在 1 到 n 之间(包括 1 和 n)”。因此左边界可以取 1 ,右边界可以取 n。

    +

    要注意 2 点:

    +

    如果 left 和 right 表示的是数组的索引,就要考虑“索引是否有效” ,即“索引是否越界” 是重要的定界依据;

    +

    左右边界一定要包括目标元素,例如 LeetCode 第 35 题:“搜索插入位置” ,当 target 比数组中的最后一个数字还要大(不能等于)的时候,插入元素的位置就是数组的最后一个位置 + 1,即 (len - 1 + 1 =) len,如果忽略掉这一点,把右边界定为 len - 1 ,代码就不能通过在线测评。

    +

    2、中位数先写 int mid = (left + right) >>> 1 ; 根据循环里分支的编写情况,再做调整
    理解这一点,首先要知道:当数组的元素个数是偶数的时候,中位数有左中位数和右中位数之分。

    +

    当数组的元素个数是偶数的时候:
    使用 int mid = left + (right - left) / 2 ; 得到左中位数的索引;

    +

    使用 int mid = left + (right - left + 1) / 2 ; 得到右中位数的索引。

    +

    当数组的元素个数是奇数的时候,以上二者都能选到最中间的那个中位数。
    其次,

    +

    int mid = left + (right - left) / 2 ; 等价于 int mid = (left + right) >>> 1;

    +

    int mid = left + (right - left + 1) / 2 ; 等价于 int mid = (left + right + 1) >>> 1 。

    +

    我们使用一个具体的例子来验证:当左边界索引 left = 3,右边界索引 right = 4 的时候,

    +

    mid1 = left + (right - left) // 2 = 3 + (4 - 3) // 2 = 3 + 0 = 3,

    +

    mid2 = left + (right - left + 1) // 2 = 3 + (4 - 3 + 1) // 2 = 3 + 1 = 4。

    +

    左中位数 mid1 是索引 left,右中位数 mid2 是索引 right。

    +

    记忆方法:

    +

    (right - left) 不加 11 选左中位数,加 11 选右中位数。

    +

    那么,什么时候使用左中位数,什么时候使用右中位数呢?选中位数的依据是为了避免死循环,得根据分支的逻辑来选择中位数,而分支逻辑的编写也有技巧,下面具体说。

    +

    3、先写逻辑上容易想到的分支逻辑,这个分支逻辑通常是排除中位数的逻辑;
    在逻辑上,“可能是也有可能不是”让我们感到犹豫不定,但**“一定不是”是我们非常坚决的,通常考虑的因素特别单一,因此“好想” **。在生活中,我们经常听到这样的话:找对象时,“有车、有房,可以考虑,但没有一定不要”;找工作时,“事儿少、离家近可以考虑,但是钱少一定不去”,就是这种思想的体现。

    +

    例:LeetCode 第 69 题:x 的平方根

    +

    实现 int sqrt(int x) 函数。

    +

    计算并返回 x 的平方根,其中 x 是非负整数。

    +

    由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

    +

    分析:因为题目中说“返回类型是整数,结果只保留整数的部分,小数部分将被舍去”。例如 55 的平方根约等于 2.2362.236,在这道题应该返回 22。因此如果一个数的平方小于或者等于 x,那么这个数有可能是也有可能不是 x 的平方根,但是能很肯定的是,如果一个数的平方大于 x ,这个数肯定不是 x 的平方根。

    +

    注意:先写“好想”的分支,排除了中位数之后,通常另一个分支就不排除中位数,而不必具体考虑另一个分支的逻辑的具体意义,且代码几乎是固定的。

    +

    4、循环内只写两个分支,一个分支排除中位数,另一个分支不排除中位数,循环中不单独对中位数作判断
    既然是“夹逼”法,没有必要在每一轮循环开始前单独判断当前中位数是否是目标元素,因此分支数少了一支,代码执行效率更高。

    +

    以下是“排除中位数的逻辑”思考清楚以后,可能出现的两个模板代码。

    +

    +

    可以排除“中位数”的逻辑,通常比较好想,但并不绝对,这一点视情况而定。

    +

    分支条数变成 2 条,比原来 3 个分支要考虑的情况少,好处是:

    +

    不用在每次循环开始单独考虑中位数是否是目标元素,节约了时间,我们只要在退出循环的时候,即左右区间压缩成一个数(索引)的时候,去判断这个索引表示的数是否是目标元素,而不必在二分的逻辑中单独做判断。

    +

    这一点很重要,希望读者结合具体练习仔细体会,每次循环开始的时候都单独做一次判断,在统计意义上看,二分时候的中位数恰好是目标元素的概率并不高,并且即使要这么做,也不是普适性的,不能解决绝大部分的问题。

    +

    还以 LeetCode 第 35 题为例,通过之前的分析,我们需要找到“大于或者等于目标值的第 1 个数的索引”。对于这道题而言:

    +
      +
    • 如果中位数小于目标值,它就应该被排除,左边界 left 就至少是 mid + 1;

      +
    • +
    • 如果中位数大于等于目标值,还不能够肯定它就是我们要找的数,因为要找的是等于目标值的第 11 个数的索引,中位数以及中位数的左边都有可能是符合题意的数,因此右边界就不能把 mid 排除,因此右边界 right 至多是 mid,此时右边界不向左边收缩。

      +
    • +
    +

    下一点就更关键了。

    +

    5、根据分支逻辑选择中位数的类型,可能是左中位数,也可能是右位数,选择的标准是避免死循环

    +

    +

    死循环容易发生在区间只有 22 个元素时候,此时中位数的选择尤为关键。选择中位数的依据是:避免出现死循环。我们需要确保:

    +

    (下面的这两条规则说起来很绕,可以暂时跳过)。

    +
      +
    • 如果分支的逻辑,在选择左边界的时候,不能排除中位数,那么中位数就选“右中位数”,只有这样区间才会收缩,否则进入死循环;

      +
    • +
    • 同理,如果分支的逻辑,在选择右边界的时候,不能排除中位数,那么中位数就选“左中位数”,只有这样区间才会收缩,否则进入死循环。

      +
    • +
    +

    理解上面的这个规则可以通过具体的例子。针对以上规则的第 1 点:如果分支的逻辑,在选择左边界的时候不能排除中位数,例如:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    while left < right:
    # 不妨先写左中位数,看看你的分支会不会让你代码出现死循环,从而调整
    mid = left + (right - left) // 2
    # 业务逻辑代码
    if (check(mid)):
    # 选择右边界的时候,可以排除中位数
    right = mid - 1
    else:
    # 选择左边界的时候,不能排除中位数
    left = mid

    + +

    在区间中的元素只剩下 22 个时候,例如:left = 3,right = 4。此时左中位数就是左边界,如果你的逻辑执行到 left = mid 这个分支,且你选择的中位数是左中位数,此时左边界就不会得到更新,区间就不会再收缩(理解这句话是关键),从而进入死循环;
    为了避免出现死循环,你需要选择中位数是右中位数,当逻辑执行到 left = mid 这个分支的时候,因为你选择了右中位数,让逻辑可以转而执行到 right = mid - 1 让区间收缩,最终成为 1 个数,退出 while 循环。
    上面这段话不理解没有关系,因为我还没有举例子,你有个印象就好,类似地,理解选择中位数的依据的第 2 点。

    +

    6、退出循环的时候,可能需要对“夹逼”剩下的那个数单独做一次判断,这一步称之为“后处理”。
    二分查找法之所以高效,是因为它利用了数组有序的特点,在每一次的搜索过程中,都可以排除将近一半的数,使得搜索区间越来越小,直到区间成为一个数。回到这一节最开始的疑问:“区间左右边界相等(即收缩成 1 个数)时,这个数是否会漏掉”,解释如下:

    +
      +
    • 如果你的业务逻辑保证了你要找的数一定在左边界和右边界所表示的区间里出现,那么可以放心地返回 left 或者 right,无需再做判断;

      +
    • +
    • 如果你的业务逻辑不能保证你要找的数一定在左边界和右边界所表示的区间里出现,那么只要在退出循环以后,再针对 nums[left] 或者 nums[right] (此时 nums[left] == nums[right])单独作一次判断,看它是不是你要找的数即可,这一步操作常常叫做“后处理”。

      +
    • +
    +

    如果你能确定候选区间里目标元素一定存在,则不必做“后处理”。
    例:LeetCode 第 69 题:x 的平方根

    +

    实现 int sqrt(int x) 函数。

    +

    计算并返回 x 的平方根,其中 x 是非负整数。

    +

    由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

    +

    分析:非负实数 x 的平方根在 [0, x] 内一定存在,故退出 while (left < right) 循环以后,不必单独判断 left 或者 right 是否符合题意。

    +

    如果你不能确定候选区间里目标元素一定存在,需要单独做一次判断。
    例:LeetCode 第 704 题:二分查找

    +

    给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

    +

    分析:因为目标数有可能不在数组中,当候选区间夹逼成一个数的时候,要单独判断一下这个数是不是目标数,如果不是,返回 -1。

    +

    7、取中位数的时候,要避免在计算上出现整型溢出;
    int mid = (left + right) / 2; 的问题:在 left 和 right 很大的时候,left + right 会发生整型溢出,变成负数,这是一个 bug ,得改!

    +

    int mid = left + (right - left) / 2; 在 right 很大、 left 是负数且很小的时候, right - left 也有可能超过 int 类型能表示的最大值,只不过一般情况下 left 和 right 表示的是数组索引值,left 是非负数,因此 right - left 溢出的可能性很小。因此,它是正确的写法。下面介绍推荐的写法。

    +

    int mid = (left + right) >>> 1; 如果这样写, left + right 在发生整型溢出以后,会变成负数,此时如果除以 22 ,mid 是一个负数,但是经过无符号右移,可以得到在不溢出的情况下正确的结果。

    +

    解释“无符号右移”:在 Java 中,无符号右移运算符 >>> 和右移运算符 >> 的区别如下:

    +

    右移运算符 >> 在右移时,丢弃右边指定位数,左边补上符号位;
    无符号右移运算符 >>> 在右移时,丢弃右边指定位数,左边补上 00,也就是说,对于正数来说,二者一样,而负数通过 >>> 后能变成正数。
    下面解释上面的模板中,取中位数的时候使用先用“+”,然后“无符号右移”。

    +

    a、int mid = (left + right) / 2 与 int mid = left + (right - left) / 2 两种写法都有整型溢出的风险,没有哪一个是绝对安全的,注意:这里我们取平均值用的是除以 2,并且是整除:

    +

    int mid = (left + right) / 2 在 left 和 right 都很大的时候会溢出;
    int mid = left + (right - left) / 2 在 right 很大,且 left 是负数且很小的时候会溢出;
    b、写算法题的话,一般是让你在数组中做二分查找,因此 left 和 right 一般都表示数组的索引,因此 left 在绝大多数情况下不会是负数并且很小,因此使用 int mid = left + (right - left) // 2 相对 int mid = (left + right) // 2 更安全一些,并且也能向别人展示我们注意到了整型溢出这种情况,但事实上,还有更好的方式;

    +

    c、建议使用 int mid = (left + right) >>> 1 这种写法,其实是大有含义的:

    +

    JDK8 中采用 int mid = (left + right) >>> 1 ,重点不在 + ,而在 >>> 。

    +

    我们看极端的情况,left 和 high 都是整型最大值的时候,注意,此时 3232 位整型最大值它的二进制表示的最高位是 00,它们相加以后,最高位是 11 ,变成负数,但是再经过无符号右移 >>>(重点是忽略了符号位,空位都以 00 补齐),就能保证使用 + 在整型溢出了以后结果还是正确的。

    +

    Java 中 Collections 和 Arrays 提供的 binarySearch 方法,我们点进去看 left 和 right 都表示索引,使用无符号右移又不怕整型溢出,那就用 int mid = (left + right) >>> 1 好啦。位运算本来就比使用除法快,这样看来使用 + 和 <<< 真的是又快又好了。

    +

    我想这一点可能是 JDK8 的编写者们更层次的考量。

    +

    看来以后写算法题,就用 int mid = (left + right) >>> 1 吧,反正更多的时候 left 和 right 表示索引。

    +

    8、编码一旦出现死循环,输出必要的变量值、分支逻辑是调试的重要方法。
    当出现死循环的时候的调试方法:打印输出左右边界、中位数的值和目标值、分支逻辑等必要的信息。

    +

    按照我的经验,一开始编码的时候,稍不注意就很容易出现死循环,不过没有关系,你可以你的代码中写上一些输出语句,就容易理解“在区间元素只有 2 个的时候容易出现死循环”。具体编码调试的细节,可以参考我在「力扣」第 69 题:x 的平方根的题解《二分查找 + 牛顿法(Python 代码、Java 代码)》 。

    +

    总结

    总结一下,我爱用这个模板的原因、技巧、优点和注意事项:

    +

    原因:
    无脑地写 while left < right: ,这样你就不用判断,在退出循环的时候你应该返回 left 还是 right,因为返回 left 或者 right 都对;

    +

    技巧:
    先写分支逻辑,并且先写排除中位数的逻辑分支(因为更多时候排除中位数的逻辑容易想,但是前面我也提到过,这并不绝对),另一个分支的逻辑你就不用想了,写出第 1 个分支的反面代码即可(下面的说明中有介绍),再根据分支的情况选择使用左中位数还是右中位数;

    +

    说明:这里再多说一句。如果从代码可读性角度来说,只要是你认为好想的逻辑分支,就把它写在前面,并且加上你的注释,这样方便别人理解,而另一个分支,你就不必考虑它的逻辑了。有的时候另一个分支的逻辑并不太好想,容易把自己绕进去。如果你练习做得多了,会形成条件反射。

    +

    我简单总结了一下,左右分支的规律就如下两点:

    +

    如果第 1 个分支的逻辑是“左边界排除中位数”(left = mid + 1),那么第 2 个分支的逻辑就一定是“右边界不排除中位数”(right = mid),反过来也成立;

    +

    如果第 2 个分支的逻辑是“右边界排除中位数”(right = mid - 1),那么第 2 个分支的逻辑就一定是“左边界不排除中位数”(left = mid),反之也成立。

    +

    “反过来也成立”的意思是:如果在你的逻辑中,“边界不能排除中位数”的逻辑好想,你就把它写在第 1 个分支,另一个分支是它的反面,你可以不用管逻辑是什么,按照上面的规律直接给出代码就可以了。能这么做的理论依据就是“排除法”。

    +

    在「力扣」第 287 题:寻找重复数的题解《二分法(Python 代码、Java 代码)》和这篇题解的评论区中,有我和用户
    @fighterhit 给出的代码,在一些情况下,我们先写了不排除中位数的逻辑分支,更合适的标准就是“哪个逻辑分支好想,就先写哪一个”,欢迎大家参与讨论。

    +

    优点:
    分支条数只有 2 条,代码执行效率更高,不用在每一轮循环中单独判断中位数是否符合题目要求,写分支的逻辑的目的是尽量排除更多的候选元素,而判断中位数是否符合题目要求我们放在最后进行,这就是第 5 点;

    +

    说明:每一轮循环开始都单独判断中位数是否符合要求,这个操作不是很有普适性,因为从统计意义上说,中位数直接就是你想找的数的概率并不大,有的时候还要看看左边,还要看看右边。不妨就把它放在最后来看,把候选区间“夹逼”到只剩 11 个元素的时候,视情况单独再做判断即可。

    +

    注意事项 1:
    左中位数还是右中位数选择的标准根据分支的逻辑而来,标准是每一次循环都应该让区间收缩,当候选区间只剩下 22 个元素的时候,为了避免死循环发生,选择正确的中位数类型。如果你实在很晕,不防就使用有 22 个元素的测试用例,就能明白其中的原因,另外在代码出现死循环的时候,建议你可以将左边界、右边界、你选择的中位数的值,还有分支逻辑都打印输出一下,出现死循环的原因就一目了然了;

    +

    注意事项 2:
    如果能确定要找的数就在候选区间里,那么退出循环的时候,区间最后收缩成为 11 个数后,直接把这个数返回即可;如果你要找的数有可能不在候选区间里,区间最后收缩成为 11 个数后,还要单独判断一下这个数是否符合题意。

    +

    最后给出两个模板,大家看的时候看注释,不必也无需记忆它们。

    +

    +

    +

    说明:我写的时候,一般是先默认将中位数写成左中位数,再根据分支的情况,看看是否有必要调整成右中位数,即是不是要在 (right - left) 这个括号里面加 11 。

    +

    虽说是两个模板,区别在于选中位数,中位数根据分支逻辑来选,原则是区间要收缩,且不出现死循环,退出循环的时候,视情况,有可能需要对最后剩下的数单独做判断。

    +

    我想我应该是成功地把你绕晕了,如果您觉得啰嗦的地方,就当我是“重要的事情说了三遍”吧,确实是重点的地方我才会重复说。当然,最好的理解这个模板的方法还是应用它。在此建议您不妨多做几道使用“二分查找法”解决的问题,用一下我说的这个模板,在发现问题的过程中,体会这个模板好用的地方,相信你一定会和我一样爱上这个模板的。

    +

    在「力扣」的探索版块中,给出了二分查找法的 3 个模板,我这篇文章着重介绍了第 2 个模板,但是我介绍的角度和这个版块中给出的角度并不一样,第 1 个模板被我“嫌弃”了,第 3 个模板我看过了,里面给出的例题也可以用第 2 个模板来完成,如果大家有什么使用心得,欢迎与我交流。

    +

    来源:力扣(LeetCode),作者:liweiwei1419

    +
    发布于

    2019-12-05

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\345\212\250\346\200\201\350\247\204\345\210\222DP\347\256\227\346\263\225\350\257\246\350\247\243.html" "b/algorithm/\345\212\250\346\200\201\350\247\204\345\210\222DP\347\256\227\346\263\225\350\257\246\350\247\243.html" new file mode 100644 index 0000000000..30ffa28e4c --- /dev/null +++ "b/algorithm/\345\212\250\346\200\201\350\247\204\345\210\222DP\347\256\227\346\263\225\350\257\246\350\247\243.html" @@ -0,0 +1,288 @@ + +动态规划DP算法详解 - 辣椒の酱 + +
    动态规划DP算法详解

    动态规划DP算法详解

    定义

    动态规划(dynamic programing)和分治法类似,都是通过组合子问题的解来求解原问题的解。(在经典排序算法中的二路归并排序和快速排序都用到了分而治之的思想-分治法)。

    +

    分治法是将原问题划分为没有交集,相互独立的子问题,并分别求解后再进行合并,求出原问题的解。

    +

    动态规划应用于子问题重叠的情况,即不同的子问题具有公共的子子问题。分治法会做许多不必要的工作,它会反复地求解那些公共子问题。动态规划算法对每个子问题只求解一次,将其解保存在一个表格中,从而无需每次求解一个子子问题时都需要重新计算。

    + + +

    动态规划上用来求解最优化问题(optimization problem)。

    +

    可以按照下面四个步骤来设计一个动态规划算法

    +

    1、刻画一个最优解的结构特征。

    +

    2、递归地定义最优解的值。

    +

    3、计算最优解的值,通常采用自底向上的方法。

    +

    4、利用计算出的信息构造一个最优解。

    +

    对于确定状态转移方程就在第一步和第二步中,首先要确定问题的决策对象,接着对决策对象划分阶段并确定各个阶段的状态变量,最后建立各阶段的状态变量的转移方程。

    +

    例如用dp[i]表示以序列中第i个数字结尾的最长递增子序列长度和最长公共子序列中用dp[i][j]表示的两个字符串中前 i、 j 个字符的最长公共子序列,我们就是通过对这两个数字量的不断求解最终得到答案的。这个数字量就被我们称为状态。状态是描述问题当前状况的一个数字量。首先,它是数字的,是可以被抽象出来保存在内存中的。其次,它可以完全的表示一个状态的特征,而不需要其他任何的辅助信息。最后,也是状态最重要的特点,状态间的转移完全依赖于各个状态本身,如最长递增子序列中,dp[x]的值由 dp[i](i < x)的值确定。若我们在分析动态规划问题的时候能够找到这样一个符合以上所有条件的状态,那么多半这个问题是可以被正确解出的。所以说,解动态规划问题的关键,就是寻找一个好的状态。

    +

    最优子结构

    用动态规划求解最优化问题的第一步就是刻画一个最优解的结构特征。如果一个问题的最优解包含其子问题的最优解,我们称此问题具有最优子结构性质。因此,某个问题是否适合用动态规划,它是否具有最优子结构性质是一个好的标准。使用动态规划方法时,我们用子问题的最优解来构造原问题的最优解。

    +

    如何发掘最优子结构的性质?

    1、证明问题最优解的第一个组成部分是做出一个选择,而做出这个选择将会产生一个或多个待解的子问题。

    +

    2、对一个给定问题,在其可能的第一步选择中,假定已经知道哪种选择才会得到最优解。而我们并不关心这种选择具体是如何得到的,只是假定已经知道了这种选择。

    +

    3、给定获取的最优解选择后,确定这次选择会产生哪些子问题,以及如何最好地刻画子问题空间。

    +

    4、利用“剪切-粘贴(cut and paste)”技术证明作为构成原问题最优解组成部分,每个子问题的解就是它本身的最优解。

    +

    反证法:假定子问题的解不是自身的最优解,那么我们就可以从原问题中剪切掉这些非最优解,将最优解粘贴进去,从而得到原问题一个更优的解,这个解与最初的解的前提假设矛盾。

    +

    刻画子问题空间的经验

    保持子问题空间尽量简单,只在必要时才扩展它。例如下一节的例子,求钢条切割的最大收益问题中,子问题空间包含的问题为:对每个i值,长度为i的钢条最优切割问题。

    +

    对于不同问题领域,最优子结构的不同体现在两个方面:

      +
    1. 原问题的最优解中涉及到多个子问题。
    2. +
    3. 在确定最优解使用哪些子问题时,需要考察多少种选择。
    4. +
    +

    重叠子问题

    适合用动态规划方法求解最优化问题的第二个性质是子问题的空间必须足够小,即问题的递归算法会反复地求解相同的子问题,而不是一直生成新的子问题。动态规划算法会对重叠的子问题只求解一次,并保存在一张表里,需要用的时候直接查表即可,每次查表的时间代价为常量O(1)。

    +

    核心问题

    动态规划的核心是状态和状态转移方程。

    +

    在记忆化搜索中,可以为正在处理的表项声明一个引用,简化对它的读写操作;

    +

    动态规划解决的是多阶段决策问题;

    +
    1
    初始状态→│决策1│→│决策2│→…→│决策n│→结束状态
    + +

    和分治法最大的区别在于:适合于用动态规划的问题,经过分解以后得到的子问题往往不是相互独立的(即下一个子阶段的求解是建立在上一个子阶段的基础之上,进行进一步的求解,而不是相互独立的问题)

    +

    动态规划问题一般由难到易分为一维动态规划,二维动态规划,多维动态规划,以及多变量动态规划问题。其中多维动态规划问题又可以进行降维。动态规划问题求解的最重要的一步就是求解出 状态转移方程

    +

    特性

    +
      +
    • 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理.
    • +
    • 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关
    • +
    • 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势,动态规划可以避免多次计算)
    • +
    +

    动态规划的解题核心主要分为两步:

    +
      +
    1. 第一步:状态的定义
    2. +
    3. 第二步:状态转移方程的定义
    4. +
    +

    在这里,我们为了避免混淆用“状态”这个词来替代“问题”这个词。“问题”表示的含义类似:题目、要求解的内容、题干中的疑问句这样的概念。状态表示我们在求解问题之中对问题的分析转化。

    +

    第一步:状态的定义

    +

    有的问题过于抽象,或者过于啰嗦干扰我们解题的思路,我们要做的就是将题干中的问题进行转化(换一种说法,含义不变)。转化成一系列同类问题的某个解的情况,比如说:

    +
    +

    题目:求一个数列中最大连续子序列的和。

    +
    +

    我们要将这个原问题转化为:

    +
    +

    状态定义:Fk是第k项前的最大序列和,求F1~FN中最大值。

    +
    +

    通过换一种表述方式,我们清晰的发现了解决问题的思路,如何求出F1~FN中的最大值是解决原问题的关键部分。上述将原问题转化成另一种表述方式的过程叫做:状态的定义。这样的状态定义给出了一种类似通解的思路,把一个原来毫无头绪的问题转换成了可以求解的问题。

    +

    第二步:状态转移方程的定义

    +

    在进行了状态的定义后,自然而然的想到去求解F1~FN中最大值。这也是状态定义的作用,让我们把一个总体的问题转化成一系列问题,而第二步:状态转移方程的定义则告诉我们如何去求解一个问题,对于上述已经转换成一系列问题我们要关注的点就在于:如何能够用前一项或者前几项的信息得到下一项,这种从最优子状态转换为下一个最优状态的思路就是动态规划的核心。
    对于上面的例子题目来说,状态转移方程的定义应该是:

    +
    +

    Fk=max{Fk-1+Ak,Ak}
    Fk是前k项的和,Ak是第k项的值

    +
    +

    仔细思考一番,我们能够得到这样的结论,对于前k个项的最大子序列和是前k-1项的最大子序列和Fk与第k项的和、或者第k项两者中较大的。如果大家还是不能理解这个原理建议用演算纸自己计算一番,这里就不过多赘述了。这种状态转移的思路就是DP的核心。

    +

    状态转移方程

    动态规划中当前的状态往往依赖于前一阶段的状态和前一阶段的决策结果。例如我们知道了第i个阶段的状态Si以及决策Ui,那么第i+1阶段的状态Si+1也就确定了。所以解决动态规划问题的关键就是确定状态转移方程,一旦状态转移方程确定了,那么我们就可以根据方程式进行编码。

    +

    各种模型的状态转移方程汇总如下:

    1、最长公共子串

    假设两个字符串为str1和str2,它们的长度分别为n和m。d[i][j]表示str1中前i个字符与str2中前j个字符分别组成的两个前缀字符串的最长公共长度。这样就把长度为n的str1和长度为m的str2划分成长度为i和长度为j的子问题进行求解。状态转移方程如下:

    +
    1
    2
    3
    4
    dp[0][j] = 0; (0<=j<=m)
    dp[i][0] = 0; (0<=i<=n)
    dp[i][j] = dp[i-1][j-1] +1; (str1[i] == str2[j])
    dp[i][j] = 0; (str1[i] != str2[j])
    + +

    因为最长公共子串要求必须在原串中是连续的,所以一但某处出现不匹配的情况,此处的值就重置为0。

    +

    详细代码请看最长公共子串

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    #include "stdafx.h"
    #include <stdio.h>
    #include <string>
    #include <iostream>
    using namespace std;

    #define MAXSIZE 100
    char str1[MAXSIZE];
    char str2[MAXSIZE];

    int dp[MAXSIZE][MAXSIZE];
    //'y'代表str1[i] = str2[j];'n'反之
    char path[MAXSIZE][MAXSIZE];

    void printComStr(int i, int j)
    {
    if (path[i][j] == 'n' || i == 0 || j == 0)
    return;
    if (path[i][j] == 'y')
    {
    printComStr(i - 1, j - 1);
    cout << str1[i - 1];
    }


    }

    int main()
    {
    int n, m;
    int indexi, indexj;
    int ans = 0;
    cin >> str1 >> str2;
    n = strlen(str1);
    m = strlen(str2);
    for (int i = 0; i <= n;i++)
    for (int j = 0; j <= m; j++)
    {
    dp[i][j] = 0;
    }
    for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
    {
    if (str1[i - 1] == str2[j - 1])
    {
    dp[i][j] = dp[i - 1][j - 1] + 1;
    path[i][j] = 'y';
    }
    else
    {
    dp[i][j] = 0;
    path[i][j] = 'n';
    }
    }
    for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
    {
    if (ans < dp[i][j])
    {
    ans = dp[i][j];
    indexi = i;
    indexj = j;
    }
    }
    cout << ans << endl;
    cout << indexi << ' ' << indexj << endl;
    printComStr(indexi, indexj);
    }
    + +
    2、最长公共子序列

    区分一下,最长公共子序列不同于最长公共子串,序列是保持子序列字符串的下标在str1和str2中的下标顺序是递增的,该字符串在原串中并不一定是连续的。同样的我们可以假设dp[i][j]表示为字符串str1的前i个字符和字符串str2的前j个字符的最长公共子序列的长度。状态转移方程如下:

    +
    1
    2
    3
    4
    dp[0][j] = 0; (0<=j<=m)
    dp[i][0] = 0; (0<=i<=n)
    dp[i][j] = dp[i-1][j-1] +1; (str1[i-1] == str2[j-1])
    dp[i][j] = max{dp[i][j-1],dp[i-1][j]}; (str1[i-1] != str2[j-1])
    + +

    详细代码请看最长公共子序列

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include "stdafx.h"
    #include <iostream>
    #include <string>
    using namespace std;

    #define MAXSIZE 101
    char str1[MAXSIZE];
    char str2[MAXSIZE];
    //'l'表示dp[i][j] = dp[i][j] = dp[i - 1][j];
    //‘q’表示dp[i][j] = dp[i][j] = dp[i - 1][j];
    //'u'表示dp[i][j] = dp[i][j - 1];
    char path[MAXSIZE][MAXSIZE];
    int dp[MAXSIZE][MAXSIZE];

    void printLCS(int i, int j)
    {
    if (i == 0 || j == 0)
    return;
    if (path[i][j] == 'q')
    {
    printLCS(i - 1, j - 1);
    cout << str1[i-1] << ' ';
    }
    else if (path[i][j] == 'u')
    printLCS(i - 1, j);
    else
    printLCS(i, j - 1);

    }

    int main()
    {
    int n, m;
    cin >> str1 >> str2;
    n = strlen(str1);
    m = strlen(str2);
    //初始化
    for (int i = 0; i < n;i++)
    for (int j = 0; j < m; j++)
    dp[i][j] = 0;
    for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
    {
    if (str1[i - 1] == str2[j - 1])
    {
    dp[i][j] = dp[i - 1][j - 1] + 1;
    path[i][j] = 'q';
    }
    else
    {
    if (dp[i - 1][j] >= dp[i][j - 1])
    {
    dp[i][j] = dp[i - 1][j];
    path[i][j] = 'u';
    }
    else
    {
    dp[i][j] = dp[i][j - 1];
    path[i][j] = 'l';
    }

    }
    }
    cout << dp[n][m] << endl;
    printLCS(n, m);
    return 0;
    }
    + +
    3、最长递增子序列(最长递减子序列)

    因为两者的思路都是一样的,所以只给出最长递增子序列的状态转移方程。假设有序列{a1,a2,…,an},我们求其最长递增子序列长度。按照递推求解的思想,我们用F[i]代表若递增子序列以ai结束时它的最长长度。当 i 较小,我们容易直接得出其值,如 F[1] = 1。那么,如何由已经求得的 F[i]值推得后面的值呢?假设,F[1]到F[x-1]的值都已经确定,注意到,以ax 结尾的递增子序列,除了长度为1的情况,其它情况中,ax都是紧跟在一个由 ai(i < x)组成递增子序列之后。要求以ax结尾的最长递增子序列长度,我们依次比较 ax 与其之前所有的 ai(i < x), 若ai小于 ax,则说明ax可以跟在以ai结尾的递增子序列之后,形成一个新的递 增子序列。又因为以ai结尾的递增子序列最长长度已经求得,那么在这种情况下,由以 ai 结尾的最长递增子序列再加上 ax 得到的新的序列,其长度也可以确定,取所有这些长度的最大值,我们即能得到 F[x]的值。特殊的,当没有ai(i < x)小 于ax, 那么以 ax 结尾的递增子序列最长长度为1。 即F[x] = max{1,F[i]+1|ai<ax && i<x}。

    +

    详细代码请看最长递增子序列

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include <iostream>
    using namespace std;
    const int MAXSIZE = 10;
    const int MIN = 0;
    int arr[] = { 1, 4, 3, 2, 6, 5 };
    int F[MAXSIZE];
    int main()
    {
    int maxLen = MIN;
    memset(F, 0, MAXSIZE);
    F[0] = 1;
    for (int i = 1; i < 6; i++)
    {
    for (int j = 0; j < i; j++)
    {
    if (arr[i] > arr[j] && maxLen < F[j])
    {
    maxLen = F[j];
    }
    }
    F[i] = maxLen + 1;
    }

    for (int k = 0; k < 6; k++)
    cout << F[k] << ' ';
    cout << endl;
    }
    + +
    4、最大子序列和的问题

    假设有序列{a1,a2,…,an},求子序列的和最大问题,我们用dp[i]表示以ai结尾的子序列的最大和。

    +
    1
    2
    3
    4
    5
    dp[1] = a1; (a1>=0 && i == 1)

    dp[i] = dp[i-1]+ai; (ai>=0 && i>=2)

    dp[i] = 0; (dp[i-1] + ai <=0 && i>=2)
    + +

    详细代码请看最大子序列的和

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <iostream>
    using namespace std;

    #define MAXSIZE 100

    int a[MAXSIZE];
    int dp[MAXSIZE];
    int max = 0;
    int main()
    {
    int n;
    cin >> n;
    memset(dp, 0, MAXSIZE);
    for (int i = 1; i <= n; i++)
    cin >> a[i];
    for (int i = 1; i <= n; i++)
    {
    if (dp[i-1] + a[i] > 0)
    {
    dp[i] = dp[i - 1] + a[i];
    }
    else
    {
    dp[i] = 0;
    }
    if (max < dp[i])
    max = dp[i];
    }
    cout << max << endl;
    return 0;
    }
    + +
    5、数塔问题(动态搜索)

    给定一个数组data[n][m]构成一个数塔求从最上面走到最低端经过的路径和最大。可以假设dp[i][j]表示走到第i行第j列位置处的最大值,那么可以推出状态转移方程:

    +
    1
    dp[i][j] = max{dp[i-1][j-1],dp[i-1][j]} + data[i][j];
    + +
    1
    2
    3
    4
    5
    for(i=n-1;i>=1;i--){
    for(j=1;j<=i;j++){
    dp[i][j]=max{dp[i-1][j-1],dp[i-1][j]}+s[i][j]
    }
    }
    + +
    6、(01)背包问题

    这是一个经典的动态规划问题,另外在贪心算法里也有背包问题,至于二者的区别在此就不做介绍了。

    +

    假设有N件物品和一个容量为V的背包。第i件物品的体积是v[i],价值是c[i],将哪些物品装入背包可使价值总和最大?

    +

    每一种物品都有两种可能即放入背包或者不放入背包。可以用dp[i][j]表示第i件物品放入容量为j的背包所得的最大价值,则状态转移方程可以推出如下:

    +
    1
    dp[i][j]=max{dp[i-1][j-v[i]]+c[i],dp[i-1][j]};
    + +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    for (int i = 1;i <= N;i++) //枚举物品  
    {
    for (int j = 0;j <= V;j++) //枚举背包容量
    {
    f[i][j] = f[i - 1][j];
    if (j >= v[i])
    {
    f[i][j] = Max(f[i - 1][j],f[i - 1][j - v[i]] + c[i]);
    }
    }
    }
    + +

    说明

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    01背包问题与背包问题的区别在于,01背包,物品的选择只有两种一种是拿,另一种是不拿,而背包问题在于,物品可以只取一部分。所以01背包问题不能用贪心算法解决。

    以dp[i][j]表示用i种物品,重量为j表示所取得的价值。

    对于第i种物品,如果第i种物品重量大于j,就证明第i种物品肯定不能取,这时的dp[i][j]=dp[i-1][j]

    如果第i种物品重量小于j,那就会出现两种情况,采用i的话,物品价值dp[i][j]=采用前面的i-1种物品,所占用的重量为j-i.getweight,所产生的价值+第i 种物品的价值,。如果不采用i,价值为dp[i-1][j]。换成数学表达式就是dp[i][j]=Math.max(dp[i-1][j-weight]+value,dp[i-1][j]);

    比如当i=5,j=10时,dp[5][10]就代表了所取得的最大价值。到这里我们就完成了任务的一半,接下为我们要寻找到底哪些物品放入了背包,从前面的表达式我们可以发现,当dp[i][j]=dp[i-1][j-weight]时,这时为i的物品就会放入背包,所以我们从结果,开始往回走,遇到这种情况,就说明有物品放入背包,然后物品数减1,重量减去为i的重量,继续,最后就能求出哪 些物品放入背包了。
    + +

    JAVA代码

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    public class Test {
    public static void main(String[] args) {
    int allweight=12; //总价值
    int num=8; //物品
    bao[] baos=new bao[num+1];
    baos[1]=new bao(2, 13);
    baos[2]=new bao(1, 10);
    baos[3]=new bao(3, 24);
    baos[4]=new bao(2, 15);
    baos[5]=new bao(4, 28);
    baos[6]=new bao(5, 33);
    baos[7]=new bao(3, 20);
    baos[8]=new bao(1, 8);
    int[][] dp=new int[num+1][allweight+1];
    //构成动态规划表
    for(int i=0;i<=num;i++)
    {
    for(int j=0;j<=allweight;j++)
    {
    if(i==0||j==0)
    {
    dp[i][j]=0;
    }else {
    if (j<baos[i].getWeight()) {
    dp[i][j]=dp[i-1][j];
    }else {
    int value=baos[i].getValue();
    int weight=baos[i].getWeight();
    dp[i][j]=Math.max(dp[i-1][j-weight]+value,dp[i-1][j]);
    }
    }
    System.out.println("dp"+"["+i+"]"+"["+j+"]"+dp[i][j]);
    }
    }
    int m=num;
    int n=allweight;
    int all=dp[m][n];
    //寻找哪些物品放入背包
    while(all>=0)
    {
    if (m>0&&dp[m][n]==dp[m-1][n]) {
    m=m-1;
    }else {
    System.out.println(baos[m]+"加入背包");
    m=m-1;
    if (m==0) {
    return;
    }else {
    n=n-baos[m].getWeight();
    all=all-baos[m].getWeight();
    }
    }
    }
    }
    }
    + +

    可以参照动态规划 - 0-1背包问题的算法优化动态规划-完全背包问题动态规划-多重背包问题01背包问题

    +
    7、矩阵连乘(矩阵链问题)-参考《算法导论》

    例如矩阵链<A1,A2,A3>,它们的维数分别为10100,1005,550,那么如果顺序相乘即((A1A2)A3),共需101005 + 10550 = 7500次乘法,如果按照(A1(A2A3))顺序相乘,却需做100550 + 10100*50 = 75000次乘法。两者之间相差了10倍,所以说矩阵链的相乘顺序也决定了计算量的大小。

    +

    我们用利用动态规划的方式(dp[i][j]表示第i个矩阵至第j个矩阵这段的最优解,还有对于两个矩阵A(i,j)B(j,k)则需要ij*k次乘法),推出状态转移方程:

    +
    1
    2
    3
    dp[i][j] = 0; (i ==j,表示只有一个矩阵,计算次数为0)
    dp[i][j] = min{dp[i][k] + dp[k+1][j] + p[i-1]*p[k]*p[j]}; (i<j && i<=k<j)
    dp[1][n]即为最终求解.
    + +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #define MAXSIZE 100

    int dp[MAXSIZE][MAXSIZE];//存储最小的就算次数
    int s[MAXSIZE][MAXSIZE];//存储断点,用在输出上面

    int i, j, tmp;

    for (int l = 2; l <= n; l++){//j-i的长度,由于长度为1是相同的矩阵那么为0不用计算
    for (i = 1; i <= n - l + 1; i++){//由于j-i =l - 1 , 那么j的最大值为n,所以i上限为 n - l+1;
    j = i + l - 1;//由于j-i = l - 1 , 那么j = l+i-1
    dp[i][j] = dp[i + 1][j] + r[i] * c[i] * c[j];//初始化,就是k = i;
    s[i][j] = i;
    for (k = i + 1; k < j; k++){//循环枚举k i < k < j
    tmp = dp[i][k] + dp[k + 1][j] + r[i] * c[k] * c[j];
    if (dp[i][j] > tmp){
    dp[i][j] = tmp;//更新为最小值
    s[i][j] = k;
    }
    }
    }
    }
    //递归调用输出
    void output(int i, int j){
    if (i == j){
    printf("A%d", i);//当两个相等的时候就不用继续递归就输出A
    return;//返回上一层
    }

    else{
    printf("(");
    output(i, s[i][j]);
    printf(" x ");
    output(s[i][j] + 1, j);
    printf(")");
    }
    }
    +

    总结

    太难了,没事多来看看示例希望早日彻底吃透!

    +

    参考文章:
    参考链接1
    参考链接2

    +
    发布于

    2019-12-14

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode1-4.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode1-4.html" new file mode 100644 index 0000000000..7070cedfcc --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode1-4.html" @@ -0,0 +1,234 @@ + +算法成长之路leetcode1-4 - 辣椒の酱 + +
    算法成长之路leetcode1-4

    算法成长之路leetcode1-4

    1.Two Sum

    desc

    Given an array of integers, return indices of the two numbers such that they add up to a specific target.

    +

    You may assume that each input would have exactly one solution, and you may not use the same element twice.

    + + +

    Example:

    +
    1
    2
    3
    4
    Given nums = [2, 7, 11, 15], target = 9,
    Because nums[0] + nums[1] = 2 + 7 = 9,
    return [0, 1].

    + +

    solution

    s.eg1.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //24 ms	38 MB s.O(n^2) k.O(1)
    class Solution {
    public int[] twoSum(int[] nums, int target) {
    int[] result =new int[2];
    for(int i = 0;i<nums.length-1;i++){
    for(int j = i+1;j<nums.length;j++){
    if(nums[i]+nums[j] == target){
    result[0] = i;
    result[1] = j;
    return new int[]{i,j};
    }
    }
    }
    return new int[0];
    }
    }
    + +

    eg2.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 3 ms	37.2 MB s.O(n) k.O(n)
    class Solution {
    public int[] twoSum(int[] nums, int target) {
    HashMap<Integer,Integer> cache = new HashMap();
    for(int i = 0;i<nums.length;i++){
    if(cache.get(nums[i]) != null){
    return new int[]{cache.get(nums[i]),i};
    }
    cache.put(target-nums[i],i);
    }
    return new int[0];
    }
    }
    + +

    2.Add Two Numbers

    des

    You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

    +

    You may assume the two numbers do not contain any leading zero, except the number 0 itself.

    +

    Example:

    +
    1
    2
    3
    Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
    Output: 7 -> 0 -> 8
    Explanation: 342 + 465 = 807.
    + +

    solution

    eg1.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // 2 ms	44.7 MB
    class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    int carry = 0; // 进位
    ListNode head = new ListNode(0);
    ListNode cur = head; // 一定要用两个链表,不能用一个操作
    while(l1 != null ||l2 != null|| carry != 0){ // lastSum当最后一位刚好进1的时候,需要在循环

    int l1v = l1 == null?0:l1.val;
    int l2v = l2 == null?0:l2.val;
    int temp =l1v+l2v+carry;
    ListNode node;
    if(temp>=10){
    node = new ListNode(temp-10);
    lastSum = 1;
    }else{
    node = new ListNode(temp);
    lastSum = 0;
    }

    if(l1 != null) l1 = l1.next;
    if(l2 != null) l2 = l2.next;

    cur.next = node;
    cur = node;
    }
    return head.next;
    }
    }
    + +

    3.Longest Substring Without Repeating Characters

    desc

    Given a string, find the length of the longest substring without repeating characters.

    +

    Example 1:

    +
    1
    2
    3
    Input: "abcabcbb"
    Output: 3
    Explanation: The answer is "abc", with the length of 3.
    + +

    Example 2:

    +
    1
    2
    3
    Input: "bbbbb"
    Output: 1
    Explanation: The answer is "b", with the length of 1.
    + +

    Example 3:

    +
    1
    2
    3
    4
    Input: "pwwkew"
    Output: 3
    Explanation: The answer is "wke", with the length of 3.
    Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
    + +

    solution

    eg1.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    //2 ms 24.05% 36.9 MB 95.35%
    class Solution {
    public int lengthOfLongestSubstring(String s) {
    Set<Character> strSet = new HashSet();
    int maxLen = 0;
    if(s != null && s.length() >0){
    char ss[] = s.toCharArray(); //利用toCharArray方法转换
    for (int i = 0; i < ss.length-1; i++) {
    strSet.add(ss[i]);
    for(int j = i+1; j<ss.length; j++){
    int oL = strSet.size();
    strSet.add(ss[j]);
    int cL = strSet.size();
    if(oL != cL){ // 不相等时记下个数
    if(cL > maxLen){
    maxLen = cL;
    }
    }else{ // 相等时 跳出此次循环 清空set
    strSet.clear();
    break;
    }
    }
    }
    if(maxLen == 0){ // 全相等时
    maxLen = 1;
    }
    }
    return maxLen;
    }
    }
    + + + +

    eg2.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 2 ms	37.3 MB
    class Solution {
    public int lengthOfLongestSubstring(String s) {
    int maxLength = 0;
    char[] chars = s.toCharArray();
    int leftIndex = 0;//记录最左边相等时的值,然后向右滑动窗口
    for (int j = 0; j < chars.length; j++) {
    for (int innerIndex = leftIndex; innerIndex < j; innerIndex++) {
    if (chars[innerIndex] == chars[j]) {
    maxLength = Math.max(maxLength, j - leftIndex);
    leftIndex = innerIndex + 1;
    break;
    }
    }
    }
    return Math.max(chars.length - leftIndex, maxLength);
    }
    }
    + + + + + +

    4.Median of Two Sorted Arrays

    desc

    There are two sorted arrays nums1 and nums2 of size m and n respectively.

    +

    Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

    +

    You may assume nums1 and nums2 cannot be both empty.

    +

    Example 1:

    +
    1
    2
    3
    nums1 = [1, 3]
    nums2 = [2]
    The median is 2.0
    + +

    Example 2:

    +
    1
    2
    3
    nums1 = [1, 2]
    nums2 = [3, 4]
    The median is (2 + 3)/2 = 2.5
    + +

    solution

    eg1.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // 20 ms  10.07%
    // 2.2 MB 99.84%
    class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int maxL = 0;
    if (nums1.length >= nums2.length) {
    maxL = nums1.length;
    } else {
    maxL = nums2.length;
    }
    List<Integer> newList = new ArrayList(maxL);
    for (int i = 0; i < maxL; i++) {
    if (i < nums1.length) {
    newList.add(nums1[i]);
    }
    if (i < nums2.length) {
    newList.add(nums2[i]);
    }
    }

    int size = newList.size();
    int index = size / 2;
    newList.sort(Comparator.comparing(Integer::valueOf));
    if (size % 2 == 0) {
    return (newList.get(index) + newList.get(index - 1)) / 2d;
    } else {
    return newList.get(index);
    }
    }
    }
    + + + +

    eg2.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int n = nums1.length + nums2.length;
    double res = 0.0;
    if (n <= 0) {
    return res;
    }
    if ((n & 1) == 0) {
    res = (findKth(nums1, nums2, 0, 0, n / 2) + findKth(nums1, nums2, 0, 0, n / 2 + 1)) / 2.0;
    }
    else {
    res = findKth(nums1, nums2, 0, 0, n / 2 + 1);
    }
    return res;
    }
    private int findKth(int[] nums1, int[] nums2, int start1, int start2, int k) {
    if (start1 >= nums1.length) {
    return nums2[start2 + k - 1];
    }
    if (start2 >= nums2.length) {
    return nums1[start1 + k - 1];
    }
    if (k == 1) {
    return Math.min(nums1[start1], nums2[start2]);
    }
    int left = start1 + k / 2 - 1 >= nums1.length ? Integer.MAX_VALUE : nums1[start1 + k / 2 - 1];
    int right = start2 + k / 2 - 1 >= nums2.length ? Integer.MAX_VALUE : nums2[start2 + k / 2 - 1];
    if (left < right) {
    return findKth(nums1, nums2, start1 + k / 2, start2, k - k / 2);
    }
    return findKth(nums1, nums2, start1, start2 + k / 2, k - k / 2);
    }
    }
    + +

    eg3.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    // 二分查找、分治算法
    class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
    //m:A数组的长度
    int m = A.length;
    //n:B数组的长度

    int n = B.length;
    //如果A的长度大于B
    if (m > n) { // to ensure m<=n
    //交换AB数组,确保m<=n
    int[] temp = A; A = B; B = temp;
    int tmp = m; m = n; n = tmp;
    }
    //设置两个指针,iMin为头指针,IMAX为尾指针,halfLen为中位数指针
    int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
    //如果头指针走向不大于尾指针,进行循环
    while (iMin <= iMax) {
    //i为中位数
    int i = (iMin + iMax) / 2;
    //j为
    int j = halfLen - i;
    if (i < iMax && B[j - 1] > A[i]){
    iMin = i + 1; // i is too small
    }
    else if (i > iMin && A[i - 1] > B[j]) {
    iMax = i - 1; // i is too big
    }
    else { // i is perfect
    int maxLeft = 0;
    if (i == 0) { maxLeft = B[j-1]; }
    else if (j == 0) { maxLeft = A[i - 1]; }
    else { maxLeft = Math.max(A[i - 1], B[j - 1]); }
    if ( (m + n) % 2 == 1 ) { return maxLeft; }

    int minRight = 0;
    if (i == m) { minRight = B[j]; }
    else if (j == n) { minRight = A[i]; }
    else { minRight = Math.min(B[j], A[i]); }

    return (maxLeft + minRight) / 2.0;
    }
    }
    return 0d;
    }
    }
    + + +
    发布于

    2019-11-05

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode11-12.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode11-12.html" new file mode 100644 index 0000000000..3cd4621dd5 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode11-12.html" @@ -0,0 +1,195 @@ + +算法成长之路leetcode11-12 - 辣椒の酱 + +
    算法成长之路leetcode11-12

    算法成长之路leetcode11-12

    11. Container With Most Water

    Given n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

    + +

    Note: You may not slant the container and n is at least 2.

    +

    +

    The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.

    +

    Example

    1
    2
    3
    4
    Example:

    Input: [1,8,6,2,5,4,8,3,7]
    Output: 49
    + +

    JAVA题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    package algorithm;

    /**
    * 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。
    * 在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。
    * 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
    *
    * 说明:你不能倾斜容器,且 n 的值至少为 2。
    *
    *
    *
    * 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
    *
    *
    *
    * 示例:
    *
    * 输入: [1,8,6,2,5,4,8,3,7]
    * 输出: 49
    *
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/container-with-most-water
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode11 {

    // 暴力解法
    public static int maxArea(int[] height) {
    int max = 0;
    for (int i = 0; i < height.length - 1; i++) {
    for (int j = i + 1; j < height.length; j++) {
    max = Math.max(max, Math.min(height[i], height[j]) * (j-i));
    }
    }
    return max;
    }


    // 官方 双指针法

    /**
    * 算法
    *
    * 这种方法背后的思路在于,两线段之间形成的区域总是会受到其中较短那条长度的限制。此外,两线段距离越远,得到的面积就越大。
    *
    * 我们在由线段长度构成的数组中使用两个指针,一个放在开始,一个置于末尾。
    * 此外,我们会使用变量 maxareamaxarea 来持续存储到目前为止所获得的最大面积。
    * 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxareamaxarea,并将指向较短线段的指针向较长线段那端移动一步。
    *
    * 作者:LeetCode
    * 链接:https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    *
    * 算法流程: 设置双指针 ii,jj 分别位于容器壁两端,根据规则移动指针(后续说明),并且更新面积最大值 res,直到 i == j 时返回 res。
    *
    * 指针移动规则与证明: 每次选定围成水槽两板高度 h[i]h[i],h[j]h[j] 中的短板,向中间收窄 11 格。以下证明:
    *
    * 设每一状态下水槽面积为 S(i, j)S(i,j),(0 <= i < j < n)(0<=i<j<n),由于水槽的实际高度由两板中的短板决定,
    * 则可得面积公式 S(i, j) = min(h[i], h[j]) × (j - i)S(i,j)=min(h[i],h[j])×(j−i)。
    * 在每一个状态下,无论长板或短板收窄 11 格,都会导致水槽 底边宽度 -1−1:
    * 若向内移动短板,水槽的短板 min(h[i], h[j])min(h[i],h[j]) 可能变大,因此水槽面积 S(i, j)S(i,j) 可能增大。
    * 若向内移动长板,水槽的短板 min(h[i], h[j])min(h[i],h[j]) 不变或变小,下个水槽的面积一定小于当前水槽面积。
    * 因此,向内收窄短板可以获取面积最大值。换个角度理解:
    * 若不指定移动规则,所有移动出现的 S(i, j)S(i,j) 的状态数为 C(n, 2)C(n,2),即暴力枚举出所有状态。
    * 在状态 S(i, j)S(i,j) 下向内移动短板至 S(i + 1, j)S(i+1,j)(假设 h[i] < h[j]h[i]<h[j] ),
    * 则相当于消去了 {S(i, j - 1), S(i, j - 2), ... , S(i, i + 1)}S(i,j−1),S(i,j−2),...,S(i,i+1) 状态集合。
    * 而所有消去状态的面积一定 <= S(i, j)<=S(i,j):
    * 短板高度:相比 S(i, j)S(i,j) 相同或更短(<= h[i]<=h[i]);
    * 底边宽度:相比 S(i, j)S(i,j) 更短。
    * 因此所有消去的状态的面积都 < S(i, j)<S(i,j)。通俗的讲,我们每次向内移动短板,所有的消去状态都不会导致丢失面积最大值 。
    *
    *
    * 作者:jyd
    * 链接:https://leetcode-cn.com/problems/container-with-most-water/solution/container-with-most-water-shuang-zhi-zhen-fa-yi-do/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    * @param height
    * @return
    */
    public static int maxArea1(int[] height) {

    int maxarea = 0, l = 0, r = height.length - 1;

    while (l < r) {
    // 计算面积,取最大值
    maxarea = Math.max(maxarea, Math.min(height[l], height[r]) * (r - l));
    // 小的向大的一方移动,如果左边小于右边,左边向右边移动一位,即左++,l++,否则右移
    if (height[l] < height[r])
    l++;
    else
    r--;
    }
    return maxarea;
    }

    public static int maxArea2(int[] height) {
    int i = 0, j = height.length - 1, res = 0;
    while(i < j){
    res = height[i] < height[j] ?
    Math.max(res, (j - i) * height[i++]):
    Math.max(res, (j - i) * height[j--]);
    }
    return res;
    }

    // best one
    public static int maxArea3(int[] height) {
    int lastIndex = height.length - 1, max = 0, temp = 0;
    for (int i = 0; i < lastIndex;) {
    // 取左右边上的最小的数
    temp = Math.min(height[i], height[lastIndex]);
    // 计算 距离最大面积
    if (temp * (lastIndex - i) > max) {
    max = temp * (lastIndex - i);
    System.out.println("" + i + "," + lastIndex);
    }


    // 最小值在右边的话 右边往左边移动
    while (temp >= height[lastIndex] && i < lastIndex)
    lastIndex--;
    // 最小值在左边的话 左边往右移动 直到重合
    while (temp >= height[i] && i < lastIndex)
    i++;
    }
    return max;
    }

    public static void main(String[] args) {
    System.out.println(maxArea3(new int[]{10, 8, 6, 2, 5, 4, 8, 3, 7}));
    }

    }
    + +

    12. Integer to Roman

    Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

    +

    Symbol Value
    I 1
    V 5
    X 10
    L 50
    C 100
    D 500
    M 1000
    For example, two is written as II in Roman numeral, just two one’s added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.

    +

    Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

    +

    I can be placed before V (5) and X (10) to make 4 and 9.
    X can be placed before L (50) and C (100) to make 40 and 90.
    C can be placed before D (500) and M (1000) to make 400 and 900.
    Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.

    +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    Example 1:

    Input: 3
    Output: "III"
    Example 2:

    Input: 4
    Output: "IV"
    Example 3:

    Input: 9
    Output: "IX"
    Example 4:

    Input: 58
    Output: "LVIII"
    Explanation: L = 50, V = 5, III = 3.
    Example 5:

    Input: 1994
    Output: "MCMXCIV"
    Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

    + +

    JAVA题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    package algorithm;

    /**
    * 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
    *
    * 字符 数值
    * I 1
    * V 5
    * X 10
    * L 50
    * C 100
    * D 500
    * M 1000
    * 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,
    * 即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。
    *
    * 通常情况下,罗马数字中小的数字在大的数字的右边。
    * 但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,
    * 所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,
    * 数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
    *
    * I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
    * X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
    * C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
    * 给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
    *
    * 示例 1:
    *
    * 输入: 3
    * 输出: "III"
    * 示例 2:
    *
    * 输入: 4
    * 输出: "IV"
    * 示例 3:
    *
    * 输入: 9
    * 输出: "IX"
    * 示例 4:
    *
    * 输入: 58
    * 输出: "LVIII"
    * 解释: L = 50, V = 5, III = 3.
    * 示例 5:
    *
    * 输入: 1994
    * 输出: "MCMXCIV"
    * 解释: M = 1000, CM = 900, XC = 90, IV = 4.
    *
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/integer-to-roman
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode12 {

    /**
    * 执行用时 :6 ms, 在所有 java 提交中击败了的用户
    * 内存消耗 :36.1 MB, 在所有 java 提交中击败了100.00%的用户
    * @param num
    * @return
    */
    public static String intToRoman(int num) {
    // 个位数
    String[] map = new String[]{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
    // 十位数
    String[] map1 = new String[]{"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
    // 百位
    String[] map2 = new String[]{"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
    // 千位
    String[] map3 = new String[]{"", "M", "MM", "MMM"};
    StringBuilder sb = new StringBuilder();
    String[] res = new String[4];
    int i = 10;
    int j = 0;
    while (num > 0) {
    int temp = num % i;
    if (i > 10) {
    temp = temp / (i / 10);
    }
    switch (j) {
    case 0:
    res[j++] = map[temp];
    break;
    case 1:
    res[j++] = map1[temp];
    break;
    case 2:
    res[j++] = map2[temp];
    break;
    case 3:
    res[j++] = map3[temp];
    break;
    }
    i = 10*i;
    if (j > 3) {
    break;
    }
    }
    for (int k = res.length - 1; k >= 0; k--) {
    sb.append(res[k]);
    }
    return sb.toString();
    }


    /**
    * 贪心算法
    *
    * 解题思路
    * 参考大佬们的思路 吃透之后 写出来
    * 贪心算法 我永远用最接近的去做比较
    *
    * 如果我去小卖部买55元的东西
    *
    * 你可以选择一张面值50的 和一张5块的
    * 也可以给一张100的让老板找零
    * 贪心算法就是前者
    *
    * 假定我买3块的东西 我先用5块去比较 太多了 老板问 你还有小点的纸币没 我找不开
    * 这时候 你给个两块 还差一块 又给了一块
    * 看着很蠢 但是这确实有效
    *
    * 作者:guo-tang-feng
    * 链接:https://leetcode-cn.com/problems/integer-to-roman/solution/tan-xin-suan-fa-by-guo-tang-feng/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    *
    * @param num
    * @return
    */
    public static String intToRoman1(int num) {
    StringBuilder stringBuilder = new StringBuilder();
    int[] moneys = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    String[] moneyToStr = new String[]{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
    int index = 0;
    while (num > 0) {
    // 如果大于最大的数
    if (num >= moneys[index]) {
    // 加进去
    stringBuilder.append(moneyToStr[index]);
    // 把加进去的减掉
    num -= moneys[index];
    // 索引前移,num -= moneys[index] 还可能满足 num >= moneys[index]
    // ,此时如果只index++,那么就漏掉一部分了,所以要index--,如2000减掉1000还有1000 还是应该和moneys[0]比较
    index--;
    }
    // 索引后移
    index++;
    }
    return stringBuilder.toString();
    }

    public static void main(String[] args) {
    // 第一次超过100%用户的内存,有点小小激动 😂
    System.out.println(intToRoman(400));
    System.out.println(intToRoman1(1994));
    }

    }
    + +
    发布于

    2019-12-17

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode13-14.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode13-14.html" new file mode 100644 index 0000000000..31369f3641 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode13-14.html" @@ -0,0 +1,251 @@ + +算法成长之路leetcode13-14 - 辣椒の酱 + +
    算法成长之路leetcode13-14

    算法成长之路leetcode13-14

    13. Roman to Integer

    Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SymbolValue
    I1
    V5
    X10
    L50
    C100
    D500
    M1000
    +

    For example, two is written as II in Roman numeral, just two one’s added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.

    +

    Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

    +

    I can be placed before V (5) and X (10) to make 4 and 9.
    X can be placed before L (50) and C (100) to make 40 and 90.
    C can be placed before D (500) and M (1000) to make 400 and 900.
    Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.

    +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    Example 1:

    Input: "III"
    Output: 3
    Example 2:

    Input: "IV"
    Output: 4
    Example 3:

    Input: "IX"
    Output: 9
    Example 4:

    Input: "LVIII"
    Output: 58
    Explanation: L = 50, V= 5, III = 3.
    Example 5:

    Input: "MCMXCIV"
    Output: 1994
    Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

    + +

    JAVA题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    package algorithm;

    import java.util.HashMap;
    import java.util.Map;

    /**
    * 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
    *
    * 字符 数值
    * I 1
    * V 5
    * X 10
    * L 50
    * C 100
    * D 500
    * M 1000
    * 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。
    *
    * 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,
    * 例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,
    * 所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。
    * 这个特殊的规则只适用于以下六种情况:
    *
    * I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
    * X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
    * C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
    * 给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
    *
    * 示例 1:
    *
    * 输入: "III"
    * 输出: 3
    * 示例 2:
    *
    * 输入: "IV"
    * 输出: 4
    * 示例 3:
    *
    * 输入: "IX"
    * 输出: 9
    * 示例 4:
    *
    * 输入: "LVIII"
    * 输出: 58
    * 解释: L = 50, V= 5, III = 3.
    * 示例 5:
    *
    * 输入: "MCMXCIV"
    * 输出: 1994
    * 解释: M = 1000, CM = 900, XC = 90, IV = 4.
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/roman-to-integer
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode13 {

    public static int romanToInt(String s) {
    int[] moneys = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    String[] moneyToStr = new String[]{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
    char[] chars = s.toCharArray();
    int result = 0;
    int tempJ = 0;
    for (int i = 0; i < chars.length; ) {
    for (int j = tempJ; j < moneyToStr.length; ) {
    // 从左往右开始一个字符一个字符匹配,匹配到一个字符后开始下一个
    if (new String(new char[]{chars[i]}).equals(moneyToStr[j])) {
    result += moneys[j];
    i++;
    // 此时下一次可能还会出现一样的字符如VV=20
    tempJ = j;
    break;
    // 匹配到两个字符是开始下两个字符
    } else if (i + 1 < chars.length && new String(new char[]{chars[i], chars[i + 1]}).equals(moneyToStr[j])) {
    result += moneys[j];
    i += 2;
    // 下次出现的一定是一个字符的,如IV下次不会再出现IV 只能出现I
    tempJ = j + 1;
    break;
    } else {
    j++;
    }
    }
    }
    return result;
    }

    public static int romanToInt1(String s) {
    Map<String, Integer> map = new HashMap<>();
    map.put("I", 1);
    map.put("IV", 4);
    map.put("V", 5);
    map.put("IX", 9);
    map.put("X", 10);
    map.put("XL", 40);
    map.put("L", 50);
    map.put("XC", 90);
    map.put("C", 100);
    map.put("CD", 400);
    map.put("D", 500);
    map.put("CM", 900);
    map.put("M", 1000);

    int ans = 0;
    // 所有的字符,要么匹配两个要么匹配一个,没有其余的情况
    for(int i = 0;i < s.length();) {
    // 两个匹配的
    if(i + 1 < s.length() && map.containsKey(s.substring(i, i+2))) {
    ans += map.get(s.substring(i, i+2));
    // 匹配上后往后移两个
    i += 2;
    } else {
    // 一个匹配上的
    ans += map.get(s.substring(i, i+1));
    // 匹配后往后移一个
    i ++;
    }
    }
    return ans;
    }

    public static void main(String[] args) {
    System.out.println(romanToInt("XIX"));
    }
    }

    + +

    14. Longest Common Prefix

    Write a function to find the longest common prefix string amongst an array of strings.

    +

    If there is no common prefix, return an empty string “”.

    +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Example 1:

    Input: ["flower","flow","flight"]
    Output: "fl"
    Example 2:

    Input: ["dog","racecar","car"]
    Output: ""
    Explanation: There is no common prefix among the input strings.

    Note:
    All given inputs are in lowercase letters a-z.

    + +

    JAVA题解

    水平扫描


    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    package algorithm;
    /**
    * 编写一个函数来查找字符串数组中的最长公共前缀。
    *
    * 如果不存在公共前缀,返回空字符串 ""。
    *
    * 示例 1:
    *
    * 输入: ["flower","flow","flight"]
    * 输出: "fl"
    * 示例 2:
    *
    * 输入: ["dog","racecar","car"]
    * 输出: ""
    * 解释: 输入不存在公共前缀。
    * 说明:
    *
    * 所有输入只包含小写字母 a-z 。
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/longest-common-prefix
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode14 {

    public static String longestCommonPrefix(String[] strs) {

    if (strs.length == 0) {
    return "";
    }

    if (strs.length == 1) {
    return strs[0];
    }

    int i = 0;
    String pre = "";
    for (; i < strs[0].length(); i++) {
    pre = strs[0].substring(0, i + 1);
    int j = 1;
    boolean end = false;
    for (; j < strs.length; j++) {
    if (!strs[j].startsWith(pre)) {
    break;
    }
    if (pre.length() == strs[j].length()) {
    end = true;
    }
    }

    if (j == strs.length && !end) {
    continue;
    } else if (j != strs.length) {

    if (pre.length() > 1) {
    return pre.substring(0, pre.length() - 1);
    } else {
    return "";
    }

    } else {
    return pre;
    }

    }

    return pre;
    }

    // 水平扫描法
    public static String longestCommonPrefix1(String[] strs) {
    if (strs.length == 0) return "";
    String prefix = strs[0];
    // 1,2->s1,3->s2,4;前两个中找到前缀公共最长的s1,然后和第3个一起找出s2,以此类推
    for (int i = 1; i < strs.length; i++)
    // 不相等时为-1
    while (strs[i].indexOf(prefix) != 0) {
    // 从后往前缩短,直到找到最长的
    prefix = prefix.substring(0, prefix.length() - 1);
    // 找完都没找到的话返回空
    if (prefix.isEmpty()) return "";
    }
    return prefix;
    }


    public static void main(String[] args) {
    System.out.println(longestCommonPrefix1(new String[]{"flower","fl","flight"}));
    }

    // 水平扫描,单个字符逐一进行比较
    public static String longestCommonPrefix2(String[] strs) {
    if (strs == null || strs.length == 0) return "";

    for (int i = 0; i < strs[0].length() ; i++){
    char c = strs[0].charAt(i);
    for (int j = 1; j < strs.length; j ++) {
    // 如果i == strs[j].length() 代表找出最短的,直接返回,或者不相等时直接返回
    if (i == strs[j].length() || strs[j].charAt(i) != c)
    return strs[0].substring(0, i);
    }
    }
    // 到此处已经找完
    return strs[0];
    }
    }
    + +
    分治算法

    +

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public String longestCommonPrefix(String[] strs) {
    if (strs == null || strs.length == 0) return "";
    return longestCommonPrefix(strs, 0 , strs.length - 1);
    }

    private String longestCommonPrefix(String[] strs, int l, int r) {
    // 只有一个字符串的时候,返回此字符串
    if (l == r) {
    return strs[l];
    }
    else {
    int mid = (l + r)/2;
    // 找出左边最长前缀
    String lcpLeft = longestCommonPrefix(strs, l , mid);
    // 找出右边最长前缀
    String lcpRight = longestCommonPrefix(strs, mid + 1,r);
    // 左边右边中找出最长前缀
    return commonPrefix(lcpLeft, lcpRight);
    }
    }

    String commonPrefix(String left,String right) {
    int min = Math.min(left.length(), right.length());
    for (int i = 0; i < min; i++) {
    // 循环最小的一边字符逐一比较,不相等时跳出
    if ( left.charAt(i) != right.charAt(i) )
    return left.substring(0, i);
    }
    return left.substring(0, min);
    }
    + +
    二分查找法

    +

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public String longestCommonPrefix(String[] strs) {
    if (strs == null || strs.length == 0)
    return "";
    int minLen = Integer.MAX_VALUE;
    for (String str : strs)
    minLen = Math.min(minLen, str.length());
    int low = 1;
    int high = minLen;
    while (low <= high) {
    int middle = (low + high) / 2;
    if (isCommonPrefix(strs, middle))
    low = middle + 1;
    else
    high = middle - 1;
    }
    return strs[0].substring(0, (low + high) / 2);
    }

    private boolean isCommonPrefix(String[] strs, int len){
    String str1 = strs[0].substring(0,len);
    for (int i = 1; i < strs.length; i++)
    if (!strs[i].startsWith(str1))
    return false;
    return true;
    }

    + +
    字典树

    给定一些键值字符串 S = [S 1 ,S 2 …S n ],我们要找到字符串 q 与 S 的最长公共前缀。 这样的查询操作可能会非常频繁。

    +

    我们可以通过将所有的键值 S 存储到一颗字典树中来优化最长公共前缀查询操作。 如果你想学习更多关于字典树的内容,可以从 208. 实现 Trie (前缀树)开始。在字典树中,从根向下的每一个节点都代表一些键值的公共前缀。 但是我们需要找到字符串q 和所有键值字符串的最长公共前缀。 这意味着我们需要从根找到一条最深的路径,满足以下条件:

    +

    这是所查询的字符串 q 的一个前缀

    +

    路径上的每一个节点都有且仅有一个孩子。 否则,找到的路径就不是所有字符串的公共前缀

    +

    路径不包含被标记成某一个键值字符串结尾的节点。 因为最长公共前缀不可能比某个字符串本身长

    +

    算法

    +

    最后的问题就是如何找到字典树中满足上述所有要求的最深节点。 最有效的方法就是建立一颗包含字符串[S 1 …S n ] 的字典树。 然后在这颗树中匹配 q 的前缀。 我们从根节点遍历这颗字典树,直到因为不能满足某个条件而不能再遍历为止。

    +

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    public String longestCommonPrefix(String q, String[] strs) {
    if (strs == null || strs.length == 0)
    return "";
    if (strs.length == 1)
    return strs[0];
    Trie trie = new Trie();
    for (int i = 1; i < strs.length ; i++) {
    trie.insert(strs[i]);
    }
    return trie.searchLongestPrefix(q);
    }

    class TrieNode {

    // 子节点的链接数组
    private TrieNode[] links;

    private final int R = 26;

    private boolean isEnd;

    // 非空子节点的数量
    private int size;
    public void put(char ch, TrieNode node) {
    links[ch -'a'] = node;
    size++;
    }

    public int getLinks() {
    return size;
    }
    // 假设方法 containsKey、isEnd、get、put 都已经实现了
    // 可以参考文章:https://leetcode.com/articles/implement-trie-prefix-tree/
    }

    public class Trie {

    private TrieNode root;

    public Trie() {
    root = new TrieNode();
    }

    // 假设方法 insert、search、searchPrefix 都已经实现了
    // 可以参考文章:https://leetcode.com/articles/implement-trie-prefix-tree/
    private String searchLongestPrefix(String word) {
    TrieNode node = root;
    StringBuilder prefix = new StringBuilder();
    for (int i = 0; i < word.length(); i++) {
    char curLetter = word.charAt(i);
    if (node.containsKey(curLetter) && (node.getLinks() == 1) && (!node.isEnd())) {
    prefix.append(curLetter);
    node = node.get(curLetter);
    }
    else
    return prefix.toString();

    }
    return prefix.toString();
    }
    }
    + + + +
    发布于

    2019-12-24

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode15-16.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode15-16.html" new file mode 100644 index 0000000000..8b746aa3e1 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode15-16.html" @@ -0,0 +1,191 @@ + +算法成长之路leetcode15-16 - 辣椒の酱 + +
    算法成长之路leetcode15-16

    算法成长之路leetcode15-16

    15. 3Sum

    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

    + +

    Note:

    +

    The solution set must not contain duplicate triplets.

    +
    Example
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Example:
    Given array nums = [-1, 0, 1, 2, -1, -4],

    A solution set is:
    [
    [-1, 0, 1],
    [-1, -1, 2]
    ]

    + +
    JAVA题解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    package algorithm;

    import java.util.*;

    /**
    * 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,
    * 使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
    *
    * 注意:答案中不可以包含重复的三元组。
    *
    * 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
    *
    * 满足要求的三元组集合为:
    * [
    * [-1, 0, 1],
    * [-1, -1, 2]
    * ]
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/3sum
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode15 {
    // ❌错解
    public static List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> res = new ArrayList<>();
    Set<String> ids = new HashSet<>();
    for (int i = 0; i < nums.length - 2; i++) {
    for (int j = i+1; j < nums.length-1; j++) {
    for (int k = j+1; k < nums.length; k++) {
    if(nums[i]+nums[j]+nums[k] == 0){
    String i2 = nums[i] + ""+nums[j]+nums[k];
    System.out.println(nums[i]+","+nums[j]+","+nums[k]+"="+i2);
    if(!ids.contains(i2)){
    ids.add(i2);
    res.add(Arrays.asList(nums[i],nums[j],nums[k]));
    }
    }
    }
    }
    }
    return res;
    }

    /**
    * 思路
    * 标签:数组遍历
    * 首先对数组进行排序,排序后固定一个数 nums[i]nums[i],再使用左右指针指向 nums[i]nums[i]后面的两端,数字分别为 nums[L]nums[L] 和 nums[R]nums[R],计算三个数的和 sumsum 判断是否满足为 00,满足则添加进结果集
    * 如果 nums[i]nums[i]大于 00,则三数之和必然无法等于 00,结束循环
    * 如果 nums[i]nums[i] == nums[i-1]nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过
    * 当 sumsum == 00 时,nums[L]nums[L] == nums[L+1]nums[L+1] 则会导致结果重复,应该跳过,L++L++
    * 当 sumsum == 00 时,nums[R]nums[R] == nums[R-1]nums[R−1] 则会导致结果重复,应该跳过,R--R−−
    * 时间复杂度:O(n^2),n 为数组长度
    *
    * 作者:guanpengchn
    * 链接:https://leetcode-cn.com/problems/3sum/solution/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    * @param nums
    * @return
    */
    public static List<List<Integer>> threeSum1(int[] nums) {
    List<List<Integer>> ans = new ArrayList();
    int len = nums.length;
    if (nums == null || len < 3) return ans;
    Arrays.sort(nums); // 排序
    for (int i = 0; i < len; i++) {
    if (nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
    if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
    int L = i + 1;
    int R = len - 1;
    while (L < R) {
    int sum = nums[i] + nums[L] + nums[R];
    if (sum == 0) {
    ans.add(Arrays.asList(nums[i], nums[L], nums[R]));
    // 此时nums[L] == nums[L + 1] 会重复,继续跳过一个
    while (L < R && nums[L] == nums[L + 1]) L++; // 去重
    while (L < R && nums[R] == nums[R - 1]) R--; // 去重
    L++;
    R--;
    } else if (sum < 0) L++;
    else if (sum > 0) R--;
    }
    }
    return ans;
    }


    public static void main(String[] args) {
    System.out.println(threeSum(new int[]{-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6}));
    }
    }

    + +

    16. 3Sum Closest

    Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    +
    Example
    1
    2
    3
    4
    5
    6
    Example:

    Given array nums = [-1, 2, 1, -4], and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

    + +
    JAVA题解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    package algorithm;

    import java.util.Arrays;

    /**
    * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,
    * 使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
    *
    * 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
    *
    * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/3sum-closest
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode16 {
    // 想到的思路,找出所有的组合以及它们的sum,然后排好序二分法查找sum中最接近的
    public int threeSumClosest(int[] nums, int target) {

    return 0;
    }

    /**
    * 思路
    * 标签:排序和双指针
    * 本题目因为要计算三个数,如果靠暴力枚举的话时间复杂度会到 O(n^3),需要降低时间复杂度
    * 首先进行数组排序,时间复杂度 O(nlogn)O(nlogn)
    * 在数组 nums 中,进行遍历,每遍历一个值利用其下标i,形成一个固定值 nums[i]
    * 再使用前指针指向 start = i + 1 处,后指针指向 end = nums.length - 1 处,也就是结尾处
    * 根据 sum = nums[i] + nums[start] + nums[end] 的结果,判断 sum 与目标 target 的距离,如果更近则更新结果 ans
    * 同时判断 sum 与 target 的大小关系,因为数组有序,如果 sum > target 则 end--,如果 sum < target 则 start++,如果 sum == target 则说明距离为 0 直接返回结果
    * 整个遍历过程,固定值为 n 次,双指针为 n 次,时间复杂度为 O(n^2)
    * 总时间复杂度:O(nlogn) + O(n^2) = O(n^2)
    *
    * 作者:guanpengchn
    * 链接:https://leetcode-cn.com/problems/3sum-closest/solution/hua-jie-suan-fa-16-zui-jie-jin-de-san-shu-zhi-he-b/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    * @param nums
    * @param target
    * @return
    */
    public int threeSumClosest1(int[] nums, int target) {

    Arrays.sort(nums);
    int ans = nums[0] + nums[1] + nums[2];
    for(int i=0;i<nums.length;i++) {
    int start = i+1, end = nums.length - 1;
    while(start < end) {
    int sum = nums[start] + nums[end] + nums[i];
    // 结果差值更小时,取更小的
    if(Math.abs(target - sum) < Math.abs(target - ans))
    ans = sum;
    // 结果大于目标,右边的左移
    if(sum > target)
    end--;
    else if(sum < target)
    start++;
    else
    // 相等时直接返回结果
    return ans;
    }
    }
    return ans;
    }
    }
    + +
    发布于

    2020-01-01

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode17-18.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode17-18.html" new file mode 100644 index 0000000000..1d3fdd4c34 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode17-18.html" @@ -0,0 +1,193 @@ + +算法成长之路leetcode17-18 - 辣椒の酱 + +
    算法成长之路leetcode17-18

    算法成长之路leetcode17-18

    17. Letter Combinations of a Phone Number

    Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.

    + + +

    A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

    +
    Example
    1
    2
    3
    4
    5
    6
    7
    8
    Example:

    Input: "23"
    Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
    Note:

    Although the above answer is in lexicographical order, your answer could be in any order you want.

    + +
    JAVA题解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    package algorithm;

    import java.util.*;

    /**
    * 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
    *
    * 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
    *
    示例:
    输入:"23"
    输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
    */
    public class Leetcode17 {

    public static List<String> letterCombinations(String digits) {

    List<String> res = new ArrayList<>();
    String[] indexToStr = new String[]{"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    if (digits == null || "".equals(digits))
    return res;
    else if(digits.length() == 1) {
    char[] chars = indexToStr[Integer.parseInt(digits)].toCharArray();
    for (int i = 0; i < chars.length; i++) {
    res.add(new String(new char[]{chars[i]}));
    }
    }

    char[] charArray = digits.toCharArray();
    char[] i0Char = indexToStr[(int) charArray[0] - (int) ('0')].toCharArray();

    for (int i = 1; i < charArray.length; i++) {

    for (int i1 = 0; i1 < i0Char.length; i1++) {
    char[] chars1 = indexToStr[(int) charArray[i] - (int) ('0')].toCharArray();
    for (int i2 = 0; i2 < chars1.length; i2++) {
    res.add(new String(new char[]{i0Char[i1], chars1[i2]}));
    }
    }

    }
    return res;
    }

    Map<String, String> phone = new HashMap<String, String>() {{
    put("2", "abc");
    put("3", "def");
    put("4", "ghi");
    put("5", "jkl");
    put("6", "mno");
    put("7", "pqrs");
    put("8", "tuv");
    put("9", "wxyz");
    }};

    List<String> output = new ArrayList<String>();

    public void backtrack(String combination, String next_digits) {
    // if there is no more digits to check
    if (next_digits.length() == 0) {
    // the combination is done
    output.add(combination);
    }
    // if there are still digits to check
    else {
    // iterate over all letters which map
    // the next available digit
    String digit = next_digits.substring(0, 1);
    String letters = phone.get(digit);
    for (int i = 0; i < letters.length(); i++) {
    String letter = phone.get(digit).substring(i, i + 1);
    // append the current letter to the combination
    // and proceed to the next digits
    backtrack(combination + letter, next_digits.substring(1));
    }
    }
    }

    /**
    * 方法:回溯
    * 回溯是一种通过穷举所有可能情况来找到所有解的算法。如果一个候选解最后被发现并不是可行解,回溯算法会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。
    *
    * 给出如下回溯函数 backtrack(combination, next_digits) ,它将一个目前已经产生的组合 combination 和接下来准备要输入的数字 next_digits 作为参数。
    *
    * 如果没有更多的数字需要被输入,那意味着当前的组合已经产生好了。
    * 如果还有数字需要被输入:
    * 遍历下一个数字所对应的所有映射的字母。
    * 将当前的字母添加到组合最后,也就是 combination = combination + letter 。
    * 重复这个过程,输入剩下的数字: backtrack(combination + letter, next_digits[1:]) 。
    *
    * 有动画图解
    * 作者:LeetCode
    * 链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/solution/dian-hua-hao-ma-de-zi-mu-zu-he-by-leetcode/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    * @param digits
    * @return
    */
    public List<String> letterCombinations1(String digits) {
    if (digits.length() != 0)
    backtrack("", digits);
    return output;
    }


    public static void main(String[] args) {
    System.out.println(letterCombinations("3"));
    System.out.println(new Leetcode17().letterCombinations1("234"));
    }
    }

    + +

    18. 4Sum

    Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

    +

    Note:

    +

    The solution set must not contain duplicate quadruplets.

    +
    Example
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Example:

    Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

    A solution set is:
    [
    [-1, 0, 0, 1],
    [-2, -1, 1, 2],
    [-2, 0, 0, 2]
    ]

    + +
    JAVA题解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    package algorithm;

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;

    /**
    * 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,
    * 使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
    *
    * 注意:
    *
    * 答案中不可以包含重复的四元组。
    *
    * 示例:
    *
    * 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
    *
    * 满足要求的四元组集合为:
    * [
    * [-1, 0, 0, 1],
    * [-2, -1, 1, 2],
    * [-2, 0, 0, 2]
    * ]
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/4sum
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode18 {

    /**
    * 思路:
    *
    * 四数之和与前面三数之和的思路几乎是一样的,嗝。(刚好前些天才写了三数之和的题解)
    * 如果前面的三数之和会做了的话,这里其实就是在前面的基础上多添加一个遍历的指针而已。
    * 会做三数之和的可以不用看下面的了。。
    *
    * 使用四个指针(a<b<c<d)。固定最小的a和b在左边,c=b+1,d=_size-1 移动两个指针包夹求解。
    * 保存使得nums[a]+nums[b]+nums[c]+nums[d]==target的解。偏大时d左移,偏小时c右移。c和d相
    * 遇时,表示以当前的a和b为最小值的解已经全部求得。b++,进入下一轮循环b循环,当b循环结束后。
    * a++,进入下一轮a循环。 即(a在最外层循环,里面嵌套b循环,再嵌套双指针c,d包夹求解)。
    * 准备工作:
    *
    * 因为要使用双指针的方法,排序是必须要做der~。 时间复杂度O(NlogN).
    *
    * 作者:misakasagiri-2
    * 链接:https://leetcode-cn.com/problems/4sum/solution/shuang-zhi-zhen-jie-fa-can-zhao-san-shu-zhi-he-ge-/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    *
    * @param nums
    * @param target
    * @return
    */
    public List<List<Integer>> fourSum(int[] nums, int target) {
    /*定义一个返回值*/
    List<List<Integer>> result = new ArrayList<>();
    /*当数组为null或元素小于4个时,直接返回*/
    if (nums == null || nums.length < 4) {
    return result;
    }
    /*对数组进行从小到大排序*/
    Arrays.sort(nums);
    System.out.println("-4,-1,-1,0,1,2");
    /*数组长度*/
    int length = nums.length;
    /*定义4个指针k,i,j,h k从0开始遍历,i从k+1开始遍历,留下j和h,j指向i+1,h指向数组最大值*/
    for (int k = 0; k < length - 3; k++) {
    /*当k的值与前面的值相等时忽略*/
    if (k > 0 && nums[k] == nums[k - 1]) {
    continue;
    }
    /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏*/
    int min1 = nums[k] + nums[k + 1] + nums[k + 2] + nums[k + 3];
    if (min1 > target) {
    break;
    }
    /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/
    int max1 = nums[k] + nums[length - 1] + nums[length - 2] + nums[length - 3];
    if (max1 < target) {
    continue;
    }
    /*第二层循环i,初始值指向k+1*/
    for (int i = k + 1; i < length - 2; i++) {
    /*当i的值与前面的值相等时忽略*/
    if (i > k + 1 && nums[i] == nums[i - 1]) {
    continue;
    }
    /*定义指针j指向i+1*/
    int j = i + 1;
    /*定义指针h指向数组末尾*/
    int h = length - 1;
    /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏,忽略*/
    int min = nums[k] + nums[i] + nums[j] + nums[j + 1];
    if (min > target) {
    System.out.println("m,k="+k+",i="+i+",j="+j+",j+1="+(j+1));
    break; // 此时直接滑动k,因为不管怎么滑动i,min 都会大于target
    }
    /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/
    int max = nums[k] + nums[i] + nums[h] + nums[h - 1];
    if (max < target) {
    System.out.println("ma,k="+k+",i="+i+",j="+j+",j+1="+(j+1));
    continue; // 此时continue滑动i 值,nums[i] + nums[h] + nums[h - 1] 变大 ,整个max 会变大
    }
    /**
    * -4,-1,-1,0,1,2
    * ma,k=0,i=1,j=2,j+1=3
    * m,k=1,i=3,j=4,j+1=5
    * [[-4, 0, 1, 2], [-1, -1, 0, 1]]
    *
    * -4,-1,-1,0,1,2
    * ma,k=0,i=1,j=2,j+1=3
    * m,k=1,i=3,j=4,j+1=5
    * [[-1, -1, 0, 1]]
    */


    /*开始j指针和h指针的表演,计算当前和,如果等于目标值,j++并去重,h--并去重,当当前和大于目标值时h--,当当前和小于目标值时j++*/
    while (j < h) {
    int curr = nums[k] + nums[i] + nums[j] + nums[h];
    if (curr == target) {
    result.add(Arrays.asList(nums[k], nums[i], nums[j], nums[h]));
    j++;
    while (j < h && nums[j] == nums[j - 1]) {
    j++;
    }
    h--;
    while (j < h && i < h && nums[h] == nums[h + 1]) {
    h--;
    }
    } else if (curr > target) {
    h--;
    } else {
    j++;
    }
    }
    }
    }
    return result;
    }

    /*
    作者:you-wei-wu
    链接:https://leetcode-cn.com/problems/4sum/solution/ji-bai-9994de-yong-hu-you-dai-ma-you-zhu-shi-by-yo/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    */

    public static void main(String[] args) {
    System.out.println(new Leetcode18().fourSum(new int[]{-1,0,1,2,-1,-4},-1));
    }
    }

    + +
    发布于

    2020-01-08

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode19-20.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode19-20.html" new file mode 100644 index 0000000000..06dc8b1cc7 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode19-20.html" @@ -0,0 +1,210 @@ + +算法成长之路leetcode19-20 - 辣椒の酱 + +
    算法成长之路leetcode19-20

    算法成长之路leetcode19-20

    19. Remove Nth Node From End of List

    Given a linked list, remove the n-th node from the end of list and return its head.

    + + +
    Example
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Example:

    Given linked list: 1->2->3->4->5, and n = 2.

    After removing the second node from the end, the linked list becomes 1->2->3->5.
    Note:

    Given n will always be valid.

    Follow up:

    Could you do this in one pass?

    + +
    JAVA题解

    方法一:两次遍历算法

    +
      +
    • 思路
    • +
    +

    我们注意到这个问题可以容易地简化成另一个问题:删除从列表开头数起的第 (L - n + 1)(L−n+1) 个结点,其中 LL 是列表的长度。只要我们找到列表的长度 LL,这个问题就很容易解决。

    +
      +
    • 算法
    • +
    +

    首先我们将添加一个哑结点作为辅助,该结点位于列表头部。哑结点用来简化某些极端情况,例如列表中只含有一个结点,或需要删除列表的头部。在第一次遍历中,我们找出列表的长度 LL。然后设置一个指向哑结点的指针,并移动它遍历列表,直至它到达第 (L - n)(L−n) 个结点那里。我们把第 (L - n)(L−n) 个结点的 next 指针重新链接至第 (L - n + 2)(L−n+2) 个结点,完成这个算法。

    +

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    /**
    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

    示例:
    给定一个链表: 1->2->3->4->5, 和 n = 2.
    当删除了倒数第二个节点后,链表变为 1->2->3->5.
    说明:
    给定的 n 保证是有效的。
    进阶:
    你能尝试使用一趟扫描实现吗?
    */
    public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    int length = 0;
    ListNode first = head;
    while (first != null) {
    length++;
    first = first.next;
    }
    length -= n;
    first = dummy;
    while (length > 0) {
    length--;
    first = first.next;
    }
    first.next = first.next.next;
    return dummy.next;
    }
    + +

    方法二:一次遍历算法

    +
      +
    • 算法
    • +
    +

    上述算法可以优化为只使用一次遍历。我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1n+1 步,而第二个指针将从列表的开头出发。现在,这两个指针被 nn 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 nn 个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。

    +

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode first = dummy;
    ListNode second = dummy;
    // Advances first pointer so that the gap between first and second is n nodes apart
    for (int i = 1; i <= n + 1; i++) {
    first = first.next;
    }
    // Move first to the end, maintaining the gap
    while (first != null) {
    first = first.next;
    second = second.next;
    }
    second.next = second.next.next;
    return dummy.next;
    }

    作者:LeetCode
    链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-by-l/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    + +

    20. Valid Parentheses

    Given a string containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[‘ and ‘]’, determine if the input string is valid.

    +

    An input string is valid if:

    +

    Open brackets must be closed by the same type of brackets.
    Open brackets must be closed in the correct order.
    Note that an empty string is also considered valid.

    +
    Example
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Example 1:

    Input: "()"
    Output: true
    Example 2:

    Input: "()[]{}"
    Output: true
    Example 3:

    Input: "(]"
    Output: false
    Example 4:

    Input: "([)]"
    Output: false
    Example 5:

    Input: "{[]}"
    Output: true

    + +
    JAVA题解
    Leetcode20.java >folded
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    package algorithm;

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    /**
    * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
    *
    * 有效字符串需满足:
    *
    * 左括号必须用相同类型的右括号闭合。
    * 左括号必须以正确的顺序闭合。
    * 注意空字符串可被认为是有效字符串。
    *
    * 示例 1:
    *
    * 输入: "()"
    * 输出: true
    * 示例 2:
    *
    * 输入: "()[]{}"
    * 输出: true
    * 示例 3:
    *
    * 输入: "(]"
    * 输出: false
    * 示例 4:
    *
    * 输入: "([)]"
    * 输出: false
    * 示例 5:
    *
    * 输入: "{[]}"
    * 输出: true
    *
    */
    public class Leetcode20 {

    // 类似栈的处理
    public boolean isValid(String s) {

    if(s == null || s.equals("")){
    return true;
    }

    // 奇数
    if(s.length() % 2 != 0){
    return false;
    }
    List<Integer> arr = new ArrayList<>();
    Map<Character, Integer> cIn = new HashMap<>();
    cIn.put('(', 1);
    cIn.put(')', -1);
    cIn.put('{', 2);
    cIn.put('}', -2);
    cIn.put('[', 3);
    cIn.put(']', -3);

    char[] chars = s.toCharArray();
    arr.add(cIn.get(chars[0]));
    for (int i = 1; i < chars.length; i++) {
    // 相等则移除
    int latestIndex = arr.size() - 1;
    if (latestIndex >= 0 && arr.get(latestIndex) == -cIn.get(chars[i])) {
    arr.remove(latestIndex);
    } else {
    arr.add(cIn.get(chars[i]));
    }
    }
    if (arr.size() > 0) {
    return false;
    } else {
    return true;
    }
    }

    public static void main(String[] args) {
    System.out.println(new Leetcode20().isValid("([])[]"));
    }
    }

    // 栈的处理
    class Solution {
    public boolean isValid(String s) {
    if(s.isEmpty())
    return true;
    Stack<Character> stack=new Stack<Character>();
    for(char c:s.toCharArray()){
    if(c=='(')
    stack.push(')');
    else if(c=='{')
    stack.push('}');
    else if(c=='[')
    stack.push(']');
    else if(stack.empty()||c!=stack.pop())
    return false;
    }
    if(stack.empty())
    return true;
    return false;
    }
    }

    // 栈 官方
    class Solution {

    // Hash table that takes care of the mappings.
    private HashMap<Character, Character> mappings;

    // Initialize hash map with mappings. This simply makes the code easier to read.
    public Solution() {
    this.mappings = new HashMap<Character, Character>();
    this.mappings.put(')', '(');
    this.mappings.put('}', '{');
    this.mappings.put(']', '[');
    }

    public boolean isValid(String s) {

    // Initialize a stack to be used in the algorithm.
    Stack<Character> stack = new Stack<Character>();

    for (int i = 0; i < s.length(); i++) {
    char c = s.charAt(i);

    // If the current character is a closing bracket.
    if (this.mappings.containsKey(c)) {

    // Get the top element of the stack. If the stack is empty, set a dummy value of '#'
    char topElement = stack.empty() ? '#' : stack.pop();

    // If the mapping for this bracket doesn't match the stack's top element, return false.
    if (topElement != this.mappings.get(c)) {
    return false;
    }
    } else {
    // If it was an opening bracket, push to the stack.
    stack.push(c);
    }
    }

    // If the stack still contains elements, then it is an invalid expression.
    return stack.isEmpty();
    }
    }
    + +
    发布于

    2020-01-19

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode21-22.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode21-22.html" new file mode 100644 index 0000000000..cd5c886c70 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode21-22.html" @@ -0,0 +1,188 @@ + +算法成长之路leetcode21-22 - 辣椒の酱 + +
    算法成长之路leetcode21-22

    算法成长之路leetcode21-22

    21. Merge Two Sorted Lists

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

    + +

    Example:

    1
    2
    Input: 1->2->4, 1->3->4
    Output: 1->1->2->3->4->4
    + +

    JAVA题解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    package algorithm.c3;

    /**
    * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 
    *
    * 示例:
    *
    * 输入:1->2->4, 1->3->4
    * 输出:1->1->2->3->4->4
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode21 {

    // 错解
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {

    ListNode l = new ListNode(0);
    ListNode cur = l;
    while (l1.next != null || l2.next != null){

    if (l1.next == null) {
    cur.next = l2;
    } else if (l2.next == null) {
    cur.next = l1;
    }else {
    if(l1.val > l2.val){
    cur.next= l2;
    l2 = l2.next;
    }else if(l1.val == l2.val){
    cur.next= l2;
    cur.next.next = l1;
    l1 = l1.next;
    l2 = l2.next;
    }else{
    cur.next = l1;
    l1 = l1.next;
    }
    }
    cur = cur.next;
    }

    return l.next;

    }

    public ListNode mergeTwoLists1(ListNode l1, ListNode l2) {
    // maintain an unchanging reference to node ahead of the return node.
    ListNode prehead = new ListNode(-1);

    ListNode prev = prehead;
    while (l1 != null && l2 != null) {
    if (l1.val <= l2.val) {
    prev.next = l1;
    l1 = l1.next;
    } else {
    prev.next = l2;
    l2 = l2.next;
    }
    prev = prev.next;
    }

    // exactly one of l1 and l2 can be non-null at this point, so connect
    // the non-null list to the end of the merged list.
    prev.next = l1 == null ? l2 : l1;

    return prehead.next;
    }

    // 递归
    public ListNode mergeTwoLists2(ListNode l1, ListNode l2) {
    if (l1 == null) {
    return l2;
    } else if (l2 == null) {
    return l1;
    } else if (l1.val < l2.val) {
    l1.next = mergeTwoLists(l1.next, l2);
    return l1;
    } else {
    l2.next = mergeTwoLists(l1, l2.next);
    return l2;
    }
    }

    public static void main(String[] args) {
    ListNode l1 = new ListNode(1);
    l1.next = new ListNode(2);
    l1.next.next = new ListNode(4);

    ListNode l2 = new ListNode(1);
    l2.next = new ListNode(1);
    l2.next.next = new ListNode(3);

    System.out.println(new Leetcode21().mergeTwoLists1(l1,l2));

    }

    public static class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
    val = x;
    }
    }
    }
    + +

    22. Generate Parentheses

    Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

    +

    Example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    For example, given n = 3, a solution set is:

    [
    "((()))",
    "(()())",
    "(())()",
    "()(())",
    "()()()"
    ]
    + +

    JAVA题解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    package algorithm.c3;

    import java.util.LinkedList;
    import java.util.List;

    /**
    * 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
    *
    * 例如,给出 n = 3,生成结果为:
    *
    * [
    * "((()))",
    * "(()())",
    * "(())()",
    * "()(())",
    * "()()()"
    * ]
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/generate-parentheses
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public class Leetcode22 {

    /**
    *
    * 在此题中,动态规划的思想类似于数学归纳法,当知道所有 i<n 的情况时,我们可以通过某种算法算出 i=n 的情况。
    * 本题最核心的思想是,考虑 i=n 时相比 n-1 组括号增加的那一组括号的位置。
    *
    * 思路:
    * 当我们清楚所有 i<n 时括号的可能生成排列后,对与 i=n 的情况,我们考虑整个括号排列中最左边的括号。
    * 它一定是一个左括号,那么它可以和它对应的右括号组成一组完整的括号 "( )",我们认为这一组是相比 n-1 增加进来的括号。
    *
    * 那么,剩下 n-1 组括号有可能在哪呢?
    *
    * 【这里是重点,请着重理解】
    *
    * 剩下的括号要么在这一组新增的括号内部,要么在这一组新增括号的外部(右侧)。
    *
    * 既然知道了 i<n 的情况,那我们就可以对所有情况进行遍历:
    *
    * "(" + 【i=p时所有括号的排列组合】 + ")" + 【i=q时所有括号的排列组合】
    *
    * 其中 p + q = n-1,且 p q 均为非负整数。
    *
    * 事实上,当上述 p 从 0 取到 n-1,q 从 n-1 取到 0 后,所有情况就遍历完了。
    *
    * 注:上述遍历是没有重复情况出现的,即当 (p1,q1)≠(p2,q2) 时,按上述方式取的括号组合一定不同。
    *
    * 作者:yuyu-13
    * 链接:https://leetcode-cn.com/problems/generate-parentheses/solution/zui-jian-dan-yi-dong-de-dong-tai-gui-hua-bu-lun-da/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    *
    * 简单来说,在求N个括号的排列组合时,把第N种情况(也就是N个括号排列组合)视为单独拿一个括号E出来,
    * 剩下的N-1个括号分为两部分,P个括号和Q个括号,P+Q=N-1,然后这两部分分别处于括号E内和括号E的右边,
    * 各自进行括号的排列组合。由于我们是一步步计算得到N个括号的情况的,所以小于等于N-1个括号的排列组合方式我们是已知的(
    * 用合适的数据结构存储,方便后续调用,且在存储时可利用特定数据结构实现题目某些要求,如排序,去重等),
    * 且P+Q=N-1,P和Q是小于等于N-1的,所以我们能直接得到P个和Q个括号的情况,进而得到N个括号的结果!
    *
    * 楼主的算法思想很巧妙,赞一个~这个算法主要的基点就是将排列组合的情况分为了括号内和括号外这两种情况,
    * 且仅存在两种情况!至于为什么,原因在于楼主的算法的前提是单独拿出来的括号E的左边在N个括号所有排列组合情况中都是处于最左边,
    * 所以不存在括号位于括号E的左边的情况。因此,N-1个括号(拿出了括号E)仅可能分布于括号E内和括号E外,分为两种子情况讨论!
    * 这种思想还可以应用于其他类似的题的求解中,即怎样合理高效的利用前面步骤的计算结果得出当前步骤结果,从而得出最终结果。
    *
    * @param n
    * @return
    */
    public List<String> generateParenthesis(int n) {
    LinkedList<LinkedList<String>> result = new LinkedList<LinkedList<String>>();
    if (n == 0)
    return result.get(0);
    LinkedList<String> list0 = new LinkedList<String>();
    list0.add("");
    result.add(list0);
    LinkedList<String> list1 = new LinkedList<String>();
    list1.add("()");
    result.add(list1);
    for (int i = 2; i <= n; i++) {
    LinkedList<String> temp = new LinkedList<String>();
    for (int j = 0; j < i; j++) {
    List<String> str1 = result.get(j);
    List<String> str2 = result.get(i - 1 - j);
    for (String s1 : str1) {
    for (String s2 : str2) {
    String el = "(" + s1 + ")" + s2;
    temp.add(el);
    }
    }

    }
    result.add(temp);
    }
    return result.get(n);
    }
    }
    +
    发布于

    2020-02-10

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode5-6.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode5-6.html" new file mode 100644 index 0000000000..70f2405924 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode5-6.html" @@ -0,0 +1,189 @@ + +算法成长之路leetcode5-6 - 辣椒の酱 + +
    算法成长之路leetcode5-6

    算法成长之路leetcode5-6

    5. Longest Palindromic Substring

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

    + +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    Example 1:
    Input: "babad"
    Output: "bab"
    Note: "aba" is also a valid answer.

    Example 2:
    Input: "cbbd"
    Output: "bb"
    +

    JAVA题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    package algorithm;

    public class Leetcode5 {
    public static void main(String[] args) {
    System.out.println(longestPalindrome("abbaabb"));
    }

    /**
    * 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
    *
    * 示例 1:
    *
    * 输入: "babad"
    * 输出: "bab"
    * 注意: "aba" 也是一个有效答案。
    * 示例 2:
    *
    * 输入: "cbbd"
    * 输出: "bb"
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/longest-palindromic-substring
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */

    /**
    * 终于看懂了这个中心向两边扩张算法是什么意思了。
    * 先来解释一下为什么中心是2n-1而不是n 比如有字符串abcba,这时回文子串是abcda,
    * 中心是c;又有字符串adccda,这时回文子串是adccda,中心是cc。 由此可见中心点既有可能是一个字符,
    * 也有可能是两个字符,当中心为一个字符的时候有n个中心,
    * 当中心为两个字符的时候有n-1个中心,所以一共有2n-1个中心。
    * 然后for循环开始从左到右遍历,为什么会有两次expandAroundCenter,一次是i和i本身,一次是i和i+1,
    * 这就是上面说到的一个中心与两个中心。 而后会去判断这两种情况下谁的回文子串最长,并标记出这个子串在原字符串中的定位,即start和end。
    *
    * @param s
    * @return
    */
    public static String longestPalindrome(String s) {

    if (s == null || s.length() < 1) return "";
    int start = 0, end = 0;
    for (int i = 0; i < s.length(); i++) {
    // 一个数向两边扩张
    int len1 = expandAroundCenter(s, i, i);
    // 两个数向两边扩张
    int len2 = expandAroundCenter(s, i, i + 1);
    // 取最长的回文
    int len = Math.max(len1, len2);
    // 判读此时长度和原来的最长度
    if (len > end - start) {
    // 求最长回文开始位置
    start = i - (len - 1) / 2;
    // 求最长回文结束位置
    end = i + len / 2;
    }
    }
    // 截取最长回文
    return s.substring(start, end + 1);
    }

    /**
    * 向两边向两边扩张求长度
    *
    * @param s
    * @param left
    * @param right
    * @return
    */
    private static int expandAroundCenter(String s, int left, int right) {
    // 定位中心位置
    int L = left, R = right;
    // 判读中间位置是否相等,以及两边扩张是否相等
    while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
    // 向左扩张一位
    L--;
    // 向右扩张一位
    R++;
    }
    // 回文的长度 如 aba 时,当 b = 1时,一个中心点进来,L = 1,R = 1,此时满足循环,L=0,R=2,此时也满足
    // 循环,L = -1,R=3,此时循环结束,长度为3 = 3 -(-1) -1
    return R - L - 1;
    }
    }

    +

    6. ZigZag Conversion

    The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

    +

    P A H N
    A P L S I I G
    Y I R
    And then read line by line: “PAHNAPLSIIGYIR”

    +

    Write the code that will take a string and make this conversion given a number of rows:

    +

    string convert(string s, int numRows);

    +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Example 1:
    Input: s = "PAYPALISHIRING", numRows = 3
    Output: "PAHNAPLSIIGYIR"

    Example 2:
    Input: s = "PAYPALISHIRING", numRows = 4
    Output: "PINALSIGYAHRPI"
    Explanation:

    P I N
    A L S I G
    Y A H R
    P I
    +

    JAVA题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    package algorithm;

    import java.util.ArrayList;
    import java.util.List;

    public class Leetcode6 {
    /**
    * 将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
    * <p>
    * 比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
    * <p>
    * L C I R
    * E T O E S I I G
    * E D H N
    * 之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。
    * <p>
    * 请你实现这个将字符串进行指定行数变换的函数:
    * <p>
    * string convert(string s, int numRows);
    * 示例 1:
    * <p>
    * 输入: s = "LEETCODEISHIRING", numRows = 3
    * 输出: "LCIRETOESIIGEDHN"
    * 示例 2:
    * <p>
    * 输入: s = "LEETCODEISHIRING", numRows = 4
    * 输出: "LDREOEIIECIHNTSG"
    * 解释:
    * <p>
    * L D R
    * E O E I I
    * E C I H N
    * T S G
    * <p>
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/zigzag-conversion
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public String convert(String s, int numRows) {

    if (numRows == 1) return s;

    List<StringBuilder> rows = new ArrayList<>();
    for (int i = 0; i < Math.min(numRows, s.length()); i++)
    // 确定有多少行,每一行放一个待填充的字符串
    rows.add(new StringBuilder());
    // 当前行
    int curRow = 0;
    // 上移或下移 false上移
    boolean goingDown = false;

    for (char c : s.toCharArray()) {
    // 挨着放字符到对应的行
    rows.get(curRow).append(c);
    // 判断是否下移,当第一行和最后一行的时候转向
    if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
    // 下移行数+1,上移行数-1
    curRow += goingDown ? 1 : -1;
    }
    // 存最终结果
    StringBuilder ret = new StringBuilder();
    // 遍历每行,进行连接
    for (StringBuilder row : rows) ret.append(row);
    return ret.toString();
    }

    public static void main(String[] args) {
    Leetcode6 l = new Leetcode6();
    System.out.println(l.convert("weweqw", 3));
    }
    }
    + +
    发布于

    2019-12-05

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode7-8.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode7-8.html" new file mode 100644 index 0000000000..df10bd25ce --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode7-8.html" @@ -0,0 +1,200 @@ + +算法成长之路leetcode7-8 - 辣椒の酱 + +
    算法成长之路leetcode7-8

    算法成长之路leetcode7-8

    7. Reverse Integer

    Given a 32-bit signed integer, reverse digits of an integer.

    + + +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Example 1:

    Input: 123
    Output: 321

    Example 2:

    Input: -123
    Output: -321

    Example 3:

    Input: 120
    Output: 21
    + + + +

    Note:
    Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

    +

    JAVA题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    package algorithm;

    public class Leetcode7 {
    /**
    * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
    *
    * 示例 1:
    *
    * 输入: 123
    * 输出: 321
    *  示例 2:
    *
    * 输入: -123
    * 输出: -321
    * 示例 3:
    *
    * 输入: 120
    * 输出: 21
    * 注意:
    *
    * 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31,  2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/reverse-integer
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    public int reverse(int x) {

    if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) {
    return 0;
    }

    boolean isNe = x < 0 ? true : false;
    x = Math.abs(x);
    // 取绝对值时越界了,直接返回0
    if (isNe && x < 0) {
    return 0;
    }
    StringBuilder sb = new StringBuilder();
    long m = 10;
    long base = 1;

    while (true) {
    base = m * base;
    long re = x % base;
    if (base == 10) {
    sb.append(re);
    } else {
    sb.append((re * m) / base);
    }
    if (x < base) {
    break;
    }
    }
    Long res;
    if (isNe) {
    res = 0 - Long.parseLong(sb.toString());
    } else {
    res = Long.parseLong(sb.toString());
    }

    if (res > Integer.MAX_VALUE || res < Integer.MIN_VALUE) {
    return 0;
    } else {
    return res.intValue();
    }
    }

    public int reverse1(int x) {
    int rev = 0;
    while (x != 0) {
    int pop = x % 10;
    x /= 10;
    // Integer.MAX_VALUE = 2147483647,因为后面 rev = rev * 10 + pop,所以rev >Integer.MAX_VALUE 溢出
    // rev == Integer.MAX_VALUE / 10 时,Integer.MAX_VALUE / 10 = 2147483640,so,pop > 7时溢出
    if (rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
    // Integer.MIN_VALUE = -2147483648
    // 同理如上
    if (rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
    rev = rev * 10 + pop;
    }
    return rev;
    }

    public static void main(String[] args) {
    System.out.println(Integer.MAX_VALUE);
    // System.out.println(reverse1(123));
    }
    }

    + +

    8. String to Integer (atoi)

    Implement atoi which converts a string to an integer.

    +

    The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.

    +

    The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.

    +

    If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.

    +

    If no valid conversion could be performed, a zero value is returned.

    +

    Note:

    +

    Only the space character ‘ ‘ is considered as whitespace character.
    Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. If the numerical value is out of the range of representable values, INT_MAX (2^31 − 1) or INT_MIN (−2^31) is returned.

    +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    Example 1:

    Input: "42"
    Output: 42
    Example 2:

    Input: " -42"
    Output: -42
    Explanation: The first non-whitespace character is '-', which is the minus sign.
    Then take as many numerical digits as possible, which gets 42.
    Example 3:

    Input: "4193 with words"
    Output: 4193
    Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
    Example 4:

    Input: "words and 987"
    Output: 0
    Explanation: The first non-whitespace character is 'w', which is not a numerical
    digit or a +/- sign. Therefore no valid conversion could be performed.
    Example 5:

    Input: "-91283472332"
    Output: -2147483648
    Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer.
    Thefore INT_MIN (−2^31) is returned.

    + +

    JAVA题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    package algorithm;

    public class Leetcode8 {

    /**
    *
    *请你来实现一个 atoi 函数,使其能将字符串转换成整数。
    *
    * 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
    *
    * 当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
    *
    * 该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
    *
    * 注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
    *
    * 在任何情况下,若函数不能进行有效的转换时,请返回 0。
    *
    * 说明:
    *
    * 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31,  2^31 − 1]。如果数值超过这个范围,请返回  INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。
    *
    * 示例 1:
    *
    * 输入: "42"
    * 输出: 42
    * 示例 2:
    *
    * 输入: " -42"
    * 输出: -42
    * 解释: 第一个非空白字符为 '-', 它是一个负号。
    *   我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
    * 示例 3:
    *
    * 输入: "4193 with words"
    * 输出: 4193
    * 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
    * 示例 4:
    *
    * 输入: "words and 987"
    * 输出: 0
    * 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
    * 因此无法执行有效的转换。
    * 示例 5:
    *
    * 输入: "-91283472332"
    * 输出: -2147483648
    * 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。
    *   因此返回 INT_MIN (−2^31) 。
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/string-to-integer-atoi
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */

    public static int myAtoi(String str) {
    StringBuilder st = new StringBuilder();
    for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);
    if (c == '-') {
    if (st.length() > 0) {
    break;
    }
    st.append(c);
    } else if (c == '+') {
    if (st.length() > 0) {
    break;
    }
    st.append(c);
    } else if (c == ' ') {
    if (st.length() > 0) {
    break;
    } else {
    continue;
    }
    } else if (c >= 48 && c <= 57) {
    st.append(c);
    } else {
    break;
    }
    if (st.length() > 1) {
    if (Long.parseLong(st.toString()) > Integer.MAX_VALUE) {
    return Integer.MAX_VALUE;
    }

    if (Long.parseLong(st.toString()) < Integer.MIN_VALUE) {
    return Integer.MIN_VALUE;
    }
    }

    }
    if (st.length() == 0) {
    return 0;
    }
    if (st.toString().equals("-") || st.toString().equals("+")) {
    return 0;
    }
    return Long.valueOf(st.toString()).intValue();
    }


    public int myAtoi1(String str) {
    if (str.isEmpty())
    return 0;
    char[] mychar = str.toCharArray();
    long ans = 0;
    int index = 0, flag = 1, n = str.length();
    //排除字符串开头的空格元素
    while (index < n && mychar[index] == ' ') {
    index++;
    }
    //排除空格后判断首字符是+还是-还是都不是
    if (index < n && mychar[index] == '+') {
    index++;
    } else if (index < n && mychar[index] == '-') {
    index++;
    flag = -1;
    }
    //重点:只管是数字的时候,其余取0
    while (index < n && (mychar[index] >= '0' && mychar[index] <= '9')) {
    if (ans != (int) ans) {//超出int范围
    return (flag == 1) ? Integer.MAX_VALUE : Integer.MIN_VALUE;//提前结束
    }

    // 巧妙的加起来值来 如 111 ,第一个1时 ans = 0 * 10 +1,第二个1时 ans = 1*10 + 1 = 11,第三个1时, ans = 11*10 + 1 = 111;
    ans = ans * 10 + mychar[index++] - '0';
    }
    // 强转long是否等于int 判断是否超界,机智
    if (ans != (int) ans) {
    return (flag == 1) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
    }
    return (int) (ans * flag);

    }

    public static void main(String[] args) {
    /**
    * "42"
    * "----01"
    * "0-1"
    * "-5-"
    */
    System.out.println(myAtoi("0-1"));
    }
    }

    + + +
    发布于

    2019-12-10

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode9-10.html" "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode9-10.html" new file mode 100644 index 0000000000..08f4d55138 --- /dev/null +++ "b/algorithm/\347\256\227\346\263\225\346\210\220\351\225\277\344\271\213\350\267\257leetcode9-10.html" @@ -0,0 +1,193 @@ + +算法成长之路leetcode9-10 - 辣椒の酱 + +
    算法成长之路leetcode9-10

    算法成长之路leetcode9-10

    9. Palindrome Number

    Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

    + +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Example 1:

    Input: 121
    Output: true
    Example 2:

    Input: -121
    Output: false
    Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
    Example 3:

    Input: 10
    Output: false
    Explanation: Reads 01 from right to left. Therefore it is not a palindrome.
    Follow up:

    Coud you solve it without converting the integer to a string?

    + +

    Java 题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    package algorithm;
    public class Leetcode9 {

    /**
    * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
    *
    * 示例 1:
    *
    * 输入: 121
    * 输出: true
    * 示例 2:
    *
    * 输入: -121
    * 输出: false
    * 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
    * 示例 3:
    *
    * 输入: 10
    * 输出: false
    * 解释: 从右向左读, 为 01 。因此它不是一个回文数。
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/palindrome-number
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    * @param x
    * @return
    */

    public static boolean isPalindrome(int x) {
    if (x >= 0 && x < 10) {
    return true;
    }

    String source = x + "";
    int length = source.length();
    // mid中间位置1,mid1中间位置2
    int mid, mid1;
    // 偶数
    if (length % 2 == 0) {
    // 如 1221 偶数,中间位置分别为2,2
    mid = length / 2 - 1;
    mid1 = mid + 1;
    } else {
    // 奇数时,212,中间位置分别是1,1
    mid = length / 2;
    mid1 = mid;
    }
    // 确定中心位置向两边扩展是否相等,直到扩展完位置
    while (mid >= 0 && source.charAt(mid) == source.charAt(mid1)) {
    mid = mid - 1;
    mid1 = mid1 + 1;
    }

    // 如果循环结束并且所有数都遍历完
    if (mid == -1 && mid1 == length) {
    return true;
    } else {
    return false;
    }
    }

    public static boolean isPalindrome1(int x) {
    // 特殊情况:
    // 如上所述,当 x < 0 时,x 不是回文数。
    // 同样地,如果数字的最后一位是 0,为了使该数字为回文,
    // 则其第一位数字也应该是 0
    // 只有 0 满足这一属性
    if (x < 0 || (x % 10 == 0 && x != 0)) {
    return false;
    }

    // 一位一位反转的数
    int revertedNumber = 0;
    // 如121
    while (x > revertedNumber) {
    revertedNumber = revertedNumber * 10 + x % 10;
    x /= 10;
    System.out.println("x=" + x + ",revertedNumber=" + revertedNumber);
    }

    // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
    // 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
    // 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
    return x == revertedNumber || x == revertedNumber / 10;
    }

    public static void main(String[] args) {
    /**
    * -1
    * 121
    * 222
    * 2222
    * 1221
    * -12
    */
    System.out.println(isPalindrome(1221));
    System.out.println(isPalindrome1(121));
    }
    }

    + +

    10. Regular Expression Matching

    Given an input string (s) and a pattern (p), implement regular expression matching with support for ‘.’ and ‘*’.

    +

    ‘.’ Matches any single character.
    ‘*’ Matches zero or more of the preceding element.
    The matching should cover the entire input string (not partial).

    +

    Note:

    +

    s could be empty and contains only lowercase letters a-z.
    p could be empty and contains only lowercase letters a-z, and characters like . or *.

    +

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    Example 1:

    Input:
    s = "aa"
    p = "a"
    Output: false
    Explanation: "a" does not match the entire string "aa".
    Example 2:

    Input:
    s = "aa"
    p = "a"
    Output: true
    Explanation: '' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
    Example 3:

    Input:
    s = "ab"
    p = "."
    Output: true
    Explanation: "." means "zero or more (*) of any character (.)".
    Example 4:

    Input:
    s = "aab"
    p = "cab"
    Output: true
    Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches "aab".
    Example 5:

    Input:
    s = "mississippi"
    p = "misisp*."
    Output: false
    + +

    JAVA 题解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    package algorithm;


    public class Leetcode10 {
    /**
    * 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
    *
    * '.' 匹配任意单个字符
    * '*' 匹配零个或多个前面的那一个元素
    * 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
    *
    * 说明:
    *
    * s 可能为空,且只包含从 a-z 的小写字母。
    * p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
    * 示例 1:
    *
    * 输入:
    * s = "aa"
    * p = "a"
    * 输出: false
    * 解释: "a" 无法匹配 "aa" 整个字符串。
    * 示例 2:
    *
    * 输入:
    * s = "aa"
    * p = "a*"
    * 输出: true
    * 解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
    * 示例 3:
    *
    * 输入:
    * s = "ab"
    * p = ".*"
    * 输出: true
    * 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
    * 示例 4:
    *
    * 输入:
    * s = "aab"
    * p = "c*a*b"
    * 输出: true
    * 解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
    * 示例 5:
    *
    * 输入:
    * s = "mississippi"
    * p = "mis*is*p*."
    * 输出: false
    *
    * 来源:力扣(LeetCode)
    * 链接:https://leetcode-cn.com/problems/regular-expression-matching
    * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    *
    *
    *
    * 如果模式串中有星号,它会出现在第二个位置,
    * 即pattern[1] 。这种情况下,我们可以直接忽略模式串中这一部分,
    * 或者删除匹配串的第一个字符,前提是它能够匹配模式串当前位置字符,即 pattern[0] 。
    * 如果两种操作中有任何一种使得剩下的字符串能匹配,那么初始时,匹配串和模式串就可以被匹配。
    *
    * @param text
    * @param pattern
    * @return
    */

    public static boolean isMatch(String text, String pattern) { // 递归回溯

    if (pattern.isEmpty()) return text.isEmpty();

    boolean first_match = (!text.isEmpty() &&
    (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));// 判断第一个是否相等

    System.out.println("t="+text+",p="+pattern+",firstM="+first_match);

    if (pattern.length() >= 2 && pattern.charAt(1) == '*'){ // 长度>=2 并且p第二个是*
    System.out.println("if1");
    return (isMatch(text, pattern.substring(2)) || // 直接忽略模式串中这一部分 如t=abc,p=a*. 直接忽略 a*
    (first_match && isMatch(text.substring(1), pattern))); // 删除匹配串的第一个字符
    } else {
    System.out.println("if2");
    return first_match && isMatch(text.substring(1), pattern.substring(1));// 第一个匹配后,后面逐个匹配
    }
    }


    /**
    * 状态
    * 首先状态 dp 一定能自己想出来。
    * dp[i][j] 表示 s 的前 ii 个是否能被 p 的前 jj 个匹配
    *
    * 转移方程
    * 怎么想转移方程?首先想的时候从已经求出了 dp[i-1][j-1] 入手,再加上已知 s[i]、p[j],要想的问题就是怎么去求 dp[i][j]。
    *
    * 已知 dp[i-1][j-1] 意思就是前面子串都匹配上了,不知道新的一位的情况。
    * 那就分情况考虑,所以对于新的一位 p[j] s[i] 的值不同,要分情况讨论:
    *
    * 考虑最简单的 p[j] == s[i] : dp[i][j] = dp[i-1][j-1]
    * 然后从 p[j] 可能的情况来考虑,让 p[j]=各种能等于的东西。
    *
    * p[j] == "." : dp[i][j] = dp[i-1][j-1]
    *
    * p[j] ==" * ":
    *
    * 第一个难想出来的点:怎么区分 *∗ 的两种讨论情况
    * 首先给了 *,明白 * 的含义是 匹配零个或多个前面的那一个元素,所以要考虑他前面的元素 p[j-1]。* 跟着他前一个字符走,前一个能匹配上 s[i],* 才能有用,前一个都不能匹配上 s[i],* 也无能为力,只能让前一个字符消失,也就是匹配 00 次前一个字符。
    * 所以按照 p[j-1] 和 s[i] 是否相等,我们分为两种情况:
    *
    * 3.1 p[j-1] != s[i] : dp[i][j] = dp[i][j-2]
    * 这就是刚才说的那种前一个字符匹配不上的情况。
    * 比如(ab, abc * )。遇到 * 往前看两个,发现前面 s[i] 的 ab 对 p[j-2] 的 ab 能匹配,虽然后面是 c*,但是可以看做匹配 00 次 c,相当于直接去掉 c *,所以也是 True。注意 (ab, abc**) 是 False。
    * 3.2 p[j-1] == s[i] or p[j-1] == ".":
    * * 前面那个字符,能匹配 s[i],或者 * 前面那个字符是万能的 .
    * 因为 . * 就相当于 . .,那就只要看前面可不可以匹配就行。
    * 比如 (##b , ###b *),或者 ( ##b , ### . * ) 只看 ### 后面一定是能够匹配上的。
    * 所以要看 b 和 b * 前面那部分 ## 的地方匹不匹配。
    * 第二个难想出来的点:怎么判断前面是否匹配
    * dp[i][j] = dp[i-1][j] // 多个字符匹配的情况
    * or dp[i][j] = dp[i][j-1] // 单个字符匹配的情况
    * or dp[i][j] = dp[i][j-2] // 没有匹配的情况
    * 看 ### 匹不匹配,不是直接只看 ### 匹不匹配,要综合后面的 b b* 来分析
    * 这三种情况是 oror 的关系,满足任意一种都可以匹配上,同时是最难以理解的地方:
    *
    * dp[i-1][j] 就是看 s 里 b 多不多, ### 和 ###b * 是否匹配,一旦匹配,s 后面再添个 b 也不影响,因为有 * 在,也就是 ###b 和 ###b *也会匹配。
    *
    * dp[i][j-1] 就是去掉 * 的那部分,###b 和 ###b 是否匹配,比如 qqb qqb
    *
    * dp[i][j-2] 就是 去掉多余的 b *,p 本身之前的能否匹配,###b 和 ### 是否匹配,比如 qqb qqbb* 之前的 qqb qqb 就可以匹配,那多了的 b * 也无所谓,因为 b * 可以是匹配 00 次 b,相当于 b * 可以直接去掉了。
    *
    * 三种满足一种就能匹配上。
    *
    * 为什么没有 dp[i-1][j-2] 的情况? 就是 ### 和 ### 是否匹配?因为这种情况已经是 dp[i][j-1] 的子问题。也就是 s[i]==p[j-1],则 dp[i-1][j-2]=dp[i][j-1]。
    *
    * 最后来个归纳:
    * 如果 p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1];
    * 如果 p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1];
    * 如果 p.charAt(j) == '*':
    * 如果 p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2] //in this case, a* only counts as empty
    * 如果 p.charAt(i-1) == s.charAt(i) or p.charAt(i-1) == '.':
    * dp[i][j] = dp[i-1][j] //in this case, a* counts as multiple a
    * or dp[i][j] = dp[i][j-1] // in this case, a* counts as single a
    * or dp[i][j] = dp[i][j-2] // in this case, a* counts as empty
    *
    * 作者:kao-la-7
    * 链接:https://leetcode-cn.com/problems/regular-expression-matching/solution/dong-tai-gui-hua-zen-yao-cong-0kai-shi-si-kao-da-b/
    * 来源:力扣(LeetCode)
    * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    * @param s
    * @param p
    * @return
    */
    public static boolean isMatch1(String s, String p) { // 动态规划

    if (s == null || p == null) {
    return false;
    }
    boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
    dp[0][0] = true;//dp[i][j] 表示 s 的前 i 个是否能被 p 的前 j 个匹配
    for (int i = 0; i < p.length(); i++) { // here's the p's length, not s's
    if (p.charAt(i) == '*' && dp[0][i - 1]) {
    dp[0][i + 1] = true; // here's y axis should be i+1
    }
    }
    for (int i = 0; i < s.length(); i++) {
    for (int j = 0; j < p.length(); j++) {
    if (p.charAt(j) == '.' || p.charAt(j) == s.charAt(i)) {//如果是任意元素 或者是对于元素匹配
    dp[i + 1][j + 1] = dp[i][j];
    }
    if (p.charAt(j) == '*') {
    if (p.charAt(j - 1) != s.charAt(i) && p.charAt(j - 1) != '.') {//如果前一个元素不匹配 且不为任意元素
    dp[i + 1][j + 1] = dp[i + 1][j - 1];
    } else {
    dp[i + 1][j + 1] = (dp[i + 1][j] || dp[i][j + 1] || dp[i + 1][j - 1]);
    /*
    dp[i][j] = dp[i-1][j] // 多个字符匹配的情况
    or dp[i][j] = dp[i][j-1] // 单个字符匹配的情况
    or dp[i][j] = dp[i][j-2] // 没有匹配的情况
    */

    }
    }
    }
    }
    return dp[s.length()][p.length()];
    }

    // 官方解法--
    enum Result {
    TRUE, FALSE
    }

    Result[][] memo;

    public boolean isMatch2(String text, String pattern) { // 自顶向下 官方
    memo = new Result[text.length() + 1][pattern.length() + 1];
    return dp(0, 0, text, pattern);
    }

    public boolean dp(int i, int j, String text, String pattern) {
    if (memo[i][j] != null) {
    return memo[i][j] == Result.TRUE;
    }
    boolean ans;
    if (j == pattern.length()) {
    ans = i == text.length();
    } else {
    boolean first_match = (i < text.length() &&
    (pattern.charAt(j) == text.charAt(i) ||
    pattern.charAt(j) == '.'));

    if (j + 1 < pattern.length() && pattern.charAt(j + 1) == '*') {
    ans = (dp(i, j + 2, text, pattern) ||
    first_match && dp(i + 1, j, text, pattern));
    } else {
    ans = first_match && dp(i + 1, j + 1, text, pattern);
    }
    }
    memo[i][j] = ans ? Result.TRUE : Result.FALSE;
    return ans;
    }

    public boolean isMatch3(String text, String pattern) { //动态规划,自底向上
    boolean[][] dp = new boolean[text.length() + 1][pattern.length() + 1];
    dp[text.length()][pattern.length()] = true;

    for (int i = text.length(); i >= 0; i--) {
    for (int j = pattern.length() - 1; j >= 0; j--) {
    boolean first_match = (i < text.length() &&
    (pattern.charAt(j) == text.charAt(i) ||
    pattern.charAt(j) == '.'));
    if (j + 1 < pattern.length() && pattern.charAt(j + 1) == '*') {
    dp[i][j] = dp[i][j + 2] || first_match && dp[i + 1][j];
    } else {
    dp[i][j] = first_match && dp[i + 1][j + 1];
    }
    }
    }
    return dp[0][0];
    }
    // 官方解法---

    public static void main(String[] args) {
    // "abc","a*."
    // "abc","ab*."
    System.out.println(isMatch("abc","ab*."));
    /**
    * log
    * t=abc,p=ab*.,firstM=true
    * if2
    * t=bc,p=b*.,firstM=true
    * if1
    * t=bc,p=.,firstM=true
    * if2
    * t=c,p=b*.,firstM=false
    * if1
    * t=c,p=.,firstM=true
    * if2
    * true
    */
    int cons[] = new int[]{1,2,3};
    System.out.println(getLeastCoinAmount(3,cons));
    }

    /**
    *
    * 常见DP小问题 参考自 https://www.cnblogs.com/fefjay/p/7541760.html
    *
    * 动态规划算法是一种比较灵活的算法,针对具体的问题要具体分析,其宗旨就是要找出要解决问题的状态,
    * 然后逆向转化为求解子问题,最终回到已知的初始态,然后再顺序累计各个子问题的解从而得到最终问题的解。
    *
    * 关键点就是找到状态转移方程和初始边界条件,说白了就是要找到“递推公式”和初始值,然后计算时保存每一步中间结果,最后累加判断得到结果。
    */


    /**
    * 0.求数组最值
    * 求数组最值方法很多,这里使用动态规划的思想来尝试处理,以便更好地理解DP的思想。为了方便这里假设数组a[i]大小为n,要找n个数当中的最大值。
    *
    * 设dp[i]表示第0...i个数的最大值,dp[i-1]表示第0...i-1个数的最大值,所以求前i个数的最大值时,
    * 已经知道前i-1个是的最大值是dp[i-1],那么只需要比较dp[i-1]和第i个数谁大就知道了,即dp[i] = max(dp[-1], a[i])。
    */
    public int max(int[] a){
    int len = a.length;
    int[] dp = new int[len];
    dp[0] = a[0];
    for(int i=1; i<len; i++){
    dp[i] = (dp[i-1] > a[i]) ? dp[i-1] : a[i];
    }
    return dp[len-1];
    }

    /**
    * 1.求最大公共子序列长度
    * 给定一个字符串,想要删掉某些字符使得最后剩下的字符构成一个回文串(左右对称的字符串,如abcba),
    * 问最少删掉多少个字符可获得一个最长回文串。
    */

    /**
    * 本题求回文串最大长度就转化为求两个字符串的最长公共子序列(不一定连续)
    * 策略:字符串可以看做是字符序列,即字符数组。
    * 比如有序列A=a0,a1,a2...an;有序列B=b0,b1,b2,b3...bm;设A序列和B序列的公共子序列为C=c0,c1,c2,c3...ck。
    * 设L[][]为公共子序列C的长度,L[i][j]的i、j分别表示A、B序列的字符下标,L[i][j]含义是A序列a0、a1、a2...ai和B序列b0、b1、b2、
    * ...bj的公共子序列的长度。
    *
    * 1)如果A序列的i字符和B序列的j字符相等,那么就有ck=ai=bj,公共子序列C的长度L[i][j]=L[i-1][j-1]+1。
    * 2)如果A序列的i字符和B序列的j字符不相等,若ai != ck则C为a0...ai-1和b0...bj的最长子序列,若bj != ck则C为a0...ai和b0...bj-1的最长子序列,
    * 所以此时公共子序列长度为L[i][j] = max(L[i][j-1], L[i-1][j])。
    */

    public static int lcs(String s){
    if (s == null ) {
    return -1;
    }
    String rs = new StringBuilder(s).reverse().toString();
    char[] chars1 = s.toCharArray();
    char[] chars2 = rs.toCharArray();//获得反序的字符串
    int n = chars1.length;
    int[][] dp = new int[n+1][n+1];
    for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
    if(chars1[i] == chars2[j]){
    dp[i][j] = dp[i-1][j-1] + 1;
    }else {
    dp[i][j] = dp[i][j-1] > dp[i-1][j] ? dp[i][j-1] : dp[i-1][j];
    }
    }
    }
    return n - dp[n][n];
    }

    /**
    * 2.硬币凑钱问题
    * 只有面值为1元、3元、5元的硬币,数量足够。现在要凑够n元,求需要的最少硬币枚数。
    *
    * @param n 目标总钱数
    * @param coins 硬币数组【1,3,5】
    * @return 返回凑够n元需要的最少硬币数
    */
    public static int getLeastCoinAmount(int n, int[] coins){
    if (coins == null || n < 0) {
    return -1;
    }
    if (n == 0){
    return 0;
    }
    int[] dp = new int[n+1]; //dp[i]=j表示凑够i元最少需要j枚硬币。数组长度设为(n+1)保证可以访问dp[n]。
    dp[0] = 0;
    for (int i = 1; i <= n; i++) {
    dp[i] = Integer.MAX_VALUE;
    }

    int coinValue = 0;
    for (int i = 1; i <= n; i++) {//问题规模从小到大,直到达到目标面值
    for (int j = 0; j < coins.length; j++) {//遍历所有面值的硬币,j表示硬币面值的下标
    coinValue = coins[j];
    if (i - coinValue >= 0 && 1 + dp[i-coinValue] < dp[i]){ //当前方案的硬币数更少,则使用当前方案
    dp[i] = 1 + dp[i-coins[j]];
    }
    }

    }
    return dp[n];
    }

    /**
    * 3.最长非降子序列
    * 一个序列有N个数:A[1],A[2],…,A[N],求出最长非降子序列的长度。
    */

    /**
    *
    * 定义d(i)表示前i个数中"以A[i]结尾"的最长非降子序列的长度。
    * 对序列A1...Ai,找到的最长子序列长度d[i]分两种情况:
    * (1)包含最后一个数Ai,即d[i]=max{d[j]+1}(1<=j<i且Aj<=Ai),满足条件的Aj可能会有多个,选最大的d[j],如果Aj都大于Ai则d[j]=0;
    * (2)不含最后一个数,即d[i]=d[i-1]
    *
    * 综上:d[i] = max{d[i-1], max{d[j]+1}}
    */
    public static int longestIncreasingSubsequence(int[] a){
    if (a == null) {
    return -1;
    }
    if (a.length < 1){
    return 0;
    }
    int len = a.length;
    int[] dp = new int[len];//dp[i]系统自动初始化为0
    dp[0] = 1;
    for (int i = 1; i < len; i++) {//迭代,求序列0...len-1的最长子序列长度
    for (int j = 0; j < i; j++) {//寻找Ai之前的序列,看是否有不大于Ai的数字Aj
    if (a[j] <= a[i] && dp[i] < dp[j] + 1){//假设最长子序列包含最后一个数
    dp[i] = dp[j] + 1;
    }
    }
    //寻找Ai之前的序列如果Ai都小于Aj,此时dp[i]并没有被修改仍为初始值0。所以包含最后一个数的最长子序列就只有最后一个数自身,长1
    dp[i] = Math.max(1, dp[i]);
    //至此,已经求出了包含最后一个数的最长子序列的长度,和不包含最后一个数的最长子序列长度比较,取最大值为当前的最大长度
    dp[i] = Math.max(dp[i], dp[i-1]);
    }
    return dp[len-1];

    }

    /**
    * 4.经典01背包问题
    * 01背包问题:一个承重(或体积)为W的背包,可选物品有n个,第i个物品分别重w[i]和价值v[i],
    * 每个物品只能拿或不拿,求背包可放物品的最大价值。
    */

    /**
    *
    * 策略:这里的关键制约因素是背包只能承重w,而且每放入一个物品其承重就会减少。
    * 因此定义maxValue=V[i][j],数组表示目前可选物品有i个:0、1...i-1,背包承重(剩余的存放重量)为j的最大价值。
    * 现在假设已经知道了(i-1)个物品且剩余承重为j的最大价值V[i-1][j],那么考虑准备放入第i个物品的情况:
    * (1)如果第i个物品的重量大于背包的剩余承重w_i>j,显然放不下了,所以此时V[i][j]=V[i-1][j];
    * (2)w_i<=j,显然可以放下第i个物品,物品可以放得下,但是一定要装进来吗?如果装进的物品价值较低且较重,无疑会影响后续物品的装入情况。
    * 所以还要考虑要不要放进来的子问题,V[i][j]=max{vi+V[i-1][j-wi], V[i-1][j]}。
    *
    * @param W
    * @param n
    * @param w
    * @param v
    * @return
    */
    public static int knapsack(int W, int n, int[] w, int[] v){
    if ( W < 1 || n < 1 || w == null || v == null) {
    return -1;
    }
    int[][] dp = new int[n+1][W+1]; //可选的物品最多可以有n个,所以行数设为n+1。最大承重是W,所以列设为W+1。
    int index = 0;
    for (int i = 1; i <= n; i++) { //物品数肯定是从1开始。dp[0][j]系统初始化为0.
    index = i-1;
    for (int j = 1; j <= W ; j++) {//能装进的重量肯定是从1开始。dp[i][0]系统初始化为0.
    if (w[index] > j){
    dp[i][j] = dp[i-1][j];
    }else {
    dp[i][j] = Math.max(dp[i - 1][j - w[index]] + v[index], dp[i - 1][j]);
    }
    }

    }

    //找出是哪些物品放入背包
    boolean[] isTaken = new boolean[n];//标记是否放入背包里
    for (int i = n; i > 0 ; i--) {
    if (dp[i][W] != dp[i-1][W]){
    isTaken[i-1] = true;//装入
    W -= w[i-1];//装入之后背包的承重减少
    System.out.println(i-1);
    }
    }
    return dp[n][W];//返回n个物品承重为W时的最大价值
    }
    }

    + + +
    发布于

    2019-12-14

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git "a/algorithm/\350\264\252\345\277\203\347\256\227\346\263\225\350\247\243\346\236\220\347\244\272\344\276\213.html" "b/algorithm/\350\264\252\345\277\203\347\256\227\346\263\225\350\247\243\346\236\220\347\244\272\344\276\213.html" new file mode 100644 index 0000000000..0a1b54944b --- /dev/null +++ "b/algorithm/\350\264\252\345\277\203\347\256\227\346\263\225\350\247\243\346\236\220\347\244\272\344\276\213.html" @@ -0,0 +1,279 @@ + +贪心算法解析示例 - 辣椒の酱 + +
    贪心算法解析示例

    贪心算法解析示例

    定义

    贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解

    +

    贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

    + +

    思想

    贪心算法的基本思路是从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止

    +

    过程

      +
    • 建立数学模型来描述问题;
    • +
    • 把求解的问题分成若干个子问题;
    • +
    • 对每一子问题求解,得到子问题的局部最优解;
    • +
    • 把子问题的解局部最优解合成原来解问题的一个解。
    • +
    +

    示例

    假设山洞中有 n 种宝物,每种宝物有一定重量 w 和相应的价值 v,毛驴运载能力有限,
    只能运走 m 重量的宝物,一种宝物只能拿一样,宝物可以分割。那么怎么才能使毛驴运走宝
    物的价值最大呢?
    尝试贪心策略:
    (1)每次挑选价值最大的宝物装入背包,得到的结果是否最优?
    (2)每次挑选重量最小的宝物装入,能否得到最优解?
    (3)每次选取单位重量价值最大的宝物,能否使价值最高?
    思考一下,如果选价值最大的宝物,但重量非常大,也是不行的,因为运载能力是有限
    的,所以第 1 种策略舍弃;如果选重量最小的物品装入,那么其价值不一定高,所以不能在
    总重限制的情况下保证价值最大,第 2 种策略舍弃;而第 3 种是每次选取单位重量价值最大
    的宝物,也就是说每次选择性价比(价值/重量)最高的宝物,如果可以达到运载重量 m,

    +

    那么一定能得到价值最大。
    因此采用第 3 种贪心策略,每次从剩下的宝物中选择性价比最高的宝物。

    +

    算法设计:
    (1)数据结构及初始化。将 n 种宝物的重量和价值存储在结构体 three(包含重量、价
    值、性价比 3 个成员)中,同时求出每种宝物的性价比也存储在对应的结构体 three 中,将
    其按照性价比从高到低排序。采用 sum 来存储毛驴能够运走的最大价值,初始化为 0。
    (2)根据贪心策略,按照性价比从大到小选取宝物,直到达到毛驴的运载能力。每次选
    择性价比高的物品,判断是否小于 m(毛驴运载能力),如果小于 m,则放入,sum(已放入
    物品的价值)加上当前宝物的价值,m 减去放入宝物的重量;如果不小于 m,则取该宝物的
    一部分 m * p[i],m=0,程序结束。m 减少到 0,则 sum 得到最大值。

    +

    +

    完美图解
    假设现在有一批宝物,价值和重量如表 2-3 所示,毛驴运载能力 m=30,那么怎么装入
    最大价值的物品?
    宝物清单:

    +
    1
    2
    3
    宝物 i  1  2  3  4  5  6  7  8  9  10
    重量 w[i] 4 2 9 5 5 8 5 4 5 5
    价值 v[i] 3 8 18 6 8 20 5 6 7 15
    +

    (1)因为贪心策略是每次选择性价比(价值/重量)高的宝物,按照性价比降序排序:
    排序后宝物清单:

    +
    1
    2
    3
    4
    宝物 i  2  10  6  3  5  8  9  4  7  1
    重量 w[i] 2 5 8 9 5 4 5 5 5 4
    价值 v[i] 8 15 20 18 8 6 7 6 5 3
    性价比 p[i] 4 3 2.5 2 1.6 1.5 1.4 1.2 1 0.75
    + + +

    (2)按照贪心策略,每次选择性价比高的宝物放入:
    第 1 次选择宝物 2,剩余容量 30−2=28,目前装入最大价值为 8。
    第 2 次选择宝物 10,剩余容量 28−5=23,目前装入最大价值为 8+15=23。
    第 3 次选择宝物 6,剩余容量 23−8=15,目前装入最大价值为 23+20=43。
    第 4 次选择宝物 3,剩余容量 15−9=6,目前装入最大价值为 43+18=61。

    +

    第 5 次选择宝物 5,剩余容量 6−5=1,目前装入最大价值为 61+8=69。
    第 6 次选择宝物 8,发现上次处理完时剩余容量为 1,而 8 号宝物重量为 4,无法全部
    放入,那么可以采用部分装入的形式,装入 1 个重量单位,因为 8 号宝物的单位重量价值为
    1.5,因此放入价值 1×1.5=1.5,你也可以认为装入了 8 号宝物的 1/4,目前装入最大价值为
    69+1.5=70.5,剩余容量为 0。
    (3)构造最优解
    把这些放入的宝物序号组合在一起,就得到了最优解(2,10,6,3,5,8),其中最后
    一个宝物为部分装入(装了 8 号财宝的 1/4),能够装入宝物的最大价值为 70.5。

    +

    +

    +

    伪代码详解

    (1)数据结构定义
    根据算法设计中的数据结构,我们首先定义一个结构体 three:
    struct three{
    double w; //每种宝物的重量
    double v; //每种宝物的价值
    double p; //每种宝物的性价比(价值/重量)

    (2)性价比排序
    我们可以利用 C++中的排序函数 sort(见附录 B),对宝物的性价比从大到小(非递增)
    排序。要使用此函数需引入头文件:
    #include
    语法描述为:
    sort(begin, end)// 参数 begin 和 end 表示一个范围,分别为待排序数组的首地址和尾地址
    在本例中我们采用结构体形式存储,按结构体中的一个字段,即按性价比排序。如果不
    使用自定义比较函数,那么 sort 函数排序时不知道按哪一项的值排序,因此采用自定义比较
    函数的办法实现宝物性价比的降序排序:
    bool cmp(three a,three b)//比较函数按照宝物性价比降序排列
    {
    return a.p > b.p; //指明按照宝物性价比降序排列
    }
    sort(s, s+n, cmp); //前两个参数分别为待排序数组的首地址和尾地址
    //最后一个参数 compare 表示比较的类型
    (3)贪心算法求解
    在性价比排序的基础上,进行贪心算法运算。如果剩余容量比当前宝物的重量大,则可以放入,剩余容量减去当前宝物的重量,已放入物品的价值加上当前宝物的价值。如果剩余
    容量比当前宝物的重量小,表示不可以全部放入,可以切割下来一部分(正好是剩余容量),
    然后令剩余容量乘以当前物品的单位重量价值,已放入物品的价值加上该价值,即为能放入
    宝物的最大价值。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    for(int i = 0;i < n;i++)//按照排好的顺序,执行贪心策略
    {
    if( m > s[i].w )//如果宝物的重量小于毛驴剩下的运载能力,即剩余容量
    {
    m -= s[i].w;
    sum += s[i].v;
    }
    else //如果宝物的重量大于毛驴剩下的承载能力
    {
    sum += m 乘以 s[i].p; //进行宝物切割,切割一部分(m 重量),正好达到驴子承重
    break;
    }
    }
    + +

    实现代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int M=1000005;
    struct three{
    double w;//每个宝物的重量
    double v;//每个宝物的价值
    double p;//性价比
    }s[M];
    bool cmp(three a,three b)
    {
    return a.p>b.p;//根据宝物的单位价值从大到小排序
    }
    int main()
    {
    int n;//n 表示有 n 个宝物
    double m ;//m 表示毛驴的承载能力
    cout<<"请输入宝物数量 n 及毛驴的承载能力 m :"<<endl;
    cin>>n>>m;
    cout<<"请输入每个宝物的重量和价值,用空格分开: "<<endl;
    for(int i=0;i<n;i++)
    {
    cin>>s[i].w>>s[i].v;
    s[i].p=s[i].v/s[i].w;//每个宝物单位价值
    }
    sort(s,s+n,cmp);
    double sum=0.0;// sum 表示贪心记录运走宝物的价值之和
    for(int i=0;i<n;i++)//按照排好的顺序贪心
    {
    if( m>s[i].w )//如果宝物的重量小于毛驴剩下的承载能力
    {
    m-=s[i].w;
    sum+=s[i].v;
    }
    else//如果宝物的重量大于毛驴剩下的承载能力
    {
    sum+=m * s[i].p;//部分装入
    break;
    }
    }
    cout<<"装入宝物的最大价值 Maximum value="<<sum<<endl;
    return 0;
    }
    + +

    注意

    如果物品不能被分割,就不能采用贪心算法。

    +

    +

    leetcode12. 整数转罗马数字

    +

    生活中的经验:

    +

    在以前还使用现金购物的时候,如果我们不想让对方找钱,付款的时候我们会尽量选择面值大的纸币给对方,这样才会使得我们给对方的纸币张数最少,对方点钱的时候也最方便。

    +

    本题“整数转罗马数字”也有类似的思想:在表示一个较大整数的时候,“罗马数字”的设计者不会让你都用 11 加起来,我们总是希望写出来的“罗马数字”的个数越少越好,以方便表示,并且这种表示方式还应该是唯一的。

    +

    “罗马数字”与阿拉伯数字的对应关系表中,并且按照从大到小的顺序排列

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    罗马数字阿拉伯数字
    M1000
    CM900
    D500
    CD400
    C100
    XC90
    L50
    XL40
    X10
    IX9
    V5
    IV4
    I1
    +

    于是,“将整数转换为罗马数字”的过程,就是用上面这张表中右边的数字作为“加法因子”去分解一个整数,目的是“分解的整数个数”尽可能少,因此,对于这道问题,类似于用最少的纸币凑成一个整数,贪心算法的规则如下:

    +

    每一步都使用当前较大的罗马数字作为加法因子,最后得到罗马数字表示就是长度最少的。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class Solution {

    public String intToRoman(int num) {
    // 把阿拉伯数字与罗马数字可能出现的所有情况和对应关系,放在两个数组中
    // 并且按照阿拉伯数字的大小降序排列,这是贪心选择思想
    int[] nums = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    String[] romans = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};

    StringBuilder stringBuilder = new StringBuilder();
    int index = 0;
    while (index < 13) {
    // 特别注意:这里是等号
    while (num >= nums[index]) {
    // 注意:这里是等于号,表示尽量使用大的"面值"
    stringBuilder.append(romans[index]);
    num -= nums[index];
    }
    index++;
    }
    return stringBuilder.toString();
    }
    }

    作者:liweiwei1419
    链接:https://leetcode-cn.com/problems/integer-to-roman/solution/tan-xin-suan-fa-by-liweiwei1419/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    + +

    参考文章:
    参考链接1
    参考链接2

    +
    发布于

    2019-12-22

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    \ No newline at end of file diff --git a/anniversary.html b/anniversary.html new file mode 100644 index 0000000000..c6e70aeba4 --- /dev/null +++ b/anniversary.html @@ -0,0 +1,495 @@ + +
    + +
    + +

    + Since 2015.12.01 +
    + +

    +

    + About her→    +

    + + + + diff --git a/archives/2018/11/index.html b/archives/2018/11/index.html new file mode 100644 index 0000000000..9e8adf175d --- /dev/null +++ b/archives/2018/11/index.html @@ -0,0 +1,233 @@ + +归档: 2018/11 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2018/11/page/2/index.html b/archives/2018/11/page/2/index.html new file mode 100644 index 0000000000..042b62030a --- /dev/null +++ b/archives/2018/11/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2018/11 - 辣椒の酱 + +

    十一月 2018



    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2018/12/index.html b/archives/2018/12/index.html new file mode 100644 index 0000000000..f7eefa0bec --- /dev/null +++ b/archives/2018/12/index.html @@ -0,0 +1,233 @@ + +归档: 2018/12 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2018/index.html b/archives/2018/index.html new file mode 100644 index 0000000000..33685b6e67 --- /dev/null +++ b/archives/2018/index.html @@ -0,0 +1,233 @@ + +归档: 2018 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2018/page/2/index.html b/archives/2018/page/2/index.html new file mode 100644 index 0000000000..281dbcc9b1 --- /dev/null +++ b/archives/2018/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2018 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/01/index.html b/archives/2019/01/index.html new file mode 100644 index 0000000000..ee523584a1 --- /dev/null +++ b/archives/2019/01/index.html @@ -0,0 +1,233 @@ + +归档: 2019/1 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/02/index.html b/archives/2019/02/index.html new file mode 100644 index 0000000000..f059856d99 --- /dev/null +++ b/archives/2019/02/index.html @@ -0,0 +1,233 @@ + +归档: 2019/2 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/04/index.html b/archives/2019/04/index.html new file mode 100644 index 0000000000..0c8003bd62 --- /dev/null +++ b/archives/2019/04/index.html @@ -0,0 +1,233 @@ + +归档: 2019/4 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/05/index.html b/archives/2019/05/index.html new file mode 100644 index 0000000000..7b67b76553 --- /dev/null +++ b/archives/2019/05/index.html @@ -0,0 +1,233 @@ + +归档: 2019/5 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/06/index.html b/archives/2019/06/index.html new file mode 100644 index 0000000000..c9c0aad87a --- /dev/null +++ b/archives/2019/06/index.html @@ -0,0 +1,233 @@ + +归档: 2019/6 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/07/index.html b/archives/2019/07/index.html new file mode 100644 index 0000000000..130da4805e --- /dev/null +++ b/archives/2019/07/index.html @@ -0,0 +1,233 @@ + +归档: 2019/7 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/08/index.html b/archives/2019/08/index.html new file mode 100644 index 0000000000..fa52d02399 --- /dev/null +++ b/archives/2019/08/index.html @@ -0,0 +1,233 @@ + +归档: 2019/8 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/08/page/2/index.html b/archives/2019/08/page/2/index.html new file mode 100644 index 0000000000..fa544d6d78 --- /dev/null +++ b/archives/2019/08/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2019/8 - 辣椒の酱 + +

    八月 2019



    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/09/index.html b/archives/2019/09/index.html new file mode 100644 index 0000000000..fa7cc31df2 --- /dev/null +++ b/archives/2019/09/index.html @@ -0,0 +1,233 @@ + +归档: 2019/9 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html new file mode 100644 index 0000000000..5cbd14b4e9 --- /dev/null +++ b/archives/2019/10/index.html @@ -0,0 +1,233 @@ + +归档: 2019/10 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html new file mode 100644 index 0000000000..6750dbba7b --- /dev/null +++ b/archives/2019/11/index.html @@ -0,0 +1,233 @@ + +归档: 2019/11 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html new file mode 100644 index 0000000000..02f08778a5 --- /dev/null +++ b/archives/2019/12/index.html @@ -0,0 +1,233 @@ + +归档: 2019/12 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/12/page/2/index.html b/archives/2019/12/page/2/index.html new file mode 100644 index 0000000000..8efa7c4cf6 --- /dev/null +++ b/archives/2019/12/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2019/12 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/index.html b/archives/2019/index.html new file mode 100644 index 0000000000..748f49c06c --- /dev/null +++ b/archives/2019/index.html @@ -0,0 +1,233 @@ + +归档: 2019 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html new file mode 100644 index 0000000000..a140e6ad46 --- /dev/null +++ b/archives/2019/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2019 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/page/3/index.html b/archives/2019/page/3/index.html new file mode 100644 index 0000000000..9101b106b5 --- /dev/null +++ b/archives/2019/page/3/index.html @@ -0,0 +1,233 @@ + +归档: 2019 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/page/4/index.html b/archives/2019/page/4/index.html new file mode 100644 index 0000000000..f073e2e8ae --- /dev/null +++ b/archives/2019/page/4/index.html @@ -0,0 +1,233 @@ + +归档: 2019 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/page/5/index.html b/archives/2019/page/5/index.html new file mode 100644 index 0000000000..a04d8078ed --- /dev/null +++ b/archives/2019/page/5/index.html @@ -0,0 +1,233 @@ + +归档: 2019 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/page/6/index.html b/archives/2019/page/6/index.html new file mode 100644 index 0000000000..896f6821ec --- /dev/null +++ b/archives/2019/page/6/index.html @@ -0,0 +1,233 @@ + +归档: 2019 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2019/page/7/index.html b/archives/2019/page/7/index.html new file mode 100644 index 0000000000..405c0feb2f --- /dev/null +++ b/archives/2019/page/7/index.html @@ -0,0 +1,233 @@ + +归档: 2019 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html new file mode 100644 index 0000000000..8e02940472 --- /dev/null +++ b/archives/2020/01/index.html @@ -0,0 +1,233 @@ + +归档: 2020/1 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html new file mode 100644 index 0000000000..97f9285d70 --- /dev/null +++ b/archives/2020/02/index.html @@ -0,0 +1,233 @@ + +归档: 2020/2 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/02/page/2/index.html b/archives/2020/02/page/2/index.html new file mode 100644 index 0000000000..fd7b5a51f9 --- /dev/null +++ b/archives/2020/02/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2020/2 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html new file mode 100644 index 0000000000..ada06766c6 --- /dev/null +++ b/archives/2020/03/index.html @@ -0,0 +1,233 @@ + +归档: 2020/3 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/03/page/2/index.html b/archives/2020/03/page/2/index.html new file mode 100644 index 0000000000..8eabd20b16 --- /dev/null +++ b/archives/2020/03/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2020/3 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html new file mode 100644 index 0000000000..6c82584d97 --- /dev/null +++ b/archives/2020/07/index.html @@ -0,0 +1,233 @@ + +归档: 2020/7 - 辣椒の酱 + +

    七月 2020



    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/12/index.html b/archives/2020/12/index.html new file mode 100644 index 0000000000..f1c9a0acb4 --- /dev/null +++ b/archives/2020/12/index.html @@ -0,0 +1,233 @@ + +归档: 2020/12 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/index.html b/archives/2020/index.html new file mode 100644 index 0000000000..553b22f49f --- /dev/null +++ b/archives/2020/index.html @@ -0,0 +1,233 @@ + +归档: 2020 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html new file mode 100644 index 0000000000..9ee52c36a2 --- /dev/null +++ b/archives/2020/page/2/index.html @@ -0,0 +1,233 @@ + +归档: 2020 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/page/3/index.html b/archives/2020/page/3/index.html new file mode 100644 index 0000000000..125af726fc --- /dev/null +++ b/archives/2020/page/3/index.html @@ -0,0 +1,233 @@ + +归档: 2020 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2020/page/4/index.html b/archives/2020/page/4/index.html new file mode 100644 index 0000000000..9846ea684a --- /dev/null +++ b/archives/2020/page/4/index.html @@ -0,0 +1,233 @@ + +归档: 2020 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2023/04/index.html b/archives/2023/04/index.html new file mode 100644 index 0000000000..3ce3b2ce79 --- /dev/null +++ b/archives/2023/04/index.html @@ -0,0 +1,233 @@ + +归档: 2023/4 - 辣椒の酱 + +

    四月 2023



    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2023/index.html b/archives/2023/index.html new file mode 100644 index 0000000000..3f47a3bf62 --- /dev/null +++ b/archives/2023/index.html @@ -0,0 +1,233 @@ + +归档: 2023 - 辣椒の酱 + +

    2023



    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2024/12/index.html b/archives/2024/12/index.html new file mode 100644 index 0000000000..6aab7836a2 --- /dev/null +++ b/archives/2024/12/index.html @@ -0,0 +1,233 @@ + +归档: 2024/12 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2024/index.html b/archives/2024/index.html new file mode 100644 index 0000000000..c444e269c7 --- /dev/null +++ b/archives/2024/index.html @@ -0,0 +1,233 @@ + +归档: 2024 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2025/01/index.html b/archives/2025/01/index.html new file mode 100644 index 0000000000..704629e152 --- /dev/null +++ b/archives/2025/01/index.html @@ -0,0 +1,233 @@ + +归档: 2025/1 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/2025/index.html b/archives/2025/index.html new file mode 100644 index 0000000000..1f6d4abd68 --- /dev/null +++ b/archives/2025/index.html @@ -0,0 +1,233 @@ + +归档: 2025 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 0000000000..f4a2a344d7 --- /dev/null +++ b/archives/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    2023



    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/10/index.html b/archives/page/10/index.html new file mode 100644 index 0000000000..f88f6cb130 --- /dev/null +++ b/archives/page/10/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/11/index.html b/archives/page/11/index.html new file mode 100644 index 0000000000..6f658a4966 --- /dev/null +++ b/archives/page/11/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/12/index.html b/archives/page/12/index.html new file mode 100644 index 0000000000..f8859c261b --- /dev/null +++ b/archives/page/12/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/13/index.html b/archives/page/13/index.html new file mode 100644 index 0000000000..487b8dc0e9 --- /dev/null +++ b/archives/page/13/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    2018



    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 0000000000..bd6849cd8f --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/3/index.html b/archives/page/3/index.html new file mode 100644 index 0000000000..b60c93bcdf --- /dev/null +++ b/archives/page/3/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/4/index.html b/archives/page/4/index.html new file mode 100644 index 0000000000..20e46f4668 --- /dev/null +++ b/archives/page/4/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/5/index.html b/archives/page/5/index.html new file mode 100644 index 0000000000..ad27fe0347 --- /dev/null +++ b/archives/page/5/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/6/index.html b/archives/page/6/index.html new file mode 100644 index 0000000000..9ab0124901 --- /dev/null +++ b/archives/page/6/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/7/index.html b/archives/page/7/index.html new file mode 100644 index 0000000000..7981a6715c --- /dev/null +++ b/archives/page/7/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/8/index.html b/archives/page/8/index.html new file mode 100644 index 0000000000..0f55d28ce3 --- /dev/null +++ b/archives/page/8/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/archives/page/9/index.html b/archives/page/9/index.html new file mode 100644 index 0000000000..4a5b596ef2 --- /dev/null +++ b/archives/page/9/index.html @@ -0,0 +1,233 @@ + +归档 - 辣椒の酱 + +

    :D 一言句子获取中...

    \ No newline at end of file diff --git a/assets/algolia/algoliasearch.js b/assets/algolia/algoliasearch.js new file mode 100644 index 0000000000..7707138f15 --- /dev/null +++ b/assets/algolia/algoliasearch.js @@ -0,0 +1,7190 @@ +/*! algoliasearch 3.35.1 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +(function(f){var g;if(typeof window!=='undefined'){g=window}else if(typeof self!=='undefined'){g=self}g.ALGOLIA_MIGRATION_LAYER=f()})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;owindow.ALGOLIA_SUPPORTS_DOCWRITE = true\x3C/script>'); + + if (window.ALGOLIA_SUPPORTS_DOCWRITE === true) { + document.write('\x3Cscript src="' + v2ScriptUrl + '">\x3C/script>'); + scriptLoaded('document.write')(); + } else { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } + } catch (e) { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } +} + +function scriptLoaded(method) { + return function log() { + var message = 'AlgoliaSearch: loaded V2 script using ' + method; + + if (window.console && window.console.log) { + window.console.log(message); + } + }; +} + +},{"1":1}],4:[function(require,module,exports){ +'use strict'; + +/* eslint no-unused-vars: [2, {"vars": "local"}] */ + +module.exports = oldGlobals; + +// put old window.AlgoliaSearch.. into window. again so that +// users upgrading to V3 without changing their code, will be warned +function oldGlobals() { + var message = '-- AlgoliaSearch V2 => V3 error --\n' + + 'You are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\n' + + 'Please read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n' + + '-- /AlgoliaSearch V2 => V3 error --'; + + window.AlgoliaSearch = function() { + throw new Error(message); + }; + + window.AlgoliaSearchHelper = function() { + throw new Error(message); + }; + + window.AlgoliaExplainResults = function() { + throw new Error(message); + }; +} + +},{}],5:[function(require,module,exports){ +'use strict'; + +// This script will be browserified and prepended to the normal build +// directly in window, not wrapped in any module definition +// To avoid cases where we are loaded with /latest/ along with +migrationLayer("algoliasearch"); + +// Now onto the V2 related code: +// If the client is using /latest/$BUILDNAME.min.js, load V2 of the library +// +// Otherwise, setup a migration layer that will throw on old constructors like +// new AlgoliaSearch(). +// So that users upgrading from v2 to v3 will have a clear information +// message on what to do if they did not read the migration guide +function migrationLayer(buildName) { + var isUsingLatest = require(2); + var loadV2 = require(3); + var oldGlobals = require(4); + + if (isUsingLatest(buildName)) { + loadV2(buildName); + } else { + oldGlobals(); + } +} + +},{"2":2,"3":3,"4":4}]},{},[5])(5) +});(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.algoliasearch = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; + } + + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } +}; + + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + var useColors = this.useColors; + + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); + + if (!useColors) return; + + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') + + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ + +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); +} + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ + +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + return window.localStorage; + } catch (e) {} +} + +}).call(this,require(12)) +},{"12":12,"2":2}],2:[function(require,module,exports){ + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = require(9); + +/** + * The currently active debug mode names, and names to skip. + */ + +exports.names = []; +exports.skips = []; + +/** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + +exports.formatters = {}; + +/** + * Previous log timestamp. + */ + +var prevTime; + +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ + +function selectColor(namespace) { + var hash = 0, i; + + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return exports.colors[Math.abs(hash) % exports.colors.length]; +} + +/** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + +function createDebug(namespace) { + + function debug() { + // disabled? + if (!debug.enabled) return; + + var self = debug; + + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + args[0] = exports.coerce(args[0]); + + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); + } + + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); + + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); + + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); + } + + return debug; +} + +/** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + +function enable(namespaces) { + exports.save(namespaces); + + exports.names = []; + exports.skips = []; + + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} + +/** + * Disable debug output. + * + * @api public + */ + +function disable() { + exports.enable(''); +} + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } + } + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } + } + return false; +} + +/** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +},{"9":9}],3:[function(require,module,exports){ +(function (process,global){ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE + * @version 4.1.1 + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.ES6Promise = factory()); +}(this, (function () { 'use strict'; + +function objectOrFunction(x) { + var type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} + +function isFunction(x) { + return typeof x === 'function'; +} + +var _isArray = undefined; +if (Array.isArray) { + _isArray = Array.isArray; +} else { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; +} + +var isArray = _isArray; + +var len = 0; +var vertxNext = undefined; +var customSchedulerFn = undefined; + +var asap = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (customSchedulerFn) { + customSchedulerFn(flush); + } else { + scheduleFlush(); + } + } +}; + +function setScheduler(scheduleFn) { + customSchedulerFn = scheduleFn; +} + +function setAsap(asapFn) { + asap = asapFn; +} + +var browserWindow = typeof window !== 'undefined' ? window : undefined; +var browserGlobal = browserWindow || {}; +var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; +var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]'; + +// test for web worker but not in IE10 +var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; + +// node +function useNextTick() { + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // see https://github.com/cujojs/when/issues/410 for details + return function () { + return process.nextTick(flush); + }; +} + +// vertx +function useVertxTimer() { + if (typeof vertxNext !== 'undefined') { + return function () { + vertxNext(flush); + }; + } + + return useSetTimeout(); +} + +function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function () { + node.data = iterations = ++iterations % 2; + }; +} + +// web worker +function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + return channel.port2.postMessage(0); + }; +} + +function useSetTimeout() { + // Store setTimeout reference so es6-promise will be unaffected by + // other code modifying setTimeout (like sinon.useFakeTimers()) + var globalSetTimeout = setTimeout; + return function () { + return globalSetTimeout(flush, 1); + }; +} + +var queue = new Array(1000); +function flush() { + for (var i = 0; i < len; i += 2) { + var callback = queue[i]; + var arg = queue[i + 1]; + + callback(arg); + + queue[i] = undefined; + queue[i + 1] = undefined; + } + + len = 0; +} + +function attemptVertx() { + try { + var r = require; + var vertx = r('vertx'); + vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch (e) { + return useSetTimeout(); + } +} + +var scheduleFlush = undefined; +// Decide what async method to use to triggering processing of queued callbacks: +if (isNode) { + scheduleFlush = useNextTick(); +} else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); +} else if (isWorker) { + scheduleFlush = useMessageChannel(); +} else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertx(); +} else { + scheduleFlush = useSetTimeout(); +} + +function then(onFulfillment, onRejection) { + var _arguments = arguments; + + var parent = this; + + var child = new this.constructor(noop); + + if (child[PROMISE_ID] === undefined) { + makePromise(child); + } + + var _state = parent._state; + + if (_state) { + (function () { + var callback = _arguments[_state - 1]; + asap(function () { + return invokeCallback(_state, child, callback, parent._result); + }); + })(); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; +} + +/** + `Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` +*/ +function resolve$1(object) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop); + resolve(promise, object); + return promise; +} + +var PROMISE_ID = Math.random().toString(36).substring(16); + +function noop() {} + +var PENDING = void 0; +var FULFILLED = 1; +var REJECTED = 2; + +var GET_THEN_ERROR = new ErrorObject(); + +function selfFulfillment() { + return new TypeError("You cannot resolve a promise with itself"); +} + +function cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); +} + +function getThen(promise) { + try { + return promise.then; + } catch (error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } +} + +function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) { + try { + then$$1.call(value, fulfillmentHandler, rejectionHandler); + } catch (e) { + return e; + } +} + +function handleForeignThenable(promise, thenable, then$$1) { + asap(function (promise) { + var sealed = false; + var error = tryThen(then$$1, thenable, function (value) { + if (sealed) { + return; + } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function (reason) { + if (sealed) { + return; + } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); +} + +function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (thenable._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function (value) { + return resolve(promise, value); + }, function (reason) { + return reject(promise, reason); + }); + } +} + +function handleMaybeThenable(promise, maybeThenable, then$$1) { + if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) { + handleOwnThenable(promise, maybeThenable); + } else { + if (then$$1 === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + GET_THEN_ERROR.error = null; + } else if (then$$1 === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then$$1)) { + handleForeignThenable(promise, maybeThenable, then$$1); + } else { + fulfill(promise, maybeThenable); + } + } +} + +function resolve(promise, value) { + if (promise === value) { + reject(promise, selfFulfillment()); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value, getThen(value)); + } else { + fulfill(promise, value); + } +} + +function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); +} + +function fulfill(promise, value) { + if (promise._state !== PENDING) { + return; + } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length !== 0) { + asap(publish, promise); + } +} + +function reject(promise, reason) { + if (promise._state !== PENDING) { + return; + } + promise._state = REJECTED; + promise._result = reason; + + asap(publishRejection, promise); +} + +function subscribe(parent, child, onFulfillment, onRejection) { + var _subscribers = parent._subscribers; + var length = _subscribers.length; + + parent._onerror = null; + + _subscribers[length] = child; + _subscribers[length + FULFILLED] = onFulfillment; + _subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + asap(publish, parent); + } +} + +function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { + return; + } + + var child = undefined, + callback = undefined, + detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; +} + +function ErrorObject() { + this.error = null; +} + +var TRY_CATCH_ERROR = new ErrorObject(); + +function tryCatch(callback, detail) { + try { + return callback(detail); + } catch (e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } +} + +function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value = undefined, + error = undefined, + succeeded = undefined, + failed = undefined; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value.error = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, cannotReturnOwn()); + return; + } + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } +} + +function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value) { + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch (e) { + reject(promise, e); + } +} + +var id = 0; +function nextId() { + return id++; +} + +function makePromise(promise) { + promise[PROMISE_ID] = id++; + promise._state = undefined; + promise._result = undefined; + promise._subscribers = []; +} + +function Enumerator$1(Constructor, input) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop); + + if (!this.promise[PROMISE_ID]) { + makePromise(this.promise); + } + + if (isArray(input)) { + this.length = input.length; + this._remaining = input.length; + + this._result = new Array(this.length); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(input); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, validationError()); + } +} + +function validationError() { + return new Error('Array Methods must be provided an Array'); +} + +Enumerator$1.prototype._enumerate = function (input) { + for (var i = 0; this._state === PENDING && i < input.length; i++) { + this._eachEntry(input[i], i); + } +}; + +Enumerator$1.prototype._eachEntry = function (entry, i) { + var c = this._instanceConstructor; + var resolve$$1 = c.resolve; + + if (resolve$$1 === resolve$1) { + var _then = getThen(entry); + + if (_then === then && entry._state !== PENDING) { + this._settledAt(entry._state, i, entry._result); + } else if (typeof _then !== 'function') { + this._remaining--; + this._result[i] = entry; + } else if (c === Promise$2) { + var promise = new c(noop); + handleMaybeThenable(promise, entry, _then); + this._willSettleAt(promise, i); + } else { + this._willSettleAt(new c(function (resolve$$1) { + return resolve$$1(entry); + }), i); + } + } else { + this._willSettleAt(resolve$$1(entry), i); + } +}; + +Enumerator$1.prototype._settledAt = function (state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = value; + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } +}; + +Enumerator$1.prototype._willSettleAt = function (promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function (value) { + return enumerator._settledAt(FULFILLED, i, value); + }, function (reason) { + return enumerator._settledAt(REJECTED, i, reason); + }); +}; + +/** + `Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = resolve(2); + let promise3 = resolve(3); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = reject(new Error("2")); + let promise3 = reject(new Error("3")); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static +*/ +function all$1(entries) { + return new Enumerator$1(this, entries).promise; +} + +/** + `Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. +*/ +function race$1(entries) { + /*jshint validthis:true */ + var Constructor = this; + + if (!isArray(entries)) { + return new Constructor(function (_, reject) { + return reject(new TypeError('You must pass an array to race.')); + }); + } else { + return new Constructor(function (resolve, reject) { + var length = entries.length; + for (var i = 0; i < length; i++) { + Constructor.resolve(entries[i]).then(resolve, reject); + } + }); + } +} + +/** + `Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. +*/ +function reject$1(reason) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop); + reject(promise, reason); + return promise; +} + +function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); +} + +function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); +} + +/** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + let promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + let xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor +*/ +function Promise$2(resolver) { + this[PROMISE_ID] = nextId(); + this._result = this._state = undefined; + this._subscribers = []; + + if (noop !== resolver) { + typeof resolver !== 'function' && needsResolver(); + this instanceof Promise$2 ? initializePromise(this, resolver) : needsNew(); + } +} + +Promise$2.all = all$1; +Promise$2.race = race$1; +Promise$2.resolve = resolve$1; +Promise$2.reject = reject$1; +Promise$2._setScheduler = setScheduler; +Promise$2._setAsap = setAsap; +Promise$2._asap = asap; + +Promise$2.prototype = { + constructor: Promise$2, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + let result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + let author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: then, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function _catch(onRejection) { + return this.then(null, onRejection); + } +}; + +/*global self*/ +function polyfill$1() { + var local = undefined; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + var P = local.Promise; + + if (P) { + var promiseToString = null; + try { + promiseToString = Object.prototype.toString.call(P.resolve()); + } catch (e) { + // silently ignored + } + + if (promiseToString === '[object Promise]' && !P.cast) { + return; + } + } + + local.Promise = Promise$2; +} + +// Strange compat.. +Promise$2.polyfill = polyfill$1; +Promise$2.Promise = Promise$2; + +return Promise$2; + +}))); + + + +}).call(this,require(12),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"12":12}],4:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); + err.context = er; + throw err; + } + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + } else if (isObject(handler)) { + args = Array.prototype.slice.call(arguments, 1); + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.prototype.listenerCount = function(type) { + if (this._events) { + var evlistener = this._events[type]; + + if (isFunction(evlistener)) + return 1; + else if (evlistener) + return evlistener.length; + } + return 0; +}; + +EventEmitter.listenerCount = function(emitter, type) { + return emitter.listenerCount(type); +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],5:[function(require,module,exports){ + +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; + +module.exports = function forEach (obj, fn, ctx) { + if (toString.call(fn) !== '[object Function]') { + throw new TypeError('iterator must be a function'); + } + var l = obj.length; + if (l === +l) { + for (var i = 0; i < l; i++) { + fn.call(ctx, obj[i], i, obj); + } + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } + } + } +}; + + +},{}],6:[function(require,module,exports){ +(function (global){ +var win; + +if (typeof window !== "undefined") { + win = window; +} else if (typeof global !== "undefined") { + win = global; +} else if (typeof self !== "undefined"){ + win = self; +} else { + win = {}; +} + +module.exports = win; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],7:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],8:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + +},{}],9:[function(require,module,exports){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; + } + if (ms >= h) { + return Math.round(ms / h) + 'h'; + } + if (ms >= m) { + return Math.round(ms / m) + 'm'; + } + if (ms >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +},{}],10:[function(require,module,exports){ +'use strict'; + +// modified from https://github.com/es-shims/es5-shim +var has = Object.prototype.hasOwnProperty; +var toStr = Object.prototype.toString; +var slice = Array.prototype.slice; +var isArgs = require(11); +var isEnumerable = Object.prototype.propertyIsEnumerable; +var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); +var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); +var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' +]; +var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; +}; +var excludedKeys = { + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true +}; +var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; +}()); +var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } +}; + +var keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; +}; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + return (Object.keys(arguments) || '').length === 2; + }(1, 2)); + if (!keysWorksWithArguments) { + var originalKeys = Object.keys; + Object.keys = function keys(object) { + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } else { + return originalKeys(object); + } + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; +}; + +module.exports = keysShim; + +},{"11":11}],11:[function(require,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; +}; + +},{}],12:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],13:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +// If obj.hasOwnProperty has been overridden, then calling +// obj.hasOwnProperty(prop) will break. +// See: https://github.com/joyent/node/issues/1707 +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +module.exports = function(qs, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + var obj = {}; + + if (typeof qs !== 'string' || qs.length === 0) { + return obj; + } + + var regexp = /\+/g; + qs = qs.split(sep); + + var maxKeys = 1000; + if (options && typeof options.maxKeys === 'number') { + maxKeys = options.maxKeys; + } + + var len = qs.length; + // maxKeys <= 0 means that we should not limit keys count + if (maxKeys > 0 && len > maxKeys) { + len = maxKeys; + } + + for (var i = 0; i < len; ++i) { + var x = qs[i].replace(regexp, '%20'), + idx = x.indexOf(eq), + kstr, vstr, k, v; + + if (idx >= 0) { + kstr = x.substr(0, idx); + vstr = x.substr(idx + 1); + } else { + kstr = x; + vstr = ''; + } + + k = decodeURIComponent(kstr); + v = decodeURIComponent(vstr); + + if (!hasOwnProperty(obj, k)) { + obj[k] = v; + } else if (isArray(obj[k])) { + obj[k].push(v); + } else { + obj[k] = [obj[k], v]; + } + } + + return obj; +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +},{}],14:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; + + case 'boolean': + return v ? 'true' : 'false'; + + case 'number': + return isFinite(v) ? v : ''; + + default: + return ''; + } +}; + +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } + + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); + + } + + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + return res; +} + +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; +}; + +},{}],15:[function(require,module,exports){ +'use strict'; + +exports.decode = exports.parse = require(13); +exports.encode = exports.stringify = require(14); + +},{"13":13,"14":14}],16:[function(require,module,exports){ +module.exports = AlgoliaSearch; + +var Index = require(18); +var deprecate = require(28); +var deprecatedMessage = require(29); +var AlgoliaSearchCore = require(17); +var inherits = require(7); +var errors = require(30); + +function AlgoliaSearch() { + AlgoliaSearchCore.apply(this, arguments); +} + +inherits(AlgoliaSearch, AlgoliaSearchCore); + +/* + * Delete an index + * + * @param indexName the name of index to delete + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.deleteIndex = function(indexName, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexName), + hostType: 'write', + callback: callback + }); +}; + +/** + * Move an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy of + * srcIndexName (destination will be overriten if it already exist). + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.moveIndex = function(srcIndexName, dstIndexName, callback) { + var postObj = { + operation: 'move', destination: dstIndexName + }; + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Copy an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy + * of srcIndexName (destination will be overriten if it already exist). + * @param scope an array of scopes to copy: ['settings', 'synonyms', 'rules'] + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.copyIndex = function(srcIndexName, dstIndexName, scopeOrCallback, _callback) { + var postObj = { + operation: 'copy', + destination: dstIndexName + }; + var callback = _callback; + if (typeof scopeOrCallback === 'function') { + // oops, old behaviour of third argument being a function + callback = scopeOrCallback; + } else if (Array.isArray(scopeOrCallback) && scopeOrCallback.length > 0) { + postObj.scope = scopeOrCallback; + } else if (typeof scopeOrCallback !== 'undefined') { + throw new Error('the scope given to `copyIndex` was not an array with settings, synonyms or rules'); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Return last log entries. + * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry). + * @param length Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param type Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.getLogs = function(offset, length, callback) { + var clone = require(26); + var params = {}; + if (typeof offset === 'object') { + // getLogs(params) + params = clone(offset); + callback = length; + } else if (arguments.length === 0 || typeof offset === 'function') { + // getLogs([cb]) + callback = offset; + } else if (arguments.length === 1 || typeof length === 'function') { + // getLogs(1, [cb)] + callback = length; + params.offset = offset; + } else { + // getLogs(1, 2, [cb]) + params.offset = offset; + params.length = length; + } + + if (params.offset === undefined) params.offset = 0; + if (params.length === undefined) params.length = 10; + + return this._jsonRequest({ + method: 'GET', + url: '/1/logs?' + this._getSearchParams(params, ''), + hostType: 'read', + callback: callback + }); +}; + +/* + * List all existing indexes (paginated) + * + * @param page The page to retrieve, starting at 0. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with index list + */ +AlgoliaSearch.prototype.listIndexes = function(page, callback) { + var params = ''; + + if (page === undefined || typeof page === 'function') { + callback = page; + } else { + params = '?page=' + page; + } + + return this._jsonRequest({ + method: 'GET', + url: '/1/indexes' + params, + hostType: 'read', + callback: callback + }); +}; + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearch.prototype.initIndex = function(indexName) { + return new Index(this, indexName); +}; + +AlgoliaSearch.prototype.initAnalytics = function(opts) { + // the actual require must be inside the function, when put outside then you have a cyclic dependency + // not well resolved that ends up making the main "./index.js" (main module, the agloliasearch function) + // export an object instead of a function + // Other workarounds: + // - rewrite the lib in ES6, cyclic dependencies may be better supported + // - move initAnalytics to a property on the main module (algoliasearch.initAnalytics), + // same as places. + // The current API was made mostly to mimic the one made in PHP + var createAnalyticsClient = require(27); + return createAnalyticsClient(this.applicationID, this.apiKey, opts); +}; + +/* + * @deprecated use client.listApiKeys + */ +AlgoliaSearch.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('client.listUserKeys()', 'client.listApiKeys()')); + +/* + * List all existing api keys with their associated ACLs + * + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with api keys list + */ +AlgoliaSearch.prototype.listApiKeys = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys', + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.getApiKey + */ +AlgoliaSearch.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('client.getUserKeyACL()', 'client.getApiKey()')); + +/* + * Get an API key + * + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the right API key + */ +AlgoliaSearch.prototype.getApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys/' + key, + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.deleteApiKey + */ +AlgoliaSearch.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('client.deleteUserKey()', 'client.deleteApiKey()')); + +/* + * Delete an existing API key + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the date of deletion + */ +AlgoliaSearch.prototype.deleteApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/keys/' + key, + hostType: 'write', + callback: callback + }); +}; + +/** + * Restore a deleted API key + * + * @param {String} key - The key to restore + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the restored API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.restoreApiKey('APIKEY') + * @see {@link https://www.algolia.com/doc/rest-api/search/#restore-api-key|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.restoreApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'POST', + url: '/1/keys/' + key + '/restore', + hostType: 'write', + callback: callback + }); +}; + +/* + @deprecated see client.addApiKey + */ +AlgoliaSearch.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKey()', 'client.addApiKey()')); + +/* + * Add a new global API key + * + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the added API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.addApiKey(['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#AddKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.addApiKey = function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.indexes = params.indexes; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * @deprecated Please use client.addApiKey() + */ +AlgoliaSearch.prototype.addUserKeyWithValidity = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKeyWithValidity()', 'client.addApiKey()')); + +/** + * @deprecated Please use client.updateApiKey() + */ +AlgoliaSearch.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('client.updateUserKey()', 'client.updateApiKey()')); + +/** + * Update an existing API key + * @param {string} key - The key to update + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the modified API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.updateApiKey('APIKEY', ['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.updateApiKey = function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.indexes = params.indexes; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'PUT', + url: '/1/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Initialize a new batch of search queries + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.startQueriesBatch = deprecate(function startQueriesBatchDeprecated() { + this._batch = []; +}, deprecatedMessage('client.startQueriesBatch()', 'client.search()')); + +/** + * Add a search query in the batch + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.addQueryInBatch = deprecate(function addQueryInBatchDeprecated(indexName, query, args) { + this._batch.push({ + indexName: indexName, + query: query, + params: args + }); +}, deprecatedMessage('client.addQueryInBatch()', 'client.search()')); + +/** + * Launch the batch of queries using XMLHttpRequest. + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.sendQueriesBatch = deprecate(function sendQueriesBatchDeprecated(callback) { + return this.search(this._batch, callback); +}, deprecatedMessage('client.sendQueriesBatch()', 'client.search()')); + +/** + * Perform write operations across multiple indexes. + * + * To reduce the amount of time spent on network round trips, + * you can create, update, or delete several objects in one call, + * using the batch endpoint (all operations are done in the given order). + * + * Available actions: + * - addObject + * - updateObject + * - partialUpdateObject + * - partialUpdateObjectNoCreate + * - deleteObject + * + * https://www.algolia.com/doc/rest_api#Indexes + * @param {Object[]} operations An array of operations to perform + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.batch([{ + * action: 'addObject', + * indexName: 'clients', + * body: { + * name: 'Bill' + * } + * }, { + * action: 'udpateObject', + * indexName: 'fruits', + * body: { + * objectID: '29138', + * name: 'banana' + * } + * }], cb) + */ +AlgoliaSearch.prototype.batch = function(operations, callback) { + var isArray = require(8); + var usage = 'Usage: client.batch(operations[, callback])'; + + if (!isArray(operations)) { + throw new Error(usage); + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/batch', + body: { + requests: operations + }, + hostType: 'write', + callback: callback + }); +}; + +/** + * Assign or Move a userID to a cluster + * + * @param {string} data.userID The userID to assign to a new cluster + * @param {string} data.cluster The cluster to assign the user to + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.assignUserID({ cluster: 'c1-test', userID: 'some-user' }); + */ +AlgoliaSearch.prototype.assignUserID = function(data, callback) { + if (!data.userID || !data.cluster) { + throw new errors.AlgoliaSearchError('You have to provide both a userID and cluster', data); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping', + hostType: 'write', + body: {cluster: data.cluster}, + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Assign a array of userIDs to a cluster. + * + * @param {Array} data.userIDs The array of userIDs to assign to a new cluster + * @param {string} data.cluster The cluster to assign the user to + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.assignUserIDs({ cluster: 'c1-test', userIDs: ['some-user-1', 'some-user-2'] }); + */ +AlgoliaSearch.prototype.assignUserIDs = function(data, callback) { + if (!data.userIDs || !data.cluster) { + throw new errors.AlgoliaSearchError('You have to provide both an array of userIDs and cluster', data); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping/batch', + hostType: 'write', + body: { + cluster: data.cluster, + users: data.userIDs + }, + callback: callback + }); +}; + +/** + * Get the top userIDs + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getTopUserID(); + */ +AlgoliaSearch.prototype.getTopUserID = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/top', + hostType: 'read', + callback: callback + }); +}; + +/** + * Get userID + * + * @param {string} data.userID The userID to get info about + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.getUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/' + data.userID, + hostType: 'read', + callback: callback + }); +}; + +/** + * List all the clusters + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + */ +AlgoliaSearch.prototype.listClusters = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters', + hostType: 'read', + callback: callback + }); +}; + +/** + * List the userIDs + * + * (the callback is the second argument) + * + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + * client.listClusters({ page: 3, hitsPerPage: 30}); + */ +AlgoliaSearch.prototype.listUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping', + body: data, + hostType: 'read', + callback: callback + }); +}; + +/** + * Remove an userID + * + * @param {string} data.userID The userID to assign to a new cluster + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.removeUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.removeUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'DELETE', + url: '/1/clusters/mapping', + hostType: 'write', + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Search for userIDs + * + * @param {string} data.cluster The cluster to target + * @param {string} data.query The query to execute + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.searchUserIDs({ cluster: 'c1-test', query: 'some-user' }); + * client.searchUserIDs({ + * cluster: "c1-test", + * query: "some-user", + * page: 3, + * hitsPerPage: 2 + * }); + */ +AlgoliaSearch.prototype.searchUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping/search', + body: data, + hostType: 'read', + callback: callback + }); +}; + +/** + * Set strategy for personalization + * + * @param {Object} data + * @param {Object} data.eventsScoring Associate a score to an event + * @param {Object} data.eventsScoring. The name of the event + * @param {Number} data.eventsScoring..score The score to associate to + * @param {String} data.eventsScoring..type Either "click", "conversion" or "view" + * @param {Object} data.facetsScoring Associate a score to a facet + * @param {Object} data.facetsScoring. The name of the facet + * @param {Number} data.facetsScoring..score The score to associate to + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.setPersonalizationStrategy({ + * eventsScoring: { + * "Add to cart": { score: 50, type: "conversion" }, + * Purchase: { score: 100, type: "conversion" } + * }, + * facetsScoring: { + * brand: { score: 100 }, + * categories: { score: 10 } + * } + * }); + */ +AlgoliaSearch.prototype.setPersonalizationStrategy = function(data, callback) { + return this._jsonRequest({ + method: 'POST', + url: '/1/recommendation/personalization/strategy', + body: data, + hostType: 'write', + callback: callback + }); +}; + +/** + * Get strategy for personalization + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getPersonalizationStrategy(); + */ + +AlgoliaSearch.prototype.getPersonalizationStrategy = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/recommendation/personalization/strategy', + hostType: 'read', + callback: callback + }); +}; + +// environment specific methods +AlgoliaSearch.prototype.destroy = notImplemented; +AlgoliaSearch.prototype.enableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.disableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.useSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.disableSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.generateSecuredApiKey = notImplemented; +AlgoliaSearch.prototype.getSecuredApiKeyRemainingValidity = notImplemented; + +function notImplemented() { + var message = 'Not implemented in this environment.\n' + + 'If you feel this is a mistake, write to support@algolia.com'; + + throw new errors.AlgoliaSearchError(message); +} + +},{"17":17,"18":18,"26":26,"27":27,"28":28,"29":29,"30":30,"7":7,"8":8}],17:[function(require,module,exports){ +(function (process){ +module.exports = AlgoliaSearchCore; + +var errors = require(30); +var exitPromise = require(31); +var IndexCore = require(20); +var store = require(36); + +// We will always put the API KEY in the JSON body in case of too long API KEY, +// to avoid query string being too long and failing in various conditions (our server limit, browser limit, +// proxies limit) +var MAX_API_KEY_LENGTH = 500; +var RESET_APP_DATA_TIMER = + process.env.RESET_APP_DATA_TIMER && parseInt(process.env.RESET_APP_DATA_TIMER, 10) || + 60 * 2 * 1000; // after 2 minutes reset to first host + +/* + * Algolia Search library initialization + * https://www.algolia.com/ + * + * @param {string} applicationID - Your applicationID, found in your dashboard + * @param {string} apiKey - Your API key, found in your dashboard + * @param {Object} [opts] + * @param {number} [opts.timeout=2000] - The request timeout set in milliseconds, + * another request will be issued after this timeout + * @param {string} [opts.protocol='https:'] - The protocol used to query Algolia Search API. + * Set to 'http:' to force using http. + * @param {Object|Array} [opts.hosts={ + * read: [this.applicationID + '-dsn.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]), + * write: [this.applicationID + '.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]) - The hosts to use for Algolia Search API. + * If you provide them, you will less benefit from our HA implementation + */ +function AlgoliaSearchCore(applicationID, apiKey, opts) { + var debug = require(1)('algoliasearch'); + + var clone = require(26); + var isArray = require(8); + var map = require(32); + + var usage = 'Usage: algoliasearch(applicationID, apiKey, opts)'; + + if (opts._allowEmptyCredentials !== true && !applicationID) { + throw new errors.AlgoliaSearchError('Please provide an application ID. ' + usage); + } + + if (opts._allowEmptyCredentials !== true && !apiKey) { + throw new errors.AlgoliaSearchError('Please provide an API key. ' + usage); + } + + this.applicationID = applicationID; + this.apiKey = apiKey; + + this.hosts = { + read: [], + write: [] + }; + + opts = opts || {}; + + this._timeouts = opts.timeouts || { + connect: 1 * 1000, // 500ms connect is GPRS latency + read: 2 * 1000, + write: 30 * 1000 + }; + + // backward compat, if opts.timeout is passed, we use it to configure all timeouts like before + if (opts.timeout) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = opts.timeout; + } + + var protocol = opts.protocol || 'https:'; + // while we advocate for colon-at-the-end values: 'http:' for `opts.protocol` + // we also accept `http` and `https`. It's a common error. + if (!/:$/.test(protocol)) { + protocol = protocol + ':'; + } + + if (protocol !== 'http:' && protocol !== 'https:') { + throw new errors.AlgoliaSearchError('protocol must be `http:` or `https:` (was `' + opts.protocol + '`)'); + } + + this._checkAppIdData(); + + if (!opts.hosts) { + var defaultHosts = map(this._shuffleResult, function(hostNumber) { + return applicationID + '-' + hostNumber + '.algolianet.com'; + }); + + // no hosts given, compute defaults + var mainSuffix = (opts.dsn === false ? '' : '-dsn') + '.algolia.net'; + this.hosts.read = [this.applicationID + mainSuffix].concat(defaultHosts); + this.hosts.write = [this.applicationID + '.algolia.net'].concat(defaultHosts); + } else if (isArray(opts.hosts)) { + // when passing custom hosts, we need to have a different host index if the number + // of write/read hosts are different. + this.hosts.read = clone(opts.hosts); + this.hosts.write = clone(opts.hosts); + } else { + this.hosts.read = clone(opts.hosts.read); + this.hosts.write = clone(opts.hosts.write); + } + + // add protocol and lowercase hosts + this.hosts.read = map(this.hosts.read, prepareHost(protocol)); + this.hosts.write = map(this.hosts.write, prepareHost(protocol)); + + this.extraHeaders = {}; + + // In some situations you might want to warm the cache + this.cache = opts._cache || {}; + + this._ua = opts._ua; + this._useCache = opts._useCache === undefined || opts._cache ? true : opts._useCache; + this._useRequestCache = this._useCache && opts._useRequestCache; + this._useFallback = opts.useFallback === undefined ? true : opts.useFallback; + + this._setTimeout = opts._setTimeout; + + debug('init done, %j', this); +} + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearchCore.prototype.initIndex = function(indexName) { + return new IndexCore(this, indexName); +}; + +/** +* Add an extra field to the HTTP request +* +* @param name the header field name +* @param value the header field value +*/ +AlgoliaSearchCore.prototype.setExtraHeader = function(name, value) { + this.extraHeaders[name.toLowerCase()] = value; +}; + +/** +* Get the value of an extra HTTP header +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.getExtraHeader = function(name) { + return this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Remove an extra field from the HTTP request +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.unsetExtraHeader = function(name) { + delete this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Augment sent x-algolia-agent with more data, each agent part +* is automatically separated from the others by a semicolon; +* +* @param algoliaAgent the agent to add +*/ +AlgoliaSearchCore.prototype.addAlgoliaAgent = function(algoliaAgent) { + var algoliaAgentWithDelimiter = '; ' + algoliaAgent; + + if (this._ua.indexOf(algoliaAgentWithDelimiter) === -1) { + this._ua += algoliaAgentWithDelimiter; + } +}; + +/* + * Wrapper that try all hosts to maximize the quality of service + */ +AlgoliaSearchCore.prototype._jsonRequest = function(initialOpts) { + this._checkAppIdData(); + + var requestDebug = require(1)('algoliasearch:' + initialOpts.url); + + + var body; + var cacheID; + var additionalUA = initialOpts.additionalUA || ''; + var cache = initialOpts.cache; + var client = this; + var tries = 0; + var usingFallback = false; + var hasFallback = client._useFallback && client._request.fallback && initialOpts.fallback; + var headers; + + if ( + this.apiKey.length > MAX_API_KEY_LENGTH && + initialOpts.body !== undefined && + (initialOpts.body.params !== undefined || // index.search() + initialOpts.body.requests !== undefined) // client.search() + ) { + initialOpts.body.apiKey = this.apiKey; + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + withApiKey: false, + headers: initialOpts.headers + }); + } else { + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + } + + if (initialOpts.body !== undefined) { + body = safeJSONStringify(initialOpts.body); + } + + requestDebug('request start'); + var debugData = []; + + + function doRequest(requester, reqOpts) { + client._checkAppIdData(); + + var startTime = new Date(); + + if (client._useCache && !client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && !client._useRequestCache && body) { + cacheID += '_body_' + reqOpts.body; + } + + // handle cache existence + if (isCacheValidWithCurrentID(!client._useRequestCache, cache, cacheID)) { + requestDebug('serving response from cache'); + + var responseText = cache[cacheID]; + + // Cache response must match the type of the original one + return client._promise.resolve({ + body: JSON.parse(responseText), + responseText: responseText + }); + } + + // if we reached max tries + if (tries >= client.hosts[initialOpts.hostType].length) { + if (!hasFallback || usingFallback) { + requestDebug('could not get any response'); + // then stop + return client._promise.reject(new errors.AlgoliaSearchError( + 'Cannot connect to the AlgoliaSearch API.' + + ' Send an email to support@algolia.com to report and resolve the issue.' + + ' Application id was: ' + client.applicationID, {debugData: debugData} + )); + } + + requestDebug('switching to fallback'); + + // let's try the fallback starting from here + tries = 0; + + // method, url and body are fallback dependent + reqOpts.method = initialOpts.fallback.method; + reqOpts.url = initialOpts.fallback.url; + reqOpts.jsonBody = initialOpts.fallback.body; + if (reqOpts.jsonBody) { + reqOpts.body = safeJSONStringify(reqOpts.jsonBody); + } + // re-compute headers, they could be omitting the API KEY + headers = client._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + client._setHostIndexByType(0, initialOpts.hostType); + usingFallback = true; // the current request is now using fallback + return doRequest(client._request.fallback, reqOpts); + } + + var currentHost = client._getHostByType(initialOpts.hostType); + + var url = currentHost + reqOpts.url; + var options = { + body: reqOpts.body, + jsonBody: reqOpts.jsonBody, + method: reqOpts.method, + headers: headers, + timeouts: reqOpts.timeouts, + debug: requestDebug, + forceAuthHeaders: reqOpts.forceAuthHeaders + }; + + requestDebug('method: %s, url: %s, headers: %j, timeouts: %d', + options.method, url, options.headers, options.timeouts); + + if (requester === client._request.fallback) { + requestDebug('using fallback'); + } + + // `requester` is any of this._request or this._request.fallback + // thus it needs to be called using the client as context + return requester.call(client, url, options).then(success, tryFallback); + + function success(httpResponse) { + // compute the status of the response, + // + // When in browser mode, using XDR or JSONP, we have no statusCode available + // So we rely on our API response `status` property. + // But `waitTask` can set a `status` property which is not the statusCode (it's the task status) + // So we check if there's a `message` along `status` and it means it's an error + // + // That's the only case where we have a response.status that's not the http statusCode + var status = httpResponse && httpResponse.body && httpResponse.body.message && httpResponse.body.status || + + // this is important to check the request statusCode AFTER the body eventual + // statusCode because some implementations (jQuery XDomainRequest transport) may + // send statusCode 200 while we had an error + httpResponse.statusCode || + + // When in browser mode, using XDR or JSONP + // we default to success when no error (no response.status && response.message) + // If there was a JSON.parse() error then body is null and it fails + httpResponse && httpResponse.body && 200; + + requestDebug('received response: statusCode: %s, computed statusCode: %d, headers: %j', + httpResponse.statusCode, status, httpResponse.headers); + + var httpResponseOk = Math.floor(status / 100) === 2; + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime, + statusCode: status + }); + + if (httpResponseOk) { + if (client._useCache && !client._useRequestCache && cache) { + cache[cacheID] = httpResponse.responseText; + } + + return { + responseText: httpResponse.responseText, + body: httpResponse.body + }; + } + + var shouldRetry = Math.floor(status / 100) !== 4; + + if (shouldRetry) { + tries += 1; + return retryRequest(); + } + + requestDebug('unrecoverable error'); + + // no success and no retry => fail + var unrecoverableError = new errors.AlgoliaSearchError( + httpResponse.body && httpResponse.body.message, {debugData: debugData, statusCode: status} + ); + + return client._promise.reject(unrecoverableError); + } + + function tryFallback(err) { + // error cases: + // While not in fallback mode: + // - CORS not supported + // - network error + // While in fallback mode: + // - timeout + // - network error + // - badly formatted JSONP (script loaded, did not call our callback) + // In both cases: + // - uncaught exception occurs (TypeError) + requestDebug('error: %s, stack: %s', err.message, err.stack); + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime + }); + + if (!(err instanceof errors.AlgoliaSearchError)) { + err = new errors.Unknown(err && err.message, err); + } + + tries += 1; + + // stop the request implementation when: + if ( + // we did not generate this error, + // it comes from a throw in some other piece of code + err instanceof errors.Unknown || + + // server sent unparsable JSON + err instanceof errors.UnparsableJSON || + + // max tries and already using fallback or no fallback + tries >= client.hosts[initialOpts.hostType].length && + (usingFallback || !hasFallback)) { + // stop request implementation for this command + err.debugData = debugData; + return client._promise.reject(err); + } + + // When a timeout occurred, retry by raising timeout + if (err instanceof errors.RequestTimeout) { + return retryRequestWithHigherTimeout(); + } + + return retryRequest(); + } + + function retryRequest() { + requestDebug('retrying request'); + client._incrementHostIndex(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + + function retryRequestWithHigherTimeout() { + requestDebug('retrying request with higher timeout'); + client._incrementHostIndex(initialOpts.hostType); + client._incrementTimeoutMultipler(); + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + } + + function isCacheValidWithCurrentID( + useRequestCache, + currentCache, + currentCacheID + ) { + return ( + client._useCache && + useRequestCache && + currentCache && + currentCache[currentCacheID] !== undefined + ); + } + + + function interopCallbackReturn(request, callback) { + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + request.catch(function() { + // Release the cache on error + delete cache[cacheID]; + }); + } + + if (typeof initialOpts.callback === 'function') { + // either we have a callback + request.then(function okCb(content) { + exitPromise(function() { + initialOpts.callback(null, callback(content)); + }, client._setTimeout || setTimeout); + }, function nookCb(err) { + exitPromise(function() { + initialOpts.callback(err); + }, client._setTimeout || setTimeout); + }); + } else { + // either we are using promises + return request.then(callback); + } + } + + if (client._useCache && client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && client._useRequestCache && body) { + cacheID += '_body_' + body; + } + + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + requestDebug('serving request from cache'); + + var maybePromiseForCache = cache[cacheID]; + + // In case the cache is warmup with value that is not a promise + var promiseForCache = typeof maybePromiseForCache.then !== 'function' + ? client._promise.resolve({responseText: maybePromiseForCache}) + : maybePromiseForCache; + + return interopCallbackReturn(promiseForCache, function(content) { + // In case of the cache request, return the original value + return JSON.parse(content.responseText); + }); + } + + var request = doRequest( + client._request, { + url: initialOpts.url, + method: initialOpts.method, + body: body, + jsonBody: initialOpts.body, + timeouts: client._getTimeoutsForRequest(initialOpts.hostType), + forceAuthHeaders: initialOpts.forceAuthHeaders + } + ); + + if (client._useCache && client._useRequestCache && cache) { + cache[cacheID] = request; + } + + return interopCallbackReturn(request, function(content) { + // In case of the first request, return the JSON value + return content.body; + }); +}; + +/* +* Transform search param object in query string +* @param {object} args arguments to add to the current query string +* @param {string} params current query string +* @return {string} the final query string +*/ +AlgoliaSearchCore.prototype._getSearchParams = function(args, params) { + if (args === undefined || args === null) { + return params; + } + for (var key in args) { + if (key !== null && args[key] !== undefined && args.hasOwnProperty(key)) { + params += params === '' ? '' : '&'; + params += key + '=' + encodeURIComponent(Object.prototype.toString.call(args[key]) === '[object Array]' ? safeJSONStringify(args[key]) : args[key]); + } + } + return params; +}; + +/** + * Compute the headers for a request + * + * @param [string] options.additionalUA semi-colon separated string with other user agents to add + * @param [boolean=true] options.withApiKey Send the api key as a header + * @param [Object] options.headers Extra headers to send + */ +AlgoliaSearchCore.prototype._computeRequestHeaders = function(options) { + var forEach = require(5); + + var ua = options.additionalUA ? + this._ua + '; ' + options.additionalUA : + this._ua; + + var requestHeaders = { + 'x-algolia-agent': ua, + 'x-algolia-application-id': this.applicationID + }; + + // browser will inline headers in the url, node.js will use http headers + // but in some situations, the API KEY will be too long (big secured API keys) + // so if the request is a POST and the KEY is very long, we will be asked to not put + // it into headers but in the JSON body + if (options.withApiKey !== false) { + requestHeaders['x-algolia-api-key'] = this.apiKey; + } + + if (this.userToken) { + requestHeaders['x-algolia-usertoken'] = this.userToken; + } + + if (this.securityTags) { + requestHeaders['x-algolia-tagfilters'] = this.securityTags; + } + + forEach(this.extraHeaders, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + + if (options.headers) { + forEach(options.headers, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + } + + return requestHeaders; +}; + +/** + * Search through multiple indices at the same time + * @param {Object[]} queries An array of queries you want to run. + * @param {string} queries[].indexName The index name you want to target + * @param {string} [queries[].query] The query to issue on this index. Can also be passed into `params` + * @param {Object} queries[].params Any search param like hitsPerPage, .. + * @param {Function} callback Callback to be called + * @return {Promise|undefined} Returns a promise if no callback given + */ +AlgoliaSearchCore.prototype.search = function(queries, opts, callback) { + var isArray = require(8); + var map = require(32); + + var usage = 'Usage: client.search(arrayOfQueries[, callback])'; + + if (!isArray(queries)) { + throw new Error(usage); + } + + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var client = this; + + var postObj = { + requests: map(queries, function prepareRequest(query) { + var params = ''; + + // allow query.query + // so we are mimicing the index.search(query, params) method + // {indexName:, query:, params:} + if (query.query !== undefined) { + params += 'query=' + encodeURIComponent(query.query); + } + + return { + indexName: query.indexName, + params: client._getSearchParams(query.params, params) + }; + }) + }; + + var JSONPParams = map(postObj.requests, function prepareJSONPParams(request, requestId) { + return requestId + '=' + + encodeURIComponent( + '/1/indexes/' + encodeURIComponent(request.indexName) + '?' + + request.params + ); + }).join('&'); + + var url = '/1/indexes/*/queries'; + + if (opts.strategy !== undefined) { + postObj.strategy = opts.strategy; + } + + return this._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url, + body: postObj, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/*', + body: { + params: JSONPParams + } + }, + callback: callback + }); +}; + +/** +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* This is the top-level API for SFFV. +* +* @param {object[]} queries An array of queries to run. +* @param {string} queries[].indexName Index name, name of the index to search. +* @param {object} queries[].params Query parameters. +* @param {string} queries[].params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} queries[].params.facetQuery Query for the facet search +* @param {string} [queries[].params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +*/ +AlgoliaSearchCore.prototype.searchForFacetValues = function(queries) { + var isArray = require(8); + var map = require(32); + + var usage = 'Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])'; // eslint-disable-line max-len + + if (!isArray(queries)) { + throw new Error(usage); + } + + var client = this; + + return client._promise.all(map(queries, function performQuery(query) { + if ( + !query || + query.indexName === undefined || + query.params.facetName === undefined || + query.params.facetQuery === undefined + ) { + throw new Error(usage); + } + + var clone = require(26); + var omit = require(34); + + var indexName = query.indexName; + var params = query.params; + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = client._getSearchParams(filteredParams, ''); + + return client._jsonRequest({ + cache: client.cache, + method: 'POST', + url: + '/1/indexes/' + + encodeURIComponent(indexName) + + '/facets/' + + encodeURIComponent(facetName) + + '/query', + hostType: 'read', + body: {params: searchParameters} + }); + })); +}; + +/** + * Set the extra security tagFilters header + * @param {string|array} tags The list of tags defining the current security filters + */ +AlgoliaSearchCore.prototype.setSecurityTags = function(tags) { + if (Object.prototype.toString.call(tags) === '[object Array]') { + var strTags = []; + for (var i = 0; i < tags.length; ++i) { + if (Object.prototype.toString.call(tags[i]) === '[object Array]') { + var oredTags = []; + for (var j = 0; j < tags[i].length; ++j) { + oredTags.push(tags[i][j]); + } + strTags.push('(' + oredTags.join(',') + ')'); + } else { + strTags.push(tags[i]); + } + } + tags = strTags.join(','); + } + + this.securityTags = tags; +}; + +/** + * Set the extra user token header + * @param {string} userToken The token identifying a uniq user (used to apply rate limits) + */ +AlgoliaSearchCore.prototype.setUserToken = function(userToken) { + this.userToken = userToken; +}; + +/** + * Clear all queries in client's cache + * @return undefined + */ +AlgoliaSearchCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/** +* Set the number of milliseconds a request can take before automatically being terminated. +* @deprecated +* @param {Number} milliseconds +*/ +AlgoliaSearchCore.prototype.setRequestTimeout = function(milliseconds) { + if (milliseconds) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = milliseconds; + } +}; + +/** +* Set the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.setTimeouts = function(timeouts) { + this._timeouts = timeouts; +}; + +/** +* Get the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.getTimeouts = function() { + return this._timeouts; +}; + +AlgoliaSearchCore.prototype._getAppIdData = function() { + var data = store.get(this.applicationID); + if (data !== null) this._cacheAppIdData(data); + return data; +}; + +AlgoliaSearchCore.prototype._setAppIdData = function(data) { + data.lastChange = (new Date()).getTime(); + this._cacheAppIdData(data); + return store.set(this.applicationID, data); +}; + +AlgoliaSearchCore.prototype._checkAppIdData = function() { + var data = this._getAppIdData(); + var now = (new Date()).getTime(); + if (data === null || now - data.lastChange > RESET_APP_DATA_TIMER) { + return this._resetInitialAppIdData(data); + } + + return data; +}; + +AlgoliaSearchCore.prototype._resetInitialAppIdData = function(data) { + var newData = data || {}; + newData.hostIndexes = {read: 0, write: 0}; + newData.timeoutMultiplier = 1; + newData.shuffleResult = newData.shuffleResult || shuffle([1, 2, 3]); + return this._setAppIdData(newData); +}; + +AlgoliaSearchCore.prototype._cacheAppIdData = function(data) { + this._hostIndexes = data.hostIndexes; + this._timeoutMultiplier = data.timeoutMultiplier; + this._shuffleResult = data.shuffleResult; +}; + +AlgoliaSearchCore.prototype._partialAppIdDataUpdate = function(newData) { + var foreach = require(5); + var currentData = this._getAppIdData(); + foreach(newData, function(value, key) { + currentData[key] = value; + }); + + return this._setAppIdData(currentData); +}; + +AlgoliaSearchCore.prototype._getHostByType = function(hostType) { + return this.hosts[hostType][this._getHostIndexByType(hostType)]; +}; + +AlgoliaSearchCore.prototype._getTimeoutMultiplier = function() { + return this._timeoutMultiplier; +}; + +AlgoliaSearchCore.prototype._getHostIndexByType = function(hostType) { + return this._hostIndexes[hostType]; +}; + +AlgoliaSearchCore.prototype._setHostIndexByType = function(hostIndex, hostType) { + var clone = require(26); + var newHostIndexes = clone(this._hostIndexes); + newHostIndexes[hostType] = hostIndex; + this._partialAppIdDataUpdate({hostIndexes: newHostIndexes}); + return hostIndex; +}; + +AlgoliaSearchCore.prototype._incrementHostIndex = function(hostType) { + return this._setHostIndexByType( + (this._getHostIndexByType(hostType) + 1) % this.hosts[hostType].length, hostType + ); +}; + +AlgoliaSearchCore.prototype._incrementTimeoutMultipler = function() { + var timeoutMultiplier = Math.max(this._timeoutMultiplier + 1, 4); + return this._partialAppIdDataUpdate({timeoutMultiplier: timeoutMultiplier}); +}; + +AlgoliaSearchCore.prototype._getTimeoutsForRequest = function(hostType) { + return { + connect: this._timeouts.connect * this._timeoutMultiplier, + complete: this._timeouts[hostType] * this._timeoutMultiplier + }; +}; + +function prepareHost(protocol) { + return function prepare(host) { + return protocol + '//' + host.toLowerCase(); + }; +} + +// Prototype.js < 1.7, a widely used library, defines a weird +// Array.prototype.toJSON function that will fail to stringify our content +// appropriately +// refs: +// - https://groups.google.com/forum/#!topic/prototype-core/E-SAVvV_V9Q +// - https://github.com/sstephenson/prototype/commit/038a2985a70593c1a86c230fadbdfe2e4898a48c +// - http://stackoverflow.com/a/3148441/147079 +function safeJSONStringify(obj) { + /* eslint no-extend-native:0 */ + + if (Array.prototype.toJSON === undefined) { + return JSON.stringify(obj); + } + + var toJSON = Array.prototype.toJSON; + delete Array.prototype.toJSON; + var out = JSON.stringify(obj); + Array.prototype.toJSON = toJSON; + + return out; +} + +function shuffle(array) { + var currentIndex = array.length; + var temporaryValue; + var randomIndex; + + // While there remain elements to shuffle... + while (currentIndex !== 0) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; +} + +function removeCredentials(headers) { + var newHeaders = {}; + + for (var headerName in headers) { + if (Object.prototype.hasOwnProperty.call(headers, headerName)) { + var value; + + if (headerName === 'x-algolia-api-key' || headerName === 'x-algolia-application-id') { + value = '**hidden for security purposes**'; + } else { + value = headers[headerName]; + } + + newHeaders[headerName] = value; + } + } + + return newHeaders; +} + +}).call(this,require(12)) +},{"1":1,"12":12,"20":20,"26":26,"30":30,"31":31,"32":32,"34":34,"36":36,"5":5,"8":8}],18:[function(require,module,exports){ +var inherits = require(7); +var IndexCore = require(20); +var deprecate = require(28); +var deprecatedMessage = require(29); +var exitPromise = require(31); +var errors = require(30); + +var deprecateForwardToSlaves = deprecate( + function() {}, + deprecatedMessage('forwardToSlaves', 'forwardToReplicas') +); + +module.exports = Index; + +function Index() { + IndexCore.apply(this, arguments); +} + +inherits(Index, IndexCore); + +/* +* Add an object in this index +* +* @param content contains the javascript object to add inside the index +* @param objectID (optional) an objectID you want to attribute to this object +* (if the attribute already exist the old object will be overwrite) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.addObject = function(content, objectID, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof objectID === 'function') { + callback = objectID; + objectID = undefined; + } + + return this.as._jsonRequest({ + method: objectID !== undefined ? + 'PUT' : // update or create + 'POST', // create (API generates an objectID) + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + // create + (objectID !== undefined ? '/' + encodeURIComponent(objectID) : ''), // update or create + body: content, + hostType: 'write', + callback: callback + }); +}; + +/* +* Add several objects +* +* @param objects contains an array of objects to add +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.addObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.addObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'addObject', + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Update partially an object (only update attributes passed in argument) +* +* @param partialObject contains the javascript attributes to override, the +* object must contains an objectID attribute +* @param createIfNotExists (optional) if false, avoid an automatic creation of the object +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.partialUpdateObject = function(partialObject, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = undefined; + } + + var indexObj = this; + var url = '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial'; + if (createIfNotExists === false) { + url += '?createIfNotExists=false'; + } + + return this.as._jsonRequest({ + method: 'POST', + url: url, + body: partialObject, + hostType: 'write', + callback: callback + }); +}; + +/* +* Partially Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.partialUpdateObjects = function(objects, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = true; + } + + var isArray = require(8); + var usage = 'Usage: index.partialUpdateObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: createIfNotExists === true ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of object +* +* @param object contains the javascript object to save, the object must contains an objectID attribute +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObject = function(object, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID), + body: object, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.saveObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'updateObject', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete an object from the index +* +* @param objectID the unique identifier of object to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObject = function(objectID, callback) { + if (typeof objectID === 'function' || typeof objectID !== 'string' && typeof objectID !== 'number') { + var err = new errors.AlgoliaSearchError( + objectID && typeof objectID !== 'function' + ? 'ObjectID must be a string' + : 'Cannot delete an object without an objectID' + ); + callback = objectID; + if (typeof callback === 'function') { + return callback(err); + } + + return this.as._promise.reject(err); + } + + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID), + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete several objects from an index +* +* @param objectIDs contains an array of objectID to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObjects = function(objectIDs, callback) { + var isArray = require(8); + var map = require(32); + + var usage = 'Usage: index.deleteObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: map(objectIDs, function prepareRequest(objectID) { + return { + action: 'deleteObject', + objectID: objectID, + body: { + objectID: objectID + } + }; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete all objects matching a query +* +* @param query the query string +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +* @deprecated see index.deleteBy +*/ +Index.prototype.deleteByQuery = deprecate(function(query, params, callback) { + var clone = require(26); + var map = require(32); + + var indexObj = this; + var client = indexObj.as; + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = {}; + } else { + params = clone(params); + } + + params.attributesToRetrieve = 'objectID'; + params.hitsPerPage = 1000; + params.distinct = false; + + // when deleting, we should never use cache to get the + // search results + this.clearCache(); + + // there's a problem in how we use the promise chain, + // see how waitTask is done + var promise = this + .search(query, params) + .then(stopOrDelete); + + function stopOrDelete(searchContent) { + // stop here + if (searchContent.nbHits === 0) { + // return indexObj.as._request.resolve(); + return searchContent; + } + + // continue and do a recursive call + var objectIDs = map(searchContent.hits, function getObjectID(object) { + return object.objectID; + }); + + return indexObj + .deleteObjects(objectIDs) + .then(waitTask) + .then(doDeleteByQuery); + } + + function waitTask(deleteObjectsContent) { + return indexObj.waitTask(deleteObjectsContent.taskID); + } + + function doDeleteByQuery() { + return indexObj.deleteByQuery(query, params); + } + + if (!callback) { + return promise; + } + + promise.then(success, failure); + + function success() { + exitPromise(function exit() { + callback(null); + }, client._setTimeout || setTimeout); + } + + function failure(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}, deprecatedMessage('index.deleteByQuery()', 'index.deleteBy()')); + +/** +* Delete all objects matching a query +* +* the query parameters that can be used are: +* - filters (numeric, facet, tag) +* - geo +* +* you can not send an empty query or filters +* +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +*/ +Index.prototype.deleteBy = function(params, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/deleteByQuery', + body: {params: indexObj.as._getSearchParams(params, '')}, + hostType: 'write', + callback: callback + }); +}; + +/* +* Browse all content from an index using events. Basically this will do +* .browse() -> .browseFrom -> .browseFrom -> .. until all the results are returned +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @return {EventEmitter} +* @example +* var browser = index.browseAll('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }); +* +* browser.on('result', function resultCallback(content) { +* console.log(content.hits); +* }); +* +* // if any error occurs, you get it +* browser.on('error', function(err) { +* throw err; +* }); +* +* // when you have browsed the whole index, you get this event +* browser.on('end', function() { +* console.log('finished'); +* }); +* +* // at any point if you want to stop the browsing process, you can stop it manually +* // otherwise it will go on and on +* browser.stop(); +* +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +Index.prototype.browseAll = function(query, queryParameters) { + if (typeof query === 'object') { + queryParameters = query; + query = undefined; + } + + var merge = require(33); + + var IndexBrowser = require(19); + + var browser = new IndexBrowser(); + var client = this.as; + var index = this; + var params = client._getSearchParams( + merge({}, queryParameters || {}, { + query: query + }), '' + ); + + // start browsing + browseLoop(); + + function browseLoop(cursor) { + if (browser._stopped) { + return; + } + + var body; + + if (cursor !== undefined) { + body = { + cursor: cursor + }; + } else { + body = { + params: params + }; + } + + client._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(index.indexName) + '/browse', + hostType: 'read', + body: body, + callback: browseCallback + }); + } + + function browseCallback(err, content) { + if (browser._stopped) { + return; + } + + if (err) { + browser._error(err); + return; + } + + browser._result(content); + + // no cursor means we are finished browsing + if (content.cursor === undefined) { + browser._end(); + return; + } + + browseLoop(content.cursor); + } + + return browser; +}; + +/* +* Get a Typeahead.js adapter +* @param searchParams contains an object with query parameters (see search for details) +*/ +Index.prototype.ttAdapter = deprecate(function(params) { + var self = this; + return function ttAdapter(query, syncCb, asyncCb) { + var cb; + + if (typeof asyncCb === 'function') { + // typeahead 0.11 + cb = asyncCb; + } else { + // pre typeahead 0.11 + cb = syncCb; + } + + self.search(query, params, function searchDone(err, content) { + if (err) { + cb(err); + return; + } + + cb(content.hits); + }); + }; +}, +'ttAdapter is not necessary anymore and will be removed in the next version,\n' + +'have a look at autocomplete.js (https://github.com/algolia/autocomplete.js)'); + +/* +* Wait the publication of a task on the server. +* All server task are asynchronous and you can check with this method that the task is published. +* +* @param taskID the id of the task returned by server +* @param callback the result callback with with two arguments: +* error: null or Error('message') +* content: the server answer that contains the list of results +*/ +Index.prototype.waitTask = function(taskID, callback) { + // wait minimum 100ms before retrying + var baseDelay = 100; + // wait maximum 5s before retrying + var maxDelay = 5000; + var loop = 0; + + // waitTask() must be handled differently from other methods, + // it's a recursive method using a timeout + var indexObj = this; + var client = indexObj.as; + + var promise = retryLoop(); + + function retryLoop() { + return client._jsonRequest({ + method: 'GET', + hostType: 'read', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/task/' + taskID + }).then(function success(content) { + loop++; + var delay = baseDelay * loop * loop; + if (delay > maxDelay) { + delay = maxDelay; + } + + if (content.status !== 'published') { + return client._promise.delay(delay).then(retryLoop); + } + + return content; + }); + } + + if (!callback) { + return promise; + } + + promise.then(successCb, failureCb); + + function successCb(content) { + exitPromise(function exit() { + callback(null, content); + }, client._setTimeout || setTimeout); + } + + function failureCb(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}; + +/* +* This function deletes the index content. Settings and index specific API keys are kept untouched. +* +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occurred +*/ +Index.prototype.clearIndex = function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear', + hostType: 'write', + callback: callback + }); +}; + +/* +* Get settings of this index +* +* @param opts an object of options to add +* @param opts.advanced get more settings like nbShards (useful for Enterprise) +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occurred +*/ +Index.prototype.getSettings = function(opts, callback) { + if (arguments.length === 1 && typeof opts === 'function') { + callback = opts; + opts = {}; + } + opts = opts || {}; + + var indexName = encodeURIComponent(this.indexName); + return this.as._jsonRequest({ + method: 'GET', + url: + '/1/indexes/' + + indexName + + '/settings?getVersion=2' + + (opts.advanced ? '&advanced=' + opts.advanced : ''), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.searchSynonyms = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/search', + body: params, + hostType: 'read', + callback: callback + }); +}; + +function exportData(method, _hitsPerPage, callback) { + function search(page, _previous) { + var options = { + page: page || 0, + hitsPerPage: _hitsPerPage || 100 + }; + var previous = _previous || []; + + return method(options).then(function(result) { + var hits = result.hits; + var nbHits = result.nbHits; + var current = hits.map(function(s) { + delete s._highlightResult; + return s; + }); + var synonyms = previous.concat(current); + if (synonyms.length < nbHits) { + return search(options.page + 1, synonyms); + } + return synonyms; + }); + } + return search().then(function(data) { + if (typeof callback === 'function') { + callback(data); + return undefined; + } + return data; + }); +} + +/** + * Retrieve all the synonyms in an index + * @param [number=100] hitsPerPage The amount of synonyms to retrieve per batch + * @param [function] callback will be called after all synonyms are retrieved + */ +Index.prototype.exportSynonyms = function(hitsPerPage, callback) { + return exportData(this.searchSynonyms.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveSynonym = function(synonym, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(synonym.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: synonym, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getSynonym = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteSynonym = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearSynonyms = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchSynonyms = function(synonyms, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&replaceExistingSynonyms=' + (opts.replaceExistingSynonyms ? 'true' : 'false'), + hostType: 'write', + body: synonyms, + callback: callback + }); +}; + +Index.prototype.searchRules = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/search', + body: params, + hostType: 'read', + callback: callback + }); +}; +/** + * Retrieve all the query rules in an index + * @param [number=100] hitsPerPage The amount of query rules to retrieve per batch + * @param [function] callback will be called after all query rules are retrieved + * error: null or Error('message') + */ +Index.prototype.exportRules = function(hitsPerPage, callback) { + return exportData(this.searchRules.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveRule = function(rule, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (!rule.objectID) { + throw new errors.AlgoliaSearchError('Missing or empty objectID field for rule'); + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(rule.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: rule, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getRule = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteRule = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearRules = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchRules = function(rules, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&clearExistingRules=' + (opts.clearExistingRules === true ? 'true' : 'false'), + hostType: 'write', + body: rules, + callback: callback + }); +}; + +Index.prototype.exists = function(callback) { + var result = this.getSettings().then(function() { + return true; + }).catch(function(err) { + if (err instanceof errors.AlgoliaSearchError && err.statusCode === 404) { + return false; + } + + throw err; + }); + + if (typeof callback !== 'function') { + return result; + } + + result.then(function(res) { + callback(null, res); + }).catch(function(err) { + callback(err); + }); +}; + +Index.prototype.findObject = function(findCallback, requestOptions, callback) { + requestOptions = requestOptions === undefined ? {} : requestOptions; + var paginate = requestOptions.paginate !== undefined ? requestOptions.paginate : true; + var query = requestOptions.query !== undefined ? requestOptions.query : ''; + + var that = this; + var page = 0; + + var paginateLoop = function() { + requestOptions.page = page; + + return that.search(query, requestOptions).then(function(result) { + var hits = result.hits; + + for (var position = 0; position < hits.length; position++) { + var hit = hits[position]; + if (findCallback(hit)) { + return { + object: hit, + position: position, + page: page + }; + } + } + + page += 1; + + // paginate if option was set and has next page + if (!paginate || page >= result.nbPages) { + throw new errors.ObjectNotFound('Object not found'); + } + + return paginateLoop(); + }); + }; + + var promise = paginateLoop(page); + + if (callback === undefined) { + return promise; + } + + promise + .then(function(res) { + callback(null, res); + }) + .catch(function(err) { + callback(err); + }); +}; + +Index.prototype.getObjectPosition = function(result, objectID) { + var hits = result.hits; + + for (var position = 0; position < hits.length; position++) { + if (hits[position].objectID === objectID) { + return position; + } + } + + return -1; +}; + +/* +* Set settings for this index +* +* @param settings the settings object that can contains : +* - minWordSizefor1Typo: (integer) the minimum number of characters to accept one typo (default = 3). +* - minWordSizefor2Typos: (integer) the minimum number of characters to accept two typos (default = 7). +* - hitsPerPage: (integer) the number of hits per page (default = 10). +* - attributesToRetrieve: (array of strings) default list of attributes to retrieve in objects. +* If set to null, all attributes are retrieved. +* - attributesToHighlight: (array of strings) default list of attributes to highlight. +* If set to null, all indexed attributes are highlighted. +* - attributesToSnippet**: (array of strings) default list of attributes to snippet alongside the number +* of words to return (syntax is attributeName:nbWords). +* By default no snippet is computed. If set to null, no snippet is computed. +* - attributesToIndex: (array of strings) the list of fields you want to index. +* If set to null, all textual and numerical attributes of your objects are indexed, +* but you should update it to get optimal results. +* This parameter has two important uses: +* - Limit the attributes to index: For example if you store a binary image in base64, +* you want to store it and be able to +* retrieve it but you don't want to search in the base64 string. +* - Control part of the ranking*: (see the ranking parameter for full explanation) +* Matches in attributes at the beginning of +* the list will be considered more important than matches in attributes further down the list. +* In one attribute, matching text at the beginning of the attribute will be +* considered more important than text after, you can disable +* this behavior if you add your attribute inside `unordered(AttributeName)`, +* for example attributesToIndex: ["title", "unordered(text)"]. +* - attributesForFaceting: (array of strings) The list of fields you want to use for faceting. +* All strings in the attribute selected for faceting are extracted and added as a facet. +* If set to null, no attribute is used for faceting. +* - attributeForDistinct: (string) The attribute name used for the Distinct feature. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in query with the distinct=1 parameter, all hits containing a duplicate +* value for this attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best one is kept and others are removed. +* - ranking: (array of strings) controls the way results are sorted. +* We have six available criteria: +* - typo: sort according to number of typos, +* - geo: sort according to decreassing distance when performing a geo-location based search, +* - proximity: sort according to the proximity of query words in hits, +* - attribute: sort according to the order of attributes defined by attributesToIndex, +* - exact: +* - if the user query contains one word: sort objects having an attribute +* that is exactly the query word before others. +* For example if you search for the "V" TV show, you want to find it +* with the "V" query and avoid to have all popular TV +* show starting by the v letter before it. +* - if the user query contains multiple words: sort according to the +* number of words that matched exactly (and not as a prefix). +* - custom: sort according to a user defined formula set in **customRanking** attribute. +* The standard order is ["typo", "geo", "proximity", "attribute", "exact", "custom"] +* - customRanking: (array of strings) lets you specify part of the ranking. +* The syntax of this condition is an array of strings containing attributes +* prefixed by asc (ascending order) or desc (descending order) operator. +* For example `"customRanking" => ["desc(population)", "asc(name)"]` +* - queryType: Select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - highlightPreTag: (string) Specify the string that is inserted before +* the highlighted parts in the query result (default to ""). +* - highlightPostTag: (string) Specify the string that is inserted after +* the highlighted parts in the query result (default to ""). +* - optionalWords: (array of strings) Specify a list of words that should +* be considered as optional when found in the query. +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the server answer or the error message if a failure occurred +*/ +Index.prototype.setSettings = function(settings, opts, callback) { + if (arguments.length === 1 || typeof opts === 'function') { + callback = opts; + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings?forwardToReplicas=' + + forwardToReplicas, + hostType: 'write', + body: settings, + callback: callback + }); +}; + +/* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('index.listUserKeys()', 'client.listApiKeys()')); + +/* +* List all existing API keys to this index +* +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with API keys belonging to the index +* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listApiKeys = deprecate(function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys', + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.listApiKeys()', 'client.listApiKeys()')); + +/* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('index.getUserKeyACL()', 'client.getApiKey()')); + + +/* +* Get an API key from this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the right API key +* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.getApiKey()', 'client.getApiKey()')); + +/* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('index.deleteUserKey()', 'client.deleteApiKey()')); + +/* +* Delete an existing API key associated to this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the deletion date +* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.deleteApiKey()', 'client.deleteApiKey()')); + +/* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKey()', 'client.addApiKey()')); + +/* +* Add a new API key to this index +* +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the added API key +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.addUserKey(['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#AddIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addApiKey = deprecate(function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.addApiKey()', 'client.addApiKey()')); + +/** +* @deprecated use client.addApiKey() +*/ +Index.prototype.addUserKeyWithValidity = deprecate(function deprecatedAddUserKeyWithValidity(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKeyWithValidity()', 'client.addApiKey()')); + +/* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('index.updateUserKey()', 'client.updateApiKey()')); + +/** +* Update an existing API key of this index +* @param {string} key - The key to update +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with user keys list +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.updateApiKey('APIKEY', ['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateApiKey = deprecate(function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.updateApiKey()', 'client.updateApiKey()')); + +},{"19":19,"20":20,"26":26,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"7":7,"8":8}],19:[function(require,module,exports){ +'use strict'; + +// This is the object returned by the `index.browseAll()` method + +module.exports = IndexBrowser; + +var inherits = require(7); +var EventEmitter = require(4).EventEmitter; + +function IndexBrowser() { +} + +inherits(IndexBrowser, EventEmitter); + +IndexBrowser.prototype.stop = function() { + this._stopped = true; + this._clean(); +}; + +IndexBrowser.prototype._end = function() { + this.emit('end'); + this._clean(); +}; + +IndexBrowser.prototype._error = function(err) { + this.emit('error', err); + this._clean(); +}; + +IndexBrowser.prototype._result = function(content) { + this.emit('result', content); +}; + +IndexBrowser.prototype._clean = function() { + this.removeAllListeners('stop'); + this.removeAllListeners('end'); + this.removeAllListeners('error'); + this.removeAllListeners('result'); +}; + +},{"4":4,"7":7}],20:[function(require,module,exports){ +var buildSearchMethod = require(25); +var deprecate = require(28); +var deprecatedMessage = require(29); + +module.exports = IndexCore; + +/* +* Index class constructor. +* You should not use this method directly but use initIndex() function +*/ +function IndexCore(algoliasearch, indexName) { + this.indexName = indexName; + this.as = algoliasearch; + this.typeAheadArgs = null; + this.typeAheadValueOption = null; + + // make sure every index instance has it's own cache + this.cache = {}; +} + +/* +* Clear all queries in cache +*/ +IndexCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/* +* Search inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the full text query +* @param {object} [args] (optional) if set, contains an object with query parameters: +* - page: (integer) Pagination parameter used to select the page to retrieve. +* Page is zero-based and defaults to 0. Thus, +* to retrieve the 10th page you need to set page=9 +* - hitsPerPage: (integer) Pagination parameter used to select the number of hits per page. Defaults to 20. +* - attributesToRetrieve: a string that contains the list of object attributes +* you want to retrieve (let you minimize the answer size). +* Attributes are separated with a comma (for example "name,address"). +* You can also use an array (for example ["name","address"]). +* By default, all attributes are retrieved. You can also use '*' to retrieve all +* values when an attributesToRetrieve setting is specified for your index. +* - attributesToHighlight: a string that contains the list of attributes you +* want to highlight according to the query. +* Attributes are separated by a comma. You can also use an array (for example ["name","address"]). +* If an attribute has no match for the query, the raw value is returned. +* By default all indexed text attributes are highlighted. +* You can use `*` if you want to highlight all textual attributes. +* Numerical attributes are not highlighted. +* A matchLevel is returned for each highlighted attribute and can contain: +* - full: if all the query terms were found in the attribute, +* - partial: if only some of the query terms were found, +* - none: if none of the query terms were found. +* - attributesToSnippet: a string that contains the list of attributes to snippet alongside +* the number of words to return (syntax is `attributeName:nbWords`). +* Attributes are separated by a comma (Example: attributesToSnippet=name:10,content:10). +* You can also use an array (Example: attributesToSnippet: ['name:10','content:10']). +* By default no snippet is computed. +* - minWordSizefor1Typo: the minimum number of characters in a query word to accept one typo in this word. +* Defaults to 3. +* - minWordSizefor2Typos: the minimum number of characters in a query word +* to accept two typos in this word. Defaults to 7. +* - getRankingInfo: if set to 1, the result hits will contain ranking +* information in _rankingInfo attribute. +* - aroundLatLng: search for entries around a given +* latitude/longitude (specified as two floats separated by a comma). +* For example aroundLatLng=47.316669,5.016670). +* You can specify the maximum distance in meters with the aroundRadius parameter (in meters) +* and the precision for ranking with aroundPrecision +* (for example if you set aroundPrecision=100, two objects that are distant of +* less than 100m will be considered as identical for "geo" ranking parameter). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - insideBoundingBox: search entries inside a given area defined by the two extreme points +* of a rectangle (defined by 4 floats: p1Lat,p1Lng,p2Lat,p2Lng). +* For example insideBoundingBox=47.3165,4.9665,47.3424,5.0201). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - numericFilters: a string that contains the list of numeric filters you want to +* apply separated by a comma. +* The syntax of one filter is `attributeName` followed by `operand` followed by `value`. +* Supported operands are `<`, `<=`, `=`, `>` and `>=`. +* You can have multiple conditions on one attribute like for example numericFilters=price>100,price<1000. +* You can also use an array (for example numericFilters: ["price>100","price<1000"]). +* - tagFilters: filter the query by a set of tags. You can AND tags by separating them by commas. +* To OR tags, you must add parentheses. For example, tags=tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3). +* You can also use an array, for example tagFilters: ["tag1",["tag2","tag3"]] +* means tag1 AND (tag2 OR tag3). +* At indexing, tags should be added in the _tags** attribute +* of objects (for example {"_tags":["tag1","tag2"]}). +* - facetFilters: filter the query by a list of facets. +* Facets are separated by commas and each facet is encoded as `attributeName:value`. +* For example: `facetFilters=category:Book,author:John%20Doe`. +* You can also use an array (for example `["category:Book","author:John%20Doe"]`). +* - facets: List of object attributes that you want to use for faceting. +* Comma separated list: `"category,author"` or array `['category','author']` +* Only attributes that have been added in **attributesForFaceting** index setting +* can be used in this parameter. +* You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**. +* - queryType: select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - optionalWords: a string that contains the list of words that should +* be considered as optional when found in the query. +* Comma separated and array are accepted. +* - distinct: If set to 1, enable the distinct feature (disabled by default) +* if the attributeForDistinct index setting is set. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in a query with the distinct=1 parameter, +* all hits containing a duplicate value for the attributeForDistinct attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best +* one is kept and others are removed. +* - restrictSearchableAttributes: List of attributes you want to use for +* textual search (must be a subset of the attributesToIndex index setting) +* either comma separated or as an array +* @param {function} [callback] the result callback called with two arguments: +* error: null or Error('message'). If false, the content contains the error. +* content: the server answer that contains the list of results. +*/ +IndexCore.prototype.search = buildSearchMethod('query'); + +/* +* -- BETA -- +* Search a record similar to the query inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the similar query +* @param {object} [args] (optional) if set, contains an object with query parameters. +* All search parameters are supported (see search function), restrictSearchableAttributes and facetFilters +* are the two most useful to restrict the similar results and get more relevant content +*/ +IndexCore.prototype.similarSearch = deprecate( + buildSearchMethod('similarQuery'), + deprecatedMessage( + 'index.similarSearch(query[, callback])', + 'index.search({ similarQuery: query }[, callback])' + ) +); + +/* +* Browse index content. The response content will have a `cursor` property that you can use +* to browse subsequent pages for this query. Use `index.browseFrom(cursor)` when you want. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browse('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }, callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browse = function(query, queryParameters, callback) { + var merge = require(33); + + var indexObj = this; + + var page; + var hitsPerPage; + + // we check variadic calls that are not the one defined + // .browse()/.browse(fn) + // => page = 0 + if (arguments.length === 0 || arguments.length === 1 && typeof arguments[0] === 'function') { + page = 0; + callback = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'number') { + // .browse(2)/.browse(2, 10)/.browse(2, fn)/.browse(2, 10, fn) + page = arguments[0]; + if (typeof arguments[1] === 'number') { + hitsPerPage = arguments[1]; + } else if (typeof arguments[1] === 'function') { + callback = arguments[1]; + hitsPerPage = undefined; + } + query = undefined; + queryParameters = undefined; + } else if (typeof arguments[0] === 'object') { + // .browse(queryParameters)/.browse(queryParameters, cb) + if (typeof arguments[1] === 'function') { + callback = arguments[1]; + } + queryParameters = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') { + // .browse(query, cb) + callback = arguments[1]; + queryParameters = undefined; + } + + // otherwise it's a .browse(query)/.browse(query, queryParameters)/.browse(query, queryParameters, cb) + + // get search query parameters combining various possible calls + // to .browse(); + queryParameters = merge({}, queryParameters || {}, { + page: page, + hitsPerPage: hitsPerPage, + query: query + }); + + var params = this.as._getSearchParams(queryParameters, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse', + body: {params: params}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Continue browsing from a previous position (cursor), obtained via a call to `.browse()`. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browseFrom('14lkfsakl32', callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browseFrom = function(cursor, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/browse', + body: {cursor: cursor}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* +* @param {string} params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} params.facetQuery Query for the facet search +* @param {string} [params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +* @param callback (optional) +*/ +IndexCore.prototype.searchForFacetValues = function(params, callback) { + var clone = require(26); + var omit = require(34); + var usage = 'Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])'; + + if (params.facetName === undefined || params.facetQuery === undefined) { + throw new Error(usage); + } + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = this.as._getSearchParams(filteredParams, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + + encodeURIComponent(this.indexName) + '/facets/' + encodeURIComponent(facetName) + '/query', + hostType: 'read', + body: {params: searchParameters}, + callback: callback + }); +}; + +IndexCore.prototype.searchFacet = deprecate(function(params, callback) { + return this.searchForFacetValues(params, callback); +}, deprecatedMessage( + 'index.searchFacet(params[, callback])', + 'index.searchForFacetValues(params[, callback])' +)); + +IndexCore.prototype._search = function(params, url, callback, additionalUA) { + return this.as._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url || '/1/indexes/' + encodeURIComponent(this.indexName) + '/query', + body: {params: params}, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName), + body: {params: params} + }, + callback: callback, + additionalUA: additionalUA + }); +}; + +/* +* Get an object from this index +* +* @param objectID the unique identifier of the object to retrieve +* @param attrs (optional) if set, contains the array of attribute names to retrieve +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the object to retrieve or the error message if a failure occurred +*/ +IndexCore.prototype.getObject = function(objectID, attrs, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof attrs === 'function') { + callback = attrs; + attrs = undefined; + } + + var params = ''; + if (attrs !== undefined) { + params = '?attributes='; + for (var i = 0; i < attrs.length; ++i) { + if (i !== 0) { + params += ','; + } + params += attrs[i]; + } + } + + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params, + hostType: 'read', + callback: callback + }); +}; + +/* +* Get several objects from this index +* +* @param objectIDs the array of unique identifier of objects to retrieve +*/ +IndexCore.prototype.getObjects = function(objectIDs, attributesToRetrieve, callback) { + var isArray = require(8); + var map = require(32); + + var usage = 'Usage: index.getObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + + if (arguments.length === 1 || typeof attributesToRetrieve === 'function') { + callback = attributesToRetrieve; + attributesToRetrieve = undefined; + } + + var body = { + requests: map(objectIDs, function prepareRequest(objectID) { + var request = { + indexName: indexObj.indexName, + objectID: objectID + }; + + if (attributesToRetrieve) { + request.attributesToRetrieve = attributesToRetrieve.join(','); + } + + return request; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/objects', + hostType: 'read', + body: body, + callback: callback + }); +}; + +IndexCore.prototype.as = null; +IndexCore.prototype.indexName = null; +IndexCore.prototype.typeAheadArgs = null; +IndexCore.prototype.typeAheadValueOption = null; + +},{"25":25,"26":26,"28":28,"29":29,"32":32,"33":33,"34":34,"8":8}],21:[function(require,module,exports){ +'use strict'; + +var AlgoliaSearch = require(16); +var createAlgoliasearch = require(22); + +module.exports = createAlgoliasearch(AlgoliaSearch, 'Browser'); + +},{"16":16,"22":22}],22:[function(require,module,exports){ +(function (process){ +'use strict'; + +var global = require(6); +var Promise = global.Promise || require(3).Promise; + +// This is the standalone browser build entry point +// Browser implementation of the Algolia Search JavaScript client, +// using XMLHttpRequest, XDomainRequest and JSONP as fallback +module.exports = function createAlgoliasearch(AlgoliaSearch, uaSuffix) { + var inherits = require(7); + var errors = require(30); + var inlineHeaders = require(23); + var jsonpRequest = require(24); + var places = require(35); + uaSuffix = uaSuffix || ''; + + if (process.env.NODE_ENV === 'debug') { + require(1).enable('algoliasearch*'); + } + + function algoliasearch(applicationID, apiKey, opts) { + var cloneDeep = require(26); + + opts = cloneDeep(opts || {}); + + opts._ua = opts._ua || algoliasearch.ua; + + return new AlgoliaSearchBrowser(applicationID, apiKey, opts); + } + + algoliasearch.version = require(37); + + algoliasearch.ua = + 'Algolia for JavaScript (' + algoliasearch.version + '); ' + uaSuffix; + + algoliasearch.initPlaces = places(algoliasearch); + + // we expose into window no matter how we are used, this will allow + // us to easily debug any website running algolia + global.__algolia = { + debug: require(1), + algoliasearch: algoliasearch + }; + + var support = { + hasXMLHttpRequest: 'XMLHttpRequest' in global, + hasXDomainRequest: 'XDomainRequest' in global + }; + + if (support.hasXMLHttpRequest) { + support.cors = 'withCredentials' in new XMLHttpRequest(); + } + + function AlgoliaSearchBrowser() { + // call AlgoliaSearch constructor + AlgoliaSearch.apply(this, arguments); + } + + inherits(AlgoliaSearchBrowser, AlgoliaSearch); + + AlgoliaSearchBrowser.prototype._request = function request(url, opts) { + return new Promise(function wrapRequest(resolve, reject) { + // no cors or XDomainRequest, no request + if (!support.cors && !support.hasXDomainRequest) { + // very old browser, not supported + reject(new errors.Network('CORS not supported')); + return; + } + + url = inlineHeaders(url, opts.headers); + + var body = opts.body; + var req = support.cors ? new XMLHttpRequest() : new XDomainRequest(); + var reqTimeout; + var timedOut; + var connected = false; + + reqTimeout = setTimeout(onTimeout, opts.timeouts.connect); + // we set an empty onprogress listener + // so that XDomainRequest on IE9 is not aborted + // refs: + // - https://github.com/algolia/algoliasearch-client-js/issues/76 + // - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment + req.onprogress = onProgress; + if ('onreadystatechange' in req) req.onreadystatechange = onReadyStateChange; + req.onload = onLoad; + req.onerror = onError; + + // do not rely on default XHR async flag, as some analytics code like hotjar + // breaks it and set it to false by default + if (req instanceof XMLHttpRequest) { + req.open(opts.method, url, true); + + // The Analytics API never accepts Auth headers as query string + // this option exists specifically for them. + if (opts.forceAuthHeaders) { + req.setRequestHeader( + 'x-algolia-application-id', + opts.headers['x-algolia-application-id'] + ); + req.setRequestHeader( + 'x-algolia-api-key', + opts.headers['x-algolia-api-key'] + ); + } + } else { + req.open(opts.method, url); + } + + // headers are meant to be sent after open + if (support.cors) { + if (body) { + if (opts.method === 'POST') { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests + req.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); + } else { + req.setRequestHeader('content-type', 'application/json'); + } + } + req.setRequestHeader('accept', 'application/json'); + } + + if (body) { + req.send(body); + } else { + req.send(); + } + + // event object not received in IE8, at least + // but we do not use it, still important to note + function onLoad(/* event */) { + // When browser does not supports req.timeout, we can + // have both a load and timeout event, since handled by a dumb setTimeout + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + var out; + + try { + out = { + body: JSON.parse(req.responseText), + responseText: req.responseText, + statusCode: req.status, + // XDomainRequest does not have any response headers + headers: req.getAllResponseHeaders && req.getAllResponseHeaders() || {} + }; + } catch (e) { + out = new errors.UnparsableJSON({ + more: req.responseText + }); + } + + if (out instanceof errors.UnparsableJSON) { + reject(out); + } else { + resolve(out); + } + } + + function onError(event) { + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + // error event is trigerred both with XDR/XHR on: + // - DNS error + // - unallowed cross domain request + reject( + new errors.Network({ + more: event + }) + ); + } + + function onTimeout() { + timedOut = true; + req.abort(); + + reject(new errors.RequestTimeout()); + } + + function onConnect() { + connected = true; + clearTimeout(reqTimeout); + reqTimeout = setTimeout(onTimeout, opts.timeouts.complete); + } + + function onProgress() { + if (!connected) onConnect(); + } + + function onReadyStateChange() { + if (!connected && req.readyState > 1) onConnect(); + } + }); + }; + + AlgoliaSearchBrowser.prototype._request.fallback = function requestFallback(url, opts) { + url = inlineHeaders(url, opts.headers); + + return new Promise(function wrapJsonpRequest(resolve, reject) { + jsonpRequest(url, opts, function jsonpRequestDone(err, content) { + if (err) { + reject(err); + return; + } + + resolve(content); + }); + }); + }; + + AlgoliaSearchBrowser.prototype._promise = { + reject: function rejectPromise(val) { + return Promise.reject(val); + }, + resolve: function resolvePromise(val) { + return Promise.resolve(val); + }, + delay: function delayPromise(ms) { + return new Promise(function resolveOnTimeout(resolve/* , reject*/) { + setTimeout(resolve, ms); + }); + }, + all: function all(promises) { + return Promise.all(promises); + } + }; + + return algoliasearch; +}; + +}).call(this,require(12)) +},{"1":1,"12":12,"23":23,"24":24,"26":26,"3":3,"30":30,"35":35,"37":37,"6":6,"7":7}],23:[function(require,module,exports){ +'use strict'; + +module.exports = inlineHeaders; + +var encode = require(14); + +function inlineHeaders(url, headers) { + if (/\?/.test(url)) { + url += '&'; + } else { + url += '?'; + } + + return url + encode(headers); +} + +},{"14":14}],24:[function(require,module,exports){ +'use strict'; + +module.exports = jsonpRequest; + +var errors = require(30); + +var JSONPCounter = 0; + +function jsonpRequest(url, opts, cb) { + if (opts.method !== 'GET') { + cb(new Error('Method ' + opts.method + ' ' + url + ' is not supported by JSONP.')); + return; + } + + opts.debug('JSONP: start'); + + var cbCalled = false; + var timedOut = false; + + JSONPCounter += 1; + var head = document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + var cbName = 'algoliaJSONP_' + JSONPCounter; + var done = false; + + window[cbName] = function(data) { + removeGlobals(); + + if (timedOut) { + opts.debug('JSONP: Late answer, ignoring'); + return; + } + + cbCalled = true; + + clean(); + + cb(null, { + body: data, + responseText: JSON.stringify(data)/* , + // We do not send the statusCode, there's no statusCode in JSONP, it will be + // computed using data.status && data.message like with XDR + statusCode*/ + }); + }; + + // add callback by hand + url += '&callback=' + cbName; + + // add body params manually + if (opts.jsonBody && opts.jsonBody.params) { + url += '&' + opts.jsonBody.params; + } + + var ontimeout = setTimeout(timeout, opts.timeouts.complete); + + // script onreadystatechange needed only for + // <= IE8 + // https://github.com/angular/angular.js/issues/4523 + script.onreadystatechange = readystatechange; + script.onload = success; + script.onerror = error; + + script.async = true; + script.defer = true; + script.src = url; + head.appendChild(script); + + function success() { + opts.debug('JSONP: success'); + + if (done || timedOut) { + return; + } + + done = true; + + // script loaded but did not call the fn => script loading error + if (!cbCalled) { + opts.debug('JSONP: Fail. Script loaded but did not call the callback'); + clean(); + cb(new errors.JSONPScriptFail()); + } + } + + function readystatechange() { + if (this.readyState === 'loaded' || this.readyState === 'complete') { + success(); + } + } + + function clean() { + clearTimeout(ontimeout); + script.onload = null; + script.onreadystatechange = null; + script.onerror = null; + head.removeChild(script); + } + + function removeGlobals() { + try { + delete window[cbName]; + delete window[cbName + '_loaded']; + } catch (e) { + window[cbName] = window[cbName + '_loaded'] = undefined; + } + } + + function timeout() { + opts.debug('JSONP: Script timeout'); + timedOut = true; + clean(); + cb(new errors.RequestTimeout()); + } + + function error() { + opts.debug('JSONP: Script error'); + + if (done || timedOut) { + return; + } + + clean(); + cb(new errors.JSONPScriptError()); + } +} + +},{"30":30}],25:[function(require,module,exports){ +module.exports = buildSearchMethod; + +var errors = require(30); + +/** + * Creates a search method to be used in clients + * @param {string} queryParam the name of the attribute used for the query + * @param {string} url the url + * @return {function} the search method + */ +function buildSearchMethod(queryParam, url) { + /** + * The search method. Prepares the data and send the query to Algolia. + * @param {string} query the string used for query search + * @param {object} args additional parameters to send with the search + * @param {function} [callback] the callback to be called with the client gets the answer + * @return {undefined|Promise} If the callback is not provided then this methods returns a Promise + */ + return function search(query, args, callback) { + // warn V2 users on how to search + if (typeof query === 'function' && typeof args === 'object' || + typeof callback === 'object') { + // .search(query, params, cb) + // .search(cb, params) + throw new errors.AlgoliaSearchError('index.search usage is index.search(query, params, cb)'); + } + + // Normalizing the function signature + if (arguments.length === 0 || typeof query === 'function') { + // Usage : .search(), .search(cb) + callback = query; + query = ''; + } else if (arguments.length === 1 || typeof args === 'function') { + // Usage : .search(query/args), .search(query, cb) + callback = args; + args = undefined; + } + // At this point we have 3 arguments with values + + // Usage : .search(args) // careful: typeof null === 'object' + if (typeof query === 'object' && query !== null) { + args = query; + query = undefined; + } else if (query === undefined || query === null) { // .search(undefined/null) + query = ''; + } + + var params = ''; + + if (query !== undefined) { + params += queryParam + '=' + encodeURIComponent(query); + } + + var additionalUA; + if (args !== undefined) { + if (args.additionalUA) { + additionalUA = args.additionalUA; + delete args.additionalUA; + } + // `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if + params = this.as._getSearchParams(args, params); + } + + + return this._search(params, url, callback, additionalUA); + }; +} + +},{"30":30}],26:[function(require,module,exports){ +module.exports = function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +}; + +},{}],27:[function(require,module,exports){ +module.exports = createAnalyticsClient; + +var algoliasearch = require(21); + +function createAnalyticsClient(appId, apiKey, opts) { + var analytics = {}; + + opts = opts || {}; + // there need to be 4 hosts, like on the client, since if requests fail, + // the counter goes up by 1, so we need to have the same amount of hosts + // 4 because: -dsn, -1, -2, -3 + // This is done because the APPID used for search will be the same for the analytics client created, + // and since the state of available hosts is shared by APPID globally for the module, we had issues + // where the hostIndex would be 1 while the array was only one entry (you got an empty host) + opts.hosts = opts.hosts || [ + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com' + ]; + opts.protocol = opts.protocol || 'https:'; + + analytics.as = algoliasearch(appId, apiKey, opts); + + analytics.getABTests = function(_params, callback) { + var params = params || {}; + var offset = params.offset || 0; + var limit = params.limit || 10; + + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests?offset=' + encodeURIComponent(offset) + '&limit=' + encodeURIComponent(limit), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.getABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.addABTest = function(abTest, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests', + body: abTest, + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.stopABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests/' + encodeURIComponent(abTestID) + '/stop', + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.deleteABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'DELETE', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'write', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.waitTask = function(indexName, taskID, callback) { + return this.as.initIndex(indexName).waitTask(taskID, callback); + }; + + return analytics; +} + +},{"21":21}],28:[function(require,module,exports){ +module.exports = function deprecate(fn, message) { + var warned = false; + + function deprecated() { + if (!warned) { + /* eslint no-console:0 */ + console.warn(message); + warned = true; + } + + return fn.apply(this, arguments); + } + + return deprecated; +}; + +},{}],29:[function(require,module,exports){ +module.exports = function deprecatedMessage(previousUsage, newUsage) { + var githubAnchorLink = previousUsage.toLowerCase() + .replace(/[\.\(\)]/g, ''); + + return 'algoliasearch: `' + previousUsage + '` was replaced by `' + newUsage + + '`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#' + githubAnchorLink; +}; + +},{}],30:[function(require,module,exports){ +'use strict'; + +// This file hosts our error definitions +// We use custom error "types" so that we can act on them when we need it +// e.g.: if error instanceof errors.UnparsableJSON then.. + +var inherits = require(7); + +function AlgoliaSearchError(message, extraProperties) { + var forEach = require(5); + + var error = this; + + // try to get a stacktrace + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, this.constructor); + } else { + error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old'; + } + + this.name = 'AlgoliaSearchError'; + this.message = message || 'Unknown error'; + + if (extraProperties) { + forEach(extraProperties, function addToErrorObject(value, key) { + error[key] = value; + }); + } +} + +inherits(AlgoliaSearchError, Error); + +function createCustomError(name, message) { + function AlgoliaSearchCustomError() { + var args = Array.prototype.slice.call(arguments, 0); + + // custom message not set, use default + if (typeof args[0] !== 'string') { + args.unshift(message); + } + + AlgoliaSearchError.apply(this, args); + this.name = 'AlgoliaSearch' + name + 'Error'; + } + + inherits(AlgoliaSearchCustomError, AlgoliaSearchError); + + return AlgoliaSearchCustomError; +} + +// late exports to let various fn defs and inherits take place +module.exports = { + AlgoliaSearchError: AlgoliaSearchError, + UnparsableJSON: createCustomError( + 'UnparsableJSON', + 'Could not parse the incoming response as JSON, see err.more for details' + ), + RequestTimeout: createCustomError( + 'RequestTimeout', + 'Request timed out before getting a response' + ), + Network: createCustomError( + 'Network', + 'Network issue, see err.more for details' + ), + JSONPScriptFail: createCustomError( + 'JSONPScriptFail', + '"),window.ALGOLIA_SUPPORTS_DOCWRITE===!0?(document.write(''),n("document.write")()):r(o,n("DOMElement"))}catch(s){r(o,n("DOMElement"))}}function n(e){return function(){var t="AlgoliaSearch: loaded V2 script using "+e;window.console&&window.console.log&&window.console.log(t)}}t.exports=o},{1:1}],4:[function(e,t,r){"use strict";function o(){var e="-- AlgoliaSearch V2 => V3 error --\nYou are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\nPlease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch V2 => V3 error --";window.AlgoliaSearch=function(){throw new Error(e)},window.AlgoliaSearchHelper=function(){throw new Error(e)},window.AlgoliaExplainResults=function(){throw new Error(e)}}t.exports=o},{}],5:[function(e,t,r){"use strict";function o(t){var r=e(2),o=e(3),n=e(4);r(t)?o(t):n()}o("algoliasearch")},{2:2,3:3,4:4}]},{},[5])(5)}),function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.algoliasearch=e()}}(function(){var e;return function t(e,r,o){function n(s,a){if(!r[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};e[s][0].call(l.exports,function(t){var r=e[s][1][t];return n(r?r:t)},l,l.exports,t,e,r,o)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(e){var t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+r.humanize(this.diff),t){var o="color: "+this.color;e.splice(1,0,o,"color: inherit");var n=0,i=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(n++,"%c"===e&&(i=n))}),e.splice(i,0,o)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?r.storage.removeItem("debug"):r.storage.debug=e}catch(t){}}function c(){var e;try{e=r.storage.debug}catch(t){}return!e&&"undefined"!=typeof o&&"env"in o&&(e=o.env.DEBUG),e}function u(){try{return window.localStorage}catch(e){}}r=t.exports=e(2),r.log=s,r.formatArgs=i,r.save=a,r.load=c,r.useColors=n,r.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:u(),r.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],r.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},r.enable(c())}).call(this,e(12))},{12:12,2:2}],2:[function(e,t,r){function o(e){var t,o=0;for(t in e)o=(o<<5)-o+e.charCodeAt(t),o|=0;return r.colors[Math.abs(o)%r.colors.length]}function n(e){function t(){if(t.enabled){var e=t,o=+new Date,n=o-(u||o);e.diff=n,e.prev=u,e.curr=o,u=o;for(var i=new Array(arguments.length),s=0;s0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())),this},o.prototype.on=o.prototype.addListener,o.prototype.once=function(e,t){function r(){this.removeListener(e,r),o||(o=!0,t.apply(this,arguments))}if(!n(t))throw TypeError("listener must be a function");var o=!1;return r.listener=t,this.on(e,r),this},o.prototype.removeListener=function(e,t){var r,o,i,a;if(!n(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],i=r.length,o=-1,r===t||n(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(s(r)){for(a=i;a-- >0;)if(r[a]===t||r[a].listener&&r[a].listener===t){o=a;break}if(o<0)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(o,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},o.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],n(r))this.removeListener(e,r);else if(r)for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},o.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?n(this._events[e])?[this._events[e]]:this._events[e].slice():[]},o.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(n(t))return 1;if(t)return t.length}return 0},o.listenerCount=function(e,t){return e.listenerCount(t)}},{}],5:[function(e,t,r){var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString;t.exports=function(e,t,r){if("[object Function]"!==n.call(t))throw new TypeError("iterator must be a function");var i=e.length;if(i===+i)for(var s=0;s100)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]),o=(t[2]||"ms").toLowerCase();switch(o){case"years":case"year":case"yrs":case"yr":case"y":return r*p;case"days":case"day":case"d":return r*l;case"hours":case"hour":case"hrs":case"hr":case"h":return r*u;case"minutes":case"minute":case"mins":case"min":case"m":return r*c;case"seconds":case"second":case"secs":case"sec":case"s":return r*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function n(e){return e>=l?Math.round(e/l)+"d":e>=u?Math.round(e/u)+"h":e>=c?Math.round(e/c)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function i(e){return s(e,l,"day")||s(e,u,"hour")||s(e,c,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,r){if(!(e0)return o(e);if("number"===r&&isNaN(e)===!1)return t["long"]?i(e):n(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],10:[function(e,t,r){"use strict";var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString,i=Array.prototype.slice,s=e(11),a=Object.prototype.propertyIsEnumerable,c=!a.call({toString:null},"toString"),u=a.call(function(){},"prototype"),l=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],p=function(e){var t=e.constructor;return t&&t.prototype===e},d={$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},h=function(){if("undefined"==typeof window)return!1;for(var e in window)try{if(!d["$"+e]&&o.call(window,e)&&null!==window[e]&&"object"==typeof window[e])try{p(window[e])}catch(t){return!0}}catch(t){return!0}return!1}(),f=function(e){if("undefined"==typeof window||!h)return p(e);try{return p(e)}catch(t){return!1}},y=function(e){var t=null!==e&&"object"==typeof e,r="[object Function]"===n.call(e),i=s(e),a=t&&"[object String]"===n.call(e),p=[];if(!t&&!r&&!i)throw new TypeError("Object.keys called on a non-object");var d=u&&r;if(a&&e.length>0&&!o.call(e,0))for(var h=0;h0)for(var y=0;y=0&&"[object Function]"===o.call(e.callee)),r}},{}],12:[function(e,t,r){function o(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function i(e){if(p===setTimeout)return setTimeout(e,0);if((p===o||!p)&&setTimeout)return p=setTimeout,setTimeout(e,0);try{return p(e,0)}catch(t){try{return p.call(null,e,0)}catch(t){return p.call(this,e,0)}}}function s(e){if(d===clearTimeout)return clearTimeout(e);if((d===n||!d)&&clearTimeout)return d=clearTimeout,clearTimeout(e);try{return d(e)}catch(t){try{return d.call(null,e)}catch(t){return d.call(this,e)}}}function a(){m&&f&&(m=!1,f.length?y=f.concat(y):v=-1,y.length&&c())}function c(){if(!m){var e=i(a);m=!0;for(var t=y.length;t;){for(f=y,y=[];++v1)for(var r=1;r0&&u>c&&(u=c);for(var l=0;l=0?(p=y.substr(0,m),d=y.substr(m+1)):(p=y,d=""),h=decodeURIComponent(p),f=decodeURIComponent(d),o(s,h)?n(s[h])?s[h].push(f):s[h]=[s[h],f]:s[h]=f}return s};var n=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)}},{}],14:[function(e,t,r){"use strict";function o(e,t){if(e.map)return e.map(t);for(var r=[],o=0;o0)n.scope=r;else if("undefined"!=typeof r)throw new Error("the scope given to `copyIndex` was not an array with settings, synonyms or rules");return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:n,hostType:"write",callback:i})},o.prototype.getLogs=function(t,r,o){var n=e(26),i={};return"object"==typeof t?(i=n(t),o=r):0===arguments.length||"function"==typeof t?o=t:1===arguments.length||"function"==typeof r?(o=r,i.offset=t):(i.offset=t,i.length=r),void 0===i.offset&&(i.offset=0),void 0===i.length&&(i.length=10),this._jsonRequest({method:"GET",url:"/1/logs?"+this._getSearchParams(i,""),hostType:"read",callback:o})},o.prototype.listIndexes=function(e,t){var r="";return void 0===e||"function"==typeof e?t=e:r="?page="+e,this._jsonRequest({method:"GET",url:"/1/indexes"+r,hostType:"read",callback:t})},o.prototype.initIndex=function(e){return new i(this,e)},o.prototype.initAnalytics=function(t){var r=e(27);return r(this.applicationID,this.apiKey,t)},o.prototype.listUserKeys=s(function(e){return this.listApiKeys(e)},a("client.listUserKeys()","client.listApiKeys()")),o.prototype.listApiKeys=function(e){return this._jsonRequest({method:"GET",url:"/1/keys",hostType:"read",callback:e})},o.prototype.getUserKeyACL=s(function(e,t){return this.getApiKey(e,t)},a("client.getUserKeyACL()","client.getApiKey()")),o.prototype.getApiKey=function(e,t){return this._jsonRequest({method:"GET",url:"/1/keys/"+e,hostType:"read",callback:t})},o.prototype.deleteUserKey=s(function(e,t){return this.deleteApiKey(e,t)},a("client.deleteUserKey()","client.deleteApiKey()")),o.prototype.deleteApiKey=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+e,hostType:"write",callback:t})},o.prototype.restoreApiKey=function(e,t){return this._jsonRequest({method:"POST",url:"/1/keys/"+e+"/restore",hostType:"write",callback:t})},o.prototype.addUserKey=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKey()","client.addApiKey()")),o.prototype.addApiKey=function(t,r,o){var n=e(8),i="Usage: client.addApiKey(arrayOfAcls[, params, callback])";if(!n(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.indexes=r.indexes,s.description=r.description,r.queryParameters&&(s.queryParameters=this._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this._jsonRequest({method:"POST",url:"/1/keys",body:s,hostType:"write",callback:o})},o.prototype.addUserKeyWithValidity=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKeyWithValidity()","client.addApiKey()")),o.prototype.updateUserKey=s(function(e,t,r,o){return this.updateApiKey(e,t,r,o)},a("client.updateUserKey()","client.updateApiKey()")),o.prototype.updateApiKey=function(t,r,o,n){var i=e(8),s="Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof o||(n=o,o=null);var a={acl:r};return o&&(a.validity=o.validity,a.maxQueriesPerIPPerHour=o.maxQueriesPerIPPerHour,a.maxHitsPerQuery=o.maxHitsPerQuery,a.indexes=o.indexes,a.description=o.description,o.queryParameters&&(a.queryParameters=this._getSearchParams(o.queryParameters,"")),a.referers=o.referers),this._jsonRequest({method:"PUT",url:"/1/keys/"+t,body:a,hostType:"write",callback:n})},o.prototype.startQueriesBatch=s(function(){this._batch=[]},a("client.startQueriesBatch()","client.search()")),o.prototype.addQueryInBatch=s(function(e,t,r){this._batch.push({indexName:e,query:t,params:r})},a("client.addQueryInBatch()","client.search()")),o.prototype.sendQueriesBatch=s(function(e){return this.search(this._batch,e)},a("client.sendQueriesBatch()","client.search()")),o.prototype.batch=function(t,r){var o=e(8),n="Usage: client.batch(operations[, callback])";if(!o(t))throw new Error(n);return this._jsonRequest({method:"POST",url:"/1/indexes/*/batch",body:{requests:t},hostType:"write",callback:r})},o.prototype.assignUserID=function(e,t){if(!e.userID||!e.cluster)throw new l.AlgoliaSearchError("You have to provide both a userID and cluster",e);return this._jsonRequest({method:"POST",url:"/1/clusters/mapping",hostType:"write",body:{cluster:e.cluster},callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.assignUserIDs=function(e,t){if(!e.userIDs||!e.cluster)throw new l.AlgoliaSearchError("You have to provide both an array of userIDs and cluster",e);return this._jsonRequest({method:"POST",url:"/1/clusters/mapping/batch",hostType:"write",body:{cluster:e.cluster,users:e.userIDs},callback:t})},o.prototype.getTopUserID=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/top",hostType:"read",callback:e})},o.prototype.getUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/"+e.userID,hostType:"read",callback:t})},o.prototype.listClusters=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters",hostType:"read",callback:e})},o.prototype.listUserIDs=function(e,t){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping",body:e,hostType:"read",callback:t})},o.prototype.removeUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"DELETE",url:"/1/clusters/mapping",hostType:"write",callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.searchUserIDs=function(e,t){return this._jsonRequest({method:"POST",url:"/1/clusters/mapping/search",body:e,hostType:"read",callback:t})},o.prototype.setPersonalizationStrategy=function(e,t){return this._jsonRequest({method:"POST",url:"/1/recommendation/personalization/strategy",body:e,hostType:"write",callback:t})},o.prototype.getPersonalizationStrategy=function(e){return this._jsonRequest({method:"GET",url:"/1/recommendation/personalization/strategy",hostType:"read",callback:e})},o.prototype.destroy=n,o.prototype.enableRateLimitForward=n,o.prototype.disableRateLimitForward=n,o.prototype.useSecuredAPIKey=n,o.prototype.disableSecuredAPIKey=n,o.prototype.generateSecuredApiKey=n,o.prototype.getSecuredApiKeyRemainingValidity=n},{17:17,18:18,26:26,27:27,28:28,29:29,30:30,7:7,8:8}],17:[function(e,t,r){ +(function(r){function o(t,r,o){var i=e(1)("algoliasearch"),s=e(26),a=e(8),u=e(32),l="Usage: algoliasearch(applicationID, apiKey, opts)";if(o._allowEmptyCredentials!==!0&&!t)throw new c.AlgoliaSearchError("Please provide an application ID. "+l);if(o._allowEmptyCredentials!==!0&&!r)throw new c.AlgoliaSearchError("Please provide an API key. "+l);this.applicationID=t,this.apiKey=r,this.hosts={read:[],write:[]},o=o||{},this._timeouts=o.timeouts||{connect:1e3,read:2e3,write:3e4},o.timeout&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=o.timeout);var p=o.protocol||"https:";if(/:$/.test(p)||(p+=":"),"http:"!==p&&"https:"!==p)throw new c.AlgoliaSearchError("protocol must be `http:` or `https:` (was `"+o.protocol+"`)");if(this._checkAppIdData(),o.hosts)a(o.hosts)?(this.hosts.read=s(o.hosts),this.hosts.write=s(o.hosts)):(this.hosts.read=s(o.hosts.read),this.hosts.write=s(o.hosts.write));else{var d=u(this._shuffleResult,function(e){return t+"-"+e+".algolianet.com"}),h=(o.dsn===!1?"":"-dsn")+".algolia.net";this.hosts.read=[this.applicationID+h].concat(d),this.hosts.write=[this.applicationID+".algolia.net"].concat(d)}this.hosts.read=u(this.hosts.read,n(p)),this.hosts.write=u(this.hosts.write,n(p)),this.extraHeaders={},this.cache=o._cache||{},this._ua=o._ua,this._useCache=!(void 0!==o._useCache&&!o._cache)||o._useCache,this._useRequestCache=this._useCache&&o._useRequestCache,this._useFallback=void 0===o.useFallback||o.useFallback,this._setTimeout=o._setTimeout,i("init done, %j",this)}function n(e){return function(t){return e+"//"+t.toLowerCase()}}function i(e){if(void 0===Array.prototype.toJSON)return JSON.stringify(e);var t=Array.prototype.toJSON;delete Array.prototype.toJSON;var r=JSON.stringify(e);return Array.prototype.toJSON=t,r}function s(e){for(var t,r,o=e.length;0!==o;)r=Math.floor(Math.random()*o),o-=1,t=e[o],e[o]=e[r],e[r]=t;return e}function a(e){var t={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){var o;o="x-algolia-api-key"===r||"x-algolia-application-id"===r?"**hidden for security purposes**":e[r],t[r]=o}return t}t.exports=o;var c=e(30),u=e(31),l=e(20),p=e(36),d=500,h=r.env.RESET_APP_DATA_TIMER&&parseInt(r.env.RESET_APP_DATA_TIMER,10)||12e4;o.prototype.initIndex=function(e){return new l(this,e)},o.prototype.setExtraHeader=function(e,t){this.extraHeaders[e.toLowerCase()]=t},o.prototype.getExtraHeader=function(e){return this.extraHeaders[e.toLowerCase()]},o.prototype.unsetExtraHeader=function(e){delete this.extraHeaders[e.toLowerCase()]},o.prototype.addAlgoliaAgent=function(e){var t="; "+e;this._ua.indexOf(t)===-1&&(this._ua+=t)},o.prototype._jsonRequest=function(t){function r(e,n){function u(e){var t=e&&e.body&&e.body.message&&e.body.status||e.statusCode||e&&e.body&&200;h("received response: statusCode: %s, computed statusCode: %d, headers: %j",e.statusCode,t,e.headers);var r=2===Math.floor(t/100),o=new Date;if(w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:o,duration:o-x,statusCode:t}),r)return m._useCache&&!m._useRequestCache&&y&&(y[l]=e.responseText),{responseText:e.responseText,body:e.body};var i=4!==Math.floor(t/100);if(i)return v+=1,_();h("unrecoverable error");var u=new c.AlgoliaSearchError(e.body&&e.body.message,{debugData:w,statusCode:t});return m._promise.reject(u)}function d(e){h("error: %s, stack: %s",e.message,e.stack);var r=new Date;return w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:r,duration:r-x}),e instanceof c.AlgoliaSearchError||(e=new c.Unknown(e&&e.message,e)),v+=1,e instanceof c.Unknown||e instanceof c.UnparsableJSON||v>=m.hosts[t.hostType].length&&(g||!b)?(e.debugData=w,m._promise.reject(e)):e instanceof c.RequestTimeout?T():_()}function _(){return h("retrying request"),m._incrementHostIndex(t.hostType),r(e,n)}function T(){return h("retrying request with higher timeout"),m._incrementHostIndex(t.hostType),m._incrementTimeoutMultipler(),n.timeouts=m._getTimeoutsForRequest(t.hostType),r(e,n)}m._checkAppIdData();var x=new Date;if(m._useCache&&!m._useRequestCache&&(l=t.url),m._useCache&&!m._useRequestCache&&s&&(l+="_body_"+n.body),o(!m._useRequestCache,y,l)){h("serving response from cache");var R=y[l];return m._promise.resolve({body:JSON.parse(R),responseText:R})}if(v>=m.hosts[t.hostType].length)return!b||g?(h("could not get any response"),m._promise.reject(new c.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+m.applicationID,{debugData:w}))):(h("switching to fallback"),v=0,n.method=t.fallback.method,n.url=t.fallback.url,n.jsonBody=t.fallback.body,n.jsonBody&&(n.body=i(n.jsonBody)),p=m._computeRequestHeaders({additionalUA:f,headers:t.headers}),n.timeouts=m._getTimeoutsForRequest(t.hostType),m._setHostIndexByType(0,t.hostType),g=!0,r(m._request.fallback,n));var A=m._getHostByType(t.hostType),j=A+n.url,S={body:n.body,jsonBody:n.jsonBody,method:n.method,headers:p,timeouts:n.timeouts,debug:h,forceAuthHeaders:n.forceAuthHeaders};return h("method: %s, url: %s, headers: %j, timeouts: %d",S.method,j,S.headers,S.timeouts),e===m._request.fallback&&h("using fallback"),e.call(m,j,S).then(u,d)}function o(e,t,r){return m._useCache&&e&&t&&void 0!==t[r]}function n(e,r){return o(m._useRequestCache,y,l)&&e["catch"](function(){delete y[l]}),"function"!=typeof t.callback?e.then(r):void e.then(function(e){u(function(){t.callback(null,r(e))},m._setTimeout||setTimeout)},function(e){u(function(){t.callback(e)},m._setTimeout||setTimeout)})}this._checkAppIdData();var s,l,p,h=e(1)("algoliasearch:"+t.url),f=t.additionalUA||"",y=t.cache,m=this,v=0,g=!1,b=m._useFallback&&m._request.fallback&&t.fallback;this.apiKey.length>d&&void 0!==t.body&&(void 0!==t.body.params||void 0!==t.body.requests)?(t.body.apiKey=this.apiKey,p=this._computeRequestHeaders({additionalUA:f,withApiKey:!1,headers:t.headers})):p=this._computeRequestHeaders({additionalUA:f,headers:t.headers}),void 0!==t.body&&(s=i(t.body)),h("request start");var w=[];if(m._useCache&&m._useRequestCache&&(l=t.url),m._useCache&&m._useRequestCache&&s&&(l+="_body_"+s),o(m._useRequestCache,y,l)){h("serving request from cache");var _=y[l],T="function"!=typeof _.then?m._promise.resolve({responseText:_}):_;return n(T,function(e){return JSON.parse(e.responseText)})}var x=r(m._request,{url:t.url,method:t.method,body:s,jsonBody:t.body,timeouts:m._getTimeoutsForRequest(t.hostType),forceAuthHeaders:t.forceAuthHeaders});return m._useCache&&m._useRequestCache&&y&&(y[l]=x),n(x,function(e){return e.body})},o.prototype._getSearchParams=function(e,t){if(void 0===e||null===e)return t;for(var r in e)null!==r&&void 0!==e[r]&&e.hasOwnProperty(r)&&(t+=""===t?"":"&",t+=r+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[r])?i(e[r]):e[r]));return t},o.prototype._computeRequestHeaders=function(t){var r=e(5),o=t.additionalUA?this._ua+"; "+t.additionalUA:this._ua,n={"x-algolia-agent":o,"x-algolia-application-id":this.applicationID};return t.withApiKey!==!1&&(n["x-algolia-api-key"]=this.apiKey),this.userToken&&(n["x-algolia-usertoken"]=this.userToken),this.securityTags&&(n["x-algolia-tagfilters"]=this.securityTags),r(this.extraHeaders,function(e,t){n[t]=e}),t.headers&&r(t.headers,function(e,t){n[t]=e}),n},o.prototype.search=function(t,r,o){var n=e(8),i=e(32),s="Usage: client.search(arrayOfQueries[, callback])";if(!n(t))throw new Error(s);"function"==typeof r?(o=r,r={}):void 0===r&&(r={});var a=this,c={requests:i(t,function(e){var t="";return void 0!==e.query&&(t+="query="+encodeURIComponent(e.query)),{indexName:e.indexName,params:a._getSearchParams(e.params,t)}})},u=i(c.requests,function(e,t){return t+"="+encodeURIComponent("/1/indexes/"+encodeURIComponent(e.indexName)+"?"+e.params)}).join("&"),l="/1/indexes/*/queries";return void 0!==r.strategy&&(c.strategy=r.strategy),this._jsonRequest({cache:this.cache,method:"POST",url:l,body:c,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:u}},callback:o})},o.prototype.searchForFacetValues=function(t){var r=e(8),o=e(32),n="Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])";if(!r(t))throw new Error(n);var i=this;return i._promise.all(o(t,function(t){if(!t||void 0===t.indexName||void 0===t.params.facetName||void 0===t.params.facetQuery)throw new Error(n);var r=e(26),o=e(34),s=t.indexName,a=t.params,c=a.facetName,u=o(r(a),function(e){return"facetName"===e}),l=i._getSearchParams(u,"");return i._jsonRequest({cache:i.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(s)+"/facets/"+encodeURIComponent(c)+"/query",hostType:"read",body:{params:l}})}))},o.prototype.setSecurityTags=function(e){if("[object Array]"===Object.prototype.toString.call(e)){for(var t=[],r=0;rh?this._resetInitialAppIdData(e):e},o.prototype._resetInitialAppIdData=function(e){var t=e||{};return t.hostIndexes={read:0,write:0},t.timeoutMultiplier=1,t.shuffleResult=t.shuffleResult||s([1,2,3]),this._setAppIdData(t)},o.prototype._cacheAppIdData=function(e){this._hostIndexes=e.hostIndexes,this._timeoutMultiplier=e.timeoutMultiplier,this._shuffleResult=e.shuffleResult},o.prototype._partialAppIdDataUpdate=function(t){var r=e(5),o=this._getAppIdData();return r(t,function(e,t){o[t]=e}),this._setAppIdData(o)},o.prototype._getHostByType=function(e){return this.hosts[e][this._getHostIndexByType(e)]},o.prototype._getTimeoutMultiplier=function(){return this._timeoutMultiplier},o.prototype._getHostIndexByType=function(e){return this._hostIndexes[e]},o.prototype._setHostIndexByType=function(t,r){var o=e(26),n=o(this._hostIndexes);return n[r]=t,this._partialAppIdDataUpdate({hostIndexes:n}),t},o.prototype._incrementHostIndex=function(e){return this._setHostIndexByType((this._getHostIndexByType(e)+1)%this.hosts[e].length,e)},o.prototype._incrementTimeoutMultipler=function(){var e=Math.max(this._timeoutMultiplier+1,4);return this._partialAppIdDataUpdate({timeoutMultiplier:e})},o.prototype._getTimeoutsForRequest=function(e){return{connect:this._timeouts.connect*this._timeoutMultiplier,complete:this._timeouts[e]*this._timeoutMultiplier}}}).call(this,e(12))},{1:1,12:12,20:20,26:26,30:30,31:31,32:32,34:34,36:36,5:5,8:8}],18:[function(e,t,r){function o(){s.apply(this,arguments)}function n(e,t,r){function o(r,n){var i={page:r||0,hitsPerPage:t||100},s=n||[];return e(i).then(function(e){var t=e.hits,r=e.nbHits,n=t.map(function(e){return delete e._highlightResult,e}),a=s.concat(n);return a.lengths&&(t=s),"published"!==e.status?l._promise.delay(t).then(r):e})}function o(e){u(function(){t(null,e)},l._setTimeout||setTimeout)}function n(e){u(function(){t(e)},l._setTimeout||setTimeout)}var i=100,s=5e3,a=0,c=this,l=c.as,p=r();return t?void p.then(o,n):p},o.prototype.clearIndex=function(e){var t=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/clear",hostType:"write",callback:e})},o.prototype.getSettings=function(e,t){1===arguments.length&&"function"==typeof e&&(t=e,e={}),e=e||{};var r=encodeURIComponent(this.indexName);return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+r+"/settings?getVersion=2"+(e.advanced?"&advanced="+e.advanced:""),hostType:"read",callback:t})},o.prototype.searchSynonyms=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/search",body:e,hostType:"read",callback:t})},o.prototype.exportSynonyms=function(e,t){return n(this.searchSynonyms.bind(this),e,t)},o.prototype.saveSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getSynonym=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearSynonyms=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),void 0!==e.forwardToSlaves&&p();var r=e.forwardToSlaves||e.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchSynonyms=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/batch?forwardToReplicas="+o+"&replaceExistingSynonyms="+(t.replaceExistingSynonyms?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.searchRules=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/search",body:e,hostType:"read",callback:t})},o.prototype.exportRules=function(e,t){return n(this.searchRules.bind(this),e,t)},o.prototype.saveRule=function(e,t,r){if("function"==typeof t?(r=t,t={}):void 0===t&&(t={}),!e.objectID)throw new l.AlgoliaSearchError("Missing or empty objectID field for rule");var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getRule=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteRule=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearRules=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={});var r=e.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchRules=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/batch?forwardToReplicas="+o+"&clearExistingRules="+(t.clearExistingRules===!0?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.exists=function(e){var t=this.getSettings().then(function(){return!0})["catch"](function(e){if(e instanceof l.AlgoliaSearchError&&404===e.statusCode)return!1;throw e});return"function"!=typeof e?t:void t.then(function(t){e(null,t)})["catch"](function(t){e(t)})},o.prototype.findObject=function(e,t,r){t=void 0===t?{}:t;var o=void 0===t.paginate||t.paginate,n=void 0!==t.query?t.query:"",i=this,s=0,a=function(){return t.page=s,i.search(n,t).then(function(t){for(var r=t.hits,n=0;n=t.nbPages)throw new l.ObjectNotFound("Object not found");return a()})},c=a(s);return void 0===r?c:void c.then(function(e){r(null,e)})["catch"](function(e){r(e)})},o.prototype.getObjectPosition=function(e,t){for(var r=e.hits,o=0;o1&&a()}if(!h.cors&&!h.hasXDomainRequest)return void o(new u.Network("CORS not supported"));e=l(e,t.headers);var d,f,y=t.body,m=h.cors?new XMLHttpRequest:new XDomainRequest,v=!1;d=setTimeout(s,t.timeouts.connect),m.onprogress=c,"onreadystatechange"in m&&(m.onreadystatechange=p),m.onload=n,m.onerror=i,m instanceof XMLHttpRequest?(m.open(t.method,e,!0),t.forceAuthHeaders&&(m.setRequestHeader("x-algolia-application-id",t.headers["x-algolia-application-id"]),m.setRequestHeader("x-algolia-api-key",t.headers["x-algolia-api-key"]))):m.open(t.method,e),h.cors&&(y&&("POST"===t.method?m.setRequestHeader("content-type","application/x-www-form-urlencoded"):m.setRequestHeader("content-type","application/json")),m.setRequestHeader("accept","application/json")),y?m.send(y):m.send()})},a.prototype._request.fallback=function(e,t){return e=l(e,t.headers),new n(function(r,o){p(e,t,function(e,t){return e?void o(e):void r(t)})})},a.prototype._promise={reject:function(e){return n.reject(e)},resolve:function(e){return n.resolve(e)},delay:function(e){return new n(function(t){setTimeout(t,e)})},all:function(e){return n.all(e)}},s}}).call(this,e(12))},{1:1,12:12,23:23,24:24,26:26,3:3,30:30,35:35,37:37,6:6,7:7}],23:[function(e,t,r){"use strict";function o(e,t){return e+=/\?/.test(e)?"&":"?",e+n(t)}t.exports=o;var n=e(14)},{14:14}],24:[function(e,t,r){"use strict";function o(e,t,r){function o(){t.debug("JSONP: success"),m||d||(m=!0,p||(t.debug("JSONP: Fail. Script loaded but did not call the callback"), +a(),r(new n.JSONPScriptFail)))}function s(){"loaded"!==this.readyState&&"complete"!==this.readyState||o()}function a(){clearTimeout(v),f.onload=null,f.onreadystatechange=null,f.onerror=null,h.removeChild(f)}function c(){try{delete window[y],delete window[y+"_loaded"]}catch(e){window[y]=window[y+"_loaded"]=void 0}}function u(){t.debug("JSONP: Script timeout"),d=!0,a(),r(new n.RequestTimeout)}function l(){t.debug("JSONP: Script error"),m||d||(a(),r(new n.JSONPScriptError))}if("GET"!==t.method)return void r(new Error("Method "+t.method+" "+e+" is not supported by JSONP."));t.debug("JSONP: start");var p=!1,d=!1;i+=1;var h=document.getElementsByTagName("head")[0],f=document.createElement("script"),y="algoliaJSONP_"+i,m=!1;window[y]=function(e){return c(),d?void t.debug("JSONP: Late answer, ignoring"):(p=!0,a(),void r(null,{body:e,responseText:JSON.stringify(e)}))},e+="&callback="+y,t.jsonBody&&t.jsonBody.params&&(e+="&"+t.jsonBody.params);var v=setTimeout(u,t.timeouts.complete);f.onreadystatechange=s,f.onload=o,f.onerror=l,f.async=!0,f.defer=!0,f.src=e,h.appendChild(f)}t.exports=o;var n=e(30),i=0},{30:30}],25:[function(e,t,r){function o(e,t){return function(r,o,i){if("function"==typeof r&&"object"==typeof o||"object"==typeof i)throw new n.AlgoliaSearchError("index.search usage is index.search(query, params, cb)");0===arguments.length||"function"==typeof r?(i=r,r=""):1!==arguments.length&&"function"!=typeof o||(i=o,o=void 0),"object"==typeof r&&null!==r?(o=r,r=void 0):void 0!==r&&null!==r||(r="");var s="";void 0!==r&&(s+=e+"="+encodeURIComponent(r));var a;return void 0!==o&&(o.additionalUA&&(a=o.additionalUA,delete o.additionalUA),s=this.as._getSearchParams(o,s)),this._search(s,t,i,a)}}t.exports=o;var n=e(30)},{30:30}],26:[function(e,t,r){t.exports=function(e){return JSON.parse(JSON.stringify(e))}},{}],27:[function(e,t,r){function o(e,t,r){var o={};return r=r||{},r.hosts=r.hosts||["analytics.algolia.com","analytics.algolia.com","analytics.algolia.com","analytics.algolia.com"],r.protocol=r.protocol||"https:",o.as=n(e,t,r),o.getABTests=function(e,t){var r=r||{},o=r.offset||0,n=r.limit||10;return this.as._jsonRequest({method:"GET",url:"/2/abtests?offset="+encodeURIComponent(o)+"&limit="+encodeURIComponent(n),hostType:"read",forceAuthHeaders:!0,callback:t})},o.getABTest=function(e,t){return this.as._jsonRequest({method:"GET",url:"/2/abtests/"+encodeURIComponent(e),hostType:"read",forceAuthHeaders:!0,callback:t})},o.addABTest=function(e,t){return this.as._jsonRequest({method:"POST",url:"/2/abtests",body:e,hostType:"read",forceAuthHeaders:!0,callback:t})},o.stopABTest=function(e,t){return this.as._jsonRequest({method:"POST",url:"/2/abtests/"+encodeURIComponent(e)+"/stop",hostType:"read",forceAuthHeaders:!0,callback:t})},o.deleteABTest=function(e,t){return this.as._jsonRequest({method:"DELETE",url:"/2/abtests/"+encodeURIComponent(e),hostType:"write",forceAuthHeaders:!0,callback:t})},o.waitTask=function(e,t,r){return this.as.initIndex(e).waitTask(t,r)},o}t.exports=o;var n=e(21)},{21:21}],28:[function(e,t,r){t.exports=function(e,t){function r(){return o||(console.warn(t),o=!0),e.apply(this,arguments)}var o=!1;return r}},{}],29:[function(e,t,r){t.exports=function(e,t){var r=e.toLowerCase().replace(/[\.\(\)]/g,"");return"algoliasearch: `"+e+"` was replaced by `"+t+"`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#"+r}},{}],30:[function(e,t,r){"use strict";function o(t,r){var o=e(5),n=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):n.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name="AlgoliaSearchError",this.message=t||"Unknown error",r&&o(r,function(e,t){n[t]=e})}function n(e,t){function r(){var r=Array.prototype.slice.call(arguments,0);"string"!=typeof r[0]&&r.unshift(t),o.apply(this,r),this.name="AlgoliaSearch"+e+"Error"}return i(r,o),r}var i=e(7);i(o,Error),t.exports={AlgoliaSearchError:o,UnparsableJSON:n("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:n("RequestTimeout","Request timed out before getting a response"),Network:n("Network","Network issue, see err.more for details"),JSONPScriptFail:n("JSONPScriptFail"," + +
    2019年国庆70周年阅兵完整图文解说(收藏!)

    2019年国庆70周年阅兵完整图文解说(收藏!)

    +

    问:你在哪个瞬间觉得中国很强大?
    答:就是现在!
    开国大典的时候飞机不够,您说飞两遍,现在再也不需要飞两遍了,要多少有多少。
    这盛世,如你所愿吧,山河犹在,国泰民安。当年送你的十里长安街,如今已是十里繁荣!

    +
    + + +

    多图预警,加载较慢,好事多磨,请耐心等待!!!

    +

    阅兵解说

    海霞:今天是你的生日,我的中国。在这个不同寻常的节日,相信每一位中华儿女都会从心底里说一句,我爱你,中国。

    +

    康辉:70年风雨兼程,天安门广场上的红飘带寓意着红色基因连接历史,现实与未来。
    海霞:今天的天安门广场是世界瞩目的中心,今天的中国正前所未有的靠近世界舞台中心。
    康辉:长安街上,人民军队精神抖擞,这支曾经穿草鞋,拿梭镖走上征途的队伍,现在已经拥有了自己的航母和新一代隐身战机,正阔步迈向世界一流军队。此时此刻,4名上将,2名中将,100多名少将,近15000名官兵列队完毕,等待接受统帅的检阅,接受祖国和人民的检阅。
    海霞:长安街两侧身穿节日盛装的10万游行群众已集结完毕,一个多小时后,他们将组成一个个方阵,从天安门前通过,向全世界展示自由生动,欢愉活泼。70年前中国人的平均预期寿命只有三十五岁,七十年后的今天已经达到七十七岁,七十年来不断创造奇迹的中国让世界刮目相看。
    康辉:新中国用短短几十年的时间走过了西方发达国家几百年的工业化历程,70年前的中国满目疮痍积贫积弱,今天中国已经成为世界第二大经济体,是全球经济发展的第一引擎。

    +

    海霞:长安街始建于明代,寓意长治久安,回望长安大街,它记载着一个国家的兴衰和曾经有过的悲伤挣扎,奋斗喜悦,也记载着我们浴血奋战得解放,披荆斩棘成大道,砥砺奋进新时代的伟大征程。今天走在中国特色社会主义道路上我们无比自豪,无比自信。

    +

    康辉:黄河长江的浪,长城内外的风,起起伏伏,多少仁人志士上下求索。
    海霞:革命先行者孙中山,凝视着天安门广场,他曾经奋力让黑暗的中国走向黎明。
    康辉:开国领袖毛泽东注视着天安门广场,他让沉睡的东方雄狮昂起了头颅。
    海霞:1949年一唱雄鸡天下白,中国迈进新纪元。
    康辉:此时此刻,地域不同,口音不同的人们汇聚在这里,有56个民族的兄弟姐妹,有港澳台同胞和海外侨胞,有关心和支持中国发展的外国友人,我们将共同见证历史。
    康辉:中央广播电视总台。
    海霞:中央广播电视总台。
    康辉:这里是中华人民共和国首都北京。
    海霞:我们在这里向全球直播,庆祝中华人民共和国成立70周年大会。
    康辉:一个必将载入史册的国家盛典即将开始。
    康辉:习近平,李克强,栗战书,汪洋,王沪宁,赵乐际,韩正,王岐山等党和国家领导人来到了天安门城楼,江泽民,胡锦涛同志来到了天安门城楼。他们和全国亿万人民一起庆祝中华人民共和国70华诞。
    海霞:今天在天安门城楼参加庆典的,还有中共中央、全国人大常委会、国务院、全国政协、中央军委的领导同志和部分老同志代表,国家勋章、国家荣誉称号获得者代表等。
    康辉:来自全国各条战线的英雄模范人物,各界各族代表,香港、澳门、台湾同胞和海外侨胞代表以及在京重要外宾,各国驻华使节,外国专家等到现场观礼。
    康辉:五十六门礼炮,70响轰鸣,仿佛历史跃动的脉搏诉说着五十六个民族的中华儿女七十载春华秋实的拼博。
    海霞:隆隆炮声如冲锋的战士前赴后继,如燃烧的火炬薪火相传,我们的共和国就这样筚路蓝缕一路走来。
    康辉:正步铿锵堂堂气,寒光闪耀凛凛威。
    海霞:从人民英雄纪念碑到五星红旗升起,短短几百步距离,浓缩着革命先烈奋斗的历程,无数苦苦求索奋勇牺牲的先辈凝望着我们,踩下一个个坚实的脚印。
    康辉:一切向前走都不能忘记走过的路,走的再远,走到再光辉的未来,也不能忘记为什么出发。
    海霞:一个崭新的时代,从我们手中诞生,民族复兴的梦想,正由我们去实现。

    +

    康辉:古老的中国、年轻的中国、充满希望的中国;遥远的世界、连通的世界、命运与共的世界,将共同见证我们这一代人的新长征。
    海霞:义勇军进行曲,这不屈的旋律,必胜的强音,即将再次唱响,让我们心跳随他跃动,让我们的脚步随他前进,前进,前进进!

    +

    +

    康辉:标兵,是阅兵场上标定位置界线的军人,60名标兵以标准的正步,走向指定位置。
    海霞:脚踏着祖国大地。人民军队牢记宗旨,担当使命,用忠诚用热血,为国家富强,民族振兴,人民幸福,建立了不朽功勋。
    康辉:与祖国共奋进,人民军队由单一军种的军队发展成为诸军兵种联合基本实现机械化,加快迈向信息化的强大军队。
    海霞:这次国庆阅兵增设了一个庄严的仪式,习近平主席将在党旗、国旗和军旗前,向三面光辉的旗帜行注目礼。
    康辉:这次阅兵,是中国特色现代军事力量体系建设成果的充分展示,集中体现、信息主导、体系支撑、精兵作战、联合制胜的特点。
    海霞:这是中国特色社会主义进入新时代的首次国庆阅兵。
    康辉:这是共和国武装力量改革重塑后的首次整体亮相。
    海霞:现在,习近平主席乘坐的检阅车已经从折返点返回。
    康辉:建设一支听党指挥、能打胜仗、作风优良的人民军队,把人民军队建设成为世界一流军队,这是党的重托,也是人民的期盼。
    海霞:整齐的方阵,展现了共和国钢铁长城的时代风貌;铿锵的誓言,传递了全军将士对统帅的信赖、拥戴。
    康辉:关山飞渡的新征程,离不开登高望远的领路人。坚持以习近平新时代中国特色社会主义思想为指导,深入贯彻习近平强军思想,增强四个意识,坚定四个自信,做到两个维护,贯彻军委主席负责制,全军官兵思想上高度自觉,政治上高度自觉,行动上高度自觉。

    +

    海霞:为巩固中国共产党领导,和社会主义制度提供战略支撑,为捍卫国家主权统一领土完整提供战略支撑。为维护国家海外利益提供战略支撑。为促进世界和平与发展,提供战略支撑。人民军队,重任在肩,奋勇向前。
    康辉:刚刚接受了统帅检阅的徒步方队,现在已经调整完队形,驾驶车辆和操作装备的官兵,也已经进入自己的战斗岗位。
    康辉:空中梯队的战机已经陆续起飞,一会儿,他们将飞越天安门广场,接受检阅。
    康辉:分列式即将开始,47个地面方队,12个空中梯队,将从天安门前豪迈地通过。
    海霞:强国,必须强军,军强才能国安。党的十八大以来,党中央、中央军委和习主席领导人民军队,以党在新时代的强军目标为引领,贯彻新时代军事战略方针,政治建军,铸就忠诚,改革强军体系重塑,科技兴军跨越发展,依法治军严明纲纪,练兵备战锻造胜战之师,面向未来,塑造世界一流军队,人民军队体质一心、节奏一心、格局一心、面貌一心、中国特色强军之路,越走越宽广。

    +

    康辉:旗帜引领方向,旗帜凝聚力量。空中护旗梯队,破空而来,拉开了分列式的序幕。
    海霞:20架直升机汇成巨大70字样,象征着中华人民共和国走过的70年光辉历程。
    康辉:回望历史,放眼世界,今天的中国,比历史上任何时期都更接近中华民族伟大复兴的目标,比历史上任何时期,都更需要建设一支强大的人民军队。
    海霞:正在走来的15个地面徒步方队,来自战略战役联合作战指挥机构,诸军兵种部队,院校科研单位等。这种组合方式,体现了解放军、武警部队、民兵三结合的武装力量体制。
    康辉:鲜红的旗帜迎风招展,中国人民解放军仪仗方队,高擎党旗、国旗、军旗阔步走来。人民军队永远是中国共产党领导下的军队,永远是国家的捍卫者,永远是社会主义的捍卫者,永远是人民利益的捍卫者。
    海霞:紧随三面旗帜,领导指挥方队接受检阅,领队是姜国平少将、陈作松少将。27位将军和325位校尉军官,来自军委机关、五大战区、各军兵种和武警部队,展现了我军领导指挥体制改革后的崭新面貌,体现了练兵先练将。
    康辉:现在走来的是陆军方队,领队是林向阳少将、唐兴华少将。
    作为人民军队中最早诞生的军种,从战火硝烟中一路走来。人民陆军加快提高精确作战、立体作战、全域作战、多能作战、持续作的战能力。
    海霞:海军方队走过来了。领队是周名贵少将、梁旭少将。从浅蓝走向深蓝,从近海防御走向远海防卫,与新中国同龄的人民海军一路劈波斩浪,纵横万里海疆,勇闯远海大洋。
    康辉:现在走过来的是空军方队。领队是景涛少将、赵永远少将。人民空军成立不久后就开赴战场,为捍卫和平而战。70年搏击长空,逐梦蓝天,与共和国一起展翅高飞h今天的人民空军,正向着空天一体,攻防兼备的战略目标迈进。
    海霞:现在走过来的是火箭军方队,领队是薛今峰少将、张凤中少将。
    火箭军的常规导弹和核导弹,动于九天之上,打得越来越远,越来越准,越来越难以防御,经过半个多世纪的潜心砺剑,火箭军已成为核常兼备、全域慑战的战略军种。
    康辉:战略支援部队方队首次出现在国庆阅兵中,领队是王学武少将、康怀海少将。战略支援部队在改革强军中诞生,为人民军队输送现代战争内功,是维护国家安全的新型作战力量。

    +

    海霞:联勤保障部队方队,也是第一次亮相天安门广场,领队是刘向东少将,任延兵少将。兵马为重,保障先行,现代战争需要规模精良的能源和物资供应,需要科学高效精准,从不掉链子的联合保障。
    康辉:现在接受检阅的是武警部队方队,领队是赵东方少将、张卫国少将。多能一体,维稳维权。武警部队常年奋战在执勤、处突、反恐、维权执法和抢险救援第一线,维护国家安全政治安全和社会稳定,保卫人民美好生活,永远做党和人民的忠诚卫士。
    海霞:女兵方队走过来了,领队是程晓健少将、唐冰少将。352名女兵来自各军兵种和武警部队,飒爽英姿五尺枪,她们在火热军营中放飞青春成就梦想。

    +

    康辉:现在走过来的是院校科研方队,领队是衣述强少将、栾复新少将。受阅队员来自军事科学院、国防大学、国防科技大学。面向战场、面向部队、面向未来,培养-流军事人才,军事科研工作开创崭新局面。
    海霞:文职人员方队首次亮相阅兵场,领队是王海涛、王华岩。汇聚天下英才,壮大强军事业,伴随着人民军队改革重塑,各方面的优秀人才汇入军营,用知识和智慧助力国防和军队现代化。
    康辉:现在走过来的是预备役部队方队,领队是高新江大校、徐振刚预备役大校。建设祖国有作为,保卫祖国有能力,预备役部队是人民解放军的后备力量,和现役部队一体建设运用稳步推进。
    海霞:现在走过来的是民兵方队,领队是赵冰清、廖炜炜。受阅女民兵来自首都各行各业。民兵源自百姓,定期接受军事训练,保持战斗能力。兵民是胜利之本,高技术战争条件下,人民战争依然是克敌制胜的重要法宝。
    康辉:蓝色贝雷帽,荒漠迷彩服,维和部队方队阔步走来。领队是徐有泽少将、马宝川少将。我国是联合国安理会常任理事国中派出维和官兵最多的国家。2500多名中国军人坚守在7个维和任务区,8000人的维和部队待命出征。先后有13名维和勇士牺牲在异国他乡。中国军人用热血和生命,谱写了维护世界和平的大国担当。
    海霞:轰鸣声由远而近,装备方队即将进场。受阅的70个型号装备,均为中国制造,40%是首次亮相,32支装备方队编为7个作战模块,按照联合作战编程接受检阅。
    海霞:由全军荣誉功勋部队代表组成的战旗方队正浩荡而来。领队是五大战区主要指挥员,他们是刘粤军上将、王建武中将、赵宗岐上将.李桥铭中将、朱生岭上将。
    康辉: 100面鲜红的战旗迎风飘扬! 100个英雄部队的荣誉称号气壮天地!为什么战旗美如画,英雄的鮮血染红了她。人民军队基因永不磨面,红色血脉永远传承。
    海霞:机动作战,勇往直前,陆上作战模块即将接受检阅。
    海霞:坦克方队气势磅礴,领队是李明少将。22辆99A坦克呈”箭”形布阵,如战场霹雳,长驱直入。99A坦克是我国自主研发的主战坦克,具备优异的火力、机动、防护、和信息化水平。

    +

    康辉:紧随而来的轻型装甲方队,领队是邝德旺少将、王永胜少将。
    方队由15式新型轻型坦克、04A式履带步战车和履带指挥车混合编成,这些机械化、信息化装备,能够快速部署、快速反应、快速突击,是陆上应急作战的“急先锋”。
    海霞:现在驶来的是海军陆战队抽组的两栖突击车方队,领队是祝传生少将、沙成录少将。受阅的05A式两栖装甲突击车既能陆地作战,也可以近海航渡,向目标海滩发起攻击,让我军在抢滩登陆作战中,进攻矛头更锋利,防护盾牌更坚固。
    康辉:空降兵战车方队接受检阅,领队是邱火林少将、陈涛少将。
    受阅的轻型履带式步战车,可以空投敌人纵深地带,要害目标附近,让空降兵一落地,手头就有重家伙。他们从天而降,雷霆一击,是联合作战体系中的尖刀利刃。
    海霞:自行火炮方队,领队是张剑锋少将、何纪抗少将。箱式火箭炮,集远程压制精确打击和信息化作战于一体,一次调炮,多点攻击,155车载加榴炮,是新型炮兵压制武器型,火力更猛,精度更高,机动性更强。
    康辉:现在驶来的是反坦克导弹方队。领队是邹美余少将、李振领少将。受阅的红箭10反坦克导弹,既能精确打击地面目标,又能抗击低空低速的飞行。目前,我军已经形成多种发射类别、多种射程、多种制导方式的反坦克装备体系。
    海霞:特战装备方队,领队是田越少将、王信民少将。全地形车,机动灵活,空中突击旋翼机展翅欲飞。两型装备适应复杂战场环境,兵力兵器实现快速投送,灵活布局,是破袭突击、出奇制胜的拳头力量。
    康辉:紧随而来的是武警反恐突击方队,领队是刘兴立少将、王再发少将。受阅的反恐突击车和防暴装甲车,灵活机动,具备多种打击能力,能灵活地选择攻防手段,是武警部队维护国家安全和社会稳定的重要装备。
    海霞:乘风破浪,向海图强!海上作战模块即将接受检阅!
    海霞:首先开过来的是岸舰导弹方队,领队是王显峰少将、吴育红少将。受阅的鹰击12B岸舰导弹可以打击大中型水面舰,对海突击威力大,反应迅速射程远,是沿海防御体系的坚实盾牌。
    康辉:舰舰/潜舰导弹方队开过来了,领队是刘杰少将、姜平少将。受阅的鹰击18和鹰击18A导弹是我国新一代的反舰巡航导弹,藏得好,打得准,威力大,是海上联合打击体系的利剑。
    海霞:舰载防空武器方队,领队是刘宏伟少将、张宝军少将。受阅的海红旗9B,红旗16,红旗10和万发炮,共同构成远程、中程、近程和末端对空防御体系,可以拦击高速来袭的敌方战机和导弹,为海上舰艇编队撑起一方立体保护网。
    康辉:铸盾长空,御敌千里,防空反导模块即将接受检阅。
    康辉:预警雷达方队,领队是李国平少将、张磊少将。受阅装备是我国新一代高机动多功能雷达,能够探测和锁定飞机导弹等空天目标,提前发现这些不速之客!
    海霞:地空导弹第一方队,领队是刘明豹少将、韩宪锋少将。受阅的红旗9B远程地空导弹和红旗22中远程地空导弹,能够在复杂电磁环境下拦截多种空袭兵器,构筑起区域防空的坚固屏障!
    康辉:地空导弹第二方队,领队是朱瑞少将、董玉江少将。八套红旗12A地空导弹蓄势待发,四套红旗六弹炮系统昂首向前。远中近程结合,高中低空衔接,重要一点防空能力有效提升。
    海霞:野战防空导弹方队,领队是张帆少将、裴晓昌少将。受阅的红旗17A、红旗16B两型防空导弹,机动性能强,反应速度快,拦截精度高,为野战防空提供了多种手段。
    康辉:信息主导,体系制胜!即将接受检阅的是信息作战模块。
    康辉:首先开过来的是信息作战第一方队,领队是徐桂明少将、孟繁浩少将。受阅的信息侦测、数据干扰作战车组,侦察干扰能力强,既能独立遂行作战任务,又能支援战略方向联合作战,是无形战场上的神兵利器。
    海霞:信息作战第二方队,领队是李发义少将、杨小康少将。受阅的三型侦察干扰车和区域拦阻式干扰车,具有部署灵活、机动性强等特点。新型电子对抗装备,为我军赢得复杂电磁环境下战场主动提供坚实支撑。
    康辉:信息作战第三方队,领队是孙宝泰少将、景贤舫少将。受阅的频谱监测车,无线电接入节点车、卫星通信车和散射通信车,是联合作战体系制胜的可靠通信保障,能确保部队在严酷战争环境下通信畅通,耳聪目明。
    海霞:信息作战第四方队,领队是邓洪勤少将、金锋少将。气象水文观测车、地形勘测车、预报保障车、测绘导航车,能快速获取处理和传输战场环境信息,让指挥员对战场条件了如指掌!是我军全域作战的重要保障力量。
    康辉:智能对抗,引领前沿,无人作战模块即将接受检阅。
    康辉:无人作战第一方队,领队是姜鹏少将、顾庆友少将。高空高速无人侦察机,侦察校射无人机,小型近程侦察无人机和中程高速无人机,能时时感知战场态势,精准引导,火力打击!
    海霞:无人作战第二方队,领队是王燕崎少将、乔亚军少将。受阅的攻击2无人机能够提供强大的火力支援,攻击11无人机能够对敌人纵深目标实施精确打击,反辐射无人机能够对敌人纵深目标实施精确打击,反辐射无人机可以压制摧毁防风预警系统。
    康辉:无人作战第三方队,领队是李广泉少将、徐贵福少将。中国受阅的两型侦察干扰无人机和水下无火潜航器,上天入海,纵横驰程,是我军新型作战力量创新发展的显著成果。
    海霞:联合作战,保障先行,后勤装备保障模块即将接受检阅。
    海霞:现在开过来的是武警供应方队,领队是白忠斌少将、徐宝龙少将。受阅装备由野战近程车,野战站台车,运加油车,主食加工方舱混编而成。有了它们,官兵饮水吃饭,战场应急装卸,装备加油补给都更有保障。
    康辉:正在接受检阅的是抢修抢救方队,领队是沈竹君少将、汤辛少将。受阅的野战手术方舱,装备抢救车,拆装修理车,装甲抢救车和装甲抢修车,共同构成了现代战场上人员和装备的移动医院。
    海霞:大国长剑,浩荡东风,战略打击模块即将接受检阅。
    海霞:首先通过的是东风-17常规导弹方队,领队是张建强少将、王新国少将。东风快递,使命必达。首次公开亮相的东风-17常规导弹,具备全天候、无依托、强突防等特点,可对中近程目标实施精确打击。
    康辉:现在通过的是长剑-100巡航导弹方队,领队是樊具贤少将、李家勤少将。作为长剑系列中的最新型号,长剑-100首次亮相国庆阅兵。这款超音速巡航导弹精度高、射程远、反应速快,长剑在手,敢缚苍龙!
    海霞:东风26核常兼备导弹方队正接受检阅,领队是张继春少将、刘同江少将。种导弹既能装核弹头,也能装常规弹头,可以跨区域机动,灵活选择发射阵地,精确打击地面、地下、海上目标。
    康辉:巨浪-2导弹方队开过来了,领队是吴栋柱少将、初恩涛少将。巨浪-2型导弹是我国第二代潜射远程弹道导弹,它承担着支撑国家海基核威慑的重任。潜入深海,悄无声息,巨浪奔腾,威震海天。
    海霞:东风-31甲改核导弹方队,领队是袁德华少将、何骏少将。这种导弹是我国自主研制的第二代固体洲际战略核导弹,机动性能好,生存能力强,部署转换快,打击精度高,担负着震慑强敌与核反击作战的重要使命。
    康辉:东风-5B核导弹方队,领队是汪晓初少将、邓荣珍少将。东风浩荡,雷霆万钧,东风-5B液体洲际战略核导弹,突防能力强、毁伤威力大,是维护国家主权、捍卫民族尊严的重器。
    海霞:装备方队最后一个出场的是东风一41核导弹方队,领队是赵秋领少将、孙乐少将。战略制衡、战略慑控、战略决胜,东风41洲际战略核导弹是我国战略核力量的重要支撑。
    康辉:从弹道导弹到巡航导弹,从常规导弹到核导弹,它们是支撑强国梦、强军梦的坚强实力,是维护和平、捍卫和平的坚强盾牌。
    海霞:展翅长空,傲视苍穹,空中梯队即将接受检阅。
    康辉:领队机梯队率先飞临。
    康辉:空军司令员丁来杭上将在空警2000预警机.上担任指挥。空军八一飞行表演队的8架歼-10飞机护卫两翼,7道彩烟寓意着新中国70年的光辉历程。
    海霞:预警指挥机梯队飞过来了空警500空警200预警机和运8指挥通信机分别由四架歼击机护卫,编成3个五机楔形梯队。长空千里眼,云天中军帐,国产预警机指挥控制、预警探测、识别跟踪能力稳步提升。
    康辉:海上巡逻机梯队由空警500H预警机和首次亮相的运8反潜巡逻机组成第一楔队,空警200H、运8技术侦察机组成第二楔队,他们是维护国家领海领空安全,维护海洋权益的重要力量。
    海霞:运输机梯队飞过来了。受阅的运20又称疯狂,它航程远,载重大,速度快,可以在复杂气象条件下执行长距离空中运输任务,使我军战略投送能力登上新高峰!和运20一起受阅的运9也是一款国产新型运输机。
    康辉:现在飞过来的是支援保障机梯队。运9通信对抗飞机、心理战飞机、医疗救护机和运8远距离支援干扰及电子对抗侦察机,电子侦察机六型特种飞机分编为两个三级楔队,支援保障飞机的列装,有效提升了我军联合作战、全域作战的能力。
    海霞:轰炸机梯队正呼啸而来。三架轰6N,c6架轰6K分为三个三机楔队,第一次亮相的轰6N为国产新型远程战略轰炸机,可以空中授油,这两型轰炸机能够实施远程奔袭、大区域巡航和防区外打击。
    康辉:加受油机梯队飞过来了。轰油-6伸出输油管,演示为歼10B战斗机空中加油。受油机距离加油机的加油锥套只有五米,长着翅膀的加油站,让战机有了更大的作战半径。
    海霞:舰载机梯队接受检阅。歼15战机把人们的思绪带到了海天之间,带到了辽宁舰的甲板上。航母是现代海军的重器,舰载机是航母的刀锋!
    康辉:歼击机梯队进入我们的视野,5架歼20、5架歼16、5架歼10C战机组成三个楔队接受检阅。今天中国的歼击机家族不断壮天,为夺取战场制空权增添了制胜砝码。
    海霞:陆航突击梯队正在接受检阅。五架直9武装侦察直升机组成的侦察警戒分队,九架直10武装直升机组成火力突击分队,三架直19武装直升机,六架直20战术通用直升机,九架直8B运输直升机混编为运输分队,八架直19武装直升机担任护卫任务,其中直20战术通用直升机是首次亮相阅兵场,飞旋的铁翼为陆军插上腾飞的翅膀。
    康辉:最后接受检阅的是教练机梯队,有5架教10,5架歼教9,12架教8组成,其中教10加挂武器后可以执行空战任务。
    康辉:机群飞过,彩烟绚丽,余味悠长。
    康辉:今天十万群众和70组彩车将组成36个方阵和3个情景式行进,以同心共筑中国梦为主题分为建国创业、改革开放、伟大复兴三个篇章,展现中国共产党团结带领全国各族人民从站起来、富起来到强起来的伟大征程。
    海霞:国旗方阵,国庆年号和国徽方阵、致敬方阵拉开了群众游行的序幕。
    海霞:国旗方阵由高举巨幅国旗的1949名青年组成,70年前就在这里,五星红旗和世人初次见面,70年后的今天它比任何时候都闪耀惊艳。
    康辉:2019名青年组成国庆年号和国徽方阵。1949到2019,70年栉风沐雨,70年砥砺奋进。
    康辉:庄严神圣的国徽巍然屹立,这是我们伟大祖国的象征,代表着全体中国人民的尊严和力量。
    海霞:一曲《红旗颂》奏响,致敬方阵的21辆礼宾车徐徐驶来。第一辆礼宾车上,是6位新中国缔造者的亲属代表,3位老一辈科学家的家属代表和9位老红军、老八路军、老解放军。
    海霞:紧随而来的20辆礼宾车上也坐着老一辈党和国家、军队领导人亲属代表;老一辈建设者和家属代表;新中国成立前参加革命工作的老战士,老一辈军队退役英模、民兵英模和支前模范代表。
    康辉:一切向前走,都不能忘记走过的路。为了民族独立、人民解放和国家富强、人民幸福,无数先辈筑起了坚不可摧的血肉长城,铸就了坚强不屈的民族脊梁。
    海霞:一部民族史,一部奋斗史,一部英雄史。英雄胸前的勋章、奖章凝结着人民的敬意,后代手中的荣誉牌和纪念物铭刻着国家的记忆。一个有希望的民族不能没有英雄,一个有前途的国家不能没有先锋,今天,让我们再次向共和国的英雄和先锋致敬。
    康辉:今天,我们比历史上任何时期都更接近、更有信心和能力实现中华民族伟大复兴的目标。今天,老一辈的革命理想、优良传统和时代精神将继续激励我们,不忘初心、牢记使命、永远奋斗,向着这个宏伟目标奋勇前进!
    海霞:群众游行第一部分“建国创业”由5个方阵组成,打头的是“开天辟地”方阵。
    海霞:中国诞生了共产党,这是开天辟地的大事变。彩车上热血青年手持火把,拨开历史的迷雾,攀登真理的高峰,取来信念的火种,点亮革命的火炬,“星星之火”渐成燎原之势,荡涤风雨如磐的暗夜,燃烧成光耀中华的绚烂日出。

    +

    康辉:从开天辟地到改天换地,凝结了一个民族刻骨铭心的磨难与觉醒、一个政党矢志不渝的奋斗与探索、一个国家波澜壮阔的进步与崛起。

    +

    海霞:“浴血奋战”方阵中,三辆并行的彩车上,八一勋章、独立自由勋章和解放勋章熠熠生辉。金色勋章是建功立业的历历铭记,红色绶带是拼搏奋战的滚滚热血。抗击侵略,救亡图存,反抗压迫,争取自由,中国共产党团结带领中国人民浴血奋战28年,谱写了一曲气壮山河的英雄赞歌。为有牺牲多壮志,敢教日月换新天。牢记革命历史,传承红色基因,我们必将从胜利走向新的胜利!

    +

    康辉:簇拥着毛泽东同志巨幅画像和标语的“建国伟业”方阵向我们走来。以毛泽东同志为主要代表的中国共产党人,创立了毛泽东思想,团结带领全党全国各族人民,取得了新民主主义革命的胜利,建立中华人民共和国,中华民族的发展进步从此开启了新纪元。中国人民,站起来了!五洲寰宇,换了人间!

    +

    海霞:红旗漫卷,红绸翻飞,游行群众跳起了热情欢腾的“红绸舞”。“当家作主”方阵展现了亿万中国人民当家作主后的喜悦心情。彩车上的巨型雕塑,再现了“人民代表意气风发步出人民大会堂”的经典场景。中国人民,终于成为了国家的主人、社会的主人、自己命运的主人。

    +

    康辉:“艰苦奋斗”方阵向我们走来。王进喜、时传祥……这每一个名字都让我们永远铭记。正是这种自力更生、艰苦奋斗的精神,让新中国从“一穷二白”中艰难走来,在砥砺奋进中拼搏成长。钢花飞溅、铁水奔流、石油流淌、麦浪滚滚,社会主义建设热火朝天。奋斗本身就是一种幸福。新时代,依然是属于奋斗者的时代!

    +

    海霞:长安街上熙熙攘攘的自行车流,是属于一代人的青春记忆。少男少女拨响车铃穿梭而过,仿佛时光倒流,开启了第一段情境式行进“青春万岁”。

    +

    海霞:一代青年有一代青年的青春之歌,实现中华民族伟大复兴,中国青年始终是先锋力量。

    +

    康辉:群众游行第二部分“改革开放”由9个方阵组成。簇拥着邓小平同志巨幅画像和标语的“关键抉择”方阵正向我们走来。

    +

    康辉:以邓小平同志为主要代表的中国共产党人,团结带领全党全国各族人民,创立了邓小平理论,作出实行改革开放的历史性决策,确立社会主义初级阶段基本路线,成功开创了中国特色社会主义。改革开放,是决定当代中国命运的关键一招,实现了中华民族从站起来到富起来的伟大飞跃!

    +

    海霞:中国革命,从农村出发;中国改革,从农村突破。来自安徽凤阳小岗村、浙江安吉余村等地的农村改革领头人,和农民群众代表组成“希望田野”方阵,带着丰收的喜悦向我们走来。这是一块永远孕育着希望的热土。撒上火种,它就燃起燎原的烈焰;吹过春风,它就涌起翻滚的麦浪。

    +

    康辉:时间就是金钱,效率就是生命。新中国在改革开放的浪潮中加快了前进的脚步。“春潮滚滚”方阵中,深圳、厦门等经济特区,万丈高楼平地起,谱写了改革开放的壮丽篇章。一代代的开拓者和建设者,以拓荒牛的精神,书写了一个个让世界瞩目的中国奇迹。

    +

    海霞:簇拥着江泽民同志巨幅画像和标语的“与时俱进”方阵正向我们走来。以江泽民同志为主要代表的中国共产党人,团结带领全党全国各族人民,形成了“三个代表”重要思想,在严峻考验面前捍卫了中国特色社会主义,开创了全面改革开放新局面,成功把中国特色社会主义推向21世纪。世纪之交,风云际会,辉煌的成就,证明了中国特色社会主义制度的蓬勃生机和光明未来。

    +

    康辉:港澳台同胞和各界群众组成了“一国两制”方阵,他们挥舞旗帜,欢呼致意,为共和国的生日献上儿女们最赤诚的祝福。“一国两制”伟大构想具有强大生命力。只要坚持全面准确理解和贯彻“一国两制”方针,严格按照宪法和基本法办事,香港和澳门必将拥有更加美好的明天。

    +

    海霞:岁月如斯,不舍昼夜。“跨越世纪”方阵中,圆形日晷上流转着金色的光芒日历。世纪之初呱呱坠地的“世纪宝宝”,如今已长成英姿勃发的青年。源远流长的古老中国,历久弥新;跨越世纪的青春中国,风华正茂!

    +

    康辉:簇拥着胡锦涛同志巨幅画像和标语的“科学发展”方阵向我们走来。以胡锦涛同志为主要代表的中国共产党人,团结带领全党全国各族人民,形成了科学发展观,形成中国特色社会主义事业总体布局,成功在新的历史起点上坚持和发展了中国特色社会主义。以人为本民心皆暖,和谐世界天下共赢。

    +

    海霞:众志成城的彩车上,汶川县的映秀小学,红白镇的红顶民居,阿坝州的古堡新寨,这些都是在废墟上建立的新家园。时光荏苒,当年的“敬礼娃娃”,如今已经是青春少年。方阵中有参与抗击非典的医护工作人员,有参与汶川重建的解放军和武警部队官兵、救援队员、消防指战员、医疗队员、志愿者和各界群众。在无情灾害面前,我们万众一心,创造了抢险救灾和灾后重建的双重奇迹。

    +

    康辉:“北京欢迎你”,这熟悉的旋律把我们拉回到了2008年那个盛夏。百年奥运,百年梦圆。只有上下一心的国家、富有进取心和想象力的国家,才能有那样的华彩呈现。“给中国一个机会,还世界一个奇迹”。2022年冬奥会,我们继续相约北京。

    +

    海霞:激昂雄壮的鼓点催人奋进,中国功夫和舞狮表演的互动组合,开启了第二段情境式行进“东方雄狮”。睡狮早已醒来,雄狮昂首东方。美哉,我少年中国,与天不老!壮哉,我中国少年,与国无疆!

    +

    康辉:群众游行第三部分“伟大复兴”由18个方阵组成。簇拥着习近平同志巨幅画像和标语的“伟大复兴”方阵向我们走来。党的十八大以来,以习近平同志为核心的党中央,团结带领全党全国各族人民,进行伟大斗争、建设伟大工程、推进伟大事业、实现伟大梦想,创立了习近平新时代中国特色社会主义思想,推动党和国家事业发生了历史性变革、取得了历史性成就。中国特色社会主义进入新时代!中华民族迎来了从站起来、富起来到强起来的伟大飞跃!

    +

    海霞:科学技术是第一生产力,创新是引领发展的第一动力。科技创新领域的代表组成“创新驱动”方阵,自信昂扬地向我们走来。高铁、天宫、蛟龙,搭载着“天眼”“北斗”“C919大飞机”“长征三号”“天河二号”等大国重器,驰骋在科技强国的征途上。三辆彩车在行进中首尾相连,组成一列高速飞驰的“复兴号”,驶向更加美好的明天。

    +

    康辉:“区域协调”方阵中,四条龙舟你追我赶,旋转“魔方”气象万千,东西南北纵横联动发展的新格局全面铺展。京津冀、长江经济带、粤港澳、长三角,“四大战略”齐头并进;西部开发、东北振兴、中部崛起、东部率先,“四大板块”协调发展。

    +

    海霞:村口杨柳依依,院内海棠盛开,一幅幅农民画,描绘出新时代的美丽乡村。农村致富带头人、劳动模范和农民群众组成“乡村振兴”方阵向我们走来,产业兴旺、生态宜居、乡风文明、治理有效、生活富裕,中国农民的美好梦想正在变成现实。

    +

    康辉:《宣誓号角》乐曲奏响,“民主法治”方阵向我们走来。彩车上,人民大会堂五星穹顶星光灿烂,《中华人民共和国宪法》庄严神圣,金色大手托起的,是我们共同捍卫人民民主的决心,是我们共同捍卫宪法法律尊严的承诺。

    +

    海霞:56个民族56支花,56族兄弟姐妹是一家。“民族团结”方阵中的各族群众,手拉手,载歌载舞而来。彩车上“石榴瓶”光彩夺目,各民族像石榴籽一样紧紧抱在一起,血脉相连,风雨同舟。

    +

    康辉:“人民有信仰,国家有力量,民族有希望”。“凝心铸魂”方阵走来,习近平新时代中国特色社会主义思想的火炬凝聚起强大的精神力量。强信心、聚民心、暖人心、筑同心,为国家立心,为民族立魂。14亿人一心谋发展,发展就有不竭动力。14亿人共爱一个家,祖国就欣欣向荣、日新月异。

    +

    海霞:“中华文化”方阵彩车上好戏连台,乐手八音迭奏,舞者摇曳生姿,戏曲精彩绝伦,百花齐放,各展芳华。一个民族的复兴需要强大的物质力量,也需要强大的精神力量,文化兴国运兴,文化强民族强。

    +

    康辉:“老师好!同学们好!”“立德树人”方阵中的师生代表们挥舞着校旗,簇拥着彩车从青春的歌声中走来。“打开的书本”生长出硕果累累的“知识树”,数据链组成的树干上耸立着“教育云”。三尺讲台系国运,只有德智体美劳全面发展的新一代才能真正肩负起民族复兴的重任。

    +

    海霞:竞技体育成绩傲人,全民健身蓬勃开展,冬奥筹备卓有成效,冰雪运动快速普及。“体育强国”方阵的彩车,以“冰丝带”速滑馆造型为底座,以“首钢滑雪大跳台”造型为车体。北京冬奥会和冬残奥会的吉祥物“冰墩墩”和“雪容融”正在彩车上向大家招手示意。

    +

    康辉:走在小康路上,一路歌美花香。来自独龙江乡、十八洞村等贫困地区驻村的“第一书记”出现在“脱贫攻坚”方阵的彩车上,6年时间,8000多万人脱贫,这是中国减贫史上的壮举,这是人类社会难以想象的奇迹!2020年,坚决打赢脱贫攻坚战,中华民族千百年来存在的绝对贫困问题将在我们这一代人的手里彻底解决。

    +

    海霞:美好生活是什么?是环卫工人清扫的整洁环境,是快递小哥便捷的物流服务,是医生护士的悉心照料,是最美家庭的幸福相伴,是老年模特队的神采奕奕,是残障人士的方便出行。彩车上“幼有所育、学有所教、劳有所得、病有所医、老有所养、住有所居、弱有所扶”的生活场景一一呈现。美好生活从哪儿来?中国人的回答是:从奋斗中来。

    +

    康辉:青山悠悠,绿水荡漾,生态环保战线的工作者组成“绿水青山”方阵。最严厉的环保执法,最大力度的环保投入,最深入人心的绿色生活理念,小到垃圾分类,大到江河治理。“绿水青山就是金山银山”这不仅是金句,更是中国最接地气的新发展理念。

    +

    海霞:巨大的鲲鹏造型彩车,引领“中华儿女”方阵向我们走来。鲲鹏展翅,扶摇直上,象征着中华民族生生不息、展翅腾飞。紧随其后的是各省、自治区、直辖市和香港、澳门、台湾的彩车。

    +

    康辉:第一辆是“首善北京”彩车;

    +

    海霞:这是“新时代新天津”彩车;

    +

    康辉:这是“盛世雄安”河北彩车;

    +

    海霞:这是“奋进山西”彩车;

    +

    康辉:这是“亮丽北疆”内蒙古彩车;

    +

    海霞:这是“展翅腾飞”辽宁彩车;

    +

    康辉:这是“速度吉林”彩车;

    +

    海霞:这是“中华粮仓”黑龙江彩车;

    +

    康辉:这是“奋进上海”彩车;

    +

    海霞:这是“江苏智造”彩车;

    +

    康辉:这是“潮涌之江”浙江彩车;

    +

    海霞:这是“美好安徽”彩车;

    +

    康辉:这是“高素质高颜值新福建”彩车;

    +

    海霞:这是“金色赣鄱”江西彩车;

    +

    康辉:这是“国泰民安”山东彩车;

    +

    海霞:这是“出彩中原”河南彩车;

    +

    康辉:这是“光耀湖北”彩车;

    +

    海霞:这是“潇湘今朝”湖南彩车;

    +

    康辉:这是“扬帆大湾”广东彩车;

    +

    海霞:这是“壮美广西”彩车;

    +

    康辉:这是“美好新海南”彩车;

    +

    海霞:这是“魅力重庆”彩车;

    +

    康辉:这是“逐梦兴川”四川彩车;

    +

    海霞:这是“多彩贵州”彩车;

    +

    康辉:这是“七彩云南”彩车;

    +

    海霞:这是“幸福西藏”彩车;

    +

    康辉:这是“壮阔三秦”陕西彩车;

    +

    海霞:这是“交响丝路 如意甘肃”彩车;

    +

    康辉:这是“中华水塔”青海彩车;

    +

    海霞:这是“建设美丽新宁夏”彩车;

    +

    康辉:这是“美丽新疆”彩车;

    +

    海霞:这是“香港,进”彩车;

    +

    康辉:这是“莲花绽放”澳门彩车;

    +

    海霞:最后一辆是“宝岛台湾”彩车。

    +

    康辉:一曲《千年之约》,婉转悠扬。中外青年携手前行,组成“人类命运共同体”方阵。彩车上,“一带一路”通古今,“友谊之桥”跨海陆,和平风帆共五洲。中国发展离不开世界,世界发展也需要中国。今天的节日,属于中国人民,也属于热爱和平的世界人民。

    +

    海霞:“从严治党”彩车上是全国先进基层党组织代表和全国优秀党务工作者代表,中央八项规定精神、“民有所呼,我有所应”、“学习强国”等新时代的党建成果生动呈现。中国特色社会主义进入新时代,党内政治生态展现新气象,反腐败斗争取得压倒性胜利,全面从严治党取得重大成果。党的面貌焕然一新,党群关系、干群关系更加紧密。

    +

    康辉:“不忘初心”方阵彩车上,焦裕禄、孔繁森、杨善洲等各个时期优秀共产党员的彩塑屹立山肩,全国优秀共产党员环立山腰,共产党人“全心全意为人民服务”承诺如山。

    +

    海霞:七十载惊涛拍岸,九万里风鹏正举。“扬帆远航”方阵中的“中国号”巨轮两侧云帆徐徐升起,乘着新时代的浩荡东风,承载着14亿中国人民的梦想,劈波斩浪,扬帆远航。“直挂云帆济沧海”。中国共产党掌舵领航,“中国号”巨轮向着实现中华民族伟大复兴的目标,奋勇前进!

    +

    康辉:红旗翻飞,鼓点激昂,2019名少先队员组成的行进乐团带来了第三段情境式行进“同心追梦”。少年当立凌云志,报效祖国会有时。中华民族伟大复兴的中国梦,终将在接续奋斗中成为现实。

    +

    海霞:“我和我的祖国,一刻也不能分割”,这是我们心中永远的歌。康辉:5000名首都各界群众组成了“祖国万岁”方阵。

    +

    海霞:70载风雨兼程,70载岁月峥嵘。

    +

    康辉:70载沧桑巨变,70载春华秋实。

    +

    海霞:祖国万岁大花篮,繁花锦簇,万紫千红,盘旋上升的红绸带寓意人民共和国发展蒸蒸日上。

    +

    海霞:70年,弹指一挥间。70年,我们重整行装再出发。

    +

    康辉:让我们紧密团结在以习近平同志为核心的党中央周围,高举中国特色社会主义伟大旗帜,以马克思列宁主义、毛泽东思想、邓小平理论、“三个代表”重要思想、科学发展观、习近平新时代中国特色社会主义思想为指导,为实现“两个一百年”奋斗目标和中华民族伟大复兴的中国梦而努力奋斗!

    +

    海霞:我们祝福祖国更加繁荣富强!

    +

    康辉:我们祝福人民更加幸福安康!

    +

    海霞、康辉:我们祝福明天更加灿烂辉煌!

    +

    李克强:庆祝大会到此结束。

    +

    7万羽和平鸽展翅高飞,7万只气球腾空而起,伴着《歌唱祖国》的激昂旋律,庆祝大会圆满结束。

    +

    人民日报评论

    +

    奋斗的史诗 复兴的伟力
    ——热烈庆祝中华人民共和国成立七十周年

    +
    +

    70年前的10月1日,第一面五星红旗冉冉升起,新生的人民共和国迎着朝阳出发,一路披荆斩棘,一路凯歌行进,把一个又一个胜利写在这片古老的土地上。

    +

    70年后,迎着又一个10月1日的晨曦,新长征路上的人民共和国,重整行装再出发。在新中国成立70周年的历史性时刻,近14亿中华儿女满怀喜悦和豪情,共庆人民共和国华诞,共享伟大祖国荣光!

    +

    时间是伟大的书写者,记录走过的足迹,写下历史的华章。新中国成立70年来,中国大地沧海桑田,我们伟大祖国的面貌、伟大人民的面貌、中华民族的面貌发生了前所未有的大变化。70年风雨兼程,70年砥砺奋进,中国共产党带领人民开启筚路蓝缕的创业征程,掀起气壮山河的建设浪潮,闯出波澜壮阔的改革之路,张开拥抱世界的开放胸怀,创造了世所罕见的经济快速发展奇迹和社会长期稳定奇迹。以党的十八大为标志,中国特色社会主义进入新时代,中华民族迎来了从站起来、富起来到强起来的伟大飞跃。今天,曾经温饱不足的人们,即将迈入全面小康;曾经一穷二白的中国,巍然屹立于世界东方;曾经积贫积弱的民族,迎来伟大复兴的光明前景。正如习近平总书记豪迈宣示的:“历史充分证明,中国共产党和中国人民不仅善于打破一个旧世界,而且善于建设一个新世界。展望未来,中国的发展前景无限美好。”

    +

    雄关漫道真如铁,人间正道是沧桑。70年来新中国的发展历程,充满着苦难和辉煌、曲折和胜利、付出和收获。习近平总书记高度评价:“无论是在中华民族历史上,还是在世界历史上,这都是一部感天动地的奋斗史诗。”

    +

    1949—2019,这一部感天动地的奋斗史诗,印证了中国共产党人的初心和使命。实现中华民族伟大复兴,是近代以来中华民族最伟大的梦想。中国共产党一经成立,就义无反顾肩负起“为中国人民谋幸福、为中华民族谋复兴”的历史使命。近百年来,无论是弱小还是强大,无论是顺境还是逆境,我们党都初心不改、矢志不渝,团结带领人民历经千难万险,付出巨大牺牲,敢于面对曲折,勇于修正错误,攻克了一个又一个看似不可攻克的难关,创造了一个又一个彪炳史册的人间奇迹。新中国70年巨变的根本原因,70年历史性变革的内在逻辑,就是中国共产党的领导。中国共产党领导是中国特色社会主义最本质的特征,是中国特色社会主义制度的最大优势。在前进道路上,这个立志于千秋伟业的人民政党,牢记初心使命、推进自我革命,始终是中国人民和中华民族的主心骨,始终是复兴征程上的坚强领导核心。

    +

    1949—2019,这一部感天动地的奋斗史诗,彰显了亿万人民的奋斗与豪情。“人民是共和国的坚实根基,人民是我们执政的最大底气。”亿万人胼手胝足的勤劳奋斗,成为一代又一代中国人的集体记忆;无数人奋勇向前的铿锵步履,汇成新中国70年发展壮大的雄浑乐章。今天,中国人民拥有的一切,都是拼搏奋斗干出来的,凝聚着追梦人的聪明才智,浸透着奋斗者的辛勤汗水。依靠人民的支持和信任,“与人民心心相印、与人民同甘共苦、与人民团结奋斗”,我们书写了无愧于时代、无愧于人民、无愧于历史的业绩。有创造历史的激情,有实现梦想的能力,有续写奇迹的信心,亿万人民撸起袖子加油干,一定能把我们的人民共和国建设得更加繁荣富强。

    +

    1949—2019,这一部感天动地的奋斗史诗,铸就了中国特色社会主义的成功与辉煌。在新中国70年的持续探索中,特别是在改革开放40多年的伟大实践中,我们开创和发展了中国特色社会主义,从根本上改变了中国人民和中华民族的前途命运。治理中国这样一个大国不容易,但我们交出了一份优异的答卷。中国特色社会主义的巨大成功,用事实宣告了“历史终结论”的破产,宣告了各国最终都要以西方制度模式为归宿的单线式历史观的破产。70年来形成的中国特色社会主义制度和国家治理体系,显示出强大生命力和巨大优越性。今天,我们的道路越走越宽广、我们的理论不断发展、我们的制度日趋成熟、我们的文化持续繁荣。历史必将证明,中国特色社会主义,是一条引领中华民族走向伟大复兴的必由之路。

    +

    大道之行,天下为公。从一个积贫积弱的落后国家发展成为世界第二大经济体,中国靠的不是对外扩张和殖民掠夺,而是始终不渝走和平发展之路。70年来,中国专注于“把自己的事情办好”,走出了一条现代化的新路。多年来中国对世界经济增长贡献率超过30%,已连续13年成为世界经济增长的“第一引擎”,更以推动“一带一路”建设、构建人类命运共同体展现出一个大国担当、开放的胸怀。中国特色社会主义道路、理论、制度、文化不断发展,拓展了发展中国家走向现代化的途径,给世界上那些既希望加快发展又希望保持自身独立性的国家和民族提供了全新选择,为解决人类问题贡献了中国智慧和中国方案。世界命运握在各国人民手中,人类前途系于各国人民的抉择。中国人民愿同各国人民一道,推动人类命运共同体建设,共同创造人类的美好未来。

    +

    时代大潮滚滚向前,复兴伟力不可阻挡。当今世界正经历百年未有之大变局,实现中华民族伟大复兴正处于关键时期,我们正在进行具有许多新的历史特点的伟大斗争。展望未来,决胜全面小康、开启强国征程,中华民族伟大复兴绝不是轻轻松松、敲锣打鼓就能实现的。对历史最好的致敬,是书写新的历史;对未来最好的把握,就是开创更美好的未来。让我们更加紧密地团结在以习近平同志为核心的党中央周围,增强“四个意识”、坚定“四个自信”、做到“两个维护”,万众一心、众志成城,在实现中华民族伟大复兴的新长征中创造新的更大奇迹!

    +

    祝福伟大祖国更加繁荣昌盛!   

    +

    祝福中华民族昂首走向复兴!

    +

    说在最后

    慢慢看视频暂停截图上传,插入对应的文字后面,用时几个小时,整理不易,且看且珍惜。
    转载请标明出处,由辣椒の酱收集整理。

    +
    发布于

    2019-10-13

    更新于

    2025-01-21

    许可协议

    评论

    :D 一言句子获取中...

    加载中,最新评论有1分钟缓存...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/English/grammar/index.html b/categories/English/grammar/index.html new file mode 100644 index 0000000000..e58d755880 --- /dev/null +++ b/categories/English/grammar/index.html @@ -0,0 +1,199 @@ + +分类: grammar - 辣椒の酱 + +
    英语语法-基本语法
    英语语法-句子类型
    英语语法-状语从句
    英语语法-形容词adjective
    英语语法-限定词2
    英语语法-限定词1
    英语语法-完成时

    英语语法-完成时

    现在完成时(一):开始于过去的动作一直持续到现在,有可能继续持续。谓语动词为延续性动词

    I have lived here for 3 years. 我仍然住在这里,而且还可能继续住下去。

    +

    如果在搬家时说这句话,则live这件事只持续到目前为止。

    +

    The teacher has taught in this school since I came here.

    英语语法-完成进行时

    英语语法-完成进行时

    现在完成进行时

    (一)到现在仍在延续的动作

    1. 与一段时间连用:强调动作的持续性,开始于过去的动作持续到现在,并且还会继续持续
    常与for + 时间段、since + 时间点、all morning、all day、all week表示段时间的状语连用

    +

    ​ It began raining two hours ago and it’s still raining. It has been raining for two hours.

    英语语法-人称代词
    英语语法-名词从句
    英语语法-句子简化
    英语语法-介词
    英语语法-基本句子结构
    英语语法-关系从句
    英语语法-副词
    英语语法-动名词
    英语语法-动词不定式
    英语语法-定语从句
    英语语法-被动语态

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/English/index.html b/categories/English/index.html new file mode 100644 index 0000000000..009cc8d884 --- /dev/null +++ b/categories/English/index.html @@ -0,0 +1,199 @@ + +分类: English - 辣椒の酱 + +
    英语语法-基本语法
    英语语法-句子类型
    英语语法-状语从句
    英语语法-形容词adjective
    英语语法-限定词2
    英语语法-限定词1
    英语语法-完成时

    英语语法-完成时

    现在完成时(一):开始于过去的动作一直持续到现在,有可能继续持续。谓语动词为延续性动词

    I have lived here for 3 years. 我仍然住在这里,而且还可能继续住下去。

    +

    如果在搬家时说这句话,则live这件事只持续到目前为止。

    +

    The teacher has taught in this school since I came here.

    英语语法-完成进行时

    英语语法-完成进行时

    现在完成进行时

    (一)到现在仍在延续的动作

    1. 与一段时间连用:强调动作的持续性,开始于过去的动作持续到现在,并且还会继续持续
    常与for + 时间段、since + 时间点、all morning、all day、all week表示段时间的状语连用

    +

    ​ It began raining two hours ago and it’s still raining. It has been raining for two hours.

    英语语法-人称代词
    英语语法-名词从句
    英语语法-句子简化
    英语语法-介词
    英语语法-基本句子结构
    英语语法-关系从句
    英语语法-副词
    英语语法-动名词
    英语语法-动词不定式
    英语语法-定语从句
    英语语法-被动语态

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/algorithm/index.html b/categories/algorithm/index.html new file mode 100644 index 0000000000..6ef9b68c8c --- /dev/null +++ b/categories/algorithm/index.html @@ -0,0 +1,167 @@ + +分类: algorithm - 辣椒の酱 + +
    算法成长之路leetcode21-22
    算法成长之路leetcode19-20
    算法成长之路leetcode17-18
    算法成长之路leetcode15-16
    算法成长之路leetcode13-14
    贪心算法解析示例

    贪心算法解析示例

    定义

    贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解

    +

    贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

    算法成长之路leetcode11-12
    动态规划DP算法详解

    动态规划DP算法详解

    定义

    动态规划(dynamic programing)和分治法类似,都是通过组合子问题的解来求解原问题的解。(在经典排序算法中的二路归并排序和快速排序都用到了分而治之的思想-分治法)。

    +

    分治法是将原问题划分为没有交集,相互独立的子问题,并分别求解后再进行合并,求出原问题的解。

    +

    动态规划应用于子问题重叠的情况,即不同的子问题具有公共的子子问题。分治法会做许多不必要的工作,它会反复地求解那些公共子问题。动态规划算法对每个子问题只求解一次,将其解保存在一个表格中,从而无需每次求解一个子子问题时都需要重新计算。

    算法成长之路leetcode9-10
    算法成长之路leetcode7-8
    算法成长之路leetcode5-6
    二分查找法模板的基本思想-leetcode35
    算法成长之路leetcode1-4
    leetcode-2-Add Two Numbers

    leetcode-2-Add Two Numbers

    Add Two Numbers

    +

    You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
    You may assume the two numbers do not contain any leading zero, except the number 0 itself.

      
    leetcode-1-Two Sum

    leetcode-1-Two Sum

    description

    +

    Given an array of integers, return indices of the two numbers such that they add up to a specific target.
    You may assume that each input would have exactly one solution, and you may not use the same element twice.
    Example:
    Given nums = [2, 7, 11, 15], target = 9,
    Because nums[0] + nums[1] = 2 + 7 = 9,
    return [0, 1].

      

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/develop/git/index.html b/categories/develop/git/index.html new file mode 100644 index 0000000000..c4e1d655a0 --- /dev/null +++ b/categories/develop/git/index.html @@ -0,0 +1,160 @@ + +分类: git - 辣椒の酱 + +
    github gpg failed to sign the data

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/develop/index.html b/categories/develop/index.html new file mode 100644 index 0000000000..ce1b9d5743 --- /dev/null +++ b/categories/develop/index.html @@ -0,0 +1,160 @@ + +分类: develop - 辣椒の酱 + +
    github gpg failed to sign the data
    intellj idea 详细调试代码debug

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/health/index.html b/categories/health/index.html new file mode 100644 index 0000000000..eb227abc41 --- /dev/null +++ b/categories/health/index.html @@ -0,0 +1,160 @@ + +分类: health - 辣椒の酱 + +
    常见隔夜菜谨慎食用

    常见隔夜菜谨慎食用

    我们有许多习惯,总是重复来,重复去,就像上世纪中的人们带着保温盒去上班,现在的人又重回带着饭盒去公司的现象。自己带饭去公司吃的话,不仅大大地节省了一笔吃外卖的费用,而且菜色也可以随便换。但是,很多人带的都是前一天晚上就准备好的隔夜菜,这样对我们的身体健康到底是有益还是有害呢?

      

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 0000000000..72d3bf171f --- /dev/null +++ b/categories/index.html @@ -0,0 +1,160 @@ + +分类 - 辣椒の酱 + +

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/ios/index.html b/categories/ios/index.html new file mode 100644 index 0000000000..748cfc50d4 --- /dev/null +++ b/categories/ios/index.html @@ -0,0 +1,160 @@ + +分类: ios - 辣椒の酱 + +
    苹果6s ios12 nfc 模拟门禁

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/java/JVM/index.html b/categories/java/JVM/index.html new file mode 100644 index 0000000000..6ce5b6bc68 --- /dev/null +++ b/categories/java/JVM/index.html @@ -0,0 +1,162 @@ + +分类: JVM - 辣椒の酱 + +
    Java 垃圾回收

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/java/elasticsearch6/index.html b/categories/java/elasticsearch6/index.html new file mode 100644 index 0000000000..eec930d8f1 --- /dev/null +++ b/categories/java/elasticsearch6/index.html @@ -0,0 +1,168 @@ + +分类: elasticsearch6 - 辣椒の酱 + +
    elasticsearch6.x倒排索引和分词
    Elasticsearch常用工具api
    elasticsearch6 query 全文查询与词项查询

    elasticsearch6 query 全文查询与词项查询

    query

    全文查询

      +
    1. QueryBuilders.matchQuery(“filed”,”value”).operator(Operator.AND); // 对查询的语句进行分词,分词后的词任意一个匹配doc都能查出来 term query 查询的是词项<分词后的> (eg:Java编程思想) Java编程 term query 不能查到 分词后变成(Java 编程 思想) matchQuery能查到
    2. +
    3. QueryBuilders.matchPhraseQuery(“field”,”value”);
      对value进行分词,可以自定义分词器,满足两个条件才能被搜到:
        +
      • 分词后的所有词项都要匹配原字段
      • +
      • 顺序还需要一致

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/java/index.html b/categories/java/index.html new file mode 100644 index 0000000000..e52a0a30b7 --- /dev/null +++ b/categories/java/index.html @@ -0,0 +1,230 @@ + +分类: java - 辣椒の酱 + +
    springboot websocket server服务端代码demo
    springboot接入dubbo-nacos注册中心
    Java-策略模式

    Java-策略模式

    策略模式遵循开闭原则,实现代码的解耦合。扩展新的方法时也比较方便,只需要继承策略接口就好了上面列出的这两点算是策略模式的优点了,但是不是说他就是完美的,有很多缺点仍然需要我们去掌握和理解。
    策略模式把对象本身和运算规则区分开来,因此我们整个模式也分为三个部分。

    +
      +
    • 环境类(Context):用来操作策略的上下文环境,也就是我们游客。
    • +
    • 抽象策略类(Strategy):策略的抽象,出行方式的抽象
    • +
    • 具体策略类(ConcreteStrategy):具体的策略实现,每一种出行方式的具体实现。
    spring-boot实现动态增删启停定时任务

    spring-boot实现动态增删启停定时任务

    在spring boot项目中,可以通过@EnableScheduling注解和@Scheduled注解实现定时任务,也可以通过SchedulingConfigurer接口来实现定时任务。但是这两种方式不能动态添加、删除、启动、停止任务。要实现动态增删启停定时任务功能,比较广泛的做法是集成Quartz框架。但是本人的开发原则是:在满足项目需求的情况下,尽量少的依赖其它框架,避免项目过于臃肿和复杂。查看spring-context这个jar包中org.springframework.scheduling.ScheduledTaskRegistrar这个类的源代码,发现可以通过改造这个类就能实现动态增删启停定时任务功能。

    SpringBoot@Valid注解以及全局异常处理器优雅处理参数验证

    SpringBoot@Valid注解以及全局异常处理器优雅处理参数验证

    一、为什么使用 @Valid 来验证参数

    在平常通过 Spring 框架写代码时候,会经常写接口类,相信大家对该类的写法非常熟悉。在写接口时经常要写效验请求参数逻辑,这时候我们会常用做法是写大量的 ifif else 类似这样的代码来做判断,如下:

    Spring的Bean生命周期

    Spring的Bean生命周期

    一、获取Bean

    第一阶段获取Bean

    这里的流程图的入口在 AbstractBeanFactory类的 doGetBean方法,这里可以配合前面的 getBean方法分析文章进行阅读。主要流程就是

    +

    1、先处理Bean 的名称,因为如果以“&”开头的Bean名称表示获取的是对应的FactoryBean对象;
    2、从缓存中获取单例Bean,有则进一步判断这个Bean是不是在创建中,如果是的就等待创建完毕,否则直接返回这个Bean对象
    3、如果不存在单例Bean缓存,则先进行循环依赖的解析
    4、解析完毕之后先获取父类BeanFactory,获取到了则调用父类的getBean方法,不存在则先合并然后创建Bean

    springboot优雅的停止服务
    springboot-restful-swagger实战
    hash冲突开放地址法rehash
    原码补码异或与位运算移位知识点

    原码补码异或与位运算移位知识点

    异或,英文为exclusive OR,缩写成xor
    异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:
    a⊕b = (¬a ∧ b) ∨ (a ∧¬b)
    如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
    异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法。

    Spring 如何解决循环依赖

    Spring 如何解决循环依赖

    过程演练

    关于Spring bean的创建,其本质上还是一个对象的创建,既然是对象,读者朋友一定要明白一点就是,一个完整的对象包含两部分:当前对象实例化对象属性的实例化。在Spring中,对象的实例化是通过反射实现的,而对象的属性则是在对象实例化之后通过一定的方式设置的。这个过程可以按照如下方式进行理解:

    Spring cloud feign重试问题排查

    Spring cloud feign重试问题排查

    Feign设置超时时间

    使用Feign调用接口分两层,ribbon的调用hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间。

    +

    Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里。

    Java日志的正确使用方法
    Java容器集合
    Java并发相关知识点

    Java并发相关知识点

    +

    互斥同步最主要的问题就是线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步。
    互斥同步属于一种悲观的并发策略,总是认为只要不去做正确的同步措施,那就肯定会出现问题。无论共享数据是否真的会出现竞争,它都要进行加锁(这里讨论的是概念模型,实际上虚拟机会优化掉很大一部分不必要的加锁)、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。

    +
    Java 垃圾回收
    Java BIO NIO AIO区别与使用
    java注解Annotation说明实例
    elasticsearch6.x倒排索引和分词
    Elasticsearch常用工具api
    java基础-static关键字
    java基础-final关键字
    Java设计模式之代理模式

    Java设计模式之代理模式

    代理模式

    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
    这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法

    +

    举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子.

    Java设计模式之命令模式
    java 8部分读书笔记

    java 8部分读书笔记

    Lambda 表达式

      +
    1. Lambda 表达式引用的是值,不是变量。

      +
    2. +
    3. Lambda 表达式中的变量只能是final类型,只能给变量赋值一次。

      +
      1
      2
      3
      String name = getUserName();
      name = formatUesrName();
      button.addActionListener(event -> System.out.println("Hi" + name))
      + +

      如上代码将不会编译通过,name被赋值多次。

      +
    4. +
    Java设计模式之适配器模式
    Java设计模式之装饰者模式

    Java设计模式之装饰者模式

    问题引入

    咖啡店的类设计:

    +
      +
    1. 一个饮料基类,各种饮料类继承这个基类,并且计算各自的价钱。
    2. +
    3. 饮料中需要加入各种调料,考虑在基类中加入一些布尔值变量代表是否加入各种调料,基类的cost()中的计算各种调料的价钱,子类覆盖cost(),并且在其中调用超类的cost(),加上特定饮料的价钱,计算出子类特定饮料的价钱。
    4. +
    +

    缺点:类数量爆炸、基类加入的新功能并不适用于所有的子类、调料价钱的改变、新调料的出现都会要求改变现有代码;有的子类并不适合某些调料等情况……

    Java设计模式之工厂模式

    Java设计模式之工厂模式

    工厂模式

    序言

    工厂模式在《Java与模式》中分为三类:

    +
      +
    1. 简单工厂模式(Simple Factory):不利于产生系列产品;

      +
    2. +
    3. 工厂方法模式(Factory Method):又称为多形性工厂;

      +
    4. +
    5. 抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;

    Effective-Java-2-遇到多个构造器参数时考虑用构建器

    Effective-Java-2-遇到多个构造器参数时考虑用构建器

    遇到多个构造器参数时考虑用构建器

    静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。当有超过20个可选域是必须的时候,对于此种情况,程序员一般考虑采用重叠构造器模式。这种模式下,提供第一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,以此类推,最后一个构造器包含所有的参数。

    Java设计模式之单例模式
    Java设计模式之观察者模式

    Java设计模式之观察者模式

    定义

    +

    在阎宏博士的《JAVA与模式》一书中开头是这样描述观察者(Observer)模式的:
    观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

    +
    Immutable Object(不可变对象)模式

    Immutable Object(不可变对象)模式

    +

    多线程下,一个对象会被多个线程共享,存在多线程并发地修改对象的属性,需要做些同步访问控制,
    如显示锁,CAS操作,会带来额外的开销和问题,如上下文切换、等待时间、ABA问题。Immutable Object
    模式意图通过使用对外可见的状态不可变的对象,使得天生具有线程安全性。

    +
    elasticsearch6 query 全文查询与词项查询

    elasticsearch6 query 全文查询与词项查询

    query

    全文查询

      +
    1. QueryBuilders.matchQuery(“filed”,”value”).operator(Operator.AND); // 对查询的语句进行分词,分词后的词任意一个匹配doc都能查出来 term query 查询的是词项<分词后的> (eg:Java编程思想) Java编程 term query 不能查到 分词后变成(Java 编程 思想) matchQuery能查到
    2. +
    3. QueryBuilders.matchPhraseQuery(“field”,”value”);
      对value进行分词,可以自定义分词器,满足两个条件才能被搜到:
        +
      • 分词后的所有词项都要匹配原字段
      • +
      • 顺序还需要一致

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/java/java\345\237\272\347\241\200/index.html" "b/categories/java/java\345\237\272\347\241\200/index.html" new file mode 100644 index 0000000000..f891f99182 --- /dev/null +++ "b/categories/java/java\345\237\272\347\241\200/index.html" @@ -0,0 +1,184 @@ + +分类: java基础 - 辣椒の酱 + +
    hash冲突开放地址法rehash
    原码补码异或与位运算移位知识点

    原码补码异或与位运算移位知识点

    异或,英文为exclusive OR,缩写成xor
    异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:
    a⊕b = (¬a ∧ b) ∨ (a ∧¬b)
    如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
    异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法。

    Java日志的正确使用方法
    Java容器集合
    Java BIO NIO AIO区别与使用
    java注解Annotation说明实例
    java基础-static关键字
    java基础-final关键字
    java 8部分读书笔记

    java 8部分读书笔记

    Lambda 表达式

      +
    1. Lambda 表达式引用的是值,不是变量。

      +
    2. +
    3. Lambda 表达式中的变量只能是final类型,只能给变量赋值一次。

      +
      1
      2
      3
      String name = getUserName();
      name = formatUesrName();
      button.addActionListener(event -> System.out.println("Hi" + name))
      + +

      如上代码将不会编译通过,name被赋值多次。

      +
    4. +
    Immutable Object(不可变对象)模式

    Immutable Object(不可变对象)模式

    +

    多线程下,一个对象会被多个线程共享,存在多线程并发地修改对象的属性,需要做些同步访问控制,
    如显示锁,CAS操作,会带来额外的开销和问题,如上下文切换、等待时间、ABA问题。Immutable Object
    模式意图通过使用对外可见的状态不可变的对象,使得天生具有线程安全性。

    +

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/java/spring/index.html b/categories/java/spring/index.html new file mode 100644 index 0000000000..1822bcb3fb --- /dev/null +++ b/categories/java/spring/index.html @@ -0,0 +1,161 @@ + +分类: spring - 辣椒の酱 + +
    Spring的Bean生命周期

    Spring的Bean生命周期

    一、获取Bean

    第一阶段获取Bean

    这里的流程图的入口在 AbstractBeanFactory类的 doGetBean方法,这里可以配合前面的 getBean方法分析文章进行阅读。主要流程就是

    +

    1、先处理Bean 的名称,因为如果以“&”开头的Bean名称表示获取的是对应的FactoryBean对象;
    2、从缓存中获取单例Bean,有则进一步判断这个Bean是不是在创建中,如果是的就等待创建完毕,否则直接返回这个Bean对象
    3、如果不存在单例Bean缓存,则先进行循环依赖的解析
    4、解析完毕之后先获取父类BeanFactory,获取到了则调用父类的getBean方法,不存在则先合并然后创建Bean


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/java/springboot/index.html b/categories/java/springboot/index.html new file mode 100644 index 0000000000..9fdd6c275b --- /dev/null +++ b/categories/java/springboot/index.html @@ -0,0 +1,165 @@ + +分类: springboot - 辣椒の酱 + +
    springboot接入dubbo-nacos注册中心
    spring-boot实现动态增删启停定时任务

    spring-boot实现动态增删启停定时任务

    在spring boot项目中,可以通过@EnableScheduling注解和@Scheduled注解实现定时任务,也可以通过SchedulingConfigurer接口来实现定时任务。但是这两种方式不能动态添加、删除、启动、停止任务。要实现动态增删启停定时任务功能,比较广泛的做法是集成Quartz框架。但是本人的开发原则是:在满足项目需求的情况下,尽量少的依赖其它框架,避免项目过于臃肿和复杂。查看spring-context这个jar包中org.springframework.scheduling.ScheduledTaskRegistrar这个类的源代码,发现可以通过改造这个类就能实现动态增删启停定时任务功能。

    SpringBoot@Valid注解以及全局异常处理器优雅处理参数验证

    SpringBoot@Valid注解以及全局异常处理器优雅处理参数验证

    一、为什么使用 @Valid 来验证参数

    在平常通过 Spring 框架写代码时候,会经常写接口类,相信大家对该类的写法非常熟悉。在写接口时经常要写效验请求参数逻辑,这时候我们会常用做法是写大量的 ifif else 类似这样的代码来做判断,如下:

    springboot优雅的停止服务
    springboot-restful-swagger实战

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/java/\345\271\266\345\217\221/index.html" "b/categories/java/\345\271\266\345\217\221/index.html" new file mode 100644 index 0000000000..c9dbc5063a --- /dev/null +++ "b/categories/java/\345\271\266\345\217\221/index.html" @@ -0,0 +1,162 @@ + +分类: 并发 - 辣椒の酱 + +
    Java并发相关知识点

    Java并发相关知识点

    +

    互斥同步最主要的问题就是线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步。
    互斥同步属于一种悲观的并发策略,总是认为只要不去做正确的同步措施,那就肯定会出现问题。无论共享数据是否真的会出现竞争,它都要进行加锁(这里讨论的是概念模型,实际上虚拟机会优化掉很大一部分不必要的加锁)、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。

    +

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/java/\346\241\206\346\236\266/index.html" "b/categories/java/\346\241\206\346\236\266/index.html" new file mode 100644 index 0000000000..d97e6180d2 --- /dev/null +++ "b/categories/java/\346\241\206\346\236\266/index.html" @@ -0,0 +1,162 @@ + +分类: 框架 - 辣椒の酱 + +
    springboot websocket server服务端代码demo
    Spring 如何解决循环依赖

    Spring 如何解决循环依赖

    过程演练

    关于Spring bean的创建,其本质上还是一个对象的创建,既然是对象,读者朋友一定要明白一点就是,一个完整的对象包含两部分:当前对象实例化对象属性的实例化。在Spring中,对象的实例化是通过反射实现的,而对象的属性则是在对象实例化之后通过一定的方式设置的。这个过程可以按照如下方式进行理解:

    Spring cloud feign重试问题排查

    Spring cloud feign重试问题排查

    Feign设置超时时间

    使用Feign调用接口分两层,ribbon的调用hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间。

    +

    Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/java/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" "b/categories/java/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" new file mode 100644 index 0000000000..41b41f9f30 --- /dev/null +++ "b/categories/java/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" @@ -0,0 +1,186 @@ + +分类: 设计模式 - 辣椒の酱 + +
    Java-策略模式

    Java-策略模式

    策略模式遵循开闭原则,实现代码的解耦合。扩展新的方法时也比较方便,只需要继承策略接口就好了上面列出的这两点算是策略模式的优点了,但是不是说他就是完美的,有很多缺点仍然需要我们去掌握和理解。
    策略模式把对象本身和运算规则区分开来,因此我们整个模式也分为三个部分。

    +
      +
    • 环境类(Context):用来操作策略的上下文环境,也就是我们游客。
    • +
    • 抽象策略类(Strategy):策略的抽象,出行方式的抽象
    • +
    • 具体策略类(ConcreteStrategy):具体的策略实现,每一种出行方式的具体实现。
    Java设计模式之代理模式

    Java设计模式之代理模式

    代理模式

    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
    这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法

    +

    举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子.

    Java设计模式之命令模式
    Java设计模式之适配器模式
    Java设计模式之装饰者模式

    Java设计模式之装饰者模式

    问题引入

    咖啡店的类设计:

    +
      +
    1. 一个饮料基类,各种饮料类继承这个基类,并且计算各自的价钱。
    2. +
    3. 饮料中需要加入各种调料,考虑在基类中加入一些布尔值变量代表是否加入各种调料,基类的cost()中的计算各种调料的价钱,子类覆盖cost(),并且在其中调用超类的cost(),加上特定饮料的价钱,计算出子类特定饮料的价钱。
    4. +
    +

    缺点:类数量爆炸、基类加入的新功能并不适用于所有的子类、调料价钱的改变、新调料的出现都会要求改变现有代码;有的子类并不适合某些调料等情况……

    Java设计模式之工厂模式

    Java设计模式之工厂模式

    工厂模式

    序言

    工厂模式在《Java与模式》中分为三类:

    +
      +
    1. 简单工厂模式(Simple Factory):不利于产生系列产品;

      +
    2. +
    3. 工厂方法模式(Factory Method):又称为多形性工厂;

      +
    4. +
    5. 抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;

    Java设计模式之单例模式
    Java设计模式之观察者模式

    Java设计模式之观察者模式

    定义

    +

    在阎宏博士的《JAVA与模式》一书中开头是这样描述观察者(Observer)模式的:
    观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

    +

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/java/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" "b/categories/java/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" new file mode 100644 index 0000000000..bd5a45a763 --- /dev/null +++ "b/categories/java/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" @@ -0,0 +1,160 @@ + +分类: 读书笔记 - 辣椒の酱 + +
    Effective-Java-2-遇到多个构造器参数时考虑用构建器

    Effective-Java-2-遇到多个构造器参数时考虑用构建器

    遇到多个构造器参数时考虑用构建器

    静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。当有超过20个可选域是必须的时候,对于此种情况,程序员一般考虑采用重叠构造器模式。这种模式下,提供第一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,以此类推,最后一个构造器包含所有的参数。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/marathon/index.html b/categories/marathon/index.html new file mode 100644 index 0000000000..cbb87c19b1 --- /dev/null +++ b/categories/marathon/index.html @@ -0,0 +1,162 @@ + +分类: marathon - 辣椒の酱 + +
    马拉松-2019西昌最美赛道邛海马拉松

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/private/index.html b/categories/private/index.html new file mode 100644 index 0000000000..13669a165d --- /dev/null +++ b/categories/private/index.html @@ -0,0 +1,164 @@ + +分类: private - 辣椒の酱 + +
    2019成长记01

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/python3/index.html b/categories/python3/index.html new file mode 100644 index 0000000000..b3633f81e3 --- /dev/null +++ b/categories/python3/index.html @@ -0,0 +1,161 @@ + +分类: python3 - 辣椒の酱 + +
    一张图学会python3

    一张图学会python3

    这张图包含了Python 3 几乎所有的知识点,包括输出、输入、变量、赋值、计算、模块、函数、参数、返回值、缩进、注释、for循环、条件判断、逻辑运算、字符串及格式化、转义字符、类型转换、列表,甚至也包含了点面向对象的应用(调用对象的方法)。

    +

    跟着这张图片一步一步学习,学会 Python指日可待!


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/think/index.html b/categories/think/index.html new file mode 100644 index 0000000000..98eae2ba78 --- /dev/null +++ b/categories/think/index.html @@ -0,0 +1,173 @@ + +分类: think - 辣椒の酱 + +
    2019年终总结
    Hello blog
    Hello World

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/categories/travel/index.html b/categories/travel/index.html new file mode 100644 index 0000000000..18b6723491 --- /dev/null +++ b/categories/travel/index.html @@ -0,0 +1,160 @@ + +分类: travel - 辣椒の酱 + +

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\211\215\347\253\257\346\212\200\346\234\257/index.html" "b/categories/\345\211\215\347\253\257\346\212\200\346\234\257/index.html" new file mode 100644 index 0000000000..71dd852e41 --- /dev/null +++ "b/categories/\345\211\215\347\253\257\346\212\200\346\234\257/index.html" @@ -0,0 +1,160 @@ + +分类: 前端技术 - 辣椒の酱 + +
    替代web-cookie存储方案实现

    替代web-cookie存储方案实现

    随着移动网络的发展与演化,我们手机上现在除了有原生 App,还能跑“WebApp”——它即开即用,用完即走。一个优秀的 WebApp 甚至可以拥有和原生 App 媲美的功能和体验。
    WebApp 优异的性能表现,有一部分原因要归功于浏览器存储技术的提升。cookie存储数据的功能已经很难满足开发所需,逐渐被WebStorage、IndexedDB所取代,本文将介绍这几种存储方式的差异和优缺点。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Git/index.html" "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Git/index.html" new file mode 100644 index 0000000000..3db4ee12ad --- /dev/null +++ "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Git/index.html" @@ -0,0 +1,164 @@ + +分类: Git - 辣椒の酱 + +
    Git-rebase-用法示例小结

    Git-rebase-用法示例小结

    看过上一篇文章【Git如何优雅地回退代码】的小伙伴们,肯定还有很多跟我一样对rebase的使用还是云里雾里的,这篇文章将使你彻底搞明白怎么使用。
    rebase在git中是一个非常有魅力的命令,使用得当会极大提高自己的工作效率;相反,如果乱用,会给团队中其他人带来麻烦。它的作用简要概括为:可以对某一段线性提交历史进行编辑、删除、复制、粘贴;因此,合理使用rebase命令可以使我们的提交历史干净、简洁!

    +

    前提:不要通过rebase对任何已经提交到公共仓库中的commit进行修改(你自己一个人玩的分支除外)

    Git如何优雅地回退代码

    Git如何优雅地回退代码

    前言

    从接触编程就开始使用 Git 进行代码管理,先是自己玩 Github,又在工作中使用 Gitlab,虽然使用时间挺长,可是也只进行一些常用操作,如推拉代码、提交、合并等,更复杂的操作没有使用过,看过的教程也逐渐淡忘了,有些对不起 Linus 大神。

    +

    出来混总是要还的,前些天就遇到了 Git 里一种十分糟心的场景,并为之前没有深入理解 Git 命令付出了一下午时间的代价。

    +

    先介绍一下这种场景,我们一个项目从 N 版本升到 A 版本时引入了另一项目的 jar 包,又陆续发布了 B、C 版本,但在 C 版本后忽然发现了 A 版本引入的 jar 包有极大的性能问题,B、C 版本都是基于 A 版本发布的,要修复 jar 包性能问题,等 jar 包再发版还得几天,可此时线上又有紧急的 Bug 要修,于是就陷入了进退两难的境地。

    +

    最后决定先将代码回退到 A 版本之前,再基于旧版本修复 Bug,也就开始了五个小时的受苦之路。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Vim/index.html" "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Vim/index.html" new file mode 100644 index 0000000000..ed2249da88 --- /dev/null +++ "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/Vim/index.html" @@ -0,0 +1,162 @@ + +分类: Vim - 辣椒の酱 + +
    Vim基本入门操作

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/docker/index.html" "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/docker/index.html" new file mode 100644 index 0000000000..90b14e2b77 --- /dev/null +++ "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/docker/index.html" @@ -0,0 +1,160 @@ + +分类: docker - 辣椒の酱 + +
    docker安装与使用

    docker安装与使用

    简介

    Docker简介

    Docker 使用客户端-服务器 (C/S) 架构模式。Docker 客户端会与 Docker 守护进程进行通信。Docker 守护进程会处理复杂繁重的任务,例如建立、运行、发布你的 Docker 容器。Docker 客户端和守护进程可以运行在同一个系统上,当然你也可以使用 Docker 客户端去连接一个远程的 Docker 守护进程。Docker 客户端和守护进程之间通过 socket 或者 RESTful API 进行通信。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/index.html" "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/index.html" new file mode 100644 index 0000000000..f043f23a37 --- /dev/null +++ "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/index.html" @@ -0,0 +1,168 @@ + +分类: 基础工具类 - 辣椒の酱 + +
    Git-rebase-用法示例小结

    Git-rebase-用法示例小结

    看过上一篇文章【Git如何优雅地回退代码】的小伙伴们,肯定还有很多跟我一样对rebase的使用还是云里雾里的,这篇文章将使你彻底搞明白怎么使用。
    rebase在git中是一个非常有魅力的命令,使用得当会极大提高自己的工作效率;相反,如果乱用,会给团队中其他人带来麻烦。它的作用简要概括为:可以对某一段线性提交历史进行编辑、删除、复制、粘贴;因此,合理使用rebase命令可以使我们的提交历史干净、简洁!

    +

    前提:不要通过rebase对任何已经提交到公共仓库中的commit进行修改(你自己一个人玩的分支除外)

    Git如何优雅地回退代码

    Git如何优雅地回退代码

    前言

    从接触编程就开始使用 Git 进行代码管理,先是自己玩 Github,又在工作中使用 Gitlab,虽然使用时间挺长,可是也只进行一些常用操作,如推拉代码、提交、合并等,更复杂的操作没有使用过,看过的教程也逐渐淡忘了,有些对不起 Linus 大神。

    +

    出来混总是要还的,前些天就遇到了 Git 里一种十分糟心的场景,并为之前没有深入理解 Git 命令付出了一下午时间的代价。

    +

    先介绍一下这种场景,我们一个项目从 N 版本升到 A 版本时引入了另一项目的 jar 包,又陆续发布了 B、C 版本,但在 C 版本后忽然发现了 A 版本引入的 jar 包有极大的性能问题,B、C 版本都是基于 A 版本发布的,要修复 jar 包性能问题,等 jar 包再发版还得几天,可此时线上又有紧急的 Bug 要修,于是就陷入了进退两难的境地。

    +

    最后决定先将代码回退到 A 版本之前,再基于旧版本修复 Bug,也就开始了五个小时的受苦之路。

    docker安装与使用

    docker安装与使用

    简介

    Docker简介

    Docker 使用客户端-服务器 (C/S) 架构模式。Docker 客户端会与 Docker 守护进程进行通信。Docker 守护进程会处理复杂繁重的任务,例如建立、运行、发布你的 Docker 容器。Docker 客户端和守护进程可以运行在同一个系统上,当然你也可以使用 Docker 客户端去连接一个远程的 Docker 守护进程。Docker 客户端和守护进程之间通过 socket 或者 RESTful API 进行通信。

    Vim基本入门操作
    Java版常用正则表达式说明

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/\346\255\243\345\210\231/index.html" "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/\346\255\243\345\210\231/index.html" new file mode 100644 index 0000000000..737d397c7b --- /dev/null +++ "b/categories/\345\237\272\347\241\200\345\267\245\345\205\267\347\261\273/\346\255\243\345\210\231/index.html" @@ -0,0 +1,162 @@ + +分类: 正则 - 辣椒の酱 + +
    Java版常用正则表达式说明

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" new file mode 100644 index 0000000000..32a1f22bda --- /dev/null +++ "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" @@ -0,0 +1,177 @@ + +分类: 工具教程 - 辣椒の酱 + +
    不蒜子统计常见问题
    github Issue 作为博客微型数据库的应用

    github Issue 作为博客微型数据库的应用

    背景

    众所周知,对于hexo框架搭建的静态博客,难免会产生一些动态的数据,比如一些碎碎念、友链、音乐、时间轴等微型数据。目前一般的做法:

    +

    a.是创建一个json数据,来存储这些微型数据,但是如果数据太多的话,一是比较慢,二是有个硬伤问题,就是json数据不能分页请求,只能一次拿完,太多的话网络带宽占用太多。

    github page网站cdn优化加速

    github page网站cdn优化加速

    CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。——百度百科

    +

    放在Github的资源在国内加载速度比较慢,因此需要使用CDN加速来优化网站打开速度,jsDelivr + Github便是免费且好用的CDN,非常适合博客网站使用。

    博客源码分享

    博客源码分享

    写在前面

    +

    博客源码包括两个主题icarusnext,在主题基础之上参照各网友博客,以及自己的一些想法做出的一些修改以及增加部分新元素。 以下是修改后的需要的部分配置,其余的配置参照icarus主题配置next主题配置
    因为修改了原作者源码,有什么问题请先联系我,不要去麻烦原作者了,能自己解决的问题就不要麻烦别人了,每个人的时间都很宝贵。
    膜拜和感谢所有模块的原作者,orz👻,辛苦了。

    +
    +

    欢迎围观:博客+主题源码纯主题源码博客+主题源码 Live Demo

    博客换肤的一种实现方式思路

    博客换肤的一种实现方式思路

    +

    当博客内容很多的时候,比如需要加载很多资源文件,许多炫酷的东西的时候,可能相应的就是比较慢了(正可谓时间和空间不能兼得)。虽然目前也有很多方式手段可以提高访问速度,但是博客提供一个简洁模式还是很有必要的,萝卜青菜,各有所爱嘛。说不定很多网友就当纯的想看看文字,不需要那些花里胡哨的东西。这时候提供个清爽模式就相当有用了。

    +
    博客中gitalk最新评论的获取

    博客中gitalk最新评论的获取

    +

    博客中,对于网友的评论以及每篇文章的评论数还是很重要的。但是基于静态的页面想要存储动态的评论数据是比较难的,一般博客主题中都内置了评论插件,但是博客主题中对于最新评论的支持显示还是很少的,至少目前我是没怎么发现。博客 Powered by Hexo & Icarus,采用Gitalk评论,再次感谢此三位作者的辛勤码代码,才有了以下的内容。基于此背景基础上,聊聊最新评论的实现。

    +
    博客图片上传picgo工具github图传使用

    博客图片上传picgo工具github图传使用

    +

    摘要
    对于每一个写博客的人来说,图片是至关重要。这一路经历了多次图片的烦恼,之前选择了微博个人文章那里粘贴图片的方式上传,感觉也挺方便的。但是由于新浪的图片显示问题,如果header中不设置 标签就不能异步访问图片,导致图裂,那之恶心。然而设置之后又与网站访客统计的插件冲突,使之不能统计,真是神仙打架。无赖之下使用了PicGo工具,使用后感觉真XX方便!

    +
    安装、部分配置icarus主题中文版

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\267\245\345\205\267\346\225\231\347\250\213/\344\270\273\351\242\230\345\267\245\345\205\267/index.html" "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/\344\270\273\351\242\230\345\267\245\345\205\267/index.html" new file mode 100644 index 0000000000..c0b80d6e87 --- /dev/null +++ "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/\344\270\273\351\242\230\345\267\245\345\205\267/index.html" @@ -0,0 +1,173 @@ + +分类: 主题工具 - 辣椒の酱 + +
    github Issue 作为博客微型数据库的应用

    github Issue 作为博客微型数据库的应用

    背景

    众所周知,对于hexo框架搭建的静态博客,难免会产生一些动态的数据,比如一些碎碎念、友链、音乐、时间轴等微型数据。目前一般的做法:

    +

    a.是创建一个json数据,来存储这些微型数据,但是如果数据太多的话,一是比较慢,二是有个硬伤问题,就是json数据不能分页请求,只能一次拿完,太多的话网络带宽占用太多。

    github page网站cdn优化加速

    github page网站cdn优化加速

    CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。——百度百科

    +

    放在Github的资源在国内加载速度比较慢,因此需要使用CDN加速来优化网站打开速度,jsDelivr + Github便是免费且好用的CDN,非常适合博客网站使用。

    博客源码分享

    博客源码分享

    写在前面

    +

    博客源码包括两个主题icarusnext,在主题基础之上参照各网友博客,以及自己的一些想法做出的一些修改以及增加部分新元素。 以下是修改后的需要的部分配置,其余的配置参照icarus主题配置next主题配置
    因为修改了原作者源码,有什么问题请先联系我,不要去麻烦原作者了,能自己解决的问题就不要麻烦别人了,每个人的时间都很宝贵。
    膜拜和感谢所有模块的原作者,orz👻,辛苦了。

    +
    +

    欢迎围观:博客+主题源码纯主题源码博客+主题源码 Live Demo

    博客换肤的一种实现方式思路

    博客换肤的一种实现方式思路

    +

    当博客内容很多的时候,比如需要加载很多资源文件,许多炫酷的东西的时候,可能相应的就是比较慢了(正可谓时间和空间不能兼得)。虽然目前也有很多方式手段可以提高访问速度,但是博客提供一个简洁模式还是很有必要的,萝卜青菜,各有所爱嘛。说不定很多网友就当纯的想看看文字,不需要那些花里胡哨的东西。这时候提供个清爽模式就相当有用了。

    +
    博客中gitalk最新评论的获取

    博客中gitalk最新评论的获取

    +

    博客中,对于网友的评论以及每篇文章的评论数还是很重要的。但是基于静态的页面想要存储动态的评论数据是比较难的,一般博客主题中都内置了评论插件,但是博客主题中对于最新评论的支持显示还是很少的,至少目前我是没怎么发现。博客 Powered by Hexo & Icarus,采用Gitalk评论,再次感谢此三位作者的辛勤码代码,才有了以下的内容。基于此背景基础上,聊聊最新评论的实现。

    +
    博客图片上传picgo工具github图传使用

    博客图片上传picgo工具github图传使用

    +

    摘要
    对于每一个写博客的人来说,图片是至关重要。这一路经历了多次图片的烦恼,之前选择了微博个人文章那里粘贴图片的方式上传,感觉也挺方便的。但是由于新浪的图片显示问题,如果header中不设置 标签就不能异步访问图片,导致图裂,那之恶心。然而设置之后又与网站访客统计的插件冲突,使之不能统计,真是神仙打架。无赖之下使用了PicGo工具,使用后感觉真XX方便!

    +
    安装、部分配置icarus主题中文版

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\345\267\245\345\205\267\346\225\231\347\250\213/\345\215\232\345\256\242\347\273\237\350\256\241\346\217\222\344\273\266/index.html" "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/\345\215\232\345\256\242\347\273\237\350\256\241\346\217\222\344\273\266/index.html" new file mode 100644 index 0000000000..a0614a40d2 --- /dev/null +++ "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/\345\215\232\345\256\242\347\273\237\350\256\241\346\217\222\344\273\266/index.html" @@ -0,0 +1,164 @@ + +分类: 博客统计插件 - 辣椒の酱 + +
    不蒜子统计常见问题

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\225\260\346\215\256\345\272\223/index.html" "b/categories/\346\225\260\346\215\256\345\272\223/index.html" new file mode 100644 index 0000000000..700ebd026a --- /dev/null +++ "b/categories/\346\225\260\346\215\256\345\272\223/index.html" @@ -0,0 +1,185 @@ + +分类: 数据库 - 辣椒の酱 + +
    mysql允许最大sql语句长度配置

    mysql允许最大sql语句长度配置

    MySQL对于每个客户端连接都会分配连接buffer和结果集发送的buffer,连接buffer主要就是来接受客户端发送过来的sql语句,并且初始分配大小都是 net_buffer_length,可以动态增长,最多可以达到 max_allow_packet大小。这个参数是会话只读的,言外之意就是只能全局修改,新建连接才生效。max_allow_packet是MySQL控制网络包大小的参数,默认是4M。有次可控制一条mysql查询语句大大小,实现mysql慢sql相关优化。

    mysql-like模糊查询优化

    mysql-like模糊查询优化

    sql语句写法

    一张表大概40万左右的数据,用like模糊查询title字段,很慢,title字段已经建立了索引,mysql 对 someTitle% 这样的模糊查询在有索引的前提下是很快的。
    所以下面这两台sql语句差别就很大了
    $sql1 = “… title like someTitle%” (0.001秒)

    +

    $sql2 = “…… title like %someTitle%” (0.8秒)

    mysql-b+Tree索引

    mysql-b+Tree索引

    索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据。
    索引最形象的比喻就是图书的目录了。注意这里的大量,数据量大了索引才显得有意义,如果我想要在 [1,2,3,4] 中找到 4 这个数据,直接对全数据检索也很快,没有必要费力气建索引再去查找。

    +

    索引在 MySQL 数据库中分三类:

    +
      +
    • B+ 树索引
    • +
    • Hash 索引
    • +
    • 全文索引
    Redis的内存淘汰策略问题
    MyBatis二级缓存
    redis分布式锁Redlock的实现
    mysql高性能优化规范方法

    mysql高性能优化规范方法

    数据库命令规范

      +
    • 所有数据库对象名称必须使用小写字母并用下划线分割
    • +
    • 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来)
    • +
    • 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符
    • +
    • **临时库表必须以tmp_为前缀并以日期为后缀,备份表必须以bak_**为前缀并以日期(时间戳)为后缀
    • +
    • 所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低)
    常见sql错误写法
    mysql索引优化方案
    一次数据库的死锁问题排查过程
    mysql数据库索引解析
    一千行 MySQL 学习笔记(转载)

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\225\260\346\215\256\345\272\223/mybatis/index.html" "b/categories/\346\225\260\346\215\256\345\272\223/mybatis/index.html" new file mode 100644 index 0000000000..12b40f0895 --- /dev/null +++ "b/categories/\346\225\260\346\215\256\345\272\223/mybatis/index.html" @@ -0,0 +1,162 @@ + +分类: mybatis - 辣椒の酱 + +
    MyBatis二级缓存

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\225\260\346\215\256\345\272\223/mysql/index.html" "b/categories/\346\225\260\346\215\256\345\272\223/mysql/index.html" new file mode 100644 index 0000000000..c2fe87db87 --- /dev/null +++ "b/categories/\346\225\260\346\215\256\345\272\223/mysql/index.html" @@ -0,0 +1,181 @@ + +分类: mysql - 辣椒の酱 + +
    mysql允许最大sql语句长度配置

    mysql允许最大sql语句长度配置

    MySQL对于每个客户端连接都会分配连接buffer和结果集发送的buffer,连接buffer主要就是来接受客户端发送过来的sql语句,并且初始分配大小都是 net_buffer_length,可以动态增长,最多可以达到 max_allow_packet大小。这个参数是会话只读的,言外之意就是只能全局修改,新建连接才生效。max_allow_packet是MySQL控制网络包大小的参数,默认是4M。有次可控制一条mysql查询语句大大小,实现mysql慢sql相关优化。

    mysql-like模糊查询优化

    mysql-like模糊查询优化

    sql语句写法

    一张表大概40万左右的数据,用like模糊查询title字段,很慢,title字段已经建立了索引,mysql 对 someTitle% 这样的模糊查询在有索引的前提下是很快的。
    所以下面这两台sql语句差别就很大了
    $sql1 = “… title like someTitle%” (0.001秒)

    +

    $sql2 = “…… title like %someTitle%” (0.8秒)

    mysql-b+Tree索引

    mysql-b+Tree索引

    索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据。
    索引最形象的比喻就是图书的目录了。注意这里的大量,数据量大了索引才显得有意义,如果我想要在 [1,2,3,4] 中找到 4 这个数据,直接对全数据检索也很快,没有必要费力气建索引再去查找。

    +

    索引在 MySQL 数据库中分三类:

    +
      +
    • B+ 树索引
    • +
    • Hash 索引
    • +
    • 全文索引
    mysql高性能优化规范方法

    mysql高性能优化规范方法

    数据库命令规范

      +
    • 所有数据库对象名称必须使用小写字母并用下划线分割
    • +
    • 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来)
    • +
    • 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符
    • +
    • **临时库表必须以tmp_为前缀并以日期为后缀,备份表必须以bak_**为前缀并以日期(时间戳)为后缀
    • +
    • 所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低)
    常见sql错误写法
    mysql索引优化方案
    一次数据库的死锁问题排查过程
    mysql数据库索引解析
    一千行 MySQL 学习笔记(转载)

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\225\260\346\215\256\345\272\223/redis/index.html" "b/categories/\346\225\260\346\215\256\345\272\223/redis/index.html" new file mode 100644 index 0000000000..f58c57052d --- /dev/null +++ "b/categories/\346\225\260\346\215\256\345\272\223/redis/index.html" @@ -0,0 +1,162 @@ + +分类: redis - 辣椒の酱 + +
    Redis的内存淘汰策略问题
    redis分布式锁Redlock的实现

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\225\260\346\215\256\347\273\223\346\236\204/index.html" "b/categories/\346\225\260\346\215\256\347\273\223\346\236\204/index.html" new file mode 100644 index 0000000000..9594daf249 --- /dev/null +++ "b/categories/\346\225\260\346\215\256\347\273\223\346\236\204/index.html" @@ -0,0 +1,162 @@ + +分类: 数据结构 - 辣椒の酱 + +
    用栈实现队列/用队列实现栈

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\236\266\346\236\204/Kafka/index.html" "b/categories/\346\236\266\346\236\204/Kafka/index.html" new file mode 100644 index 0000000000..7227fcbe97 --- /dev/null +++ "b/categories/\346\236\266\346\236\204/Kafka/index.html" @@ -0,0 +1,160 @@ + +分类: Kafka - 辣椒の酱 + +
    Kafka基本架构及原理

    Kafka基本架构及原理

    一、为什么需要消息系统

    1.解耦:
    允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
    2.冗余:
    消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
    3.扩展性:
    因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\236\266\346\236\204/index.html" "b/categories/\346\236\266\346\236\204/index.html" new file mode 100644 index 0000000000..526b5e8890 --- /dev/null +++ "b/categories/\346\236\266\346\236\204/index.html" @@ -0,0 +1,164 @@ + +分类: 架构 - 辣椒の酱 + +
    秒杀系统如何支撑百万QPS

    秒杀系统如何支撑百万QPS

    12306抢票,极限并发带来的思考?

    每到节假日期间,一二线城市返乡、外出游玩的人们几乎都面临着一个问题:抢火车票!虽然现在大多数情况下都能订到票,但是放票瞬间即无票的场景,相信大家都深有体会。尤其是春节期间,大家不仅使用12306,还会考虑“智行”和其他的抢票软件,全国上下几亿人在这段时间都在抢票。

    Kafka基本架构及原理

    Kafka基本架构及原理

    一、为什么需要消息系统

    1.解耦:
    允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
    2.冗余:
    消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
    3.扩展性:
    因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。

    并发扣款相关问题
    restful api 设计以及幂等性相关设计
    支付系统设计(转载)

    支付系统设计(转载)

    支付系统

    概述

    支付系统是连接消费者、商家(或平台)和金融机构的桥梁,管理支付数据,调用第三方支付平台接口,记录支付信息(对应订单号,支付金额等),金额对账等功能,根据不同公司对于支付业务的定位不同大概有几个阶段:第一阶段:支付作为一个(封闭)的、独立的应用系统,为各系统提供支付功能支持。一般来说,这个系统仅限于为公司内部的业务提供支付支持,并且和业务紧密耦合。第二阶段:支付作为一个开发的系统,为公司内外部系统、各种业务提供支付服务,支付服务本身应该是和具体的业务解耦合。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\236\266\346\236\204/\350\256\276\350\256\241/index.html" "b/categories/\346\236\266\346\236\204/\350\256\276\350\256\241/index.html" new file mode 100644 index 0000000000..0048bbd8a6 --- /dev/null +++ "b/categories/\346\236\266\346\236\204/\350\256\276\350\256\241/index.html" @@ -0,0 +1,164 @@ + +分类: 设计 - 辣椒の酱 + +
    秒杀系统如何支撑百万QPS

    秒杀系统如何支撑百万QPS

    12306抢票,极限并发带来的思考?

    每到节假日期间,一二线城市返乡、外出游玩的人们几乎都面临着一个问题:抢火车票!虽然现在大多数情况下都能订到票,但是放票瞬间即无票的场景,相信大家都深有体会。尤其是春节期间,大家不仅使用12306,还会考虑“智行”和其他的抢票软件,全国上下几亿人在这段时间都在抢票。

    并发扣款相关问题
    restful api 设计以及幂等性相关设计
    支付系统设计(转载)

    支付系统设计(转载)

    支付系统

    概述

    支付系统是连接消费者、商家(或平台)和金融机构的桥梁,管理支付数据,调用第三方支付平台接口,记录支付信息(对应订单号,支付金额等),金额对账等功能,根据不同公司对于支付业务的定位不同大概有几个阶段:第一阶段:支付作为一个(封闭)的、独立的应用系统,为各系统提供支付功能支持。一般来说,这个系统仅限于为公司内部的业务提供支付支持,并且和业务紧密耦合。第二阶段:支付作为一个开发的系统,为公司内外部系统、各种业务提供支付服务,支付服务本身应该是和具体的业务解耦合。


    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\346\263\225\345\276\213/index.html" "b/categories/\346\263\225\345\276\213/index.html" new file mode 100644 index 0000000000..11f5632e7c --- /dev/null +++ "b/categories/\346\263\225\345\276\213/index.html" @@ -0,0 +1,206 @@ + +分类: 法律 - 辣椒の酱 + +
    中国共产党章程(2017修改)
    中华人民共和国国旗法
    中华人民共和国宪法
    中华人民共和国消费者权益保护法
    中华人民共和国刑事诉讼法
    中华人民共和国劳动法
    中华人民共和国婚姻法
    中华人民共和国网络安全法

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\347\247\221\346\231\256/index.html" "b/categories/\347\247\221\346\231\256/index.html" new file mode 100644 index 0000000000..0dcc1f2ed3 --- /dev/null +++ "b/categories/\347\247\221\346\231\256/index.html" @@ -0,0 +1,162 @@ + +分类: 科普 - 辣椒の酱 + +
    2019年国庆70周年阅兵完整图文解说(收藏!)

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\346\210\220\351\225\277/index.html" "b/categories/\347\273\217\351\252\214\346\210\220\351\225\277/index.html" new file mode 100644 index 0000000000..703df8eb75 --- /dev/null +++ "b/categories/\347\273\217\351\252\214\346\210\220\351\225\277/index.html" @@ -0,0 +1,162 @@ + +分类: 经验成长 - 辣椒の酱 + +
    阿里一年的成长经历

    阿里一年的成长经历

    +

    摘要
    任何工作一定对个人都是有提升的,但是不会总结的人,在每个项目/需求中成长的东西都是散的,久而久之就忘了。通过充分的总结之后,犯过的错误我们不会二次再犯,理清楚的业务的来龙去脉铭记在心,对自己是一种提升,分享给别人对别人也是很大的帮助。
    失败者失败的原因各有不同,成功者的做事方式总是相似的,从宏观角度去看,我认为总结就是成功者之所以能成功,很重要一个原因。

    +

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git "a/categories/\350\207\252\345\212\250\351\203\250\347\275\262Hexo\345\215\232\345\256\242\357\274\214Github-Action/index.html" "b/categories/\350\207\252\345\212\250\351\203\250\347\275\262Hexo\345\215\232\345\256\242\357\274\214Github-Action/index.html" new file mode 100644 index 0000000000..96d0abef7c --- /dev/null +++ "b/categories/\350\207\252\345\212\250\351\203\250\347\275\262Hexo\345\215\232\345\256\242\357\274\214Github-Action/index.html" @@ -0,0 +1,160 @@ + +分类: 自动部署Hexo博客,Github Action - 辣椒の酱 + +
    Github-Action自动部署Hexo博客

    :D 一言句子获取中...

    © 2025 辣椒の酱  Powered by Hexo & Icarus & Amazing 
    © 版权说明:[本网站所有内容均收集于互联网或自己创作,
        方便于网友与自己学习交流,如有侵权,请留言,立即处理]
    loading...

    ❤️感谢 99+ 小伙伴的 99+ 次光临!❤️

    \ No newline at end of file diff --git a/clock.html b/clock.html new file mode 100644 index 0000000000..78557df4a7 --- /dev/null +++ b/clock.html @@ -0,0 +1,25 @@ + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + diff --git a/content.json b/content.json new file mode 100644 index 0000000000..fa97a2e975 --- /dev/null +++ b/content.json @@ -0,0 +1 @@ +{"posts":[{"title":"博客源码分享","text":"写在前面 博客源码包括两个主题icarus和next,在主题基础之上参照各网友博客,以及自己的一些想法做出的一些修改以及增加部分新元素。 以下是修改后的需要的部分配置,其余的配置参照icarus主题配置和next主题配置。因为修改了原作者源码,有什么问题请先联系我,不要去麻烦原作者了,能自己解决的问题就不要麻烦别人了,每个人的时间都很宝贵。膜拜和感谢所有模块的原作者,orz👻,辛苦了。 欢迎围观:博客+主题源码、纯主题源码、博客+主题源码 Live Demo 一、icarus主题之上主要改动 新增gitalk最新评论widget 首页增加热门推荐 增加弹性配置影音(可加音乐、视频)模块 丰富弹性配置about页面 新增弹性配置友链模块 整体布局左右拉伸了一点,紧凑一些 文章页双栏模式、固定导航栏 引入可配置看板娘 归档页加入了一个文章贡献概览 置顶文章的设置 文章列表评论数显示 文章中推荐文章模块配置 增加深色主题切换 加入加密文章 碎碎念功能 透明无界样式 简化部分widget数据,加入查看全部按钮 gitalk评论增加评论开关,评论列表中标记博主 加入pjax提升页面访问体验,配置文件中可开启关闭 侧边栏加入可配置网易云歌单音乐插件,配合pjax可以实现页面间切换背景音乐不间断 文章中加入相关文章模块,取分类相同的最新的5条文章 支持valine最新评论以及文章评论数显示 还有什么新的,好的feature欢迎大家随时提出来,有能力有时间就做出来 二、部分配置说明:克隆博客代码到本地1git clone https://github.com/removeif/hexo-theme-amazing.git themes/amazing 通过npm安装123npm i hexo-theme-amazing hexo config theme amazing // 提示缺少依赖就按提示的安装相应依赖即可// 博客目录下增加 博客配置文件_config.yml(具体配置指定使用该主题theme: amazing) ,以及主题配置文件_config.amazing.yml进行配置即可 开始部分配置:敲黑板!!!!首先全局以及主题中的_config.yml配置成自己的对应参数。 1.热门推荐,最新评论:热门推荐仅支持gitalk,最新评论支持gitalk & valine 对应主题中的_config.yml要开启如下配置(此为gitalk,valine配置文件中也有示例),xxx换成自己的,否则无效。对于gitalk部署博客后需要到相应文章评论处点击初始化issue评论,完成评论的初始化。 themes/icarus/_config.yml >folded1234567891011comment: type: gitalk owner: xxx # (required) GitHub user name repo: xxx # (required) GitHub repository name client_id: xxx # (required) OAuth application client id client_secret: xxx # (required) OAuth application client secret admin: xxx #此账户一般为用户名 GitHub user name 文章中能创建issue需要此用户登录才可以,点了创建issue后刷新一遍才能看到!!!! create_issue_manually: true distraction_free_mode: true has_hot_recommend: true # 是否有热门推荐 has_latest_comment: true #是否有最新评论 说明: has_hot_recommend: true 是否开启首页热评,false-不开启,true-开启 has_latest_comment: true 是否开启最新评论,false-不开启,true-开启 热门推荐数据为评论数最多的文章,🔥后面的数字:根据文章的评论数*101 。 最新评论:为该仓库下,所有issue中的最新评论。 目前的最新评论有1分钟的本地缓存,评论后可能1分钟后才能看见最新评论,出于性能优化,每次请求接口处理还是挺耗时,comment-issue-data.js中可以自己去掉。 2.友链数据文件:文件路径:themes/icarus/source/js/friend.js相应格式增加自己需要的数据。 3.影音数据文件:文件路径:音乐:themes/icarus/source/json_data/music.json视频:themes/icarus/source/json_data/video.json相应格式增加自己需要的数据。 4.关于页面时间轴记录数据文件:文件路径:themes/icarus/source/json_data/record.json相应格式增加自己需要的数据。 5.看板娘配置主题中的_config.yml配置如下设置 1live2Dswitch: off #live2D开关 on为打开,off为关闭 6.置顶设置:.md文章头部数据中加入top值,top值越大越靠前,大于0显示置顶图标。修改依赖包中文件removeif/node_modules/hexo-generator-index/lib/generator.js如下: node_modules/hexo-generator-index/lib/generator.js >folded12345678910111213141516171819202122232425262728'use strict';const pagination = require('hexo-pagination');module.exports = function(locals){ var config = this.config; var posts = locals.posts; posts.data = posts.data.sort(function(a, b) { if(a.top == undefined){ a.top = 0; } if(b.top == undefined){ b.top = 0; } if(a.top == b.top){ return b.date - a.date; }else{ return b.top - a.top; } }); var paginationDir = config.pagination_dir || 'page'; return pagination('', posts, { perPage: config.index_generator.per_page, layout: ['index', 'archive'], format: paginationDir + '/%d/', data: { __index: true } });}; 7.配置文章中推荐文章模块根据配置的recommend值(必须大于0),值越大越靠前,相等取最新的,最多取5条。recommend(6.中top值也在下面示例)配置在.md文章头中,如下 123456789title: 博客源码分享top: 1toc: truerecommend: 1 keywords: categories-githubdate: 2019-09-19 22:10:43thumbnail: https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20190919221611.pngtags: 工具教程categories: [工具教程,主题工具] 8.文章中某个代码块折叠的方法代码块头部加入标记 >folded,如下代码块中使用。 main.java >folded123456789// 使用示例,.md 文件中头行标记\">folded\"// ```java main.java >folded// import main.java// private static void main(){// // test// int i = 0;// return i;// }// \\\\``` 9.加入加密文章如下需要加密的文章头部加入以下代码 1234567891011121314---title: 2019成长记01top: -1toc: truekeywords: categories-java#以下为文章加密信息encrypt: truepassword: 123456 #此处为文章密码abstract: 咦,这是一篇加密文章,好像需要输入密码才能查看呢!message: 嗨,请准确无误地输入密码查看哟!wrong_pass_message: 不好意思,密码没对哦,在检查检查呢!wrong_hash_message: 不好意思,信息无法验证!--- 注:加密文章不会出现在最新文章列表widget中,也不会出现在文章中推荐列表中,首页列表中需要设置top: -1 让它排在最后比较合理一些。 10.碎碎念的使用在github中,创建碎碎念issue,并且打上对应的label(eg:Gitalk,666666)如下图,此处666666对应下面配置代码中的id,填写到source/self-talking/index.md文件中如下对应位置,其余配置也要改成自己的,如clientID等。 12345678910111213<script> var gitalk = new Gitalk({ clientID: '46a9f3481b46ea0129d8', clientSecret: '79c7c9cb847e141757d7864453bcbf89f0655b24', id: '666666', repo: 'issue_database', owner: 'removeif', admin: \"removeif\", createIssueManually: true, distractionFreeMode: false }) gitalk.render('comment-container1')</script> 如下: 11.本博客样式(透明无界)只需要放开themes/icarus/source/css/base.styl文件中以下样式代码注释即可,默认是注释的没启用 base.styl >folded123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051//=================本博客使用样式 start// 首页去图.body_hot_comment .comment-content .card-comment-item .ava, .media-left, .is-6-widescreen .card-image { display: none;}hover-color = #deeafb;// 去card.card { background-color: unset; //box-shadow: unset;}.navbar, footer.footer { background-color: unset;}body:not(.night) .navbar:hover,body:not(.night) .footer:hover,body:not(.night) .card:hover,body:not(.night) .pagination:hover,body:not(.night) .post-navigation:hover{ background-color: hover-color; box-shadow: 0 4px 10px rgba(0,0,0,0.05),0 0 1px rgba(0,0,0,0.1);}.pagination, .post-navigation{ padding: 10px;}.pagination .pagination-link:not(.is-current), .pagination .pagination-previous, .pagination .pagination-next { background-color:rgba(255,255,255,0);}.timeline .media:last-child:after { background: unset;}.footer { box-shadow: 0px 4px 10px 10px rgba(0,0,0,0.05); padding: 3rem 1.5rem 2rem;}@media screen and (max-width: 1087px) .navbar-menu { background-color: unset; }//=================本博客使用样式 end 如下: 精简部分widget数据widget中的归档和分类和标签精简了,数据多时很丑,改为了分别展示5条和10条和20条,增加了查看全部。 gitalk评论增加评论开关,评论列表中标记博主需要关闭评论的在文章头部加入 comments: false,原来已经评论的依然会显示,如下 原来已有博客文章的迁移,只需要把原来对应的文章放到source/_posts里即可。然后去对应文章下面创建评论issue。 以上配置好后12345$ npm install #安装依赖包(只需要执行一次)ps:如果是纯主题仓库,可直接把本文最后的json文件复制到博客下面的依赖文件package.json后在执行此命令$ hexo clean #清除缓存$ hexo g #编译 $ hexo s #启动服务 $ hexo d #推到远程 安装依赖包(只需要执行一次),以后修改了代码 只需要执行后面几条就好。 ok,enjoy it!!👏👏 有什么问题,欢迎issue里讨论。 写在后面如果你有问题请反馈: issues (请务必先于issues中寻找答案)如果你喜欢该主题: star如果你想定制主题: fork 文章中横竖图demo;对于横竖图推荐分开使用,且长宽一致的,如统一手机拍照、电脑截图使用方法:md文章中放入以下代码 index.html>folded12345678910111213141516171819+ 横竖图<div class=\"justified-gallery\">![张芷溪](https://wx1.sinaimg.cn/large/b5d1b710ly1g6bz7n92s7j212w0nr1kx.jpg) ![李一桐](https://wx2.sinaimg.cn/mw1024/005RAHfgly1fvfc4f19qfj33402c0qv9.jpg) ![gakki](https://wx1.sinaimg.cn/mw1024/70396e5agy1g5qe457i6yj21660ogtap.jpg) ![李一桐](https://wx1.sinaimg.cn/mw1024/005RAHfgly1fuzz17s2q3j32e43cku0x.jpg) ![彭小苒](https://wx1.sinaimg.cn/mw1024/d79c9b94ly1g1pb1uthr5j21f02iox6t.jpg)</div>+ 横图4<div class=\"img-x\">![v4](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191022182226.png) ![v3](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191018114126.png) ![v4](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191022182226.png) ![v3](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191018114126.png)</div>+ 竖图5<div class=\"img-y\">![电池](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191024145940.jpg) ![打王者荣耀](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191024141906.jpg) ![支付宝付款](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191024141926.jpg) ![锤子便签](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191024145956.jpg) ![电池](https://cdn.jsdelivr.net/gh/removeif/blog_image/img/2019/20191024145940.jpg)</div> 效果如下(多图左右拉查看) 横竖图 横图4 竖图5 博客快照: 主页 深色主题 置顶 文章评论数 推荐文章模块 归档 留言 友链 美图 影音 关于 提供hexo博客目录下依赖包 package.json123456789101112131415161718192021222324252627282930313233343536373839404142{ \"name\": \"hexo-site\", \"version\": \"3.0.0\", \"private\": true, \"scripts\": { \"build\": \"hexo generate\", \"clean\": \"hexo clean\", \"deploy\": \"hexo deploy\", \"server\": \"hexo server\" }, \"hexo\": { \"version\": \"4.2.0\" }, \"dependencies\": { \"ajv\": \"^6.10.2\", \"bulma-stylus\": \"0.8.0\", \"deepmerge\": \"^4.2.2\", \"hexo\": \"^4.2.0\", \"hexo-blog-encrypt\": \"^3.0.3\", \"hexo-deployer-git\": \"^2.1.0\", \"hexo-generator-archive\": \"^1.0.0\", \"hexo-generator-category\": \"^1.0.0\", \"hexo-generator-feed\": \"^2.2.0\", \"hexo-generator-index\": \"^1.0.0\", \"hexo-generator-tag\": \"^1.0.0\", \"hexo-log\": \"^1.0.0\", \"hexo-pagination\": \"^1.0.0\", \"hexo-renderer-ejs\": \"^1.0.0\", \"hexo-renderer-inferno\": \"^0.1.1\", \"hexo-renderer-marked\": \"^2.0.0\", \"hexo-renderer-stylus\": \"^1.1.0\", \"hexo-server\": \"^1.0.0\", \"hexo-util\": \"^1.8.0\", \"inferno\": \"^7.3.3\", \"inferno-create-element\": \"^7.3.3\", \"js-yaml\": \"^3.13.1\", \"moment\": \"^2.22.2\", \"save\": \"^2.4.0\", \"semver\": \">=5.0.0\" }}","link":"/theme/%E5%8D%9A%E5%AE%A2%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB.html"},{"title":"2019年国庆70周年阅兵完整图文解说(收藏!)","text":"问:你在哪个瞬间觉得中国很强大?答:就是现在!开国大典的时候飞机不够,您说飞两遍,现在再也不需要飞两遍了,要多少有多少。这盛世,如你所愿吧,山河犹在,国泰民安。当年送你的十里长安街,如今已是十里繁荣! 多图预警,加载较慢,好事多磨,请耐心等待!!! 阅兵解说海霞:今天是你的生日,我的中国。在这个不同寻常的节日,相信每一位中华儿女都会从心底里说一句,我爱你,中国。 康辉:70年风雨兼程,天安门广场上的红飘带寓意着红色基因连接历史,现实与未来。海霞:今天的天安门广场是世界瞩目的中心,今天的中国正前所未有的靠近世界舞台中心。康辉:长安街上,人民军队精神抖擞,这支曾经穿草鞋,拿梭镖走上征途的队伍,现在已经拥有了自己的航母和新一代隐身战机,正阔步迈向世界一流军队。此时此刻,4名上将,2名中将,100多名少将,近15000名官兵列队完毕,等待接受统帅的检阅,接受祖国和人民的检阅。海霞:长安街两侧身穿节日盛装的10万游行群众已集结完毕,一个多小时后,他们将组成一个个方阵,从天安门前通过,向全世界展示自由生动,欢愉活泼。70年前中国人的平均预期寿命只有三十五岁,七十年后的今天已经达到七十七岁,七十年来不断创造奇迹的中国让世界刮目相看。康辉:新中国用短短几十年的时间走过了西方发达国家几百年的工业化历程,70年前的中国满目疮痍积贫积弱,今天中国已经成为世界第二大经济体,是全球经济发展的第一引擎。 海霞:长安街始建于明代,寓意长治久安,回望长安大街,它记载着一个国家的兴衰和曾经有过的悲伤挣扎,奋斗喜悦,也记载着我们浴血奋战得解放,披荆斩棘成大道,砥砺奋进新时代的伟大征程。今天走在中国特色社会主义道路上我们无比自豪,无比自信。 康辉:黄河长江的浪,长城内外的风,起起伏伏,多少仁人志士上下求索。海霞:革命先行者孙中山,凝视着天安门广场,他曾经奋力让黑暗的中国走向黎明。康辉:开国领袖毛泽东注视着天安门广场,他让沉睡的东方雄狮昂起了头颅。海霞:1949年一唱雄鸡天下白,中国迈进新纪元。康辉:此时此刻,地域不同,口音不同的人们汇聚在这里,有56个民族的兄弟姐妹,有港澳台同胞和海外侨胞,有关心和支持中国发展的外国友人,我们将共同见证历史。康辉:中央广播电视总台。海霞:中央广播电视总台。康辉:这里是中华人民共和国首都北京。海霞:我们在这里向全球直播,庆祝中华人民共和国成立70周年大会。康辉:一个必将载入史册的国家盛典即将开始。康辉:习近平,李克强,栗战书,汪洋,王沪宁,赵乐际,韩正,王岐山等党和国家领导人来到了天安门城楼,江泽民,胡锦涛同志来到了天安门城楼。他们和全国亿万人民一起庆祝中华人民共和国70华诞。海霞:今天在天安门城楼参加庆典的,还有中共中央、全国人大常委会、国务院、全国政协、中央军委的领导同志和部分老同志代表,国家勋章、国家荣誉称号获得者代表等。康辉:来自全国各条战线的英雄模范人物,各界各族代表,香港、澳门、台湾同胞和海外侨胞代表以及在京重要外宾,各国驻华使节,外国专家等到现场观礼。康辉:五十六门礼炮,70响轰鸣,仿佛历史跃动的脉搏诉说着五十六个民族的中华儿女七十载春华秋实的拼博。海霞:隆隆炮声如冲锋的战士前赴后继,如燃烧的火炬薪火相传,我们的共和国就这样筚路蓝缕一路走来。康辉:正步铿锵堂堂气,寒光闪耀凛凛威。海霞:从人民英雄纪念碑到五星红旗升起,短短几百步距离,浓缩着革命先烈奋斗的历程,无数苦苦求索奋勇牺牲的先辈凝望着我们,踩下一个个坚实的脚印。康辉:一切向前走都不能忘记走过的路,走的再远,走到再光辉的未来,也不能忘记为什么出发。海霞:一个崭新的时代,从我们手中诞生,民族复兴的梦想,正由我们去实现。 康辉:古老的中国、年轻的中国、充满希望的中国;遥远的世界、连通的世界、命运与共的世界,将共同见证我们这一代人的新长征。海霞:义勇军进行曲,这不屈的旋律,必胜的强音,即将再次唱响,让我们心跳随他跃动,让我们的脚步随他前进,前进,前进进! 康辉:标兵,是阅兵场上标定位置界线的军人,60名标兵以标准的正步,走向指定位置。海霞:脚踏着祖国大地。人民军队牢记宗旨,担当使命,用忠诚用热血,为国家富强,民族振兴,人民幸福,建立了不朽功勋。康辉:与祖国共奋进,人民军队由单一军种的军队发展成为诸军兵种联合基本实现机械化,加快迈向信息化的强大军队。 海霞:这次国庆阅兵增设了一个庄严的仪式,习近平主席将在党旗、国旗和军旗前,向三面光辉的旗帜行注目礼。 康辉:这次阅兵,是中国特色现代军事力量体系建设成果的充分展示,集中体现、信息主导、体系支撑、精兵作战、联合制胜的特点。海霞:这是中国特色社会主义进入新时代的首次国庆阅兵。康辉:这是共和国武装力量改革重塑后的首次整体亮相。海霞:现在,习近平主席乘坐的检阅车已经从折返点返回。 康辉:建设一支听党指挥、能打胜仗、作风优良的人民军队,把人民军队建设成为世界一流军队,这是党的重托,也是人民的期盼。海霞:整齐的方阵,展现了共和国钢铁长城的时代风貌;铿锵的誓言,传递了全军将士对统帅的信赖、拥戴。 康辉:关山飞渡的新征程,离不开登高望远的领路人。坚持以习近平新时代中国特色社会主义思想为指导,深入贯彻习近平强军思想,增强四个意识,坚定四个自信,做到两个维护,贯彻军委主席负责制,全军官兵思想上高度自觉,政治上高度自觉,行动上高度自觉。 海霞:为巩固中国共产党领导,和社会主义制度提供战略支撑,为捍卫国家主权统一领土完整提供战略支撑。为维护国家海外利益提供战略支撑。为促进世界和平与发展,提供战略支撑。人民军队,重任在肩,奋勇向前。康辉:刚刚接受了统帅检阅的徒步方队,现在已经调整完队形,驾驶车辆和操作装备的官兵,也已经进入自己的战斗岗位。康辉:空中梯队的战机已经陆续起飞,一会儿,他们将飞越天安门广场,接受检阅。康辉:分列式即将开始,47个地面方队,12个空中梯队,将从天安门前豪迈地通过。海霞:强国,必须强军,军强才能国安。党的十八大以来,党中央、中央军委和习主席领导人民军队,以党在新时代的强军目标为引领,贯彻新时代军事战略方针,政治建军,铸就忠诚,改革强军体系重塑,科技兴军跨越发展,依法治军严明纲纪,练兵备战锻造胜战之师,面向未来,塑造世界一流军队,人民军队体质一心、节奏一心、格局一心、面貌一心、中国特色强军之路,越走越宽广。 康辉:旗帜引领方向,旗帜凝聚力量。空中护旗梯队,破空而来,拉开了分列式的序幕。海霞:20架直升机汇成巨大70字样,象征着中华人民共和国走过的70年光辉历程。康辉:回望历史,放眼世界,今天的中国,比历史上任何时期都更接近中华民族伟大复兴的目标,比历史上任何时期,都更需要建设一支强大的人民军队。海霞:正在走来的15个地面徒步方队,来自战略战役联合作战指挥机构,诸军兵种部队,院校科研单位等。这种组合方式,体现了解放军、武警部队、民兵三结合的武装力量体制。康辉:鲜红的旗帜迎风招展,中国人民解放军仪仗方队,高擎党旗、国旗、军旗阔步走来。人民军队永远是中国共产党领导下的军队,永远是国家的捍卫者,永远是社会主义的捍卫者,永远是人民利益的捍卫者。海霞:紧随三面旗帜,领导指挥方队接受检阅,领队是姜国平少将、陈作松少将。27位将军和325位校尉军官,来自军委机关、五大战区、各军兵种和武警部队,展现了我军领导指挥体制改革后的崭新面貌,体现了练兵先练将。康辉:现在走来的是陆军方队,领队是林向阳少将、唐兴华少将。 作为人民军队中最早诞生的军种,从战火硝烟中一路走来。人民陆军加快提高精确作战、立体作战、全域作战、多能作战、持续作的战能力。海霞:海军方队走过来了。领队是周名贵少将、梁旭少将。从浅蓝走向深蓝,从近海防御走向远海防卫,与新中国同龄的人民海军一路劈波斩浪,纵横万里海疆,勇闯远海大洋。康辉:现在走过来的是空军方队。领队是景涛少将、赵永远少将。人民空军成立不久后就开赴战场,为捍卫和平而战。70年搏击长空,逐梦蓝天,与共和国一起展翅高飞h今天的人民空军,正向着空天一体,攻防兼备的战略目标迈进。海霞:现在走过来的是火箭军方队,领队是薛今峰少将、张凤中少将。 火箭军的常规导弹和核导弹,动于九天之上,打得越来越远,越来越准,越来越难以防御,经过半个多世纪的潜心砺剑,火箭军已成为核常兼备、全域慑战的战略军种。康辉:战略支援部队方队首次出现在国庆阅兵中,领队是王学武少将、康怀海少将。战略支援部队在改革强军中诞生,为人民军队输送现代战争内功,是维护国家安全的新型作战力量。 海霞:联勤保障部队方队,也是第一次亮相天安门广场,领队是刘向东少将,任延兵少将。兵马为重,保障先行,现代战争需要规模精良的能源和物资供应,需要科学高效精准,从不掉链子的联合保障。康辉:现在接受检阅的是武警部队方队,领队是赵东方少将、张卫国少将。多能一体,维稳维权。武警部队常年奋战在执勤、处突、反恐、维权执法和抢险救援第一线,维护国家安全政治安全和社会稳定,保卫人民美好生活,永远做党和人民的忠诚卫士。海霞:女兵方队走过来了,领队是程晓健少将、唐冰少将。352名女兵来自各军兵种和武警部队,飒爽英姿五尺枪,她们在火热军营中放飞青春成就梦想。 康辉:现在走过来的是院校科研方队,领队是衣述强少将、栾复新少将。受阅队员来自军事科学院、国防大学、国防科技大学。面向战场、面向部队、面向未来,培养-流军事人才,军事科研工作开创崭新局面。海霞:文职人员方队首次亮相阅兵场,领队是王海涛、王华岩。汇聚天下英才,壮大强军事业,伴随着人民军队改革重塑,各方面的优秀人才汇入军营,用知识和智慧助力国防和军队现代化。康辉:现在走过来的是预备役部队方队,领队是高新江大校、徐振刚预备役大校。建设祖国有作为,保卫祖国有能力,预备役部队是人民解放军的后备力量,和现役部队一体建设运用稳步推进。海霞:现在走过来的是民兵方队,领队是赵冰清、廖炜炜。受阅女民兵来自首都各行各业。民兵源自百姓,定期接受军事训练,保持战斗能力。兵民是胜利之本,高技术战争条件下,人民战争依然是克敌制胜的重要法宝。康辉:蓝色贝雷帽,荒漠迷彩服,维和部队方队阔步走来。领队是徐有泽少将、马宝川少将。我国是联合国安理会常任理事国中派出维和官兵最多的国家。2500多名中国军人坚守在7个维和任务区,8000人的维和部队待命出征。先后有13名维和勇士牺牲在异国他乡。中国军人用热血和生命,谱写了维护世界和平的大国担当。海霞:轰鸣声由远而近,装备方队即将进场。受阅的70个型号装备,均为中国制造,40%是首次亮相,32支装备方队编为7个作战模块,按照联合作战编程接受检阅。海霞:由全军荣誉功勋部队代表组成的战旗方队正浩荡而来。领队是五大战区主要指挥员,他们是刘粤军上将、王建武中将、赵宗岐上将.李桥铭中将、朱生岭上将。康辉: 100面鲜红的战旗迎风飘扬! 100个英雄部队的荣誉称号气壮天地!为什么战旗美如画,英雄的鮮血染红了她。人民军队基因永不磨面,红色血脉永远传承。海霞:机动作战,勇往直前,陆上作战模块即将接受检阅。海霞:坦克方队气势磅礴,领队是李明少将。22辆99A坦克呈”箭”形布阵,如战场霹雳,长驱直入。99A坦克是我国自主研发的主战坦克,具备优异的火力、机动、防护、和信息化水平。 康辉:紧随而来的轻型装甲方队,领队是邝德旺少将、王永胜少将。 方队由15式新型轻型坦克、04A式履带步战车和履带指挥车混合编成,这些机械化、信息化装备,能够快速部署、快速反应、快速突击,是陆上应急作战的“急先锋”。海霞:现在驶来的是海军陆战队抽组的两栖突击车方队,领队是祝传生少将、沙成录少将。受阅的05A式两栖装甲突击车既能陆地作战,也可以近海航渡,向目标海滩发起攻击,让我军在抢滩登陆作战中,进攻矛头更锋利,防护盾牌更坚固。康辉:空降兵战车方队接受检阅,领队是邱火林少将、陈涛少将。 受阅的轻型履带式步战车,可以空投敌人纵深地带,要害目标附近,让空降兵一落地,手头就有重家伙。他们从天而降,雷霆一击,是联合作战体系中的尖刀利刃。海霞:自行火炮方队,领队是张剑锋少将、何纪抗少将。箱式火箭炮,集远程压制精确打击和信息化作战于一体,一次调炮,多点攻击,155车载加榴炮,是新型炮兵压制武器型,火力更猛,精度更高,机动性更强。康辉:现在驶来的是反坦克导弹方队。领队是邹美余少将、李振领少将。受阅的红箭10反坦克导弹,既能精确打击地面目标,又能抗击低空低速的飞行。目前,我军已经形成多种发射类别、多种射程、多种制导方式的反坦克装备体系。海霞:特战装备方队,领队是田越少将、王信民少将。全地形车,机动灵活,空中突击旋翼机展翅欲飞。两型装备适应复杂战场环境,兵力兵器实现快速投送,灵活布局,是破袭突击、出奇制胜的拳头力量。康辉:紧随而来的是武警反恐突击方队,领队是刘兴立少将、王再发少将。受阅的反恐突击车和防暴装甲车,灵活机动,具备多种打击能力,能灵活地选择攻防手段,是武警部队维护国家安全和社会稳定的重要装备。海霞:乘风破浪,向海图强!海上作战模块即将接受检阅!海霞:首先开过来的是岸舰导弹方队,领队是王显峰少将、吴育红少将。受阅的鹰击12B岸舰导弹可以打击大中型水面舰,对海突击威力大,反应迅速射程远,是沿海防御体系的坚实盾牌。康辉:舰舰/潜舰导弹方队开过来了,领队是刘杰少将、姜平少将。受阅的鹰击18和鹰击18A导弹是我国新一代的反舰巡航导弹,藏得好,打得准,威力大,是海上联合打击体系的利剑。海霞:舰载防空武器方队,领队是刘宏伟少将、张宝军少将。受阅的海红旗9B,红旗16,红旗10和万发炮,共同构成远程、中程、近程和末端对空防御体系,可以拦击高速来袭的敌方战机和导弹,为海上舰艇编队撑起一方立体保护网。康辉:铸盾长空,御敌千里,防空反导模块即将接受检阅。康辉:预警雷达方队,领队是李国平少将、张磊少将。受阅装备是我国新一代高机动多功能雷达,能够探测和锁定飞机导弹等空天目标,提前发现这些不速之客!海霞:地空导弹第一方队,领队是刘明豹少将、韩宪锋少将。受阅的红旗9B远程地空导弹和红旗22中远程地空导弹,能够在复杂电磁环境下拦截多种空袭兵器,构筑起区域防空的坚固屏障!康辉:地空导弹第二方队,领队是朱瑞少将、董玉江少将。八套红旗12A地空导弹蓄势待发,四套红旗六弹炮系统昂首向前。远中近程结合,高中低空衔接,重要一点防空能力有效提升。海霞:野战防空导弹方队,领队是张帆少将、裴晓昌少将。受阅的红旗17A、红旗16B两型防空导弹,机动性能强,反应速度快,拦截精度高,为野战防空提供了多种手段。康辉:信息主导,体系制胜!即将接受检阅的是信息作战模块。康辉:首先开过来的是信息作战第一方队,领队是徐桂明少将、孟繁浩少将。受阅的信息侦测、数据干扰作战车组,侦察干扰能力强,既能独立遂行作战任务,又能支援战略方向联合作战,是无形战场上的神兵利器。海霞:信息作战第二方队,领队是李发义少将、杨小康少将。受阅的三型侦察干扰车和区域拦阻式干扰车,具有部署灵活、机动性强等特点。新型电子对抗装备,为我军赢得复杂电磁环境下战场主动提供坚实支撑。康辉:信息作战第三方队,领队是孙宝泰少将、景贤舫少将。受阅的频谱监测车,无线电接入节点车、卫星通信车和散射通信车,是联合作战体系制胜的可靠通信保障,能确保部队在严酷战争环境下通信畅通,耳聪目明。 海霞:信息作战第四方队,领队是邓洪勤少将、金锋少将。气象水文观测车、地形勘测车、预报保障车、测绘导航车,能快速获取处理和传输战场环境信息,让指挥员对战场条件了如指掌!是我军全域作战的重要保障力量。康辉:智能对抗,引领前沿,无人作战模块即将接受检阅。康辉:无人作战第一方队,领队是姜鹏少将、顾庆友少将。高空高速无人侦察机,侦察校射无人机,小型近程侦察无人机和中程高速无人机,能时时感知战场态势,精准引导,火力打击!海霞:无人作战第二方队,领队是王燕崎少将、乔亚军少将。受阅的攻击2无人机能够提供强大的火力支援,攻击11无人机能够对敌人纵深目标实施精确打击,反辐射无人机能够对敌人纵深目标实施精确打击,反辐射无人机可以压制摧毁防风预警系统。康辉:无人作战第三方队,领队是李广泉少将、徐贵福少将。中国受阅的两型侦察干扰无人机和水下无火潜航器,上天入海,纵横驰程,是我军新型作战力量创新发展的显著成果。 海霞:联合作战,保障先行,后勤装备保障模块即将接受检阅。海霞:现在开过来的是武警供应方队,领队是白忠斌少将、徐宝龙少将。受阅装备由野战近程车,野战站台车,运加油车,主食加工方舱混编而成。有了它们,官兵饮水吃饭,战场应急装卸,装备加油补给都更有保障。康辉:正在接受检阅的是抢修抢救方队,领队是沈竹君少将、汤辛少将。受阅的野战手术方舱,装备抢救车,拆装修理车,装甲抢救车和装甲抢修车,共同构成了现代战场上人员和装备的移动医院。海霞:大国长剑,浩荡东风,战略打击模块即将接受检阅。海霞:首先通过的是东风-17常规导弹方队,领队是张建强少将、王新国少将。东风快递,使命必达。首次公开亮相的东风-17常规导弹,具备全天候、无依托、强突防等特点,可对中近程目标实施精确打击。康辉:现在通过的是长剑-100巡航导弹方队,领队是樊具贤少将、李家勤少将。作为长剑系列中的最新型号,长剑-100首次亮相国庆阅兵。这款超音速巡航导弹精度高、射程远、反应速快,长剑在手,敢缚苍龙!海霞:东风26核常兼备导弹方队正接受检阅,领队是张继春少将、刘同江少将。种导弹既能装核弹头,也能装常规弹头,可以跨区域机动,灵活选择发射阵地,精确打击地面、地下、海上目标。康辉:巨浪-2导弹方队开过来了,领队是吴栋柱少将、初恩涛少将。巨浪-2型导弹是我国第二代潜射远程弹道导弹,它承担着支撑国家海基核威慑的重任。潜入深海,悄无声息,巨浪奔腾,威震海天。海霞:东风-31甲改核导弹方队,领队是袁德华少将、何骏少将。这种导弹是我国自主研制的第二代固体洲际战略核导弹,机动性能好,生存能力强,部署转换快,打击精度高,担负着震慑强敌与核反击作战的重要使命。康辉:东风-5B核导弹方队,领队是汪晓初少将、邓荣珍少将。东风浩荡,雷霆万钧,东风-5B液体洲际战略核导弹,突防能力强、毁伤威力大,是维护国家主权、捍卫民族尊严的重器。海霞:装备方队最后一个出场的是东风一41核导弹方队,领队是赵秋领少将、孙乐少将。战略制衡、战略慑控、战略决胜,东风41洲际战略核导弹是我国战略核力量的重要支撑。康辉:从弹道导弹到巡航导弹,从常规导弹到核导弹,它们是支撑强国梦、强军梦的坚强实力,是维护和平、捍卫和平的坚强盾牌。海霞:展翅长空,傲视苍穹,空中梯队即将接受检阅。康辉:领队机梯队率先飞临。康辉:空军司令员丁来杭上将在空警2000预警机.上担任指挥。空军八一飞行表演队的8架歼-10飞机护卫两翼,7道彩烟寓意着新中国70年的光辉历程。海霞:预警指挥机梯队飞过来了空警500空警200预警机和运8指挥通信机分别由四架歼击机护卫,编成3个五机楔形梯队。长空千里眼,云天中军帐,国产预警机指挥控制、预警探测、识别跟踪能力稳步提升。康辉:海上巡逻机梯队由空警500H预警机和首次亮相的运8反潜巡逻机组成第一楔队,空警200H、运8技术侦察机组成第二楔队,他们是维护国家领海领空安全,维护海洋权益的重要力量。海霞:运输机梯队飞过来了。受阅的运20又称疯狂,它航程远,载重大,速度快,可以在复杂气象条件下执行长距离空中运输任务,使我军战略投送能力登上新高峰!和运20一起受阅的运9也是一款国产新型运输机。康辉:现在飞过来的是支援保障机梯队。运9通信对抗飞机、心理战飞机、医疗救护机和运8远距离支援干扰及电子对抗侦察机,电子侦察机六型特种飞机分编为两个三级楔队,支援保障飞机的列装,有效提升了我军联合作战、全域作战的能力。海霞:轰炸机梯队正呼啸而来。三架轰6N,c6架轰6K分为三个三机楔队,第一次亮相的轰6N为国产新型远程战略轰炸机,可以空中授油,这两型轰炸机能够实施远程奔袭、大区域巡航和防区外打击。康辉:加受油机梯队飞过来了。轰油-6伸出输油管,演示为歼10B战斗机空中加油。受油机距离加油机的加油锥套只有五米,长着翅膀的加油站,让战机有了更大的作战半径。海霞:舰载机梯队接受检阅。歼15战机把人们的思绪带到了海天之间,带到了辽宁舰的甲板上。航母是现代海军的重器,舰载机是航母的刀锋!康辉:歼击机梯队进入我们的视野,5架歼20、5架歼16、5架歼10C战机组成三个楔队接受检阅。今天中国的歼击机家族不断壮天,为夺取战场制空权增添了制胜砝码。海霞:陆航突击梯队正在接受检阅。五架直9武装侦察直升机组成的侦察警戒分队,九架直10武装直升机组成火力突击分队,三架直19武装直升机,六架直20战术通用直升机,九架直8B运输直升机混编为运输分队,八架直19武装直升机担任护卫任务,其中直20战术通用直升机是首次亮相阅兵场,飞旋的铁翼为陆军插上腾飞的翅膀。康辉:最后接受检阅的是教练机梯队,有5架教10,5架歼教9,12架教8组成,其中教10加挂武器后可以执行空战任务。康辉:机群飞过,彩烟绚丽,余味悠长。康辉:今天十万群众和70组彩车将组成36个方阵和3个情景式行进,以同心共筑中国梦为主题分为建国创业、改革开放、伟大复兴三个篇章,展现中国共产党团结带领全国各族人民从站起来、富起来到强起来的伟大征程。海霞:国旗方阵,国庆年号和国徽方阵、致敬方阵拉开了群众游行的序幕。海霞:国旗方阵由高举巨幅国旗的1949名青年组成,70年前就在这里,五星红旗和世人初次见面,70年后的今天它比任何时候都闪耀惊艳。康辉:2019名青年组成国庆年号和国徽方阵。1949到2019,70年栉风沐雨,70年砥砺奋进。康辉:庄严神圣的国徽巍然屹立,这是我们伟大祖国的象征,代表着全体中国人民的尊严和力量。海霞:一曲《红旗颂》奏响,致敬方阵的21辆礼宾车徐徐驶来。第一辆礼宾车上,是6位新中国缔造者的亲属代表,3位老一辈科学家的家属代表和9位老红军、老八路军、老解放军。海霞:紧随而来的20辆礼宾车上也坐着老一辈党和国家、军队领导人亲属代表;老一辈建设者和家属代表;新中国成立前参加革命工作的老战士,老一辈军队退役英模、民兵英模和支前模范代表。康辉:一切向前走,都不能忘记走过的路。为了民族独立、人民解放和国家富强、人民幸福,无数先辈筑起了坚不可摧的血肉长城,铸就了坚强不屈的民族脊梁。海霞:一部民族史,一部奋斗史,一部英雄史。英雄胸前的勋章、奖章凝结着人民的敬意,后代手中的荣誉牌和纪念物铭刻着国家的记忆。一个有希望的民族不能没有英雄,一个有前途的国家不能没有先锋,今天,让我们再次向共和国的英雄和先锋致敬。康辉:今天,我们比历史上任何时期都更接近、更有信心和能力实现中华民族伟大复兴的目标。今天,老一辈的革命理想、优良传统和时代精神将继续激励我们,不忘初心、牢记使命、永远奋斗,向着这个宏伟目标奋勇前进!海霞:群众游行第一部分“建国创业”由5个方阵组成,打头的是“开天辟地”方阵。海霞:中国诞生了共产党,这是开天辟地的大事变。彩车上热血青年手持火把,拨开历史的迷雾,攀登真理的高峰,取来信念的火种,点亮革命的火炬,“星星之火”渐成燎原之势,荡涤风雨如磐的暗夜,燃烧成光耀中华的绚烂日出。 康辉:从开天辟地到改天换地,凝结了一个民族刻骨铭心的磨难与觉醒、一个政党矢志不渝的奋斗与探索、一个国家波澜壮阔的进步与崛起。 海霞:“浴血奋战”方阵中,三辆并行的彩车上,八一勋章、独立自由勋章和解放勋章熠熠生辉。金色勋章是建功立业的历历铭记,红色绶带是拼搏奋战的滚滚热血。抗击侵略,救亡图存,反抗压迫,争取自由,中国共产党团结带领中国人民浴血奋战28年,谱写了一曲气壮山河的英雄赞歌。为有牺牲多壮志,敢教日月换新天。牢记革命历史,传承红色基因,我们必将从胜利走向新的胜利! 康辉:簇拥着毛泽东同志巨幅画像和标语的“建国伟业”方阵向我们走来。以毛泽东同志为主要代表的中国共产党人,创立了毛泽东思想,团结带领全党全国各族人民,取得了新民主主义革命的胜利,建立中华人民共和国,中华民族的发展进步从此开启了新纪元。中国人民,站起来了!五洲寰宇,换了人间! 海霞:红旗漫卷,红绸翻飞,游行群众跳起了热情欢腾的“红绸舞”。“当家作主”方阵展现了亿万中国人民当家作主后的喜悦心情。彩车上的巨型雕塑,再现了“人民代表意气风发步出人民大会堂”的经典场景。中国人民,终于成为了国家的主人、社会的主人、自己命运的主人。 康辉:“艰苦奋斗”方阵向我们走来。王进喜、时传祥……这每一个名字都让我们永远铭记。正是这种自力更生、艰苦奋斗的精神,让新中国从“一穷二白”中艰难走来,在砥砺奋进中拼搏成长。钢花飞溅、铁水奔流、石油流淌、麦浪滚滚,社会主义建设热火朝天。奋斗本身就是一种幸福。新时代,依然是属于奋斗者的时代! 海霞:长安街上熙熙攘攘的自行车流,是属于一代人的青春记忆。少男少女拨响车铃穿梭而过,仿佛时光倒流,开启了第一段情境式行进“青春万岁”。 海霞:一代青年有一代青年的青春之歌,实现中华民族伟大复兴,中国青年始终是先锋力量。 康辉:群众游行第二部分“改革开放”由9个方阵组成。簇拥着邓小平同志巨幅画像和标语的“关键抉择”方阵正向我们走来。 康辉:以邓小平同志为主要代表的中国共产党人,团结带领全党全国各族人民,创立了邓小平理论,作出实行改革开放的历史性决策,确立社会主义初级阶段基本路线,成功开创了中国特色社会主义。改革开放,是决定当代中国命运的关键一招,实现了中华民族从站起来到富起来的伟大飞跃! 海霞:中国革命,从农村出发;中国改革,从农村突破。来自安徽凤阳小岗村、浙江安吉余村等地的农村改革领头人,和农民群众代表组成“希望田野”方阵,带着丰收的喜悦向我们走来。这是一块永远孕育着希望的热土。撒上火种,它就燃起燎原的烈焰;吹过春风,它就涌起翻滚的麦浪。 康辉:时间就是金钱,效率就是生命。新中国在改革开放的浪潮中加快了前进的脚步。“春潮滚滚”方阵中,深圳、厦门等经济特区,万丈高楼平地起,谱写了改革开放的壮丽篇章。一代代的开拓者和建设者,以拓荒牛的精神,书写了一个个让世界瞩目的中国奇迹。 海霞:簇拥着江泽民同志巨幅画像和标语的“与时俱进”方阵正向我们走来。以江泽民同志为主要代表的中国共产党人,团结带领全党全国各族人民,形成了“三个代表”重要思想,在严峻考验面前捍卫了中国特色社会主义,开创了全面改革开放新局面,成功把中国特色社会主义推向21世纪。世纪之交,风云际会,辉煌的成就,证明了中国特色社会主义制度的蓬勃生机和光明未来。 康辉:港澳台同胞和各界群众组成了“一国两制”方阵,他们挥舞旗帜,欢呼致意,为共和国的生日献上儿女们最赤诚的祝福。“一国两制”伟大构想具有强大生命力。只要坚持全面准确理解和贯彻“一国两制”方针,严格按照宪法和基本法办事,香港和澳门必将拥有更加美好的明天。 海霞:岁月如斯,不舍昼夜。“跨越世纪”方阵中,圆形日晷上流转着金色的光芒日历。世纪之初呱呱坠地的“世纪宝宝”,如今已长成英姿勃发的青年。源远流长的古老中国,历久弥新;跨越世纪的青春中国,风华正茂! 康辉:簇拥着胡锦涛同志巨幅画像和标语的“科学发展”方阵向我们走来。以胡锦涛同志为主要代表的中国共产党人,团结带领全党全国各族人民,形成了科学发展观,形成中国特色社会主义事业总体布局,成功在新的历史起点上坚持和发展了中国特色社会主义。以人为本民心皆暖,和谐世界天下共赢。 海霞:众志成城的彩车上,汶川县的映秀小学,红白镇的红顶民居,阿坝州的古堡新寨,这些都是在废墟上建立的新家园。时光荏苒,当年的“敬礼娃娃”,如今已经是青春少年。方阵中有参与抗击非典的医护工作人员,有参与汶川重建的解放军和武警部队官兵、救援队员、消防指战员、医疗队员、志愿者和各界群众。在无情灾害面前,我们万众一心,创造了抢险救灾和灾后重建的双重奇迹。 康辉:“北京欢迎你”,这熟悉的旋律把我们拉回到了2008年那个盛夏。百年奥运,百年梦圆。只有上下一心的国家、富有进取心和想象力的国家,才能有那样的华彩呈现。“给中国一个机会,还世界一个奇迹”。2022年冬奥会,我们继续相约北京。 海霞:激昂雄壮的鼓点催人奋进,中国功夫和舞狮表演的互动组合,开启了第二段情境式行进“东方雄狮”。睡狮早已醒来,雄狮昂首东方。美哉,我少年中国,与天不老!壮哉,我中国少年,与国无疆! 康辉:群众游行第三部分“伟大复兴”由18个方阵组成。簇拥着习近平同志巨幅画像和标语的“伟大复兴”方阵向我们走来。党的十八大以来,以习近平同志为核心的党中央,团结带领全党全国各族人民,进行伟大斗争、建设伟大工程、推进伟大事业、实现伟大梦想,创立了习近平新时代中国特色社会主义思想,推动党和国家事业发生了历史性变革、取得了历史性成就。中国特色社会主义进入新时代!中华民族迎来了从站起来、富起来到强起来的伟大飞跃! 海霞:科学技术是第一生产力,创新是引领发展的第一动力。科技创新领域的代表组成“创新驱动”方阵,自信昂扬地向我们走来。高铁、天宫、蛟龙,搭载着“天眼”“北斗”“C919大飞机”“长征三号”“天河二号”等大国重器,驰骋在科技强国的征途上。三辆彩车在行进中首尾相连,组成一列高速飞驰的“复兴号”,驶向更加美好的明天。 康辉:“区域协调”方阵中,四条龙舟你追我赶,旋转“魔方”气象万千,东西南北纵横联动发展的新格局全面铺展。京津冀、长江经济带、粤港澳、长三角,“四大战略”齐头并进;西部开发、东北振兴、中部崛起、东部率先,“四大板块”协调发展。 海霞:村口杨柳依依,院内海棠盛开,一幅幅农民画,描绘出新时代的美丽乡村。农村致富带头人、劳动模范和农民群众组成“乡村振兴”方阵向我们走来,产业兴旺、生态宜居、乡风文明、治理有效、生活富裕,中国农民的美好梦想正在变成现实。 康辉:《宣誓号角》乐曲奏响,“民主法治”方阵向我们走来。彩车上,人民大会堂五星穹顶星光灿烂,《中华人民共和国宪法》庄严神圣,金色大手托起的,是我们共同捍卫人民民主的决心,是我们共同捍卫宪法法律尊严的承诺。 海霞:56个民族56支花,56族兄弟姐妹是一家。“民族团结”方阵中的各族群众,手拉手,载歌载舞而来。彩车上“石榴瓶”光彩夺目,各民族像石榴籽一样紧紧抱在一起,血脉相连,风雨同舟。 康辉:“人民有信仰,国家有力量,民族有希望”。“凝心铸魂”方阵走来,习近平新时代中国特色社会主义思想的火炬凝聚起强大的精神力量。强信心、聚民心、暖人心、筑同心,为国家立心,为民族立魂。14亿人一心谋发展,发展就有不竭动力。14亿人共爱一个家,祖国就欣欣向荣、日新月异。 海霞:“中华文化”方阵彩车上好戏连台,乐手八音迭奏,舞者摇曳生姿,戏曲精彩绝伦,百花齐放,各展芳华。一个民族的复兴需要强大的物质力量,也需要强大的精神力量,文化兴国运兴,文化强民族强。 康辉:“老师好!同学们好!”“立德树人”方阵中的师生代表们挥舞着校旗,簇拥着彩车从青春的歌声中走来。“打开的书本”生长出硕果累累的“知识树”,数据链组成的树干上耸立着“教育云”。三尺讲台系国运,只有德智体美劳全面发展的新一代才能真正肩负起民族复兴的重任。 海霞:竞技体育成绩傲人,全民健身蓬勃开展,冬奥筹备卓有成效,冰雪运动快速普及。“体育强国”方阵的彩车,以“冰丝带”速滑馆造型为底座,以“首钢滑雪大跳台”造型为车体。北京冬奥会和冬残奥会的吉祥物“冰墩墩”和“雪容融”正在彩车上向大家招手示意。 康辉:走在小康路上,一路歌美花香。来自独龙江乡、十八洞村等贫困地区驻村的“第一书记”出现在“脱贫攻坚”方阵的彩车上,6年时间,8000多万人脱贫,这是中国减贫史上的壮举,这是人类社会难以想象的奇迹!2020年,坚决打赢脱贫攻坚战,中华民族千百年来存在的绝对贫困问题将在我们这一代人的手里彻底解决。 海霞:美好生活是什么?是环卫工人清扫的整洁环境,是快递小哥便捷的物流服务,是医生护士的悉心照料,是最美家庭的幸福相伴,是老年模特队的神采奕奕,是残障人士的方便出行。彩车上“幼有所育、学有所教、劳有所得、病有所医、老有所养、住有所居、弱有所扶”的生活场景一一呈现。美好生活从哪儿来?中国人的回答是:从奋斗中来。 康辉:青山悠悠,绿水荡漾,生态环保战线的工作者组成“绿水青山”方阵。最严厉的环保执法,最大力度的环保投入,最深入人心的绿色生活理念,小到垃圾分类,大到江河治理。“绿水青山就是金山银山”这不仅是金句,更是中国最接地气的新发展理念。 海霞:巨大的鲲鹏造型彩车,引领“中华儿女”方阵向我们走来。鲲鹏展翅,扶摇直上,象征着中华民族生生不息、展翅腾飞。紧随其后的是各省、自治区、直辖市和香港、澳门、台湾的彩车。 康辉:第一辆是“首善北京”彩车; 海霞:这是“新时代新天津”彩车; 康辉:这是“盛世雄安”河北彩车; 海霞:这是“奋进山西”彩车; 康辉:这是“亮丽北疆”内蒙古彩车; 海霞:这是“展翅腾飞”辽宁彩车; 康辉:这是“速度吉林”彩车; 海霞:这是“中华粮仓”黑龙江彩车; 康辉:这是“奋进上海”彩车; 海霞:这是“江苏智造”彩车; 康辉:这是“潮涌之江”浙江彩车; 海霞:这是“美好安徽”彩车; 康辉:这是“高素质高颜值新福建”彩车; 海霞:这是“金色赣鄱”江西彩车; 康辉:这是“国泰民安”山东彩车; 海霞:这是“出彩中原”河南彩车; 康辉:这是“光耀湖北”彩车; 海霞:这是“潇湘今朝”湖南彩车; 康辉:这是“扬帆大湾”广东彩车; 海霞:这是“壮美广西”彩车; 康辉:这是“美好新海南”彩车; 海霞:这是“魅力重庆”彩车; 康辉:这是“逐梦兴川”四川彩车; 海霞:这是“多彩贵州”彩车; 康辉:这是“七彩云南”彩车; 海霞:这是“幸福西藏”彩车; 康辉:这是“壮阔三秦”陕西彩车; 海霞:这是“交响丝路 如意甘肃”彩车; 康辉:这是“中华水塔”青海彩车; 海霞:这是“建设美丽新宁夏”彩车; 康辉:这是“美丽新疆”彩车; 海霞:这是“香港,进”彩车; 康辉:这是“莲花绽放”澳门彩车; 海霞:最后一辆是“宝岛台湾”彩车。 康辉:一曲《千年之约》,婉转悠扬。中外青年携手前行,组成“人类命运共同体”方阵。彩车上,“一带一路”通古今,“友谊之桥”跨海陆,和平风帆共五洲。中国发展离不开世界,世界发展也需要中国。今天的节日,属于中国人民,也属于热爱和平的世界人民。 海霞:“从严治党”彩车上是全国先进基层党组织代表和全国优秀党务工作者代表,中央八项规定精神、“民有所呼,我有所应”、“学习强国”等新时代的党建成果生动呈现。中国特色社会主义进入新时代,党内政治生态展现新气象,反腐败斗争取得压倒性胜利,全面从严治党取得重大成果。党的面貌焕然一新,党群关系、干群关系更加紧密。 康辉:“不忘初心”方阵彩车上,焦裕禄、孔繁森、杨善洲等各个时期优秀共产党员的彩塑屹立山肩,全国优秀共产党员环立山腰,共产党人“全心全意为人民服务”承诺如山。 海霞:七十载惊涛拍岸,九万里风鹏正举。“扬帆远航”方阵中的“中国号”巨轮两侧云帆徐徐升起,乘着新时代的浩荡东风,承载着14亿中国人民的梦想,劈波斩浪,扬帆远航。“直挂云帆济沧海”。中国共产党掌舵领航,“中国号”巨轮向着实现中华民族伟大复兴的目标,奋勇前进! 康辉:红旗翻飞,鼓点激昂,2019名少先队员组成的行进乐团带来了第三段情境式行进“同心追梦”。少年当立凌云志,报效祖国会有时。中华民族伟大复兴的中国梦,终将在接续奋斗中成为现实。 海霞:“我和我的祖国,一刻也不能分割”,这是我们心中永远的歌。康辉:5000名首都各界群众组成了“祖国万岁”方阵。 海霞:70载风雨兼程,70载岁月峥嵘。 康辉:70载沧桑巨变,70载春华秋实。 海霞:祖国万岁大花篮,繁花锦簇,万紫千红,盘旋上升的红绸带寓意人民共和国发展蒸蒸日上。 海霞:70年,弹指一挥间。70年,我们重整行装再出发。 康辉:让我们紧密团结在以习近平同志为核心的党中央周围,高举中国特色社会主义伟大旗帜,以马克思列宁主义、毛泽东思想、邓小平理论、“三个代表”重要思想、科学发展观、习近平新时代中国特色社会主义思想为指导,为实现“两个一百年”奋斗目标和中华民族伟大复兴的中国梦而努力奋斗! 海霞:我们祝福祖国更加繁荣富强! 康辉:我们祝福人民更加幸福安康! 海霞、康辉:我们祝福明天更加灿烂辉煌! 李克强:庆祝大会到此结束。 7万羽和平鸽展翅高飞,7万只气球腾空而起,伴着《歌唱祖国》的激昂旋律,庆祝大会圆满结束。 人民日报评论 奋斗的史诗 复兴的伟力——热烈庆祝中华人民共和国成立七十周年 70年前的10月1日,第一面五星红旗冉冉升起,新生的人民共和国迎着朝阳出发,一路披荆斩棘,一路凯歌行进,把一个又一个胜利写在这片古老的土地上。 70年后,迎着又一个10月1日的晨曦,新长征路上的人民共和国,重整行装再出发。在新中国成立70周年的历史性时刻,近14亿中华儿女满怀喜悦和豪情,共庆人民共和国华诞,共享伟大祖国荣光! 时间是伟大的书写者,记录走过的足迹,写下历史的华章。新中国成立70年来,中国大地沧海桑田,我们伟大祖国的面貌、伟大人民的面貌、中华民族的面貌发生了前所未有的大变化。70年风雨兼程,70年砥砺奋进,中国共产党带领人民开启筚路蓝缕的创业征程,掀起气壮山河的建设浪潮,闯出波澜壮阔的改革之路,张开拥抱世界的开放胸怀,创造了世所罕见的经济快速发展奇迹和社会长期稳定奇迹。以党的十八大为标志,中国特色社会主义进入新时代,中华民族迎来了从站起来、富起来到强起来的伟大飞跃。今天,曾经温饱不足的人们,即将迈入全面小康;曾经一穷二白的中国,巍然屹立于世界东方;曾经积贫积弱的民族,迎来伟大复兴的光明前景。正如习近平总书记豪迈宣示的:“历史充分证明,中国共产党和中国人民不仅善于打破一个旧世界,而且善于建设一个新世界。展望未来,中国的发展前景无限美好。” 雄关漫道真如铁,人间正道是沧桑。70年来新中国的发展历程,充满着苦难和辉煌、曲折和胜利、付出和收获。习近平总书记高度评价:“无论是在中华民族历史上,还是在世界历史上,这都是一部感天动地的奋斗史诗。” 1949—2019,这一部感天动地的奋斗史诗,印证了中国共产党人的初心和使命。实现中华民族伟大复兴,是近代以来中华民族最伟大的梦想。中国共产党一经成立,就义无反顾肩负起“为中国人民谋幸福、为中华民族谋复兴”的历史使命。近百年来,无论是弱小还是强大,无论是顺境还是逆境,我们党都初心不改、矢志不渝,团结带领人民历经千难万险,付出巨大牺牲,敢于面对曲折,勇于修正错误,攻克了一个又一个看似不可攻克的难关,创造了一个又一个彪炳史册的人间奇迹。新中国70年巨变的根本原因,70年历史性变革的内在逻辑,就是中国共产党的领导。中国共产党领导是中国特色社会主义最本质的特征,是中国特色社会主义制度的最大优势。在前进道路上,这个立志于千秋伟业的人民政党,牢记初心使命、推进自我革命,始终是中国人民和中华民族的主心骨,始终是复兴征程上的坚强领导核心。 1949—2019,这一部感天动地的奋斗史诗,彰显了亿万人民的奋斗与豪情。“人民是共和国的坚实根基,人民是我们执政的最大底气。”亿万人胼手胝足的勤劳奋斗,成为一代又一代中国人的集体记忆;无数人奋勇向前的铿锵步履,汇成新中国70年发展壮大的雄浑乐章。今天,中国人民拥有的一切,都是拼搏奋斗干出来的,凝聚着追梦人的聪明才智,浸透着奋斗者的辛勤汗水。依靠人民的支持和信任,“与人民心心相印、与人民同甘共苦、与人民团结奋斗”,我们书写了无愧于时代、无愧于人民、无愧于历史的业绩。有创造历史的激情,有实现梦想的能力,有续写奇迹的信心,亿万人民撸起袖子加油干,一定能把我们的人民共和国建设得更加繁荣富强。 1949—2019,这一部感天动地的奋斗史诗,铸就了中国特色社会主义的成功与辉煌。在新中国70年的持续探索中,特别是在改革开放40多年的伟大实践中,我们开创和发展了中国特色社会主义,从根本上改变了中国人民和中华民族的前途命运。治理中国这样一个大国不容易,但我们交出了一份优异的答卷。中国特色社会主义的巨大成功,用事实宣告了“历史终结论”的破产,宣告了各国最终都要以西方制度模式为归宿的单线式历史观的破产。70年来形成的中国特色社会主义制度和国家治理体系,显示出强大生命力和巨大优越性。今天,我们的道路越走越宽广、我们的理论不断发展、我们的制度日趋成熟、我们的文化持续繁荣。历史必将证明,中国特色社会主义,是一条引领中华民族走向伟大复兴的必由之路。 大道之行,天下为公。从一个积贫积弱的落后国家发展成为世界第二大经济体,中国靠的不是对外扩张和殖民掠夺,而是始终不渝走和平发展之路。70年来,中国专注于“把自己的事情办好”,走出了一条现代化的新路。多年来中国对世界经济增长贡献率超过30%,已连续13年成为世界经济增长的“第一引擎”,更以推动“一带一路”建设、构建人类命运共同体展现出一个大国担当、开放的胸怀。中国特色社会主义道路、理论、制度、文化不断发展,拓展了发展中国家走向现代化的途径,给世界上那些既希望加快发展又希望保持自身独立性的国家和民族提供了全新选择,为解决人类问题贡献了中国智慧和中国方案。世界命运握在各国人民手中,人类前途系于各国人民的抉择。中国人民愿同各国人民一道,推动人类命运共同体建设,共同创造人类的美好未来。 时代大潮滚滚向前,复兴伟力不可阻挡。当今世界正经历百年未有之大变局,实现中华民族伟大复兴正处于关键时期,我们正在进行具有许多新的历史特点的伟大斗争。展望未来,决胜全面小康、开启强国征程,中华民族伟大复兴绝不是轻轻松松、敲锣打鼓就能实现的。对历史最好的致敬,是书写新的历史;对未来最好的把握,就是开创更美好的未来。让我们更加紧密地团结在以习近平同志为核心的党中央周围,增强“四个意识”、坚定“四个自信”、做到“两个维护”,万众一心、众志成城,在实现中华民族伟大复兴的新长征中创造新的更大奇迹! 祝福伟大祖国更加繁荣昌盛! 祝福中华民族昂首走向复兴! 说在最后慢慢看视频暂停截图上传,插入对应的文字后面,用时几个小时,整理不易,且看且珍惜。转载请标明出处,由辣椒の酱收集整理。","link":"/breaking-news/2019%E5%B9%B4%E5%9B%BD%E5%BA%8670%E5%91%A8%E5%B9%B4%E9%98%85%E5%85%B5%E5%AE%8C%E6%95%B4%E5%9B%BE%E6%96%87%E8%A7%A3%E8%AF%B4.html"},{"title":"springboot websocket server服务端代码demo","text":"后端java springboot 项目 简单websocket server 端代码 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465<?xml version=\"1.0\" encoding=\"UTF-8\"?><project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"> <modelVersion>4.0.0</modelVersion> <groupId>com.cloudkd</groupId> <artifactId>websocket-server</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>websocket</name> <description>websocket for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.20</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project> // 定义相关地址,以及session集合,用户存储管理client ws://{ip}:{port}/websocket/data 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151package com.cloudkd.websocket;import java.io.IOException;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;import com.alibaba.fastjson.JSONObject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;@ServerEndpoint(\"/websocket/data\")@Componentpublic class WebSocketServer { private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class); //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; public static void kill(String id) { for (WebSocketServer item : webSocketSet) { try { if (item.session.getId().equals(id)) { log.info(\"Kill {} success\", id); item.session.close(); } } catch (IOException ignored) { } } } public static Map<String, Object> getAllSessionIds() { Map<String, Object> map = new HashMap<>(); for (WebSocketServer item : webSocketSet) { map.put(item.session.getId(),item.session.getId()); } return map; } /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session) { this.session = session; //加入set中 webSocketSet.add(this); //在线数加1 addOnlineCount(); log.info(\"有新连接加入!当前在线人数为\" + getOnlineCount()); try { sendMessage(\"连接成功\"); } catch (IOException e) { log.error(\"websocket IO异常\"); } } // //连接打开时执行 // @OnOpen // public void onOpen(@PathParam(\"user\") String user, Session session) { // currentUser = user; // System.out.println(\"Connected ... \" + session.getId()); // } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 subOnlineCount(); //在线数减1 log.info(\"有一连接关闭!当前在线人数为\" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session) { log.info(\"来自客户端的消息 sessionId = {} ,data :{}\", session.getId(), message); //群发消息 // for (WebSocketServer item : webSocketSet) { // try { // item.sendMessage(message); // } catch (IOException e) { // e.printStackTrace(); // }// } } /** * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { log.error(\"发生错误\"); error.printStackTrace(); } public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 群发自定义消息 */ public static void sendInfo(BodyEntity message) { log.info(\"SEND MESSAGE:{}\", message); for (WebSocketServer item : webSocketSet) { try { if (item.session.getId().equals(message.getSessionId())) { JSONObject sa = JSONObject.parseObject(message.getMessage()); item.sendMessage(sa.toString()); } } catch (IOException ignored) { } } } private static synchronized int getOnlineCount() { return onlineCount; } private static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } private static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; }} // WebSocketConfig 相关配置 12345678910111213package com.cloudkd.websocket;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configurationpublic class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }} // 管理api,可往对应连接发送消息 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960package com.cloudkd.websocket;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.*;import java.util.HashMap;import java.util.Map;@RestControllerpublic class ManageController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @PostMapping(value = \"/pushData\") public Map<String, Object> pushVideoListToWeb(@RequestBody BodyEntity message) { Map<String, Object> result = new HashMap<String, Object>(); try { WebSocketServer.sendInfo(message); result.put(\"operationResult\", true); } catch (Exception e) { result.put(\"operationResult\", true); } return result; } @GetMapping(value = \"/kill\") public Map<String, Object> pushVideoListToWeb(String id) { WebSocketServer.kill(id); return new HashMap<>(); } @GetMapping(value = \"/getAll\") public Map<String, Object> getAll() { return WebSocketServer.getAllSessionIds(); }}package com.cloudkd.websocket;public class MessageEntity { private String message; private String sessionId; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; }} // 测试页面 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137<!DOCTYPE html><html lang=\"en\"><head> <meta charset=\"UTF-8\"> <title>Title</title> </head><body><h3>server地址 :</h3> <input id=\"serveraddress\" type=\"text\" value=\"ws://192.168.102.17:28080/elevator/realData\" style=\"width: 500px;%\"/><br/><h3>您的用户id :</h3> <input id=\"userId\" type=\"text\"/><br/><button onclick=\"initSocket()\">连接</button><br/>=====================================================<br/>消息 : <input id=\"message\" type=\"text\"/><br/><button onclick=\"send()\">发送</button><br/>=====================================================<br/>连接状态 :<button onclick=\"clearConnectStatu()\">清空</button><br/><div id=\"connectStatu\"></div><br/>=====================================================<br/>收到消息 :<br/><div id=\"receivedMessage\"></div><br/>=====================================================<br/>心跳 :<br/><div id=\"heartdiv\"></div><br/></body><script src=\"https://code.jquery.com/jquery-3.1.1.min.js\"></script><script type=\"text/javascript\"> var heartflag = false; var webSocket = null; var tryTime = 0; $(function () {// initSocket(); window.onbeforeunload = function () { }; }); /** * 初始化websocket,建立连接 */ function initSocket() { var serveraddress = $(\"#serveraddress\").val(); var userId = $(\"#userId\").val(); if (!window.WebSocket) { $(\"#connectStatu\").append(getNowFormatDate() + \" 您的浏览器不支持ws<br/>\"); return false; } webSocket = new WebSocket(serveraddress/* + \"/\" + userId*/); // 收到服务端消息 webSocket.onmessage = function (msg) { if (msg.data !== \"&\") { $(\"#receivedMessage\").append(getNowFormatDate() + \" 收到消息 : \" + msg.data + \"<br/>\"); } }; // 异常 webSocket.onerror = function (event) { heartflag = false; $(\"#connectStatu\").append(getNowFormatDate() + \" 异常<br/>\"); }; // 建立连接 webSocket.onopen = function (event) { heartflag = true; heart(); $(\"#connectStatu\").append(getNowFormatDate() + \" 建立连接成功<br/>\"); tryTime = 0; }; // 断线重连 webSocket.onclose = function () { heartflag = false; // 重试10次,每次之间间隔10秒 if (tryTime < 10) { setTimeout(function () { webSocket = null; tryTime++; initSocket(); $(\"#connectStatu\").append(getNowFormatDate() + \" 第\" + tryTime + \"次重连<br/>\"); }, 3 * 1000); } else { alert(\"重连失败.\"); } }; } function send() { var message = $(\"#message\").val(); webSocket.send(message); } function clearConnectStatu() { $(\"#connectStatu\").empty(); } function getNowFormatDate() { var date = new Date(); var seperator1 = \"-\"; var seperator2 = \":\"; var month = date.getMonth() + 1; var strDate = date.getDate(); if (month >= 1 && month <= 9) { month = \"0\" + month; } if (strDate >= 0 && strDate <= 9) { strDate = \"0\" + strDate; } var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate + \" \" + date.getHours() + seperator2 + date.getMinutes() + seperator2 + date.getSeconds(); return currentdate; } function heart() { if (heartflag) { webSocket.send(\"&\"); $(\"#heartdiv\").append(getNowFormatDate() + \" 心跳 <br/>\"); } setTimeout(\"heart()\", 10 * 60 * 1000); }</script></html> // 配置文件 1server.port=8081 // 启动Main 1234567@SpringBootApplicationpublic class WebsocketApplication { public static void main(String[] args) { SpringApplication.run(WebsocketApplication.class, args); }} 启动后默认,返回 http://{ip}:8081 ,进入测试页面","link":"/java/frame/springboot-websocket-server%E4%BB%A3%E7%A0%81demo%E7%A4%BA%E4%BE%8B.html"},{"title":"Github-Action自动部署Hexo博客","text":"写好文件,提交到GitHub将会自动部署Hexo 博客 仓库目录中增加以下文件: .github\\workflows\\autodeploy.yml内容如下 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758# 当有改动推送到master分支时,启动Actionname: 自动部署on: push: branches: - main #2020年10月后github新建仓库默认分支改为main,注意更改 release: types: - publishedjobs: deploy: runs-on: ubuntu-latest steps: - name: 检查分支 uses: actions/checkout@v2 with: ref: main #2020年10月后github新建仓库默认分支改为main,注意更改 - name: 安装 Node uses: actions/setup-node@v1 with: node-version: \"14.x\" #action使用的node版本,建议大版本和本地保持一致。可以在本地用node -v查询版本号。 - name: 安装 Hexo run: | export TZ='Asia/Shanghai' npm install hexo-cli -g - name: 缓存 Hexo uses: actions/cache@v1 id: cache with: path: node_modules key: ${{runner.OS}}-${{hashFiles('**/package-lock.json')}} - name: 安装依赖 run: | npm -v npm install --save echo \"'use strict';const pagination=require('hexo-pagination');module.exports=function(locals){var config=this.config;var posts=locals.posts;posts.data=posts.data.sort(function(a,b){if(a.top==undefined){a.top=0;}if(b.top==undefined){b.top=0;}if(a.top==b.top){return b.date-a.date;}else{return b.top-a.top;}});var paginationDir=config.pagination_dir||'page';return pagination('',posts,{perPage:config.index_generator.per_page,layout:['index','archive'],format:paginationDir+'/%d/',data:{__index:true}});};\" > ./node_modules/hexo-generator-index/lib/generator.js # 可执行任何脚本,此处增加排序的逻辑 - name: 生成静态文件 run: | hexo clean hexo generate - name: 部署 #此处master:master 指从本地的master分支提交到远程仓库的master分支,若远程仓库没有对应分支则新建一个。如有其他需要,可以根据自己的需求更改。 run: | cd ./public git init git config --global user.name '${{ secrets.GITHUBUSERNAME }}' git config --global user.email '${{ secrets.GITHUBEMAIL }}' git add . git commit -m \"${{ github.event.head_commit.message }} $(date +\"%Z %Y-%m-%d %A %H:%M:%S\") Updated By Github Actions\" git push --force --quiet \"https://${{ secrets.GITHUBUSERNAME }}:${{ secrets.GITHUBTOKEN }}@github.com/${{ secrets.GITHUBUSERNAME }}/${{ secrets.GITHUBREPO }}.git\" master:main 代码中有相应的变量$,需要自行添加到仓库的配置中。","link":"/theme/Github-Action%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2Hexo%E5%8D%9A%E5%AE%A2.html"},{"title":"后续计划","text":"TODO 重构博客 优化代码 坚持写优质博文","link":"/think/%E5%90%8E%E7%BB%AD%E8%AE%A1%E5%88%92.html"},{"title":"springboot接入dubbo-nacos注册中心","text":"springboot接入dubbo-nacos注册中心 项目结构: pro-parentparent.pom 12345678910111213141516<?xml version=\"1.0\" encoding=\"UTF-8\"?><project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"> <artifactId>pro-parent</artifactId> <groupId>removeif.io.java</groupId> <version>1.0-SNAPSHOT</version> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging> <modules> <module>service-api</module> <module>service-provider</module> <module>service-consumer</module> </modules></project> 暴露服务接口apiservice-api.pom 12345678910111213<?xml version=\"1.0\" encoding=\"UTF-8\"?><project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"> <parent> <artifactId>pro-parent</artifactId> <groupId>removeif.io.java</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>service-api</artifactId></project> service-api.class 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970package io.github.removeif.springboot.api;import io.github.removeif.springboot.dto.UserDTO;/** * 用户服务 RPC Service 接口 */public interface UserRpcService { /** * 根据指定用户编号,获得用户信息 * * @param id 用户编号 * @return 用户信息 */ UserDTO get(Integer id);}package io.github.removeif.springboot.dto;import java.io.Serializable;/** * 用户信息 DTO */public class UserDTO implements Serializable { /** * 用户编号 */ private Integer id; /** * 昵称 */ private String name; /** * 性别 */ private Integer gender; public Integer getId() { return id; } public UserDTO setId(Integer id) { this.id = id; return this; } public String getName() { return name; } public UserDTO setName(String name) { this.name = name; return this; } public Integer getGender() { return gender; } public UserDTO setGender(Integer gender) { this.gender = gender; return this; }} 服务提供方service-providerservice-provider.pom 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556<?xml version=\"1.0\" encoding=\"UTF-8\"?><project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>service-provider</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- 引入定义的 Dubbo API 接口 --> <dependency> <artifactId>service-api</artifactId> <groupId>removeif.io.java</groupId> <version>1.0-SNAPSHOT</version> </dependency> <!-- 引入 Spring Boot 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- Dubbo Spring Cloud Starter --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> <version>2.2.3.RELEASE</version> </dependency> <!-- Spring Cloud Nacos Service Discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.3.RELEASE</version> </dependency> </dependencies></project> service-provider.yaml 1234567891011121314151617181920212223242526spring: application: name: user-service-provider# dubbo 配置项,对应 DubboConfigurationProperties 配置类dubbo: # Dubbo 应用配置 application: name: user-service-provider # 应用名 # Dubbo 注册中心配 registry: address: nacos://127.0.0.1:8848 # 注册中心地址。可以配置多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 group: dev #分组 可用于环境隔离,不同分组不能调用 parameters[namespace]: dev # 空间管理 # Dubbo 服务提供者协议配置 protocol: port: -1 # 协议端口。使用 -1 表示随机端口。 name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 # Dubbo 服务提供者配置 provider: timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,可以根据自己业务修改 UserRpcService: version: 1.0.0 # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 scan: base-packages: io.github.removeif.springboot.service group以及namespace对应nacos中结构: service-provider.class 1234567891011121314151617181920212223242526272829303132333435package io.github.removeif.springboot.service;import io.github.removeif.springboot.api.UserRpcService;import io.github.removeif.springboot.dto.UserDTO;import org.apache.dubbo.config.annotation.DubboService;@DubboService(version = \"${dubbo.provider.UserRpcService.version}\")public class UserRpcServiceImpl implements UserRpcService { @Override public UserDTO get(Integer id) { return new UserDTO().setId(id) .setName(\"没有昵称:\" + id) .setGender(id % 2 + 1); // 1 - 男;2 - 女 }}package io.github.removeif.springboot;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@EnableDubbopublic class ProviderApplication { public static void main(String[] args) { // 启动 Spring Boot 应用 SpringApplication.run(ProviderApplication.class, args); }} 消费方service-consumerservice-consumer.pom 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657<?xml version=\"1.0\" encoding=\"UTF-8\"?><project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>service-consumer</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- 引入定义的 Dubbo API 接口 --> <dependency> <artifactId>service-api</artifactId> <groupId>removeif.io.java</groupId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Dubbo Spring Cloud Starter --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> <version>2.2.3.RELEASE</version> </dependency> <!-- 引入 Spring Boot 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.2.3.RELEASE</version> </dependency> <!-- Spring Cloud Nacos Service Discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.3.RELEASE</version> </dependency> </dependencies></project> service-consumer.ymal 12345678910111213141516171819202122spring: application: name: user-service-consumer# dubbo 配置项,对应 DubboConfigurationProperties 配置类dubbo: # Dubbo 应用配置 application: name: user-service-consumer # 应用名 # Dubbo 注册中心配置 registry: address: nacos://127.0.0.1:8848 # 注册中心地址。可以配置多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 group: dev #分组 parameters[namespace]: dev # 空间管理 # Dubbo 消费者配置 consumer: timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,可以根据自己业务修改 UserRpcService: version: 1.0.0 protocol: port: -1 name: dubbo service-consumer.class 123456789101112131415161718192021222324252627282930313233343536373839package io.github.removeif.springboot;import io.github.removeif.springboot.api.UserRpcService;import io.github.removeif.springboot.dto.UserDTO;import org.apache.dubbo.config.annotation.DubboReference;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.stereotype.Component;@SpringBootApplication@EnableDubbopublic class ConsumerApplication { public static void main(String[] args) { // 启动 Spring Boot 应用 ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); } @Component public class UserRpcServiceTest implements CommandLineRunner { private final Logger logger = LoggerFactory.getLogger(getClass()); @DubboReference(version = \"${dubbo.consumer.UserRpcService.version}\") private UserRpcService userRpcService; @Override public void run(String... args) throws Exception { UserDTO user = userRpcService.get(1); logger.info(\"[run][发起一次 Dubbo RPC 请求,获得用户为({})\", user); } }} 启动provider,在启动consumer后可以看到控制台 123452020-12-19 11:36:49.219 INFO 16272 --- [ main] c.a.c.n.registry.NacosServiceRegistry : nacos registry, DEFAULT_GROUP user-service-consumer 192.168.88.1:20881 register finished2020-12-19 11:36:49.228 INFO 16272 --- [ main] s.ConsumerApplication$UserRpcServiceTest : [run][发起一次 Dubbo RPC 请求,获得用户为(io.github.removeif.springboot.dto.UserDTO@79696332)2020-12-19 11:36:49.231 INFO 16272 --- [ main] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848] [subscribe] user-service-consumer+DEFAULT_GROUP2020-12-19 11:36:49.231 INFO 16272 --- [ main] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848] [add-listener] ok, tenant=, dataId=user-service-consumer, group=DEFAULT_GROUP, cnt=1","link":"/java/frame/springboot-dubbo-nacos-example.html"},{"title":"Java-策略模式","text":"策略模式遵循开闭原则,实现代码的解耦合。扩展新的方法时也比较方便,只需要继承策略接口就好了上面列出的这两点算是策略模式的优点了,但是不是说他就是完美的,有很多缺点仍然需要我们去掌握和理解。策略模式把对象本身和运算规则区分开来,因此我们整个模式也分为三个部分。 环境类(Context):用来操作策略的上下文环境,也就是我们游客。 抽象策略类(Strategy):策略的抽象,出行方式的抽象 具体策略类(ConcreteStrategy):具体的策略实现,每一种出行方式的具体实现。 一、策略模式定义举个列子 我们出去旅游的时候可能有很多种出行方式,比如说我们可以坐火车、坐高铁、坐飞机等等。不管我们使用哪一种出行方式,最终的目的地都是一样的。也就是选择不同的方式产生的结果都是一样的。 定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换 二、实现策略模式策略模式把对象本身和运算规则区分开来,因此我们整个模式也分为三个部分。 环境类(Context):用来操作策略的上下文环境,也就是我们游客。 抽象策略类(Strategy):策略的抽象,出行方式的抽象 具体策略类(ConcreteStrategy):具体的策略实现,每一种出行方式的具体实现。 第一步:定义抽象策略接口123interface TravelStrategy{ void travelStyle();} 第二步:具体策略类1234567891011121314151617181920public class TrainStrategy implements TravelStrategy{ @Override public void travelStyle(){ System.out.println(\"火车\"); }}public class HighTrainStrategy implements TravelStrategy{ @Override public void travelStyle(){ System.out.println(\"高铁\"); }}public class AirplaneStrategy implements TravelStrategy{ @Override public void travelStyle(){ System.out.println(\"飞机\"); }} 第三步:环境类实现1234567891011121314151617public class Traveler{ private TravelStrategy travelStrategy; public void setTravelStrategy(TravelStrategy travelStrategy){ this.travelStrategy = travelStrategy; } public void travelStyle(){ travelStrategy.travelStyle(); } public static void main(String[] args){ Traveler traveler = new Traveler(); traveler.setTravelStrategy(new AirplaneStrategy()) // 飞机出行 traveler.travelStyle() }} 三、分析策略模式策略模式的优点: 我们之前在选择出行方式的时候,往往会使用if-else语句,也就是用户不选择A那么就选择B这样的一种情况。这种情况耦合性太高了,而且代码臃肿,有了策略模式我们就可以避免这种现象。 策略模式遵循开闭原则,实现代码的解耦合。扩展新的方法时也比较方便,只需要继承策略接口就好了上面列出的这两点算是策略模式的优点了,但是不是说他就是完美的,有很多缺点仍然需要我们去掌握和理解。 策略模式的优点: 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。 策略模式会出现很多的策略类。 context在使用这些策略类的时候,这些策略类由于继承了策略接口,所以有些数据可能用不到,但是依然初始化了。 参考文章:参考链接","link":"/java/design-mode/java-strategy-pattern.html"},{"title":"mysql允许最大sql语句长度配置","text":"MySQL对于每个客户端连接都会分配连接buffer和结果集发送的buffer,连接buffer主要就是来接受客户端发送过来的sql语句,并且初始分配大小都是 net_buffer_length,可以动态增长,最多可以达到 max_allow_packet大小。这个参数是会话只读的,言外之意就是只能全局修改,新建连接才生效。max_allow_packet是MySQL控制网络包大小的参数,默认是4M。有次可控制一条mysql查询语句大大小,实现mysql慢sql相关优化。 一、前言前几天在生产环境抓到一条慢SQL,内容大致如下: 1select xxx from table where conditions and id in (in_list); 这个SQL看起来貌似没有什么问题,但是 in_list的元素个数多达3000多个,然后我尝试统计了这个表的总数据量,刚好跟这个 in_list吻合,用大腿猜了下,应该是用了框架,先查出表里所有的数据放入list,再进行拼接生成的SQL,这尼玛不是蠢么。 二、问题抛开这个蠢不蠢的问题,我比较关心的是在MySQL里面,这个 in_list的元素个数能不能控制。咨询了下叶师傅,加上自己搜索了一圈文档,很遗憾,MySQL没法限制这个 in_list的元素个数。那么既然没法控制 in_list,那我们是不是可以控制sql语句的长度呢? net_buffer_length MySQL有一个参数叫做 net_buffer_length,它是做什么用的呢? 1Each client thread is associated with a connection buffer and result buffer. Both begin with a size given by net_buffer_length but are dynamically enlarged up to max_allowed_packet bytes as needed. The result buffer shrinks to net_buffer_length after each SQL statement.This variable should not normally be changed, but if you have very little memory, you can set it to the expected length of statements sent by clients. If statements exceed this length, the connection buffer is automatically enlarged. The maximum value to which net_buffer_length can be set is 1MB.The session value of this variable is read only. 简单翻译一下的意思就是,MySQL对于每个客户端连接都会分配连接buffer和结果集发送的buffer,连接buffer主要就是来接受客户端发送过来的sql语句,并且初始分配大小都是 net_buffer_length,可以动态增长,最多可以达到 max_allow_packet大小。这个参数是会话只读的,言外之意就是只能全局修改,新建连接才生效。max_allow_packet是MySQL控制网络包大小的参数,默认是4M。 三、测试既然是这样的话,我们就来测试一把,下面是我的测试过程。 参数设置 1234567891011121314root@mysqldb 16:58: [(none)]> show global variables like 'net_buffer_length';+-------------------+-------+| Variable_name | Value |+-------------------+-------+| net_buffer_length | 16384 |+-------------------+-------+1 row in set (0.00 sec)root@mysqldb 17:00: [(none)]> show global variables like 'max_allowed_packet';+--------------------+--------+| Variable_name | Value |+--------------------+--------+| max_allowed_packet | 131072 |+--------------------+--------+ 这里我设置 net_buffer_length为16K, max_allowed_packet为128K 测试脚本 1234567891011121314151617181920212223242526272829#!/bin/env python#coding:utf-8import pymysqldef get_in_list(i): in_list = '' for i in range(1,i): in_list = str(i) + ',' + in_list in_list = in_list + str(i+1) return in_listdef exec_mysql(sql): conn = pymysql.connect(host='127.0.0.1', user='xucl', password='xuclxucl123', database='sbtest', charset='utf8') cursor = conn.cursor() cursor.execute(sql) results = cursor.fetchall() if results: print(\"get results\") conn.close()if __name__ == \"__main__\": in_list = get_in_list(100) sql = \"select * from sbtest1 where id in ({})\".format(in_list) # 打印出sql占用的字节数 print(len(in_list.encode())) exec_mysql(sql) 测试结果 当i为4200时,sql大小为19892字节(大于 net_buffer_length),MySQL能正常返回数据,结果如下 1[root@izbp13wpxafsmeraypddyvz python_scripts]# python test.py 19892get results 当i为23690时,sql大小为131033字节(小于 max_allowed_packet),也能正常输出,结果如下,此时sql的字节数为131033 1[root@izbp13wpxafsmeraypddyvz python_scripts]# python test.py 131033get results 当i为23691时,sql大小为131039字节(仍然小于 max_allowed_packet),抛出异常 123456789101112131415161718192021222324[root@izbp13wpxafsmeraypddyvz python_scripts]# python test.py 131039Traceback (most recent call last): File \"test.py\", line 29, in <module> exec_mysql(sql) File \"test.py\", line 19, in exec_mysql cursor.execute(sql) File \"/usr/lib64/python2.7/site-packages/pymysql/cursors.py\", line 170, in execute result = self._query(query) File \"/usr/lib64/python2.7/site-packages/pymysql/cursors.py\", line 328, in _query conn.query(q) File \"/usr/lib64/python2.7/site-packages/pymysql/connections.py\", line 517, in query self._affected_rows = self._read_query_result(unbuffered=unbuffered) File \"/usr/lib64/python2.7/site-packages/pymysql/connections.py\", line 732, in _read_query_result result.read() File \"/usr/lib64/python2.7/site-packages/pymysql/connections.py\", line 1075, in read first_packet = self.connection._read_packet() File \"/usr/lib64/python2.7/site-packages/pymysql/connections.py\", line 684, in _read_packet packet.check_error() File \"/usr/lib64/python2.7/site-packages/pymysql/protocol.py\", line 220, in check_error err.raise_mysql_exception(self._data) File \"/usr/lib64/python2.7/site-packages/pymysql/err.py\", line 109, in raise_mysql_exception raise errorclass(errno, errval)pymysql.err.InternalError: (1153, u\"Got a packet bigger than 'max_allowed_packet' bytes\") MySQL错误日志如下: 12020-03-10T09:07:46.992043Z 32 [Note] Aborted connection 32 to db: 'sbtest' user: 'xucl' host: '127.0.0.1' (Got a packet bigger than 'max_allowed_packet' bytes) 释惑 为什么sql字节数为131039<131072( max_allowed_packet大小),MySQL还是报错了呢?因为这里还需要加上MySQL的包头大小,这个包头的大小是多少呢?还是用i=23690的例子,在MySQL服务器上抓包 看到MySQL接收到的包大小是131070字节,那么这个包头大小就为37字节了(未深入研究,留到以后研究),而上述实验中i=23691的例子中,sql大小为131039字节,加上包头的大小37字节,总大小为131076字节,大于 max_allowed_packet的131072,所以MySQL报错,符合逻辑。 四、结论经过这次测试,得出了以下节点结论 虽然MySQL没有限制子查询内元素个数,但是还是不建议元素太多,会影响执行计划同时也会影响SQL解析的效率和内存占用 适当调大 net_buffer_length,最好能够一次性缓存sql,无需再分配内存,并且这是一个全局性参数 适当调大 max_allowed_packet大小,但是也不要分配过大,这是一个会话级变量,生产建议调为32M为佳 学会利用抓包解决”网络”相关的问题 参考文章:参考链接","link":"/database/mysql/mysql%E5%85%81%E8%AE%B8%E6%9C%80%E5%A4%A7sql%E8%AF%AD%E5%8F%A5%E9%95%BF%E5%BA%A6%E9%85%8D%E7%BD%AE.html"},{"title":"github gpg failed to sign the data","text":"git gpg commit sign error:gpg failed to sign the datafatal: failed to write commit object 1234567891011121314brew uninstall gpgbrew install gpg2brew install pinentry-mac (if needed)gpg --full-generate-key #Create a key by using an algorithm.#Get generated key by executing: gpg --list-keys#detail listgpg --list-secret-keys --keyid-format LONGsec rsa2048/F9F78B768Fxxxxx 2020-03-13 [SC] [有效至:2022-03-13] 79418A9275A4D98B86FF39F6xxxxxxxxxxx#Set the key here git config --global user.signingkey F9F78B768Fxxxxxgit config --global gpg.program /usr/local/bin/gpggit config --global commit.gpgsign true If you want to export your Key to GitHub then:gpg --armor --export F9F78B768Fxxxxx and add this key to GitHub at GPG keys: https://github.com/settings/keys (with START and END line included) If the issue still exists: 123test -r ~/.bash_profile && echo 'export GPG_TTY=$(tty)' >> ~/.bash_profileecho 'export GPG_TTY=$(tty)' >> ~/.profile If the issue still exists: Install https://gpgtools.org and sign the key that you used by pressing Sign from the menu bar: Key->Sign If the issue still exists: Go to: ‎⁨your global .gitconfig file which in my case is at: ‎⁨/Users/gent/.gitconfig And modify the .gitconfig file (please make sure Email and Name are the same with the one that you have created while generating the Key): 1234567891011121314151617[user] email = gent@youremail.com name = Gent signingkey = <YOURKEY>[gpg] program = /usr/local/bin/gpg[commit] gpsign = true gpgsign = true[filter \"lfs\"] process = git-lfs filter-process required = true clean = git-lfs clean -- %f smudge = git-lfs smudge -- %f[credential] helper = osxkeychain When you create and add a key to gpg-agent you define something called passphrase. Now that passphrase at some point expires, and gpg needs you to enter it again to unlock your key so that you can start signing again. When you use any other program that interfaces with gpg, gpg’s prompt to you to enter your passphrase does not appear (basically gpg-agent when daemonized cannot possibly show you the input dialog in stdin). One of the solutions is gpg --sign a_file.txt (this is very import!!!) then enter the passphrase that you have entered when you created your key and then everything should be fine (gpg-agent should automatically sign) See this answer on how to set longer timeouts for your passphrase so that you do not have to do this all the time. Or you can completely remove the passphrase with ssh-keygen -p Edit: Do a man gpg-agent to read some stuff on how to have the above happen automatically and add the lines: GPG_TTY=$(tty)export GPG_TTYon your .bashrc if you are using bash(this is the correct answer but I am keeping my train of thought above as well) my environment 1234567gpg --versiongpg (GnuPG) 2.2.19libgcrypt 1.8.5Copyright (C) 2019 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. reference:reference","link":"/develop/github-gpg-failed-to-sign-the-data.html"},{"title":"mysql-like模糊查询优化","text":"sql语句写法一张表大概40万左右的数据,用like模糊查询title字段,很慢,title字段已经建立了索引,mysql 对 someTitle% 这样的模糊查询在有索引的前提下是很快的。所以下面这两台sql语句差别就很大了$sql1 = “… title like someTitle%” (0.001秒) $sql2 = “…… title like %someTitle%” (0.8秒) 这两句的效率相差了800倍,这很可观啊。所以我有个想法:在不用分词的方法的前提下,把存储的title字段,加一个特别的前缀,比如”im_prefix”,比如一条记录的title=”我是标题党”,那么存储的时候就存储为”im_prefix我是标题党”。这样一来,我们要模糊查找”标题党”这个关键词的时候,就把sql写成这样:$sql1 = “…… title like im_prefix%标题党%” (花费0.001秒),前台显示数据的时候,自然把取到的title过滤掉”im_prefix”这个前缀了。 在使用msyql进行模糊查询的时候,很自然的会用到like语句,通常情况下,在数据量小的时候,不容易看出查询的效率,但在数据量达到百万级,千万级的时候,查询的效率就很容易显现出来。这个时候查询的效率就显得很重要! 一般情况下like模糊查询的写法为(field已建立索引): SELECTcolumnFROMtableWHEREfieldlike’%keyword%’; 上面的语句用explain解释来看,SQL语句并未用到索引,而且是全表搜索,如果在数据量超大的时候,可想而知最后的效率会是这样 对比下面的写法: SELECTcolumnFROMtableWHEREfieldlike’keyword%’; 这样的写法用explain解释看到,SQL语句使用了索引,搜索的效率大大的提高了! 但是有的时候,我们在做模糊查询的时候,并非要想查询的关键词都在开头,所以如果不是特别的要求,”keywork%”并不合适所有的模糊查询 我在网上搜索时发现很多mysql函数用来解决这个问题,我测试出来的结果是跟like相比并没有任何优势。 1.LOCATE(’substr’,str,pos)方法 SELECTcolumnFROMtableWHERELOCATE(‘keyword’, field)>0 2.POSITION(‘substr’ IN field)方法 SELECTcolumnFROMtableWHEREPOSITION(‘keyword’INfiled) 3.INSTR(str,’substr’)方法 SELECTcolumnFROMtableWHEREINSTR(field,’keyword’)>0 这几种方法都试过后,发现百万级别数据以上,时间是跟like差不多,并没有解决问题,因为都没走到索引。 这种情况下想要实现后几位模糊查询并且速度要快,在此我想了两个办法,一个是不需要mysql版本支持,一个需要mysql5.7版本以上 第一种方法:新增一列字段新增一列字段,那个字段是你需要实现模糊查询的倒序,也就是原本是ABCD,那列字段就是DCBA 然后在那个字段添上索引 UPDATE tbl_ser_apply a set order_no_desc = REVERSE (SUBSTRING(a.order_no, -6)) ALTER TABLE tbl_ser_apply ADD INDEX order_no_desc ( order_no_desc ) 我这边设的是后六位 也就是我把之前字段的后6位倒序后存入新的字段,也可以整个字段倒序后存入新的字段 12345678910111213141516171819202122select a.*,a1.id as id2,a1.order_no as orderNo2,a1.tran_amt as tranAmt2,a1.fee_amt as feeAmt2,a1.repayment_date_req as repaymentDateReq2 ,a1.status as status2,a1.create_time as createTime2,a1.update_time as updateTime2 from ( select tsa.id,tsa.order_no as orderNo,tsa.repayment_date_req as repaymentDateReq,tsa.status,tsa.fee_state as feeState,tsa.repayment_flag as repaymentFlag, tsa.capital_return_flag as capitalReturnFlag,tsa.tran_amt as tranAmt,tsa.fee_amt as feeAmt,tsa.capital_returned_amont as capitalReturnedAmont, tsa.wait_amt as waitAmt,tsa.back_charge_amt as backChargeAmt,tsa.create_time as createTime,tui.real_name as realName,tui.mobile_no as mobileNo, tc.bank_card_no as bankCardNo,tmi.merchant_name as merchantName,tui.mer_no as merNo,tsa.reserved1 as reserved1,tsa.parent_id as parentId,tc.bank_name as bankName,tc.holder_name as holderName, tc.certificate_no as certificateNo from tbl_ser_apply as tsa LEFT JOIN tbl_user_info as tui on tsa.userid=tui.id LEFT JOIN tbl_merchant_inf as tmi on tmi.merchant_no=tui.mer_no LEFT JOIN tbl_cusinfo tc on tc.id=tsa.cusInf_id where tsa.order_no_desc like REVERSE('%372191') ORDER BY tsa.create_time desc ) a LEFT JOIN tbl_ser_apply a1 on a.parentId=a1.id 我的整个sql是这样的 实际上最后查询的时候是这样 where tsa.order_no_desc like REVERSE(‘%372191’) 需要修改sql和java代码,查询的是新增反向字段,而不是原来的字段 这样就能实现走索引 原来的sql不走索引的情况下查询出来需要20S,优化后只需要0.049S 这种方法适合mysql5.7以下版本,这样能大大加快模糊查询速度,而且能到1000W以上应该都是没问题的 第二种方法:虚拟列需要mysql5.7以上版本支持,用到虚拟列的方法,原理跟上述方法一样 alter table tbl_ser_apply add column virtual_col varchar(20) as (REVERSE (SUBSTRING(tbl_ser_apply.order_no, -6))); ALTER TABLE tbl_ser_apply ADD INDEX virtual_col ( virtual_col ) 在MySQL 5.7中,支持两种Generated Column,即Virtual Generated Column和Stored Generated Column,前者只将Generated Column保存在数据字典中(表的元数据),并不会将这一列数据持久化到磁盘上;后者会将Generated Column持久化到磁盘上,而不是每次读取的时候计算所得。很明显,后者存放了可以通过已有数据计算而得的数据,需要更多的磁盘空间,与Virtual Column相比并没有优势,因此,MySQL 5.7中,不指定Generated Column的类型,默认是Virtual Column。 如果需要Stored Generated Golumn的话,可能在Virtual Generated Column上建立索引更加合适 综上,一般情况下,都使用Virtual Generated Column,这也是MySQL默认的方式 语法: [ GENERATED ALWAYS ] AS ( ) [ VIRTUAL|STORED ] [ UNIQUE [KEY] ] [ [PRIMARY] KEY ] [ NOT NULL ] [ COMMENT ] 这样做比上一个方法好的地方是,不需要修改java代码,只需要修改很小一部分的sql语句即可,上一个方法其实实现后要修改的java代码要不少,而且每次新增修改删除时,都要加上这个字段的代码,而新增虚拟列的话,那一列的字段是自动添加修改,通过计算得出的,所以代码完全不需要修改,只需要修改操作原来字段的sql即可。 12345678910111213141516171819202122select a.*,a1.id as id2,a1.order_no as orderNo2,a1.tran_amt as tranAmt2,a1.fee_amt as feeAmt2,a1.repayment_date_req as repaymentDateReq2 ,a1.status as status2,a1.create_time as createTime2,a1.update_time as updateTime2 from ( select tsa.id,tsa.order_no as orderNo,tsa.repayment_date_req as repaymentDateReq,tsa.status,tsa.fee_state as feeState,tsa.repayment_flag as repaymentFlag, tsa.capital_return_flag as capitalReturnFlag,tsa.tran_amt as tranAmt,tsa.fee_amt as feeAmt,tsa.capital_returned_amont as capitalReturnedAmont, tsa.wait_amt as waitAmt,tsa.back_charge_amt as backChargeAmt,tsa.create_time as createTime,tui.real_name as realName,tui.mobile_no as mobileNo, tc.bank_card_no as bankCardNo,tmi.merchant_name as merchantName,tui.mer_no as merNo,tsa.reserved1 as reserved1,tsa.parent_id as parentId,tc.bank_name as bankName,tc.holder_name as holderName, tc.certificate_no as certificateNo from tbl_ser_apply as tsa LEFT JOIN tbl_user_info as tui on tsa.userid=tui.id LEFT JOIN tbl_merchant_inf as tmi on tmi.merchant_no=tui.mer_no LEFT JOIN tbl_cusinfo tc on tc.id=tsa.cusInf_id where tsa.virtual_col like '372191%' ORDER BY tsa.create_time desc ) a LEFT JOIN tbl_ser_apply a1 on a.parentId=a1.id 经过我的测试后,原来不走索引是20S 用上一个方法是0.049s 用第二个方法的话是0.1S 虽然慢了0.05S 那是计算数据的时间,但这样的方案已经大大缩短了模糊查询时间,而且不需要修改java代码,个人推荐使用第二种! 参考文章:参考链接1参考链接2","link":"/database/mysql/mysql-like%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2%E4%BC%98%E5%8C%96.html"},{"title":"英语语法-基本语法","text":"五种句型学习语法:分析句子=>理清句子成分=>理清句子关系 句子基本结构:主语部分+谓语部分(名词+动词) 五种句型: 主 谓 表 I am a Webaholic 主 谓 Internet dating hurts 主 谓 宾 I like chatting online 主 谓 间宾 主宾 Chatting on the internet brings me a lot of fun 主 谓 宾 宾补 We can call Internet addicts a Webaholic 关键在于谓语动词:动词构成了一个句子的骨架 1 主语+系动词+主语补足语(表语) 系动词(Linking Verb) 作用:无具体动作,仅起连接作用; 后面所接成分:说明主语特点性质特征 种类:be动词(am is are) ​ look sound smell taste feel seem appear become turn 表语:名词 or 形容词 2 主语+谓语(+状语) 不及物动词(Intransitive Verb)vi 特点:主语自身可以完成,不需要作用对象 习惯:带状语(修饰动作的成分) 3 主语+谓语+宾语 及物动词(Transitive Verb)vt 作用;:说明主语动作作用对象(宾语:主语动作承受对象) 4 主语+谓语+间宾+直宾 双宾动词(Dative Verb) 特点:后面成分有人(间接宾语[接受者])又有物(直接宾语[承受者]) 5 主语+谓语+宾语+宾语补足语 宾补动词(Factitive Verb) 6 区分双宾语和复合宾语 在间接宾语后加上be动词,若能成句,则是补足语。 动词种类 句型 Linking verb 主+系+表 Intransitive Verb 主+谓 Transitive Verb 主+谓+宾 Transitive Verb with direct object and indirect object 主+谓+间宾+直宾 Transitive Verb with direct object and object complement 主+谓+宾+宾补 动词分类1 实义动词(Notional Verb) 特点: 词义:完整 作用:能独立充当谓语 分类:助动词和情态动词以外的动词 2 助动词(Auxiliary Verb) 特点: 词义:不完整 作用:无法独立充当谓语 ​ 必须和实义动词连用,构成各种时态、语态、语气、否定、疑问 分类: Be: am, is, are, was, were, been, being Do: does, did Have: has, had, having 助动词 变化形式 功能 例句 Be am, is, are, was, were, been, being 帮助构成进行时态 I am studying grammar.He is playing football. 帮助构成被动语态 I was cheated. Do Does, did 帮助实义动词构成否定 I do not like English. 帮助实义动词构成疑问 Do you like English? Have Has, had, having 帮助构成完成时态 I have studied English for 3 years be do have可作实义动词又可作助动词 例句 词义 词性及作用 be I am a student “是” 系动词, 作谓语 I am studying grammar 无词义 助动词, 构成进行时 have I have two brothers “有” 实义动词, 作谓语 I have studied English for 3 years 无词义 助动词, 构成完成时 do I often do my homework at home “做” 实义动词, 作谓语 I do not like English 无词义 助动词, 构成否定 3 情态动词(Modal Verb) 特点: 词义:有词义,表示可能、建议、愿望、必要、允许、能力、怀疑、表示说话者对某种行为或状态的看法或态度 作用:无法独立充当谓语,必须和实义动词一起构成复合谓语 常见: can/could may/might must shall/should will/would have to ought to used to need/dare 句子的变化1 陈述句否定 谓语动词含有助动词或情态动词 变形:助动词或情态动词后 + not ​ 例:He is a teacher. He is not a teacher. ​ I can swim. I cannot swim. ​ He will come to the party he will not come to the party 谓语动词是实义动词 变形:借助助动词do not来构成,第三人称用does + not + 动词原形,过去式did + not ​ 例:I like English. I do not like English. ​ He likes English.. He does not like English. ​ There are some dogs. There aren’t any dogs. 否定的缩写 I am Am not Null We/You/They are Are not Aren’t She/He/It is Is not Isn’t I/He/She/It was Was not Wasn’t We/You/They were Were not Weren’t I/You/We/They do Do not Don’t He/She/It does Does not Doesn’t Did Did not Didn’t I/You/We/They have Have not Haven’t He/She/It has Has not Hasn’ Had Had not Hadn’t 情态动词 Will Will not Won’t Would Would not Wouldn’t Shall Shall not Shan’t Should Should not Shouldn’t Can Cannot Can’t Could Could not Couldn’t May May not Null Might Might not Mightn’t Must Must not Mustn’t 其他词变化:and->or already->yet both->either some->any 祈使句: 祈使句前+don’t Don’t open the door. 不定式: 不定式前+not She asks the boy not to play in the street. 2 一般疑问句 谓语动词含有助动词或情态动词 变形:助动词 or 情态动词移至句首 ​ 例:He is a teacher. Is he a teacher? Yes, he is/No, he isn’t 谓语动词是实义动词 变形:加do does did于句首,实义动词变原形 ​ 例:He likes English. Does he like English? Yes, he does/No, he doesn’t. ​ I like English. Do you like English? Yes, I do/No, I don’t. 3 特殊疑问句 不接名词连用的疑问句 对人提问:who ​ He can sing in English. Who can sing in English. ​ I saw him at the party last night. Who did you see at the party last night? 对事或物:what ​ I like English. What do you like? ​ I am studying English grammar. What are you doing? ​ I am studying English grammar. What are you studying? ​ I’d like to go swimming tomorrow. What would you like to do tomorrow? 对时间提问:when ​ I was born in 1980. When were you born? 对地点提问:where ​ He lives in Beijing. Where does he live? 对方式提问:how ​ He goes to school by bus. How does he go to school? 对原因提问:why ​ I often study at the library because it’s quiet. Why do you often study at the library? 接名词连用的疑问词 Which: ​ Could you lend me your pen? ​ Sure. I have two pens. This pen has black ink. That pen has red ink. ​ Which pen/Which one/Which do you want? ​ That red one. Thanks. ​ Which也可不接名词。这时which用作代词。 Whose: ​ 必须接名词 ​ This is his book. Whose book is this? ​ I borrowed Jack’s car last night. Whose car did you borrow last night? How用法详解 单独使用:对动作方式的提问 ​ How do you go to work? ​ I drive/ By car/I take a taxi/I take a bus/By bus. ​ How did he break his leg? ​ He fell off the ladder. 和形容词 or 副词连用 ​ How old are you? ​ How tall is he? ​ How big is your new house? ​ How far is it from your home to school? ​ How well does he speak English? ​ How quickly can you get here? 对频率提问:how often/how many times? I write to my parents once a month. How often do you write to your parents? I go shopping twice a week. How often do you go shopping?/How many times a week do you go shopping? 其他频率短语 Every Once a —> day/week/month/year Twice a Three times 一般时态和现在时态The present simple tense is used to express a general truth or fact, or an action that occurs regularly or habitually. Generally, the present simple tense verb conveys a sense of permanence. Truth or fact The sun rises in the east and sets in the west. The earth moves around the sun. An action that occurs regularly or habitually I often spend two hours reading English in the morning. Classes begin at nine in the morning 1.事实 The world is round. 2.经常性,习惯性动作或状态 He doesn’t work hard. (1)常连用频率副词(助动词后,实义动词前) ​ always frequently usually sometimes generally occasionally often ​ never seldom rarely 3.以there或here开头句子中,表正在发生的短暂动作 Here comes your wife= your wife is coming. There goes our bus; we’ll have to wait for the next one. 4.条件状语(if unless),时间状语(when as soon as before after )从句中,表示将来动作 Please let me know when he comes back. What are you going to do when you leave school? I’ll be glad if she comes over to visit me. The past simple tense is used to express a completed action which took place eat a specified time in the past. The specified time is either stated or implied. A completed action I saw him in the library yesterday morning. I began to learn English ten years ago. A past action that occurred regularly or habitually I slept for eight hours last night. She lived in our town for three years,but now she is living in Beijing. 1.过去动作或状态 He was late for school this morning. I bought this computer three years ago. 2.过去一段时间一直持续或反复发生的动作 I lived in the country for ten years. He used to do morning exercises. He took a walk after supper when he was alive. The future simple tense is used to express an action that will occur at some time in the future. Will or Be Going To can be used to express sort of certainty. According to the weather report, it will be windy tomorrow.说话人认为将要发生 According to the weather report, it is going to be windy tomorrow.根据明显迹象判断 Be Going To is used to express a definite plan. I have bought a computer and I’m going to learn the computer science. Will is used to express a willingness. The telephone is ringing; I will answer it. Will(说话时做出的决定) Be Going To(对话前做出的决定) 进行时态时态构成 助动词+进行分词 be+doing 意义 该时刻(具体时间,另一个具体活动背景下),活动正在进行 现在进行时 1.说话此刻正在进行 What program are you watching? He is not available now. He is talking on another phone. 2.现阶段正在持续的动作 what are you doing these days? I am learning the usage of verb tenses. 3.最近的将来已定的安排(计划 安排做) What are you doing on Saturday night? I’m doing some shopping with Jane. I am taking a makeup test tomorrow. 4.与always forever continually constantly等连用,表示抱怨,厌烦 Jack is always borrowing money and forgetting to pay you back. He’s continually asking me for money. 过去进行时1.过去特定时刻发生的事情 I was discussing my thesis with my director at this time last night. What were you doing at 10 o’clock last night? I was having dinner with my friends 2.过去进行时(背景)+一般过去时(背景下发生的短暂动作或状态) The phone rang while I was having my bath, as usual. I was watching TV when the phone rang. 将来进行时(will be doing)1.将来某特定时刻活动正在进行 I’ll be lying on a beach in Sanya this time tomorrow. Don’t telephone after eight tomorrow. I’ll be having a meeting. 名词名词短语(名词与它前面的修饰语) These red roses are for you. I have three close friends. I really need a new computer. 1.功能 ​ 主语 宾语(介词不能单独使用,后面所接宾语) 表语 2.修饰语 ​ 限定词: 泛指,特指,定量,不定量(these three a the my that),冠 词(a an the) ​ 形容词: red close new best small 3.位置 ​ 限定词在形容词前: 限定词+形容词+名词: three red roses. 名词可数与不可数名词分类 专有名词 Paris, the United States, Bill Gates 普通名词​ 可数名词 ​ 个体名词 student tree hospital house piano ​ 集体名词 team committee police group family ​ 不可数名词 ​ 物质名词 paper water cotton air ​ 抽象名词 birth happiness evolution technology hope ​ 简单名词 story student teacher ​ 复合名词 girlfriend roommate mother-in-law 相对性 paper ​ I need some paper to write a letter(纸 不可数) ​ I have a term paper to write on weekends(论文 可数) ​ I bought a paper(报纸 可数) ​ room(空间 不可数; 房间 可数) 可数名词与不可数名词比较 可数名词: 前面可以+ a or an or 数词(two) 不可数名词: 不可+ 变形及读音 1.末尾+s(清辅音s 浊辅音z) 2.-s -x -ch -sh结尾+es读[iz] 若ch发音为[k]时+s (stomach/stomachs) 3.辅音字母+y: 变y->ies 读[iz]; 元音字母+y: 直接+s 读[z] 4.特殊变化 ​ 1)o结尾 读[z] ​ potato/potatoes tomato/tomatoes hero/heroes piano/pianos photo/photos radio/radios ​ 2)f或fe结尾 f, fe->ves 读[s] or 直接+读[s] ​ half/halves knife/knives leaf/leaves life/lives ​ belief/beliefs chief/chiefs cliff/cliffs proof/proofs roof/roofs ​ 3)单复数同形 ​ aircraft deer giraffe sheep ​ 4)man/woman 构成的复合名词(都变) ​ man teacher/men teachers woman pilot/women pilots ​ 5)名词+介词或介词短语构成的复合名词(名词变) ​ passer-by/passers-by looker-on/lookers-on 不可数名词1.物质名词不可数​ beer blood coffee cream gasoline honey juice milk oil tea water wine ​ bread butter cheese ice ice-cream meat beef chicken fish chalk copper cotton glass gold iron ​ air fog oxygen smoke 2.抽象名词​ advice anger beauty confidence fun happiness health honesty informaation love luch peace 3.总称名词不可数​ furniture fruit jewelry luggage equipment poetry machinery 不可数名词的度量 1.piece ​ advice bread baggage chalk equipment furniture information jewelry luggage music news 2.bottle cup drop glass ​ beer blood coffee milk tea water wine 3.else ​ a loaf of bread a tube of toothpaste a pack of cigarette a slice of meat 名词所有格 1.单数名词后+’s 2.复数名词后+s’ ;复数型名词后+’s ​ her friends’ money ​ the children’s Day 3.复合名词后+’s ​ my father-in-law’ s company ​ everyone else’ s viewpoints ​ Henry the Eighth’ s wives ​ the President of America’ s secretary 4.and连接的并列名词: 共有情况: 最后+’s ; 各自所有情况: 每个名词后+’s 5.重量 度量 价值 ​ two pounds’ weight a ton’s weight a ton’ s steel two dollars’ worth of sugar 6.省略 ​ 1)前文以出现,避免重复 ​ This bike is mine, not Michael’s ​ 2)表示店铺或教堂(要加the) ​ at the baker’s at the butcher’s at the chemist’s at the doctor’s ​ 3)人名后的所有格省去名词表示住宅 ​ go to my sister’s I called at my uncle’s yesterday. 7.of所有格的其他关系 ​ 1)主谓关系 ​ the visitor’s departure the teacher’s request the growth of agriculture ​ 2)动宾关系 ​ the children’s education the boy’s punishment the discussion of the plan 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95.html"},{"title":"英语语法-句子类型","text":"特殊疑问句:疑问词+一般疑问句​ What time i convenient for you ​ How late are you open ​ Where were we ​ What was I just going to say ​ What’s in your mind ​ What’s going on ​ When did you begin to study English 一般疑问句:助动词+主语+谓语(yes or no 回答)选择疑问句:提供两种或两种以上情形提对方选择​ Do you like tea or coffee ​ Did you speak to them, or did the manager ​ Which ice cream would you like, chocolate, vanilla or strawberry. 反意疑问句:​ I am going to look like a lemon, aren’t I? ​ You have completed that job,haven’t you? ​ You have not completed that job, have you? 祈使句:表示请求,命令,劝告,建议等​ 主语you省略 ​ 动词原型,没有时态,不用情态动词 ​ Stop bugging me ​ Don’t judge a book by its cover ​ Don’t get me wrong ​ Let’s just have a rest ​ Let’s hope for the best ​ Let’s talk over dinner ​ Let bygones be bygones ​ Strike while the iron is hot ​ Make hay while the sun shines 感叹句:what1.what + a(n) + 形容词 + 可数名词单数 + 谓语部分​ what a lovely boy he is. 2.what + 形容词 +不可数名词或可数名词复数 + 谓语部分​ what foolish mistakes you have made ​ what nice weather(it is) 3.what + a(n) +可数名词单数:是​ 没有感情色彩的普通名词时: 有两种理解 ​ what a day: 可以是今天天气多好,也可以是天气很糟糕 ​ 有感情色彩的名词 ​ what a mess 感叹句: how1.how + 形容词 or 副词 + 谓语部分​ How lovely the boy is ​ How fast time flies 2.How + 主谓部分​ How he ssnores! ​ How I hate exams! 3.How + 形容词 + a(n) +可数名词单数 + 主谓部分​ How lovely a boy he is. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%8F%A5%E5%AD%90%E7%B1%BB%E5%9E%8B.html"},{"title":"英语语法-状语从句","text":"本质:连接词(关键)表达分句之间逻辑关系 种类:时间,地点,原因,目的,结果,条件,让步,比较,方式 时间状语:说明两个从句的时间 when:调节两个时间点【起始点&结束点(完成时)】来说明主从句发生顺序 三要点: 同 时 态:从句先发生 有完成时:强调已完成的时间点 从 句 中:现在表将来 (主句/从句)时态 例句 将来/现在 I’ll speak to him when he arrives. 将来/现在完成 I’ll give you a call when I have finished the work. 过去/过去 I started my dinner when he left. 过去/过去完成 He left when I had got there. 过去完成/过去 I had started my dinner when he left. whenever:强调无论何时(每次) Smile whenever you pick up the phone, for the caller will be able to notice it. while + 延续动词:从句发生期间发生 The doorbell rang while we were watching TV. until:主句持续到从句的时间点保持同一状态 肯定形式:持续发生状态 We’ll stay here till it stops raining. 否定形式:持续未发生状态 I did not realize I would need English in the future until I came to Japan. 三种特殊结构 until句首 Until he saw his mother, the little boy didn’t smile. 主句倒装 Not until he saw his mother did the little boy smile. 强调 It was not until he saw his mother that the little boy smiled. 一…就:as soon as, once, the minute, the moment, the instant, immediately, directly, instantly. 说明:强调主从句说明的两个时间点同时发生;时态一般一致 It began to rain as soon as/immediately/the moment I arrived home. 特殊:倒装比较方式,主句动作刚结束(过去完成),从句动作就开始(过去) No sooner had I arrived home than it began to rain. ​ 2. Hardly/Scarcely had I arrived home when it began to rain. ​ 3. No sooner had we begun having dinner than the doorbell rang. 时间短语引导: next time, by the time, every time, each time, the day, the week. a. The day he returned, his father was already dead. ​ b. Next time you come, remember to bring along your sister. ​ c. Every time I listen to your advice, I get into trouble. 在…之前:by the time 强调:主句动作(完成时)在从句动作之前已经完成 a. By the time they arrived, we had already left. ​ b. By the time they arrive, we will have already left. 地点状语主句后边:一般 Generally, air will be heavily polluted where there are factories. 主句前边:需要灵活翻译 wherever there is love, there is also wealth and success. wherever, anywhere, everywhere引导 wherever I happens to be, I can make myself at home. 原因状语Because 语气最强,只有它能回答why问句。听话人未知原因 You want to know why I am leaving? ​ I am leaving because I’m fed up with the job and boss. 强调词:only,just ​ You shouldn’t get angry just because some people speak ill of you. Since:已知道的原因,既然 Since Monday is Bob’s birthday, let’s throw him a party. As:和since差不多 She didn’t hear us come in as she was asleep. For:推断理由 Pay attention to your enemies, for they are the first to discover your mistakes. 介词短语表原因:because of,due to(非句首),owing to(句首):只接名词 Owing to his carelessness we had an accident. because否定转移:从句的否定转移到主句 I didn’t attend the meeting because he was present. 复合连词表原因:seeing (that),now (that),considering (that),given (that) = since Now that the semester is finished, I’m going to rest a few days and then take a trip. In that:原因就在于 The girl is like her mother in that she also has very delicate feeling. 目的状语常用连词:so that,in order that,that;从句:有表能力的情态动词 I spoke slowly and clearly so that/ in order that the audience could understand me. 不定式简化 In order for sb to do sth I spoke slowly and clearly in order for the audience to understand me. In order to(可句首)/so as to do:主从句主语一致 All the key words in the article are printed in bold type so as to attract attention. 以免连词:lest,for fear (that),in case:以免,生怕 Take an umbrella with you lest it would rain. 其他连词:in the hope that,on purpose that,for the pupose that,to the end that The teacher raised his voice on purpose that the students could hear more clearly. 结果状语常用连词:so…that,such…that,such that(such = so+adj.) His anger was so explosive that he lost control of himself. 主句倒装 a. So fast does light travel that it is difficult for us to imagine its speed. ​ b. Such a fool was he that he believed him. 不定式简化 such…as to do sth,such as to do sth,so…as to do sth (as不能省略) Her voice was such as to make everyone stare. 其他短语:to the degree/extent (that),to such a degree/extent (that)(句首时倒装) a. To such an extent did his health deteriorate that he was forced to retire. ​ b. The bereaved mother was grieved to the deggree that she couldn’t eat for 3 days. so和such区别 1.a. so + 形容词 or 副词 b. such + 名词 ​ a. This is so expensive a house that I can’t afford to buy it. ​ b. This is such an expensive house that I can’t afford to buy it. 2. a. so + 形容词 + a(n) + 名词 b. so + many/much/few/little + 名词 ​ a. This is so expensive a house that I can’t afford to buy it. 3. 数量词/限定词 + such + 名词 ​ one such man; no such man; every such man; five hundred such men 让步状语常用连词:though, although, even though, even if. (主句前不用but,可用yet/still) Though he tried hard, yet he failed. 介词让步:despite, in spite of, for all, notwithstanding后只接名词(短语) ​ Although it was dangerous, … = Despite the danger, … 句首while:表示尽管 While I sympathize with your point of view, I can not accept it. No matter 特殊疑问词 = 特殊疑问词 + ever ​ Whoever may trouble you, I will help you to the last. as倒装:(adj/ adv/ 分词/ 名词/ 短语) + as + 主语 + 谓语 ​ a. Young as he is, he is knowledgeable. ​ b. Much as I respect him, I can not agree with him. ​ c. Child as he is, he is knowledgeable. ​ d. Lazy a boy as he is, he is kind to help others. ​ f. Praised as he was, he remained modest. (as/so) + 形容词 + as + 主谓,放在句首 ​ As amusing and perceptive as graffiti may sometimes be, it has by no means won universal approval. be倒装 ​ Be it ever so humble, there is no place like home. ​ = However humble it may be, there is no place like home. 比较状语as 结构1: as 形容词/副词 + as ​ The work is not as difficult as you think. 结构2: as + 形容词 +a(n) + 可数名词 + as ​ Americans tend to think from small to large. Let us take as simple an example as the addressing of envelopes. 结构3: 否定句中so代替as ​ He is not so/as clever as you. than: 必须同类比较,必有比较级 ​ He is taller than me. 三种倍数 ​ a. A is … times bigger than B. ​ b. A is … times as big as B. ​ c. A is … times the size of B. The more … , the more: 先翻译从句,后翻译主句 ​ a. The more she practiced, the worse she sang. ​ b. The less you open your heart to others, the more your heart suffers. ​ c. The nearer it is drawn to the surface of the earth, the more a body weighs. (just)as … , so …:类比 ​ a. Just as dark clouds cannot long hide the sun, so no lies can cover up the fact. ​ b. As it is the mark of great minds to say many things in a few words, so it is the mark of little minds to use many words to say nothing. A is to B (what/as) C is to D ​ Air is to man what/as water is to fish = What/As water is to fish, so is air to man. No more … than或not … any more than:同 … 一样不能(than后面肯定式,否定意思) ​ You are no more clever than he. = You are as stupid as he. Not more … than …:平起平坐 ​ You are not more clever than he = You both are clever, not stupid. Not A so much as B/ not so much A as B: ​ 1. 与其说A,不如说B(A,B是平行结构[同介词短语,动词不定时]) ​ a. The great use of a school education is not so much to teach you things as to teach you the art of learning. ​ b. The trumpet player was certainly loud, but I was not bothered by this loudness so much as by his lack of talent. 方式状语常用连词:as, like, as if, as though, the way ​ a. When in Rome, do as the Romans do. ​ b. Work like you don’t need money, love like you’ve never been hurt, dance like nobody’s watching. ​ c. Do it the way you were taught. ​ d. He looks (as though/as if) he is an actor. ​ e. Do as I say, not as I do. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E7%8A%B6%E8%AF%AD%E4%BB%8E%E5%8F%A5.html"},{"title":"英语语法-形容词adjective","text":"两种形容词的区别 ing:描述引起人某种感觉的事物(主语通常是事物) ed:描述人对事物的感觉(主语通常是人) The interesting children can make other people feel interested in them. 位置 1.限定词+形容词+名词 ​ I am reading an interesting book. 2.不定代词+形容词 ​ There is something(某事) wrong with my computer. 形容词顺序 观点形容词(opinion adjective)+描绘形容词(descriptive adjective) ​ a beautiful white table 描绘形容词顺序 ​ size->shape->age->color->origin->material ​ This beautiful big round old red chinese wooden table was mine. 比较级和最高级单音节:-er -est​ -e结尾:-r -st ​ large->larger brave->braver ​ -y结尾:变y->i 加-er -est ​ shy->shier ​ 元音+辅音:双写最后字母后加-er -est ​ fat->fatter big->bigger sad->sadder 双音节:前面+more most​ 特例:y结尾双音节词,变y->i 加-er -est ​ happy->happier early->earlier ​ early和showly ​ early是不可分割:故变earlier ​ slowly是组合词:故变more slowly 多音节:前面+more most特殊: 原级 比较级 最高级 good/well better best bad/ill worse worst far farther/further farthest/furthest old older/elder oldest/eldest little less least many/much more most late later/latter latest/last up upper uppermost/upmost 特别说明 ​ A:farther(多用实际距离) further(表示抽象,进一步) ​ further discussion ​ B:older(大小,用于比较级中) elder(成员长幼关系,并非大小,不用比较级中) ​ my elder brother his eldest son ​ I am seven years older than Rex ​ C:later, latter, latest, last ​ later(时间上”较迟“):I am on the phone right, Could you call me later? ​ latter(顺序上”后者“):The latter point is the most important. ​ latest(最新的,最近的):the latest games the latest fashions. ​ last(1.上一次,最近一次;2.所有事物中的最后一个) ​ 1.The last game, I won. last week ​ 2.The last three pages of the chapter 原级比较 如同:A + as + 形容词 or 副词 + as + B ​ You are as lazy as she. ​ The work is not as difficult as you think. 如同的否定句:可用so代替第一个as ​ The work is not so difficult as you think. 表示几倍/几分之几:A + 几倍(three times)/几分之几(a third) + as + 形容词 or 副词 +as + B ​ This book is twice as thick as that one. ​ The Earth has a mass nearly one hundred times as much as that of the Moon. A + the same + 名词 + as + B ​ I am as old as you ​ I am the same age as you. 形容词比较级注意1.than前面必须有比较级2.必须是同类事物比较​ a.两个彼此独立的同类事物比较 ​ This question is less difficult than that question. ​ b.自身比较:A + 比较级 + 情形1 + than + 情形2 ​ He did much better in the finals this term than last term ​ c.前后有从属关系时,加other,else与整体区别开来,避免逻辑错误 ​ She works harder than any other student in her class.(不说other就把自身也比较了) 3.比较级前+the的情况:有介词短语 of the two时.​ I think this painting is the more interesting of the two. 越来越…… 单音节:比较级 + and + 比较级:That female singer is getting fatter and fatter. 多音节:more and more 形容词原级: As summer approaches, the sea seems more and more beautiful. 可以修饰比较级的词 a bit, a little bit, a little, a lot, a great deal, any, even, far, by far, much, very much, no, rather, still, slightly. 不用:very, many, quite, fairly. Are you feeling any better? Things are no better than before He makes far fewer mistakes in spellings than before 否定比较级可表示最高级:few, nothing, never, not How have you been? It couldn’t be worse Few are better qualified for the job than he is. I have never heard a better song(This is the best song that I have ever heard) 最高级注意1.the + 最高级 + in +地方-不说:It is the most expensive car of the world-​ It is the most expensive car in the world. 2.第几最高: the + 序数词 + 最高级 + in + 地方​ The Huanghe River is the second longset river in China. ​ THe Yangtze River is the longest river in China, but it is the third longset river in the world 3.the + 最高级 + of + 所属范围​ The youngest (one) of the family is most successful.(理解时+one,but实际应用时省去) ​ Gold is sthe least useful of all metals. ​ The Atlantic is not the largest of the world’s oceans. ​ Silk is the strongest of all natural fibers, ranking in strength with the synthetic fiber nylon. ​ A good book is the best of friends, the same today and forever. ​ 特别:of + 范围放置句首:Of all metals, gold is the least useful. 4.最高级是否加the​ a.形容词需要+the:This is the most interesting book of all. ​ b.副词可加可不加:He works hardest in his class. ​ c.most不加the的特殊用法=very much:The story is most interesting. 无等级形容词:含绝对含义-可用nearly,almost,the most closely,more nearly修饰-absolute, alone, dead, empty, equal, eternal, final, harizontal, perfect, primary, pregnant, round, single, square, straight, supreme, unique, unanimous. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%BD%A2%E5%AE%B9%E8%AF%8Dadjective.html"},{"title":"英语语法-限定词2","text":"冠词 a 辅音因素开头的名词前, an 元音因素开头的名词前** 单数可数名词:不能单独使用,必须用冠词或其他限定词 复数可数名词 or 不可数名词: ​**(1)不能同冠词连用** (2)复数名词 or 不可数名词 ​ 泛指:不用the ​ Life is hard sometimes ​ 特指:用the ​ The writer is writing a book about the life of blacks in America. ​ I love music, poetry and art. ​ I don’t like the film, but I like the music(of the film) ​ 表示特指的时候,一般会带有后置定语 第一次提到单数可数名词前用不定冠词a or an,再次出现要用定冠词the谈到对话双方都知道的事物要用the(比如自己房间里的东西)​ can you turn off the light, please? 表示世界上独一无二的事物用the​ the earth, the sky, the equator, the moon, the world, the universe 做形容词的only、最高级、序数词修饰的名词前+the​ the only/best way to cope with the problem. ​ this is the first time I’ve come to Beijing. 乐器、乐团+the(运动不+the)play football or chess or tennis​ the Beatles ​ the Philaadelphia Orchestra ​ play/learn the guitar learn the piano 独一无二的身份不+the​ Henry was elected chairman of the committee ​ For the first time I am king of myself 限定词彼此互斥,不能同时出现在名词前面​ (1)冠词:the an a ​ (2)物主形容词: my your his her our their ​ (3)指示形容词: this that these those ​ (4)名词属格: Tom’s John’s 特殊名词前省略the​ (1)nature : in nature (2)society: in society (3)space: in space ​ (4)man在泛指整个人类时,不加冠词 ​ (5)history在泛指整个历史时,不加冠词 ​ (6)三餐前不+冠词:have something for breakfast/lunch/supper/dinner 交通工具​ 若用介词on:+冠词the(on foot 步行不加the)on the train/plane/boat ​ 若不用介词on,如用by时,不加the: by bicycle/boat/bus/car/plane/train/metro 其他固定介词搭配​ face to face , arm in arm , hand in hand , shoulder to shoulder , side by side ​ inch by inch , day after day , dentist after dentist school or the school​ bed, church, court, hospital, prison, school/college/unversity, sea, work, office ​ 当人们去这些地方做在这些地方应该做的事情时,不加冠词,表示抽象概念 ​ 当要去这些地方不是要做特定的事,而是由于其他原因,要用the ​ his mother is in hospital and he has been in the hospital to take care of her. ​ Bill Blinton came into office in 1992./Bill Clinton came into the office and saw sth. ​ to church(to pray) ​ to hospital(as patients) ​ to/at sea(出海/在海上) ​ to/at/from(去上班/在上班/下班) ​ go to sea(as sailors) go to the sea(go to the seaside) ​ be at sea(as passengers or crew) be at the sea(be at the seaside) ​ by sea(by ship) ​ by the sea(by the seaside) ​ be in office(在任职) be in the office(在办公室里) ​ be out of office(离职) be out of the office(离开办公室) 泛指的四种表达​ 1.不带the的不可数名词 ​ I like music ​ 2.不带the的复数可数名词 ​ bananas are yellow I am afraid of dogs ​ 3.the+单数可数名词(也可表示特指) ​ the whale is the largest mammal on earth ​ the whale is dead ​ 4.a/an+单数可数名词(也可以表示一个) ​ I ate a banana this morning ​ A banana is yellow ​ 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E9%99%90%E5%AE%9A%E8%AF%8D2.html"},{"title":"英语语法-限定词1","text":"数量限定词只与可数名词连用 只接单数 one each every 只接复数 two(three) both a couple of a few several many a number of 只与不可数名词连用 a little little much a great deal of a large amount of 与可数名词复数或不可数名词连用均可 not any some a lot of lots of plenty of most all 数量词与of连用all/most/some/any of+特指限定词+复数可数或不可数名词 most books most of books 不正确 most of my/these/the/john’s books many/a few/few/several/both/two/three of +特指限定词+ 复数可数名词 many students many of students 不正确 many of these students much/a little/little of +特指限定词+ 不可数名词 much water much of water 不正确 much of the water 其他数量词 a lot of , lots of , a couple of , plenty of , a number of , a great deal of 直接+名词all和both特殊用法all/both my students 可以不加of,其他much/many数量限定词不可这么用 all students all of my students all of students 不正确 数量词a few, few(只接可数), a little, little(只接不可数)a little,a few为肯定之意,等同于some,有一些 His theory is rather difficult; few people understand it.=almost no people understand it. I have little interest in English, so I am very poor at it. little,few为否定之意,等同于几乎没有 His theory is rather difficult, but a few people understand it. I have a little interest in English, so I like learning it. only a little,only a few very few,very little some and any 陈述句:some 一般用肯定,any一般用否定,表示”一些“。可与可数或不可数名词连用。 I need some medicine to cure my cough. I don’t have any friends here. 疑问句:多用any;在期待对方回答”是“的时候,要用some Have you got any medicine to cure your cough? Would you like to give me some advice? Can I have some more wine? any可以表示”任何一个,无论哪一个“,用于任何句型。 You can catch any bus. They all go to the railway station. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E9%99%90%E5%AE%9A%E8%AF%8D1.html"},{"title":"英语语法-完成时","text":"现在完成时(一):开始于过去的动作一直持续到现在,有可能继续持续。谓语动词为延续性动词 I have lived here for 3 years. 我仍然住在这里,而且还可能继续住下去。 ​ 如果在搬家时说这句话,则live这件事只持续到目前为止。 The teacher has taught in this school since I came here. I’ve worked in this company since I left school. ​ since表明了动作开始的时间点。 有上下问明确告知,动作只持续到说话的时刻为止。 ​ a. A: Have you waited long? ​ B: I’ve waited for three hours. ​ b. I’ve waited for him all day; I don’t want to wait any longer. 特点: 谓语动词为延续性动词 动作的发生时间是过去,持续到现在,还可能继续持续下去。 常常与表示一段时间的时间状语连用,是说明某个状态持续了多久。 与现在完成时搭配的时间状语 1. since + 时间点 ​ a. I’ve worked in thiss company since 1980 ​ b. I’ve worked in this company since I left school. (从句中一般过去时) 2. for + 时间段 ​ a. I’ve worked in this company for three years. ​ b. Great changes have taken place in Beijing for the past few years. 3. 到目前为止:until now, up until now, up to now, up till now, so far. ​ a. We have up until now failed to take any action to decide on a common language that would further communication between nations. 4. 在最近几世纪/年/月以来:in the past few years, over the past few years, during the last three months, for the last few centuries, through centuries, throughout history. ​ a. Throughout history man has had to accept the fact that all living things must die, for the very nature of life includes death. ​ b. Through centuries the bizarre anticss of sleepwalkers have puzzled police, perplexed scientists anad fascinated writers. 现在完成时(二):过去发生但与现在仍有联系的动作或状态 a. He has broken his leg. 他现在还在医院,所以不能和同学一起郊游。 b. He broke this leg. 退摔断过,单纯表示一种过去的经历,但现在腿已经好了。 c. You should have put the milk into icebox; I expect it has become undrinkable by now. ​ 牛奶变质是过去某一时刻的动作,但其影响延续到现在。现在牛奶已经不能喝了。 第二种现在完成时使用技巧。 1. 不与一段时间的时间状语连用:常见 come, go, leave, kill, die, lose, buy, start, give, marry ​ he has left his hometown for 3 years. ​ 改正: ​ a. He left this hometown 3 years ago. ​ b. It’s 3 years since he left this home town. ​ c. He hasn’t come back since he left his hometown 3 years ago. ​ d. He has been away from his home town for 3 years. 2. 终止性动词的完成时句子若用否定,表示尚未发生的事情,则可以为一种状态,从而表示延续。 ​ a. I haven’t seen a film for weeks. ​ b. I haven’t heard form my girlfriends since I came to America ​ c. I haven’t bought a pair of shoes for a year. 3. 与不确定时间的时间状语连用 ​ 这种完成时,可以同一些表示不确定的时间状语连用:already, yet, lately, often, just, never ​ a. A: would you like something to eat? ​ B: No, thanks. I’ve just had dinner. ​ b. The leading expert on sleep in America claims that he has never seen a sleepwalker. ​ c. Has it stopped raining yet? ​ d. He has already arrived. ​ f. I have often thought that it would be perfect if we could fly without any aid. 4. 具有新闻性质:表示最近才发生的动作,提供新消息。有新闻性质 ​ a. The President has been assassinated. ​ b. He can’t go on holiday because he has broken his leg. ​ 强调的时间内容,而不算是发生的过去具体时间。 ​ 通常的日常对话,以现在完成时开始问答。过去时间咋唉说话人的脑子中已经确定了,则继续用一般过去时。 ​ c. I hear that famous Chinese comedian has died. ​ Really? When did she die? She was dead late last night. 现在完成时(三):表示到目前为止的一个时间段内重复发生的动作。 For more than eighty years, scientists have argued over whehter life exists on the planet Mars. We have taken three tests so far this week. 其他现在完成时的结构 1. This/ That/ It is + 序数词 + 名词 + that + 现在完成时 ​ a. It is the third thime that I’ve come to Beijing. ​ b. It is the fifth time that someone has knocked at my door. ​ c. This is the thenth cup of coffee that I’ve drunk this evening. 2. This/ That/ It is + 最高等或only修饰名词 + 现在完成时 ​ a. This is the most interesting movie that I’ve ever seen ​ b. This is the best wine I have ever drunk ​ c. This is the hardest job I have ever had. 3. 如果是It was the second/ best… that 后面要用过去完成时 ​ a. It was the fifth time that someone had knocked at my door that night. 总结:一直在持续; 重复发生;影响现状 现在完成时与一般过去时比较 不同时态,表明了说话的时间不同。 a. I haven’t seen him this morning. b. I didn’t see him this morning. a. 句用了现在完成时,而完成时生死要与现在发生联系的。所以a说话的时间是this morning b. 句用的是一般过去时,说明this morning已经成为了过去,所以b说话时间是今早后 c. I have called thim three times this morning. d. I called thim three times this morning. c. 表示到现在为止的一个是时间段内重复的动作。所以c说话时间是this morning d. 过去时,和现在没有什么联系,所以说话时间是今早后 延续性动词的两种时态区别 a. He lives in Beijing. He has lived here for 3 years. (可能还继续住在这里) b. He lived in Beijing for 3 years and then emigrated to America (曾经住过,已经搬走了) 过去完成时:过去某时刻之前就开始的动作;​ (1)该过去时刻仍然在继续,或该过去时刻刚刚停止 ​ (2)在该过去时刻之前的某一时刻已经停止的动作做 ​ (3)在该过去时刻之前一段时间内重复的动作 (1) a. I had stayed in America for two years when he moved here. b. I had lived in 兵庫 for one and a half years when I came to Aizu. 有上下文表示持续过去这一时刻刚刚停止 c. I had waited for her for two hours in susch a severe winter when she eventually turned up d. There had been fifty colleges in our city up till 1993. (2) a. She had made everything ready before I came. b. Her baby had fallen asleep when she went into the room. c. Before John got home, Mary had gone to bed. d. I had just poured myself a cup of tea when the phone rang. When I came back from answering it, the cup was empty. Somebody had drunk the tea or thrown it away. (3) a. I had written her 100 letters when she finally promised to marry me. b. I had proposed to her five times, but she still refused to marry me. 过去完成时的其他用法 1. intend, mean, hope, want, plan, suppose, expect, think, propose, wish ​ 动词的过去完成时,可以表示过去未能时间的计划,设想,意图或希望等 ​ a. I had planned to go shopping with you but my mother came to see me just when I was about to go. ​ b. She had hoped that he would come to date her, but he didn’t show up. ​ c. I had intended to see you, but I was busy. ​ d. They had hoped to see you off at the airport, but they got there too late. 2. 用在It was the + 序数词 或最高级 that 句中。 ​ a. Last week I attended an international conference and saw Mr. Machine. It was the third time that I had met him. 一把拿过去时与过去完成时的比较 1. 两个或以上相继发生的动作,用and 或 but 按动作发生的先后顺序连接,此时要用一般过去时。 过去完成时则强调主语在过去某一时刻回顾更早的动作,具体来说。当我们在讨论过去某一事件时,想到了在这之前已经发生的某事,这时用过去完成时。 ​ a. He opened the door and entered, but found nobody. ​ b. He served in the army for ten years; then retired and married. His children are now at school. ​ c. When I had written my letters I did some gardening. ​ d. When I wrote him a letter, he came at once. ​ e. When the singer had sung her song, she sat down.如果说when the singer sang her song, she sat down.给中一种印象,这位歌手喜欢坐着唱歌。 将来完成时:站在将来某一时间来谈某一个动作的完成情况 动作开始的时间可以是过去,现在,未来。但并不重要,说话人强调的是他们一共有5门 ​ a. We started our exam yesterday and we will have taken five exams by next Friday. ​ b. We have started our exam today and we will have taken five exams by next Friday. ​ c. We will start our exam tomorrow and we will have taken five exams by next Friday. 1. 同现在完成时第一种用法的将来完成时 ​ a. I will have taught English in New Oriental School for five years by the end of next month. ​ b. I will have learned 8000 words by the end of next year. ​ c. I will have waited for her for two hourss when she arrives at 2 o’clock this afternoon. 2. 同现在完成时第二种用法的将来完成时:对将来有影响 ​ a. We will have finished our exam by the end of next week. ​ b. By the year 2050, scientists probably will have discovered a cure for cancer. ​ c. I will graduate in July. I will see you in September. By the time I see you, I will have graduated. ​ d. I will have finished my homework by the time I go out on a date tonight. 3. 同现在完成时第二种用法的将来完成时:重复发生。 ​ a. By five o’ clock this afternoon the spaceship will have traveled eleven times round the world. 完成时的三种思维用法​ 1. 延续到现在的动作或状态,可能继续延续,也可能到现在为止。 ​ 2. 过去发生但与现在仍有联系的动作或状态。对现在有影响。 ​ 3. 到目前为止的一个时间段内重复发的动作。 ​ 4.不同时间的完成时本质上是一样的。只是说话人的立足时间不同。 ● Sorry I’m late. The car broke down on my way here. ● Yesterday I had a phone call from Clint. I was very surprised. I had written to him many times but he had never replied to my letters. ● The man sitting next to me on the plane was very nervous. It was his first flight. He had never flown before. ● Last spring I went to France. It was the first time that I had been there. ● Look! Somebody has spilt milk on the carpet. Well, it wasn’t me. I didn’t do it. I wonder who it was then. ● I lost my key, so I couldn’t get into my house. But now I have found it. ● He has been in the army for five years. ● I’ve already had lunch. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%AE%8C%E6%88%90%E6%97%B6.html"},{"title":"英语语法-完成进行时","text":"现在完成进行时(一)到现在仍在延续的动作 1. 与一段时间连用:强调动作的持续性,开始于过去的动作持续到现在,并且还会继续持续 常与for + 时间段、since + 时间点、all morning、all day、all week表示段时间的状语连用 ​ It began raining two hours ago and it’s still raining. It has been raining for two hours. 2. 可不与时间段连用;表示最近一段时间内正在持续的活动 ​ I have been thinking about changing my job. 我最近一直在考虑换工作。 (二)刚刚结束的动作 1. 动作持续到说话为止 ​ a. Where have you been? I’ve been looking for you for the last half hour. ​ b. Thank you for the binoculars. I’ve been wanting a pair for ages. 2. 不久前刚刚结束的动作(完成时没有的用法) ​ a. Your friend is out of breath. you ask, “Have you been running?” ​ b. Why are your clothes so dirty? what have you been doing? ​ c. The little boy is dirty from head to foot because he has been playing in the mud. (三)重复发生的的动作 说话时刻以前的一段时间内重复发生的动作 ​ a. Every Sunday they meet in the same bar. They’re been going there for years. ​ b. I’ve been getting up early since I entered the college. ​ c. The price has been going up recently. I wonder whether it will remain so. ​ d. You’ve been staying up late again? 与现在完成时比较(一)相同点: 1. 都是延续性谓语动作live, learn, study, sleep, snow, wait, work, teach, stay 2. 与时间段连用(这时两种时态几乎没有多大的区别) ​ a. I have been learning/ have learned English for ten years. ​ b. I have been living/ have lived here since 3 years ago. 不同点: 现在完成时只与段时间连用才能表示这类动作。 a. I have worked/ have been working in this company for 3 years. b. I have worked in this company(现在不在了,表示过去的经历) c. I have been working in this company. (现在还在这家公司) d. He has been sleeping/ has slept for three hours. e. He has slept(他睡过了,所以现在不困了) g. he has been sleeping(现在还在睡) 与现在完成时比较(二) 完成进行时强调动作过程 完成时强调动作的结果 a. My hands are very dirty. I’ve been painting the house(理由,做的动作过程) b. I have painted the house green. The house was white, but now it’s green. c. Sorry about the mess–I’ve been painting the house. 与现在完成时比较(三) 1. 短暂动词的完成进行时表示重复。 ​ 短暂动词的完成时不能与一段时间的时间状语连用。但是完成进行时可以,表示重复动作 ​ a. Over the past few years, many towns in the United States have been joining with neighboring communites to share the costs of government. ​ b. Over the past few years, many towns in the United States have joined with … ​ c.I’ve got up early since I entered the college. 2. 重复动作的分割性 ​ 完成进行时表示不间断动作。如果要表达做事情的次数,不能用现在完成进行时 ​ a. I have been sitting in class since 8 o’ clock this morning. ​ b. I have had three classes since 8 o’ clock this morning. ​ c. The phone has been ringing for almost a minute, why doesn’t someone answer it?​ d. The phone has rung four times this mrning, and each time it has been for Clint. 与现在完成时比较(四) 不能用进行时的动词,同样不能用现在完成进行时 a. How long have you known Jane? b. How long have you been knowing Jane? 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%AE%8C%E6%88%90%E8%BF%9B%E8%A1%8C%E6%97%B6.html"},{"title":"英语语法-人称代词","text":"主格人称代词 作用:主句或从句中做主语 ​ She is my daughter. ​ It was he who helped me when I was in trouble. 顺序: you, he and I ; We, you and they(I总是 放在最后) 表示泛指的主格代词 one:任何人,包括说话人 ​ One is knocking at the door.(错误,说话人不算,所以不能用one) ​ Somebody is knocking at the door. ​ One后面使用的代词,美国一般用he,him,himself,his. We/You/They 可以表示泛指:人们 ​ They say = People say or It is said ​ They say it is going to be a cold winter. she(her)的拟人化:表示country, motherland, moon, earth, ship. ​ The ship lost most of her rigging in the storm 宾格人称代词 作用:做宾语(也可做表语) ​ I like her. ​ Who is it? It’s me. ​ 注意:做表语时,后面跟定语从句时,需要用主格人称代词。 ​ It was he in whom we had the greatest faith(he在从句中做介词宾语) 主格和宾格人称代词可以做同位语: ​ We teachers should be patient with students. ​ Our teachers are all nice to us students. 做宾语时的位置 直接宾语前: He bought me a pen as birthday gift. 直接宾语后:He bought a pen for me as a birthday gift ; I’ve lent much monery to him. 若直接宾语是人称代词,只能置后,但是不适用于不定代词: ​ I will give it to you. ​ I‘ll show you something ; I didn’t give Rex any. 在短语动词中间:Hand them in ; throw it away ; pick it up. ​ 若是名词,则中间和后边都可:hand your papers in = hand in your papers. 物主代词(名词性&形容词性)作用:人称代词的所有格形式,表所有关系。 形容词性:不能单独使用: Your book is over there ; His sister is lovely. ​ 表强调时后+own:I wish I had my own house. 名词性:单独使用;避免重复:This is not my book. Mine(=my book) is in my bog. ​ of + 名词性物主代词: a friend of mine ; a teacher of hers= a teacher of her own. 反身代词 必须主语宾语为同一人时,做宾语:God helps those who help themselves. 强调主语: ​ He himself went to visit the old lady(他亲自去看望那个老太太的) ​ 不产生歧义下可置后: ​ He went to visit the old lady himself. ​ He spoke to the boss himself.(有歧义) 强调宾语:反身代词在宾语后 ​ He saw Tom himself(他看到Tom本人了) ​ I will send this gift to John himself(给john本人,不是通过转交) 介词+反身动词 ​ (1)by oneself:独自一人地 ​ I went there by myself(我自己一个人去了那里) ​ I went there myself(我亲自去了那) ​ (2)of oneself:自动地 ​ The door opened of itself(门自动地开了) 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E4%BA%BA%E7%A7%B0%E4%BB%A3%E8%AF%8D.html"},{"title":"英语语法-名词从句","text":"概念:三种句子充当另外一句子的四种句子成分 1. 陈述句:句前 + that (当宾语时可省略)​ a. That the moon itself does not give off lights is common knowledge. ​ b. I’ve learned (that) love, not time heals all wounds. 2. 一般疑问:变陈述句语序,句前 + whether(当宾语时可用if)​ a. My question is whether people will live on the moon someday. ​ b. I don’t know if/whether he needs my help. 3. 特殊疑问:变陈述句语序​ a. Money is what we are badly in need of. 句子类型 引导词 从句中作用 陈述句 that 不做成分 一般疑问 whether, if 不做成分 特殊疑问 连接副词when, where, why, how连接代词who, whom, what; which, whose 连接副词做状语who, whom, what做主语/表语/宾语which, whose做定语,后+名词连用 it形式主语:it在句首,主句在后面​ a. It is common knowledge that the moon itself does not give off light. ​ b. It is not known where they came from. it形式宾语:复合宾语中:动词 + it + 宾补 + 宾语从句​ I find it encouraging how many young women are pursuing careers in science. 双宾语:Could you tell me where the post office is? 介词后做宾语: You should vote for which candidate you assume best. 形容词后做宾语: I am afraid that I can’t come. 并列宾语从句中that不省略: I once read that “” and that “”. reason后的表语从句:引导词用that,不用because.​ The reason (why) he was dismissed is that he was careless and irresponsible. 嵌套:a. I realized that what I said was not exactly what I meant to say. ​ b. The question is how what you have learned can be put into practice. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%90%8D%E8%AF%8D%E4%BB%8E%E5%8F%A5.html"},{"title":"英语语法-句子简化","text":"名词从句逻辑思路:从句—>动名词or不定式 that引导的主语从句:动名词当主语​ It surprised us that John won the marathon. ​ John’s winning the marthon suprised us. that引导的同谓语从句:+ of 变成复合结构​ There was no chance that Davy would come from the battle alive. ​ There was no chance of Davy coming from the battle alive. that引导的宾语从句:转换动名词or不定式(取决于主句谓语动词)​ a. I hope that I can drive to work in my own car. ​ I hope to drive to work in my own car. ​ b. I consider that I will emigrate to America in the future. ​ I consider emigrating to America in the future. ​ c. Jane’s mother insisted that she should go swimming with her brother. ​ Jane’s mother insisted on her going swimming with her brother. 名词从句不定式简化:​ a. I don’t know what I should do. ​ I don’t know what to do. ​ b. Tell me how I can get to the bus station. ​ Tell me how to get to the bus station. 定语从句逻辑思路:从句—>短语(只有关系词做主语时可简化) 从句有be动词:去掉be动词and关系代词 主动:现在分词;被动:过去分词;形容词短语也可​ a. The man who is standing at the gate is my English teacher. ​ The man standing at the gate is my English teacher. ​ b. Books that are written in English are more expensive. ​ Books written in English are more expensive. ​ c. The people who were responsible for the incident were all punished. ​ The people responsible for the indident were all punished. 从句没有be动词:去掉关系代词;动词—>现在分词​ a. They live in a room that faces the south. ​ They live in a room facing the south. ​ b. English has an alphabet that consists of 26 letters. ​ English has an alphabet consisting of 26 letters. 不定式替换:the only,the last,the next,序数词,最高级修饰的名词​ a. The only one that understands me. ​ The only one to understand me. ​ b. The next train that arrives is from New York. ​ The next train to arrive is from New York. ​ c. Jango was the second person that fell into this trap. ​ Jango was the second person to fall into this trap. 状语从句注意:主句从句的主语相同时,才可以简化。 有be动词:去掉be动词(常见:时间,地点,条件,让步) 主动:现在分词;被动:过去分词;形容词or名词短语也可​ a. Metals expand when heated and contract when (they are) cooled. ​ b. When (he was) a student in the university, he read a lot. ​ c. while (he was) waitting, he took out a magazine to read. ​ d. A tiger can’t be tamed unless (it is) caught very young. 没有be动词:从句主语省略,动词变成现在分词​ a. Since I came to Beijing, I have made many new friends. ​ Since coming to Beijing, I have made many new friends. ​ b. After I finished my homework, I fed the dog. ​ After finishing my homework, I fed the dog. ​ c. After he jumped out of a boat, the man was bitten by a shark. ​ After jumping out of a boat, the man was bitten by a shark. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%8F%A5%E5%AD%90%E7%AE%80%E5%8C%96.html"},{"title":"英语语法-介词","text":"介词特点:不能单独使用,后面需带宾语(名词,代词,数词,动名词,动名词短语,名词从句)搭配:在介词前的词:动词(depend on)名词(pay attention to)形容词(be kind to) 充当: 与其宾语构成介词短语后可充当主语,补足语 ,定语,状语 作用:词与词之间的表示关系 种类:简单介词(at, by, for, from, in,near, of, off, on)复合介词​ 简单链接:inside, into, onto, out of, outside, throughout, upon, within, without ​ 搭配连用:as to, from above, from behind, from beneath, from under, until after 介词短语: at the cost of, at the mercy of, at odds with, by means of, by reason of, by virtue of, by way of, in place of, in favor of, in spite of, with an eye to. 关于:in/with reference to, in/with respect to, in/ with regard to 时间介词:1.at, in, on1)at(时间点)​ a.特定时刻:at nine after ten ​ b.不确定时刻:at night, at dawn, at midnight, at that time, at the moment, at Christmas ​ c.年龄段: ​ at the age of eight/at eight ​ He got married at twenty 2)in(时间段)​ a.长时间段 ​ in the morning/afternoon/evening ​ in spring/summer/autumn/winter ​ in the past, in the past ten years ​ in the twenty-first cenfury ​ a man in his thirties ​ b.在时间之内/后,表将来时 ​ He said he would come back in a month ​ The train is leaving in a minute ​ c.in+动名词:在做…过程中 ​ In crossing the river, we caught some fish. ​ In working, we can learn a lot. ​ d.几月:in October 3)on(表示具体日期)​ a.具体日期和星期 ​ on Monday On my birthday ​ b.特定某天上午、下午等 ​ On the night of December 31,1999 ​ On the eve of christmas/New Year ​ On a hot midnight in July ​ c.在第几天 ​ On his first day to school. ​ On the tenth day I was in Beijing. ​ d.on+动名词 or 名词 = as soon as:一…就… ​ On hearing the bad news, she burst into tears. ​ On arriving, I came directly to visit you. ​ The first thing I did on arrival of Beijing was visit him. at the beginning of 在..的开头 ​ at the begining of a book there is often a table of contents. ​ at the begining of the concert. ​ at the beginning of January. in the begining:at first = in the early stages ​ In the begining, I wrote to my family regularly. later I just gave up at the end of ​ But at the end of this process, unfortunately, the students are none the wiser. ​ At the end of abook there may be an index ​ At the end of the concert at the end of January in the end:eventually = at last:最终…. ​ Jim couldn’t decide where to go for his holidays. He didn’t go anywhere in the end. 有last/next/this/every不再加介词 ​ I’ll see your next Friday. during for ​ during在…期间内,强调这时间内发生了什么 for表示延续时间的长短 ​ I had lived in the countryside for 8 years before I moved to Beijing. ​ I studied in this university for 4 years. During that time most of my time was spent in learning English. ​ My father was in hospital for six weeks during the summer. during接表示一段时间的名词:stay, visit,travel ​ During my visit to China ​ During the travel to the south ​ During the Middle ages for+时间段​ for six years for two months for ever for two hours from​ 和to 或 till/untill连用 ​ Most people work from nine to five. since​ 和时间点连用,从那一时刻起。现在完成时,过去完成时连用 ​ He has been here since last Sunday ​ I haven’t seen him since two years ago ​ I haven’t seen him for two years ​ It’s two years since I last saw him for和时间段连用,表示动作延续到说话的那一刻。现在完成时,过去完成时连用 ​ I have lived here for a year ​ I have lived here since this time last year before, after, till/until(可做介词接短语,可做连词接从句) ​ 后接时间点,某时刻前(before)某时刻后(after)直到某一时刻(till/until) ​ We finished the work before 10 o’ clock ​ I’ll wait for you till 10 o’ clock till/until特点​ 延续性句子谓语(肯定)+till/untill+时间点(若是从句,则从句中谓语动词为短暂性动词) ​ 短暂性句子谓语(否定)+till/untill+时间点(若是从句,则从句中谓语动词为短暂性动词) ​ He didn’t finish the work untill 10 o’ clock(finish短暂动词,用否定) ​ He didn’t leave the office till 12 o’ clock ​ He will stay here until next Sunday(stay延续性动词,用肯定) by​ a.no later than:不迟于某个时间,到了某个时间 ​ by the end of next year ​ b.by引导时间状语常与将来完成时 or 过去完成时连用 ​ By the end of next year I’ll have learned 2000 words ​ By the end of last year I had learned 2000 words 方位介词at, in at表示小地方 at home, at the office, ata school, at the bridge, at the crossroads, at the bus-stop at the doctor’s, at the hairdresser’s in表示大地方 in a country, in a town, in a village, in the street, in the forest, in a field, in a desert 其他情况 in a line/in a row/in a queue in a photo/in a picture in a mirror in the sky/in the world in a book/in a newspaper/in a magazine/in a letter in the front/back row(at the front/back) in the front/back of the car at the front/back of the building/cinema/classroom 谈论建筑 at表示事情发生场合 I met him at the cinema last night. in表示建筑物本身 I enjoyed the film but it was very cold in the cinema in强调在建筑里,at包括建筑物周围及里面 at the restaurant(可以是餐馆内,也可以是在餐馆附近的某个地方) in the restaurant(在餐馆里) at the cinema(在电影院,不一定在里面) in the cinema(在里面) There were a lot of people in the shop, It was very crowed Go along this road, then turn left at the shop on, over, above on表示两者接触 Put away the books on the desk The dictionary on the table is not mine There is some water in the bottle There is a label on the bottle There is somebody at the door. Shall I go and see who it is? There is a notice on the door. It says “Do not disturb” on的其他情况 on the left/on the right on the first/second floor on a map on the page/on page seven(at the top/bottom of the page) on the menu on the list on a farm on the way to school on the corner of street, in the corner of the room over不仅接触,还有覆盖的含义 Spread the cloth over the table Mon put a rug over me when I was asleep over还可以表示正上方 There is a bridge over the river There is a lamp over the desk above仅表示上下位关系,不接触,也不是正上方 The sun rose above the horizon There is a bridge above the river He is over me(He is my immediate superior) He is above me below,under,beneath under在下方,可接触,可不接触 I put the money under the mattess The dog is groveling under the table below表示两个表面之间间隔距离 They live below us beneath可以替换under,但是偏向抽象含义 He would think it beneath him to tell a lie She married beneath her 手段介词by 表示行为方式 send something by post do something by hand pay by check/by credit card(pay in cash) 某事发生:by mistake/by accident/by chance(on purpose) 表示交通工具 by car, by train, by plane/air, by boat/sea/ship, by bus, by bicycle, by metro/subway/underground(on foot) by car(in a car, im my car, in the car) I don’t mind going by car but I don’t want to go in your car car, taxi前用介词in They didn’t come in their car. They came in a taxi. 自行车和公共交通设施前用on on the train/by train, on his bicycle/by bicycle 表示通过 某种手段达到预期效果(与with区别) We succeeded by cooperating with them Our mission is to help our clients achieve their business goals by providing a service for the timely delivery of qualified staff to support their operational needs. with 表示用具体的工具做某事 I killed a fly with a flyflap We can see with our eyes and write with our hands in 表示以某种方式做某事 Write in pencil/in ink Express this in your own words Speak in a low voice Pay in installments through 与by相近,through一般多根名词连用, by多跟 动名词连用 they talked to each other through an interpreter. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E4%BB%8B%E8%AF%8D.html"},{"title":"英语语法-基本句子结构","text":"subject + intransitive verb: 主 + 不及物动词 Man proposes; God disposes Modesty benefits; pride hurts The sun rises and the sun sets. Stars glitter and stars vanish. There are ups and downs in life 常常带有状语​ Great minds think alike ​ The sun sets in the west Subject + Link Verb + Subject Complement: 主 + 系动词 + 表语(主语补足语) He looks unhappy The leaf will trun yellow in autumn I’ve got to return the book this afternoon; it falls overdue a week The best proof of love is trust Bread is the staff of life 介词短语也可以做表语​ Beauty is in the eye of the beholder 表示特征状态: feel, look. sound, taste, smell, seem, appear​ The iron feels hot. ​ The rose doesn’t smell much 状态转变: become, grow, get, turn, fall, go, come​ Our supplies of sugar and rice fell short ​ The jokes fell flat ​ fall asleep ​ fall due ​ go hungry go sour go wrong ​ Hope your dreams will come ture ​ The leaf will turn yellow in autumn ​ I’ve got to return the book this afternoon. it falls overdue a week 状态保持: continue, remain, stay, keep, hold, rest, prove​ The weather continued fine for several days ​ He held silent fo the whole day ​ He has fallen into the habit of doing morning exercises ​ You may rest assured that he will come to the party 近似不及物动词的系动词​ Mr. Bean often acted weird in public ​ All the audience sat silent ​ He was born poor ​ The boy blushed scarlet ​ I married young ​ He died young ​ Jane Austin died a spinster ​ He died a hero’s death Subject + + Transsitive Verb + Object: 主 + 谓 +宾​ Beauty will buy no beef ​ I want to go home now ​ I’ve finished reading the book ​ I’ll pick you up this evening Subject + Dative Verb + Indirect Object + Direct Object: 主 + 谓 + 间接宾语 + 直接宾语​ He showed the guard this passport ​ I will buy you a meal ​ 1. assign, award, bring, deliver, deny, feed, give, grant, hand, lend, offer, owe, pass ​ pass, pay, promise, post, read, recomment, sell, send, show, take, write ​ He showed his passport to the guard ​ He showed the guard his passport ​ 2. 介词用for: book, buy, build, change, choose, cook, fetch, find, get, keep, make, order, prepare, sing ​ I am going to buy a gift for her ​ I am going to buy her a gift ​ 3. 不能用介词: charge, cost, bet ​ I’ll bet you ten dollars ​ The repairman charged me ten dollars ​ 特殊: ask ​ Can I ask you a question? ​ Can I ask a question of you Subject + Factitive Verb + Object + Object Complement​ They appointed John chairman ​ I believe him to be true ​ The chairman declared the meeting over ​ They elected John chairman ​ You can leave the door open ​ A hedge between keeps friendship green ​ 双宾语和复合宾语区分:宾语后加上be,若能成完整句子则是补足语 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%9F%BA%E6%9C%AC%E5%8F%A5%E5%AD%90%E7%BB%93%E6%9E%84.html"},{"title":"英语语法-关系从句","text":"概念:用句子修饰另一句子中的概念(词 to 整个句子) 单词:The woman who lives next door is a famous dancer. 短语:He likes climbing mountains, which is a good exercise. 分句:He said that he had no time, which isn’t true. 整句:He arrived an hour later, which annoyed his girlfriend very much. 形成:两个句子共用的概念为连接点 He laughs best who laughs last. ​ 句子1. he laughs best 句子2. he laughs last 关系词 who ​ 共用He,句1:描述事实,句2:限定作用 种类:形式区别:有无 “,”限制性:提供必要信息,若去掉,含义不明 I don’t like people 意思不明 I don’t like people who never keep their words. 非限制性:补充附加信息,若去掉,含义仍明 Beijing, which is the capital of China, has developed into an international city. 关系词:根据关系词在从句中充当的成分,被分为:关系代词,关系副词关系代词 关系代词 用法 例句 who:只指人 前不可加介词 The girl who you work with is his girl friend whom:只指人 只宾/表,宾语非限制性必用 Li, with whom you work, is his girl friend which:不指人 非限制性句首时用as As I expected, he didn’t believe me that:指人or物 不加介词,无非限制性 The world in which we live is made up of matter. whose+名词指人or物 whose = of which These children sit in a schoolroom of which all the windows are broken. 特殊关系代词as:正如 限制性:只能用在such,the same,as,so ​ a. He’ll repeat such points as are discussed in the book. ​ b. Such a student as works hard will be sure to succeed. ​ c. He tried to make as few mistakes as he could avoid. ​ d. He is not the same playboy as we knew. 非限制性:位于句首必须用as As is known, the whale is not fish but a mammal. 代替全句:as:主从句内容一致 which:主从句内容互斥 She has married again, as was expected. She has married again, which was unexpected. what:等于 先行词 + 关系词单独使用:不能有先行词 She is not what she used to be = She is not the girl that she used to be. what+名词:所有的… a. I will give you what help I can. b. What money I have has been given to you = All the money that I have… 辨析:结构上也可以理解成名词从句,意思上如下 名词从句:整个句子的意思 What he said shows that he is cruel. what从句:只指what这个人或物 He is not what he was a few years ago. than:主句有比较级 a. Don’t drink more wine than is good for health. b. Don’t give him more money than is needed, since money will burn a hole in his pocket. but:eq that/who/whom…not ​ a. There is no man but errs = There is no man who doesn’t err. ​ b. There are few but admire his talent = There are few who don’t admire his talent. ​ c. There are very few people in this club but he knows =whom he doesn’t know. 关系副词限制性 or 非限制性 从句中必做状语 关系副词 先行词 例句 when=on which 时间:day,year,time I’ll never forget the day (when) I met you(紧随其后可省略)I’ll never forget the time which I spent on campus(不做状语时) where=in/at which (抽象)地点place,housesituation, point,joint When you read books, you had better make a mark at the spot where you have any question(定语从句修饰spot)When you read book, you had better make a mark where you have any question(状语从句) why无非限制性 原因:why等 This is the reason why I didn’t come herewhy = for which 方式the way in whichthat省略 You know the old golden rule, “Care for others the way in which you would like them to care for you” 介词+关系代词(whom/which/whose)动词/形容词搭配的介词,可前可后 线索 说明 例句 从句中介词和动词搭配形容词搭配名词搭配 最常用常见较少 He is the man on whom I think you can depend.He referred me to some books with which I am not very familiar.I am sending you an inquiry, to which your prompt attention is highly appreciated. 介词先行词搭配 at the ratewith ease The speed at which an animal lives is determined by measuring the rate at which it uses oxygen. 修饰部分of which 最高级+of whom/which The total cultivated area is 13,000 acres, of which 10,000 acres are irrigated fields. in which to do 此结构注意 A house in which to store grains = A house to store grains inI can’t think of anybody whom to invite 没有介词不能用介词不能置后不能用关系副词代替 引导词辨析 从句 that which 定语从句 充当成分The rumor that he spread everywhere turned out to be untrue.(充当定语) 单独使用Anger is a wind which blows out the lamp of the mind. 名词从句 不当成分THe rumor that Tom was a thief truned out to be untrue.(句子完整) which + 名词连用You should vote for which candidate you assume best. 复杂定语从句 定语从句后置 先行词和定语从句分开 Consequently, nothing seems good or normal that does not accord with the requirements of the free market. 带有插入语 表达个人观点紧跟关系词后 He ran all the way from the station, which I thought was incredible. 并列定语从句 and/or/but连接多个从句修饰同一词 I’d much rather receive a gift that was unique or that I knew my friend had put some thought into. 嵌套修饰 定语从句修饰“先行词+定语从句” He is the only person that we know who speaks so many foreign languages. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%85%B3%E7%B3%BB%E4%BB%8E%E5%8F%A5.html"},{"title":"英语语法-副词","text":"时间副词种类​ 1.确切时间:yesterday, today, now, tomorrow ​ 2.不确切时间:already, recently, lately, before, soon, then, afterwards ​ 3.副词短语:this morning, last night, in the morning, a week ago, three months ago, ​ at once, in a while, in recent days. 位置​ 确切时间副词:句首 or 句末(更常见)(祈使句只在句末) ​ Tomorrow I’m leaving for Beijing on a businiess tour. ​ I’m leaving for Beijing on a business tour a week ago. ​ Come to my office this afternoon. ​ 不确切时间副词:句首 or 句中 or 句末 ​ Very soon we’ll be there ​ We’ll very soon be there ​ I have been busy recently. ​ before, early, immediately, late 句末 ​ Ihave never heard such a story before. ​ He came to school late. ​ 总结:句末保险,句中的副词不多,祈使句只在句末。 地点副词种类​ 1.表示方向:away, down, in, off, on, over, out, round, up ​ 2.表示位置:here, there, somewhere, anywhere, nowhere, everywhere ​ 介词短语:in the park, at home, in the street 位置(一般:动词后)​ 1.方向副词在地点副词之前:He often walks around in the garden after supper. ​ 2.大地点副词在后:He works in a foreign-funded company in Beijing. ​ 3.方向副词:away, down, in, off, on, over, out, round, up, here, there可以倒装 ​ 倒装1:副词+动态动词+名词主语 ​ Here comes the teacher. ​ Round and round flew the plane. ​ 倒装2:副词+物主代词+动态动词 ​ Away they went. ​ Here he comes. ​ 4.介词短语+动词+主语 倒装:down, from, in, on, over, out ,of, round, up ​ From the trees hang a lot of monkeys. ​ Down this street stand a lot of shops. ​ On the ground lies a man whose legs are broken. 总结:一般句末;有些倒装结构句首。 频率副词种类​ 1.确切频率:daily, weekly, monthly, yearly/annually, twice a week/month/year ​ 2.不确切频率:always, often, usually, sometimes, occasionally, frequently, continually, ​ repeatedly, once, ever, never, rarely, seldom(否定). 位置1.不确切频率在 句中​ 1)实义动词前(am, is, are, was, were),助动词后(will, should, have) ​ a. I often do some shopping on weekends. ​ b. She is often late for school. ​ c. I have never seen him since we parted. ​ 2)多个助动词时,在第一个助动词后 ​ a. This project will never be finished. ​ b. You should never have trusted him. ​ 3)加强语气,在系动词 or 助动词 前 ​ a. You really will get a reward one day. ​ b. I always have been patient. ​ 4)只有助动词而省略了实义动词的句子,在助动词前 ​ a. You should have known better thaan to trust him. I never will(trust him) ​ b. Can you find a plaace to park your car in the street? Yes, I usually can. ​ 也要用在省略了标语的系动词前: No, she never was. 2.确切频率在 句末​ a. Milk is delivered daily. ​ b. We have meetings twice a week. 3.不确切频率也可用在句首 or 句末​ a. Often/Sometimes/Usually I work late into the night. ​ often不单独在句末,需加very or quite修饰 ​ b. He comes late for school quite often. 4.always除在祈使句中句首,其他时候在句末​ a. You always make the same mistakes. ​ b. Always remember not to argue with your boss. 5.否定句中的频率副词​ a.often/sometimes/usually not ​ His wife complains that he sometimes doesn’t listen to her. ​ b.not always ​ He doesn’t always leave before 6 o’clock, sometimes he works until 8 o’clock. 6.never, rarely, seldom​ a.不能再与not连用 ​ He seldom goes out at night. ​ b.若在句首则倒装 ​ Never have I heard such a story (I have enever heard such a story) ​ 总结:不确切频率在句中,确切频率在句末。 程度副词 意义:表示程度或大小,修饰形容词、副词、动词、甚至名词 位置:被修饰词前 比较 ​ Only I saw him at the party last night(Nobody else saw him) ​ I only saw him at the party last night(I didn’t talk to him) ​ I saw only him at the party last night(I didn’t see any other friends) ​ I saw him only at the party last night(I didn’t see him at other places) ​ I saw him at the party only last night(I didn’t see him until last night) enough:在所修饰形容词 or 副词之后 ​ He is not old enough to go to school ​ He didn’t work quickly enough 否定副词不与否定词连用 barely, scarcely, hardly ​ 注意:与频率副词rarely区别 ​ 不说:He hardly attends class ​ 应说:He rarely attends class 可以修饰名词的程度副词 ​ quite, only, even, particularly, especially, almost, rather. ​ quite some, quite an expert ​ It was quite a surprise. ​ rather a bore, rather a shame ​ 注意:quite在a/an前,rather可前可后 ​ quite a nice day. ​ rather a long way a rather long way. ​ vegetables, especially spinach, are good for you ​ He is almost a child ​ Even a boy knows the answer 方式副词 修饰:动词专用 构成:数目不固定,可由形容词+ly构成 位置:修饰动词的后边 有宾语时,宾语在前 I can’t speak English well.He can finish the job quickly. 若动词后成分很长,则在动词前 He firmly believes that he will succeed.I happily pronouce you man and wife. 动词+介词+宾语,可位于宾语后或介词前 The class is listening to the teacher carefullyThe class is listening carefully to the teacher 方式副词在被动分词之前 I was badly paid in that company when I just graduated.When do you think you will have completely finished? 句子副词 修饰:整个句子 位置:句首 意义: 表示说话角度:Geologically, a thousand years is a short time. 表示说话人态度:Frankly, I think he is dishonest. ​ Hopefully, we can get there in time 比较方式副词和句子副词 ​ 句子副词:Happily, he didn’t die. 幸好,他还活着 ​ 方式副词:He didn’t die happily. 他不是安然地离开了这个世界 其他位置 副词顺序:方式副词+地点副词+时间副词 ​ She sang an English song nicely in the auditorium last night. ​ She checked the accounts carefully in the office this morning. (不)确定性副词:probably, possibly, perhaps, certainly, definitely, surely.不在句末 ​ He has probably not been there before. ​ I definitely know how to deal with this matter. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%89%AF%E8%AF%8D.html"},{"title":"英语语法-动名词","text":"做主语1. 直接句首做主语:谓语动词用单数​ a. Seeing is believing. ​ b. Reading is like permitting a man to talk a long time, and refusing you the right to answer. ​ c. Having a successsful marriage takes effort and patience, and communication is the key. 2. It is no good doing sth句型​ it形式主语,真正主语是doing sth ​ no可以替换为:any/some good, any/some/no use, a waste of time. ​ a. Is it any good trying to explain? ​ c. It’s not much use my buying salmon if you don’t like fish. ​ d. it’s simply a waste of time and money seeing that movie. 3. there be句型​ 1) there is no point (in) doing something,做某事没有意义 ​ a. there is no point in my going out to date somedone, I might really like if I met him a the time, but who, right now, has no chance of being anything to me but a transitional man ​ 2) there is no use/good (in) doing something ​ a. there is no use your arguing with him ​ b. there is no use your complaining to me about this. ​ 3) there is no doing something = it’s impossible to do something = we can’t do something. ​ a. there is no denying the fact that…毋庸置疑 ​ b. there is no gainsaying the fact that…毋庸置疑 ​ c. there is no telling what will happen tomorrow. ​ d. there’s no knowing the future = it’s impossible to know the future, or we can’t know it. 做宾语1. 一些动词后只能用动名词做宾语​ appreciate, avoid, consider, delay, dislike, enjoy, escape, feel like, finish, can’t help, invlove, ​ overlook, permit, postpone, practise, risk, can’t stand, suggest, tolerate, understand. ​ a. I will overlook your being so rude to my sister this time but don’t let it happen again. ​ b. Many of the things we do invlove taking some risk in order to achieve a sitisfactory result ​ c. Being a bad-tempered man , he would not tolerate having this lectures interrupted. 接动名词和不定式有区别的动词: 很多动词接动名词和不定式均可,但是意思有很大差别。 1. demand, deserve, need, require, want 动名词:主动形式表示被动 不定式:必须用被动形式 ​ a. The garden needs watering/ to be watered. 不说 The garden needs being watered. ​ b. Your hair needs cutting/ to be cut. 2. remember, forget, stop, go on, regret. 动名词:表示发生于这些动词之前的事 不定式:表示发生在这些动词之后的事 1) remember remember doing sth: remember/ recall something that happened in the past. 记得已做过某事 ​ a. I still remember being taken to Beijing for the first time. ​ b. I don’t remember/recall locking my suitcase ​ = as far as I know, my suitcase should be open remember to do sth: remember to perform a responsibility, duty or task. 记得需要履行的职责 or 任务。 ​ a. Remember to go to the post office, won’t you? ​ b. Remember to do some shopping after work. ​ c. Clint always remembers to turn off the lights when he leaves the room. 2) forget forget doing sth: forget something that happened in the past. 忘记了已做过的某事 ​ I forgot locking the door. So when I came back, I found the door locked. ​ as far as I know, the door should be open. forget to do sth: forget to perform a responsibility, duty or task. 忘记要做的事 ​ As well as getting on everybody’s nerves, he’s got a habit of borrowing money and forgetting to pay it back. 3) stop stop doing: 停下经常做的或手头正在做的事情 ​ I really must stop smoking. stop to do: 停下来去做某事 ​ stop to have a rest. 4) go on go on doing sth: 继续做一直在做的事情。 ​ a. The teacher went on explaining the text. ​ b. Peter went on sleeping despite the noise. go on to do sth: 改做另一件事 ​ a. He welcomed the new students and then went on to explain the college regulations. ​ b. Finishing the new words, the teacher went on to attack the text. 5) regret regret doing sth: regret something that happened in the past. 对已发生的事情感到遗憾 ​ a. I don’t regret telling her what I thought, even if it upset her. ​ b. I regret letting slip that opportunity. ​ c. I regret lending him so much money. He never paid me back. ​ d. Now he regrets not having gone to university. regret to do something: regret to say, to tell someone, or to inform someone of some bad news 遗憾的告诉或通知某人某个坏消息。 ​ a. We regret to inform you that we are unable to offer you employment. ​ b. I regret to tell you that you failed the test. ​ c. We regret to inform you that the flight has been cancelled. 动名词的其他结构1. have difficulty (in) doing sth​ trouble ​ problem ​ (a lot of fun) ​ (lots of) pleasure ​ a hard time ​ a good time ​ a difficult time 注意: take the trouble to do sth, trouble to do sth, have (no) time to do sth. ​ a. I worked sos late in the office last night that I hardly had time to catch the last bus. ​ b. I have a hard time getting used to living in a big place. 2. can’t help doing, can’t resist doing, can’t keep from doing, can’t hold back from doing​ can’t keep back from doing ​ 注意: can’t help but do, can’t but do, can’t choose but do,etc. ​ No one can help liking Tom; he is such a cute boy. 3. be worth doing值得做;主动形式表示被动​ be worthy of being done 或 be worthy to be done. ​ a. The book is worth reading. ​ b. The book is worthy of being read. ​ c. The book is worthy to be read. 动名词的复合结构物主代词(his, my ,your等)所有格名词(Mary’s Tom’s)与动名词连用,即构成动名词的符合结构。用来引出动名词的逻辑主语,以区别于句子主语。 Clint insisted on reading the letter. (Clint看了信) Clint insisted on my reading the letter. (我不得不看信) Would you mind telling us the whole story? (你告诉) Would you mind Tom’s telling us the whole story? = Would you mind if Tom tells us the story He disliked working late He disliked my working late I object to making private calls on this phone I object to his making private calls on this phone. 用法 做主语或宾语 ​ a. Tom’s coming home at last was a great consolation (做主语) ​ b. Do you mind my making a suggestion? (做及物动词宾语) ​ c. Our discussion of earthquakes would be imncomplete if we didn’t raise the possibility of their being caused by external forces. 物主代词(his)可以改为宾格代词(him) or 所有格名词(Tom’s)改成普通格名词(Tom) ​ a. It’s no use Tom arguing with his boss. ​ b. Do you mind me making a suggestion? ​ c. I am annoyed about John forgetting to pay. 应用原则:​ 1) 若动名词复合结构在句中做主语,最好用所有格形式 ​ a. Tom’s refusing to accept the invitation upset me. ​ b. His refusing to accept the invitation upset me. ​ c. It was a great consolation his coming home at last. ​ 2)动名词复合结构在句中做宾语时候,用普通格或所有格均可 ​ a. Do you mind me making a suggestion? ​ b. I am annoyed about John forgetting to pay. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%8A%A8%E5%90%8D%E8%AF%8D.html"},{"title":"英语语法-动词不定式","text":"做主语:It + to do sth 句型1. It + to do sth句型;it做形式主语​ a. It is easier to spend money than to make money. ​ b. It takes time to study English well. ​ 形式主语it不能用this或that替换 ​ This is impossible for people to stare directly at the sun.应用it 2. 不定式置于句首做主语,谓语动词要用单数。​ a. To err is human; to forgive, divine ​ b. To solve this problem takes a genius like Einstein. ​ c. To love for the sake of being loved is human, but to love for the sake of loving is angelic. ​ d. To send a letter is a good way to go somewhere without moving anything but your heart. 做宾语:动词 + to do1. 直接跟在一个及物动词后面做宾语​ 特点一:句子的主语和不定式的逻辑主语是一致的,动作都是由主语发出。 ​ 特点二:这时句子谓语动词多是描写态度;不定式动作则说明行为。 ​ a. I hope to see you again. ​ b. This company refused to cooperate with us. ​ c. He promised not to tell anyone about it. ​ 接不定式做宾语的动词有 ​ agree, appear, beg, begin, dare, decide, expect, fail, forget, happen, hate, hesitate ​ hope, intend, like, love, manage, mean, prefer, prepare, pretend, promise, propose ​ refuse, regret, remember, seem, start, swear, try, want, wish 2. 连接词引导宾语从句的简略形式:动词 + 连接代词or连接副词or连词whether + to do​ a. I wonder who to invite. (= who I should invite) ​ b. Show us what to do. (= what we must do) ​ c. I don’t know whether to answer his letter. (= whether I should answer) ​ 类似动词还有:ask, consider, decide, discover, explain, forget, find out, guess, imagine, ​ know, learn, observe, remember, see, tell, teach, think, understand, wonder 做宾语补足语:动词 + sb to do sth1. 通常结构:动词 + sb to do sth​ a. They don’t allow people to smoke in the theater. ​ b. The chairman declared the meeting to be over. ​ c. Allow me to drink to your success. ​ d. Allow me to propose a toast to our friendship. ​ f. My mother wishes me to return to China. ​ 常用动词:advise, allow, ask, beg, cause, encourage, expect, forbid, force, get, help, like ​ order, permit, persuade, remind, teach, tell, want, warn, wish(hope不可) 2. 在let, make, have, see, hear, feel, watch, notice, listen to等动词后面,不定式做宾语补足语to要省略,改为被动语态,则必须带to(详见“不带to的不定式”)做定语:名词 + to do sth1. 动宾关系​ 被修饰名词在逻辑上做不定式的宾语 ​ a. She has four children to take care of. ​ b. I had no place to live in. ​ c. You just regard me as a thing, an object to look at, to use, to touch, but not to listen to or to take seriously. ​ d. I gave the kid a comic to read. ​ e. He needs a place to live in. ​ f. I have no partner to speak English with. ​ g. I need a pen to write with. ​ h. I need a piiece of paper to write on. ​ 注意: ​ 1. 不定式一般不用被动形式 ​ 2. 不定式动词后面不能再加宾语 ​ a. I gave the kid a comic to read it. * ​ b. I need something to eat it. * ​ 3. 不定式动词后介词不省略 ​ a. I have no partner to speak English. * ​ b. I need a pen to write. * 2. 被only, last, next, 序数词, 最高级修饰的名词通常用不定式做定语​ a. I don’t think he is the best man to do the job. ​ b. The next train to arrive is from New York. ​ c. Clint was the second person to fall into this trap. ​ d. Clint was the only person to survive the air crash. 做独立成分 修饰整个句子: to begin with, to tell the truth, to make a long story short, so to speak, to be brief/exaact/frank/honest, to say nothing of(姑且不所说), to say the least(至少可以这么说) a. To begin with, on behalf of (代表)all of your American guests, I wish to thank you for the incomparable hospitality. b. I have a point there, to say the least. c. To make a long story short, he is in hospital now. 做状语:目的在状语 and 结果状语1.做目的状语 a. Hating people is like burning down your own house to get rid of a rat. b. To avoid criticsim, do nothing, say nothing, be nothing. c. To acquire knowledge, one must study; but to acquire wisdom, one must observe. d. We had better start early to catch the train. e. I went to the post office to mail a letter. 可以用in order to do 或 so as to do 强调目的状语 ​ a. We had better start early so as to catch the train. ​ b. I went to the post office in order to mail a letter. ​ c. I quote others in order to better express my own self. ​ d. The teacher raised her voice in order for us to hear more clearly. ​ 注意:so as to不放在句首;to do和in order to do可以放句首。 2.做结果状语 1. 直接做结果状语 ​ a. He lived to be a hundred years. ​ b. What have I done to offend you? ​ c. He lived to see second world war.(= he lived until he saw world war II) 2. never to do表结果 ​ a. John left his hometown ten years ago, never to return. ​ b. We parted never to see each other. 3. only to do引出意想不到或不愉快的结果 ​ a. We hurried to the railway station, only to find the train had just left. ​ b. All too often, women complain that they’re educated as equals, only to go out into the workforce to be treated as inferiors. ​ c. He worked very hard, only to find he had not finished half of the job. 4. enough to ​ a. He is not old enough to go to school. ​ b. The teacher speaks loudly enough to make himself heard clearly. 5. too…to结构:太…而不能 ​ a. The box is too heavy for me to even move. ​ b. The tea is too hot to drink. 形容词后的不定式1. 句子主语和不定式可以构成逻辑上的主谓关系 这类形容词通常表示人的性格特征或行为表现 brave, careful, careless, clever, considerate, cruel, foolish, generous, kind, modest, nice polite, rude, selfish, silly, stupid, thoughtful. ​ a. He was surprised to learn how much he had spent. ​ b. The boy was careless to break the window. 2. 句子主语和不定式构成逻辑上的动宾关系 a. She is interesting to listen to = It is interesting to listen to her. b. Relativity theory isn’t easy to understand = it isn’t easy to understand relativity theory. c. She is very nice to talk to = It is very nice to talk to her. d. Mary is easy to get on with = It is easy to get on with Mary. e. English is difficult to speak. f. Football is very interesting to watch. g. Barbara is interesting to listen to because she reads a lot. 在动宾关系的情况需要注意:​ 1)不定式动词不用被动式(最容易出错) ​ a. English is difficult to be spoken ​ b. Football is interesting to be watched ​ 2)不定式后不加宾语 ​ a. Football is very interesting to watch it ​ b. She is nice to talk to her ​ 3)不定式动词所带介词不能省略 ​ a. She is interesting to listen ​ b. She is easy to get on ● It’s impossble for fish to live without water. ● it’s necessary for students to do more exercise in learning English. ● The boy was made to sing the song once again. ● He couldn’t help bursting into tears after he heard the news. ● She could not but admit that they were justified in this ● They forbade him to go to the park ● The first explorer to reach California by land was Strong Smith, a trapper who crossed the southwestern deserts of the United States in 1826 ● He was the first to arrive and the last to leave ● The teachers don’t know what it takes to start and run a school. 不带to的不定式动词的复合宾语中to省去 1. 感觉动词:see, hear, watch, notice, feel, observe 2. 使役动词:let, make, have ​ a. The teacher has us write a composition every week. ​ b. I saw a man enter the shop. ​ 但为被动结构时,后面需要 + to ​ a. A man was seen to enter the shop. 一些短语中to省略 had better, would rather, would sooner, would just a soon, might(just) as well, cannot but cannot choose but, cannot help but ​ a. I cannot but admire his courage. ​ b. We might as well put up here for tonight. ​ c. I couldn’t help but fall in love with you. do nothing/anything/everything but do省略 a. I have nothing to do but wait. b. I have no choice but to wait(but前没有do,则不定式 + to) c. He needs nothing but to succeed. d. He will do anything but give in 在解释do的精确含义的名词从句和定语从句做主语的句子中,be动词后直接 + do e. All that I could do then was wait. f. What I could do then was wait. g. All you do now is complete this form. h. No mountains too high for you to climb. All you have to do is have some climbing faith. g. No rivers too wide for you to make it across. All you have to do is believe it when you pray. 英语学习-语法系列github仓库,欢迎收藏star ​参考文章: 参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%8A%A8%E8%AF%8D%E4%B8%8D%E5%AE%9A%E5%BC%8F.html"},{"title":"英语语法-定语从句","text":"完整句子做定语形容词做定语放在被修饰词前面 完整句子做定语放在被修饰词后面 定语从句的重要概念先行词:被修饰或限定的词(the people) 关系词:重复指代先行词,起连接作用并在定语从句中充当成分 代词作用:重复指代先行词,从句中充当成分 连接作用:连接主句和从句的作用 关系代词的用法 先行词指人who,whom 先行词指物which 先行词指人或物均可:that,whose 先行词指人 who和whom区别 who在从句中可做主语,宾语,表语,但who之前不可用介词 ​ I like the people who I work with ​ I like the people with whom I work whom在定语从句中不能做主语,可以做表语或宾语 ​ A rich person is not one who has the most, but is one who needs the least. **表示人或物的所有关系:whose + 名词:在从句中可做主语,动词宾语,介词宾语** a. When I looked through the window, I saw a girl whose beauty took my breath away. b. It was a meeting whose importance I did not realize at the time ​ 动词宾语 c. Atlas(in Greek mythology) was a kneeling man on whose shoulders the world rested. ​ 介词宾语 先行词指物 a. which可以指代单个名词 ​ Perhaps it is human to appreciate little that which we have and to long for that which we have not b. which可以指代单个短语 ​ He likes climbing mountains, which is a good exercise. c. which可以指代前面整个句子 ​ She wore her swimming things in the office, which shocked her boss a great deal. 非限定性定语从句:被修饰的句子不需要定语从句意思也完整,只是补充说明 that指代人或指代物:注意不可以用在介词后面 The world that/which we live in is made up of matter. The world in which we live is made up of matter. 最好用that情况 先行词有人也有物时,用that ​ The writer and his novels that the article deals with are quite familiar to us. 先行词为指物的all, little, few, much, none, the first用that ​ a. All that glitters is not gold. ​ b. This book contains little that is useful. ​ c. There is not much that can be done. ​ d. As long as you stand up to the difficulties, there are none that cannot be overcome. 先行词是不定代词something, anything, nothing, everything用that ​ a. Is there anything that I can do for you? ​ b.Greater expense does not always equal better gift, I would much rather receive a gift that was unique or that I knew my friend had put some thought into rather than something that cost a lot of money but that I didn’t need or want. I would much rather receive something that made me laugh, made me reminisce, or fit my personality that something that cost a lot but that I will just throw in my closet and forget about. 先行词被any, only, all, every, no, some, much, few, little, 序数词,最高级,the only, the one, the very, the right, the last,修饰时用that ​ a. Tell us all things that you know. ​ b. There is no difficulty (that) they can’t overcome. ​ c. The only thing that we should do is find our way home. ​ d. The very problem that I want to solve is like this. ​ e. He is the only man that can speak four foreign languages in our company. 关系代词省略 关系代词who, whom, which, that 若在定语从句中用作宾语,可以省略 ​ a. Tina likes the present which I gave her for her birthday. ​ b. Tina likes the present that I gave her for her birthday. ​ c. Tina likes the present I gave her for ther birthday. ​ d. I like the people who I work with. ​ e. I like the people I work with. ​ f. I’m talking about friends who you can share almost everything with. ​ g. I’m talking abouot friends you can share almost everything with. 关系副词的用法:when, where, why,从句中做时间状语,地点状语, 原因状语 先行词指时间 ​ when 引导限制性和非限制性定语从句,先行词须是表示时间的名词 ​ day, year, time, when可以用on which来替换 ​ a. I’ll never forget the day when I met you. ​ b. I’ll never forget the day on which I met you. ​ c. We will put off the outing until next week, when we won’t be so busy. ​ d. The day may soon come when we don’t bother to go to office but just work at home. 关系副词when在从句中做时间状语 ​ 当心:表示时间的先行词,若定语从句中不缺少状语和是缺少宾语或主语,要用which或 that来引导定语从句。因为when来引导定语从句的前提条件是:when 在其引导的定语从句中做时间状语。 ​ a. The day, which began brightly, ended with a violent storm. (which做主语) ​ b. I’ll never forget the time which I spent on campus. (which做spent宾语) ​ c. I’ll never forget the day when we first met in the park. (when做时间状语修饰met) where的用法 = at which或in which where引导定语从句,先行词必须是表示地点的名词,如place, house ​ a. Do you know any place where I can buy Clint’s grammar book? ​ b. Do you know any place at which I can buy Clint’s grammar book? ​ c. This is the town where(in which) I spent my childhood. ​ d. This is the restaurant where I often have my breakfast. 关系副词where在从句中做地点状语 ​ a. This is the town where I spent my childhood. ​ b. This is the town which I told you about before. which做about的宾语 ​ c. The library where students often study was on fire last night. ​ d. The library, which was built in the 1930’s, needs to be renovated. ​ e. One of the places which I want to visit someday is Tibet. which做visit宾语 why的用法:只用来引导限制定语从句,先行词是reason等表示原因的名词 因为说明原因,所以不是补充说明,不能做非限制定语从句 = for which This is the reason why I didn’t come here 限制性和非限制性的定语从句 形式上:有无 “,” 分割开来 限制性定语从句 ​ 作用:用来提供必要的信息,限定身份或性质,限制范围,若去掉从句,含义不明 ​ 例子:I don’t like people意思不明 ​ I don’t like people who never keep their words. 非限制性定语从句 ​ 作用:提供附加的非必要信息,补充说明或解释,去掉从句,不会引起误解。 ​ 例子:Beijing, which is the capital of China, has developed into an international city. 如果定语从句修饰一个专有名词,我用一般用逗号,就是要用非限定性定语从句。 因为专有名词本身意思已经很完整,不需要限制,只是用定语从句进行补充 用不用逗号的句子意义有差别 限制性 非限制性 解释 he has a daughter who works in a hospital he has a daughter, who works in a hospital a,表示他有多个女儿,其中一个在医院工作b,强调他有一个女儿,不是儿子,在医院工作 the food which wasn’t in the fridge all went off. the food, which wasn’t in the fridge, all went off a,没有放在冰箱里的那部分食物坏了b,食物都坏了,因为没有放在冰箱里。此时的定语从句补充说明变坏的原因。 限制性定语从句一般翻译成定语形式“….的” 非性质性定语从句往往翻译成各种状语 a. the food, which wasn’t in the fridge, all went off. ​ 翻译成原因状语从句 b. the Ambassador gave a dinner to the scientists, with whom the especially wished to talk ​ 翻译成原因状语从句 c. the people were desperate for work, any work, which could support their family. ​ 条件状语从句 d. the millionaire had another house built, which he didn’t need at all ​ 让语状语从句 that引导的定语从句和同位语从句的区别 that是否做成分:that在定语从句中充当成分,在同位语从句中不做任何成分 ​ a. the rumor that he spread everywhere turned out to be untrue. ​ b. the rumor that tom was a thief turned out to be untrue. ​ a 中that在从句he spread everywhere 做成分,充当spread的宾语,为定语从句 ​ b 中that在从句tom was a thief中不做任何成分。 从句作用 ​ 定语从句相当于形容词,他对先行词起到修饰,描述和限制的作用。 ​ 同位语从句相当于一个名词,他是前面名词的内容的具体表述。两者是同位的关系。 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E5%AE%9A%E8%AF%AD%E4%BB%8E%E5%8F%A5.html"},{"title":"英语语法-被动语态","text":"构成:be + 过去分词不同时态的被动语态be变化is, is being, has been, was, was being, had been, will be, will have been 不用by情况 实施者明显 ​ a. The rubbish hasn’t been collected. ​ b. Your hand will be X-rayed. ​ c. The streets are swept every day. 实施者未知或没必要提及 ​ a. The President has been murdered. ​ b. My car has been moved. ​ c. Rice is grown in many countries. ​ d. The library was built in 1890. 泛指人们 ​ acknowledge, assume, believe, claim, consider, estimate, feel, find, know, presume, report, ​ say, think ​ People believe him to be honest. ​ He is believed to be honest. 主句主语是one, you, they 通常用被动语态 ​ One/ You see this kind of advertisement everywhere. ​ This kind of advertisement is seen everywhere. ​ They are building a new public library in our town. ​ A new public library is being built in our town. 避免改换主语(可以接by短语) ​ When he arrived home, a detective arrested him. ​ When he arrived home, he was arrested. 不及物动词没有被动语态 He came here last night. He looks fine. 双宾语可以有两种被动语态(人做主语更常见) Someone gave me a gift. I was given a gift. Someone gave a gift to me. A gift was given to me. 静态被动语态 句子 解释 Now the door is locked 这里的is locked 只是强调动作,起着形容词的作用。 I locked the door two minutes ago. The door was locked by me two minutes ago. 这里的was locked强调动作 Clint broke the window last night The window was broken last night Now the window is broken. 常见interested, excited, satisfied, married, disappointed, scared, frightened, worried, lost ​ a. I am interested in grammar. ​ b. I am satisfied with Clint’s grammar course. ​ c. She is married to her teacher. ​ d. The table is made of wood. ​ e. Are you scared of snake? get与被动语态(get与过去分词连用) 可以构成被动语态 ​ a. My watch got broken while I was playing with the children. ​ b. He got caught by the police because he exceeded the speed limit. 可以接静态的被动形式,表示主语的状态 ​ a. I stopped working because I got tired. ​ b. I got worried because he was two hours late. ​ c. She is getting dressed to the party and has trouble deciding what clothes to wear. have/get sth done have sth done或者get sth done 安排别人把事情做好(主要用法) ​ a. Are you going to repair the car yourself? ​ b. No, I’m going to have it repaired. ​ c. I want to have/get my iterms repaired. (My iterms need repairing.) ​ d. I must get my hair cut = I want someone to cut my hair. ​ e. You should get/have your bike repaired. ​ g. If you don’t get our of my house, I’ll have you arrested. 意外或不行的事情 ​ a. I got my car stolen last year. ​ b. Have you ever had your passport stolen? ​ c. Joe had his leg broken in a fight. ​ d. It took me two hours to get the washing done. ​ e. Don’t get your plans changed. 英语学习-语法系列github仓库,欢迎收藏star 参考文章:参考链接","link":"/english-learn/%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95-%E8%A2%AB%E5%8A%A8%E8%AF%AD%E6%80%81.html"},{"title":"spring-boot实现动态增删启停定时任务","text":"在spring boot项目中,可以通过@EnableScheduling注解和@Scheduled注解实现定时任务,也可以通过SchedulingConfigurer接口来实现定时任务。但是这两种方式不能动态添加、删除、启动、停止任务。要实现动态增删启停定时任务功能,比较广泛的做法是集成Quartz框架。但是本人的开发原则是:在满足项目需求的情况下,尽量少的依赖其它框架,避免项目过于臃肿和复杂。查看spring-context这个jar包中org.springframework.scheduling.ScheduledTaskRegistrar这个类的源代码,发现可以通过改造这个类就能实现动态增删启停定时任务功能。 添加执行定时任务的线程池配置类 123456789101112@Configurationpublic class SchedulingConfig { @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); // 定时任务执行线程池核心线程数 taskScheduler.setPoolSize(4); taskScheduler.setRemoveOnCancelPolicy(true); taskScheduler.setThreadNamePrefix(\"TaskSchedulerThreadPool-\"); return taskScheduler; }} 添加ScheduledFuture的包装类。ScheduledFuture是ScheduledExecutorService定时任务线程池的执行结果。 1234567891011121314public final class ScheduledTask { volatile ScheduledFuture<?> future; /** * 取消定时任务 */ public void cancel() { ScheduledFuture<?> future = this.future; if (future != null) { future.cancel(true); } }} 添加Runnable接口实现类,被定时任务线程池调用,用来执行指定bean里面的方法。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374public class SchedulingRunnable implements Runnable { private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class); private String beanName; private String methodName; private String params; public SchedulingRunnable(String beanName, String methodName) { this(beanName, methodName, null); } public SchedulingRunnable(String beanName, String methodName, String params) { this.beanName = beanName; this.methodName = methodName; this.params = params; } @Override public void run() { logger.info(\"定时任务开始执行 - bean:{},方法:{},参数:{}\", beanName, methodName, params); long startTime = System.currentTimeMillis(); try { Object target = SpringContextUtils.getBean(beanName); Method method = null; if (StringUtils.isNotEmpty(params)) { method = target.getClass().getDeclaredMethod(methodName, String.class); } else { method = target.getClass().getDeclaredMethod(methodName); } ReflectionUtils.makeAccessible(method); if (StringUtils.isNotEmpty(params)) { method.invoke(target, params); } else { method.invoke(target); } } catch (Exception ex) { logger.error(String.format(\"定时任务执行异常 - bean:%s,方法:%s,参数:%s \", beanName, methodName, params), ex); } long times = System.currentTimeMillis() - startTime; logger.info(\"定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒\", beanName, methodName, params, times); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SchedulingRunnable that = (SchedulingRunnable) o; if (params == null) { return beanName.equals(that.beanName) && methodName.equals(that.methodName) && that.params == null; } return beanName.equals(that.beanName) && methodName.equals(that.methodName) && params.equals(that.params); } @Override public int hashCode() { if (params == null) { return Objects.hash(beanName, methodName); } return Objects.hash(beanName, methodName, params); }} 添加定时任务注册类,用来增加、删除定时任务。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950@Componentpublic class CronTaskRegistrar implements DisposableBean { private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16); @Autowired private TaskScheduler taskScheduler; public TaskScheduler getScheduler() { return this.taskScheduler; } public void addCronTask(Runnable task, String cronExpression) { addCronTask(new CronTask(task, cronExpression)); } public void addCronTask(CronTask cronTask) { if (cronTask != null) { Runnable task = cronTask.getRunnable(); if (this.scheduledTasks.containsKey(task)) { removeCronTask(task); } this.scheduledTasks.put(task, scheduleCronTask(cronTask)); } } public void removeCronTask(Runnable task) { ScheduledTask scheduledTask = this.scheduledTasks.remove(task); if (scheduledTask != null) scheduledTask.cancel(); } public ScheduledTask scheduleCronTask(CronTask cronTask) { ScheduledTask scheduledTask = new ScheduledTask(); scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger()); return scheduledTask; } @Override public void destroy() { for (ScheduledTask task : this.scheduledTasks.values()) { task.cancel(); } this.scheduledTasks.clear(); }} 添加定时任务示例类 12345678910@Component(\"demoTask\")public class DemoTask { public void taskWithParams(String params) { System.out.println(\"执行有参示例任务:\" + params); } public void taskNoParams() { System.out.println(\"执行无参示例任务\"); }} 定时任务数据库表设计 添加定时任务实体类 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111public class SysJobPO { /** * 任务ID */ private Integer jobId; /** * bean名称 */ private String beanName; /** * 方法名称 */ private String methodName; /** * 方法参数 */ private String methodParams; /** * cron表达式 */ private String cronExpression; /** * 状态(1正常 0暂停) */ private Integer jobStatus; /** * 备注 */ private String remark; /** * 创建时间 */ private Date createTime; /** * 更新时间 */ private Date updateTime; public Integer getJobId() { return jobId; } public void setJobId(Integer jobId) { this.jobId = jobId; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public String getMethodParams() { return methodParams; } public void setMethodParams(String methodParams) { this.methodParams = methodParams; } public String getCronExpression() { return cronExpression; } public void setCronExpression(String cronExpression) { this.cronExpression = cronExpression; } public Integer getJobStatus() { return jobStatus; } public void setJobStatus(Integer jobStatus) { this.jobStatus = jobStatus; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }} 新增定时任务 1234567891011boolean success = sysJobRepository.addSysJob(sysJob);if (!success) return OperationResUtils.fail(\"新增失败\");else { if (sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) { SchedulingRunnable task = new SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(), sysJob.getMethodParams()); cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression()); }}return OperationResUtils.success(); 修改定时任务,先移除原来的任务,再启动新任务 1234567891011121314151617boolean success = sysJobRepository.editSysJob(sysJob);if (!success) return OperationResUtils.fail(\"编辑失败\");else { //先移除再添加 if (existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) { SchedulingRunnable task = new SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams()); cronTaskRegistrar.removeCronTask(task); } if (sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) { SchedulingRunnable task = new SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(), sysJob.getMethodParams()); cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression()); }}return OperationResUtils.success(); 删除定时任务 1234567891011boolean success = sysJobRepository.deleteSysJobById(req.getJobId());if (!success) return OperationResUtils.fail(\"删除失败\");else{ if (existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) { SchedulingRunnable task = new SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams()); cronTaskRegistrar.removeCronTask(task); }}return OperationResUtils.success(); 定时任务启动/停止状态切换 1234567if (existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) { SchedulingRunnable task = new SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams()); cronTaskRegistrar.addCronTask(task, existedSysJob.getCronExpression());} else { SchedulingRunnable task = new SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams()); cronTaskRegistrar.removeCronTask(task);} 添加实现了CommandLineRunner接口的SysJobRunner类,当spring boot项目启动完成后,加载数据库里状态为正常的定时任务。 12345678910111213141516171819202122232425@Servicepublic class SysJobRunner implements CommandLineRunner { private static final Logger logger = LoggerFactory.getLogger(SysJobRunner.class); @Autowired private ISysJobRepository sysJobRepository; @Autowired private CronTaskRegistrar cronTaskRegistrar; @Override public void run(String... args) { // 初始加载数据库里状态为正常的定时任务 List<SysJobPO> jobList = sysJobRepository.getSysJobListByStatus(SysJobStatus.NORMAL.ordinal()); if (CollectionUtils.isNotEmpty(jobList)) { for (SysJobPO job : jobList) { SchedulingRunnable task = new SchedulingRunnable(job.getBeanName(), job.getMethodName(), job.getMethodParams()); cronTaskRegistrar.addCronTask(task, job.getCronExpression()); } logger.info(\"定时任务已加载完毕...\"); } }} 工具类SpringContextUtils,用来从spring容器里获取bean 1234567891011121314151617181920212223242526272829303132333435@Componentpublic class SpringContextUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtils.applicationContext = applicationContext; } public static Object getBean(String name) { return applicationContext.getBean(name); } public static <T> T getBean(Class<T> requiredType) { return applicationContext.getBean(requiredType); } public static <T> T getBean(String name, Class<T> requiredType) { return applicationContext.getBean(name, requiredType); } public static boolean containsBean(String name) { return applicationContext.containsBean(name); } public static boolean isSingleton(String name) { return applicationContext.isSingleton(name); } public static Class<? extends Object> getType(String name) { return applicationContext.getType(name); }} 参考文章:参考链接","link":"/java/frame/spring-boot%E5%AE%9E%E7%8E%B0%E5%8A%A8%E6%80%81%E5%A2%9E%E5%88%A0%E5%90%AF%E5%81%9C%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1.html"},{"title":"SpringBoot@Valid注解以及全局异常处理器优雅处理参数验证","text":"一、为什么使用 @Valid 来验证参数在平常通过 Spring 框架写代码时候,会经常写接口类,相信大家对该类的写法非常熟悉。在写接口时经常要写效验请求参数逻辑,这时候我们会常用做法是写大量的 if 与 if else 类似这样的代码来做判断,如下: 123456789101112131415161718@RestControllerpublic class TestController { @PostMapping(\"/user\") public String addUserInfo(@RequestBody User user) { if (user.getName() == null || \"\".equals(user.getName()) { ...... } else if(user.getSex() == null || \"\".equals(user.getSex())) { ...... } else if(user.getUsername() == null || \"\".equals(user.getUsername())) { ...... } else { ...... } ...... } } 这样的代码如果按正常代码逻辑来说,是没有什么问题的,不过按优雅来说,简直糟糕透了。不仅不优雅,而且如果存在大量的验证逻辑,这会使代码看起来乱糟糟,大大降低代码可读性,那么有没有更好的方法能够简化这个过程呢?答案当然是有,推荐的是使用 @Valid 注解来帮助我们简化验证逻辑。 二、@Valid 注解的作用注解 @Valid 的主要作用是用于数据效验,可以在定义的实体中的属性上,添加不同的注解来完成不同的校验规则,而在接口类中的接收数据参数中添加 @valid 注解,这时你的实体将会开启一个校验的功能。 三、@Valid 的相关注解下面是 @Valid 相关的注解,在实体类中不同的属性上添加不同的注解,就能实现不同数据的效验功能。 注解名称 作用描述 @Null 限制只能为null @NotNull 限制必须不为null @AssertFalse 限制必须为false @AssertTrue 限制必须为true @DecimalMax(value) 限制必须为一个不大于指定值的数字 @DecimalMin(value) 限制必须为一个不小于指定值的数字 @Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction @Future 限制必须是一个将来的日期 @Max(value) 限制必须为一个不大于指定值的数字 @Min(value) 限制必须为一个不小于指定值的数字 @Past 限制必须是一个过去的日期 @Pattern(value) 限制必须符合指定的正则表达式 @Size(max,min) 限制字符长度必须在min到max之间 @Past 验证注解的元素值(日期类型)比当前时间早 @NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) @NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 @Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式 四、使用 @Valid 进行参数效验步骤整个过程如下图所示,用户访问接口,然后进行参数效验,因为 @Valid 不支持平面的参数效验(直接写在参数中字段的效验)所以基于 GET 请求的参数还是按照原先方式进行效验,而 POST 则可以以实体对象为参数,可以使用 @Valid 方式进行效验。如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理。 1、实体类中添加 @Valid 相关注解使用 @Valid 相关注解非常简单,只需要在参数的实体类中属性上面添加如 @NotBlank、@Max、@Min 等注解来对该字段进限制,如下: User: 123456public class User { @NotBlank(message = \"姓名不为空\") private String username; @NotBlank(message = \"密码不为空\") private String password;} 如果是嵌套的实体对象,则需要在最外层属性上添加 @Valid 注解: User: 12345678910public class User { @NotBlank(message = \"姓名不为空\") private String username; @NotBlank(message = \"密码不为空\") private String password; //嵌套必须加 @Valid,否则嵌套中的验证不生效 @Valid @NotNull(message = \"用户信息不能为空\") private UserInfo userInfo;} UserInfo: 1234567public class User { @NotBlank(message = \"年龄不为空\") @Max(value = 18, message = \"不能超过18岁\") private String age; @NotBlank(message = \"性别不能为空\") private String gender;} 2、接口类中添加 @Valid 注解在 Controller 类中添加接口,POST 方法中接收设置了 @Valid 相关注解的实体对象,然后在参数中添加 @Valid 注解来开启效验功能,需要注意的是, @Valid 对 Get 请求中接收的平面参数请求无效,稍微略显遗憾。 123456789@RestControllerpublic class TestController { @PostMapping(\"/user\") public String addUserInfo(@Valid @RequestBody User user) { return \"调用成功!\"; }} 3、全局异常处理类中处理 @Valid 抛出的异常最后,我们写一个全局异常处理类,然后对接口中抛出的异常进行处理,而 @Valid 配合 Spring 会抛出 MethodArgumentNotValidException 异常,这里我们需要对该异常进行处理即可。 1234567891011121314151617181920@RestControllerAdvice(\"club.mydlq.valid\") //指定异常处理的包名public class GlobalExceptionHandler { @ResponseStatus(HttpStatus.BAD_REQUEST) //设置状态码为 400 @ExceptionHandler({MethodArgumentNotValidException.class}) public String paramExceptionHandler(MethodArgumentNotValidException e) { BindingResult exceptions = e.getBindingResult(); // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息 if (exceptions.hasErrors()) { List<ObjectError> errors = exceptions.getAllErrors(); if (!errors.isEmpty()) { // 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可 FieldError fieldError = (FieldError) errors.get(0); return fieldError.getDefaultMessage(); } } return \"请求参数错误\"; } } 五、SpringBoot 中使用 @Valid 示例1、Maven 引入相关依赖Maven 引入 SpringBoot 相关依赖,这里引入了 Lombok 包来简化开发过程。 123456789101112131415161718192021222324252627282930313233343536373839404142<?xml version=\"1.0\" encoding=\"UTF-8\"?><project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> </parent> <groupId>com.aspire</groupId> <artifactId>springboot-valid-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot-valid-demo</name> <description>@valid demo</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project> 2、自定义个异常类自定义个异常类,方便我们处理 GET 请求(GET 请求参数中一般是没有实体对象的,所以不能使用 @Valid),当请求验证失败时,手动抛出自定义异常,交由全局异常处理。 12345678910public class ParamaErrorException extends RuntimeException { public ParamaErrorException() { } public ParamaErrorException(String message) { super(message); }} 3、自定义响应枚举类定义一个返回信息的枚举类,方便我们快速响应信息,不必每次都写返回消息和响应码。 12345678910111213141516171819202122public enum ResultEnum { SUCCESS(1000, \"请求成功\"), PARAMETER_ERROR(1001, \"请求参数有误!\"), UNKNOWN_ERROR(9999, \"未知的错误!\"); private Integer code; private String message; ResultEnum(Integer code, String message) { this.code = code; this.message = message; } public Integer getCode() { return code; } public String getMessage() { return message; }} 4、自定义响应对象类创建用于返回调用方的响应信息的实体类。 123456789101112131415161718192021import com.aspire.parameter.enums.ResultEnum;import lombok.Data;@Datapublic class ResponseResult { private Integer code; private String msg; public ResponseResult(){ } public ResponseResult(ResultEnum resultEnum){ this.code = resultEnum.getCode(); this.msg = resultEnum.getMessage(); } public ResponseResult(Integer code, String msg) { this.code = code; this.msg = msg; }} 5、自定义实体类中添加 @Valid 相关注解下面将创建用于 POST 方法接收参数的实体对象,里面添加 @Valid 相关验证注解,并在注解中添加出错时的响应消息。 User 12345678910111213141516171819import lombok.Data;import javax.validation.Valid;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;/** * user实体类 */@Datapublic class User { @NotBlank(message = \"姓名不为空\") private String username; @NotBlank(message = \"密码不为空\") private String password; // 嵌套必须加 @Valid,否则嵌套中的验证不生效 @Valid @NotNull(message = \"userinfo不能为空\") private UserInfo userInfo;} UserInfo 123456789101112import lombok.Data;import javax.validation.constraints.Max;import javax.validation.constraints.NotBlank;@Datapublic class UserInfo { @NotBlank(message = \"年龄不为空\") @Max(value = 18, message = \"不能超过18岁\") private String age; @NotBlank(message = \"性别不能为空\") private String gender;} 6、Controller 中添加 @Valid 注解接口类中添加 GET 和 POST 方法的两个接口用于测试,其中 POST 方法以上面创建的 Uer 实体对象接收参数,并使用 @Valid,而 GET 请求一般接收参数较少,所以使用正常判断逻辑进行参数效验。 123456789101112131415161718192021222324252627282930313233343536373839import club.mydlq.valid.entity.ResponseResult;import club.mydlq.valid.entity.User;import club.mydlq.valid.enums.ResultEnum;import club.mydlq.valid.exception.ParamaErrorException;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.*;import javax.validation.Valid;@RestControllerpublic class TestController { /** * 获取用户信息 * * @param username 姓名 * @return ResponseResult */ @Validated @GetMapping(\"/user/{username}\") public ResponseResult findUserInfo(@PathVariable String username) { if (username == null || \"\".equals(username)) { throw new ParamaErrorException(\"username 不能为空\"); } return new ResponseResult(ResultEnum.SUCCESS); } /** * 新增用户 * * @param user 用户信息 * @return ResponseResult */ @PostMapping(\"/user\") public ResponseResult addUserInfo(@Valid @RequestBody User user) { return new ResponseResult(ResultEnum.SUCCESS); }} 7、全局异常处理这里创建一个全局异常处理类,方便统一处理异常错误信息。里面添加了不同异常处理的方法,专门用于处理接口中抛出的异常信。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889import club.mydlq.valid.entity.ResponseResult;import club.mydlq.valid.enums.ResultEnum;import club.mydlq.valid.exception.ParamaErrorException;import lombok.extern.slf4j.Slf4j;import org.springframework.http.HttpStatus;import org.springframework.http.converter.HttpMessageNotReadableException;import org.springframework.util.StringUtils;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.validation.ObjectError;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.MissingServletRequestParameterException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseStatus;import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.List;@Slf4j@RestControllerAdvice(\"club.mydlq.valid\")public class GlobalExceptionHandler { /** * 忽略参数异常处理器 * * @param e 忽略参数异常 * @return ResponseResult */ @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MissingServletRequestParameterException.class) public ResponseResult parameterMissingExceptionHandler(MissingServletRequestParameterException e) { log.error(\"\", e); return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), \"请求参数 \" + e.getParameterName() + \" 不能为空\"); } /** * 缺少请求体异常处理器 * * @param e 缺少请求体异常 * @return ResponseResult */ @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) { log.error(\"\", e); return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), \"参数体不能为空\"); } /** * 参数效验异常处理器 * * @param e 参数验证异常 * @return ResponseInfo */ @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseResult parameterExceptionHandler(MethodArgumentNotValidException e) { log.error(\"\", e); // 获取异常信息 BindingResult exceptions = e.getBindingResult(); // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息 if (exceptions.hasErrors()) { List<ObjectError> errors = exceptions.getAllErrors(); if (!errors.isEmpty()) { // 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可 FieldError fieldError = (FieldError) errors.get(0); return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), fieldError.getDefaultMessage()); } } return new ResponseResult(ResultEnum.PARAMETER_ERROR); } /** * 自定义参数错误异常处理器 * * @param e 自定义参数 * @return ResponseInfo */ @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler({ParamaErrorException.class}) public ResponseResult paramExceptionHandler(ParamaErrorException e) { log.error(\"\", e); // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息 if (!StringUtils.isEmpty(e.getMessage())) { return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), e.getMessage()); } return new ResponseResult(ResultEnum.PARAMETER_ERROR); }} 8、启动类1234567891011import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }} 9、示例测试下面将针对上面示例中设置的两种接口进行测试,分别来验证参数效验功能。 || - 测试接口 /user/{username} 使用 GET 方法请求地址 http://localhost:8080/user?username=test 时,返回信息: 1234{ \"code\": 1000, \"msg\": \"请求成功\"} 当不输入参数,输入地址 http://localhost:8080/user 时,返回信息: 1234{ \"code\": 1001, \"msg\": \"请求参数 username 不能为空\"} 可以看到在执行 GET 请求,能够正常按我们全局异常处理器中的设置处理异常信息。 || - 测试接口 /user (1)、使用 POST 方法发起请求,首先进行不加 JSON 请求体来对 http://localhost:8080/user 地址进行请求,返回信息: 1234{ \"code\": 1001, \"msg\": \"参数体不能为空\"} (2)、输入部分参数进行测试。 请求内容: 1234{ \"username\":\"test\", \"password\":\"123\"} 返回信息: 1234{ \"code\": 1001, \"msg\": \"userinfo不能为空\"} (3)、输入完整参数,且设置 age > 18 时,进行测试。 12345678{ \"username\":\"111\", \"password\":\"sa\", \"userInfo\":{ \"age\":19, \"gender\":\"男\" }} 返回信息: 1234{ \"code\": 1001, \"msg\": \"不能超过18岁\"} 可以看到在执行 POST 请求,也能正常按我们全局异常处理器中的设置处理异常信息,且提示信息为我们设置在实体类中的 Message。 参考文章:参考链接1","link":"/java/frame/SpringBoot-Valid%E6%B3%A8%E8%A7%A3%E4%BB%A5%E5%8F%8A%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%99%A8%E4%BC%98%E9%9B%85%E5%A4%84%E7%90%86%E5%8F%82%E6%95%B0%E9%AA%8C%E8%AF%81.html"},{"title":"算法成长之路leetcode21-22","text":"21. Merge Two Sorted ListsMerge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. Example:12Input: 1->2->4, 1->3->4Output: 1->1->2->3->4->4 JAVA题解:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108package algorithm.c3;/** * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  * * 示例: * * 输入:1->2->4, 1->3->4 * 输出:1->1->2->3->4->4 * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode21 { // 错解 public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode l = new ListNode(0); ListNode cur = l; while (l1.next != null || l2.next != null){ if (l1.next == null) { cur.next = l2; } else if (l2.next == null) { cur.next = l1; }else { if(l1.val > l2.val){ cur.next= l2; l2 = l2.next; }else if(l1.val == l2.val){ cur.next= l2; cur.next.next = l1; l1 = l1.next; l2 = l2.next; }else{ cur.next = l1; l1 = l1.next; } } cur = cur.next; } return l.next; } public ListNode mergeTwoLists1(ListNode l1, ListNode l2) { // maintain an unchanging reference to node ahead of the return node. ListNode prehead = new ListNode(-1); ListNode prev = prehead; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { prev.next = l1; l1 = l1.next; } else { prev.next = l2; l2 = l2.next; } prev = prev.next; } // exactly one of l1 and l2 can be non-null at this point, so connect // the non-null list to the end of the merged list. prev.next = l1 == null ? l2 : l1; return prehead.next; } // 递归 public ListNode mergeTwoLists2(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } else if (l2 == null) { return l1; } else if (l1.val < l2.val) { l1.next = mergeTwoLists(l1.next, l2); return l1; } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } } public static void main(String[] args) { ListNode l1 = new ListNode(1); l1.next = new ListNode(2); l1.next.next = new ListNode(4); ListNode l2 = new ListNode(1); l2.next = new ListNode(1); l2.next.next = new ListNode(3); System.out.println(new Leetcode21().mergeTwoLists1(l1,l2)); } public static class ListNode { int val; ListNode next; ListNode(int x) { val = x; } }} 22. Generate ParenthesesGiven n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. Example:123456789For example, given n = 3, a solution set is:[ \"((()))\", \"(()())\", \"(())()\", \"()(())\", \"()()()\"] JAVA题解:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596package algorithm.c3;import java.util.LinkedList;import java.util.List;/** * 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 * * 例如,给出 n = 3,生成结果为: * * [ * \"((()))\", * \"(()())\", * \"(())()\", * \"()(())\", * \"()()()\" * ] * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/generate-parentheses * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode22 { /** * * 在此题中,动态规划的思想类似于数学归纳法,当知道所有 i<n 的情况时,我们可以通过某种算法算出 i=n 的情况。 * 本题最核心的思想是,考虑 i=n 时相比 n-1 组括号增加的那一组括号的位置。 * * 思路: * 当我们清楚所有 i<n 时括号的可能生成排列后,对与 i=n 的情况,我们考虑整个括号排列中最左边的括号。 * 它一定是一个左括号,那么它可以和它对应的右括号组成一组完整的括号 \"( )\",我们认为这一组是相比 n-1 增加进来的括号。 * * 那么,剩下 n-1 组括号有可能在哪呢? * * 【这里是重点,请着重理解】 * * 剩下的括号要么在这一组新增的括号内部,要么在这一组新增括号的外部(右侧)。 * * 既然知道了 i<n 的情况,那我们就可以对所有情况进行遍历: * * \"(\" + 【i=p时所有括号的排列组合】 + \")\" + 【i=q时所有括号的排列组合】 * * 其中 p + q = n-1,且 p q 均为非负整数。 * * 事实上,当上述 p 从 0 取到 n-1,q 从 n-1 取到 0 后,所有情况就遍历完了。 * * 注:上述遍历是没有重复情况出现的,即当 (p1,q1)≠(p2,q2) 时,按上述方式取的括号组合一定不同。 * * 作者:yuyu-13 * 链接:https://leetcode-cn.com/problems/generate-parentheses/solution/zui-jian-dan-yi-dong-de-dong-tai-gui-hua-bu-lun-da/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * * 简单来说,在求N个括号的排列组合时,把第N种情况(也就是N个括号排列组合)视为单独拿一个括号E出来, * 剩下的N-1个括号分为两部分,P个括号和Q个括号,P+Q=N-1,然后这两部分分别处于括号E内和括号E的右边, * 各自进行括号的排列组合。由于我们是一步步计算得到N个括号的情况的,所以小于等于N-1个括号的排列组合方式我们是已知的( * 用合适的数据结构存储,方便后续调用,且在存储时可利用特定数据结构实现题目某些要求,如排序,去重等), * 且P+Q=N-1,P和Q是小于等于N-1的,所以我们能直接得到P个和Q个括号的情况,进而得到N个括号的结果! * * 楼主的算法思想很巧妙,赞一个~这个算法主要的基点就是将排列组合的情况分为了括号内和括号外这两种情况, * 且仅存在两种情况!至于为什么,原因在于楼主的算法的前提是单独拿出来的括号E的左边在N个括号所有排列组合情况中都是处于最左边, * 所以不存在括号位于括号E的左边的情况。因此,N-1个括号(拿出了括号E)仅可能分布于括号E内和括号E外,分为两种子情况讨论! * 这种思想还可以应用于其他类似的题的求解中,即怎样合理高效的利用前面步骤的计算结果得出当前步骤结果,从而得出最终结果。 * * @param n * @return */ public List<String> generateParenthesis(int n) { LinkedList<LinkedList<String>> result = new LinkedList<LinkedList<String>>(); if (n == 0) return result.get(0); LinkedList<String> list0 = new LinkedList<String>(); list0.add(\"\"); result.add(list0); LinkedList<String> list1 = new LinkedList<String>(); list1.add(\"()\"); result.add(list1); for (int i = 2; i <= n; i++) { LinkedList<String> temp = new LinkedList<String>(); for (int j = 0; j < i; j++) { List<String> str1 = result.get(j); List<String> str2 = result.get(i - 1 - j); for (String s1 : str1) { for (String s2 : str2) { String el = \"(\" + s1 + \")\" + s2; temp.add(el); } } } result.add(temp); } return result.get(n); }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode21-22.html"},{"title":"中国共产党章程(2017修改)","text":"基本信息 效力级别 党内法规 时效性 现行有效 发布日期 2017-10-24 实施日期 2017-10-24 发布机关 中共中央 正文 第一章 党员第一条 年满十八岁的中国工人、农民、军人、知识分子和其他社会阶层的先进分子,承认党的纲领和章程,愿意参加党的一个组织并在其中积极工作、执行党的决议和按期交纳党费的,可以申请加入中国共产党。 第二条 中国共产党党员是中国工人阶级的有共产主义觉悟的先锋战士。 中国共产党党员必须全心全意为人民服务,不惜牺牲个人的一切,为实现共产主义奋斗终身。 中国共产党党员永远是劳动人民的普通一员。除了法律和政策规定范围内的个人利益和工作职权以外,所有共产党员都不得谋求任何私利和特权。 第三条 党员必须履行下列义务: (一)认真学习马克思列宁主义、毛泽东思想、邓小平理论、“三个代表”重要思想、科学发展观、习近平新时代中国特色社会主义思想,学习党的路线、方针、政策和决议,学习党的基本知识,学习科学、文化、法律和业务知识,努力提高为人民服务的本领。 (二)贯彻执行党的基本路线和各项方针、政策,带头参加改革开放和社会主义现代化建设,带动群众为经济发展和社会进步艰苦奋斗,在生产、工作、学习和社会生活中起先锋模范作用。 (三)坚持党和人民的利益高于一切,个人利益服从党和人民的利益,吃苦在前,享受在后,克己奉公,多做贡献。 (四)自觉遵守党的纪律,首先是党的政治纪律和政治规矩,模范遵守国家的法律法规,严格保守党和国家的秘密,执行党的决定,服从组织分配,积极完成党的任务。 (五)维护党的团结和统一,对党忠诚老实,言行一致,坚决反对一切派别组织和小集团活动,反对阳奉阴违的两面派行为和一切阴谋诡计。 (六)切实开展批评和自我批评,勇于揭露和纠正违反党的原则的言行和工作中的缺点、错误,坚决同消极腐败现象作斗争。 (七)密切联系群众,向群众宣传党的主张,遇事同群众商量,及时向党反映群众的意见和要求,维护群众的正当利益。 (八)发扬社会主义新风尚,带头实践社会主义核心价值观和社会主义荣辱观,提倡共产主义道德,弘扬中华民族传统美德,为了保护国家和人民的利益,在一切困难和危险的时刻挺身而出,英勇斗争,不怕牺牲。 第四条 党员享有下列权利: (一)参加党的有关会议,阅读党的有关文件,接受党的教育和培训。 (二)在党的会议上和党报党刊上,参加关于党的政策问题的讨论。 (三)对党的工作提出建议和倡议。 (四)在党的会议上有根据地批评党的任何组织和任何党员,向党负责地揭发、检举党的任何组织和任何党员违法乱纪的事实,要求处分违法乱纪的党员,要求罢免或撤换不称职的干部。 (五)行使表决权、选举权,有被选举权。 (六)在党组织讨论决定对党员的党纪处分或作出鉴定时,本人有权参加和进行申辩,其他党员可以为他作证和辩护。 (七)对党的决议和政策如有不同意见,在坚决执行的前提下,可以声明保留,并且可以把自己的意见向党的上级组织直至中央提出。 (八)向党的上级组织直至中央提出请求、申诉和控告,并要求有关组织给以负责的答复。 党的任何一级组织直至中央都无权剥夺党员的上述权利。 第五条 发展党员,必须把政治标准放在首位,经过党的支部,坚持个别吸收的原则。 申请入党的人,要填写入党志愿书,要有两名正式党员作介绍人,要经过支部大会通过和上级党组织批准,并且经过预备期的考察,才能成为正式党员。 介绍人要认真了解申请人的思想、品质、经历和工作表现,向他解释党的纲领和党的章程,说明党员的条件、义务和权利,并向党组织作出负责的报告。 党的支部委员会对申请入党的人,要注意征求党内外有关群众的意见,进行严格的审查,认为合格后再提交支部大会讨论。 上级党组织在批准申请人入党以前,要派人同他谈话,作进一步的了解,并帮助他提高对党的认识。 在特殊情况下,党的中央和省、自治区、直辖市委员会可以直接接收党员。 第六条 预备党员必须面向党旗进行入党宣誓。誓词如下:我志愿加入中国共产党,拥护党的纲领,遵守党的章程,履行党员义务,执行党的决定,严守党的纪律,保守党的秘密,对党忠诚,积极工作,为共产主义奋斗终身,随时准备为党和人民牺牲一切,永不叛党。 第七条 预备党员的预备期为一年。党组织对预备党员应当认真教育和考察。 预备党员的义务同正式党员一样。预备党员的权利,除了没有表决权、选举权和被选举权以外,也同正式党员一样。 预备党员预备期满,党的支部应当及时讨论他能否转为正式党员。认真履行党员义务,具备党员条件的,应当按期转为正式党员;需要继续考察和教育的,可以延长预备期,但不能超过一年;不履行党员义务,不具备党员条件的,应当取消预备党员资格。预备党员转为正式党员,或延长预备期,或取消预备党员资格,都应当经支部大会讨论通过和上级党组织批准。 预备党员的预备期,从支部大会通过他为预备党员之日算起。党员的党龄,从预备期满转为正式党员之日算起。 第八条 每个党员,不论职务高低,都必须编入党的一个支部、小组或其他特定组织,参加党的组织生活,接受党内外群众的监督。党员领导干部还必须参加党委、党组的民主生活会。不允许有任何不参加党的组织生活、不接受党内外群众监督的特殊党员。 第九条 党员有退党的自由。党员要求退党,应当经支部大会讨论后宣布除名,并报上级党组织备案。 党员缺乏革命意志,不履行党员义务,不符合党员条件,党的支部应当对他进行教育,要求他限期改正;经教育仍无转变的,应当劝他退党。劝党员退党,应当经支部大会讨论决定,并报上级党组织批准。如被劝告退党的党员坚持不退,应当提交支部大会讨论,决定把他除名,并报上级党组织批准。 党员如果没有正当理由,连续六个月不参加党的组织生活,或不交纳党费,或不做党所分配的工作,就被认为是自行脱党。支部大会应当决定把这样的党员除名,并报上级党组织批准。 第二章 党的组织制度第十条 党是根据自己的纲领和章程,按照民主集中制组织起来的统一整体。党的民主集中制的基本原则是: (一)党员个人服从党的组织,少数服从多数,下级组织服从上级组织,全党各个组织和全体党员服从党的全国代表大会和中央委员会。 (二)党的各级领导机关,除它们派出的代表机关和在非党组织中的党组外,都由选举产生。 (三)党的最高领导机关,是党的全国代表大会和它所产生的中央委员会。党的地方各级领导机关,是党的地方各级代表大会和它们所产生的委员会。党的各级委员会向同级的代表大会负责并报告工作。 (四)党的上级组织要经常听取下级组织和党员群众的意见,及时解决他们提出的问题。党的下级组织既要向上级组织请示和报告工作,又要独立负责地解决自己职责范围内的问题。上下级组织之间要互通情报、互相支持和互相监督。党的各级组织要按规定实行党务公开,使党员对党内事务有更多的了解和参与。 (五)党的各级委员会实行集体领导和个人分工负责相结合的制度。凡属重大问题都要按照集体领导、民主集中、个别酝酿、会议决定的原则,由党的委员会集体讨论,作出决定;委员会成员要根据集体的决定和分工,切实履行自己的职责。 (六)党禁止任何形式的个人崇拜。要保证党的领导人的活动处于党和人民的监督之下,同时维护一切代表党和人民利益的领导人的威信。 第十一条 党的各级代表大会的代表和委员会的产生,要体现选举人的意志。选举采用无记名投票的方式。候选人名单要由党组织和选举人充分酝酿讨论。可以直接采用候选人数多于应选人数的差额选举办法进行正式选举。也可以先采用差额选举办法进行预选,产生候选人名单,然后进行正式选举。选举人有了解候选人情况、要求改变候选人、不选任何一个候选人和另选他人的权利。任何组织和个人不得以任何方式强迫选举人选举或不选举某个人。 党的地方各级代表大会和基层代表大会的选举,如果发生违反党章的情况,上一级党的委员会在调查核实后,应作出选举无效和采取相应措施的决定,并报再上一级党的委员会审查批准,正式宣布执行。 党的各级代表大会代表实行任期制。 第十二条 党的中央和地方各级委员会在必要时召集代表会议,讨论和决定需要及时解决的重大问题。代表会议代表的名额和产生办法,由召集代表会议的委员会决定。 第十三条 凡是成立党的新组织,或是撤销党的原有组织,必须由上级党组织决定。 在党的地方各级代表大会和基层代表大会闭会期间,上级党的组织认为有必要时,可以调动或者指派下级党组织的负责人。 党的中央和地方各级委员会可以派出代表机关。 第十四条 党的中央和省、自治区、直辖市委员会实行巡视制度,在一届任期内,对所管理的地方、部门、企事业单位党组织实现巡视全覆盖。 中央有关部委和国家机关部门党组(党委)根据工作需要,开展巡视工作。 党的市(地、州、盟)和县(市、区、旗)委员会建立巡察制度。 第十五条 党的各级领导机关,对同下级组织有关的重要问题作出决定时,在通常情况下,要征求下级组织的意见。要保证下级组织能够正常行使他们的职权。凡属应由下级组织处理的问题,如无特殊情况,上级领导机关不要干预。 第十六条 有关全国性的重大政策问题,只有党中央有权作出决定,各部门、各地方的党组织可以向中央提出建议,但不得擅自作出决定和对外发表主张。 党的下级组织必须坚决执行上级组织的决定。下级组织如果认为上级组织的决定不符合本地区、本部门的实际情况,可以请求改变;如果上级组织坚持原决定,下级组织必须执行,并不得公开发表不同意见,但有权向再上一级组织报告。 党的各级组织的报刊和其他宣传工具,必须宣传党的路线、方针、政策和决议。 第十七条 党组织讨论决定问题,必须执行少数服从多数的原则。决定重要问题,要进行表决。对于少数人的不同意见,应当认真考虑。如对重要问题发生争论,双方人数接近,除了在紧急情况下必须按多数意见执行外,应当暂缓作出决定,进一步调查研究,交换意见,下次再表决;在特殊情况下,也可将争论情况向上级组织报告,请求裁决。 党员个人代表党组织发表重要主张,如果超出党组织已有决定的范围,必须提交所在的党组织讨论决定,或向上级党组织请示。任何党员不论职务高低,都不能个人决定重大问题;如遇紧急情况,必须由个人作出决定时,事后要迅速向党组织报告。不允许任何领导人实行个人专断和把个人凌驾于组织之上。 第十八条 党的中央、地方和基层组织,都必须重视党的建设,经常讨论和检查党的宣传工作、教育工作、组织工作、纪律检查工作、群众工作、统一战线工作等,注意研究党内外的思想政治状况。 第三章 党的中央组织第十九条 党的全国代表大会每五年举行一次,由中央委员会召集。中央委员会认为有必要,或者有三分之一以上的省一级组织提出要求,全国代表大会可以提前举行;如无非常情况,不得延期举行。 全国代表大会代表的名额和选举办法,由中央委员会决定。 第二十条 党的全国代表大会的职权是: (一)听取和审查中央委员会的报告; (二)审查中央纪律检查委员会的报告; (三)讨论并决定党的重大问题; (四)修改党的章程; (五)选举中央委员会; (六)选举中央纪律检查委员会。 第二十一条 党的全国代表会议的职权是:讨论和决定重大问题;调整和增选中央委员会、中央纪律检查委员会的部分成员。调整和增选中央委员及候补中央委员的数额,不得超过党的全国代表大会选出的中央委员及候补中央委员各自总数的五分之一。 第二十二条 党的中央委员会每届任期五年。全国代表大会如提前或延期举行,它的任期相应地改变。中央委员会委员和候补委员必须有五年以上的党龄。中央委员会委员和候补委员的名额,由全国代表大会决定。中央委员会委员出缺,由中央委员会候补委员按照得票多少依次递补。 中央委员会全体会议由中央政治局召集,每年至少举行一次。中央政治局向中央委员会全体会议报告工作,接受监督。 在全国代表大会闭会期间,中央委员会执行全国代表大会的决议,领导党的全部工作,对外代表中国共产党。 第二十三条 党的中央政治局、中央政治局常务委员会和中央委员会总书记,由中央委员会全体会议选举。中央委员会总书记必须从中央政治局常务委员会委员中产生。 中央政治局和它的常务委员会在中央委员会全体会议闭会期间,行使中央委员会的职权。 中央书记处是中央政治局和它的常务委员会的办事机构;成员由中央政治局常务委员会提名,中央委员会全体会议通过。 中央委员会总书记负责召集中央政治局会议和中央政治局常务委员会会议,并主持中央书记处的工作。 党的中央军事委员会组成人员由中央委员会决定,中央军事委员会实行主席负责制。 每届中央委员会产生的中央领导机构和中央领导人,在下届全国代表大会开会期间,继续主持党的经常工作,直到下届中央委员会产生新的中央领导机构和中央领导人为止。 第二十四条 中国人民解放军的党组织,根据中央委员会的指示进行工作。中央军事委员会负责军队中党的工作和政治工作,对军队中党的组织体制和机构作出规定。 第四章 党的地方组织第二十五条 党的省、自治区、直辖市的代表大会,设区的市和自治州的代表大会,县(旗)、自治县、不设区的市和市辖区的代表大会,每五年举行一次。 党的地方各级代表大会由同级党的委员会召集。在特殊情况下,经上一级委员会批准,可以提前或延期举行。 党的地方各级代表大会代表的名额和选举办法,由同级党的委员会决定,并报上一级党的委员会批准。 第二十六条 党的地方各级代表大会的职权是: (一)听取和审查同级委员会的报告; (二)审查同级纪律检查委员会的报告; (三)讨论本地区范围内的重大问题并作出决议; (四)选举同级党的委员会,选举同级党的纪律检查委员会。 第二十七条 党的省、自治区、直辖市、设区的市和自治州的委员会,每届任期五年。这些委员会的委员和候补委员必须有五年以上的党龄。 党的县(旗)、自治县、不设区的市和市辖区的委员会,每届任期五年。这些委员会的委员和候补委员必须有三年以上的党龄。 党的地方各级代表大会如提前或延期举行,由它选举的委员会的任期相应地改变。 党的地方各级委员会的委员和候补委员的名额,分别由上一级委员会决定。党的地方各级委员会委员出缺,由候补委员按照得票多少依次递补。 党的地方各级委员会全体会议,每年至少召开两次。 党的地方各级委员会在代表大会闭会期间,执行上级党组织的指示和同级党代表大会的决议,领导本地方的工作,定期向上级党的委员会报告工作。 第二十八条 党的地方各级委员会全体会议,选举常务委员会和书记、副书记,并报上级党的委员会批准。党的地方各级委员会的常务委员会,在委员会全体会议闭会期间,行使委员会职权;在下届代表大会开会期间,继续主持经常工作,直到新的常务委员会产生为止。 党的地方各级委员会的常务委员会定期向委员会全体会议报告工作,接受监督。 第二十九条 党的地区委员会和相当于地区委员会的组织,是党的省、自治区委员会在几个县、自治县、市范围内派出的代表机关。它根据省、自治区委员会的授权,领导本地区的工作。 第五章 党的基层组织第三十条 企业、农村、机关、学校、科研院所、街道社区、社会组织、人民解放军连队和其他基层单位,凡是有正式党员三人以上的,都应当成立党的基层组织。 党的基层组织,根据工作需要和党员人数,经上级党组织批准,分别设立党的基层委员会、总支部委员会、支部委员会。基层委员会由党员大会或代表大会选举产生,总支部委员会和支部委员会由党员大会选举产生,提出委员候选人要广泛征求党员和群众的意见。 第三十一条 党的基层委员会、总支部委员会、支部委员会每届任期三年至五年。基层委员会、总支部委员会、支部委员会的书记、副书记选举产生后,应报上级党组织批准。 第三十二条 党的基层组织是党在社会基层组织中的战斗堡垒,是党的全部工作和战斗力的基础。它的基本任务是: (一)宣传和执行党的路线、方针、政策,宣传和执行党中央、上级组织和本组织的决议,充分发挥党员的先锋模范作用,积极创先争优,团结、组织党内外的干部和群众,努力完成本单位所担负的任务。 (二)组织党员认真学习马克思列宁主义、毛泽东思想、邓小平理论、“三个代表”重要思想、科学发展观、习近平新时代中国特色社会主义思想,推进“两学一做”学习教育常态化制度化,学习党的路线、方针、政策和决议,学习党的基本知识,学习科学、文化、法律和业务知识。 (三)对党员进行教育、管理、监督和服务,提高党员素质,坚定理想信念,增强党性,严格党的组织生活,开展批评和自我批评,维护和执行党的纪律,监督党员切实履行义务,保障党员的权利不受侵犯。加强和改进流动党员管理。 (四)密切联系群众,经常了解群众对党员、党的工作的批评和意见,维护群众的正当权利和利益,做好群众的思想政治工作。 (五)充分发挥党员和群众的积极性创造性,发现、培养和推荐他们中间的优秀人才,鼓励和支持他们在改革开放和社会主义现代化建设中贡献自己的聪明才智。 (六)对要求入党的积极分子进行教育和培养,做好经常性的发展党员工作,重视在生产、工作第一线和青年中发展党员。 (七)监督党员干部和其他任何工作人员严格遵守国家法律法规,严格遵守国家的财政经济法规和人事制度,不得侵占国家、集体和群众的利益。 (八)教育党员和群众自觉抵制不良倾向,坚决同各种违纪违法行为作斗争。 第三十三条 街道、乡、镇党的基层委员会和村、社区党组织,领导本地区的工作和基层社会治理,支持和保证行政组织、经济组织和群众自治组织充分行使职权。 国有企业党委(党组)发挥领导作用,把方向、管大局、保落实,依照规定讨论和决定企业重大事项。国有企业和集体企业中党的基层组织,围绕企业生产经营开展工作。保证监督党和国家的方针、政策在本企业的贯彻执行;支持股东会、董事会、监事会和经理(厂长)依法行使职权;全心全意依靠职工群众,支持职工代表大会开展工作;参与企业重大问题的决策;加强党组织的自身建设,领导思想政治工作、精神文明建设和工会、共青团等群团组织。 非公有制经济组织中党的基层组织,贯彻党的方针政策,引导和监督企业遵守国家的法律法规,领导工会、共青团等群团组织,团结凝聚职工群众,维护各方的合法权益,促进企业健康发展。 社会组织中党的基层组织,宣传和执行党的路线、方针、政策,领导工会、共青团等群团组织,教育管理党员,引领服务群众,推动事业发展。 实行行政领导人负责制的事业单位中党的基层组织,发挥战斗堡垒作用。实行党委领导下的行政领导人负责制的事业单位中党的基层组织,对重大问题进行讨论和作出决定,同时保证行政领导人充分行使自己的职权。 各级党和国家机关中党的基层组织,协助行政负责人完成任务,改进工作,对包括行政负责人在内的每个党员进行教育、管理、监督,不领导本单位的业务工作。 第三十四条 党支部是党的基础组织,担负直接教育党员、管理党员、监督党员和组织群众、宣传群众、凝聚群众、服务群众的职责。 第六章 党的干部第三十五条 党的干部是党的事业的骨干,是人民的公仆,要做到忠诚干净担当。党按照德才兼备、以德为先的原则选拔干部,坚持五湖四海、任人唯贤,坚持事业为上、公道正派,反对任人唯亲,努力实现干部队伍的革命化、年轻化、知识化、专业化。 党重视教育、培训、选拔、考核和监督干部,特别是培养、选拔优秀年轻干部。积极推进干部制度改革。 党重视培养、选拔女干部和少数民族干部。 第三十六条 党的各级领导干部必须信念坚定、为民服务、勤政务实、敢于担当、清正廉洁,模范地履行本章程第三条所规定的党员的各项义务,并且必须具备以下的基本条件: (一)具有履行职责所需要的马克思列宁主义、毛泽东思想、邓小平理论、“三个代表”重要思想、科学发展观的水平,带头贯彻落实习近平新时代中国特色社会主义思想,努力用马克思主义的立场、观点、方法分析和解决实际问题,坚持讲学习、讲政治、讲正气,经得起各种风浪的考验。 (二)具有共产主义远大理想和中国特色社会主义坚定信念,坚决执行党的基本路线和各项方针、政策,立志改革开放,献身现代化事业,在社会主义建设中艰苦创业,树立正确政绩观,做出经得起实践、人民、历史检验的实绩。 (三)坚持解放思想,实事求是,与时俱进,开拓创新,认真调查研究,能够把党的方针、政策同本地区、本部门的实际相结合,卓有成效地开展工作,讲实话,办实事,求实效。 (四)有强烈的革命事业心和政治责任感,有实践经验,有胜任领导工作的组织能力、文化水平和专业知识。 (五)正确行使人民赋予的权力,坚持原则,依法办事,清正廉洁,勤政为民,以身作则,艰苦朴素,密切联系群众,坚持党的群众路线,自觉地接受党和群众的批评和监督,加强道德修养,讲党性、重品行、作表率,做到自重、自省、自警、自励,反对形式主义、官僚主义、享乐主义和奢靡之风,反对任何滥用职权、谋求私利的行为。 (六)坚持和维护党的民主集中制,有民主作风,有全局观念,善于团结同志,包括团结同自己有不同意见的同志一道工作。 第三十七条 党员干部要善于同党外干部合作共事,尊重他们,虚心学习他们的长处。 党的各级组织要善于发现和推荐有真才实学的党外干部担任领导工作,保证他们有职有权,充分发挥他们的作用。 第三十八条 党的各级领导干部,无论是由民主选举产生的,或是由领导机关任命的,他们的职务都不是终身的,都可以变动或解除。 年龄和健康状况不适宜于继续担任工作的干部,应当按照国家的规定退、离休。 第七章 党的纪律第三十九条 党的纪律是党的各级组织和全体党员必须遵守的行为规则,是维护党的团结统一、完成党的任务的保证。党组织必须严格执行和维护党的纪律,共产党员必须自觉接受党的纪律的约束。 第四十条 党的纪律主要包括政治纪律、组织纪律、廉洁纪律、群众纪律、工作纪律、生活纪律。 坚持惩前毖后、治病救人,执纪必严、违纪必究,抓早抓小、防微杜渐,按照错误性质和情节轻重,给以批评教育直至纪律处分。运用监督执纪“四种形态”,让“红红脸、出出汗”成为常态,党纪处分、组织调整成为管党治党的重要手段,严重违纪、严重触犯刑律的党员必须开除党籍。 党内严格禁止用违反党章和国家法律的手段对待党员,严格禁止打击报复和诬告陷害。违反这些规定的组织或个人必须受到党的纪律和国家法律的追究。 第四十一条 对党员的纪律处分有五种:警告、严重警告、撤销党内职务、留党察看、开除党籍。 留党察看最长不超过两年。党员在留党察看期间没有表决权、选举权和被选举权。党员经过留党察看,确已改正错误的,应当恢复其党员的权利;坚持错误不改的,应当开除党籍。 开除党籍是党内的最高处分。各级党组织在决定或批准开除党员党籍的时候,应当全面研究有关的材料和意见,采取十分慎重的态度。 第四十二条 对党员的纪律处分,必须经过支部大会讨论决定,报党的基层委员会批准;如果涉及的问题比较重要或复杂,或给党员以开除党籍的处分,应分别不同情况,报县级或县级以上党的纪律检查委员会审查批准。在特殊情况下,县级和县级以上各级党的委员会和纪律检查委员会有权直接决定给党员以纪律处分。 对党的中央委员会委员、候补委员,给以警告、严重警告处分,由中央纪律检查委员会常务委员会审议后,报党中央批准。对地方各级党的委员会委员、候补委员,给以警告、严重警告处分,应由上一级纪律检查委员会批准,并报它的同级党的委员会备案。 对党的中央委员会和地方各级委员会的委员、候补委员,给以撤销党内职务、留党察看或开除党籍的处分,必须由本人所在的委员会全体会议三分之二以上的多数决定。在全体会议闭会期间,可以先由中央政治局和地方各级委员会常务委员会作出处理决定,待召开委员会全体会议时予以追认。对地方各级委员会委员和候补委员的上述处分,必须经过上级纪律检查委员会常务委员会审议,由这一级纪律检查委员会报同级党的委员会批准。 严重触犯刑律的中央委员会委员、候补委员,由中央政治局决定开除其党籍;严重触犯刑律的地方各级委员会委员、候补委员,由同级委员会常务委员会决定开除其党籍。 第四十三条 党组织对党员作出处分决定,应当实事求是地查清事实。处分决定所依据的事实材料和处分决定必须同本人见面,听取本人说明情况和申辩。如果本人对处分决定不服,可以提出申诉,有关党组织必须负责处理或者迅速转递,不得扣压。对于确属坚持错误意见和无理要求的人,要给以批评教育。 第四十四条 党组织如果在维护党的纪律方面失职,必须问责。 对于严重违犯党的纪律、本身又不能纠正的党组织,上一级党的委员会在查明核实后,应根据情节严重的程度,作出进行改组或予以解散的决定,并报再上一级党的委员会审查批准,正式宣布执行。 第八章 党的纪律检查机关第四十五条 党的中央纪律检查委员会在党的中央委员会领导下进行工作。党的地方各级纪律检查委员会和基层纪律检查委员会在同级党的委员会和上级纪律检查委员会双重领导下进行工作。上级党的纪律检查委员会加强对下级纪律检查委员会的领导。 党的各级纪律检查委员会每届任期和同级党的委员会相同。 党的中央纪律检查委员会全体会议,选举常务委员会和书记、副书记,并报党的中央委员会批准。党的地方各级纪律检查委员会全体会议,选举常务委员会和书记、副书记,并由同级党的委员会通过,报上级党的委员会批准。党的基层委员会是设立纪律检查委员会,还是设立纪律检查委员,由它的上一级党组织根据具体情况决定。党的总支部委员会和支部委员会设纪律检查委员。 党的中央和地方纪律检查委员会向同级党和国家机关全面派驻党的纪律检查组。纪律检查组组长参加驻在部门党的领导组织的有关会议。他们的工作必须受到该机关党的领导组织的支持。 第四十六条 党的各级纪律检查委员会是党内监督专责机关,主要任务是:维护党的章程和其他党内法规,检查党的路线、方针、政策和决议的执行情况,协助党的委员会推进全面从严治党、加强党风建设和组织协调反腐败工作。 党的各级纪律检查委员会的职责是监督、执纪、问责,要经常对党员进行遵守纪律的教育,作出关于维护党纪的决定;对党的组织和党员领导干部履行职责、行使权力进行监督,受理处置党员群众检举举报,开展谈话提醒、约谈函询;检查和处理党的组织和党员违反党的章程和其他党内法规的比较重要或复杂的案件,决定或取消对这些案件中的党员的处分;进行问责或提出责任追究的建议;受理党员的控告和申诉;保障党员的权利。 各级纪律检查委员会要把处理特别重要或复杂的案件中的问题和处理的结果,向同级党的委员会报告。党的地方各级纪律检查委员会和基层纪律检查委员会要同时向上级纪律检查委员会报告。 各级纪律检查委员会发现同级党的委员会委员有违犯党的纪律的行为,可以先进行初步核实,如果需要立案检查的,应当在向同级党的委员会报告的同时向上一级纪律检查委员会报告;涉及常务委员的,报告上一级纪律检查委员会,由上一级纪律检查委员会进行初步核实,需要审查的,由上一级纪律检查委员会报它的同级党的委员会批准。 第四十七条 上级纪律检查委员会有权检查下级纪律检查委员会的工作,并且有权批准和改变下级纪律检查委员会对于案件所作的决定。如果所要改变的该下级纪律检查委员会的决定,已经得到它的同级党的委员会的批准,这种改变必须经过它的上一级党的委员会批准。 党的地方各级纪律检查委员会和基层纪律检查委员会如果对同级党的委员会处理案件的决定有不同意见,可以请求上一级纪律检查委员会予以复查;如果发现同级党的委员会或它的成员有违犯党的纪律的情况,在同级党的委员会不给予解决或不给予正确解决的时候,有权向上级纪律检查委员会提出申诉,请求协助处理。 第九章 党组第四十八条 在中央和地方国家机关、人民团体、经济组织、文化组织和其他非党组织的领导机关中,可以成立党组。党组发挥领导核心作用。党组的任务,主要是负责贯彻执行党的路线、方针、政策;加强对本单位党的建设的领导,履行全面从严治党责任;讨论和决定本单位的重大问题;做好干部管理工作;讨论和决定基层党组织设置调整和发展党员、处分党员等重要事项;团结党外干部和群众,完成党和国家交给的任务;领导机关和直属单位党组织的工作。 第四十九条 党组的成员,由批准成立党组的党组织决定。党组设书记,必要时还可以设副书记。 党组必须服从批准它成立的党组织领导。 第五十条 对下属单位实行集中统一领导的国家工作部门可以建立党委,党委的产生办法、职权和工作任务,由中央另行规定。 第十章 党和共产主义青年团的关系第五十一条 中国共产主义青年团是中国共产党领导的先进青年的群团组织,是广大青年在实践中学习中国特色社会主义和共产主义的学校,是党的助手和后备军。共青团中央委员会受党中央委员会领导。共青团的地方各级组织受同级党的委员会领导,同时受共青团上级组织领导。 第五十二条 党的各级委员会要加强对共青团的领导,注意团的干部的选拔和培训。党要坚决支持共青团根据广大青年的特点和需要,生动活泼地、富于创造性地进行工作,充分发挥团的突击队作用和联系广大青年的桥梁作用。 团的县级和县级以下各级委员会书记,企业事业单位的团委员会书记,是党员的,可以列席同级党的委员会和常务委员会的会议。 第十一章 党徽党旗第五十三条 中国共产党党徽为镰刀和锤头组成的图案。 第五十四条 中国共产党党旗为旗面缀有金黄色党徽图案的红旗。 第五十五条 中国共产党的党徽党旗是中国共产党的象征和标志。党的各级组织和每一个党员都要维护党徽党旗的尊严。要按照规定制作和使用党徽党旗。","link":"/law/%E4%B8%AD%E5%9B%BD%E5%85%B1%E4%BA%A7%E5%85%9A%E7%AB%A0%E7%A8%8B-2017%E4%BF%AE%E6%94%B9.html"},{"title":"秒杀系统如何支撑百万QPS","text":"12306抢票,极限并发带来的思考?每到节假日期间,一二线城市返乡、外出游玩的人们几乎都面临着一个问题:抢火车票!虽然现在大多数情况下都能订到票,但是放票瞬间即无票的场景,相信大家都深有体会。尤其是春节期间,大家不仅使用12306,还会考虑“智行”和其他的抢票软件,全国上下几亿人在这段时间都在抢票。 “12306服务”承受着这个世界上任何秒杀系统都无法超越的QPS,上百万的并发再正常不过了!笔者专门研究了一下“12306”的服务端架构,学习到了其系统设计上很多亮点,在这里和大家分享一下并模拟一个例子:如何在100万人同时抢1万张火车票时,系统提供正常、稳定的服务。github代码地址 1. 大型高并发系统架构高并发的系统架构都会采用分布式集群部署,服务上层有着层层负载均衡,并提供各种容灾手段(双火机房、节点容错、服务器灾备等)保证系统的高可用,流量也会根据不同的负载能力和配置策略均衡到不同的服务器上。下边是一个简单的示意图: 1.1 负载均衡简介上图中描述了用户请求到服务器经历了三层的负载均衡,下边分别简单介绍一下这三种负载均衡: OSPF(开放式最短链路优先)是一个内部网关协议(Interior Gateway Protocol,简称IGP)。OSPF通过路由器之间通告网络接口的状态来建立链路状态数据库,生成最短路径树,OSPF会自动计算路由接口上的Cost值,但也可以通过手工指定该接口的Cost值,手工指定的优先于自动计算的值。OSPF计算的Cost,同样是和接口带宽成反比,带宽越高,Cost值越小。到达目标相同Cost值的路径,可以执行负载均衡,最多6条链路同时执行负载均衡。 LVS (Linux VirtualServer),它是一种集群(Cluster)技术,采用IP负载均衡技术和基于内容请求分发技术。调度器具有很好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故障,从而将一组服务器构成一个高性能的、高可用的虚拟服务器。 Nginx想必大家都很熟悉了,是一款非常高性能的http代理/反向代理服务器,服务开发中也经常使用它来做负载均衡。Nginx实现负载均衡的方式主要有三种:轮询、加权轮询、ip hash轮询,下面我们就针对Nginx的加权轮询做专门的配置和测试 1.2 Nginx加权轮询的演示Nginx实现负载均衡通过upstream模块实现,其中加权轮询的配置是可以给相关的服务加上一个权重值,配置的时候可能根据服务器的性能、负载能力设置相应的负载。下面是一个加权轮询负载的配置,我将在本地的监听3001-3004端口,分别配置1,2,3,4的权重: 123456789101112131415#配置负载均衡 upstream load_rule { server 127.0.0.1:3001 weight=1; server 127.0.0.1:3002 weight=2; server 127.0.0.1:3003 weight=3; server 127.0.0.1:3004 weight=4; } ... server { listen 80; server_name load_balance.com www.load_balance.com; location / { proxy_pass http://load_rule; }} 我在本地/etc/hosts目录下配置了 www.load_balance.com 的虚拟域名地址,接下来使用Go语言开启四个http端口监听服务,下面是监听在3001端口的Go程序,其他几个只需要修改端口即可: 123456789101112131415161718192021222324252627package mainimport ( \"net/http\" \"os\" \"strings\")func main() { http.HandleFunc(\"/buy/ticket\", handleReq) http.ListenAndServe(\":3001\", nil)}//处理请求函数,根据请求将响应结果信息写入日志func handleReq(w http.ResponseWriter, r *http.Request) { failedMsg := \"handle in port:\" writeLog(failedMsg, \"./stat.log\")}//写入日志func writeLog(msg string, logPath string) { fd, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) defer fd.Close() content := strings.Join([]string{msg, \"\\r\\n\"}, \"3001\") buf := []byte(content) fd.Write(buf)} 我将请求的端口日志信息写到了./stat.log文件当中,然后使用ab压测工具做压测: 1ab -n 1000 -c 100 http://www.load_balance.com/buy/ticket 统计日志中的结果,3001-3004端口分别得到了100、200、300、400的请求量,这和我在nginx中配置的权重占比很好的吻合在了一起,并且负载后的流量非常的均匀、随机。具体的实现大家可以参考nginx的upsteam模块实现源码,这里推荐一篇文章:Nginx 中 upstream 机制的负载均衡 2.秒杀抢购系统选型回到我们最初提到的问题中来:火车票秒杀系统如何在高并发情况下提供正常、稳定的服务呢? 从上面的介绍我们知道用户秒杀流量通过层层的负载均衡,均匀到了不同的服务器上,即使如此,集群中的单机所承受的QPS也是非常高的。如何将单机性能优化到极致呢?要解决这个问题,我们就要想明白一件事: 通常订票系统要处理生成订单、减扣库存、用户支付这三个基本的阶段,我们系统要做的事情是要保证火车票订单不超卖、不少卖,每张售卖的车票都必须支付才有效,还要保证系统承受极高的并发。这三个阶段的先后顺序改怎么分配才更加合理呢?我们来分析一下: 2.1 下单减库存当用户并发请求到达服务端时,首先创建订单,然后扣除库存,等待用户支付。这种顺序是我们一般人首先会想到的解决方案,这种情况下也能保证订单不会超卖,因为创建订单之后就会减库存,这是一个原子操作。但是这样也会产生一些问题,第一就是在极限并发情况下,任何一个内存操作的细节都至关影响性能,尤其像创建订单这种逻辑,一般都需要存储到磁盘数据库的,对数据库的压力是可想而知的;第二是如果用户存在恶意下单的情况,只下单不支付这样库存就会变少,会少卖很多订单,虽然服务端可以限制IP和用户的购买订单数量,这也不算是一个好方法。 2.2 支付减库存如果等待用户支付了订单在减库存,第一感觉就是不会少卖。但是这是并发架构的大忌,因为在极限并发情况下,用户可能会创建很多订单,当库存减为零的时候很多用户发现抢到的订单支付不了了,这也就是所谓的“超卖”。也不能避免并发操作数据库磁盘IO 2.3 预扣库存从上边两种方案的考虑,我们可以得出结论:只要创建订单,就要频繁操作数据库IO。那么有没有一种不需要直接操作数据库IO的方案呢,这就是预扣库存。先扣除了库存,保证不超卖,然后异步生成用户订单,这样响应给用户的速度就会快很多;那么怎么保证不少卖呢?用户拿到了订单,不支付怎么办?我们都知道现在订单都有有效期,比如说用户五分钟内不支付,订单就失效了,订单一旦失效,就会加入新的库存,这也是现在很多网上零售企业保证商品不少卖采用的方案。订单的生成是异步的,一般都会放到MQ、kafka这样的即时消费队列中处理,订单量比较少的情况下,生成订单非常快,用户几乎不用排队。 3. 扣库存的艺术从上面的分析可知,显然预扣库存的方案最合理。我们进一步分析扣库存的细节,这里还有很大的优化空间,库存存在哪里?怎样保证高并发下,正确的扣库存,还能快速的响应用户请求? 在单机低并发情况下,我们实现扣库存通常是这样的: 为了保证扣库存和生成订单的原子性,需要采用事务处理,然后取库存判断、减库存,最后提交事务,整个流程有很多IO,对数据库的操作又是阻塞的。这种方式根本不适合高并发的秒杀系统。 接下来我们对单机扣库存的方案做优化:本地扣库存。我们把一定的库存量分配到本地机器,直接在内存中减库存,然后按照之前的逻辑异步创建订单。改进过之后的单机系统是这样的: 这样就避免了对数据库频繁的IO操作,只在内存中做运算,极大的提高了单机抗并发的能力。但是百万的用户请求量单机是无论如何也抗不住的,虽然nginx处理网络请求使用epoll模型,c10k的问题在业界早已得到了解决。但是linux系统下,一切资源皆文件,网络请求也是这样,大量的文件描述符会使操作系统瞬间失去响应。上面我们提到了nginx的加权均衡策略,我们不妨假设将100W的用户请求量平均均衡到100台服务器上,这样单机所承受的并发量就小了很多。然后我们每台机器本地库存100张火车票,100台服务器上的总库存还是1万,这样保证了库存订单不超卖,下面是我们描述的集群架构: 问题接踵而至,在高并发情况下,现在我们还无法保证系统的高可用,假如这100台服务器上有两三台机器因为扛不住并发的流量或者其他的原因宕机了。那么这些服务器上的订单就卖不出去了,这就造成了订单的少卖。要解决这个问题,我们需要对总订单量做统一的管理,这就是接下来的容错方案。服务器不仅要在本地减库存,另外要远程统一减库存。有了远程统一减库存的操作,我们就可以根据机器负载情况,为每台机器分配一些多余的“buffer库存”用来防止机器中有机器宕机的情况。我们结合下面架构图具体分析一下: 我们采用Redis存储统一库存,因为Redis的性能非常高,号称单机QPS能抗10W的并发。在本地减库存以后,如果本地有订单,我们再去请求redis远程减库存,本地减库存和远程减库存都成功了,才返回给用户抢票成功的提示,这样也能有效的保证订单不会超卖。当机器中有机器宕机时,因为每个机器上有预留的buffer余票,所以宕机机器上的余票依然能够在其他机器上得到弥补,保证了不少卖。buffer余票设置多少合适呢,理论上buffer设置的越多,系统容忍宕机的机器数量就越多,但是buffer设置的太大也会对redis造成一定的影响。虽然redis内存数据库抗并发能力非常高,请求依然会走一次网络IO,其实抢票过程中对redis的请求次数是本地库存和buffer库存的总量,因为当本地库存不足时,系统直接返回用户“已售罄”的信息提示,就不会再走统一扣库存的逻辑,这在一定程度上也避免了巨大的网络请求量把redis压跨,所以buffer值设置多少,需要架构师对系统的负载能力做认真的考量。 4. 代码演示Go语言原生为并发设计,我采用go语言给大家演示一下单机抢票的具体流程。 4.1 初始化工作go包中的init函数先于main函数执行,在这个阶段主要做一些准备性工作。我们系统需要做的准备工作有:初始化本地库存、初始化远程redis存储统一库存的hash键值、初始化redis连接池;另外还需要初始化一个大小为1的int类型chan,目的是实现分布式锁的功能,也可以直接使用读写锁或者使用redis等其他的方式避免资源竞争,但使用channel更加高效,这就是go语言的哲学:不要通过共享内存来通信,而要通过通信来共享内存。redis库使用的是redigo,下面是代码实现: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647...//localSpike包结构体定义package localSpiketype LocalSpike struct { LocalInStock int64 LocalSalesVolume int64}...//remoteSpike对hash结构的定义和redis连接池package remoteSpike//远程订单存储健值type RemoteSpikeKeys struct { SpikeOrderHashKey string //redis中秒杀订单hash结构key TotalInventoryKey string //hash结构中总订单库存key QuantityOfOrderKey string //hash结构中已有订单数量key}//初始化redis连接池func NewPool() *redis.Pool { return &redis.Pool{ MaxIdle: 10000, MaxActive: 12000, // max number of connections Dial: func() (redis.Conn, error) { c, err := redis.Dial(\"tcp\", \":6379\") if err != nil { panic(err.Error()) } return c, err }, }}...func init() { localSpike = localSpike2.LocalSpike{ LocalInStock: 150, LocalSalesVolume: 0, } remoteSpike = remoteSpike2.RemoteSpikeKeys{ SpikeOrderHashKey: \"ticket_hash_key\", TotalInventoryKey: \"ticket_total_nums\", QuantityOfOrderKey: \"ticket_sold_nums\", } redisPool = remoteSpike2.NewPool() done = make(chan int, 1) done <- 1} 4.2 本地扣库存和统一扣库存个本地扣库存逻辑非常简单,用户请求过来,添加销量,然后对比销量是否大于本地库存,返回bool值: 123456package localSpike//本地扣库存,返回bool值func (spike *LocalSpike) LocalDeductionStock() bool{ spike.LocalSalesVolume = spike.LocalSalesVolume + 1 return spike.LocalSalesVolume < spike.LocalInStock} 注意这里对共享数据LocalSalesVolume的操作是要使用锁来实现的,但是因为本地扣库存和统一扣库存是一个原子性操作,所以在最上层使用channel来实现,这块后边会讲。统一扣库存操作redis,因为redis是单线程的,而我们要实现从中取数据,写数据并计算一些列步骤,我们要配合lua脚本打包命令,保证操作的原子性: 1234567891011121314151617181920212223package remoteSpike......const LuaScript = ` local ticket_key = KEYS[1] local ticket_total_key = ARGV[1] local ticket_sold_key = ARGV[2] local ticket_total_nums = tonumber(redis.call('HGET', ticket_key, ticket_total_key)) local ticket_sold_nums = tonumber(redis.call('HGET', ticket_key, ticket_sold_key)) -- 查看是否还有余票,增加订单数量,返回结果值 if(ticket_total_nums >= ticket_sold_nums) then return redis.call('HINCRBY', ticket_key, ticket_sold_key, 1) end return 0`//远端统一扣库存func (RemoteSpikeKeys *RemoteSpikeKeys) RemoteDeductionStock(conn redis.Conn) bool { lua := redis.NewScript(1, LuaScript) result, err := redis.Int(lua.Do(conn, RemoteSpikeKeys.SpikeOrderHashKey, RemoteSpikeKeys.TotalInventoryKey, RemoteSpikeKeys.QuantityOfOrderKey)) if err != nil { return false } return result != 0} 我们使用hash结构存储总库存和总销量的信息,用户请求过来时,判断总销量是否大于库存,然后返回相关的bool值。在启动服务之前,我们需要初始化redis的初始库存信息: 1hmset ticket_hash_key \"ticket_total_nums\" 10000 \"ticket_sold_nums\" 0 4.3 响应用户信息我们开启一个http服务,监听在一个端口上: 123456package main...func main() { http.HandleFunc(\"/buy/ticket\", handleReq) http.ListenAndServe(\":3005\", nil)} 上面我们做完了所有的初始化工作,接下来handleReq的逻辑非常清晰,判断是否抢票成功,返回给用户信息就可以了。 12345678910111213141516171819202122232425262728package main//处理请求函数,根据请求将响应结果信息写入日志func handleReq(w http.ResponseWriter, r *http.Request) { redisConn := redisPool.Get() LogMsg := \"\" <-done //全局读写锁 if localSpike.LocalDeductionStock() && remoteSpike.RemoteDeductionStock(redisConn) { util.RespJson(w, 1, \"抢票成功\", nil) LogMsg = LogMsg + \"result:1,localSales:\" + strconv.FormatInt(localSpike.LocalSalesVolume, 10) } else { util.RespJson(w, -1, \"已售罄\", nil) LogMsg = LogMsg + \"result:0,localSales:\" + strconv.FormatInt(localSpike.LocalSalesVolume, 10) } done <- 1 //将抢票状态写入到log中 writeLog(LogMsg, \"./stat.log\")}func writeLog(msg string, logPath string) { fd, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) defer fd.Close() content := strings.Join([]string{msg, \"\\r\\n\"}, \"\") buf := []byte(content) fd.Write(buf)}复制代码 前边提到我们扣库存时要考虑竞态条件,我们这里是使用channel避免并发的读写,保证了请求的高效顺序执行。我们将接口的返回信息写入到了./stat.log文件方便做压测统计。 4.4 单机服务压测开启服务,我们使用ab压测工具进行测试: 1ab -n 10000 -c 100 http://127.0.0.1:3005/buy/ticket 下面是我本地低配mac的压测信息 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253This is ApacheBench, Version 2.3 <$Revision: 1826891 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 127.0.0.1 (be patient)Completed 1000 requestsCompleted 2000 requestsCompleted 3000 requestsCompleted 4000 requestsCompleted 5000 requestsCompleted 6000 requestsCompleted 7000 requestsCompleted 8000 requestsCompleted 9000 requestsCompleted 10000 requestsFinished 10000 requestsServer Software:Server Hostname: 127.0.0.1Server Port: 3005Document Path: /buy/ticketDocument Length: 29 bytesConcurrency Level: 100Time taken for tests: 2.339 secondsComplete requests: 10000Failed requests: 0Total transferred: 1370000 bytesHTML transferred: 290000 bytesRequests per second: 4275.96 [#/sec] (mean)Time per request: 23.387 [ms] (mean)Time per request: 0.234 [ms] (mean, across all concurrent requests)Transfer rate: 572.08 [Kbytes/sec] receivedConnection Times (ms) min mean[+/-sd] median maxConnect: 0 8 14.7 6 223Processing: 2 15 17.6 11 232Waiting: 1 11 13.5 8 225Total: 7 23 22.8 18 239Percentage of the requests served within a certain time (ms) 50% 18 66% 24 75% 26 80% 28 90% 33 95% 39 98% 45 99% 54 100% 239 (longest request) 根据指标显示,我单机每秒就能处理4000+的请求,正常服务器都是多核配置,处理1W+的请求根本没有问题。而且查看日志发现整个服务过程中,请求都很正常,流量均匀,redis也很正常: 123456789101112131415//stat.log...result:1,localSales:145result:1,localSales:146result:1,localSales:147result:1,localSales:148result:1,localSales:149result:1,localSales:150result:0,localSales:151result:0,localSales:152result:0,localSales:153result:0,localSales:154result:0,localSales:156...复制代码 5.总结回顾总体来说,秒杀系统是非常复杂的。我们这里只是简单介绍模拟了一下单机如何优化到高性能,集群如何避免单点故障,保证订单不超卖、不少卖的一些策略,完整的订单系统还有订单进度的查看,每台服务器上都有一个任务,定时的从总库存同步余票和库存信息展示给用户,还有用户在订单有效期内不支付,释放订单,补充到库存等等。 我们实现了高并发抢票的核心逻辑,可以说系统设计的非常的巧妙,巧妙的避开了对DB数据库IO的操作,对Redis网络IO的高并发请求,几乎所有的计算都是在内存中完成的,而且有效的保证了不超卖、不少卖,还能够容忍部分机器的宕机。我觉得其中有两点特别值得学习总结: 负载均衡,分而治之。通过负载均衡,将不同的流量划分到不同的机器上,每台机器处理好自己的请求,将自己的性能发挥到极致,这样系统的整体也就能承受极高的并发了,就像工作的的一个团队,每个人都将自己的价值发挥到了极致,团队成长自然是很大的。 合理的使用并发和异步。自epoll网络架构模型解决了c10k问题以来,异步越来被服务端开发人员所接受,能够用异步来做的工作,就用异步来做,在功能拆解上能达到意想不到的效果,这点在nginx、node.js、redis上都能体现,他们处理网络请求使用的epoll模型,用实践告诉了我们单线程依然可以发挥强大的威力。服务器已经进入了多核时代,go语言这种天生为并发而生的语言,完美的发挥了服务器多核优势,很多可以并发处理的任务都可以使用并发来解决,比如go处理http请求时每个请求都会在一个goroutine中执行,总之:怎样合理的压榨CPU,让其发挥出应有的价值,是我们一直需要探索学习的方向。 参考文章:参考链接","link":"/design-architecture/%E7%A7%92%E6%9D%80%E7%B3%BB%E7%BB%9F%E5%A6%82%E4%BD%95%E6%94%AF%E6%92%91%E7%99%BE%E4%B8%87QPS.html"},{"title":"Kafka基本架构及原理","text":"一、为什么需要消息系统1.解耦: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。2.冗余: 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。3.扩展性: 因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。 4.灵活性 & 峰值处理能力: 在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。5.可恢复性: 系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。6.顺序保证: 在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)7.缓冲: 有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。8.异步通信: 很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。 二、kafka 架构拓扑结构 相关名词解释: 123456789101112131415161718192021221.producer: 消息生产者,发布消息到 kafka 集群的终端或服务。2.broker: kafka 集群中包含的服务器。3.topic: 每条发布到 kafka 集群的消息属于的类别,即 kafka 是面向 topic 的。4.partition: partition 是物理上的概念,每个 topic 包含一个或多个 partition。kafka 分配的单位是 partition。5.consumer: 从 kafka 集群中消费消息的终端或服务。6.Consumer group: high-level consumer API 中,每个 consumer 都属于一个 consumer group,每条消息只能被 consumer group 中的一个 Consumer 消费,但可以被多个 consumer group 消费。7.replica: partition 的副本,保障 partition 的高可用。8.leader: replica 中的一个角色, producer 和 consumer 只跟 leader 交互。9.follower: replica 中的一个角色,从 leader 中复制数据。10.controller: kafka 集群中的其中一个服务器,用来进行 leader election 以及 各种 failover。12.zookeeper: kafka 通过 zookeeper 来存储集群的 meta 信息。 zookeeper 节点kafka 在 zookeeper 中的存储结构如下图所示: 三、producer 发布消息写入方式producer 采用 push 模式将消息发布到 broker,每条消息都被 append 到 patition 中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障 kafka 吞吐率)。 消息路由producer 发送消息到 broker 时,会根据分区算法选择将其存储到哪一个 partition。其路由机制为: 1231. 指定了 patition,则直接使用;2. 未指定 patition 但指定 key,通过对 key 的 value 进行hash 选出一个 patition3. patition 和 key 都未指定,使用轮询选出一个 patition。 附上 java 客户端分区源码,一目了然: 123456789101112131415161718192021222324252627282930313233343536373839404142434445//创建消息实例public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value) { if (topic == null) throw new IllegalArgumentException(\"Topic cannot be null\"); if (timestamp != null && timestamp < 0) throw new IllegalArgumentException(\"Invalid timestamp \" + timestamp); this.topic = topic; this.partition = partition; this.key = key; this.value = value; this.timestamp = timestamp;}//计算 patition,如果指定了 patition 则直接使用,否则使用 key 计算private int partition(ProducerRecord<K, V> record, byte[] serializedKey , byte[] serializedValue, Cluster cluster) { Integer partition = record.partition(); if (partition != null) { List<PartitionInfo> partitions = cluster.partitionsForTopic(record.topic()); int lastPartition = partitions.size() - 1; if (partition < 0 || partition > lastPartition) { throw new IllegalArgumentException(String.format(\"Invalid partition given with record: %d is not in the range [0...%d].\", partition, lastPartition)); } return partition; } return this.partitioner.partition(record.topic(), record.key(), serializedKey, record.value(), serializedValue, cluster);}// 使用 key 选取 patitionpublic int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { List<PartitionInfo> partitions = cluster.partitionsForTopic(topic); int numPartitions = partitions.size(); if (keyBytes == null) { int nextValue = counter.getAndIncrement(); List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic); if (availablePartitions.size() > 0) { int part = DefaultPartitioner.toPositive(nextValue) % availablePartitions.size(); return availablePartitions.get(part).partition(); } else { return DefaultPartitioner.toPositive(nextValue) % numPartitions; } } else { //对 keyBytes 进行 hash 选出一个 patition return DefaultPartitioner.toPositive(Utils.murmur2(keyBytes)) % numPartitions; }} 写入流程producer 写入消息序列图: 流程说明: 123451. producer 先从 zookeeper 的 \"/brokers/.../state\" 节点找到该 partition 的 leader2. producer 将消息发送给该 leader3. leader 将消息写入本地 log4. followers 从 leader pull 消息,写入本地 log 后 leader 发送 ACK5. leader 收到所有 ISR 中的 replica 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset) 并向 producer 发送 ACK producer delivery guarantee一般情况下存在三种情况: 1231. At most once 消息可能会丢,但绝不会重复传输2. At least one 消息绝不会丢,但可能会重复传输3. Exactly once 每条消息肯定会被传输一次且仅传输一次 当 producer 向 broker 发送消息时,一旦这条消息被 commit,由于 replication 的存在,它就不会丢。但是如果 producer 发送数据给 broker 后,遇到网络问题而造成通信中断,那 Producer 就无法判断该条消息是否已经 commit。虽然 Kafka 无法确定网络故障期间发生了什么,但是 producer 可以生成一种类似于主键的东西,发生故障时幂等性的重试多次,这样就做到了 Exactly once,但目前还并未实现。所以目前默认情况下一条消息从 producer 到 broker 是确保了 At least once,可通过设置 producer 异步发送实现At most once。 四、broker 保存消息存储方式物理上把 topic 分成一个或多个 patition(对应 server.properties 中的 num.partitions=3 配置),每个 patition 物理上对应一个文件夹(该文件夹存储该 patition 的所有消息和索引文件),如下: 存储策略无论消息是否被消费,kafka 都会保留所有消息。有两种策略可以删除旧数据: 121. 基于时间:log.retention.hours=1682. 基于大小:log.retention.bytes=1073741824 需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关。 topic 创建与删除创建 topic创建 topic 的序列图 流程说明: 123451. controller 在 ZooKeeper 的 /brokers/topics 节点上注册 watcher,当 topic 被创建,则 controller 会通过 watch 得到该 topic 的 partition/replica 分配。2. controller从 /brokers/ids 读取当前所有可用的 broker 列表,对于 set_p 中的每一个 partition: 2.1 从分配给该 partition 的所有 replica(称为AR)中任选一个可用的 broker 作为新的 leader,并将AR设置为新的 ISR 2.2 将新的 leader 和 ISR 写入 /brokers/topics/[topic]/partitions/[partition]/state3. controller 通过 RPC 向相关的 broker 发送 LeaderAndISRRequest。 删除 topic删除 topic 的序列图 流程说明: 121. controller 在 zooKeeper 的 /brokers/topics 节点上注册 watcher,当 topic 被删除,则 controller 会通过 watch 得到该 topic 的 partition/replica 分配。2. 若 delete.topic.enable=false,结束;否则 controller 注册在 /admin/delete_topics 上的 watch 被 fire,controller 通过回调向对应的 broker 发送 StopReplicaRequest。 五、kafka HAreplication如图.1所示,同一个 partition 可能会有多个 replica(对应 server.properties 配置中的 default.replication.factor=N)。没有 replica 的情况下,一旦 broker 宕机,其上所有 patition 的数据都不可被消费,同时 producer 也不能再将数据存于其上的 patition。引入replication 之后,同一个 partition 可能会有多个 replica,而这时需要在这些 replica 之间选出一个 leader,producer 和 consumer 只与这个 leader 交互,其它 replica 作为 follower 从 leader 中复制数据。 Kafka 分配 Replica 的算法如下: 1231. 将所有 broker(假设共 n 个 broker)和待分配的 partition 排序2. 将第 i 个 partition 分配到第(i mod n)个 broker 上3. 将第 i 个 partition 的第 j 个 replica 分配到第((i + j) mode n)个 broker上 leader failover当 partition 对应的 leader 宕机时,需要从 follower 中选举出新 leader。在选举新leader时,一个基本的原则是,新的 leader 必须拥有旧 leader commit 过的所有消息。 kafka 在 zookeeper 中(/brokers/…/state)动态维护了一个 ISR(in-sync replicas),由3.3节的写入流程可知 ISR 里面的所有 replica 都跟上了 leader,只有 ISR 里面的成员才能选为 leader。对于 f+1 个 replica,一个 partition 可以在容忍 f 个 replica 失效的情况下保证消息不丢失。 当所有 replica 都不工作时,有两种可行的方案: 121. 等待 ISR 中的任一个 replica 活过来,并选它作为 leader。可保障数据不丢失,但时间可能相对较长。2. 选择第一个活过来的 replica(不一定是 ISR 成员)作为 leader。无法保障数据不丢失,但相对不可用时间较短。 kafka 0.8.* 使用第二种方式。 kafka 通过 Controller 来选举 leader,流程请参考5.3节。 broker failoverkafka broker failover 序列图如下所示: 流程说明: 123456781. controller 在 zookeeper 的 /brokers/ids/[brokerId] 节点注册 Watcher,当 broker 宕机时 zookeeper 会 fire watch2. controller 从 /brokers/ids 节点读取可用broker3. controller决定set_p,该集合包含宕机 broker 上的所有 partition4. 对 set_p 中的每一个 partition 4.1 从/brokers/topics/[topic]/partitions/[partition]/state 节点读取 ISR 4.2 决定新 leader(如4.3节所描述) 4.3 将新 leader、ISR、controller_epoch 和 leader_epoch 等信息写入 state 节点5. 通过 RPC 向相关 broker 发送 leaderAndISRRequest 命令 controller failover当 controller 宕机时会触发 controller failover。每个 broker 都会在 zookeeper 的 “/controller” 节点注册 watcher,当 controller 宕机时 zookeeper 中的临时节点消失,所有存活的 broker 收到 fire 的通知,每个 broker 都尝试创建新的 controller path,只有一个竞选成功并当选为 controller。 当新的 controller 当选时,会触发 KafkaController.onControllerFailover 方法,在该方法中完成如下操作: 123456789101112 1. 读取并增加 Controller Epoch。 2. 在 reassignedPartitions Patch(/admin/reassign_partitions) 上注册 watcher。 3. 在 preferredReplicaElection Path(/admin/preferred_replica_election) 上注册 watcher。 4. 通过 partitionStateMachine 在 broker Topics Patch(/brokers/topics) 上注册 watcher。 5. 若 delete.topic.enable=true(默认值是 false),则 partitionStateMachine 在 Delete Topic Patch(/admin/delete_topics) 上注册 watcher。 6. 通过 replicaStateMachine在 Broker Ids Patch(/brokers/ids)上注册Watch。 7. 初始化 ControllerContext 对象,设置当前所有 topic,“活”着的 broker 列表,所有 partition 的 leader 及 ISR等。 8. 启动 replicaStateMachine 和 partitionStateMachine。 9. 将 brokerState 状态设置为 RunningAsController。10. 将每个 partition 的 Leadership 信息发送给所有“活”着的 broker。11. 若 auto.leader.rebalance.enable=true(默认值是true),则启动 partition-rebalance 线程。12. 若 delete.topic.enable=true 且Delete Topic Patch(/admin/delete_topics)中有值,则删除相应的Topic。 六、consumer 消费消息consumer APIkafka 提供了两套 consumer API: 121. The high-level Consumer API2. The SimpleConsumer API 其中 high-level consumer API 提供了一个从 kafka 消费数据的高层抽象,而 SimpleConsumer API 则需要开发人员更多地关注细节。 The high-level consumer APIhigh-level consumer API 提供了 consumer group 的语义,一个消息只能被 group 内的一个 consumer 所消费,且 consumer 消费消息时不关注 offset,最后一个 offset 由 zookeeper 保存。 使用 high-level consumer API 可以是多线程的应用,应当注意: 1231. 如果消费线程大于 patition 数量,则有些线程将收不到消息2. 如果 patition 数量大于线程数,则有些线程多收到多个 patition 的消息3. 如果一个线程消费多个 patition,则无法保证你收到的消息的顺序,而一个 patition 内的消息是有序的 The SimpleConsumer API如果你想要对 patition 有更多的控制权,那就应该使用 SimpleConsumer API,比如: 1231. 多次读取一个消息2. 只消费一个 patition 中的部分消息3. 使用事务来保证一个消息仅被消费一次 但是使用此 API 时,partition、offset、broker、leader 等对你不再透明,需要自己去管理。你需要做大量的额外工作: 1231. 必须在应用程序中跟踪 offset,从而确定下一条应该消费哪条消息2. 应用程序需要通过程序获知每个 Partition 的 leader 是谁3. 需要处理 leader 的变更 使用 SimpleConsumer API 的一般流程如下: 123451. 查找到一个“活着”的 broker,并且找出每个 partition 的 leader2. 找出每个 partition 的 follower3. 定义好请求,该请求应该能描述应用程序需要哪些数据4. fetch 数据5. 识别 leader 的变化,并对之作出必要的响应 以下针对 high-level Consumer API 进行说明。 consumer group如 2.2 节所说, kafka 的分配单位是 patition。每个 consumer 都属于一个 group,一个 partition 只能被同一个 group 内的一个 consumer 所消费(也就保障了一个消息只能被 group 内的一个 consuemr 所消费),但是多个 group 可以同时消费这个 partition。 kafka 的设计目标之一就是同时实现离线处理和实时处理,根据这一特性,可以使用 spark/Storm 这些实时处理系统对消息在线处理,同时使用 Hadoop 批处理系统进行离线处理,还可以将数据备份到另一个数据中心,只需要保证这三者属于不同的 consumer group。如下图所示: 消费方式consumer 采用 pull 模式从 broker 中读取数据。 push 模式很难适应消费速率不同的消费者,因为消息发送速率是由 broker 决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成 consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而 pull 模式则可以根据 consumer 的消费能力以适当的速率消费消息。 对于 Kafka 而言,pull 模式更合适,它可简化 broker 的设计,consumer 可自主控制消费消息的速率,同时 consumer 可以自己控制消费方式——即可批量消费也可逐条消费,同时还能选择不同的提交方式从而实现不同的传输语义。 consumer delivery guarantee如果将 consumer 设置为 autocommit,consumer 一旦读到数据立即自动 commit。如果只讨论这一读取消息的过程,那 Kafka 确保了 Exactly once。 但实际使用中应用程序并非在 consumer 读取完数据就结束了,而是要进行进一步处理,而数据处理与 commit 的顺序在很大程度上决定了consumer delivery guarantee: 1234561.读完消息先 commit 再处理消息。 这种模式下,如果 consumer 在 commit 后还没来得及处理消息就 crash 了,下次重新开始工作后就无法读到刚刚已提交而未处理的消息,这就对应于 At most once2.读完消息先处理再 commit。 这种模式下,如果在处理完消息之后 commit 之前 consumer crash 了,下次重新开始工作时还会处理刚刚未 commit 的消息,实际上该消息已经被处理过了。这就对应于 At least once。3.如果一定要做到 Exactly once,就需要协调 offset 和实际操作的输出。 精典的做法是引入两阶段提交。如果能让 offset 和操作输入存在同一个地方,会更简洁和通用。这种方式可能更好,因为许多输出系统可能不支持两阶段提交。比如,consumer 拿到数据后可能把数据放到 HDFS,如果把最新的 offset 和数据本身一起写到 HDFS,那就可以保证数据的输出和 offset 的更新要么都完成,要么都不完成,间接实现 Exactly once。(目前就 high-level API而言,offset 是存于Zookeeper 中的,无法存于HDFS,而SimpleConsuemr API的 offset 是由自己去维护的,可以将之存于 HDFS 中) 总之,Kafka 默认保证 At least once,并且允许通过设置 producer 异步提交来实现 At most once(见文章《kafka consumer防止数据丢失》)。而 Exactly once 要求与外部存储系统协作,幸运的是 kafka 提供的 offset 可以非常直接非常容易得使用这种方式。 更多关于 kafka 传输语义的信息请参考《Message Delivery Semantics》。 consumer rebalance当有 consumer 加入或退出、以及 partition 的改变(如 broker 加入或退出)时会触发 rebalance。consumer rebalance算法如下: 123451. 将目标 topic 下的所有 partirtion 排序,存于PT2. 对某 consumer group 下所有 consumer 排序,存于 CG,第 i 个consumer 记为 Ci3. N=size(PT)/size(CG),向上取整4. 解除 Ci 对原来分配的 partition 的消费权(i从0开始)5. 将第i*N到(i+1)*N-1个 partition 分配给 Ci 在 0.8.*版本,每个 consumer 都只负责调整自己所消费的 partition,为了保证整个consumer group 的一致性,当一个 consumer 触发了 rebalance 时,该 consumer group 内的其它所有其它 consumer 也应该同时触发 rebalance。这会导致以下几个问题: 1234561.Herd effect 任何 broker 或者 consumer 的增减都会触发所有的 consumer 的 rebalance2.Split Brain 每个 consumer 分别单独通过 zookeeper 判断哪些 broker 和 consumer 宕机了,那么不同 consumer 在同一时刻从 zookeeper 看到的 view 就可能不一样,这是由 zookeeper 的特性决定的,这就会造成不正确的 reblance 尝试。3. 调整结果不可控 所有的 consumer 都并不知道其它 consumer 的 rebalance 是否成功,这可能会导致 kafka 工作在一个不正确的状态。 基于以上问题,kafka 设计者考虑在0.9.*版本开始使用中心 coordinator 来控制 consumer rebalance,然后又从简便性和验证要求两方面考虑,计划在 consumer 客户端实现分配方案。(见文章《Kafka Detailed Consumer Coordinator Design》和《Kafka Client-side Assignment Proposal》),此处不再赘述。 七、注意事项producer 无法发送消息的问题最开始在本机搭建了kafka伪集群,本地 producer 客户端成功发布消息至 broker。随后在服务器上搭建了 kafka 集群,在本机连接该集群,producer 却无法发布消息到 broker(奇怪也没有抛错)。最开始怀疑是 iptables 没开放,于是开放端口,结果还不行(又开始是代码问题、版本问题等等,倒腾了很久)。最后没办法,一项一项查看 server.properties 配置,发现以下两个配置: 123456789101112# The address the socket server listens on. It will get the value returned from # java.net.InetAddress.getCanonicalHostName() if not configured.# FORMAT:# listeners = security_protocol://host_name:port# EXAMPLE:# listeners = PLAINTEXT://your.host.name:9092listeners=PLAINTEXT://:9092# Hostname and port the broker will advertise to producers and consumers. If not set, # it uses the value for \"listeners\" if configured. Otherwise, it will use the value# returned from java.net.InetAddress.getCanonicalHostName().# advertised.listeners=PLAINTEXT://your.host.name:9092 以上说的就是 advertised.listeners 是 broker 给 producer 和 consumer 连接使用的,如果没有设置,就使用 listeners,而如果 host_name 没有设置的话,就使用 java.net.InetAddress.getCanonicalHostName() 方法返回的主机名。 修改方法: 121. listeners=PLAINTEXT://121.10.26.XXX:90922. advertised.listeners=PLAINTEXT://121.10.26.XXX:9092 修改后重启服务,正常工作。关于更多 kafka 配置说明,见文章《Kafka学习整理三(borker(0.9.0及0.10.0)配置)》。 八、参考相关文章列表 《Kafka剖析(一):Kafka背景及架构介绍》 《Kafka设计解析(二):Kafka High Availability (上)》 《Kafka设计解析(二):Kafka High Availability (下)》 《Kafka设计解析(四):Kafka Consumer解析》 《Kafka设计解析(五):Kafka Benchmark》 《Kafka学习整理三(borker(0.9.0及0.10.0)配置)》 《Using the High Level Consumer》 《Using SimpleConsumer》 《Consumer Client Re-Design》 《Message Delivery Semantics》 《Kafka Detailed Consumer Coordinator Design》 《Kafka Client-side Assignment Proposal》 《Kafka和DistributedLog技术对比》 《kafka安装和启动》 《kafka consumer防止数据丢失》 参考文章:参考链接","link":"/design-architecture/Kafka%E5%9F%BA%E6%9C%AC%E6%9E%B6%E6%9E%84%E5%8F%8A%E5%8E%9F%E7%90%86.html"},{"title":"Git-rebase-用法示例小结","text":"看过上一篇文章【Git如何优雅地回退代码】的小伙伴们,肯定还有很多跟我一样对rebase的使用还是云里雾里的,这篇文章将使你彻底搞明白怎么使用。rebase在git中是一个非常有魅力的命令,使用得当会极大提高自己的工作效率;相反,如果乱用,会给团队中其他人带来麻烦。它的作用简要概括为:可以对某一段线性提交历史进行编辑、删除、复制、粘贴;因此,合理使用rebase命令可以使我们的提交历史干净、简洁! 前提:不要通过rebase对任何已经提交到公共仓库中的commit进行修改(你自己一个人玩的分支除外) 一、合并多个commit为一个完整commit当我们在本地仓库中提交了多次,在我们把本地提交push到公共仓库中之前,为了让提交记录更简洁明了,我们希望把如下分支B、C、D三个提交记录合并为一个完整的提交,然后再push到公共仓库。 现在我们在测试分支上添加了四次提交,我们的目标是把最后三个提交合并为一个提交: 这里我们使用命令: 1git rebase -i [startpoint] [endpoint] 其中-i的意思是--interactive,即弹出交互式的界面让用户编辑完成合并操作,[startpoint] [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。 在查看到了log日志后,我们运行以下命令: 1git rebase -i 36224db or 1git rebase -i HEAD~3 然后我们会看到如下界面: 上面未被注释的部分列出的是我们本次rebase操作包含的所有提交,下面注释部分是git为我们提供的命令说明。每一个commit id 前面的pick表示指令类型,git 为我们提供了以下几个命令: pick:保留该commit(缩写:p) reword:保留该commit,但我需要修改该commit的注释(缩写:r) edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e) squash:将该commit和前一个commit合并(缩写:s) fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f) exec:执行shell命令(缩写:x) drop:我要丢弃该commit(缩写:d) 根据我们的需求,我们将commit内容编辑如下: 此做法是把后面两次提交都合并到第一次提交里,改完上面的操作后执行vim:wq保存信息,之后会跳出下面的修改注释界面: 编辑完保存即可完成commit的合并了: 二、将某一段commit粘贴到另一个分支上当我们项目中存在多个分支,有时候我们需要将某一个分支中的一段提交同时应用到其他分支中,就像下图: 我们希望将develop分支中的C~E部分复制到master分支中,这时我们就可以通过rebase命令来实现(如果只是复制某一两个提交到其他分支,建议使用更简单的命令:git cherry-pick)。 在实际模拟中,我们创建了master和develop两个分支: master分支: develop分支: 我们使用命令的形式为: 1git rebase [startpoint] [endpoint] --onto [branchName] 其中,[startpoint] [endpoint]仍然和上一个命令一样指定了一个编辑区间(前开后闭),--onto的意思是要将该指定的提交复制到哪个分支上。 所以,在找到C(90bc0045b)和E(5de0da9f2)的提交id后,我们运行以下命令: 1git rebase 90bc0045b^ 5de0da9f2 --onto master 以上命令有网友补充内容: 大帅_8183 15楼 2019.05.26 17:30 博主,关于你说的“[startpoint] [endpoint]仍然和上一个命令一样指定了一个编辑区间(前开后闭)” ,其中的前开后闭的思维,其实是有歧义的。 如果一定要用“区间”来表示的话, 那它表示的也一定是一个“前闭后闭”的区间;至于,博主理解的“前开后闭”,其实是博主想使用[startpoint] 这个commit上的功能,但这部分功能本身 就是 上 一个commit提交功能后生成的新的commit(也就是 这里的[startpoint]); 而原rebase的[startpoint] 的意思是,应该是表示,在此commit开始([startpoint])更改的代码部分; andy_dfa5 5楼 2018.08.13 14:14 作者写的很好,但是有个小错误,就是rebase是一个开闭集,就是上面例子中 git rebase 90bc0045b^ 5de0da9f2 –onto master。90bc0045b^这个提交是不会生效的,如果要这个生效要从b4d576开始rebase 关于上面的质疑自己动手试下就知道结果了。 注:因为[startpoint] [endpoint]指定的是一个前开后闭的区间,为了让这个区间包含C提交,我们将区间起始点向后退了一步。运行完成后查看当前分支的日志: 可以看到,C~E部分的提交内容已经复制到了G的后面了,大功告成?NO!我们看一下当前分支的状态: 当前HEAD处于游离状态,实际上,此时所有分支的状态应该是这样: 所以,虽然此时HEAD所指向的内容正是我们所需要的,但是master分支是没有任何变化的,git只是将C~E部分的提交内容复制一份粘贴到了master所指向的提交后面,我们需要做的就是将master所指向的提交id设置为当前HEAD所指向的提交id就可以了,即: 12git checkout mastergit reset --hard 0c72e64 此时我们才大功告成! 参考文章:参考链接","link":"/develop/Git-rebase-%E7%94%A8%E6%B3%95%E7%A4%BA%E4%BE%8B%E5%B0%8F%E7%BB%93.html"},{"title":"Git如何优雅地回退代码","text":"前言从接触编程就开始使用 Git 进行代码管理,先是自己玩 Github,又在工作中使用 Gitlab,虽然使用时间挺长,可是也只进行一些常用操作,如推拉代码、提交、合并等,更复杂的操作没有使用过,看过的教程也逐渐淡忘了,有些对不起 Linus 大神。 出来混总是要还的,前些天就遇到了 Git 里一种十分糟心的场景,并为之前没有深入理解 Git 命令付出了一下午时间的代价。 先介绍一下这种场景,我们一个项目从 N 版本升到 A 版本时引入了另一项目的 jar 包,又陆续发布了 B、C 版本,但在 C 版本后忽然发现了 A 版本引入的 jar 包有极大的性能问题,B、C 版本都是基于 A 版本发布的,要修复 jar 包性能问题,等 jar 包再发版还得几天,可此时线上又有紧急的 Bug 要修,于是就陷入了进退两难的境地。 最后决定先将代码回退到 A 版本之前,再基于旧版本修复 Bug,也就开始了五个小时的受苦之路。 基础试探revert首先肯定的是 revert,git revert commit_id 能产生一个 与 commit_id 完全相反的提交,即 commit_id 里是添加, revert 提交里就是删除。 但是使用 git log 查看了提交记录后,我就打消了这种想法,因为提交次数太多了,中途还有几次从其他分支的 merge 操作。 ”利益于”我们不太干净的提交记录,要完成从 C 版本到 N 版本的 revert,我需要倒序执行 revert 操作几十次,如果其中顺序错了一次,最终结果可能就是不对的。 另外我们知道我们在进行代码 merge 时,也会把 merge 信息产生一次新的提交,而 revert 这次 merge commit 时需要指定 m 参数,以指定 mainline 这个 mainline 是主线,也是我们要保留代码的主分支,从 feature 分支往 develop 分支合并,或由 develop 分支合并到 master 的提交还好确定,但 feature 分支互相合并时,我哪知道哪个是主线啊。 所以 revert 的文案被废弃了。 Reset然后就考虑 reset 了, reset 也能使代码回到某次提交,但跟 revert 不同的是, reset 是将提交的 HEAD 指针指到某次提交,之后的提交记录会消失,就像从没有过这么一次提交。 但由于我们都在 feature 分支开发,我在 feature 分支上将代码回退到某次提交后,将其合并到 develop 分支时却被提示报错。 这是因为 feature 分支回退了提交后,在 git 的 workflow 里,feature 分支是落后于 develop 分支的,而合并向 develop 分支,又需要和 develop 分支保持最新的同步,需要将 develop 分支的数据合并到 feature 分支上,而合并后,原来被 reset 的代码又回来了。 这个时候另一个可选项是在 master 分支上执行 reset,使用 --hard 选项完全抛弃这些旧代码,reset 后再强制推到远端。 12master> git reset --hard commit_idmaster> git push --force origin master 但是还是有问题,首先,我们的 master 分支在 gitlab 里是被保护的,不能使用 force push,毕竟风险挺大了,万一有人 reset 到最开始的提交再强制 push 的话,虽然可以使用 reflog 恢复,但也是一番折腾。 另外,reset 毕竟太野蛮,我们还是想能保留提交历史,以后排查问题也可以参考。 升级融合rebase只好用搜索引擎继续搜索,看到有人提出可以先使用 rebase 把多个提交合并成一个提交,再使用 revert 产生一次反提交,这种方法的思路非常清晰,把 revert 和 rebase 两个命令搭配得很好,相当于使用 revert 回退的升级版。 先说一下 rebase,rebase 是”变基”的意思,这里的”基”,在我理解是指[多次] commit 形成的 git workflow,使用 rebase,我们可以改变这些历史提交,修改 commit 信息,将多个 commit 进行组合。 介绍 rebase 的文档有很多,我们直接来说用它来进行代码回退的步骤。 首先,切出一个新分支 F,使用 git log 查询一下要回退到的 commit 版本 N。 使用命令 git rebase -i N, -i 指定交互模式后,会打开 git rebase 编辑界面,形如: 1234pick 6fa5869 commit1pick 0b84ee7 commit2pick 986c6c8 commit3pick 91a0dcc commit4 这些 commit 自旧到新由上而下排列,我们只需要在 commit_id 前添加操作命令即可。 在合并 commit 这个需求里,我们可以选择 pick(p) 最旧的 commit1,然后在后续的 commit_id 前添加 squash(s) 命令,将这些 commits 都合并到最旧的 commit1 上。 保存 rebase 结果后,再编辑 commit 信息,使这次 rebase 失效,git 会将之前的这些 commit 都删除,并将其更改合并为一个新的 commit5 如果出错了,也可以使用 git rebase --abort/--continue/--edit-todo`` 对之前的编辑进行撤销、继续编辑。 这个时候,主分支上的提交记录是 older, commit1, commit2, commit3, commit4 而 F 分支上的提交记录是 older, commit5,由于 F 分支的祖先节点是 older,明显落后于主分支的 commit4,将 F 分支向主分支合并是不允许的 所以我们需要执行 git merge master 将主分支向 F 分支合并,合并后 git 会发现 commit1 到 commit4 提交的内容和 F 分支上 commit5 的修改内容是完全相同的,会自动进行合并,内容不变,但多了一个 commit5。 再在 F 分支上对 commit5 进行一次 revert 反提交,就实现了把 commit1 到 commit4 的提交全部回退。 这种方法的取巧之处在于巧妙地利用了 rebase 操作历史提交的功能和 git 识别修改相同自动合并的特性,操作虽然复杂,但历史提交保留得还算完整。 rebase 这种修改历史提交的功能非常实用,能够很好地解决我们遇到的一个小功能提交了好多次才好使,而把 git 历史弄得乱七八糟的问题,只需要注意避免在多人同时开发的分支使用就行了。 遗憾的是,当天我并没有理解到 rebase 的这种思想,又由于试了几个方法都不行太过于慌乱,在 rebase 完成后,向主分支合并被拒之后对这些方式的可行性产生了怀疑,又加上有同事提出听起来更可行的方式,就中断了操作。 文件操作这种更可行的方式就是对文件操作,然后让 git 来识别变更,具体是: 从主分支上切出一个跟主分支完全相同的分支 F。 从文件管理系统复制项目文件夹为 bak,在 bak 内使用 git checkout N 将代码切到想要的历史提交,这时候 git 会将 bak 内的文件恢复到 N 状态。 在从文件管理系统内,将 bak 文件夹下 除了 .git 文件夹下的所有内容复制粘贴到原项目目录下。git 会纯从文件级别识别到变更,然后更新工作区。 在原项目目录下执行 add 和 commit,完成反提交。 这种方式的巧妙之处在于利用 git 本身对文件的识别,不牵涉到对 workflow 操作。 小结最后终于靠着文件操作方式成功完成了代码回退,事后想来真是一把心酸泪。 为了让我的五个小时不白费,复盘一下当时的场景,学习并总结一下四种代码回退的方式: revert 适合需要回退的历史提交不多,且无合并冲突的情景。 如果你可以向 master 强推代码,且想让 git log 里不再出现被回退代码的痕迹,可以使用 git reset --hard + git push --force`` 的方式。 如果你有些 geek,追求用”正规而正统”的方式来回退代码,rebase + revert 满足你的需求。 如果你不在乎是否优雅,想用最简单,最直接的方式,文件操作正合适。 git 真的是非常牛逼的代码管理工具,入手简单,三五个命令组合起来就足够完成工作需求,又对 geeker 们非常友好,你想要的骚操作它都支持,学无止境啊。 参考文章:参考链接","link":"/develop/Git%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E5%9C%B0%E5%9B%9E%E9%80%80%E4%BB%A3%E7%A0%81.html"},{"title":"Spring的Bean生命周期","text":"一、获取Bean第一阶段获取Bean这里的流程图的入口在 AbstractBeanFactory类的 doGetBean方法,这里可以配合前面的 getBean方法分析文章进行阅读。主要流程就是 1、先处理Bean 的名称,因为如果以“&”开头的Bean名称表示获取的是对应的FactoryBean对象;2、从缓存中获取单例Bean,有则进一步判断这个Bean是不是在创建中,如果是的就等待创建完毕,否则直接返回这个Bean对象3、如果不存在单例Bean缓存,则先进行循环依赖的解析4、解析完毕之后先获取父类BeanFactory,获取到了则调用父类的getBean方法,不存在则先合并然后创建Bean 二、创建Bean创建Bean之前 在真正创建Bean之前逻辑这个流程图对应的代码在 AbstractAutowireCapableBeanFactory类的 createBean方法中。 1、这里会先获取 RootBeanDefinition对象中的Class对象并确保已经关联了要创建的Bean的Class 。2、这里会检查3个条件 (1)Bean的属性中的 beforeInstantiationResolved字段是否为true,默认是false。(2)Bean是原生的Bean(3)Bean的 hasInstantiationAwareBeanPostProcessors属性为true,这个属性在Spring准备刷新容器钱转杯BeanPostProcessors的时候会设置,如果当前Bean实现了 InstantiationAwareBeanPostProcessor则这个就会是true。 当三个条件都存在的时候,就会调用实现的 InstantiationAwareBeanPostProcessor接口的 postProcessBeforeInstantiation方法,然后获取返回的Bean,如果返回的Bean不是null还会调用实现的 BeanPostProcessor接口的 postProcessAfterInitialization方法,这里用代码说明 12345678910111213141516171819202122protected Object resolveBeforeInstantiation(String beanName,RootBeanDefinition mbd) { Object bean = null; //条件1 if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { //条件2跟条件3 if(!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if(targetType != null) { //调用实现的postProcessBeforeInstantiation方法 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if(bean != null ) { //调用实现的postProcessAfterInitialization方法 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } //不满足2或者3的时候就会设置为false mbd.beforeInstantiationResolved = (bean != null); } return bean; } 如果上面3个条件其中一个不满足就不会调用实现的方法。默认这里都不会调用的这些 BeanPostProcessors的实现方法。然后继续执行后面的 doCreateBean方法。 真正的创建Bean,doCreateBean doCreateBean方法逻辑这个代码的实现还是在 AbstractAutowireCapableBeanFactory方法中。流程是 1、先检查 instanceWrapper变量是不是null,这里一般是null,除非当前正在创建的Bean在 factoryBeanInstanceCache中存在这个是保存还没创建完成的FactoryBean的集合。2、调用createBeanInstance方法实例化Bean,这个方法在后面会讲解3、如果当前 RootBeanDefinition对象还没有调用过实现了的 MergedBeanDefinitionPostProcessor接口的方法,则会进行调用 。4、 当满足以下三点(1)是单例Bean(2)尝试解析bean之间的循环引用(3)bean目前正在创建中则会进一步检查是否实现了 SmartInstantiationAwareBeanPostProcessor接口如果实现了则调用是实现的 getEarlyBeanReference方法5、 调用 populateBean方法进行属性填充,这里后面会讲解6、 调用 initializeBean方法对Bean进行初始化,这里后面会讲解 实例化Bean,createBeanInstance 实例化Bean这里的逻辑稍微有一点复杂,这个流程图已经是简化过后的了。简要根据代码说明一下流程 123456789101112131415161718192021222324252627protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, \"Bean class isn't public, and non-public access not allowed: \" + beanClass.getName()); } else if (mbd.getFactoryMethodName() != null) { return this.instantiateUsingFactoryMethod(beanName, mbd, args); } else { boolean resolved = false; boolean autowireNecessary = false; if (args == null) { Object var7 = mbd.constructorArgumentLock; synchronized(mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd); } else { Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName); return ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args) ? this.instantiateBean(beanName, mbd) : this.autowireConstructor(beanName, mbd, ctors, args); } } } 1、先检查Class是否已经关联了,并且对应的修饰符是否是public的2、如果用户定义了Bean实例化的函数,则调用并返回3、如果当前Bean实现了 FactoryBean接口则调用对应的 FactoryBean接口的 getObject方法4、根据getBean时候是否传入构造参数进行处理4.1 如果没有传入构造参数,则检查是否存在已经缓存的无参构造器,有则使用构造器直接创建,没有就会调用 instantiateBean方法先获取实例化的策略默认是 CglibSubclassingInstantiationStrategy,然后实例化Bean。最后返回4.2 如果传入了构造参数,则会先检查是否实现了 SmartInstantiationAwareBeanPostProcessor接口,如果实现了会调用 determineCandidateConstructors获取返回的候选构造器。4.3 检查4个条件是否满足一个(1)构造器不为null,(2)从RootBeanDefinition中获取到的关联的注入方式是构造器注入(没有构造参数就是setter注入,有则是构造器注入)(3)含有构造参数(4)getBean方法传入构造参数不是空 满足其中一个则会调用返回的候选构造器实例化Bean并返回,如果都不满足,则会根据构造参数选则合适的有参构造器然后实例化Bean并返回 5、如果上面都没有合适的构造器,则直接使用无参构造器创建并返回Bean。 填充Bean,populateBean 填充Bean这里还是根据代码来说一下流程 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { PropertyValues pvs = mbd.getPropertyValues(); if (bw == null) { if (!((PropertyValues)pvs).isEmpty()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, \"Cannot apply property values to null instance\"); } } else { boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) { Iterator var6 = this.getBeanPostProcessors().iterator(); while(var6.hasNext()) { BeanPostProcessor bp = (BeanPostProcessor)var6.next(); if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } if (continueWithPropertyPopulation) { if (mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) { MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs); if (mbd.getResolvedAutowireMode() == 1) { this.autowireByName(beanName, mbd, bw, newPvs); } if (mbd.getResolvedAutowireMode() == 2) { this.autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = mbd.getDependencyCheck() != 0; if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { Iterator var9 = this.getBeanPostProcessors().iterator(); while(var9.hasNext()) { BeanPostProcessor bp = (BeanPostProcessor)var9.next(); if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp; pvs = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs); } } this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs); } } } 1、检查当前Bean是否实现了 InstantiationAwareBeanPostProcessor的 postProcessAfterInstantiation方法则调用,并结束Bean的填充。2、将按照类型跟按照名称注入的Bean分开,如果注入的Bean还没有实例化的这里会实例化,然后放到 PropertyValues对象中。3、如果实现了 InstantiationAwareBeanPostProcessor类的 postProcessProperties则调用这个方法并获取返回值,如果返回值是null,则有可能是实现了过期的 postProcessPropertyValues方法,这里需要进一步调用 postProcessPropertyValues方法4、进行参数填充 初始化Bean,initializeBean 初始化Bean同时这里根据代码跟流程图来说明 1、如果Bean实现了 BeanNameAware, BeanClassLoaderAware, BeanFactoryAware则调用对应实现的方法 。2、Bean不为null并且bean不是合成的,如果实现了 BeanPostProcessor的 postProcessBeforeInitialization则会调用实现的 postProcessBeforeInitialization方法。在 ApplicationContextAwareProcessor类中实现了 postProcessBeforeInitialization方法。而这个类会在Spring刷新容器准备 beanFactory的时候会加进去,这里就会被调用,而调用里面会检查Bean是不是 EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware的实现类。这里就会调用对应的实现方法。代码如下 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.setBeanClassLoader(this.getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment())); beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); if (beanFactory.containsBean(\"loadTimeWeaver\")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } if (!beanFactory.containsLocalBean(\"environment\")) { beanFactory.registerSingleton(\"environment\", this.getEnvironment()); } if (!beanFactory.containsLocalBean(\"systemProperties\")) { beanFactory.registerSingleton(\"systemProperties\", this.getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(\"systemEnvironment\")) { beanFactory.registerSingleton(\"systemEnvironment\", this.getEnvironment().getSystemEnvironment()); } }public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { ApplicationContextAwareProcessor.this.invokeAwareInterfaces(bean); return null; } }, acc); } else { this.invokeAwareInterfaces(bean); } return bean; } 1、实例化Bean然后,检查是否实现了 InitializingBean的 afterPropertiesSet方法,如果实现了就会调用2、Bean不为null并且bean不是合成的,如果实现了 BeanPostProcessor的 postProcessBeforeInitialization则会调用实现的 postProcessAfterInitialization方法。 到此创建Bean 的流程就没了,剩下的就是容器销毁的时候的了 三、destory方法跟销毁BeanBean在创建完毕之后会检查用户是否指定了 destroyMethodName以及是否实现了 DestructionAwareBeanPostProcessor接口的 requiresDestruction方法,如果指定了会记录下来保存在 DisposableBeanAdapter对象中并保存在bean的 disposableBeans属性中。代码在 AbstractBeanFactory的 registerDisposableBeanIfNecessary中 12345678910111213141516171819202122232425262728293031323334353637383940414243444546protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) { AccessControlContext acc = System.getSecurityManager() != null ? this.getAccessControlContext() : null; if (!mbd.isPrototype() && this.requiresDestruction(bean, mbd)) { if (mbd.isSingleton()) { this.registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, this.getBeanPostProcessors(), acc)); } else { Scope scope = (Scope)this.scopes.get(mbd.getScope()); if (scope == null) { throw new IllegalStateException(\"No Scope registered for scope name '\" + mbd.getScope() + \"'\"); } scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd, this.getBeanPostProcessors(), acc)); } } }public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition, List<BeanPostProcessor> postProcessors, AccessControlContext acc) { Assert.notNull(bean, \"Disposable bean must not be null\"); this.bean = bean; this.beanName = beanName; this.invokeDisposableBean = this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod(\"destroy\"); this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed(); this.acc = acc; String destroyMethodName = this.inferDestroyMethodIfNecessary(bean, beanDefinition); if (destroyMethodName != null && (!this.invokeDisposableBean || !\"destroy\".equals(destroyMethodName)) && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { this.destroyMethodName = destroyMethodName; this.destroyMethod = this.determineDestroyMethod(); if (this.destroyMethod == null) { if (beanDefinition.isEnforceDestroyMethod()) { throw new BeanDefinitionValidationException(\"Couldn't find a destroy method named '\" + destroyMethodName + \"' on bean with name '\" + beanName + \"'\"); } } else { Class<?>[] paramTypes = this.destroyMethod.getParameterTypes(); if (paramTypes.length > 1) { throw new BeanDefinitionValidationException(\"Method '\" + destroyMethodName + \"' of bean '\" + beanName + \"' has more than one parameter - not supported as destroy method\"); } if (paramTypes.length == 1 && Boolean.TYPE != paramTypes[0]) { throw new BeanDefinitionValidationException(\"Method '\" + destroyMethodName + \"' of bean '\" + beanName + \"' has a non-boolean parameter - not supported as destroy method\"); } } } this.beanPostProcessors = this.filterPostProcessors(postProcessors, bean); } 在销毁Bean的时候最后都会调用 AbstractAutowireCapableBeanFactory的 destroyBean方法。 123public void destroyBean(Object existingBean) { (new DisposableBeanAdapter(existingBean, this.getBeanPostProcessors(), this.getAccessControlContext())).destroy();} 这里是创建一个 DisposableBeanAdapter对象,这个对象实现了Runnable接口,在实现的 run方法中会调用实现的 DisposableBean接口的 destroy方法。并且在创建 DisposableBeanAdapter对象的时候会根据传入的bean是否实现了 DisposableBean接口来设置 invokeDisposableBean变量,这个变量表实有没有实现 DisposableBean接口 DisposableBeanAdapter.java >folded123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960public DisposableBeanAdapter(Object bean, List<BeanPostProcessor> postProcessors, AccessControlContext acc) { Assert.notNull(bean, \"Disposable bean must not be null\"); this.bean = bean; this.beanName = null; this.invokeDisposableBean = this.bean instanceof DisposableBean; this.nonPublicAccessAllowed = true; this.acc = acc; this.beanPostProcessors = this.filterPostProcessors(postProcessors, bean); } public void run() { this.destroy(); }public void destroy() { if (!CollectionUtils.isEmpty(this.beanPostProcessors)) { Iterator var1 = this.beanPostProcessors.iterator(); while(var1.hasNext()) { DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next(); processor.postProcessBeforeDestruction(this.bean, this.beanName); } } if (this.invokeDisposableBean) { if (logger.isDebugEnabled()) { logger.debug(\"Invoking destroy() on bean with name '\" + this.beanName + \"'\"); } try { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { ((DisposableBean)DisposableBeanAdapter.this.bean).destroy(); return null; } }, this.acc); } else { ((DisposableBean)this.bean).destroy(); } } catch (Throwable var3) { String msg = \"Invocation of destroy method failed on bean with name '\" + this.beanName + \"'\"; if (logger.isDebugEnabled()) { logger.warn(msg, var3); } else { logger.warn(msg + \": \" + var3); } } } if (this.destroyMethod != null) { this.invokeCustomDestroyMethod(this.destroyMethod); } else if (this.destroyMethodName != null) { Method methodToCall = this.determineDestroyMethod(); if (methodToCall != null) { this.invokeCustomDestroyMethod(methodToCall); } } } 四、总结 参考文章:参考链接","link":"/java/frame/Spring%E7%9A%84Bean%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.html"},{"title":"算法成长之路leetcode19-20","text":"19. Remove Nth Node From End of ListGiven a linked list, remove the n-th node from the end of list and return its head. Example12345678910111213Example:Given linked list: 1->2->3->4->5, and n = 2.After removing the second node from the end, the linked list becomes 1->2->3->5.Note:Given n will always be valid.Follow up:Could you do this in one pass? JAVA题解方法一:两次遍历算法 思路 我们注意到这个问题可以容易地简化成另一个问题:删除从列表开头数起的第 (L - n + 1)(L−n+1) 个结点,其中 LL 是列表的长度。只要我们找到列表的长度 LL,这个问题就很容易解决。 算法 首先我们将添加一个哑结点作为辅助,该结点位于列表头部。哑结点用来简化某些极端情况,例如列表中只含有一个结点,或需要删除列表的头部。在第一次遍历中,我们找出列表的长度 LL。然后设置一个指向哑结点的指针,并移动它遍历列表,直至它到达第 (L - n)(L−n) 个结点那里。我们把第 (L - n)(L−n) 个结点的 next 指针重新链接至第 (L - n + 2)(L−n+2) 个结点,完成这个算法。 1234567891011121314151617181920212223242526272829/**给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。示例:给定一个链表: 1->2->3->4->5, 和 n = 2.当删除了倒数第二个节点后,链表变为 1->2->3->5.说明:给定的 n 保证是有效的。进阶:你能尝试使用一趟扫描实现吗?*/public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); dummy.next = head; int length = 0; ListNode first = head; while (first != null) { length++; first = first.next; } length -= n; first = dummy; while (length > 0) { length--; first = first.next; } first.next = first.next.next; return dummy.next;} 方法二:一次遍历算法 算法 上述算法可以优化为只使用一次遍历。我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1n+1 步,而第二个指针将从列表的开头出发。现在,这两个指针被 nn 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 nn 个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。 12345678910111213141516171819202122public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); dummy.next = head; ListNode first = dummy; ListNode second = dummy; // Advances first pointer so that the gap between first and second is n nodes apart for (int i = 1; i <= n + 1; i++) { first = first.next; } // Move first to the end, maintaining the gap while (first != null) { first = first.next; second = second.next; } second.next = second.next.next; return dummy.next;}作者:LeetCode链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-by-l/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 20. Valid ParenthesesGiven a string containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[‘ and ‘]’, determine if the input string is valid. An input string is valid if: Open brackets must be closed by the same type of brackets.Open brackets must be closed in the correct order.Note that an empty string is also considered valid. Example123456789101112131415161718192021Example 1:Input: \"()\"Output: trueExample 2:Input: \"()[]{}\"Output: trueExample 3:Input: \"(]\"Output: falseExample 4:Input: \"([)]\"Output: falseExample 5:Input: \"{[]}\"Output: true JAVA题解Leetcode20.java >folded123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147package algorithm;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 * * 有效字符串需满足: * * 左括号必须用相同类型的右括号闭合。 * 左括号必须以正确的顺序闭合。 * 注意空字符串可被认为是有效字符串。 * * 示例 1: * * 输入: \"()\" * 输出: true * 示例 2: * * 输入: \"()[]{}\" * 输出: true * 示例 3: * * 输入: \"(]\" * 输出: false * 示例 4: * * 输入: \"([)]\" * 输出: false * 示例 5: * * 输入: \"{[]}\" * 输出: true * */public class Leetcode20 { // 类似栈的处理 public boolean isValid(String s) { if(s == null || s.equals(\"\")){ return true; } // 奇数 if(s.length() % 2 != 0){ return false; } List<Integer> arr = new ArrayList<>(); Map<Character, Integer> cIn = new HashMap<>(); cIn.put('(', 1); cIn.put(')', -1); cIn.put('{', 2); cIn.put('}', -2); cIn.put('[', 3); cIn.put(']', -3); char[] chars = s.toCharArray(); arr.add(cIn.get(chars[0])); for (int i = 1; i < chars.length; i++) { // 相等则移除 int latestIndex = arr.size() - 1; if (latestIndex >= 0 && arr.get(latestIndex) == -cIn.get(chars[i])) { arr.remove(latestIndex); } else { arr.add(cIn.get(chars[i])); } } if (arr.size() > 0) { return false; } else { return true; } } public static void main(String[] args) { System.out.println(new Leetcode20().isValid(\"([])[]\")); }}// 栈的处理class Solution { public boolean isValid(String s) { if(s.isEmpty()) return true; Stack<Character> stack=new Stack<Character>(); for(char c:s.toCharArray()){ if(c=='(') stack.push(')'); else if(c=='{') stack.push('}'); else if(c=='[') stack.push(']'); else if(stack.empty()||c!=stack.pop()) return false; } if(stack.empty()) return true; return false; }}// 栈 官方class Solution { // Hash table that takes care of the mappings. private HashMap<Character, Character> mappings; // Initialize hash map with mappings. This simply makes the code easier to read. public Solution() { this.mappings = new HashMap<Character, Character>(); this.mappings.put(')', '('); this.mappings.put('}', '{'); this.mappings.put(']', '['); } public boolean isValid(String s) { // Initialize a stack to be used in the algorithm. Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // If the current character is a closing bracket. if (this.mappings.containsKey(c)) { // Get the top element of the stack. If the stack is empty, set a dummy value of '#' char topElement = stack.empty() ? '#' : stack.pop(); // If the mapping for this bracket doesn't match the stack's top element, return false. if (topElement != this.mappings.get(c)) { return false; } } else { // If it was an opening bracket, push to the stack. stack.push(c); } } // If the stack still contains elements, then it is an invalid expression. return stack.isEmpty(); }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode19-20.html"},{"title":"springboot优雅的停止服务","text":"在使用 SpringBoot 的时候,都要涉及到服务的停止和启动,当我们停止服务的时候,很多时候大家都是kill -9 直接把程序进程杀掉,这样程序不会执行优雅的关闭。而且一些没有执行完的程序就会直接退出。 我们很多时候都需要安全的将服务停止,也就是把没有处理完的工作继续处理完成。比如停止一些依赖的服务,输出一些日志,发一些信号给其他的应用系统,这个在保证系统的高可用是非常有必要的。那么咱么就来看一下几种停止 SpringBoot 的方法。 Springboot提供的actuator第一种就是Springboot提供的actuator的功能,它可以执行shutdown, health, info等,默认情况下,actuator的shutdown是disable的,我们需要打开它。首先引入acturator的maven依赖。 1234<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency> 然后将shutdown节点打开,也将/actuator/shutdown暴露web访问也设置上,除了shutdown之外还有health, info的web访问都打开的话将management.endpoints.web.exposure.include=*就可以。将如下配置设置到application.properties里边。设置一下服务的端口号为3333。 123server.port=3333management.endpoint.shutdown.enabled=truemanagement.endpoints.web.exposure.include=shutdown 接下来,咱们创建一个springboot工程,然后设置一个bean对象,配置上PreDestroy方法。这样在停止的时候会打印语句。bean的整个生命周期分为创建、初始化、销毁,当最后关闭的时候会执行销毁操作。在销毁的方法中执行一条输出日志。 12345678910111213141516package com.hqs.springboot.shutdowndemo.bean;import javax.annotation.PreDestroy;/** * @author huangqingshi * @Date 2019-08-17 */public class TerminateBean { @PreDestroy public void preDestroy() { System.out.println(\"TerminalBean is destroyed\"); }} 做一个configuration,然后提供一个获取bean的方法,这样该bean对象会被初始化。 123456789101112131415161718package com.hqs.springboot.shutdowndemo.config;import com.hqs.springboot.shutdowndemo.bean.TerminateBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @author huangqingshi * @Date 2019-08-17 */@Configurationpublic class ShutDownConfig { @Bean public TerminateBean getTerminateBean() { return new TerminateBean(); }} 在启动类里边输出一个启动日志,当工程启动的时候,会看到启动的输出,接下来咱们执行停止命令。 1curl -X POST http://localhost:3333/actuator/shutdown 以下日志可以输出启动时的日志打印和停止时的日志打印,同时程序已经停止。是不是比较神奇。 context.close第二种方法也比较简单,获取程序启动时候的context,然后关闭主程序启动时的context。这样程序在关闭的时候也会调用PreDestroy注解。如下方法在程序启动十秒后进行关闭。 1234567891011/* method 2: use ctx.close to shutdown all application context */ ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } ctx.close(); springboot启动写入app.pid第三种方法,在springboot启动的时候将进程号写入一个app.pid文件,生成的路径是可以指定的,可以通过命令 cat /Users/huangqingshi/app.id | xargs kill 命令直接停止服务,这个时候bean对象的PreDestroy方法也会调用的。这种方法大家使用的比较普遍。写一个start.sh用于启动springboot程序,然后写一个停止程序将服务停止。 12345/* method 3 : generate a pid in a specified path, while use command to shutdown pid : 'cat /Users/huangqingshi/app.pid | xargs kill' */ SpringApplication application = new SpringApplication(ShutdowndemoApplication.class); application.addListeners(new ApplicationPidFileWriter(\"/Users/huangqingshi/app.pid\")); application.run(); SpringApplication.exit()第四种方法,通过调用一个SpringApplication.exit()方法也可以退出程序,同时将生成一个退出码,这个退出码可以传递给所有的context。这个就是一个JVM的钩子,通过调用这个方法的话会把所有PreDestroy的方法执行并停止,并且传递给具体的退出码给所有Context。通过调用System.exit(exitCode)可以将这个错误码也传给JVM。程序执行完后最后会输出:Process finished with exit code 0,给JVM一个SIGNAL。 123456789/* method 4: exit this application using static method */ ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args); this.exitApplication(ctx);public static void exitApplication(ConfigurableApplicationContext context) { int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0); System.exit(exitCode); } Controller获取程序的context关闭第五种方法,自己写一个Controller,然后将自己写好的Controller获取到程序的context,然后调用自己配置的Controller方法退出程序。通过调用自己写的/shutDownContext方法关闭程序:curl -X POST http://localhost:3333/shutDownContext。 123456789101112131415161718192021222324252627282930313233343536package com.hqs.springboot.shutdowndemo.controller;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;/** * @author huangqingshi * @Date 2019-08-17 */@RestControllerpublic class ShutDownController implements ApplicationContextAware { private ApplicationContext context; @PostMapping(\"/shutDownContext\") public String shutDownContext() { ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) context; ctx.close(); return \"context is shutdown\"; } @GetMapping(\"/\") public String getIndex() { return \"OK\"; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; }} 好了,springboot的优雅关闭方法也都实现好了,也有同学问,如何暴力停止呢,简单,直接kill -9 相应的PID即可。 总结一下:以上这几种方法实现的话比较简单,但是真实工作中还需要考虑的点还很多,比如需要保护暴露的点不被别人利用,一般要加一些防火墙,或者只在内网使用,保证程序安全。 在真实的工作中的时候第三种比较常用,程序中一般使用内存队列或线程池的时候最好要优雅的关机,将内存队列没有处理的保存起来或线程池中没处理完的程序处理完。但是因为停机的时候比较快,所以停服务的时候最好不要处理大量的数据操作,这样会影响程序停止。 参考文章:参考链接1","link":"/java/frame/springboot%E4%BC%98%E9%9B%85%E7%9A%84%E5%81%9C%E6%AD%A2%E6%9C%8D%E5%8A%A1.html"},{"title":"算法成长之路leetcode17-18","text":"17. Letter Combinations of a Phone NumberGiven a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters. Example12345678Example:Input: \"23\"Output: [\"ad\", \"ae\", \"af\", \"bd\", \"be\", \"bf\", \"cd\", \"ce\", \"cf\"].Note:Although the above answer is in lexicographical order, your answer could be in any order you want. JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111package algorithm;import java.util.*;/** * 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 * * 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 * 示例: 输入:\"23\" 输出:[\"ad\", \"ae\", \"af\", \"bd\", \"be\", \"bf\", \"cd\", \"ce\", \"cf\"]. */public class Leetcode17 { public static List<String> letterCombinations(String digits) { List<String> res = new ArrayList<>(); String[] indexToStr = new String[]{\"\", \"\", \"abc\", \"def\", \"ghi\", \"jkl\", \"mno\", \"pqrs\", \"tuv\", \"wxyz\"}; if (digits == null || \"\".equals(digits)) return res; else if(digits.length() == 1) { char[] chars = indexToStr[Integer.parseInt(digits)].toCharArray(); for (int i = 0; i < chars.length; i++) { res.add(new String(new char[]{chars[i]})); } } char[] charArray = digits.toCharArray(); char[] i0Char = indexToStr[(int) charArray[0] - (int) ('0')].toCharArray(); for (int i = 1; i < charArray.length; i++) { for (int i1 = 0; i1 < i0Char.length; i1++) { char[] chars1 = indexToStr[(int) charArray[i] - (int) ('0')].toCharArray(); for (int i2 = 0; i2 < chars1.length; i2++) { res.add(new String(new char[]{i0Char[i1], chars1[i2]})); } } } return res; } Map<String, String> phone = new HashMap<String, String>() {{ put(\"2\", \"abc\"); put(\"3\", \"def\"); put(\"4\", \"ghi\"); put(\"5\", \"jkl\"); put(\"6\", \"mno\"); put(\"7\", \"pqrs\"); put(\"8\", \"tuv\"); put(\"9\", \"wxyz\"); }}; List<String> output = new ArrayList<String>(); public void backtrack(String combination, String next_digits) { // if there is no more digits to check if (next_digits.length() == 0) { // the combination is done output.add(combination); } // if there are still digits to check else { // iterate over all letters which map // the next available digit String digit = next_digits.substring(0, 1); String letters = phone.get(digit); for (int i = 0; i < letters.length(); i++) { String letter = phone.get(digit).substring(i, i + 1); // append the current letter to the combination // and proceed to the next digits backtrack(combination + letter, next_digits.substring(1)); } } } /** * 方法:回溯 * 回溯是一种通过穷举所有可能情况来找到所有解的算法。如果一个候选解最后被发现并不是可行解,回溯算法会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。 * * 给出如下回溯函数 backtrack(combination, next_digits) ,它将一个目前已经产生的组合 combination 和接下来准备要输入的数字 next_digits 作为参数。 * * 如果没有更多的数字需要被输入,那意味着当前的组合已经产生好了。 * 如果还有数字需要被输入: * 遍历下一个数字所对应的所有映射的字母。 * 将当前的字母添加到组合最后,也就是 combination = combination + letter 。 * 重复这个过程,输入剩下的数字: backtrack(combination + letter, next_digits[1:]) 。 * * 有动画图解 * 作者:LeetCode * 链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/solution/dian-hua-hao-ma-de-zi-mu-zu-he-by-leetcode/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * @param digits * @return */ public List<String> letterCombinations1(String digits) { if (digits.length() != 0) backtrack(\"\", digits); return output; } public static void main(String[] args) { System.out.println(letterCombinations(\"3\")); System.out.println(new Leetcode17().letterCombinations1(\"234\")); }} 18. 4SumGiven an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target. Note: The solution set must not contain duplicate quadruplets. Example1234567891011Example:Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.A solution set is:[ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2]] JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154package algorithm;import java.util.ArrayList;import java.util.Arrays;import java.util.List;/** * 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d , * 使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 * * 注意: * * 答案中不可以包含重复的四元组。 * * 示例: * * 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 * * 满足要求的四元组集合为: * [ * [-1, 0, 0, 1], * [-2, -1, 1, 2], * [-2, 0, 0, 2] * ] * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/4sum * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode18 { /** * 思路: * * 四数之和与前面三数之和的思路几乎是一样的,嗝。(刚好前些天才写了三数之和的题解) * 如果前面的三数之和会做了的话,这里其实就是在前面的基础上多添加一个遍历的指针而已。 * 会做三数之和的可以不用看下面的了。。 * * 使用四个指针(a<b<c<d)。固定最小的a和b在左边,c=b+1,d=_size-1 移动两个指针包夹求解。 * 保存使得nums[a]+nums[b]+nums[c]+nums[d]==target的解。偏大时d左移,偏小时c右移。c和d相 * 遇时,表示以当前的a和b为最小值的解已经全部求得。b++,进入下一轮循环b循环,当b循环结束后。 * a++,进入下一轮a循环。 即(a在最外层循环,里面嵌套b循环,再嵌套双指针c,d包夹求解)。 * 准备工作: * * 因为要使用双指针的方法,排序是必须要做der~。 时间复杂度O(NlogN). * * 作者:misakasagiri-2 * 链接:https://leetcode-cn.com/problems/4sum/solution/shuang-zhi-zhen-jie-fa-can-zhao-san-shu-zhi-he-ge-/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * * @param nums * @param target * @return */ public List<List<Integer>> fourSum(int[] nums, int target) { /*定义一个返回值*/ List<List<Integer>> result = new ArrayList<>(); /*当数组为null或元素小于4个时,直接返回*/ if (nums == null || nums.length < 4) { return result; } /*对数组进行从小到大排序*/ Arrays.sort(nums); System.out.println(\"-4,-1,-1,0,1,2\"); /*数组长度*/ int length = nums.length; /*定义4个指针k,i,j,h k从0开始遍历,i从k+1开始遍历,留下j和h,j指向i+1,h指向数组最大值*/ for (int k = 0; k < length - 3; k++) { /*当k的值与前面的值相等时忽略*/ if (k > 0 && nums[k] == nums[k - 1]) { continue; } /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏*/ int min1 = nums[k] + nums[k + 1] + nums[k + 2] + nums[k + 3]; if (min1 > target) { break; } /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/ int max1 = nums[k] + nums[length - 1] + nums[length - 2] + nums[length - 3]; if (max1 < target) { continue; } /*第二层循环i,初始值指向k+1*/ for (int i = k + 1; i < length - 2; i++) { /*当i的值与前面的值相等时忽略*/ if (i > k + 1 && nums[i] == nums[i - 1]) { continue; } /*定义指针j指向i+1*/ int j = i + 1; /*定义指针h指向数组末尾*/ int h = length - 1; /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏,忽略*/ int min = nums[k] + nums[i] + nums[j] + nums[j + 1]; if (min > target) { System.out.println(\"m,k=\"+k+\",i=\"+i+\",j=\"+j+\",j+1=\"+(j+1)); break; // 此时直接滑动k,因为不管怎么滑动i,min 都会大于target } /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/ int max = nums[k] + nums[i] + nums[h] + nums[h - 1]; if (max < target) { System.out.println(\"ma,k=\"+k+\",i=\"+i+\",j=\"+j+\",j+1=\"+(j+1)); continue; // 此时continue滑动i 值,nums[i] + nums[h] + nums[h - 1] 变大 ,整个max 会变大 } /** * -4,-1,-1,0,1,2 * ma,k=0,i=1,j=2,j+1=3 * m,k=1,i=3,j=4,j+1=5 * [[-4, 0, 1, 2], [-1, -1, 0, 1]] * * -4,-1,-1,0,1,2 * ma,k=0,i=1,j=2,j+1=3 * m,k=1,i=3,j=4,j+1=5 * [[-1, -1, 0, 1]] */ /*开始j指针和h指针的表演,计算当前和,如果等于目标值,j++并去重,h--并去重,当当前和大于目标值时h--,当当前和小于目标值时j++*/ while (j < h) { int curr = nums[k] + nums[i] + nums[j] + nums[h]; if (curr == target) { result.add(Arrays.asList(nums[k], nums[i], nums[j], nums[h])); j++; while (j < h && nums[j] == nums[j - 1]) { j++; } h--; while (j < h && i < h && nums[h] == nums[h + 1]) { h--; } } else if (curr > target) { h--; } else { j++; } } } } return result; } /* 作者:you-wei-wu 链接:https://leetcode-cn.com/problems/4sum/solution/ji-bai-9994de-yong-hu-you-dai-ma-you-zhu-shi-by-yo/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 */ public static void main(String[] args) { System.out.println(new Leetcode18().fourSum(new int[]{-1,0,1,2,-1,-4},-1)); }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode17-18.html"},{"title":"springboot-restful-swagger实战","text":"一、目标 了解 Restful 是什么,基本概念及风格; 能使用SpringBoot 实现一套基础的 Restful 风格接口; 利用Swagger 生成清晰的接口文档。 二、Restful 入门什么是REST 摘自百科的定义:REST即表述性状态转移(英文:Representational State Transfer,简称REST) 是Roy Fielding博士(HTTP规范主要贡献者)在2000年的论文中提出来的一种软件架构风格。 是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。 通俗点说,REST就是一组架构约束准则;在这些准则中,有不少是利用了现有的WEB标准能力。 而最终的目的则是简化当前业务层的设计及开发工作。 Restful API 则是指符合REST架构约束的API,关于这个词在早年前其实已经非常流行,但大多数开发者对其仍然 处于观望状态,并不一定会立即采用。这个相信与当时技术社区的成熟度及氛围是密切相关。 无论如何,在微服务架构如此流行的今天,Restful API已经成为了一种必备的的标准设计风格。 关键要点 理解 Restful 风格需要理解以下几点: 资源 资源指的就是一个抽象的信息实体,可以是一个用户、一首歌曲、一篇文章,只要是可作为引用的对象就是资源。 每个资源通常会被映射到一个URI,通过访问这个URI可以获取到信息。 资源的表述 资源表述(Representation)指的则是资源的外在表现形式 比如一个帖子,可以通过HTML格式展现,也可以通过XML、JSON等格式输出到客户端。 在前面的文章(SpringBoot-Scope详解)中提到,HTTP协议通过MIME来统一定义数据信息的格式标准。 通常,Accept、Content-Type可以用来指定客户端及服务端可接受的信息格式,而这个就是资源的表述 状态转移 在HTTP访问过程中,资源的状态发生变化。这里会涉及到以下的几个动词: 名称 语义 GET 获取资源 POST 新建资源 PUT 更新资源 DELETE 删除资源 对于不同的访问方法,服务器会产生对应的行为并促使资源状态产生转换。 关于无状态 Restful 是无状态的设计,这点意味着交互过程中的请求应该能包含所有需要的信息,而不需要依赖于已有的上下文。 然而 JavaEE中存在一些违背的做法,比如Cookie中设置JSESSIONID, 在多次请求间传递该值作为会话唯一标识,这标识着服务端必须保存着这些会话状态数据。 PlayFramework框架实现了无状态的Session,其将会话数据经过加密编码并置入Cookie中, 这样客户端的请求将直接携带上全部的信息,是无状态的请求,这点非常有利于服务端的可扩展性。 三、SpringBoot 实现 Restful接下来,我们利用 SpringBoot 来实现一个Restful 风格的样例。 说明基于 PetStore(宠物店) 的案例,实现对某顾客(Customer)名下的宠物(Pet)的增删改查。 1. 实体定义Customer 1234@Datapublic class Customer { private String name;} Customer 只包含一个name属性,我们假定这是唯一的标志。 Pet 1234567@Datapublic class Pet { private String petId; private String name; private String type; private String description;} Pet 包含了以下几个属性 属性名 描述 petId 宠物ID编号 name 宠物名称 type 宠物类型 description 2. URL资源基于Restful 的原则,我们定义了以下的一组URL: 接口 方法 URL 添加宠物 POST /rest/pets/{customer} 获取宠物列表 GET /rest/pets/{customer} 获取宠物信息 GET /rest/pets/{customer}/{petId} 更新宠物信息 PUT /rest/pets/{customer}/{petId} 删除宠物 DELETE /rest/pets/{customer}/{petId} 3. 数据管理接下来实现一个PetManager 类,用于模拟在内存中对Pet数据进行增删改查 代码如下: PetManager.java >folded123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127@Componentpublic class PetManager { private static Map<String, Customer> customers = new ConcurrentHashMap<String, Customer>(); private static Map<String, Map<String, Pet>> pets = new ConcurrentHashMap<String, Map<String, Pet>>(); // 启动时初始化,执行一次 @PostConstruct public void init() { String[] customerNames = new String[]{\"Lilei\", \"Hanmeimei\", \"Jim Green\"}; for (String customerName : customerNames) { customers.put(customerName, new Customer(customerName)); } } /** * 获取customer * * @param customer * @return */ public Customer getCustomer(String customer) { if (StringUtils.isEmpty(customer)) { return null; } return customers.get(customer); } /** * 获取customer名下的 pet 列表 * * @param customer * @return */ public List<Pet> getPets(String customer) { if (StringUtils.isEmpty(customer)) { return Collections.emptyList(); } if (!pets.containsKey(customer)) { return Collections.emptyList(); } return pets.get(customer).values().stream().collect(Collectors.toList()); } /** * 获取某个pet * * @param customer * @param petId * @return */ public Pet getPet(String customer, String petId) { if (StringUtils.isEmpty(customer) || StringUtils.isEmpty(petId)) { return null; } if (!pets.containsKey(customer)) { return null; } return pets.get(customer).get(petId); } /** * 删除pet * * @param customer * @param petId * @return */ public boolean removePet(String customer, String petId) { if (StringUtils.isEmpty(customer) || StringUtils.isEmpty(petId)) { return false; } if (!pets.containsKey(customer)) { return false; } return pets.get(customer).remove(petId) != null; } /** * 添加pet * * @param customer * @param pet * @return */ public Pet addPet(String customer, Pet pet) { if (StringUtils.isEmpty(customer) || pet == null) { return null; } Map<String, Pet> customerPets = null; if (!pets.containsKey(customer)) { customerPets = new LinkedHashMap<String, Pet>(); Map<String, Pet> previous = pets.putIfAbsent(customer, customerPets); // 已经存在 if (previous != null) { customerPets = previous; } } else { customerPets = pets.get(customer); } if (pet.getPetId() == null) { pet.setPetId(UUID.randomUUID().toString()); } customerPets.put(pet.getPetId(), pet); return pet; } /** * 更新某个pet * * @param customer * @param petPojo * @return */ public Pet updatePet(String customer, Pet petPojo) { if (StringUtils.isEmpty(customer) || petPojo == null) { return null; } if (petPojo.getPetId() == null) { return null; } Pet pet = getPet(customer, petPojo.getPetId()); pet.setType(petPojo.getType()); pet.setName(petPojo.getName()); pet.setDescription(petPojo.getDescription()); return pet; }} 4. 控制层实现SpringBoot 提供了 @RestController,用于快速定义一个Restful 风格的Controller类**@RestController=@ResponseBody + @Controller** RestApiController.java >folded1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889@RestController@RequestMapping(\"/rest/pets/{customer}\")public class RestApiController { @Autowired private PetManager dataManager; /** * 添加宠物 * * @param customer * @param pet * @return */ @PostMapping public ResponseEntity<Object> addPet(@PathVariable String customer, @RequestBody Pet pet) { validateCustomer(customer); Pet newPet = dataManager.addPet(customer, pet);// 返回 201.created if (newPet != null) { URI location = ServletUriComponentsBuilder.fromCurrentRequest().path(\"/{petId}\") .buildAndExpand(newPet.getPetId()).toUri(); return ResponseEntity.created(location).build(); }// 返回 204.noContent return ResponseEntity.noContent().build(); } /** * 获取宠物列表 * * @param customer * @return */ @GetMapping @ResponseBody public List<Pet> listPets(@PathVariable String customer) { validateCustomer(customer); List<Pet> pets = dataManager.getPets(customer); return pets; } /** * 获取某个宠物 * * @param customer * @param petId */ @GetMapping(\"/{petId}\") @ResponseBody public Pet getPet(@PathVariable String customer, @PathVariable String petId) { validateCustomer(customer); validatePet(customer, petId); Pet pet = dataManager.getPet(customer, petId); return pet; } /** * 更新宠物信息 * * @param customer * @param petId * @param pet */ @PutMapping(\"/{petId}\") public ResponseEntity<Object> updatePet(@PathVariable String customer, @PathVariable String petId, @RequestBody Pet pet) { validateCustomer(customer); validatePet(customer, petId); pet.setPetId(petId); Pet petObject = dataManager.updatePet(customer, pet); if (petObject != null) { return ResponseEntity.ok(petObject); } return ResponseEntity.noContent().build(); } /** * 删除某个宠物 * * @param customer * @param petId * @return */ @DeleteMapping(\"/{petId}\") public ResponseEntity<Object> removePet(@PathVariable String customer, @PathVariable String petId) { validateCustomer(customer); validatePet(customer, petId); dataManager.removePet(customer, petId); return ResponseEntity.ok().build(); } 上述代码中已经实现了完整的增删改查语义。 在Restful 风格的API 接口定义中,往往会引用 HTTP 状态码用于表示不同的结果,比如一些错误的状态类型。 这里我们对Customer、Pet 进行存在性校验,若资源不存在返回404_NotFound。 123456789101112131415161718192021/** * 校验customer是否存在 * * @param customer */ private void validateCustomer(String customer) { if (dataManager.getCustomer(customer) == null) { throw new ObjectNotFoundException(String.format(\"the customer['%s'] is not found\", customer)); } } /** * 校验pet是否存在 * * @param customer */ private void validatePet(String customer, String petId) { if (dataManager.getPet(customer, petId) == null) { throw new ObjectNotFoundException(String.format(\"the pet['%s/%s'] is not found\", customer, petId)); } } 自定义异常拦截 123456789101112131415161718/** * ⾃定义异常,及拦截逻辑 * * @author atp */ @SuppressWarnings(\"serial\") public static class ObjectNotFoundException extends RuntimeException { public ObjectNotFoundException(String msg) { super(msg); } } @ResponseBody @ExceptionHandler(ObjectNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public String objectNotFoundExceptionHandler(ObjectNotFoundException ex) { return ex.getMessage(); } 5.接口请求示例1. 添加宠物URL POST http:///rest/pets/LiLei 请求内容 12345{ \"name\": \"Smart Baby\", \"description\": \"very small and smart also.\", \"type\": \"Dog\"} 2. 获取宠物列表**URL **GET http:///rest/pets/LiLei 返回 1234567891011[{ \"petId\": \"b5400334-e7b3-42f1-b192-f5e7c3193543\", \"name\": \"Smart Baby\", \"type\": \"Dog\", \"description\": \"very small and smart also.\"}, { \"petId\": \"610780af-94f1-4011-a175-7a0f3895163d\", \"name\": \"Big Cat\", \"type\": \"Cat\", \"description\": \"very old but I like it.\"}] 3. 查询宠物信息URL GET http:///rest/pets/LiLei/b5400334-e7b3-42f1-b192-f5e7c3193543 返回 123456{ \"petId\": \"b5400334-e7b3-42f1-b192-f5e7c3193543\", \"name\": \"Smart Baby\", \"type\": \"Dog\", \"description\": \"very small and smart also.\"} 4. 更新宠物信息**URL ** PUT http:///rest/pets/LiLei/b5400334-e7b3-42f1-b192-f5e7c3193543 请求内容 12345 { \"name\": \"Big Cat V2\", \"description\": \"I don't like it any more\", \"type\": \"Cat\"} 返回 123456{ \"petId\": \"a98e4478-e754-4969-851b-bcaccd67263e\", \"name\": \"Big Cat V2\", \"type\": \"Cat\", \"description\": \"I don't like it any more\"} 5. 删除宠物**URL **DELETE http:///rest/pets/LiLei/b5400334-e7b3-42f1-b192-f5e7c3193543 相关出错 客户不存在:404 the customer[‘test’] is not found 宠物不存在:404 the pet[‘LiLei/b5400334-e7b3-42f1-b192-f5e7c31935431’] is not found 四、Swagger 的使用关于Swagger Swagger是目前非常流行的一个API设计开发框架(基于OpenApi), 可用于API的设计、管理、代码生成以及Mock测试等。 目前Swagger的应用非常广,其涵盖的开源模块也比较多,这里将使用swagger-ui实现API在线DOC的生成。 引入依赖 12345678910<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version></dependency> 定义API配置 12345678910111213141516171819202122232425262728@EnableSwagger2@Configurationpublic class SwaggerConfig { public static final String VERSION = \"1.0.0\"; @Value(\"${swagger.enable}\") private boolean enabled; ApiInfo apiInfo() { return new ApiInfoBuilder(). title(\"Pet Api Definition\") .description(\"The Petstore CRUD Example\") .license(\"Apache 2.0\") .licenseUrl(\"http://www.apache.org/licenses/LICENSE-2.0.html\") .termsOfServiceUrl(\"\") .version(VERSION) .contact(new Contact(\"\", \"\", \"zalesfoo@163.com\")) .build(); } @Bean public Docket customImplementation() { return new Docket(DocumentationType.SWAGGER_2).select() .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) .build() .enable(enabled) .apiInfo(apiInfo()); }} @EnableSwagger2声明了Swagger的启用,Docket的Bean定义是API配置的入口, 可以设置API名称、版本号,扫描范围等。 声明API描述 在原有的Controller 方法上添加关于API的声明,如下: 1234567891011121314151617@Api(value = \"Pet Restful api\")@RestController@RequestMapping(\"/rest/pets/{customer}\")public class RestApiController { @ApiOperation(\"添加宠物\") @ApiImplicitParams({ @ApiImplicitParam(paramType = \"path\", name = \"customer\", dataType = \"String\", required = true, value = \"客户名\", defa @ApiImplicitParam(paramType = \"body\", name = \"pet\", dataType = \"Pet\", required = true, value = \"pet 请求\", defaultVal @ApiResponses({ @ApiResponse(code = 201, message = \"添加成功\"), @ApiResponse(code = 404, message = \"资源不存在\")}) @PostMapping public ResponseEntity<Object>addPet(@PathVariable String customer, @RequestBody Pet pet){ } }} 为了能描述返回对象的文档说明,为Pet类做API声明: 1234567891011@ApiModel(\"宠物信息\")public class Pet { @ApiModelProperty(name = \"petId\", value = \"宠物ID\") private String petId; @ApiModelProperty(name = \"name\", value = \"宠物名称\") private String name; @ApiModelProperty(name = \"type\", value = \"宠物类型\") private String type; @ApiModelProperty(name = \"description\", value = \"宠物描述\") private String description;} 相关的注解 注解 描述 @ApiModelProperty 用在出入参数对象的字段上 @Api 用于controller类 @ApiOperation 用于controller方法,描述操作 @ApiResponses 用于controller方法,描述响应 @ApiResponse 用于@ApiResponses内,描述单个响应结果 @ApiImplicitParams 用于controller的方法,描述入参 @ApiImplicitParam 用于@ApiImplicitParams内,描述单个入参 @ApiModel 用于返回对象类 访问文档 最后,访问 http://localhost:8000/swagger_ui.html ,可看到生成的文档界面: 参考文章:参考链接","link":"/java/frame/springboot-restful-swagger%E5%AE%9E%E6%88%98.html"},{"title":"算法成长之路leetcode15-16","text":"15. 3SumGiven an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: The solution set must not contain duplicate triplets. Example123456789Example:Given array nums = [-1, 0, 1, 2, -1, -4],A solution set is:[ [-1, 0, 1], [-1, -1, 2]] JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293package algorithm;import java.util.*;/** * 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c , * 使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 * * 注意:答案中不可以包含重复的三元组。 * * 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], * * 满足要求的三元组集合为: * [ * [-1, 0, 1], * [-1, -1, 2] * ] * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/3sum * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode15 { // ❌错解 public static List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> res = new ArrayList<>(); Set<String> ids = new HashSet<>(); for (int i = 0; i < nums.length - 2; i++) { for (int j = i+1; j < nums.length-1; j++) { for (int k = j+1; k < nums.length; k++) { if(nums[i]+nums[j]+nums[k] == 0){ String i2 = nums[i] + \"\"+nums[j]+nums[k]; System.out.println(nums[i]+\",\"+nums[j]+\",\"+nums[k]+\"=\"+i2); if(!ids.contains(i2)){ ids.add(i2); res.add(Arrays.asList(nums[i],nums[j],nums[k])); } } } } } return res; } /** * 思路 * 标签:数组遍历 * 首先对数组进行排序,排序后固定一个数 nums[i]nums[i],再使用左右指针指向 nums[i]nums[i]后面的两端,数字分别为 nums[L]nums[L] 和 nums[R]nums[R],计算三个数的和 sumsum 判断是否满足为 00,满足则添加进结果集 * 如果 nums[i]nums[i]大于 00,则三数之和必然无法等于 00,结束循环 * 如果 nums[i]nums[i] == nums[i-1]nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过 * 当 sumsum == 00 时,nums[L]nums[L] == nums[L+1]nums[L+1] 则会导致结果重复,应该跳过,L++L++ * 当 sumsum == 00 时,nums[R]nums[R] == nums[R-1]nums[R−1] 则会导致结果重复,应该跳过,R--R−− * 时间复杂度:O(n^2),n 为数组长度 * * 作者:guanpengchn * 链接:https://leetcode-cn.com/problems/3sum/solution/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * @param nums * @return */ public static List<List<Integer>> threeSum1(int[] nums) { List<List<Integer>> ans = new ArrayList(); int len = nums.length; if (nums == null || len < 3) return ans; Arrays.sort(nums); // 排序 for (int i = 0; i < len; i++) { if (nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环 if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重 int L = i + 1; int R = len - 1; while (L < R) { int sum = nums[i] + nums[L] + nums[R]; if (sum == 0) { ans.add(Arrays.asList(nums[i], nums[L], nums[R])); // 此时nums[L] == nums[L + 1] 会重复,继续跳过一个 while (L < R && nums[L] == nums[L + 1]) L++; // 去重 while (L < R && nums[R] == nums[R - 1]) R--; // 去重 L++; R--; } else if (sum < 0) L++; else if (sum > 0) R--; } } return ans; } public static void main(String[] args) { System.out.println(threeSum(new int[]{-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6})); }} 16. 3Sum ClosestGiven an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution. Example123456Example:Given array nums = [-1, 2, 1, -4], and target = 1.The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). JAVA题解12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667package algorithm;import java.util.Arrays;/** * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数, * 使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 * * 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. * * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/3sum-closest * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode16 { // 想到的思路,找出所有的组合以及它们的sum,然后排好序二分法查找sum中最接近的 public int threeSumClosest(int[] nums, int target) { return 0; } /** * 思路 * 标签:排序和双指针 * 本题目因为要计算三个数,如果靠暴力枚举的话时间复杂度会到 O(n^3),需要降低时间复杂度 * 首先进行数组排序,时间复杂度 O(nlogn)O(nlogn) * 在数组 nums 中,进行遍历,每遍历一个值利用其下标i,形成一个固定值 nums[i] * 再使用前指针指向 start = i + 1 处,后指针指向 end = nums.length - 1 处,也就是结尾处 * 根据 sum = nums[i] + nums[start] + nums[end] 的结果,判断 sum 与目标 target 的距离,如果更近则更新结果 ans * 同时判断 sum 与 target 的大小关系,因为数组有序,如果 sum > target 则 end--,如果 sum < target 则 start++,如果 sum == target 则说明距离为 0 直接返回结果 * 整个遍历过程,固定值为 n 次,双指针为 n 次,时间复杂度为 O(n^2) * 总时间复杂度:O(nlogn) + O(n^2) = O(n^2) * * 作者:guanpengchn * 链接:https://leetcode-cn.com/problems/3sum-closest/solution/hua-jie-suan-fa-16-zui-jie-jin-de-san-shu-zhi-he-b/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * @param nums * @param target * @return */ public int threeSumClosest1(int[] nums, int target) { Arrays.sort(nums); int ans = nums[0] + nums[1] + nums[2]; for(int i=0;i<nums.length;i++) { int start = i+1, end = nums.length - 1; while(start < end) { int sum = nums[start] + nums[end] + nums[i]; // 结果差值更小时,取更小的 if(Math.abs(target - sum) < Math.abs(target - ans)) ans = sum; // 结果大于目标,右边的左移 if(sum > target) end--; else if(sum < target) start++; else // 相等时直接返回结果 return ans; } } return ans; }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode15-16.html"},{"title":"2019年终总结","text":"时间过得太快了,感觉每天时间都不够用,一眨眼一年又过去了! 也没啥特总结的,就几句话:革命尚未成功,还得加倍努力。珍惜时间,珍惜生命,珍惜眼前人。充满正能量的度过往后余生。","link":"/think/2019%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93.html"},{"title":"西安旅游攻略3日游","text":"西安,长安! Day1陕西历史博物馆之前很少坐火车,特别是长途的火车,想体验一下长时间的坐火车感受,选择了比较慢的K字头的绿皮火车,一路颠簸的去了西安,一整晚没睡着,简直太困了。预算够的话尽量选择高铁、动车、飞机,少花些时间在交通工具上,因为费时又费神。没特殊情况以后是再也不做慢车了😂。早上八点多到达西安南站, 下车之后打开高德地图,因为提前预定了陕西历史博物馆的门票(有免费票-基本陈列物,对于普通人差不多就够了,比较专业人士可以预约购买另外两种票,好像分别30和270,在陕西历史博物馆公众号上预约购买),9.0-10.30入场的票。然后就导航去博物馆,发现有个公交车可以直接到,然后去站台没看到那公交,也不知道什么情况。来了一个去历史地铁站的大巴,然后就上了,比公交贵两块,感觉还行,挺方便。 下了大巴直接做地铁去了西安历史博物馆。 到了历史博物馆后,预约票取票在西南口。和普通买票的地方分开的,不要排错了地方!人比较多,注意合理安排错峰时间。 整个游览过程大概一个多小时。 推荐指数:4星 小雁塔之前马蜂窝上看到推荐的,现场刷身份证入场。免费。有小雁塔和一个博物馆,文物也是一些历史文物,还是值得一看,冬季去,里面腊梅正开着,很香。 整个游览过程大概一小时之内。 推荐指数:3.5星 赛格购物中心网红购物中心,6楼全是美食,又很多网红餐厅,没去吃,只点了一杯酸奶牛。没想象中那么震惊,说是最长的扶梯。结果是一层一层的,加起来最长。进门能够看到一个最大的室内瀑布,还挺美的。 整个游览过程因人而异,花不了多长时间。 推荐指数:3.5星 上面几个地方想个不远,游完就去了酒店。酒店在钟楼附近,办理好入住,大概1点左右,点了些外卖,吃了就睡了一会儿,前一天晚上基本没睡,太累了。大概4点多睡醒了,收拾收拾出门了。 西安城墙大概5点多,溜到了西安城墙的永宁门,也就是南门,东南西北都有门可以进入,每个门最晚入门时间不一样,提前查好。门票54,城墙上有租自行车的45一人,任何一个还车点都能还。城墙全长14KM左右,我走完用了2h.20min,还是比较快的,根据自己情况预算时间。建议一定晚上去,晚上城墙上有很多灯笼🏮,夜景很好,建议去走一圈,感觉很好,那种感觉就像是自己是皇帝一样,走在上面看着自己的江山。城墙上能够看到日落和月亮,选择好的天气去,真的很重要。 整个游览过程因人而异,2-4小时。 推荐指数:4.5星 Day2第二天报了团,强烈建议报中超旅行的团,价格260(兵马俑+华清池+临潼博物馆+午饭),导游张丽美,感觉讲的超级好。报团可以很方便的接送去景区,以及推荐一些好的东西,讲解一些当地城市的真正旅游文化。 兵马俑为了错峰,上午去看了兵马俑。西安兵马俑必去 之地就不必多介绍了,自己去感受。看完兵马俑就去吃饭了。 整个游览过程因人而异,2-4小时。 推荐指数:4.5星 蓝田玉商场中午吃饭的时候,去逛了逛,蓝田玉产地,有手镯(妈妈),芙蓉玉(老婆、女朋友),给自己的妈妈,老婆买一个真的不能太好了。可以去逛下,离华清池不远,说是全是12315认证过得,比其他地方的便宜。通过历往经验来看导游的话多数情况都信不得,景区的商品10有8、9是坑,自己多辨别,提前上网多查查,不要被坑了,被导游的片面之词蒙蔽了!!! 推荐指数:4.6星 临潼博物馆吃完饭就去了临潼博物馆,博物馆里的全是珍宝,CCTV9有专门报道,可以搜到,提前可以先看下纪录片。推荐细看金棺银椁,以及佛祖的舍利(异常珍贵)。提前准备一些佛教相关的物件(配饰等),可以免费得到舍利的加持! 整个游览过程1小时。 推荐指数:4.6星 华清池看了临潼博物馆后就去了华清池,因为冬季去的,景色并不太好。可以看看当时西安事变相关的一些遗址,以及蒋介石的藏身地(可以坐电瓶车上半山看,票价20,也可以爬上去,不远)。有个长恨歌,因为是冬季去的,没演出,推荐度很高,建议要去的时候查好季节,去看一下。骊山上有个烽火台,没上去,可以坐缆车,导游没推荐,性价比不高。 整个游览过程1-2小时。 推荐指数:3.5星 驼铃传奇可以说西安最值的一段体验了,每个季节演出场次不同,一天几场,一场60分钟。讲述了整个丝绸之路。票价200到400,虽然贵些,但是真的值得看。总共有12个屏幕,我见过的最大的屏幕了,切换场景时,观众席会旋转,体验很好,有真实的狼,骆驼,瀑布,暴雨,模拟雪友情出演。 整个游览过程1小时。 推荐指数:5星+1星 钟楼、鼓楼看完上面的,已经八九点了,晚上去看了下钟楼和鼓楼夜景,没上去,以及关门了。 Day3西安事变博物馆展现了整个西安事变的过程,以及张学友的一生,值得去看看,以史明鉴,铭记历史! 整个游览过程1小时。 推荐指数:4.5星 牛羊肉泡沫老孙家(关东总店),挨着永兴坊不远,很值得去尝试一下。自己去体验下掰的过程。 吃法:服务员上了泡馍,自己掰成黄豆大小,给服务员加工。然后开吃,一口甜蒜,一口泡馍,简直不要太爽! 整个过程0.5-1小时。 推荐指数:4.6星 吃完泡馍就去北站坐车回去了,整个旅游结束! 干货:提前准备 查好天气 提前预约票 选好季节 提前做好攻略 部分景点最好报团,自己计算性价比 导游车上问到长安三绝,居然没人知道,唉,提前没做好攻略。 兵马俑等四个博物馆 驼铃传奇 牛羊肉泡馍 导游讲解笔记小本本 敲黑板导游的话不可全信,特别是推销当地特色商品时,不管说的多么天花乱坠都不要被蒙蔽了,保持清醒的头脑!导游的话不可全信,特别是推销当地特色商品时,不管说的多么天花乱坠都不要被蒙蔽了,保持清醒的头脑!导游的话不可全信,特别是推销当地特色商品时,不管说的多么天花乱坠都不要被蒙蔽了,保持清醒的头脑! 声明:以上评论全是自己的主观臆断,所有文字靠着记忆记录,如有错误欢迎指正。 写于2019.12.31,D1933高铁上。","link":"/travel/%E8%A5%BF%E5%AE%89%E6%97%85%E6%B8%B8%E6%94%BB%E7%95%A53%E6%97%A5%E6%B8%B8.html"},{"title":"一张图学会python3","text":"这张图包含了Python 3 几乎所有的知识点,包括输出、输入、变量、赋值、计算、模块、函数、参数、返回值、缩进、注释、for循环、条件判断、逻辑运算、字符串及格式化、转义字符、类型转换、列表,甚至也包含了点面向对象的应用(调用对象的方法)。 跟着这张图片一步一步学习,学会 Python指日可待! 正确查看方法,右键图片-新便签页中打开链接-放大查看 图片来源","link":"/python/%E4%B8%80%E5%BC%A0%E5%9B%BE%E5%AD%A6%E4%BC%9Apython3.html"},{"title":"hash冲突开放地址法rehash","text":"Hash碰撞Hash函数就是将任意长度的输入转化成固定长度的输出的一类函数。 比如说我的输入是任意一个自然数(0,1,2,3…),而我要求经过一个函数后我的输出的数的范围要在0-9这样一个范围之间。 很容易想到,我们可以使用Hash函数: Hash(key) = key % 10 其中key就是输入 在哈希表(散列表)里,Hash函数的作用就是将关键字Key转化为一个固定长度数组的下标,以便存取键值对<Key,Value> 当多个键(key)经过Hash函数处理后落在了同一个位置时怎么办呢? 此时使用链地址法可看:神速Hash 链地址法用链表,来一个元素加一个,让这个位置存储一个指针,指向一个链表,让所有相同位置的元素都放在这个链表中 在存储的时候,如果多个元素被Hash到同一位置,那么就加入到该位置所指向的链表中,如果该位置没有元素,则为null(指向空)。 此图中6先放进去了,因为这个插入链表的时候要采用‘头插’的方式,也就是插入链表的最前面(图中里数组最近的元素)。 因为经常发生这样的事情:新加入的元素很可能被再次访问到,所以放到头的话,如果查找就不用再遍历链表了。 rehash Hash函数设计的非常好,能够将元素均匀Hash(散列)开来,但是当我们实际存入的值越来越多的时候,这个链表也势必越来越长,那当我们进行查找的时候,势必就会遍历链表,是否效率也就越来越慢? 这样的话,随着链表的不断增长,查询某一个元素的时间也就增加了,如果链表长度远远大于数组长度,不就和用链表存储一样了吗? 对,现在只能扩大数组的长度大约为原来的两倍 然后选取一个相关的新的Hash函数(比如之前使用 key % m,现在只改变一下m的值) 将旧Hash表中所有的元素通过新的Hash函数计算出新的Hash值,并将其插入到新表中(仍然使用链表),这就叫rehash 这里的数组就扩大了近两倍,由于要大小要选素数,那就选原数组大小两倍后的第一个素数7,旧Hash表和新Hash表采用了不同的Hash函数,但相关,只是m的取值变了。 什么时候开始rehash? 装载因子 α 我们可以定义这样一个变量 α = 所有元素个数/数组的大小,我们叫它装载因子吧,它代表着我们的Hash表(也就是数组)的装满程度,在这里也代表链表的平均长度。 比如说,我们的数组大小为 5 ,我们给里面存入 3个元素,那么 α = 3/5 =0.6, 这个Hash表装满程度为60%,平均每条链有0.6个元素,当然 α 也可以等于和大于 1。 这个装载因子代表了Hash表的装满程度,这里也可以代表链表的平均长度,那么也就可以代表查询时的时间长短了 基于此,我们为了不让查询时间长,也就是查询性能低,我们可以设置一个临界 α 值,当随着存入元素导致 α 大于这个临界 α 值的时候 我们可以通过rehash来调整当前的 α 值,使之低于我们设定的 临界 α 值,从而使我们的查询性能保持在较好的范围之内 比如说,我们设定 临界 α = 0.7,对于一个Hash表大小为5的Hash表而言 当存入存入第四个元素的时候,α 就超出了临界 α 值,我们可以将数组长度变为11进行rehash(因为11是原表两倍后的第一个素数),使得装载因子 α 小于 0.7 通过rehash我们可以使得装载因子在一定范围内,那我们的查询性能也就得到了保证了 那这个 临界的 α 值应该选择多大呢? 这个 临界 α 如果选的小了,那数组的空间利用率就会太低,就比如说数组大小为100,α = 0.01,那装满程度为1%,99%还没有被利用 如果 α 太大了,那冲突就会很多,比如说 数组大小为 5,α = 10, 那平均每条链有10个元素,装满程度为1000% 即使Hash函数设计的合理,基本上每次存放元素的时候就会冲突,所以鉴于两者之间我觉得 0.6 - 0.9 之间是一个不错的选择,不妨选0.75。 开放地址法所谓开放地址法就是发生冲突时在散列表(也就是数组里)里去寻找合适的位置存取对应的元素。 合适的位置该怎么找呢? 线性探测法最容易想到的就是当前位置冲突了,那我就去找相邻的下一个位置。 就拿放入元素举例吧,当你放入<a,101>到下标为2的位置后,另一个<c,103>键值对也落入了这个位置,那么它就向后依次加一寻找合适的位置,然后把<c,103>放入进去。 我们把这种方法称作线性探测法,我们可以将Hash以及寻找位置的过程抽象成一个函数: hash(key) = (hash1(key) + i) % 7,i=0,1,2,...6 所以关键字要进行查找或者插入,首先看(hash1(key)+0)%7 位置是自己最终的位置吗?如果有冲突,就探测(查看)下一个位置:(hash1(key)+1)%7。依次进行 所谓探测,就是在插入的时候检查哪个位置可以插入,或者查找时查找哪个位置是要查找的键值对,本质就是探寻这个键值对最终的位置。 但是这样会有一个问题,就是随着键值对的增多,会在哈希表里形成连续的键值对 这样的话,当插入元素时,任意一个落入这个区间的元素都要一直探测到区间末尾,并且最终将自己加入到这个区间内。这样就会导致落在区间内的关键字Key要进行多次探测才能找到合适的位置,并且还会继续增大这个连续区间,使探测时间变得更长,这样的现象被称为“一次聚集(primary clustering)” 平方探测法我们可以在探测时不一个挨着一个地向后探测,我们可以跳跃着探测,这样就避免了一次聚集。 其实我们可以让它按照 i^2 的规律来跳跃探测 这样的话,元素就不会聚集在某一块区域了,我们把这种方法称为平方探测法 同样我们可以抽象成下面的函数: hash(key) = (hash1(key) + i^2) % 7,i=0,1,2,...6 其实可以扩展到更一般的形式: hash(key) = (hash1(key) +c1i+c2 i^2) % 7,i=0,1,2,...6 虽然平方探测法解决了线性探测法的一次聚集,但是它也有一个小问题,就是关键字key散列到同一位置后探测时的路径是一样的。 这样对于许多落在同一位置的关键字而言,越是后面插入的元素,探测的时间就越长。 这种现象被称作“二次聚集(secondary clustering)”,其实这个在线性探测法里也有。 这种现象出现的原因是由于对于落在同一个位置的关键字我们采取了一个依赖 i 的函数(i或者i^2)来进行探测,它不会因为关键字的不同或其他因素而改变探测的路径。那么我们是不是可以让探测的方法依赖于关键字呢? 双散列答案是可以的,我们可以再弄另外一个Hash函数,对落在同一个位置的关键字进行再次的Hash,探测的时候就用依赖这个Hash值去探测,比如我们可以使用下面的函数: hash(key) = (hash1(key) +hash2(key)*i) % 7,i=0,1,2,...6 经过hash1的散列后,会定位到某一个地址,如果这个地址冲突,那么就按照1hash2(key)、2hash2(key)… 的偏移去探测合适的位置。 由于Hash2函数不同于Hash1,所以两个不同的关键字Hash1值和Hash2值同时相同的概率就会变得非常低。 这样就避免了二次聚集,但同时也付出了计算另一个散列函数Hash2的代价。 如果hash2(key)=0,那探测不就一直在原地不动,失效了吗? 所以hash2函数在选择的时候要避免这种情况。 参考文章:参考链接1","link":"/java/basic/hash%E5%86%B2%E7%AA%81%E5%BC%80%E6%94%BE%E5%9C%B0%E5%9D%80%E6%B3%95rehash.html"},{"title":"算法成长之路leetcode13-14","text":"13. Roman to IntegerRoman numerals are represented by seven different symbols: I, V, X, L, C, D and M. Symbol Value I 1 V 5 X 10 L 50 C 100 D 500 M 1000 For example, two is written as II in Roman numeral, just two one’s added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II. Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used: I can be placed before V (5) and X (10) to make 4 and 9.X can be placed before L (50) and C (100) to make 40 and 90.C can be placed before D (500) and M (1000) to make 400 and 900.Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999. Example1234567891011121314151617181920212223Example 1:Input: \"III\"Output: 3Example 2:Input: \"IV\"Output: 4Example 3:Input: \"IX\"Output: 9Example 4:Input: \"LVIII\"Output: 58Explanation: L = 50, V= 5, III = 3.Example 5:Input: \"MCMXCIV\"Output: 1994Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126package algorithm;import java.util.HashMap;import java.util.Map;/** * 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 * * 字符 数值 * I 1 * V 5 * X 10 * L 50 * C 100 * D 500 * M 1000 * 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。 * * 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例, * 例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边, * 所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。 * 这个特殊的规则只适用于以下六种情况: * * I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。 * X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。  * C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。 * 给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。 * * 示例 1: * * 输入: \"III\" * 输出: 3 * 示例 2: * * 输入: \"IV\" * 输出: 4 * 示例 3: * * 输入: \"IX\" * 输出: 9 * 示例 4: * * 输入: \"LVIII\" * 输出: 58 * 解释: L = 50, V= 5, III = 3. * 示例 5: * * 输入: \"MCMXCIV\" * 输出: 1994 * 解释: M = 1000, CM = 900, XC = 90, IV = 4. * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/roman-to-integer * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode13 { public static int romanToInt(String s) { int[] moneys = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; String[] moneyToStr = new String[]{\"M\", \"CM\", \"D\", \"CD\", \"C\", \"XC\", \"L\", \"XL\", \"X\", \"IX\", \"V\", \"IV\", \"I\"}; char[] chars = s.toCharArray(); int result = 0; int tempJ = 0; for (int i = 0; i < chars.length; ) { for (int j = tempJ; j < moneyToStr.length; ) { // 从左往右开始一个字符一个字符匹配,匹配到一个字符后开始下一个 if (new String(new char[]{chars[i]}).equals(moneyToStr[j])) { result += moneys[j]; i++; // 此时下一次可能还会出现一样的字符如VV=20 tempJ = j; break; // 匹配到两个字符是开始下两个字符 } else if (i + 1 < chars.length && new String(new char[]{chars[i], chars[i + 1]}).equals(moneyToStr[j])) { result += moneys[j]; i += 2; // 下次出现的一定是一个字符的,如IV下次不会再出现IV 只能出现I tempJ = j + 1; break; } else { j++; } } } return result; } public static int romanToInt1(String s) { Map<String, Integer> map = new HashMap<>(); map.put(\"I\", 1); map.put(\"IV\", 4); map.put(\"V\", 5); map.put(\"IX\", 9); map.put(\"X\", 10); map.put(\"XL\", 40); map.put(\"L\", 50); map.put(\"XC\", 90); map.put(\"C\", 100); map.put(\"CD\", 400); map.put(\"D\", 500); map.put(\"CM\", 900); map.put(\"M\", 1000); int ans = 0; // 所有的字符,要么匹配两个要么匹配一个,没有其余的情况 for(int i = 0;i < s.length();) { // 两个匹配的 if(i + 1 < s.length() && map.containsKey(s.substring(i, i+2))) { ans += map.get(s.substring(i, i+2)); // 匹配上后往后移两个 i += 2; } else { // 一个匹配上的 ans += map.get(s.substring(i, i+1)); // 匹配后往后移一个 i ++; } } return ans; } public static void main(String[] args) { System.out.println(romanToInt(\"XIX\")); }} 14. Longest Common PrefixWrite a function to find the longest common prefix string amongst an array of strings. If there is no common prefix, return an empty string “”. Example12345678910111213Example 1:Input: [\"flower\",\"flow\",\"flight\"]Output: \"fl\"Example 2:Input: [\"dog\",\"racecar\",\"car\"]Output: \"\"Explanation: There is no common prefix among the input strings.Note:All given inputs are in lowercase letters a-z. JAVA题解水平扫描 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106package algorithm;/** * 编写一个函数来查找字符串数组中的最长公共前缀。 * * 如果不存在公共前缀,返回空字符串 \"\"。 * * 示例 1: * * 输入: [\"flower\",\"flow\",\"flight\"] * 输出: \"fl\" * 示例 2: * * 输入: [\"dog\",\"racecar\",\"car\"] * 输出: \"\" * 解释: 输入不存在公共前缀。 * 说明: * * 所有输入只包含小写字母 a-z 。 * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/longest-common-prefix * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode14 { public static String longestCommonPrefix(String[] strs) { if (strs.length == 0) { return \"\"; } if (strs.length == 1) { return strs[0]; } int i = 0; String pre = \"\"; for (; i < strs[0].length(); i++) { pre = strs[0].substring(0, i + 1); int j = 1; boolean end = false; for (; j < strs.length; j++) { if (!strs[j].startsWith(pre)) { break; } if (pre.length() == strs[j].length()) { end = true; } } if (j == strs.length && !end) { continue; } else if (j != strs.length) { if (pre.length() > 1) { return pre.substring(0, pre.length() - 1); } else { return \"\"; } } else { return pre; } } return pre; } // 水平扫描法 public static String longestCommonPrefix1(String[] strs) { if (strs.length == 0) return \"\"; String prefix = strs[0]; // 1,2->s1,3->s2,4;前两个中找到前缀公共最长的s1,然后和第3个一起找出s2,以此类推 for (int i = 1; i < strs.length; i++) // 不相等时为-1 while (strs[i].indexOf(prefix) != 0) { // 从后往前缩短,直到找到最长的 prefix = prefix.substring(0, prefix.length() - 1); // 找完都没找到的话返回空 if (prefix.isEmpty()) return \"\"; } return prefix; } public static void main(String[] args) { System.out.println(longestCommonPrefix1(new String[]{\"flower\",\"fl\",\"flight\"})); } // 水平扫描,单个字符逐一进行比较 public static String longestCommonPrefix2(String[] strs) { if (strs == null || strs.length == 0) return \"\"; for (int i = 0; i < strs[0].length() ; i++){ char c = strs[0].charAt(i); for (int j = 1; j < strs.length; j ++) { // 如果i == strs[j].length() 代表找出最短的,直接返回,或者不相等时直接返回 if (i == strs[j].length() || strs[j].charAt(i) != c) return strs[0].substring(0, i); } } // 到此处已经找完 return strs[0]; }} 分治算法 123456789101112131415161718192021222324252627282930public String longestCommonPrefix(String[] strs) { if (strs == null || strs.length == 0) return \"\"; return longestCommonPrefix(strs, 0 , strs.length - 1);}private String longestCommonPrefix(String[] strs, int l, int r) { // 只有一个字符串的时候,返回此字符串 if (l == r) { return strs[l]; } else { int mid = (l + r)/2; // 找出左边最长前缀 String lcpLeft = longestCommonPrefix(strs, l , mid); // 找出右边最长前缀 String lcpRight = longestCommonPrefix(strs, mid + 1,r); // 左边右边中找出最长前缀 return commonPrefix(lcpLeft, lcpRight); }}String commonPrefix(String left,String right) { int min = Math.min(left.length(), right.length()); for (int i = 0; i < min; i++) { // 循环最小的一边字符逐一比较,不相等时跳出 if ( left.charAt(i) != right.charAt(i) ) return left.substring(0, i); } return left.substring(0, min);} 二分查找法 1234567891011121314151617181920212223242526public String longestCommonPrefix(String[] strs) { if (strs == null || strs.length == 0) return \"\"; int minLen = Integer.MAX_VALUE; for (String str : strs) minLen = Math.min(minLen, str.length()); int low = 1; int high = minLen; while (low <= high) { int middle = (low + high) / 2; if (isCommonPrefix(strs, middle)) low = middle + 1; else high = middle - 1; } return strs[0].substring(0, (low + high) / 2);}private boolean isCommonPrefix(String[] strs, int len){ String str1 = strs[0].substring(0,len); for (int i = 1; i < strs.length; i++) if (!strs[i].startsWith(str1)) return false; return true;} 字典树给定一些键值字符串 S = [S 1 ,S 2 …S n ],我们要找到字符串 q 与 S 的最长公共前缀。 这样的查询操作可能会非常频繁。 我们可以通过将所有的键值 S 存储到一颗字典树中来优化最长公共前缀查询操作。 如果你想学习更多关于字典树的内容,可以从 208. 实现 Trie (前缀树)开始。在字典树中,从根向下的每一个节点都代表一些键值的公共前缀。 但是我们需要找到字符串q 和所有键值字符串的最长公共前缀。 这意味着我们需要从根找到一条最深的路径,满足以下条件: 这是所查询的字符串 q 的一个前缀 路径上的每一个节点都有且仅有一个孩子。 否则,找到的路径就不是所有字符串的公共前缀 路径不包含被标记成某一个键值字符串结尾的节点。 因为最长公共前缀不可能比某个字符串本身长 算法 最后的问题就是如何找到字典树中满足上述所有要求的最深节点。 最有效的方法就是建立一颗包含字符串[S 1 …S n ] 的字典树。 然后在这颗树中匹配 q 的前缀。 我们从根节点遍历这颗字典树,直到因为不能满足某个条件而不能再遍历为止。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061public String longestCommonPrefix(String q, String[] strs) { if (strs == null || strs.length == 0) return \"\"; if (strs.length == 1) return strs[0]; Trie trie = new Trie(); for (int i = 1; i < strs.length ; i++) { trie.insert(strs[i]); } return trie.searchLongestPrefix(q);}class TrieNode { // 子节点的链接数组 private TrieNode[] links; private final int R = 26; private boolean isEnd; // 非空子节点的数量 private int size; public void put(char ch, TrieNode node) { links[ch -'a'] = node; size++; } public int getLinks() { return size; } // 假设方法 containsKey、isEnd、get、put 都已经实现了 // 可以参考文章:https://leetcode.com/articles/implement-trie-prefix-tree/}public class Trie { private TrieNode root; public Trie() { root = new TrieNode(); }// 假设方法 insert、search、searchPrefix 都已经实现了// 可以参考文章:https://leetcode.com/articles/implement-trie-prefix-tree/ private String searchLongestPrefix(String word) { TrieNode node = root; StringBuilder prefix = new StringBuilder(); for (int i = 0; i < word.length(); i++) { char curLetter = word.charAt(i); if (node.containsKey(curLetter) && (node.getLinks() == 1) && (!node.isEnd())) { prefix.append(curLetter); node = node.get(curLetter); } else return prefix.toString(); } return prefix.toString(); }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode13-14.html"},{"title":"贪心算法解析示例","text":"定义贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。 思想贪心算法的基本思路是从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止 过程 建立数学模型来描述问题; 把求解的问题分成若干个子问题; 对每一子问题求解,得到子问题的局部最优解; 把子问题的解局部最优解合成原来解问题的一个解。 示例假设山洞中有 n 种宝物,每种宝物有一定重量 w 和相应的价值 v,毛驴运载能力有限,只能运走 m 重量的宝物,一种宝物只能拿一样,宝物可以分割。那么怎么才能使毛驴运走宝物的价值最大呢?尝试贪心策略:(1)每次挑选价值最大的宝物装入背包,得到的结果是否最优?(2)每次挑选重量最小的宝物装入,能否得到最优解?(3)每次选取单位重量价值最大的宝物,能否使价值最高?思考一下,如果选价值最大的宝物,但重量非常大,也是不行的,因为运载能力是有限的,所以第 1 种策略舍弃;如果选重量最小的物品装入,那么其价值不一定高,所以不能在总重限制的情况下保证价值最大,第 2 种策略舍弃;而第 3 种是每次选取单位重量价值最大的宝物,也就是说每次选择性价比(价值/重量)最高的宝物,如果可以达到运载重量 m, 那么一定能得到价值最大。因此采用第 3 种贪心策略,每次从剩下的宝物中选择性价比最高的宝物。 算法设计:(1)数据结构及初始化。将 n 种宝物的重量和价值存储在结构体 three(包含重量、价值、性价比 3 个成员)中,同时求出每种宝物的性价比也存储在对应的结构体 three 中,将其按照性价比从高到低排序。采用 sum 来存储毛驴能够运走的最大价值,初始化为 0。(2)根据贪心策略,按照性价比从大到小选取宝物,直到达到毛驴的运载能力。每次选择性价比高的物品,判断是否小于 m(毛驴运载能力),如果小于 m,则放入,sum(已放入物品的价值)加上当前宝物的价值,m 减去放入宝物的重量;如果不小于 m,则取该宝物的一部分 m * p[i],m=0,程序结束。m 减少到 0,则 sum 得到最大值。 完美图解假设现在有一批宝物,价值和重量如表 2-3 所示,毛驴运载能力 m=30,那么怎么装入最大价值的物品?宝物清单: 123宝物 i 1 2 3 4 5 6 7 8 9 10重量 w[i] 4 2 9 5 5 8 5 4 5 5价值 v[i] 3 8 18 6 8 20 5 6 7 15 (1)因为贪心策略是每次选择性价比(价值/重量)高的宝物,按照性价比降序排序:排序后宝物清单: 1234宝物 i 2 10 6 3 5 8 9 4 7 1重量 w[i] 2 5 8 9 5 4 5 5 5 4价值 v[i] 8 15 20 18 8 6 7 6 5 3性价比 p[i] 4 3 2.5 2 1.6 1.5 1.4 1.2 1 0.75 (2)按照贪心策略,每次选择性价比高的宝物放入:第 1 次选择宝物 2,剩余容量 30−2=28,目前装入最大价值为 8。第 2 次选择宝物 10,剩余容量 28−5=23,目前装入最大价值为 8+15=23。第 3 次选择宝物 6,剩余容量 23−8=15,目前装入最大价值为 23+20=43。第 4 次选择宝物 3,剩余容量 15−9=6,目前装入最大价值为 43+18=61。 第 5 次选择宝物 5,剩余容量 6−5=1,目前装入最大价值为 61+8=69。第 6 次选择宝物 8,发现上次处理完时剩余容量为 1,而 8 号宝物重量为 4,无法全部放入,那么可以采用部分装入的形式,装入 1 个重量单位,因为 8 号宝物的单位重量价值为1.5,因此放入价值 1×1.5=1.5,你也可以认为装入了 8 号宝物的 1/4,目前装入最大价值为69+1.5=70.5,剩余容量为 0。(3)构造最优解把这些放入的宝物序号组合在一起,就得到了最优解(2,10,6,3,5,8),其中最后一个宝物为部分装入(装了 8 号财宝的 1/4),能够装入宝物的最大价值为 70.5。 伪代码详解(1)数据结构定义根据算法设计中的数据结构,我们首先定义一个结构体 three:struct three{double w; //每种宝物的重量double v; //每种宝物的价值double p; //每种宝物的性价比(价值/重量)}(2)性价比排序我们可以利用 C++中的排序函数 sort(见附录 B),对宝物的性价比从大到小(非递增)排序。要使用此函数需引入头文件:#include 语法描述为:sort(begin, end)// 参数 begin 和 end 表示一个范围,分别为待排序数组的首地址和尾地址在本例中我们采用结构体形式存储,按结构体中的一个字段,即按性价比排序。如果不使用自定义比较函数,那么 sort 函数排序时不知道按哪一项的值排序,因此采用自定义比较函数的办法实现宝物性价比的降序排序:bool cmp(three a,three b)//比较函数按照宝物性价比降序排列{return a.p > b.p; //指明按照宝物性价比降序排列}sort(s, s+n, cmp); //前两个参数分别为待排序数组的首地址和尾地址//最后一个参数 compare 表示比较的类型(3)贪心算法求解在性价比排序的基础上,进行贪心算法运算。如果剩余容量比当前宝物的重量大,则可以放入,剩余容量减去当前宝物的重量,已放入物品的价值加上当前宝物的价值。如果剩余容量比当前宝物的重量小,表示不可以全部放入,可以切割下来一部分(正好是剩余容量),然后令剩余容量乘以当前物品的单位重量价值,已放入物品的价值加上该价值,即为能放入宝物的最大价值。 12345678910111213for(int i = 0;i < n;i++)//按照排好的顺序,执行贪心策略{if( m > s[i].w )//如果宝物的重量小于毛驴剩下的运载能力,即剩余容量 { m -= s[i].w; sum += s[i].v; }else //如果宝物的重量大于毛驴剩下的承载能力 { sum += m 乘以 s[i].p; //进行宝物切割,切割一部分(m 重量),正好达到驴子承重 break; }} 实现代码:12345678910111213141516171819202122232425262728293031323334353637383940414243#include<iostream>#include<algorithm>using namespace std;const int M=1000005;struct three{ double w;//每个宝物的重量 double v;//每个宝物的价值 double p;//性价比}s[M];bool cmp(three a,three b){ return a.p>b.p;//根据宝物的单位价值从大到小排序}int main(){ int n;//n 表示有 n 个宝物 double m ;//m 表示毛驴的承载能力 cout<<\"请输入宝物数量 n 及毛驴的承载能力 m :\"<<endl; cin>>n>>m; cout<<\"请输入每个宝物的重量和价值,用空格分开: \"<<endl; for(int i=0;i<n;i++) { cin>>s[i].w>>s[i].v; s[i].p=s[i].v/s[i].w;//每个宝物单位价值 } sort(s,s+n,cmp); double sum=0.0;// sum 表示贪心记录运走宝物的价值之和 for(int i=0;i<n;i++)//按照排好的顺序贪心 { if( m>s[i].w )//如果宝物的重量小于毛驴剩下的承载能力 { m-=s[i].w; sum+=s[i].v; } else//如果宝物的重量大于毛驴剩下的承载能力 { sum+=m * s[i].p;//部分装入 break; } } cout<<\"装入宝物的最大价值 Maximum value=\"<<sum<<endl; return 0;} 注意如果物品不能被分割,就不能采用贪心算法。 leetcode12. 整数转罗马数字 生活中的经验: 在以前还使用现金购物的时候,如果我们不想让对方找钱,付款的时候我们会尽量选择面值大的纸币给对方,这样才会使得我们给对方的纸币张数最少,对方点钱的时候也最方便。 本题“整数转罗马数字”也有类似的思想:在表示一个较大整数的时候,“罗马数字”的设计者不会让你都用 11 加起来,我们总是希望写出来的“罗马数字”的个数越少越好,以方便表示,并且这种表示方式还应该是唯一的。 “罗马数字”与阿拉伯数字的对应关系表中,并且按照从大到小的顺序排列。 罗马数字 阿拉伯数字 M 1000 CM 900 D 500 CD 400 C 100 XC 90 L 50 XL 40 X 10 IX 9 V 5 IV 4 I 1 于是,“将整数转换为罗马数字”的过程,就是用上面这张表中右边的数字作为“加法因子”去分解一个整数,目的是“分解的整数个数”尽可能少,因此,对于这道问题,类似于用最少的纸币凑成一个整数,贪心算法的规则如下: 每一步都使用当前较大的罗马数字作为加法因子,最后得到罗马数字表示就是长度最少的。 123456789101112131415161718192021222324252627public class Solution { public String intToRoman(int num) { // 把阿拉伯数字与罗马数字可能出现的所有情况和对应关系,放在两个数组中 // 并且按照阿拉伯数字的大小降序排列,这是贪心选择思想 int[] nums = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; String[] romans = {\"M\", \"CM\", \"D\", \"CD\", \"C\", \"XC\", \"L\", \"XL\", \"X\", \"IX\", \"V\", \"IV\", \"I\"}; StringBuilder stringBuilder = new StringBuilder(); int index = 0; while (index < 13) { // 特别注意:这里是等号 while (num >= nums[index]) { // 注意:这里是等于号,表示尽量使用大的\"面值\" stringBuilder.append(romans[index]); num -= nums[index]; } index++; } return stringBuilder.toString(); }}作者:liweiwei1419链接:https://leetcode-cn.com/problems/integer-to-roman/solution/tan-xin-suan-fa-by-liweiwei1419/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 参考文章:参考链接1参考链接2","link":"/algorithm/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95%E8%A7%A3%E6%9E%90%E7%A4%BA%E4%BE%8B.html"},{"title":"不蒜子统计常见问题","text":"不蒜子统计官网:http://busuanzi.ibruce.info/ 详细使用教程:http://ibruce.info/2015/04/04/busuanzi/ 目前支持的功能:(两行代码,搞定计数;方便、简洁、实用) a、显示站点总访问量 b、显示单页面访问量 c、显示站点总访问量和单页面访问量 d、只计数不显示 关于怎么实现当天、昨天、本月、上月(即具体时间段)的访问量目前没有支持,请配合目前不蒜子支持的功能自行实现。 1.常见问题400错误,统计不生效 如图(1)的地方没有加载出统计数据 此时F12打开浏览器控制台,找到(2)network地方,刷新一下页面找到(3),请求统计的网址如图所示,查看(4)referrer-policy是否如图所示,如图的话是不能访问的,需要更改。 导致此问题原因,检查网页源码中,一般header有如下标签 解决方法,去掉此标签,之后访问如下(1)已有统计值,(2)已改变。可详细对比正常使用不蒜子统计网址https://removeif.github.io/ 中请求busuanzi?jsonpCallback=BusuanziCallback_236107382952地址的请求和返回参数的差异! 这样设置带来的影响,可能有些图床的图片不能显示,会图裂,如新浪图床。解决方法,可以用其他不冲突的图床。 2.统计访问数巨大(清零问题)http://localhost:4000/ 或http://127.0.0.1:4000/ 访问时,统计数巨大,这是正常的,不用清零。部署到线上,用线上域名网址访问数据就正常了。 3.统计无法访问如图所示 查看红色url部分如下所示 此问题是Request URL填写错误,请确保Request URL前部分为http://busuanzi.ibruce.info/busuanzi?,,,,如下 同时查看Response,出现如下数据,就是成功访问了不蒜子统计,如果网站中还没出统计数据,就是自己的代码写错了,检查代码 4.其余问题(1).同一个页面,同名的id标签确保只能放一个如下 1234<span id=\"busuanzi_container_site_uv\" style=\"display: inline;\"> <span id=\"busuanzi_value_site_uv\"></span></span> 同一个页面id名为busuanzi_value_site_uv只能放一个! (2).safari(包括移动端的safari)浏览器页面pv统计问题,如下,因为Safari浏览器referer在文章页面时也上送的域名(而单个页面的pv统计是根据页面路径,即上送的referer),所以此时页面的pv返回的站点的pv值。暂时没解决方法,可自行搜索解决方案构造正确的referer值。对于此问题可以换个浏览器看哇,比如Chrome,哈哈。 (3).部分live2d可能与不蒜子统计有冲突,出现此问题时,请查看网页源码引用统计id处是否被隐藏,一般网页上会自动加上display: none;自行选择性的使用。网友的解决方法,修改源码为以下,并引用修改后的js文件 不蒜子源码文件: 修改为如下: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990var bszCaller, bszTag;!function() { var c, d, e, a = !1, b = []; ready = function(c) { return a || \"interactive\" === document.readyState || \"complete\" === document.readyState ? c.call(document) : b.push(function() { return c.call(this) }), this } , d = function() { for (var a = 0, c = b.length; c > a; a++) b[a].apply(document); b = [] } , e = function() { a || (a = !0, d.call(window), document.removeEventListener ? document.removeEventListener(\"DOMContentLoaded\", e, !1) : document.attachEvent && (document.detachEvent(\"onreadystatechange\", e), window == window.top && (clearInterval(c), c = null))) } , document.addEventListener ? document.addEventListener(\"DOMContentLoaded\", e, !1) : document.attachEvent && (document.attachEvent(\"onreadystatechange\", function() { /loaded|complete/.test(document.readyState) && e() }), window == window.top && (c = setInterval(function() { try { a || document.documentElement.doScroll(\"left\") } catch (b) { return } e() }, 5)))}(),bszCaller = { fetch: function(a, b) { var c = \"BusuanziCallback_\" + Math.floor(1099511627776 * Math.random()); window[c] = this.evalCall(b), a = a.replace(\"=BusuanziCallback\", \"=\" + c), scriptTag = document.createElement(\"SCRIPT\"), scriptTag.type = \"text/javascript\", scriptTag.defer = !0, scriptTag.src = a, document.getElementsByTagName(\"HEAD\")[0].appendChild(scriptTag) }, evalCall: function(a) { return function(b) { ready(function() { try { a(b), - // 此处为修改的逻辑- scriptTag.parentElement.removeChild(scriptTag)+ if(scriptTag != null && scriptTag.parentElement != null){+ scriptTag.parentElement.removeChild(scriptTag)+ } } catch (c) { bszTag.hides() } }) } }},bszCaller.fetch(\"//busuanzi.ibruce.info/busuanzi?jsonpCallback=BusuanziCallback\", function(a) { bszTag.texts(a), bszTag.shows()}),bszTag = { bszs: [\"site_pv\", \"page_pv\", \"site_uv\"], texts: function(a) { this.bszs.map(function(b) { var c = document.getElementById(\"busuanzi_value_\" + b); c && (c.innerHTML = a[b]) }) }, hides: function() { this.bszs.map(function(a) { var b = document.getElementById(\"busuanzi_container_\" + a); b && (b.style.display = \"none\") }) }, shows: function() { this.bszs.map(function(a) { var b = document.getElementById(\"busuanzi_container_\" + a); b && (b.style.display = \"inline\") }) }}; 5.官方群!!!群号:419260983,有其余问题进群讨论,提问时遇到其他的问题请同时发出问题的在线网址!!!","link":"/theme/%E4%B8%8D%E8%92%9C%E5%AD%90%E7%BB%9F%E8%AE%A1%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98.html"},{"title":"算法成长之路leetcode11-12","text":"11. Container With Most WaterGiven n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water. Note: You may not slant the container and n is at least 2. The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49. Example1234Example:Input: [1,8,6,2,5,4,8,3,7]Output: 49 JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135package algorithm;/** * 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。 * 在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。 * 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 * * 说明:你不能倾斜容器,且 n 的值至少为 2。 * * * * 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 * * * * 示例: * * 输入: [1,8,6,2,5,4,8,3,7] * 输出: 49 * * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/container-with-most-water * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode11 { // 暴力解法 public static int maxArea(int[] height) { int max = 0; for (int i = 0; i < height.length - 1; i++) { for (int j = i + 1; j < height.length; j++) { max = Math.max(max, Math.min(height[i], height[j]) * (j-i)); } } return max; } // 官方 双指针法 /** * 算法 * * 这种方法背后的思路在于,两线段之间形成的区域总是会受到其中较短那条长度的限制。此外,两线段距离越远,得到的面积就越大。 * * 我们在由线段长度构成的数组中使用两个指针,一个放在开始,一个置于末尾。 * 此外,我们会使用变量 maxareamaxarea 来持续存储到目前为止所获得的最大面积。 * 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxareamaxarea,并将指向较短线段的指针向较长线段那端移动一步。 * * 作者:LeetCode * 链接:https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * * 算法流程: 设置双指针 ii,jj 分别位于容器壁两端,根据规则移动指针(后续说明),并且更新面积最大值 res,直到 i == j 时返回 res。 * * 指针移动规则与证明: 每次选定围成水槽两板高度 h[i]h[i],h[j]h[j] 中的短板,向中间收窄 11 格。以下证明: * * 设每一状态下水槽面积为 S(i, j)S(i,j),(0 <= i < j < n)(0<=i<j<n),由于水槽的实际高度由两板中的短板决定, * 则可得面积公式 S(i, j) = min(h[i], h[j]) × (j - i)S(i,j)=min(h[i],h[j])×(j−i)。 * 在每一个状态下,无论长板或短板收窄 11 格,都会导致水槽 底边宽度 -1−1: * 若向内移动短板,水槽的短板 min(h[i], h[j])min(h[i],h[j]) 可能变大,因此水槽面积 S(i, j)S(i,j) 可能增大。 * 若向内移动长板,水槽的短板 min(h[i], h[j])min(h[i],h[j]) 不变或变小,下个水槽的面积一定小于当前水槽面积。 * 因此,向内收窄短板可以获取面积最大值。换个角度理解: * 若不指定移动规则,所有移动出现的 S(i, j)S(i,j) 的状态数为 C(n, 2)C(n,2),即暴力枚举出所有状态。 * 在状态 S(i, j)S(i,j) 下向内移动短板至 S(i + 1, j)S(i+1,j)(假设 h[i] < h[j]h[i]<h[j] ), * 则相当于消去了 {S(i, j - 1), S(i, j - 2), ... , S(i, i + 1)}S(i,j−1),S(i,j−2),...,S(i,i+1) 状态集合。 * 而所有消去状态的面积一定 <= S(i, j)<=S(i,j): * 短板高度:相比 S(i, j)S(i,j) 相同或更短(<= h[i]<=h[i]); * 底边宽度:相比 S(i, j)S(i,j) 更短。 * 因此所有消去的状态的面积都 < S(i, j)<S(i,j)。通俗的讲,我们每次向内移动短板,所有的消去状态都不会导致丢失面积最大值 。 * * * 作者:jyd * 链接:https://leetcode-cn.com/problems/container-with-most-water/solution/container-with-most-water-shuang-zhi-zhen-fa-yi-do/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * @param height * @return */ public static int maxArea1(int[] height) { int maxarea = 0, l = 0, r = height.length - 1; while (l < r) { // 计算面积,取最大值 maxarea = Math.max(maxarea, Math.min(height[l], height[r]) * (r - l)); // 小的向大的一方移动,如果左边小于右边,左边向右边移动一位,即左++,l++,否则右移 if (height[l] < height[r]) l++; else r--; } return maxarea; } public static int maxArea2(int[] height) { int i = 0, j = height.length - 1, res = 0; while(i < j){ res = height[i] < height[j] ? Math.max(res, (j - i) * height[i++]): Math.max(res, (j - i) * height[j--]); } return res; } // best one public static int maxArea3(int[] height) { int lastIndex = height.length - 1, max = 0, temp = 0; for (int i = 0; i < lastIndex;) { // 取左右边上的最小的数 temp = Math.min(height[i], height[lastIndex]); // 计算 距离最大面积 if (temp * (lastIndex - i) > max) { max = temp * (lastIndex - i); System.out.println(\"\" + i + \",\" + lastIndex); } // 最小值在右边的话 右边往左边移动 while (temp >= height[lastIndex] && i < lastIndex) lastIndex--; // 最小值在左边的话 左边往右移动 直到重合 while (temp >= height[i] && i < lastIndex) i++; } return max; } public static void main(String[] args) { System.out.println(maxArea3(new int[]{10, 8, 6, 2, 5, 4, 8, 3, 7})); }} 12. Integer to RomanRoman numerals are represented by seven different symbols: I, V, X, L, C, D and M. Symbol ValueI 1V 5X 10L 50C 100D 500M 1000For example, two is written as II in Roman numeral, just two one’s added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II. Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used: I can be placed before V (5) and X (10) to make 4 and 9.X can be placed before L (50) and C (100) to make 40 and 90.C can be placed before D (500) and M (1000) to make 400 and 900.Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999. Example1234567891011121314151617181920212223Example 1:Input: 3Output: \"III\"Example 2:Input: 4Output: \"IV\"Example 3:Input: 9Output: \"IX\"Example 4:Input: 58Output: \"LVIII\"Explanation: L = 50, V = 5, III = 3.Example 5:Input: 1994Output: \"MCMXCIV\"Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160package algorithm;/** * 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 * * 字符 数值 * I 1 * V 5 * X 10 * L 50 * C 100 * D 500 * M 1000 * 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII , * 即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。 * * 通常情况下,罗马数字中小的数字在大的数字的右边。 * 但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边, * 所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地, * 数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况: * * I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。 * X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。  * C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。 * 给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。 * * 示例 1: * * 输入: 3 * 输出: \"III\" * 示例 2: * * 输入: 4 * 输出: \"IV\" * 示例 3: * * 输入: 9 * 输出: \"IX\" * 示例 4: * * 输入: 58 * 输出: \"LVIII\" * 解释: L = 50, V = 5, III = 3. * 示例 5: * * 输入: 1994 * 输出: \"MCMXCIV\" * 解释: M = 1000, CM = 900, XC = 90, IV = 4. * * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/integer-to-roman * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */public class Leetcode12 { /** * 执行用时 :6 ms, 在所有 java 提交中击败了的用户 * 内存消耗 :36.1 MB, 在所有 java 提交中击败了100.00%的用户 * @param num * @return */ public static String intToRoman(int num) { // 个位数 String[] map = new String[]{\"\", \"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\", \"VII\", \"VIII\", \"IX\"}; // 十位数 String[] map1 = new String[]{\"\", \"X\", \"XX\", \"XXX\", \"XL\", \"L\", \"LX\", \"LXX\", \"LXXX\", \"XC\"}; // 百位 String[] map2 = new String[]{\"\", \"C\", \"CC\", \"CCC\", \"CD\", \"D\", \"DC\", \"DCC\", \"DCCC\", \"CM\"}; // 千位 String[] map3 = new String[]{\"\", \"M\", \"MM\", \"MMM\"}; StringBuilder sb = new StringBuilder(); String[] res = new String[4]; int i = 10; int j = 0; while (num > 0) { int temp = num % i; if (i > 10) { temp = temp / (i / 10); } switch (j) { case 0: res[j++] = map[temp]; break; case 1: res[j++] = map1[temp]; break; case 2: res[j++] = map2[temp]; break; case 3: res[j++] = map3[temp]; break; } i = 10*i; if (j > 3) { break; } } for (int k = res.length - 1; k >= 0; k--) { sb.append(res[k]); } return sb.toString(); } /** * 贪心算法 * * 解题思路 * 参考大佬们的思路 吃透之后 写出来 * 贪心算法 我永远用最接近的去做比较 * * 如果我去小卖部买55元的东西 * * 你可以选择一张面值50的 和一张5块的 * 也可以给一张100的让老板找零 * 贪心算法就是前者 * * 假定我买3块的东西 我先用5块去比较 太多了 老板问 你还有小点的纸币没 我找不开 * 这时候 你给个两块 还差一块 又给了一块 * 看着很蠢 但是这确实有效 * * 作者:guo-tang-feng * 链接:https://leetcode-cn.com/problems/integer-to-roman/solution/tan-xin-suan-fa-by-guo-tang-feng/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * * @param num * @return */ public static String intToRoman1(int num) { StringBuilder stringBuilder = new StringBuilder(); int[] moneys = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; String[] moneyToStr = new String[]{\"M\", \"CM\", \"D\", \"CD\", \"C\", \"XC\", \"L\", \"XL\", \"X\", \"IX\", \"V\", \"IV\", \"I\"}; int index = 0; while (num > 0) { // 如果大于最大的数 if (num >= moneys[index]) { // 加进去 stringBuilder.append(moneyToStr[index]); // 把加进去的减掉 num -= moneys[index]; // 索引前移,num -= moneys[index] 还可能满足 num >= moneys[index] // ,此时如果只index++,那么就漏掉一部分了,所以要index--,如2000减掉1000还有1000 还是应该和moneys[0]比较 index--; } // 索引后移 index++; } return stringBuilder.toString(); } public static void main(String[] args) { // 第一次超过100%用户的内存,有点小小激动 😂 System.out.println(intToRoman(400)); System.out.println(intToRoman1(1994)); }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode11-12.html"},{"title":"intellj idea 详细调试代码debug","text":"Debug用来追踪代码的运行流程,通常在程序运行过程中出现异常,启用Debug模式可以分析定位异常发生的位置,以及在运行过程中参数的变化。通常我们也可以启用Debug模式来跟踪代码的运行流程去学习三方框架的源码。 在Intellij IDEA中使用好Debug,主要包括如下内容: Debug开篇 基本用法&快捷键 变量查看 计算表达式 智能步入 断点条件设置 多线程调试 回退断点 中断Debug 一、Debug开篇首先看下IDEA中Debug模式下的界面。如下是在IDEA中启动Debug模式,进入断点后的界面,我这里是Windows,可能和Mac的图标等会有些不一样。就简单说下图中标注的8个地方: 以Debug模式启动服务,左边的一个按钮则是以Run模式启动。在开发中,我一般会直接启动Debug模式,方便随时调试代码。 断点:在左边行号栏单击左键,或者快捷键Ctrl+F8 打上/取消断点,断点行的颜色可自己去设置。 Debug窗口:访问请求到达第一个断点后,会自动激活Debug窗口。如果没有自动激活,可以去设置里设置,如图1.2。 调试按钮:一共有8个按钮,调试的主要功能就对应着这几个按钮,鼠标悬停在按钮上可以查看对应的快捷键。在菜单栏Run里可以找到同样的对应的功能,如图1.4。 服务按钮:可以在这里关闭/启动服务,设置断点等。 方法调用栈:这里显示了该线程调试所经过的所有方法,勾选右上角的[Show All Frames]按钮,就不会显示其它类库的方法了,否则这里会有一大堆的方法。 Variables:在变量区可以查看当前断点之前的当前方法内的变量。 Watches:查看变量,可以将Variables区中的变量拖到Watches中查看 在设置里勾选Show debug window on breakpoint,则请求进入到断点后自动激活Debug窗口。 如果你的IDEA底部没有显示工具栏或状态栏,可以在View里打开,显示出工具栏会方便我们使用。可以自己去尝试下这四个选项。 在菜单栏Run里有调试对应的功能,同时可以查看对应的快捷键。 二、基本用法&快捷键Debug调试的功能主要对应着图一中4和5两组按钮: 1、首先说第一组按钮,共8个按钮,从左到右依次如下: Show Execution Point (Alt + F10):如果你的光标在其它行或其它页面,点击这个按钮可跳转到当前代码执行的行。 Step Over (F8):步过,一行一行地往下走,如果这一行上有方法不会进入方法。 Step Into (F7):步入,如果当前行有方法,可以进入方法内部,一般用于进入自定义方法内,不会进入官方类库的方法,如第25行的put方法。 Force Step Into (Alt + Shift + F7):强制步入,能进入任何方法,查看底层源码的时候可以用这个进入官方类库的方法。 Step Out (Shift + F8):步出,从步入的方法内退出到方法调用处,此时方法已执行完毕,只是还没有完成赋值。 Drop Frame (默认无):回退断点,后面章节详细说明。 Run to Cursor (Alt + F9):运行到光标处,你可以将光标定位到你需要查看的那一行,然后使用这个功能,代码会运行至光标行,而不需要打断点。 Evaluate Expression (Alt + F8):计算表达式,后面章节详细说明。 2、第二组按钮,共7个按钮,从上到下依次如下: Rerun ‘xxxx’:重新运行程序,会关闭服务后重新启动程序。 Update ‘tech’ application (Ctrl + F5):更新程序,一般在你的代码有改动后可执行这个功能。而这个功能对应的操作则是在服务配置里,如图2.3。 Resume Program (F9):恢复程序,比如,你在第20行和25行有两个断点,当前运行至第20行,按F9,则运行到下一个断点(即第25行),再按F9,则运行完整个流程,因为后面已经没有断点了。 Pause Program:暂停程序,启用Debug。目前没发现具体用法。 Stop ‘xxx’ (Ctrl + F2):连续按两下,关闭程序。有时候你会发现关闭服务再启动时,报端口被占用,这是因为没完全关闭服务的原因,你就需要查杀所有JVM进程了。 View Breakpoints (Ctrl + Shift + F8):查看所有断点,后面章节会涉及到。 Mute Breakpoints:哑的断点,选择这个后,所有断点变为灰色,断点失效,按F9则可以直接运行完程序。再次点击,断点变为红色,有效。如果只想使某一个断点失效,可以在断点上右键取消Enabled,如图2.4,则该行断点失效。 更新程序,On ‘Update’ actions,执行更新操作时所做的事情,一般选择’Update classes and resources’,即更新类和资源文件。 一般配合热部署插件会更好用,如JRebel,这样就不用每次更改代码后还要去重新启动服务。如何激活JRebel,在最后章节附上。 下面的On frame deactivation,在IDEA窗口失去焦点时触发,即一般你从idea切换到浏览器的时候,idea会自动帮你做的事情,一般可以设置Do nothing,频繁切换会比较消耗资源的。 三、变量查看在Debug过程中,跟踪查看变量的变化是非常必要的,这里就简单说下IDEA中可以查看变量的几个地方,相信大部分人都了解。 1、如下,在IDEA中,参数所在行后面会显示当前变量的值。 2、光标悬停到参数上,显示当前变量信息。点击+号查看详情 3、在Variables里查看,这里显示当前方法里的所有变量。 4、在Watches里,点击New Watch,输入需要查看的变量。或者可以从Variables里拖到Watche里查看。 如果你发现你没有Watches,可能在下图所在的地方。 四、计算表达式在前面提到的计算表达式如图4.1的按钮,Evaluate Expression (Alt + F8) 。可以使用这个操作在调试过程中计算某个表达式的值,而不用再去打印信息。 1、按Alt + F8或按钮,或者,你可以选中某个表达式再Alt + F8,弹出计算表达式的窗口,如下,回车或点击Evaluate计算表达式的值。 这个表达式不仅可以是一般变量或参数,也可以是方法,当你的一行代码中调用了几个方法时,就可以通过这种方式查看查看某个方法的返回值。 2、设置变量,在计算表达式的框里,可以改变变量的值,这样有时候就能很方便我们去调试各种值的情况了不是。 五、智能步入想想,一行代码里有好几个方法,怎么只选择某一个方法进入。之前提到过使用Step Into (Alt + F7) 或者 Force Step Into (Alt + Shift + F7)进入到方法内部,但这两个操作会根据方法调用顺序依次进入,这比较麻烦。 那么智能步入就很方便了,智能步入,这个功能在Run里可以看到,Smart Step Into (Shift + F7),如图5.1 按Shift + F7,会自动定位到当前断点行,并列出需要进入的方法, 点击方法进入方法内部。 如果只有一个方法,则直接进入,类似Force Step Into。 六、断点条件设置通过设置断点条件,在满足条件时,才停在断点处,否则直接运行。 通常,当我们在遍历一个比较大的集合或数组时,在循环内设置了一个断点,难道我们要一个一个去看变量的值?那肯定很累,说不定你还错过这个值得重新来一次。 1、在断点上右键直接设置当前断点的条件,我设置exist为true时断点才生效。 2、点击View Breakpoints (Ctrl + Shift + F8),查看所有断点。 Java Line Breakpoints 显示了所有的断点,在右边勾选Condition,设置断点的条件。 勾选Log message to console,则会将当前断点行输出到控制台。 勾选Evaluate and log,可以在执行这行代码是计算表达式的值,并将结果输出到控制台。 3、再说说右边的Filters过滤,这些一般情况下不常用,简单说下意思。 Instance filters:实例过滤,输入实例ID(如下图中的实例ID),但是我这里没有成功,不知道什么原因,知道的朋友留个言。 Class filters:类过滤,根据类名过滤,同样没有成功…. Pass count:用于循环中,如果断点在循环中,可以设置该值,循环多少次后停在断点处,之后的循环都会停在断点处。 4、异常断点,通过设置异常断点,在程序中出现需要拦截的异常时,会自动定位到异常行。 如图,点击+号添加Java Exception Breakpoints,添加异常断点。然后输入需要断点的异常类,如图6.7,之后可以在Java Exception Breakpoints里看到添加的异常断点。 我这里添加了一个NullPointerException异常断点,如图,出现空指针异常后,自动定位在空指针异常行。 七、多线程调试一般情况下我们调试的时候是在一个线程中的,一步一步往下走。但有时候你会发现在Debug的时候,想发起另外一个请求都无法进行了? 那是因为IDEA在Debug时默认阻塞级别是ALL,会阻塞其它线程,只有在当前调试线程走完时才会走其它线程。可以在View Breakpoints里选择Thread,如图,然后点击Make Default设置为默认选项。 切换线程,在图中Frames的下拉列表里,可以切换当前的线程,如下我这里有两个Debug的线程,切换另外一个则进入另一个Debug的线程。 八、回退断点在调试的时候,想要重新走一下流程而不用再次发起一个请求? 1、首先认识下这个方法调用栈,如图,首先请求进入DemoController的insertDemo方法,然后调用insert方法,其它的invoke我们且先不管,最上面的方法是当前断点所在的方法。 2、断点回退 所谓的断点回退,其实就是回退到上一个方法调用的开始处,在IDEA里测试无法一行一行地回退或回到到上一个断点处,而是回到上一个方法。 回退的方式有两种,一种是Drop Frame按钮,按调用的方法逐步回退,包括三方类库的其它方法(取消Show All Frames按钮会显示三方类库的方法,下图2)。 第二种方式,在调用栈方法上选择要回退的方法,右键选择Drop Frame,回退到该方法的上一个方法调用处,此时再按F9(Resume Program),可以看到程序进入到该方法的断点处了。 但有一点需要注意,断点回退只能重新走一下流程,之前的某些参数/数据的状态已经改变了的是无法回退到之前的状态的,如对象、集合、更新了数据库数据等等。 九、中断Debug想要在Debug的时候,中断请求,不要再走剩余的流程了? 有些时候,我们看到传入的参数有误后,不想走后面的流程了,怎么中断这次请求呢(后面的流程要删除数据库数据呢….),难道要关闭服务重新启动程序?嗯,我以前也是这么干的。 确切的说,我也没发现可以直接中断请求的方式(除了关闭服务),但可以通过Force Return,即强制返回来避免后续的流程。 点击Force Return,弹出Return Value的窗口,我这个方法的返回类型为Map,所以,我这里直接返回 results,来强制返回,从而不再进行后续的流程。或者你可以new HashMap<>()。 参考文章:参考链接","link":"/develop/intellj-idea-%E8%AF%A6%E7%BB%86%E8%B0%83%E8%AF%95%E4%BB%A3%E7%A0%81debug.html"},{"title":"动态规划DP算法详解","text":"定义动态规划(dynamic programing)和分治法类似,都是通过组合子问题的解来求解原问题的解。(在经典排序算法中的二路归并排序和快速排序都用到了分而治之的思想-分治法)。 分治法是将原问题划分为没有交集,相互独立的子问题,并分别求解后再进行合并,求出原问题的解。 动态规划应用于子问题重叠的情况,即不同的子问题具有公共的子子问题。分治法会做许多不必要的工作,它会反复地求解那些公共子问题。动态规划算法对每个子问题只求解一次,将其解保存在一个表格中,从而无需每次求解一个子子问题时都需要重新计算。 动态规划上用来求解最优化问题(optimization problem)。 可以按照下面四个步骤来设计一个动态规划算法: 1、刻画一个最优解的结构特征。 2、递归地定义最优解的值。 3、计算最优解的值,通常采用自底向上的方法。 4、利用计算出的信息构造一个最优解。 对于确定状态转移方程就在第一步和第二步中,首先要确定问题的决策对象,接着对决策对象划分阶段并确定各个阶段的状态变量,最后建立各阶段的状态变量的转移方程。 例如用dp[i]表示以序列中第i个数字结尾的最长递增子序列长度和最长公共子序列中用dp[i][j]表示的两个字符串中前 i、 j 个字符的最长公共子序列,我们就是通过对这两个数字量的不断求解最终得到答案的。这个数字量就被我们称为状态。状态是描述问题当前状况的一个数字量。首先,它是数字的,是可以被抽象出来保存在内存中的。其次,它可以完全的表示一个状态的特征,而不需要其他任何的辅助信息。最后,也是状态最重要的特点,状态间的转移完全依赖于各个状态本身,如最长递增子序列中,dp[x]的值由 dp[i](i < x)的值确定。若我们在分析动态规划问题的时候能够找到这样一个符合以上所有条件的状态,那么多半这个问题是可以被正确解出的。所以说,解动态规划问题的关键,就是寻找一个好的状态。 最优子结构用动态规划求解最优化问题的第一步就是刻画一个最优解的结构特征。如果一个问题的最优解包含其子问题的最优解,我们称此问题具有最优子结构性质。因此,某个问题是否适合用动态规划,它是否具有最优子结构性质是一个好的标准。使用动态规划方法时,我们用子问题的最优解来构造原问题的最优解。 如何发掘最优子结构的性质?1、证明问题最优解的第一个组成部分是做出一个选择,而做出这个选择将会产生一个或多个待解的子问题。 2、对一个给定问题,在其可能的第一步选择中,假定已经知道哪种选择才会得到最优解。而我们并不关心这种选择具体是如何得到的,只是假定已经知道了这种选择。 3、给定获取的最优解选择后,确定这次选择会产生哪些子问题,以及如何最好地刻画子问题空间。 4、利用“剪切-粘贴(cut and paste)”技术证明作为构成原问题最优解组成部分,每个子问题的解就是它本身的最优解。 反证法:假定子问题的解不是自身的最优解,那么我们就可以从原问题中剪切掉这些非最优解,将最优解粘贴进去,从而得到原问题一个更优的解,这个解与最初的解的前提假设矛盾。 刻画子问题空间的经验保持子问题空间尽量简单,只在必要时才扩展它。例如下一节的例子,求钢条切割的最大收益问题中,子问题空间包含的问题为:对每个i值,长度为i的钢条最优切割问题。 对于不同问题领域,最优子结构的不同体现在两个方面: 原问题的最优解中涉及到多个子问题。 在确定最优解使用哪些子问题时,需要考察多少种选择。 重叠子问题适合用动态规划方法求解最优化问题的第二个性质是子问题的空间必须足够小,即问题的递归算法会反复地求解相同的子问题,而不是一直生成新的子问题。动态规划算法会对重叠的子问题只求解一次,并保存在一张表里,需要用的时候直接查表即可,每次查表的时间代价为常量O(1)。 核心问题动态规划的核心是状态和状态转移方程。 在记忆化搜索中,可以为正在处理的表项声明一个引用,简化对它的读写操作; 动态规划解决的是多阶段决策问题; 1初始状态→│决策1│→│决策2│→…→│决策n│→结束状态 和分治法最大的区别在于:适合于用动态规划的问题,经过分解以后得到的子问题往往不是相互独立的(即下一个子阶段的求解是建立在上一个子阶段的基础之上,进行进一步的求解,而不是相互独立的问题) 动态规划问题一般由难到易分为一维动态规划,二维动态规划,多维动态规划,以及多变量动态规划问题。其中多维动态规划问题又可以进行降维。动态规划问题求解的最重要的一步就是求解出 状态转移方程 特性 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理. 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势,动态规划可以避免多次计算) 动态规划的解题核心主要分为两步: 第一步:状态的定义 第二步:状态转移方程的定义 在这里,我们为了避免混淆用“状态”这个词来替代“问题”这个词。“问题”表示的含义类似:题目、要求解的内容、题干中的疑问句这样的概念。状态表示我们在求解问题之中对问题的分析转化。 第一步:状态的定义 有的问题过于抽象,或者过于啰嗦干扰我们解题的思路,我们要做的就是将题干中的问题进行转化(换一种说法,含义不变)。转化成一系列同类问题的某个解的情况,比如说: 题目:求一个数列中最大连续子序列的和。 我们要将这个原问题转化为: 状态定义:Fk是第k项前的最大序列和,求F1~FN中最大值。 通过换一种表述方式,我们清晰的发现了解决问题的思路,如何求出F1~FN中的最大值是解决原问题的关键部分。上述将原问题转化成另一种表述方式的过程叫做:状态的定义。这样的状态定义给出了一种类似通解的思路,把一个原来毫无头绪的问题转换成了可以求解的问题。 第二步:状态转移方程的定义 在进行了状态的定义后,自然而然的想到去求解F1~FN中最大值。这也是状态定义的作用,让我们把一个总体的问题转化成一系列问题,而第二步:状态转移方程的定义则告诉我们如何去求解一个问题,对于上述已经转换成一系列问题我们要关注的点就在于:如何能够用前一项或者前几项的信息得到下一项,这种从最优子状态转换为下一个最优状态的思路就是动态规划的核心。对于上面的例子题目来说,状态转移方程的定义应该是: Fk=max{Fk-1+Ak,Ak}Fk是前k项的和,Ak是第k项的值 仔细思考一番,我们能够得到这样的结论,对于前k个项的最大子序列和是前k-1项的最大子序列和Fk与第k项的和、或者第k项两者中较大的。如果大家还是不能理解这个原理建议用演算纸自己计算一番,这里就不过多赘述了。这种状态转移的思路就是DP的核心。 状态转移方程动态规划中当前的状态往往依赖于前一阶段的状态和前一阶段的决策结果。例如我们知道了第i个阶段的状态Si以及决策Ui,那么第i+1阶段的状态Si+1也就确定了。所以解决动态规划问题的关键就是确定状态转移方程,一旦状态转移方程确定了,那么我们就可以根据方程式进行编码。 各种模型的状态转移方程汇总如下:1、最长公共子串假设两个字符串为str1和str2,它们的长度分别为n和m。d[i][j]表示str1中前i个字符与str2中前j个字符分别组成的两个前缀字符串的最长公共长度。这样就把长度为n的str1和长度为m的str2划分成长度为i和长度为j的子问题进行求解。状态转移方程如下: 1234dp[0][j] = 0; (0<=j<=m)dp[i][0] = 0; (0<=i<=n)dp[i][j] = dp[i-1][j-1] +1; (str1[i] == str2[j])dp[i][j] = 0; (str1[i] != str2[j]) 因为最长公共子串要求必须在原串中是连续的,所以一但某处出现不匹配的情况,此处的值就重置为0。 详细代码请看最长公共子串。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768#include \"stdafx.h\"#include <stdio.h>#include <string>#include <iostream>using namespace std;#define MAXSIZE 100char str1[MAXSIZE];char str2[MAXSIZE];int dp[MAXSIZE][MAXSIZE];//'y'代表str1[i] = str2[j];'n'反之char path[MAXSIZE][MAXSIZE];void printComStr(int i, int j){ if (path[i][j] == 'n' || i == 0 || j == 0) return; if (path[i][j] == 'y') { printComStr(i - 1, j - 1); cout << str1[i - 1]; }}int main(){ int n, m; int indexi, indexj; int ans = 0; cin >> str1 >> str2; n = strlen(str1); m = strlen(str2); for (int i = 0; i <= n;i++) for (int j = 0; j <= m; j++) { dp[i][j] = 0; } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (str1[i - 1] == str2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; path[i][j] = 'y'; } else { dp[i][j] = 0; path[i][j] = 'n'; } } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (ans < dp[i][j]) { ans = dp[i][j]; indexi = i; indexj = j; } } cout << ans << endl; cout << indexi << ' ' << indexj << endl; printComStr(indexi, indexj);} 2、最长公共子序列区分一下,最长公共子序列不同于最长公共子串,序列是保持子序列字符串的下标在str1和str2中的下标顺序是递增的,该字符串在原串中并不一定是连续的。同样的我们可以假设dp[i][j]表示为字符串str1的前i个字符和字符串str2的前j个字符的最长公共子序列的长度。状态转移方程如下: 1234dp[0][j] = 0; (0<=j<=m)dp[i][0] = 0; (0<=i<=n)dp[i][j] = dp[i-1][j-1] +1; (str1[i-1] == str2[j-1])dp[i][j] = max{dp[i][j-1],dp[i-1][j]}; (str1[i-1] != str2[j-1]) 详细代码请看最长公共子序列。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667#include \"stdafx.h\"#include <iostream>#include <string>using namespace std;#define MAXSIZE 101char str1[MAXSIZE];char str2[MAXSIZE];//'l'表示dp[i][j] = dp[i][j] = dp[i - 1][j];//‘q’表示dp[i][j] = dp[i][j] = dp[i - 1][j];//'u'表示dp[i][j] = dp[i][j - 1];char path[MAXSIZE][MAXSIZE];int dp[MAXSIZE][MAXSIZE];void printLCS(int i, int j){ if (i == 0 || j == 0) return; if (path[i][j] == 'q') { printLCS(i - 1, j - 1); cout << str1[i-1] << ' '; } else if (path[i][j] == 'u') printLCS(i - 1, j); else printLCS(i, j - 1); } int main(){ int n, m; cin >> str1 >> str2; n = strlen(str1); m = strlen(str2); //初始化 for (int i = 0; i < n;i++) for (int j = 0; j < m; j++) dp[i][j] = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (str1[i - 1] == str2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; path[i][j] = 'q'; } else { if (dp[i - 1][j] >= dp[i][j - 1]) { dp[i][j] = dp[i - 1][j]; path[i][j] = 'u'; } else { dp[i][j] = dp[i][j - 1]; path[i][j] = 'l'; } } } cout << dp[n][m] << endl; printLCS(n, m); return 0;} 3、最长递增子序列(最长递减子序列)因为两者的思路都是一样的,所以只给出最长递增子序列的状态转移方程。假设有序列{a1,a2,…,an},我们求其最长递增子序列长度。按照递推求解的思想,我们用F[i]代表若递增子序列以ai结束时它的最长长度。当 i 较小,我们容易直接得出其值,如 F[1] = 1。那么,如何由已经求得的 F[i]值推得后面的值呢?假设,F[1]到F[x-1]的值都已经确定,注意到,以ax 结尾的递增子序列,除了长度为1的情况,其它情况中,ax都是紧跟在一个由 ai(i < x)组成递增子序列之后。要求以ax结尾的最长递增子序列长度,我们依次比较 ax 与其之前所有的 ai(i < x), 若ai小于 ax,则说明ax可以跟在以ai结尾的递增子序列之后,形成一个新的递 增子序列。又因为以ai结尾的递增子序列最长长度已经求得,那么在这种情况下,由以 ai 结尾的最长递增子序列再加上 ax 得到的新的序列,其长度也可以确定,取所有这些长度的最大值,我们即能得到 F[x]的值。特殊的,当没有ai(i < x)小 于ax, 那么以 ax 结尾的递增子序列最长长度为1。 即F[x] = max{1,F[i]+1|ai<ax && i<x}。 详细代码请看最长递增子序列。 123456789101112131415161718192021222324252627#include <iostream>using namespace std;const int MAXSIZE = 10;const int MIN = 0;int arr[] = { 1, 4, 3, 2, 6, 5 };int F[MAXSIZE];int main(){ int maxLen = MIN; memset(F, 0, MAXSIZE); F[0] = 1; for (int i = 1; i < 6; i++) { for (int j = 0; j < i; j++) { if (arr[i] > arr[j] && maxLen < F[j]) { maxLen = F[j]; } } F[i] = maxLen + 1; } for (int k = 0; k < 6; k++) cout << F[k] << ' '; cout << endl;} 4、最大子序列和的问题假设有序列{a1,a2,…,an},求子序列的和最大问题,我们用dp[i]表示以ai结尾的子序列的最大和。 12345dp[1] = a1; (a1>=0 && i == 1)dp[i] = dp[i-1]+ai; (ai>=0 && i>=2)dp[i] = 0; (dp[i-1] + ai <=0 && i>=2) 详细代码请看最大子序列的和。 12345678910111213141516171819202122232425262728293031#include <iostream>using namespace std;#define MAXSIZE 100int a[MAXSIZE];int dp[MAXSIZE];int max = 0;int main(){ int n; cin >> n; memset(dp, 0, MAXSIZE); for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) { if (dp[i-1] + a[i] > 0) { dp[i] = dp[i - 1] + a[i]; } else { dp[i] = 0; } if (max < dp[i]) max = dp[i]; } cout << max << endl; return 0;} 5、数塔问题(动态搜索)给定一个数组data[n][m]构成一个数塔求从最上面走到最低端经过的路径和最大。可以假设dp[i][j]表示走到第i行第j列位置处的最大值,那么可以推出状态转移方程: 1dp[i][j] = max{dp[i-1][j-1],dp[i-1][j]} + data[i][j]; 12345for(i=n-1;i>=1;i--){ for(j=1;j<=i;j++){ dp[i][j]=max{dp[i-1][j-1],dp[i-1][j]}+s[i][j] }} 6、(01)背包问题这是一个经典的动态规划问题,另外在贪心算法里也有背包问题,至于二者的区别在此就不做介绍了。 假设有N件物品和一个容量为V的背包。第i件物品的体积是v[i],价值是c[i],将哪些物品装入背包可使价值总和最大? 每一种物品都有两种可能即放入背包或者不放入背包。可以用dp[i][j]表示第i件物品放入容量为j的背包所得的最大价值,则状态转移方程可以推出如下: 1dp[i][j]=max{dp[i-1][j-v[i]]+c[i],dp[i-1][j]}; 1234567891011for (int i = 1;i <= N;i++) //枚举物品 { for (int j = 0;j <= V;j++) //枚举背包容量 { f[i][j] = f[i - 1][j]; if (j >= v[i]) { f[i][j] = Max(f[i - 1][j],f[i - 1][j - v[i]] + c[i]); } } } 说明 12345678901背包问题与背包问题的区别在于,01背包,物品的选择只有两种一种是拿,另一种是不拿,而背包问题在于,物品可以只取一部分。所以01背包问题不能用贪心算法解决。以dp[i][j]表示用i种物品,重量为j表示所取得的价值。对于第i种物品,如果第i种物品重量大于j,就证明第i种物品肯定不能取,这时的dp[i][j]=dp[i-1][j]如果第i种物品重量小于j,那就会出现两种情况,采用i的话,物品价值dp[i][j]=采用前面的i-1种物品,所占用的重量为j-i.getweight,所产生的价值+第i 种物品的价值,。如果不采用i,价值为dp[i-1][j]。换成数学表达式就是dp[i][j]=Math.max(dp[i-1][j-weight]+value,dp[i-1][j]);比如当i=5,j=10时,dp[5][10]就代表了所取得的最大价值。到这里我们就完成了任务的一半,接下为我们要寻找到底哪些物品放入了背包,从前面的表达式我们可以发现,当dp[i][j]=dp[i-1][j-weight]时,这时为i的物品就会放入背包,所以我们从结果,开始往回走,遇到这种情况,就说明有物品放入背包,然后物品数减1,重量减去为i的重量,继续,最后就能求出哪 些物品放入背包了。 JAVA代码 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455public class Test { public static void main(String[] args) { int allweight=12; //总价值 int num=8; //物品 bao[] baos=new bao[num+1]; baos[1]=new bao(2, 13); baos[2]=new bao(1, 10); baos[3]=new bao(3, 24); baos[4]=new bao(2, 15); baos[5]=new bao(4, 28); baos[6]=new bao(5, 33); baos[7]=new bao(3, 20); baos[8]=new bao(1, 8); int[][] dp=new int[num+1][allweight+1]; //构成动态规划表 for(int i=0;i<=num;i++) { for(int j=0;j<=allweight;j++) { if(i==0||j==0) { dp[i][j]=0; }else { if (j<baos[i].getWeight()) { dp[i][j]=dp[i-1][j]; }else { int value=baos[i].getValue(); int weight=baos[i].getWeight(); dp[i][j]=Math.max(dp[i-1][j-weight]+value,dp[i-1][j]); } } System.out.println(\"dp\"+\"[\"+i+\"]\"+\"[\"+j+\"]\"+dp[i][j]); } } int m=num; int n=allweight; int all=dp[m][n]; //寻找哪些物品放入背包 while(all>=0) { if (m>0&&dp[m][n]==dp[m-1][n]) { m=m-1; }else { System.out.println(baos[m]+\"加入背包\"); m=m-1; if (m==0) { return; }else { n=n-baos[m].getWeight(); all=all-baos[m].getWeight(); } } } }} 可以参照动态规划 - 0-1背包问题的算法优化、动态规划-完全背包问题、动态规划-多重背包问题、01背包问题 7、矩阵连乘(矩阵链问题)-参考《算法导论》例如矩阵链<A1,A2,A3>,它们的维数分别为10100,1005,550,那么如果顺序相乘即((A1A2)A3),共需101005 + 10550 = 7500次乘法,如果按照(A1(A2A3))顺序相乘,却需做100550 + 10100*50 = 75000次乘法。两者之间相差了10倍,所以说矩阵链的相乘顺序也决定了计算量的大小。 我们用利用动态规划的方式(dp[i][j]表示第i个矩阵至第j个矩阵这段的最优解,还有对于两个矩阵A(i,j)B(j,k)则需要ij*k次乘法),推出状态转移方程: 123dp[i][j] = 0; (i ==j,表示只有一个矩阵,计算次数为0)dp[i][j] = min{dp[i][k] + dp[k+1][j] + p[i-1]*p[k]*p[j]}; (i<j && i<=k<j) dp[1][n]即为最终求解. 123456789101112131415161718192021222324252627282930313233343536#define MAXSIZE 100int dp[MAXSIZE][MAXSIZE];//存储最小的就算次数int s[MAXSIZE][MAXSIZE];//存储断点,用在输出上面int i, j, tmp;for (int l = 2; l <= n; l++){//j-i的长度,由于长度为1是相同的矩阵那么为0不用计算 for (i = 1; i <= n - l + 1; i++){//由于j-i =l - 1 , 那么j的最大值为n,所以i上限为 n - l+1; j = i + l - 1;//由于j-i = l - 1 , 那么j = l+i-1 dp[i][j] = dp[i + 1][j] + r[i] * c[i] * c[j];//初始化,就是k = i; s[i][j] = i; for (k = i + 1; k < j; k++){//循环枚举k i < k < j tmp = dp[i][k] + dp[k + 1][j] + r[i] * c[k] * c[j]; if (dp[i][j] > tmp){ dp[i][j] = tmp;//更新为最小值 s[i][j] = k; } } }}//递归调用输出void output(int i, int j){ if (i == j){ printf(\"A%d\", i);//当两个相等的时候就不用继续递归就输出A return;//返回上一层 } else{ printf(\"(\"); output(i, s[i][j]); printf(\" x \"); output(s[i][j] + 1, j); printf(\")\"); }} 总结太难了,没事多来看看示例希望早日彻底吃透! 参考文章:参考链接1参考链接2","link":"/algorithm/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92DP%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3.html"},{"title":"算法成长之路leetcode9-10","text":"9. Palindrome NumberDetermine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward. Example123456789101112131415161718Example 1:Input: 121Output: trueExample 2:Input: -121Output: falseExplanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.Example 3:Input: 10Output: falseExplanation: Reads 01 from right to left. Therefore it is not a palindrome.Follow up:Coud you solve it without converting the integer to a string? Java 题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100package algorithm;public class Leetcode9 { /** * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 * * 示例 1: * * 输入: 121 * 输出: true * 示例 2: * * 输入: -121 * 输出: false * 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 * 示例 3: * * 输入: 10 * 输出: false * 解释: 从右向左读, 为 01 。因此它不是一个回文数。 * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/palindrome-number * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 * @param x * @return */ public static boolean isPalindrome(int x) { if (x >= 0 && x < 10) { return true; } String source = x + \"\"; int length = source.length(); // mid中间位置1,mid1中间位置2 int mid, mid1; // 偶数 if (length % 2 == 0) { // 如 1221 偶数,中间位置分别为2,2 mid = length / 2 - 1; mid1 = mid + 1; } else { // 奇数时,212,中间位置分别是1,1 mid = length / 2; mid1 = mid; } // 确定中心位置向两边扩展是否相等,直到扩展完位置 while (mid >= 0 && source.charAt(mid) == source.charAt(mid1)) { mid = mid - 1; mid1 = mid1 + 1; } // 如果循环结束并且所有数都遍历完 if (mid == -1 && mid1 == length) { return true; } else { return false; } } public static boolean isPalindrome1(int x) { // 特殊情况: // 如上所述,当 x < 0 时,x 不是回文数。 // 同样地,如果数字的最后一位是 0,为了使该数字为回文, // 则其第一位数字也应该是 0 // 只有 0 满足这一属性 if (x < 0 || (x % 10 == 0 && x != 0)) { return false; } // 一位一位反转的数 int revertedNumber = 0; // 如121 while (x > revertedNumber) { revertedNumber = revertedNumber * 10 + x % 10; x /= 10; System.out.println(\"x=\" + x + \",revertedNumber=\" + revertedNumber); } // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。 // 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123, // 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。 return x == revertedNumber || x == revertedNumber / 10; } public static void main(String[] args) { /** * -1 * 121 * 222 * 2222 * 1221 * -12 */ System.out.println(isPalindrome(1221)); System.out.println(isPalindrome1(121)); }} 10. Regular Expression MatchingGiven an input string (s) and a pattern (p), implement regular expression matching with support for ‘.’ and ‘*’. ‘.’ Matches any single character.‘*’ Matches zero or more of the preceding element.The matching should cover the entire input string (not partial). Note: s could be empty and contains only lowercase letters a-z.p could be empty and contains only lowercase letters a-z, and characters like . or *. Example12345678910111213141516171819202122232425262728293031323334Example 1:Input:s = \"aa\"p = \"a\"Output: falseExplanation: \"a\" does not match the entire string \"aa\".Example 2:Input:s = \"aa\"p = \"a\"Output: trueExplanation: '' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes \"aa\".Example 3:Input:s = \"ab\"p = \".\"Output: trueExplanation: \".\" means \"zero or more (*) of any character (.)\".Example 4:Input:s = \"aab\"p = \"cab\"Output: trueExplanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches \"aab\".Example 5:Input:s = \"mississippi\"p = \"misisp*.\"Output: false JAVA 题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455package algorithm;public class Leetcode10 { /** * 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。 * * '.' 匹配任意单个字符 * '*' 匹配零个或多个前面的那一个元素 * 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 * * 说明: * * s 可能为空,且只包含从 a-z 的小写字母。 * p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 * 示例 1: * * 输入: * s = \"aa\" * p = \"a\" * 输出: false * 解释: \"a\" 无法匹配 \"aa\" 整个字符串。 * 示例 2: * * 输入: * s = \"aa\" * p = \"a*\" * 输出: true * 解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 \"aa\" 可被视为 'a' 重复了一次。 * 示例 3: * * 输入: * s = \"ab\" * p = \".*\" * 输出: true * 解释: \".*\" 表示可匹配零个或多个('*')任意字符('.')。 * 示例 4: * * 输入: * s = \"aab\" * p = \"c*a*b\" * 输出: true * 解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 \"aab\"。 * 示例 5: * * 输入: * s = \"mississippi\" * p = \"mis*is*p*.\" * 输出: false * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/regular-expression-matching * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 * * * * 如果模式串中有星号,它会出现在第二个位置, * 即pattern[1] 。这种情况下,我们可以直接忽略模式串中这一部分, * 或者删除匹配串的第一个字符,前提是它能够匹配模式串当前位置字符,即 pattern[0] 。 * 如果两种操作中有任何一种使得剩下的字符串能匹配,那么初始时,匹配串和模式串就可以被匹配。 * * @param text * @param pattern * @return */ public static boolean isMatch(String text, String pattern) { // 递归回溯 if (pattern.isEmpty()) return text.isEmpty(); boolean first_match = (!text.isEmpty() && (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));// 判断第一个是否相等 System.out.println(\"t=\"+text+\",p=\"+pattern+\",firstM=\"+first_match); if (pattern.length() >= 2 && pattern.charAt(1) == '*'){ // 长度>=2 并且p第二个是* System.out.println(\"if1\"); return (isMatch(text, pattern.substring(2)) || // 直接忽略模式串中这一部分 如t=abc,p=a*. 直接忽略 a* (first_match && isMatch(text.substring(1), pattern))); // 删除匹配串的第一个字符 } else { System.out.println(\"if2\"); return first_match && isMatch(text.substring(1), pattern.substring(1));// 第一个匹配后,后面逐个匹配 } } /** * 状态 * 首先状态 dp 一定能自己想出来。 * dp[i][j] 表示 s 的前 ii 个是否能被 p 的前 jj 个匹配 * * 转移方程 * 怎么想转移方程?首先想的时候从已经求出了 dp[i-1][j-1] 入手,再加上已知 s[i]、p[j],要想的问题就是怎么去求 dp[i][j]。 * * 已知 dp[i-1][j-1] 意思就是前面子串都匹配上了,不知道新的一位的情况。 * 那就分情况考虑,所以对于新的一位 p[j] s[i] 的值不同,要分情况讨论: * * 考虑最简单的 p[j] == s[i] : dp[i][j] = dp[i-1][j-1] * 然后从 p[j] 可能的情况来考虑,让 p[j]=各种能等于的东西。 * * p[j] == \".\" : dp[i][j] = dp[i-1][j-1] * * p[j] ==\" * \": * * 第一个难想出来的点:怎么区分 *∗ 的两种讨论情况 * 首先给了 *,明白 * 的含义是 匹配零个或多个前面的那一个元素,所以要考虑他前面的元素 p[j-1]。* 跟着他前一个字符走,前一个能匹配上 s[i],* 才能有用,前一个都不能匹配上 s[i],* 也无能为力,只能让前一个字符消失,也就是匹配 00 次前一个字符。 * 所以按照 p[j-1] 和 s[i] 是否相等,我们分为两种情况: * * 3.1 p[j-1] != s[i] : dp[i][j] = dp[i][j-2] * 这就是刚才说的那种前一个字符匹配不上的情况。 * 比如(ab, abc * )。遇到 * 往前看两个,发现前面 s[i] 的 ab 对 p[j-2] 的 ab 能匹配,虽然后面是 c*,但是可以看做匹配 00 次 c,相当于直接去掉 c *,所以也是 True。注意 (ab, abc**) 是 False。 * 3.2 p[j-1] == s[i] or p[j-1] == \".\": * * 前面那个字符,能匹配 s[i],或者 * 前面那个字符是万能的 . * 因为 . * 就相当于 . .,那就只要看前面可不可以匹配就行。 * 比如 (##b , ###b *),或者 ( ##b , ### . * ) 只看 ### 后面一定是能够匹配上的。 * 所以要看 b 和 b * 前面那部分 ## 的地方匹不匹配。 * 第二个难想出来的点:怎么判断前面是否匹配 * dp[i][j] = dp[i-1][j] // 多个字符匹配的情况 * or dp[i][j] = dp[i][j-1] // 单个字符匹配的情况 * or dp[i][j] = dp[i][j-2] // 没有匹配的情况 * 看 ### 匹不匹配,不是直接只看 ### 匹不匹配,要综合后面的 b b* 来分析 * 这三种情况是 oror 的关系,满足任意一种都可以匹配上,同时是最难以理解的地方: * * dp[i-1][j] 就是看 s 里 b 多不多, ### 和 ###b * 是否匹配,一旦匹配,s 后面再添个 b 也不影响,因为有 * 在,也就是 ###b 和 ###b *也会匹配。 * * dp[i][j-1] 就是去掉 * 的那部分,###b 和 ###b 是否匹配,比如 qqb qqb * * dp[i][j-2] 就是 去掉多余的 b *,p 本身之前的能否匹配,###b 和 ### 是否匹配,比如 qqb qqbb* 之前的 qqb qqb 就可以匹配,那多了的 b * 也无所谓,因为 b * 可以是匹配 00 次 b,相当于 b * 可以直接去掉了。 * * 三种满足一种就能匹配上。 * * 为什么没有 dp[i-1][j-2] 的情况? 就是 ### 和 ### 是否匹配?因为这种情况已经是 dp[i][j-1] 的子问题。也就是 s[i]==p[j-1],则 dp[i-1][j-2]=dp[i][j-1]。 * * 最后来个归纳: * 如果 p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1]; * 如果 p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1]; * 如果 p.charAt(j) == '*': * 如果 p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2] //in this case, a* only counts as empty * 如果 p.charAt(i-1) == s.charAt(i) or p.charAt(i-1) == '.': * dp[i][j] = dp[i-1][j] //in this case, a* counts as multiple a * or dp[i][j] = dp[i][j-1] // in this case, a* counts as single a * or dp[i][j] = dp[i][j-2] // in this case, a* counts as empty * * 作者:kao-la-7 * 链接:https://leetcode-cn.com/problems/regular-expression-matching/solution/dong-tai-gui-hua-zen-yao-cong-0kai-shi-si-kao-da-b/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * @param s * @param p * @return */ public static boolean isMatch1(String s, String p) { // 动态规划 if (s == null || p == null) { return false; } boolean[][] dp = new boolean[s.length() + 1][p.length() + 1]; dp[0][0] = true;//dp[i][j] 表示 s 的前 i 个是否能被 p 的前 j 个匹配 for (int i = 0; i < p.length(); i++) { // here's the p's length, not s's if (p.charAt(i) == '*' && dp[0][i - 1]) { dp[0][i + 1] = true; // here's y axis should be i+1 } } for (int i = 0; i < s.length(); i++) { for (int j = 0; j < p.length(); j++) { if (p.charAt(j) == '.' || p.charAt(j) == s.charAt(i)) {//如果是任意元素 或者是对于元素匹配 dp[i + 1][j + 1] = dp[i][j]; } if (p.charAt(j) == '*') { if (p.charAt(j - 1) != s.charAt(i) && p.charAt(j - 1) != '.') {//如果前一个元素不匹配 且不为任意元素 dp[i + 1][j + 1] = dp[i + 1][j - 1]; } else { dp[i + 1][j + 1] = (dp[i + 1][j] || dp[i][j + 1] || dp[i + 1][j - 1]); /* dp[i][j] = dp[i-1][j] // 多个字符匹配的情况 or dp[i][j] = dp[i][j-1] // 单个字符匹配的情况 or dp[i][j] = dp[i][j-2] // 没有匹配的情况 */ } } } } return dp[s.length()][p.length()]; } // 官方解法-- enum Result { TRUE, FALSE } Result[][] memo; public boolean isMatch2(String text, String pattern) { // 自顶向下 官方 memo = new Result[text.length() + 1][pattern.length() + 1]; return dp(0, 0, text, pattern); } public boolean dp(int i, int j, String text, String pattern) { if (memo[i][j] != null) { return memo[i][j] == Result.TRUE; } boolean ans; if (j == pattern.length()) { ans = i == text.length(); } else { boolean first_match = (i < text.length() && (pattern.charAt(j) == text.charAt(i) || pattern.charAt(j) == '.')); if (j + 1 < pattern.length() && pattern.charAt(j + 1) == '*') { ans = (dp(i, j + 2, text, pattern) || first_match && dp(i + 1, j, text, pattern)); } else { ans = first_match && dp(i + 1, j + 1, text, pattern); } } memo[i][j] = ans ? Result.TRUE : Result.FALSE; return ans; } public boolean isMatch3(String text, String pattern) { //动态规划,自底向上 boolean[][] dp = new boolean[text.length() + 1][pattern.length() + 1]; dp[text.length()][pattern.length()] = true; for (int i = text.length(); i >= 0; i--) { for (int j = pattern.length() - 1; j >= 0; j--) { boolean first_match = (i < text.length() && (pattern.charAt(j) == text.charAt(i) || pattern.charAt(j) == '.')); if (j + 1 < pattern.length() && pattern.charAt(j + 1) == '*') { dp[i][j] = dp[i][j + 2] || first_match && dp[i + 1][j]; } else { dp[i][j] = first_match && dp[i + 1][j + 1]; } } } return dp[0][0]; } // 官方解法--- public static void main(String[] args) { // \"abc\",\"a*.\" // \"abc\",\"ab*.\" System.out.println(isMatch(\"abc\",\"ab*.\")); /** * log * t=abc,p=ab*.,firstM=true * if2 * t=bc,p=b*.,firstM=true * if1 * t=bc,p=.,firstM=true * if2 * t=c,p=b*.,firstM=false * if1 * t=c,p=.,firstM=true * if2 * true */ int cons[] = new int[]{1,2,3}; System.out.println(getLeastCoinAmount(3,cons)); } /** * * 常见DP小问题 参考自 https://www.cnblogs.com/fefjay/p/7541760.html * * 动态规划算法是一种比较灵活的算法,针对具体的问题要具体分析,其宗旨就是要找出要解决问题的状态, * 然后逆向转化为求解子问题,最终回到已知的初始态,然后再顺序累计各个子问题的解从而得到最终问题的解。 * * 关键点就是找到状态转移方程和初始边界条件,说白了就是要找到“递推公式”和初始值,然后计算时保存每一步中间结果,最后累加判断得到结果。 */ /** * 0.求数组最值 * 求数组最值方法很多,这里使用动态规划的思想来尝试处理,以便更好地理解DP的思想。为了方便这里假设数组a[i]大小为n,要找n个数当中的最大值。 * * 设dp[i]表示第0...i个数的最大值,dp[i-1]表示第0...i-1个数的最大值,所以求前i个数的最大值时, * 已经知道前i-1个是的最大值是dp[i-1],那么只需要比较dp[i-1]和第i个数谁大就知道了,即dp[i] = max(dp[-1], a[i])。 */ public int max(int[] a){ int len = a.length; int[] dp = new int[len]; dp[0] = a[0]; for(int i=1; i<len; i++){ dp[i] = (dp[i-1] > a[i]) ? dp[i-1] : a[i]; } return dp[len-1]; } /** * 1.求最大公共子序列长度 * 给定一个字符串,想要删掉某些字符使得最后剩下的字符构成一个回文串(左右对称的字符串,如abcba), * 问最少删掉多少个字符可获得一个最长回文串。 */ /** * 本题求回文串最大长度就转化为求两个字符串的最长公共子序列(不一定连续) * 策略:字符串可以看做是字符序列,即字符数组。 * 比如有序列A=a0,a1,a2...an;有序列B=b0,b1,b2,b3...bm;设A序列和B序列的公共子序列为C=c0,c1,c2,c3...ck。 * 设L[][]为公共子序列C的长度,L[i][j]的i、j分别表示A、B序列的字符下标,L[i][j]含义是A序列a0、a1、a2...ai和B序列b0、b1、b2、 * ...bj的公共子序列的长度。 * * 1)如果A序列的i字符和B序列的j字符相等,那么就有ck=ai=bj,公共子序列C的长度L[i][j]=L[i-1][j-1]+1。 * 2)如果A序列的i字符和B序列的j字符不相等,若ai != ck则C为a0...ai-1和b0...bj的最长子序列,若bj != ck则C为a0...ai和b0...bj-1的最长子序列, * 所以此时公共子序列长度为L[i][j] = max(L[i][j-1], L[i-1][j])。 */ public static int lcs(String s){ if (s == null ) { return -1; } String rs = new StringBuilder(s).reverse().toString(); char[] chars1 = s.toCharArray(); char[] chars2 = rs.toCharArray();//获得反序的字符串 int n = chars1.length; int[][] dp = new int[n+1][n+1]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if(chars1[i] == chars2[j]){ dp[i][j] = dp[i-1][j-1] + 1; }else { dp[i][j] = dp[i][j-1] > dp[i-1][j] ? dp[i][j-1] : dp[i-1][j]; } } } return n - dp[n][n]; } /** * 2.硬币凑钱问题 * 只有面值为1元、3元、5元的硬币,数量足够。现在要凑够n元,求需要的最少硬币枚数。 * * @param n 目标总钱数 * @param coins 硬币数组【1,3,5】 * @return 返回凑够n元需要的最少硬币数 */ public static int getLeastCoinAmount(int n, int[] coins){ if (coins == null || n < 0) { return -1; } if (n == 0){ return 0; } int[] dp = new int[n+1]; //dp[i]=j表示凑够i元最少需要j枚硬币。数组长度设为(n+1)保证可以访问dp[n]。 dp[0] = 0; for (int i = 1; i <= n; i++) { dp[i] = Integer.MAX_VALUE; } int coinValue = 0; for (int i = 1; i <= n; i++) {//问题规模从小到大,直到达到目标面值 for (int j = 0; j < coins.length; j++) {//遍历所有面值的硬币,j表示硬币面值的下标 coinValue = coins[j]; if (i - coinValue >= 0 && 1 + dp[i-coinValue] < dp[i]){ //当前方案的硬币数更少,则使用当前方案 dp[i] = 1 + dp[i-coins[j]]; } } } return dp[n]; } /** * 3.最长非降子序列 * 一个序列有N个数:A[1],A[2],…,A[N],求出最长非降子序列的长度。 */ /** * * 定义d(i)表示前i个数中\"以A[i]结尾\"的最长非降子序列的长度。 * 对序列A1...Ai,找到的最长子序列长度d[i]分两种情况: * (1)包含最后一个数Ai,即d[i]=max{d[j]+1}(1<=j<i且Aj<=Ai),满足条件的Aj可能会有多个,选最大的d[j],如果Aj都大于Ai则d[j]=0; * (2)不含最后一个数,即d[i]=d[i-1] * * 综上:d[i] = max{d[i-1], max{d[j]+1}} */ public static int longestIncreasingSubsequence(int[] a){ if (a == null) { return -1; } if (a.length < 1){ return 0; } int len = a.length; int[] dp = new int[len];//dp[i]系统自动初始化为0 dp[0] = 1; for (int i = 1; i < len; i++) {//迭代,求序列0...len-1的最长子序列长度 for (int j = 0; j < i; j++) {//寻找Ai之前的序列,看是否有不大于Ai的数字Aj if (a[j] <= a[i] && dp[i] < dp[j] + 1){//假设最长子序列包含最后一个数 dp[i] = dp[j] + 1; } } //寻找Ai之前的序列如果Ai都小于Aj,此时dp[i]并没有被修改仍为初始值0。所以包含最后一个数的最长子序列就只有最后一个数自身,长1 dp[i] = Math.max(1, dp[i]); //至此,已经求出了包含最后一个数的最长子序列的长度,和不包含最后一个数的最长子序列长度比较,取最大值为当前的最大长度 dp[i] = Math.max(dp[i], dp[i-1]); } return dp[len-1]; } /** * 4.经典01背包问题 * 01背包问题:一个承重(或体积)为W的背包,可选物品有n个,第i个物品分别重w[i]和价值v[i], * 每个物品只能拿或不拿,求背包可放物品的最大价值。 */ /** * * 策略:这里的关键制约因素是背包只能承重w,而且每放入一个物品其承重就会减少。 * 因此定义maxValue=V[i][j],数组表示目前可选物品有i个:0、1...i-1,背包承重(剩余的存放重量)为j的最大价值。 * 现在假设已经知道了(i-1)个物品且剩余承重为j的最大价值V[i-1][j],那么考虑准备放入第i个物品的情况: * (1)如果第i个物品的重量大于背包的剩余承重w_i>j,显然放不下了,所以此时V[i][j]=V[i-1][j]; * (2)w_i<=j,显然可以放下第i个物品,物品可以放得下,但是一定要装进来吗?如果装进的物品价值较低且较重,无疑会影响后续物品的装入情况。 * 所以还要考虑要不要放进来的子问题,V[i][j]=max{vi+V[i-1][j-wi], V[i-1][j]}。 * * @param W * @param n * @param w * @param v * @return */ public static int knapsack(int W, int n, int[] w, int[] v){ if ( W < 1 || n < 1 || w == null || v == null) { return -1; } int[][] dp = new int[n+1][W+1]; //可选的物品最多可以有n个,所以行数设为n+1。最大承重是W,所以列设为W+1。 int index = 0; for (int i = 1; i <= n; i++) { //物品数肯定是从1开始。dp[0][j]系统初始化为0. index = i-1; for (int j = 1; j <= W ; j++) {//能装进的重量肯定是从1开始。dp[i][0]系统初始化为0. if (w[index] > j){ dp[i][j] = dp[i-1][j]; }else { dp[i][j] = Math.max(dp[i - 1][j - w[index]] + v[index], dp[i - 1][j]); } } } //找出是哪些物品放入背包 boolean[] isTaken = new boolean[n];//标记是否放入背包里 for (int i = n; i > 0 ; i--) { if (dp[i][W] != dp[i-1][W]){ isTaken[i-1] = true;//装入 W -= w[i-1];//装入之后背包的承重减少 System.out.println(i-1); } } return dp[n][W];//返回n个物品承重为W时的最大价值 }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode9-10.html"},{"title":"算法成长之路leetcode7-8","text":"7. Reverse IntegerGiven a 32-bit signed integer, reverse digits of an integer. Example1234567891011121314Example 1:Input: 123Output: 321Example 2:Input: -123Output: -321Example 3:Input: 120Output: 21 Note:Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows. JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990package algorithm;public class Leetcode7 { /** * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 * * 示例 1: * * 输入: 123 * 输出: 321 *  示例 2: * * 输入: -123 * 输出: -321 * 示例 3: * * 输入: 120 * 输出: 21 * 注意: * * 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31,  2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。 * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/reverse-integer * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */ public int reverse(int x) { if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) { return 0; } boolean isNe = x < 0 ? true : false; x = Math.abs(x); // 取绝对值时越界了,直接返回0 if (isNe && x < 0) { return 0; } StringBuilder sb = new StringBuilder(); long m = 10; long base = 1; while (true) { base = m * base; long re = x % base; if (base == 10) { sb.append(re); } else { sb.append((re * m) / base); } if (x < base) { break; } } Long res; if (isNe) { res = 0 - Long.parseLong(sb.toString()); } else { res = Long.parseLong(sb.toString()); } if (res > Integer.MAX_VALUE || res < Integer.MIN_VALUE) { return 0; } else { return res.intValue(); } } public int reverse1(int x) { int rev = 0; while (x != 0) { int pop = x % 10; x /= 10; // Integer.MAX_VALUE = 2147483647,因为后面 rev = rev * 10 + pop,所以rev >Integer.MAX_VALUE 溢出 // rev == Integer.MAX_VALUE / 10 时,Integer.MAX_VALUE / 10 = 2147483640,so,pop > 7时溢出 if (rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0; // Integer.MIN_VALUE = -2147483648 // 同理如上 if (rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0; rev = rev * 10 + pop; } return rev; } public static void main(String[] args) { System.out.println(Integer.MAX_VALUE);// System.out.println(reverse1(123)); }} 8. String to Integer (atoi)Implement atoi which converts a string to an integer. The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value. The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function. If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed. If no valid conversion could be performed, a zero value is returned. Note: Only the space character ‘ ‘ is considered as whitespace character.Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. If the numerical value is out of the range of representable values, INT_MAX (2^31 − 1) or INT_MIN (−2^31) is returned. Example12345678910111213141516171819202122232425262728Example 1:Input: \"42\"Output: 42Example 2:Input: \" -42\"Output: -42Explanation: The first non-whitespace character is '-', which is the minus sign. Then take as many numerical digits as possible, which gets 42.Example 3:Input: \"4193 with words\"Output: 4193Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.Example 4:Input: \"words and 987\"Output: 0Explanation: The first non-whitespace character is 'w', which is not a numerical digit or a +/- sign. Therefore no valid conversion could be performed.Example 5:Input: \"-91283472332\"Output: -2147483648Explanation: The number \"-91283472332\" is out of the range of a 32-bit signed integer. Thefore INT_MIN (−2^31) is returned. JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146package algorithm;public class Leetcode8 { /** * *请你来实现一个 atoi 函数,使其能将字符串转换成整数。 * * 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。 * * 当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。 * * 该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。 * * 注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。 * * 在任何情况下,若函数不能进行有效的转换时,请返回 0。 * * 说明: * * 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31,  2^31 − 1]。如果数值超过这个范围,请返回  INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。 * * 示例 1: * * 输入: \"42\" * 输出: 42 * 示例 2: * * 输入: \" -42\" * 输出: -42 * 解释: 第一个非空白字符为 '-', 它是一个负号。 *   我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。 * 示例 3: * * 输入: \"4193 with words\" * 输出: 4193 * 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。 * 示例 4: * * 输入: \"words and 987\" * 输出: 0 * 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 * 因此无法执行有效的转换。 * 示例 5: * * 输入: \"-91283472332\" * 输出: -2147483648 * 解释: 数字 \"-91283472332\" 超过 32 位有符号整数范围。 *   因此返回 INT_MIN (−2^31) 。 * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/string-to-integer-atoi * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */ public static int myAtoi(String str) { StringBuilder st = new StringBuilder(); for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c == '-') { if (st.length() > 0) { break; } st.append(c); } else if (c == '+') { if (st.length() > 0) { break; } st.append(c); } else if (c == ' ') { if (st.length() > 0) { break; } else { continue; } } else if (c >= 48 && c <= 57) { st.append(c); } else { break; } if (st.length() > 1) { if (Long.parseLong(st.toString()) > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } if (Long.parseLong(st.toString()) < Integer.MIN_VALUE) { return Integer.MIN_VALUE; } } } if (st.length() == 0) { return 0; } if (st.toString().equals(\"-\") || st.toString().equals(\"+\")) { return 0; } return Long.valueOf(st.toString()).intValue(); } public int myAtoi1(String str) { if (str.isEmpty()) return 0; char[] mychar = str.toCharArray(); long ans = 0; int index = 0, flag = 1, n = str.length(); //排除字符串开头的空格元素 while (index < n && mychar[index] == ' ') { index++; } //排除空格后判断首字符是+还是-还是都不是 if (index < n && mychar[index] == '+') { index++; } else if (index < n && mychar[index] == '-') { index++; flag = -1; } //重点:只管是数字的时候,其余取0 while (index < n && (mychar[index] >= '0' && mychar[index] <= '9')) { if (ans != (int) ans) {//超出int范围 return (flag == 1) ? Integer.MAX_VALUE : Integer.MIN_VALUE;//提前结束 } // 巧妙的加起来值来 如 111 ,第一个1时 ans = 0 * 10 +1,第二个1时 ans = 1*10 + 1 = 11,第三个1时, ans = 11*10 + 1 = 111; ans = ans * 10 + mychar[index++] - '0'; } // 强转long是否等于int 判断是否超界,机智 if (ans != (int) ans) { return (flag == 1) ? Integer.MAX_VALUE : Integer.MIN_VALUE; } return (int) (ans * flag); } public static void main(String[] args) { /** * \"42\" * \"----01\" * \"0-1\" * \"-5-\" */ System.out.println(myAtoi(\"0-1\")); }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode7-8.html"},{"title":"mysql-b+Tree索引","text":"索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据。索引最形象的比喻就是图书的目录了。注意这里的大量,数据量大了索引才显得有意义,如果我想要在 [1,2,3,4] 中找到 4 这个数据,直接对全数据检索也很快,没有必要费力气建索引再去查找。 索引在 MySQL 数据库中分三类: B+ 树索引 Hash 索引 全文索引 我们今天要介绍的是工作开发中最常接触到的 InnoDB 存储引擎中的 B+ 树索引。要介绍 B+ 树索引,就不得不提二叉查找树,平衡二叉树和 B 树这三种数据结构。B+ 树就是从他们仨演化来的。 二叉查找树首先,让我们先看一张图: 从图中可以看到,我们为 user 表(用户信息表)建立了一个二叉查找树的索引。 图中的圆为二叉查找树的节点,节点中存储了键(key)和数据(data)。键对应 user 表中的 id,数据对应 user 表中的行数据。 二叉查找树的特点就是任何节点的左子节点的键值都小于当前节点的键值,右子节点的键值都大于当前节点的键值。顶端的节点我们称为根节点,没有子节点的节点我们称之为叶节点。 如果我们需要查找 id=12 的用户信息,利用我们创建的二叉查找树索引,查找流程如下: 将根节点作为当前节点,把 12 与当前节点的键值 10 比较,12 大于 10,接下来我们把当前节点>的右子节点作为当前节点。 继续把 12 和当前节点的键值 13 比较,发现 12 小于 13,把当前节点的左子节点作为当前节点。 把 12 和当前节点的键值 12 对比,12 等于 12,满足条件,我们从当前节点中取出 data,即 id=12,name=xm。 利用二叉查找树我们只需要 3 次即可找到匹配的数据。如果在表中一条条的查找的话,我们需要 6 次才能找到。 平衡二叉树上面我们讲解了利用二叉查找树可以快速的找到数据。但是,如果上面的二叉查找树是这样的构造: 这个时候可以看到我们的二叉查找树变成了一个链表。如果我们需要查找 id=17 的用户信息,我们需要查找 7 次,也就相当于全表扫描了。 导致这个现象的原因其实是二叉查找树变得不平衡了,也就是高度太高了,从而导致查找效率的不稳定。 为了解决这个问题,我们需要保证二叉查找树一直保持平衡,就需要用到平衡二叉树了。 平衡二叉树又称 AVL 树,在满足二叉查找树特性的基础上,要求每个节点的左右子树的高度差不能超过 1。 下面是平衡二叉树和非平衡二叉树的对比: 由平衡二叉树的构造我们可以发现第一张图中的二叉树其实就是一棵平衡二叉树。 平衡二叉树保证了树的构造是平衡的,当我们插入或删除数据导致不满足平衡二叉树不平衡时,平衡二叉树会进行调整树上的节点来保持平衡。具体的调整方式这里就不介绍了。 平衡二叉树相比于二叉查找树来说,查找效率更稳定,总体的查找速度也更快。 B 树因为内存的易失性。一般情况下,我们都会选择将 user 表中的数据和索引存储在磁盘这种外围设备中。 但是和内存相比,从磁盘中读取数据的速度会慢上百倍千倍甚至万倍,所以,我们应当尽量减少从磁盘中读取数据的次数。 另外,从磁盘中读取数据时,都是按照磁盘块来读取的,并不是一条一条的读。 如果我们能把尽量多的数据放进磁盘块中,那一次磁盘读取操作就会读取更多数据,那我们查找数据的时间也会大幅度降低。 如果我们用树这种数据结构作为索引的数据结构,那我们每查找一次数据就需要从磁盘中读取一个节点,也就是我们说的一个磁盘块。 我们都知道平衡二叉树可是每个节点只存储一个键值和数据的。那说明什么?说明每个磁盘块仅仅存储一个键值和数据!那如果我们要存储海量的数据呢? 可以想象到二叉树的节点将会非常多,高度也会极其高,我们查找数据时也会进行很多次磁盘 IO,我们查找数据的效率将会极低! 为了解决平衡二叉树的这个弊端,我们应该寻找一种单个节点可以存储多个键值和数据的平衡树。也就是我们接下来要说的 B 树。 B 树(Balance Tree)即为平衡树的意思,下图即是一棵 B 树: 图中的 p 节点为指向子节点的指针,二叉查找树和平衡二叉树其实也有,因为图的美观性,被省略了。 图中的每个节点称为页,页就是我们上面说的磁盘块,在 MySQL 中数据读取的基本单位都是页,所以我们这里叫做页更符合 MySQL 中索引的底层数据结构。 从上图可以看出,B 树相对于平衡二叉树,每个节点存储了更多的键值(key)和数据(data),并且每个节点拥有更多的子节点,子节点的个数一般称为阶,上述图中的 B 树为 3 阶 B 树,高度也会很低。 基于这个特性,B 树查找数据读取磁盘的次数将会很少,数据的查找效率也会比平衡二叉树高很多。 假如我们要查找 id=28 的用户信息,那么我们在上图 B 树中查找的流程如下: 先找到根节点也就是页 1,判断 28 在键值 17 和 35 之间,那么我们根据页 1 中的指针 p2 找到页 3。 将 28 和页 3 中的键值相比较,28 在 26 和 30 之间,我们根据页 3 中的指针 p2 找到页 8。 将 28 和页 8 中的键值相比较,发现有匹配的键值 28,键值 28 对应的用户信息为(28,bv)。 B+ 树B+ 树是对 B 树的进一步优化。让我们先来看下 B+ 树的结构图: 根据上图我们来看下 B+ 树和 B 树有什么不同: ①B+ 树非叶子节点上是不存储数据的,仅存储键值,而 B 树节点中不仅存储键值,也会存储数据。 之所以这么做是因为在数据库中页的大小是固定的,InnoDB 中页的默认大小是 16KB。 如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的 IO 次数又会再次减少,数据查询的效率也会更快。 另外,B+ 树的阶数是等于键值的数量的,如果我们的 B+ 树一个节点可以存储 1000 个键值,那么 3 层 B+ 树可以存储 1000×1000×1000=10 亿个数据。 一般根节点是常驻内存的,所以一般我们查找 10 亿数据,只需要 2 次磁盘 IO。 ②因为 B+ 树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。 那么 B+ 树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而 B 树因为数据分散在各个节点,要实现这一点是很不容易的。 有心的读者可能还发现上图 B+ 树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。 其实上面的 B 树我们也可以对各个节点加上链表。这些不是它们之前的区别,是因为在 MySQL 的 InnoDB 存储引擎中,索引就是这样存储的。 也就是说上图中的 B+ 树索引就是 InnoDB 中 B+ 树索引真正的实现方式,准确的说应该是聚集索引(聚集索引和非聚集索引下面会讲到)。 通过上图可以看到,在 InnoDB 中,我们通过数据页之间通过双向链表连接以及叶子节点中数据之间通过单向链表连接的方式可以找到表中所有的数据。 MyISAM 中的 B+ 树索引实现与 InnoDB 中的略有不同。在 MyISAM 中,B+ 树索引的叶子节点并不存储数据,而是存储数据的文件地址。 聚集索引 VS 非聚集索引在上节介绍 B+ 树索引的时候,我们提到了图中的索引其实是聚集索引的实现方式。 那什么是聚集索引呢?在 MySQL 中,B+ 树索引按照存储方式的不同分为聚集索引和非聚集索引。 这里我们着重介绍 InnoDB 中的聚集索引和非聚集索引: ①聚集索引(聚簇索引):以 InnoDB 作为存储引擎的表,表中的数据都会有一个主键,即使你不创建主键,系统也会帮你创建一个隐式的主键。 这是因为 InnoDB 是把数据存放在 B+ 树中的,而 B+ 树的键值就是主键,在 B+ 树的叶子节点中,存储了表中所有的数据。 这种以主键作为 B+ 树索引的键值而构建的 B+ 树索引,我们称之为聚集索引。 ②非聚集索引(非聚簇索引):以主键以外的列值作为键值构建的 B+ 树索引,我们称之为非聚集索引。 非聚集索引与聚集索引的区别在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。 明白了聚集索引和非聚集索引的定义,我们应该明白这样一句话:数据即索引,索引即数据。 1234567891011121314151617Innodb的存储索引是基于B+tree,理所当然,聚集索引也是基于B+tree。与非聚集索引的区别则是,聚集索引既存储了索引,也存储了行值。当一个表有一个聚集索引,它的数据是存储在索引的叶子页(leaf pages)。因此innodb也能理解为基于索引的表。Innodb如何选择一个聚集索引,对于Innodb,主键毫无疑问是一个聚集索引。但是当一个表没有主键,或者没有一个索引,Innodb会如何处理呢。请看如下规则1. 如果一个主键被定义了,那么这个主键就是作为聚集索引2. 如果没有主键被定义,那么该表的第一个唯一非空索引被作为聚集索引3. 如果没有主键也没有合适的唯一索引,那么innodb内部会生成一个隐藏的主键作为聚集索引,这个隐藏的主键是一个6个字节的列,改列的值会随着数据的插入自增。还有一个需要注意的是:次级索引的叶子节点并不存储行数据的物理地址。而是存储的该行的主键值。所以:一次级索引包含了两次查找。一次是查找次级索引自身。然后查找主键(聚集索引)现在应该明白了吧,建立自增主键的原因是:Innodb中的每张表都会有一个聚集索引,而聚集索引又是以物理磁盘顺序来存储的,自增主键会把数据自动向后插入,避免了插入过程中的聚集索引排序问题。聚集索引的排序,必然会带来大范围的数据的物理移动,这里面带来的磁盘IO性能损耗是非常大的。 而如果聚集索引上的值可以改动的话,那么也会触发物理磁盘上的移动,于是就可能出现page分裂,表碎片横生。 利用聚集索引和非聚集索引查找数据前面我们讲解 B+ 树索引的时候并没有去说怎么在 B+ 树中进行数据的查找,主要就是因为还没有引出聚集索引和非聚集索引的概念。 下面我们通过讲解如何通过聚集索引以及非聚集索引查找数据表中数据的方式介绍一下 B+ 树索引查找数据方法。 利用聚集索引查找数据 还是这张 B+ 树索引图,现在我们应该知道这就是聚集索引,表中的数据存储在其中。 现在假设我们要查找 id>=18 并且 id<40 的用户数据。对应的 sql 语句为: MySQL 1select * from user where id>=18 and id <40 其中 id 为主键,具体的查找过程如下: ①一般根节点都是常驻内存的,也就是说页 1 已经在内存中了,此时不需要到磁盘中读取数据,直接从内存中读取即可。 从内存中读取到页 1,要查找这个 id>=18 and id <40 或者范围值,我们首先需要找到 id=18 的键值。 从页 1 中我们可以找到键值 18,此时我们需要根据指针 p2,定位到页 3。 ②要从页 3 中查找数据,我们就需要拿着 p2 指针去磁盘中进行读取页 3。 从磁盘中读取页 3 后将页 3 放入内存中,然后进行查找,我们可以找到键值 18,然后再拿到页 3 中的指针 p1,定位到页 8。 ③同样的页 8 页不在内存中,我们需要再去磁盘中将页 8 读取到内存中。 将页 8 读取到内存中后。因为页中的数据是链表进行连接的,而且键值是按照顺序存放的,此时可以根据二分查找法定位到键值 18。 此时因为已经到数据页了,此时我们已经找到一条满足条件的数据了,就是键值 18 对应的数据。 因为是范围查找,而且此时所有的数据又都存在叶子节点,并且是有序排列的,那么我们就可以对页 8 中的键值依次进行遍历查找并匹配满足条件的数据。 我们可以一直找到键值为 22 的数据,然后页 8 中就没有数据了,此时我们需要拿着页 8 中的 p 指针去读取页 9 中的数据。 ④因为页 9 不在内存中,就又会加载页 9 到内存中,并通过和页 8 中一样的方式进行数据的查找,直到将页 12 加载到内存中,发现 41 大于 40,此时不满足条件。那么查找到此终止。 最终我们找到满足条件的所有数据,总共 12 条记录: (18,kl), (19,kl), (22,hj), (24,io), (25,vg) , (29,jk), (31,jk) , (33,rt) , (34,ty) , (35,yu) , (37,rt) , (39,rt) 。 下面看下具体的查找流程图 利用非聚集索引查找数据 读者看到这张图的时候可能会蒙,这是啥东西啊?怎么都是数字。如果有这种感觉,请仔细看下图中红字的解释。 什么?还看不懂?那我再来解释下吧。首先,这个非聚集索引表示的是用户幸运数字的索引(为什么是幸运数字?一时兴起想起来的:-)),此时表结构是这样的。 在叶子节点中,不再存储所有的数据了,存储的是键值和主键。对于叶子节点中的 x-y,比如 1-1。左边的 1 表示的是索引的键值,右边的 1 表示的是主键值。 如果我们要找到幸运数字为 33 的用户信息,对应的 sql 语句为: 1select * from user where luckNum=33 查找的流程跟聚集索引一样,这里就不详细介绍了。我们最终会找到主键值 47,找到主键后我们需要再到聚集索引中查找具体对应的数据信息,此时又回到了聚集索引的查找流程。 下面看下具体的查找流程图: 总结本篇文章从二叉查找树,详细说明了为什么 MySQL 用 B+ 树作为数据的索引,以及在 InnoDB 中数据库如何通过 B+ 树索引来存储数据以及查找数据。 我们一定要记住这句话:数据即索引,索引即数据。 参考文章:参考链接","link":"/database/mysql/mysql-b-Tree%E7%B4%A2%E5%BC%95.html"},{"title":"算法成长之路leetcode5-6","text":"5. Longest Palindromic SubstringGiven a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. Example12345678Example 1:Input: \"babad\"Output: \"bab\"Note: \"aba\" is also a valid answer.Example 2:Input: \"cbbd\"Output: \"bb\" JAVA题解123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384package algorithm;public class Leetcode5 { public static void main(String[] args) { System.out.println(longestPalindrome(\"abbaabb\")); } /** * 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 * * 示例 1: * * 输入: \"babad\" * 输出: \"bab\" * 注意: \"aba\" 也是一个有效答案。 * 示例 2: * * 输入: \"cbbd\" * 输出: \"bb\" * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/longest-palindromic-substring * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */ /** * 终于看懂了这个中心向两边扩张算法是什么意思了。 * 先来解释一下为什么中心是2n-1而不是n 比如有字符串abcba,这时回文子串是abcda, * 中心是c;又有字符串adccda,这时回文子串是adccda,中心是cc。 由此可见中心点既有可能是一个字符, * 也有可能是两个字符,当中心为一个字符的时候有n个中心, * 当中心为两个字符的时候有n-1个中心,所以一共有2n-1个中心。 * 然后for循环开始从左到右遍历,为什么会有两次expandAroundCenter,一次是i和i本身,一次是i和i+1, * 这就是上面说到的一个中心与两个中心。 而后会去判断这两种情况下谁的回文子串最长,并标记出这个子串在原字符串中的定位,即start和end。 * * @param s * @return */ public static String longestPalindrome(String s) { if (s == null || s.length() < 1) return \"\"; int start = 0, end = 0; for (int i = 0; i < s.length(); i++) { // 一个数向两边扩张 int len1 = expandAroundCenter(s, i, i); // 两个数向两边扩张 int len2 = expandAroundCenter(s, i, i + 1); // 取最长的回文 int len = Math.max(len1, len2); // 判读此时长度和原来的最长度 if (len > end - start) { // 求最长回文开始位置 start = i - (len - 1) / 2; // 求最长回文结束位置 end = i + len / 2; } } // 截取最长回文 return s.substring(start, end + 1); } /** * 向两边向两边扩张求长度 * * @param s * @param left * @param right * @return */ private static int expandAroundCenter(String s, int left, int right) { // 定位中心位置 int L = left, R = right; // 判读中间位置是否相等,以及两边扩张是否相等 while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) { // 向左扩张一位 L--; // 向右扩张一位 R++; } // 回文的长度 如 aba 时,当 b = 1时,一个中心点进来,L = 1,R = 1,此时满足循环,L=0,R=2,此时也满足 // 循环,L = -1,R=3,此时循环结束,长度为3 = 3 -(-1) -1 return R - L - 1; }} 6. ZigZag ConversionThe string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) P A H NA P L S I I GY I RAnd then read line by line: “PAHNAPLSIIGYIR” Write the code that will take a string and make this conversion given a number of rows: string convert(string s, int numRows); Example12345678910111213Example 1:Input: s = \"PAYPALISHIRING\", numRows = 3Output: \"PAHNAPLSIIGYIR\"Example 2:Input: s = \"PAYPALISHIRING\", numRows = 4Output: \"PINALSIGYAHRPI\"Explanation:P I NA L S I GY A H RP I JAVA题解1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071package algorithm;import java.util.ArrayList;import java.util.List;public class Leetcode6 { /** * 将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。 * <p> * 比如输入字符串为 \"LEETCODEISHIRING\" 行数为 3 时,排列如下: * <p> * L C I R * E T O E S I I G * E D H N * 之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:\"LCIRETOESIIGEDHN\"。 * <p> * 请你实现这个将字符串进行指定行数变换的函数: * <p> * string convert(string s, int numRows); * 示例 1: * <p> * 输入: s = \"LEETCODEISHIRING\", numRows = 3 * 输出: \"LCIRETOESIIGEDHN\" * 示例 2: * <p> * 输入: s = \"LEETCODEISHIRING\", numRows = 4 * 输出: \"LDREOEIIECIHNTSG\" * 解释: * <p> * L D R * E O E I I * E C I H N * T S G * <p> * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/zigzag-conversion * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */ public String convert(String s, int numRows) { if (numRows == 1) return s; List<StringBuilder> rows = new ArrayList<>(); for (int i = 0; i < Math.min(numRows, s.length()); i++) // 确定有多少行,每一行放一个待填充的字符串 rows.add(new StringBuilder()); // 当前行 int curRow = 0; // 上移或下移 false上移 boolean goingDown = false; for (char c : s.toCharArray()) { // 挨着放字符到对应的行 rows.get(curRow).append(c); // 判断是否下移,当第一行和最后一行的时候转向 if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown; // 下移行数+1,上移行数-1 curRow += goingDown ? 1 : -1; } // 存最终结果 StringBuilder ret = new StringBuilder(); // 遍历每行,进行连接 for (StringBuilder row : rows) ret.append(row); return ret.toString(); } public static void main(String[] args) { Leetcode6 l = new Leetcode6(); System.out.println(l.convert(\"weweqw\", 3)); }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode5-6.html"},{"title":"二分查找法模板的基本思想-leetcode35","text":"leetcode35给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 你可以假设数组中无重复元素。 示例 1: 123456789101112131415输入: [1,3,5,6], 5输出: 2示例 2:输入: [1,3,5,6], 2输出: 1示例 3:输入: [1,3,5,6], 7输出: 4示例 4:输入: [1,3,5,6], 0输出: 0 传统解法: 1234567891011121314151617181920212223242526272829303132333435363738394041public class Solution3 { public int searchInsert(int[] nums, int target) { int len = nums.length; if (nums[len - 1] < target) { return len; } int left = 0; int right = len - 1; while (left <= right) { int mid = (left + right) / 2; // 等于的情况最简单,我们应该放在第 1 个分支进行判断 if (nums[mid] == target) { return mid; } else if (nums[mid] < target) { // 题目要我们返回大于或者等于目标值的第 1 个数的索引 // 此时 mid 一定不是所求的左边界, // 此时左边界更新为 mid + 1 left = mid + 1; } else { // 既然不会等于,此时 nums[mid] > target // mid 也一定不是所求的右边界 // 此时右边界更新为 mid - 1 right = mid - 1; } } // 注意:一定得返回左边界 left, // 如果返回右边界 right 提交代码不会通过 // 【注意】下面我尝试说明一下理由,如果你不太理解下面我说的,那是我表达的问题 // 但我建议你不要纠结这个问题,因为我将要介绍的二分查找法模板,可以避免对返回 left 和 right 的讨论 // 理由是对于 [1,3,5,6],target = 2,返回大于等于 target 的第 1 个数的索引,此时应该返回 1 // 在上面的 while (left <= right) 退出循环以后,right < left,right = 0 ,left = 1 // 根据题意应该返回 left, // 如果题目要求你返回小于等于 target 的所有数里最大的那个索引值,应该返回 right return left; }} 说明 a、当把二分查找法的循环可以进行的条件写成 while (left <= right) 时,在写最后一句 return 的时候,如果不假思索,把左边界 left 返回回去,虽然写对了,但可以思考一下为什么不返回右边界 right 呢? b、但是事实上,返回 left 是有一定道理的,如果题目换一种问法,你可能就要返回右边界 right,这句话不太理解没有关系,我也不打算讲得很清楚(在上面代码的注释中我已经解释了原因),因为实在太绕了,这不是我要说的重点。 二分查找法模板的基本思想1、首先把循环可以进行的条件写成 while(left < right),在退出循环的时候,一定有 left == right 成立,此时返回 left 或者 right 都可以或许你会问:退出循环的时候还有一个数没有看啊(退出循环之前索引 left 或 索引 right 上的值)?没有关系,我们就等到退出循环以后来看,甚至经过分析,有时都不用看,就能确定它是目标数值。 (什么时候需要看最后剩下的那个数,什么时候不需要,会在后面介绍。) 更深层次的思想是“夹逼法”或者称为“排除法”。 2、“神奇的”二分查找法模板的基本思想(特别重要)“排除法”即:在每一轮循环中排除一半以上的元素,于是在对数级别的时间复杂度内,就可以把区间“夹逼” 只剩下 1 个数,而这个数是不是我们要找的数,单独做一次判断就可以了。 “夹逼法”或者“排除法”是二分查找算法的基本思想,“二分”是手段,在目标元素不确定的情况下,“二分” 也是“最大熵原理”告诉我们的选择。 还是 LeetCode 第 35 题,下面给出使用 while (left < right) 模板写法的 2 段参考代码,以下代码的细节部分在后文中会讲到,因此一些地方不太明白没有关系,暂时跳过即可。 参考代码 1:重点理解为什么候选区间的索引范围是 [0, size]。 12345678910111213141516171819202122232425262728from typing import Listclass Solution: def searchInsert(self, nums: List[int], target: int) -> int: # 返回大于等于 target 的索引,有可能是最后一个 size = len(nums) # 特判 if size == 0: return 0 left = 0 # 如果 target 比 nums里所有的数都大,则最后一个数的索引 + 1 就是候选值,因此,右边界应该是数组的长度 right = size # 二分的逻辑一定要写对,否则会出现死循环或者数组下标越界 while left < right: mid = left + (right - left) // 2 if nums[mid] < target: left = mid + 1 else: assert nums[mid] >= target # [1,5,7] 2 right = mid # 调试语句 # print('left = {}, right = {}, mid = {}'.format(left, right, mid)) return left 参考代码 2:对于是否接在原有序数组后面单独判断,不满足的时候,再在候选区间的索引范围 [0, size - 1] 内使用二分查找法进行搜索。 1234567891011121314151617181920212223242526from typing import Listclass Solution: def searchInsert(self, nums: List[int], target: int) -> int: # 返回大于等于 target 的索引,有可能是最后一个 size = len(nums) # 特判 1 if size == 0: return 0 # 特判 2:如果比最后一个数字还要大,直接接在它后面就可以了 if target > nums[-1]: return size left = 0 right = size - 1 # 二分的逻辑一定要写对,否则会出现死循环或者数组下标越界 while left < right: mid = left + (right - left) // 2 if nums[mid] < target: left = mid + 1 else: assert nums[mid] >= target right = mid return left 细节、注意事项、调试方法1、前提:思考左、右边界,如果左、右边界不包括目标数值,会导致错误结果例:LeetCode 第 69 题:x 的平方根 实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 分析:一个非负整数的平方根最小可能是 0 ,最大可能是它自己。因此左边界可以取 0 ,右边界可以取 x。可以分析得再细一点,但这道题没有必要,因为二分查找法会帮你排除掉不符合的区间元素。 例:LeetCode 第 287 题:寻找重复数 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 分析:题目告诉我们“其数字都在 1 到 n 之间(包括 1 和 n)”。因此左边界可以取 1 ,右边界可以取 n。 要注意 2 点: 如果 left 和 right 表示的是数组的索引,就要考虑“索引是否有效” ,即“索引是否越界” 是重要的定界依据; 左右边界一定要包括目标元素,例如 LeetCode 第 35 题:“搜索插入位置” ,当 target 比数组中的最后一个数字还要大(不能等于)的时候,插入元素的位置就是数组的最后一个位置 + 1,即 (len - 1 + 1 =) len,如果忽略掉这一点,把右边界定为 len - 1 ,代码就不能通过在线测评。 2、中位数先写 int mid = (left + right) >>> 1 ; 根据循环里分支的编写情况,再做调整理解这一点,首先要知道:当数组的元素个数是偶数的时候,中位数有左中位数和右中位数之分。 当数组的元素个数是偶数的时候:使用 int mid = left + (right - left) / 2 ; 得到左中位数的索引; 使用 int mid = left + (right - left + 1) / 2 ; 得到右中位数的索引。 当数组的元素个数是奇数的时候,以上二者都能选到最中间的那个中位数。其次, int mid = left + (right - left) / 2 ; 等价于 int mid = (left + right) >>> 1; int mid = left + (right - left + 1) / 2 ; 等价于 int mid = (left + right + 1) >>> 1 。 我们使用一个具体的例子来验证:当左边界索引 left = 3,右边界索引 right = 4 的时候, mid1 = left + (right - left) // 2 = 3 + (4 - 3) // 2 = 3 + 0 = 3, mid2 = left + (right - left + 1) // 2 = 3 + (4 - 3 + 1) // 2 = 3 + 1 = 4。 左中位数 mid1 是索引 left,右中位数 mid2 是索引 right。 记忆方法: (right - left) 不加 11 选左中位数,加 11 选右中位数。 那么,什么时候使用左中位数,什么时候使用右中位数呢?选中位数的依据是为了避免死循环,得根据分支的逻辑来选择中位数,而分支逻辑的编写也有技巧,下面具体说。 3、先写逻辑上容易想到的分支逻辑,这个分支逻辑通常是排除中位数的逻辑;在逻辑上,“可能是也有可能不是”让我们感到犹豫不定,但**“一定不是”是我们非常坚决的,通常考虑的因素特别单一,因此“好想” **。在生活中,我们经常听到这样的话:找对象时,“有车、有房,可以考虑,但没有一定不要”;找工作时,“事儿少、离家近可以考虑,但是钱少一定不去”,就是这种思想的体现。 例:LeetCode 第 69 题:x 的平方根 实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 分析:因为题目中说“返回类型是整数,结果只保留整数的部分,小数部分将被舍去”。例如 55 的平方根约等于 2.2362.236,在这道题应该返回 22。因此如果一个数的平方小于或者等于 x,那么这个数有可能是也有可能不是 x 的平方根,但是能很肯定的是,如果一个数的平方大于 x ,这个数肯定不是 x 的平方根。 注意:先写“好想”的分支,排除了中位数之后,通常另一个分支就不排除中位数,而不必具体考虑另一个分支的逻辑的具体意义,且代码几乎是固定的。 4、循环内只写两个分支,一个分支排除中位数,另一个分支不排除中位数,循环中不单独对中位数作判断既然是“夹逼”法,没有必要在每一轮循环开始前单独判断当前中位数是否是目标元素,因此分支数少了一支,代码执行效率更高。 以下是“排除中位数的逻辑”思考清楚以后,可能出现的两个模板代码。 可以排除“中位数”的逻辑,通常比较好想,但并不绝对,这一点视情况而定。 分支条数变成 2 条,比原来 3 个分支要考虑的情况少,好处是: 不用在每次循环开始单独考虑中位数是否是目标元素,节约了时间,我们只要在退出循环的时候,即左右区间压缩成一个数(索引)的时候,去判断这个索引表示的数是否是目标元素,而不必在二分的逻辑中单独做判断。 这一点很重要,希望读者结合具体练习仔细体会,每次循环开始的时候都单独做一次判断,在统计意义上看,二分时候的中位数恰好是目标元素的概率并不高,并且即使要这么做,也不是普适性的,不能解决绝大部分的问题。 还以 LeetCode 第 35 题为例,通过之前的分析,我们需要找到“大于或者等于目标值的第 1 个数的索引”。对于这道题而言: 如果中位数小于目标值,它就应该被排除,左边界 left 就至少是 mid + 1; 如果中位数大于等于目标值,还不能够肯定它就是我们要找的数,因为要找的是等于目标值的第 11 个数的索引,中位数以及中位数的左边都有可能是符合题意的数,因此右边界就不能把 mid 排除,因此右边界 right 至多是 mid,此时右边界不向左边收缩。 下一点就更关键了。 5、根据分支逻辑选择中位数的类型,可能是左中位数,也可能是右位数,选择的标准是避免死循环 死循环容易发生在区间只有 22 个元素时候,此时中位数的选择尤为关键。选择中位数的依据是:避免出现死循环。我们需要确保: (下面的这两条规则说起来很绕,可以暂时跳过)。 如果分支的逻辑,在选择左边界的时候,不能排除中位数,那么中位数就选“右中位数”,只有这样区间才会收缩,否则进入死循环; 同理,如果分支的逻辑,在选择右边界的时候,不能排除中位数,那么中位数就选“左中位数”,只有这样区间才会收缩,否则进入死循环。 理解上面的这个规则可以通过具体的例子。针对以上规则的第 1 点:如果分支的逻辑,在选择左边界的时候不能排除中位数,例如: 1234567891011while left < right: # 不妨先写左中位数,看看你的分支会不会让你代码出现死循环,从而调整 mid = left + (right - left) // 2 # 业务逻辑代码 if (check(mid)): # 选择右边界的时候,可以排除中位数 right = mid - 1 else: # 选择左边界的时候,不能排除中位数 left = mid 在区间中的元素只剩下 22 个时候,例如:left = 3,right = 4。此时左中位数就是左边界,如果你的逻辑执行到 left = mid 这个分支,且你选择的中位数是左中位数,此时左边界就不会得到更新,区间就不会再收缩(理解这句话是关键),从而进入死循环;为了避免出现死循环,你需要选择中位数是右中位数,当逻辑执行到 left = mid 这个分支的时候,因为你选择了右中位数,让逻辑可以转而执行到 right = mid - 1 让区间收缩,最终成为 1 个数,退出 while 循环。上面这段话不理解没有关系,因为我还没有举例子,你有个印象就好,类似地,理解选择中位数的依据的第 2 点。 6、退出循环的时候,可能需要对“夹逼”剩下的那个数单独做一次判断,这一步称之为“后处理”。二分查找法之所以高效,是因为它利用了数组有序的特点,在每一次的搜索过程中,都可以排除将近一半的数,使得搜索区间越来越小,直到区间成为一个数。回到这一节最开始的疑问:“区间左右边界相等(即收缩成 1 个数)时,这个数是否会漏掉”,解释如下: 如果你的业务逻辑保证了你要找的数一定在左边界和右边界所表示的区间里出现,那么可以放心地返回 left 或者 right,无需再做判断; 如果你的业务逻辑不能保证你要找的数一定在左边界和右边界所表示的区间里出现,那么只要在退出循环以后,再针对 nums[left] 或者 nums[right] (此时 nums[left] == nums[right])单独作一次判断,看它是不是你要找的数即可,这一步操作常常叫做“后处理”。 如果你能确定候选区间里目标元素一定存在,则不必做“后处理”。例:LeetCode 第 69 题:x 的平方根 实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 分析:非负实数 x 的平方根在 [0, x] 内一定存在,故退出 while (left < right) 循环以后,不必单独判断 left 或者 right 是否符合题意。 如果你不能确定候选区间里目标元素一定存在,需要单独做一次判断。例:LeetCode 第 704 题:二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 分析:因为目标数有可能不在数组中,当候选区间夹逼成一个数的时候,要单独判断一下这个数是不是目标数,如果不是,返回 -1。 7、取中位数的时候,要避免在计算上出现整型溢出;int mid = (left + right) / 2; 的问题:在 left 和 right 很大的时候,left + right 会发生整型溢出,变成负数,这是一个 bug ,得改! int mid = left + (right - left) / 2; 在 right 很大、 left 是负数且很小的时候, right - left 也有可能超过 int 类型能表示的最大值,只不过一般情况下 left 和 right 表示的是数组索引值,left 是非负数,因此 right - left 溢出的可能性很小。因此,它是正确的写法。下面介绍推荐的写法。 int mid = (left + right) >>> 1; 如果这样写, left + right 在发生整型溢出以后,会变成负数,此时如果除以 22 ,mid 是一个负数,但是经过无符号右移,可以得到在不溢出的情况下正确的结果。 解释“无符号右移”:在 Java 中,无符号右移运算符 >>> 和右移运算符 >> 的区别如下: 右移运算符 >> 在右移时,丢弃右边指定位数,左边补上符号位;无符号右移运算符 >>> 在右移时,丢弃右边指定位数,左边补上 00,也就是说,对于正数来说,二者一样,而负数通过 >>> 后能变成正数。下面解释上面的模板中,取中位数的时候使用先用“+”,然后“无符号右移”。 a、int mid = (left + right) / 2 与 int mid = left + (right - left) / 2 两种写法都有整型溢出的风险,没有哪一个是绝对安全的,注意:这里我们取平均值用的是除以 2,并且是整除: int mid = (left + right) / 2 在 left 和 right 都很大的时候会溢出;int mid = left + (right - left) / 2 在 right 很大,且 left 是负数且很小的时候会溢出;b、写算法题的话,一般是让你在数组中做二分查找,因此 left 和 right 一般都表示数组的索引,因此 left 在绝大多数情况下不会是负数并且很小,因此使用 int mid = left + (right - left) // 2 相对 int mid = (left + right) // 2 更安全一些,并且也能向别人展示我们注意到了整型溢出这种情况,但事实上,还有更好的方式; c、建议使用 int mid = (left + right) >>> 1 这种写法,其实是大有含义的: JDK8 中采用 int mid = (left + right) >>> 1 ,重点不在 + ,而在 >>> 。 我们看极端的情况,left 和 high 都是整型最大值的时候,注意,此时 3232 位整型最大值它的二进制表示的最高位是 00,它们相加以后,最高位是 11 ,变成负数,但是再经过无符号右移 >>>(重点是忽略了符号位,空位都以 00 补齐),就能保证使用 + 在整型溢出了以后结果还是正确的。 Java 中 Collections 和 Arrays 提供的 binarySearch 方法,我们点进去看 left 和 right 都表示索引,使用无符号右移又不怕整型溢出,那就用 int mid = (left + right) >>> 1 好啦。位运算本来就比使用除法快,这样看来使用 + 和 <<< 真的是又快又好了。 我想这一点可能是 JDK8 的编写者们更层次的考量。 看来以后写算法题,就用 int mid = (left + right) >>> 1 吧,反正更多的时候 left 和 right 表示索引。 8、编码一旦出现死循环,输出必要的变量值、分支逻辑是调试的重要方法。当出现死循环的时候的调试方法:打印输出左右边界、中位数的值和目标值、分支逻辑等必要的信息。 按照我的经验,一开始编码的时候,稍不注意就很容易出现死循环,不过没有关系,你可以你的代码中写上一些输出语句,就容易理解“在区间元素只有 2 个的时候容易出现死循环”。具体编码调试的细节,可以参考我在「力扣」第 69 题:x 的平方根的题解《二分查找 + 牛顿法(Python 代码、Java 代码)》 。 总结总结一下,我爱用这个模板的原因、技巧、优点和注意事项: 原因:无脑地写 while left < right: ,这样你就不用判断,在退出循环的时候你应该返回 left 还是 right,因为返回 left 或者 right 都对; 技巧:先写分支逻辑,并且先写排除中位数的逻辑分支(因为更多时候排除中位数的逻辑容易想,但是前面我也提到过,这并不绝对),另一个分支的逻辑你就不用想了,写出第 1 个分支的反面代码即可(下面的说明中有介绍),再根据分支的情况选择使用左中位数还是右中位数; 说明:这里再多说一句。如果从代码可读性角度来说,只要是你认为好想的逻辑分支,就把它写在前面,并且加上你的注释,这样方便别人理解,而另一个分支,你就不必考虑它的逻辑了。有的时候另一个分支的逻辑并不太好想,容易把自己绕进去。如果你练习做得多了,会形成条件反射。 我简单总结了一下,左右分支的规律就如下两点: 如果第 1 个分支的逻辑是“左边界排除中位数”(left = mid + 1),那么第 2 个分支的逻辑就一定是“右边界不排除中位数”(right = mid),反过来也成立; 如果第 2 个分支的逻辑是“右边界排除中位数”(right = mid - 1),那么第 2 个分支的逻辑就一定是“左边界不排除中位数”(left = mid),反之也成立。 “反过来也成立”的意思是:如果在你的逻辑中,“边界不能排除中位数”的逻辑好想,你就把它写在第 1 个分支,另一个分支是它的反面,你可以不用管逻辑是什么,按照上面的规律直接给出代码就可以了。能这么做的理论依据就是“排除法”。 在「力扣」第 287 题:寻找重复数的题解《二分法(Python 代码、Java 代码)》和这篇题解的评论区中,有我和用户@fighterhit 给出的代码,在一些情况下,我们先写了不排除中位数的逻辑分支,更合适的标准就是“哪个逻辑分支好想,就先写哪一个”,欢迎大家参与讨论。 优点:分支条数只有 2 条,代码执行效率更高,不用在每一轮循环中单独判断中位数是否符合题目要求,写分支的逻辑的目的是尽量排除更多的候选元素,而判断中位数是否符合题目要求我们放在最后进行,这就是第 5 点; 说明:每一轮循环开始都单独判断中位数是否符合要求,这个操作不是很有普适性,因为从统计意义上说,中位数直接就是你想找的数的概率并不大,有的时候还要看看左边,还要看看右边。不妨就把它放在最后来看,把候选区间“夹逼”到只剩 11 个元素的时候,视情况单独再做判断即可。 注意事项 1:左中位数还是右中位数选择的标准根据分支的逻辑而来,标准是每一次循环都应该让区间收缩,当候选区间只剩下 22 个元素的时候,为了避免死循环发生,选择正确的中位数类型。如果你实在很晕,不防就使用有 22 个元素的测试用例,就能明白其中的原因,另外在代码出现死循环的时候,建议你可以将左边界、右边界、你选择的中位数的值,还有分支逻辑都打印输出一下,出现死循环的原因就一目了然了; 注意事项 2:如果能确定要找的数就在候选区间里,那么退出循环的时候,区间最后收缩成为 11 个数后,直接把这个数返回即可;如果你要找的数有可能不在候选区间里,区间最后收缩成为 11 个数后,还要单独判断一下这个数是否符合题意。 最后给出两个模板,大家看的时候看注释,不必也无需记忆它们。 说明:我写的时候,一般是先默认将中位数写成左中位数,再根据分支的情况,看看是否有必要调整成右中位数,即是不是要在 (right - left) 这个括号里面加 11 。 虽说是两个模板,区别在于选中位数,中位数根据分支逻辑来选,原则是区间要收缩,且不出现死循环,退出循环的时候,视情况,有可能需要对最后剩下的数单独做判断。 我想我应该是成功地把你绕晕了,如果您觉得啰嗦的地方,就当我是“重要的事情说了三遍”吧,确实是重点的地方我才会重复说。当然,最好的理解这个模板的方法还是应用它。在此建议您不妨多做几道使用“二分查找法”解决的问题,用一下我说的这个模板,在发现问题的过程中,体会这个模板好用的地方,相信你一定会和我一样爱上这个模板的。 在「力扣」的探索版块中,给出了二分查找法的 3 个模板,我这篇文章着重介绍了第 2 个模板,但是我介绍的角度和这个版块中给出的角度并不一样,第 1 个模板被我“嫌弃”了,第 3 个模板我看过了,里面给出的例题也可以用第 2 个模板来完成,如果大家有什么使用心得,欢迎与我交流。 来源:力扣(LeetCode),作者:liweiwei1419","link":"/algorithm/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E6%B3%95%E6%A8%A1%E6%9D%BF%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%80%9D%E6%83%B3-leetcode35.html"},{"title":"github Issue 作为博客微型数据库的应用","text":"背景众所周知,对于hexo框架搭建的静态博客,难免会产生一些动态的数据,比如一些碎碎念、友链、音乐、时间轴等微型数据。目前一般的做法: a.是创建一个json数据,来存储这些微型数据,但是如果数据太多的话,一是比较慢,二是有个硬伤问题,就是json数据不能分页请求,只能一次拿完,太多的话网络带宽占用太多。 b.或者有的直接后台写一些接口服务啥的,还得在买个服务器部署上去,然后博客中访问接口。 c.或者有些可能就直接写到html中。 对于a、c方法都比较麻烦,每次更新了都要编译部署,不能很方便的动态更新。对于b的话,成本以及技术要求可能就更多一些了。 基于上面出现的问题,目前想到的一个解决方案就是,利用github 的issue作为一个微型数据库。能够很方便的动态更新,也能分页,也不需要啥json文件,想想都很方便。 issue数据库使用步骤issue的创建先创建一个Repository,对于此Repository可以专门作为微型的数据库,取名issue_database。创建好之后建立一些issue 如下所示 目前博客中,所有的动态数据都放到issue中了。 issue中存储数据对于创建好的issue,就可以往里面写数据了,比如我的友链数据为issue:blog_friends 对于issue中存储的数据最好存json格式的,因为可以方便后面取出来使用。存储好数据后,如果太多的话,可以点击hide,隐藏起来。同时这个issue最好给Lock conversation这样的好处是,防止别人往里面加些脏数据,只能自己往里写数据。哈哈,一般也没有闲的无聊的网友恶作剧。这样就存储好数据了。 博客中获取issue数据博客中通过js获取issue中的数据,以博客友链为例,以下是获取代码,以及处理 1234567891011121314151617181920// author by removef// https://removeif.github.io/$(function () { //获取处理友链数据,来自issue,一次取完 $.getJSON(\"https://api.github.com/repos/removeif/issue_database/issues/2/comments?per_page=100&client_id=46a9f3481b46ea0129d8&client_secret=79c7c9cb847e141757d7864453bcbf89f0655b24\", function (source) { var data = []; var source1; source1 = source; // 以后每次更新的都在后面,此处倒序,按时间降序排 source1.reverse(); // 把所有的数据放到data的列表中 $.each(source1, function (i, e) { data.push(...JSON.parse(e.body)); }); $.each(data, function (i, e) { // 博客中html文件的构建,渲染 });}); 上面代码中client_id、client_secret在另一篇文章中**博客源码分享**有详细的说明,可以查看一下。这样就能获取到相应的数据,进行操作。 issue数据的更新比如想更新任意一项数据都可以进github中对应的仓库的issue下进行更新,添加。然后实时去博客中查看。 扩展一下对于有些爱唠叨的人(比如我),弄个类似碎碎念的东西就比较实用了。之前想过各种方案,存json数据太不方便;后台写个服务部署服务器也太麻烦。最后思来想去还是利用了下现成的优秀项目gitalk,稍稍改改就能很好使用。 博客中的碎碎念对于博主而言,有发表框和修改的操作,能够方便发表和修改。 可能有时候还会发表一些图片,对图片的样式做了一些控制 对于网友的话只能查看以及点赞加❤️ 做法就是源码中改下返回html的文件内容,如果是管理员和非管理员返回一些不同的元素,能够很好的实现碎碎念的功能。查看碎碎念。 总结静态博客的动态数据是个痛点,GitHub Issue有很多可利用的地方。多去探索发掘其中的奥妙。 利用GitHub Issue来解决目前也是一种解决方法。希望后面会出现更好的解决方案。","link":"/theme/github-Issue-%E4%BD%9C%E4%B8%BA%E5%8D%9A%E5%AE%A2%E5%BE%AE%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%BA%94%E7%94%A8.html"},{"title":"苹果6s ios12 nfc 模拟门禁","text":"众所周知,ios系统封闭了对NFC的功能使用。据了解,国外是可以使用的,国内不行,实在搞不懂,有NFC又不能用,这不是浪费资源,多此一举嘛! 设备信息 本机信息6s ios12.4 16Gios 11 直接就能读出卡,没这么复杂。ios 12 可以使用,比较复杂。ios 13 好像不能使用。 步骤越狱使用之前需要设备能够越狱,关于越狱后的一系列安全问题请自行百度。越狱方法可以进威锋论坛找到自己机型版块里的对应教程。本机是通过Windows爱思助手,一键越狱完成。 安装插件源为图中倒数第三个P开头那个,插件为插件图中打钩的那个,有些插件和源的不能用,目前测试这个源和插件是可用的。 使用插件 1.图1,如果是ios11,点击最上面的scan按钮,靠近门禁卡或公交卡就能读出来,但是iOS12读不出。2.图2,点最后一项。3.图3,点击Connect按钮,把卡靠近手机后壳。4.图4,已经读出UID。5.图5,把UID填上。6.图6,然后点击Start按钮,如图开始模拟nfc卡。靠近刷卡机刷卡。我添加的是门禁卡,亲测成功。也能读取添加公交卡,没测试,应该是可以的。每次只能模拟一张卡,使用另外一张需要手动更换UID。 免责声明操作中造成的一切损失与博主无关,请自行掂量谨慎操作。","link":"/ios/%E8%8B%B9%E6%9E%9C6s-ios12-nfc-%E6%A8%A1%E6%8B%9F%E9%97%A8%E7%A6%81.html"},{"title":"常见隔夜菜谨慎食用","text":"我们有许多习惯,总是重复来,重复去,就像上世纪中的人们带着保温盒去上班,现在的人又重回带着饭盒去公司的现象。自己带饭去公司吃的话,不仅大大地节省了一笔吃外卖的费用,而且菜色也可以随便换。但是,很多人带的都是前一天晚上就准备好的隔夜菜,这样对我们的身体健康到底是有益还是有害呢? 隔夜菜的危害大节俭归节俭,殊不知,隔夜菜不仅营养流失严重,而且还会产生对身体有危害的物质。要提醒大家的是,隔夜蔬菜、海鲜不要吃,肉类食用时一定要蒸热熟透,以防食物储存时间长,腐败变质,导致食物中毒。 据说,胃癌发病率低,与不吃隔夜蔬菜的习惯有关。由于部分绿叶类蔬菜中含有较多的硝酸盐类,煮熟后假如放置的时间过久,在细菌的分解作用下,硝酸盐便会还原成亚硝酸盐,有致癌作用,加热也不能去除。 健康吃法:通常茎叶类蔬菜硝酸盐含量最高,瓜类蔬菜稍低,根茎类和花菜类居中。因此,假如同时购买了不同种类的蔬菜,应该先吃茎叶类的,比如大白菜、菠菜等。假如预备多做一些菜第二天热着吃的话,应尽量少做茎叶类蔬菜,而选择瓜类蔬菜。 五种隔夜菜千万别吃绿叶菜隔夜最危险。通常茎叶类蔬菜硝酸盐含量最高,瓜类蔬菜稍低,根茎类和花菜类居中。因此,如果同时购买了大量蔬菜,应该先吃叶菜类的,比如大白菜、菠菜等。如果准备多做一些菜第二天热着吃,应尽量少做茎叶类蔬菜,而选择瓜类蔬菜。 隔夜海鲜损肝肾。螃蟹、鱼类、虾类等海鲜,隔夜后会产生蛋白质降解物,损伤肝、肾功能。如果实在买多了,可以把生海鲜用保鲜袋或保鲜盒装好,放入冰箱冷冻,下次再烹调。 半熟蛋易致病。很多人都爱吃蛋黄软软的半熟蛋,可是这种蛋杀菌不彻底,再加上鸡蛋营养丰富,格外容易滋生细菌,食用后会发生危险。如果蛋已熟透,而且低温密封保存得当,隔夜再吃是没有问题的。 银耳蘑菇要当心。不论是野生的还是人工栽培的银耳、蘑菇等,都容易残留很多硝酸盐。如果放的时间实在有点久,就只能忍痛扔掉。 汤别放金属器皿里。熬汤费时费力,人们往往熬一大锅,一连吃好几天。剩汤如果长时间盛在铝锅、铁锅内,会析出对人体有害的物质。存汤的最好办法是,汤里不要放盐之类的调味料,煮好汤用干净的勺子盛出当天要喝的,喝不完的,最好是用瓦锅或保鲜盒存放在冰箱里。 隔夜菜的保存和食用因为蔬菜对于健康有明确的好处,我们不可能因为“可能”有硝酸盐和亚硝酸盐的存在就不吃。对许多人来说,买一次菜吃几天也是很普通很平常的事情。所以,保存蔬菜,就成了食品健康中很重要的问题。 蔬菜中亚硝酸盐的产生,原料是蔬菜中的硝酸盐,转化条件主要是细菌生长,“隔夜”只是时间长短的问题。减少亚硝酸盐的产生,可以多管齐下。首先,减少蔬菜尤其是绿叶蔬菜的保存时间,增加买菜频率。其次,需要保存的蔬菜,洗净包好可以减少携带的细菌。做好没吃完的蔬菜,也可以封好保存在冰箱中。 “隔夜”并非亚硝酸盐产生的关键,加热也不会增加致癌物的含量。当然,蔬菜中的许多种维生素,在加热的时候会被破坏,多次加热的蔬菜也比较难吃。从“ 好吃”的角度来说,“隔夜菜”确实比较差;从营养的角度说,多次加热也没什么好处。 常见的蔬菜分类瓜类蔬菜种类较多,主要有黄瓜、西葫芦、南瓜、节瓜、青瓜、丝瓜、云南小瓜、苦瓜、白瓜、茄瓜、毛瓜、瓠瓜、佛手瓜、蛇瓜等。其中,黄瓜为果菜兼用的大众蔬菜,南瓜、苦瓜是药食兼用的保健蔬菜,冬瓜为秋淡季的主要蔬菜,其它瓜类则风味各异,都是膳食佳品。瓜类蔬菜在栽培中具有以下通性:1、瓜类蔬菜均为喜温耐热性作物,生长期间需要充足的光照。2、瓜类蔬菜根系再生能力弱,栽培上除直播外,育苗移栽的要保护好根系,培育壮苗。3、瓜类蔬菜均为蔓性作物,生产中通过设立支架可提高产品的产量与品质。4、大部分瓜类蔬菜的采收要及时,防止产品生理成熟后降低品质。5、瓜类蔬菜均为雌雄异花作物,虫媒异花授粉 蔬菜植物的产品器官有根、茎、叶、花、果等5类,因此按产品器官分类也分成5种。(1)根菜类:这类莱的产品(食用)器官为肉质根或块根。 ①肉质根类菜:萝卜、胡萝卜、大头菜(根用芥菜)、芜普、芜菁甘蓝和根用甜菜等。 ②块根类菜:豆薯和葛等。 (2)茎菜类:这类蔬菜食用部分为茎或茎的变态。 ①地下茎类:马铃薯、菊芋、莲藕、姜、荸荠、慈菇和芋等。 ②地上茎类:茭白、石刁柏、竹笋、莴苣笋、球茎甘蓝和榨菜等。 (3)叶莱类:这类蔬菜以普通叶片或叶球、叶丛、变态叶为产品器官。 ①普通叶菜类:小白菜、芥菜、菠菜、芹菜和苋菜等。 ②结球叶莱类:结球甘蓝、大白菜、结球莴苣和包心芥菜等。 ③辛番叶菜类:葱、韭菜、芜荽和茴香等。 ④鳞茎菜类:洋葱、大蒜和百合等。 (4)花菜类:这类蔬菜以花、肥大的花茎或花球为产品器官,如花椰菜、金针菜、青花菜、紫菜蔓、 朝鲜蓟和芥蓝等。 (5)果菜类:这类蔬菜以嫩果实或成熟的果实为产品器官。 ①茄果类:茄子、番茄和辣椒等。 ②荚果类:豆类菜,菜豆、肛豆、刀豆、毛豆、豌豆、蚕豆、眉豆、扁豆和四棱豆等。 ③瓠果类:黄瓜、南瓜、冬瓜、丝瓜、菜瓜、瓠瓜和蛇瓜等,以及西瓜和甜瓜等鲜食的瓜类。 参考文章:参考链接1","link":"/health/%E5%B8%B8%E8%A7%81%E9%9A%94%E5%A4%9C%E8%8F%9C%E8%B0%A8%E6%85%8E%E9%A3%9F%E7%94%A8.html"},{"title":"马拉松-2019西昌最美赛道邛海马拉松","text":"最美赛道,2019西昌邛海湿地马拉松于2019.11.09举行。 前期准备比赛之前抱佛脚的方式晚上跑了几晚,还是训练太少,导致最后的悲剧产生,怨不得别人还是自己不努力,捂脸.jpg。以下是比赛之前的部分数据。总共跑了6次。 路上风景从成都出发去西昌,一路上风景还是很美的,盘山高速立于半空之中,很刺激。途中的岩石,丛林,纷繁各异。不得不惊叹祖国的大好河山,以及大自然的鬼斧神工。车上位置不太好,也拍了几张。途中流彩。 赛前比赛之前领了相关的参赛包。找好了相应的住宿,然后休息。 比赛整个赛道中风景很美,最美赛道也不是吹的,哈哈。赛中流彩1 赛中流彩2 完赛人生不经历一场全程马拉松真的不知道自己身体有多差,跑到30KM之后基本靠走,抽筋,一会儿左脚一会右脚,太难了。归根到底还是前期准备太少了,跑的太少了,不能临时抱佛脚啊。没有捷径,得一步一步的积累啊。这就是血淋淋的案例啊。跑两步,抽一下,又不得不停下来走,真的是太难了,之前跑过两次半马,没出现这个情况,可能我的极限就是30KM了吧。最后还是坚持走完了,用时5小时8分钟,赶在6小时关门前跑完了。第一次全马,也算PB了吧。全马数据。 奖牌奖牌还是挺不错的,挺有纪念意义的。人生第一次全马,也可能是最后一次,庆幸自己坚持下来安全完赛,给自己点个赞👍! 总结人生就像一场马拉松,有悲有乐,有意外有惊喜,沿途有各种美丽的风景,遇见。这一路肯定不会一番风顺,希望我们遇到困难险阻时都能乘风破浪,坚持到最后。当我们到了人生暮年的时候,回想起过去,也能都感觉到这人生不虚此行了。","link":"/marathon/%E9%A9%AC%E6%8B%89%E6%9D%BE-2019%E8%A5%BF%E6%98%8C%E6%9C%80%E7%BE%8E%E8%B5%9B%E9%81%93%E9%82%9B%E6%B5%B7%E9%A9%AC%E6%8B%89%E6%9D%BE.html"},{"title":"算法成长之路leetcode1-4","text":"1.Two SumdescGiven an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice. Example: 1234Given nums = [2, 7, 11, 15], target = 9,Because nums[0] + nums[1] = 2 + 7 = 9,return [0, 1]. solutions.eg1.12345678910111213141516//24 ms 38 MB s.O(n^2) k.O(1)class Solution { public int[] twoSum(int[] nums, int target) { int[] result =new int[2]; for(int i = 0;i<nums.length-1;i++){ for(int j = i+1;j<nums.length;j++){ if(nums[i]+nums[j] == target){ result[0] = i; result[1] = j; return new int[]{i,j}; } } } return new int[0]; }} eg2.12345678910111213// 3 ms 37.2 MB s.O(n) k.O(n)class Solution { public int[] twoSum(int[] nums, int target) { HashMap<Integer,Integer> cache = new HashMap(); for(int i = 0;i<nums.length;i++){ if(cache.get(nums[i]) != null){ return new int[]{cache.get(nums[i]),i}; } cache.put(target-nums[i],i); } return new int[0]; }} 2.Add Two NumbersdesYou are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Example: 123Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)Output: 7 -> 0 -> 8Explanation: 342 + 465 = 807. solutioneg1.1234567891011121314151617181920212223242526272829// 2 ms 44.7 MBclass Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { int carry = 0; // 进位 ListNode head = new ListNode(0); ListNode cur = head; // 一定要用两个链表,不能用一个操作 while(l1 != null ||l2 != null|| carry != 0){ // lastSum当最后一位刚好进1的时候,需要在循环 int l1v = l1 == null?0:l1.val; int l2v = l2 == null?0:l2.val; int temp =l1v+l2v+carry; ListNode node; if(temp>=10){ node = new ListNode(temp-10); lastSum = 1; }else{ node = new ListNode(temp); lastSum = 0; } if(l1 != null) l1 = l1.next; if(l2 != null) l2 = l2.next; cur.next = node; cur = node; } return head.next; }} 3.Longest Substring Without Repeating CharactersdescGiven a string, find the length of the longest substring without repeating characters. Example 1: 123Input: \"abcabcbb\"Output: 3 Explanation: The answer is \"abc\", with the length of 3. Example 2: 123Input: \"bbbbb\"Output: 1Explanation: The answer is \"b\", with the length of 1. Example 3: 1234Input: \"pwwkew\"Output: 3Explanation: The answer is \"wke\", with the length of 3. Note that the answer must be a substring, \"pwke\" is a subsequence and not a substring. solutioneg1.123456789101112131415161718192021222324252627282930//2 ms 24.05% 36.9 MB 95.35%class Solution { public int lengthOfLongestSubstring(String s) { Set<Character> strSet = new HashSet(); int maxLen = 0; if(s != null && s.length() >0){ char ss[] = s.toCharArray(); //利用toCharArray方法转换 for (int i = 0; i < ss.length-1; i++) { strSet.add(ss[i]); for(int j = i+1; j<ss.length; j++){ int oL = strSet.size(); strSet.add(ss[j]); int cL = strSet.size(); if(oL != cL){ // 不相等时记下个数 if(cL > maxLen){ maxLen = cL; } }else{ // 相等时 跳出此次循环 清空set strSet.clear(); break; } } } if(maxLen == 0){ // 全相等时 maxLen = 1; } } return maxLen; }} eg2.123456789101112131415161718// 2 ms 37.3 MBclass Solution { public int lengthOfLongestSubstring(String s) { int maxLength = 0; char[] chars = s.toCharArray(); int leftIndex = 0;//记录最左边相等时的值,然后向右滑动窗口 for (int j = 0; j < chars.length; j++) { for (int innerIndex = leftIndex; innerIndex < j; innerIndex++) { if (chars[innerIndex] == chars[j]) { maxLength = Math.max(maxLength, j - leftIndex); leftIndex = innerIndex + 1; break; } } } return Math.max(chars.length - leftIndex, maxLength); }} 4.Median of Two Sorted ArraysdescThere are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). You may assume nums1 and nums2 cannot be both empty. Example 1: 123nums1 = [1, 3]nums2 = [2]The median is 2.0 Example 2: 123nums1 = [1, 2]nums2 = [3, 4]The median is (2 + 3)/2 = 2.5 solutioneg1.123456789101112131415161718192021222324252627282930// 20 ms 10.07%// 2.2 MB 99.84%class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int maxL = 0; if (nums1.length >= nums2.length) { maxL = nums1.length; } else { maxL = nums2.length; } List<Integer> newList = new ArrayList(maxL); for (int i = 0; i < maxL; i++) { if (i < nums1.length) { newList.add(nums1[i]); } if (i < nums2.length) { newList.add(nums2[i]); } } int size = newList.size(); int index = size / 2; newList.sort(Comparator.comparing(Integer::valueOf)); if (size % 2 == 0) { return (newList.get(index) + newList.get(index - 1)) / 2d; } else { return newList.get(index); } }} eg2.123456789101112131415161718192021222324252627282930313233class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int n = nums1.length + nums2.length; double res = 0.0; if (n <= 0) { return res; } if ((n & 1) == 0) { res = (findKth(nums1, nums2, 0, 0, n / 2) + findKth(nums1, nums2, 0, 0, n / 2 + 1)) / 2.0; } else { res = findKth(nums1, nums2, 0, 0, n / 2 + 1); } return res; } private int findKth(int[] nums1, int[] nums2, int start1, int start2, int k) { if (start1 >= nums1.length) { return nums2[start2 + k - 1]; } if (start2 >= nums2.length) { return nums1[start1 + k - 1]; } if (k == 1) { return Math.min(nums1[start1], nums2[start2]); } int left = start1 + k / 2 - 1 >= nums1.length ? Integer.MAX_VALUE : nums1[start1 + k / 2 - 1]; int right = start2 + k / 2 - 1 >= nums2.length ? Integer.MAX_VALUE : nums2[start2 + k / 2 - 1]; if (left < right) { return findKth(nums1, nums2, start1 + k / 2, start2, k - k / 2); } return findKth(nums1, nums2, start1, start2 + k / 2, k - k / 2); }} eg3.12345678910111213141516171819202122232425262728293031323334353637383940414243444546// 二分查找、分治算法class Solution { public double findMedianSortedArrays(int[] A, int[] B) { //m:A数组的长度 int m = A.length; //n:B数组的长度 int n = B.length; //如果A的长度大于B if (m > n) { // to ensure m<=n //交换AB数组,确保m<=n int[] temp = A; A = B; B = temp; int tmp = m; m = n; n = tmp; } //设置两个指针,iMin为头指针,IMAX为尾指针,halfLen为中位数指针 int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2; //如果头指针走向不大于尾指针,进行循环 while (iMin <= iMax) { //i为中位数 int i = (iMin + iMax) / 2; //j为 int j = halfLen - i; if (i < iMax && B[j - 1] > A[i]){ iMin = i + 1; // i is too small } else if (i > iMin && A[i - 1] > B[j]) { iMax = i - 1; // i is too big } else { // i is perfect int maxLeft = 0; if (i == 0) { maxLeft = B[j-1]; } else if (j == 0) { maxLeft = A[i - 1]; } else { maxLeft = Math.max(A[i - 1], B[j - 1]); } if ( (m + n) % 2 == 1 ) { return maxLeft; } int minRight = 0; if (i == m) { minRight = B[j]; } else if (j == n) { minRight = A[i]; } else { minRight = Math.min(B[j], A[i]); } return (maxLeft + minRight) / 2.0; } } return 0d; }}","link":"/algorithm/%E7%AE%97%E6%B3%95%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AFleetcode1-4.html"},{"title":"替代web-cookie存储方案实现","text":"随着移动网络的发展与演化,我们手机上现在除了有原生 App,还能跑“WebApp”——它即开即用,用完即走。一个优秀的 WebApp 甚至可以拥有和原生 App 媲美的功能和体验。WebApp 优异的性能表现,有一部分原因要归功于浏览器存储技术的提升。cookie存储数据的功能已经很难满足开发所需,逐渐被WebStorage、IndexedDB所取代,本文将介绍这几种存储方式的差异和优缺点。 Cookie1、Cookie的来源Cookie 的本职工作并非本地存储,而是“维持状态”。因为HTTP协议是无状态的,HTTP协议自身不对请求和响应之间的通信状态进行保存,通俗来说,服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。 在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两瓶饮料。最后结帐时,由于HTTP的无状态性,不通过额外的手段,服务器并不知道用户到底买了什么,于是就诞生了Cookie。它就是用来绕开HTTP的无状态性的“额外手段”之一。服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。 我们可以把Cookie 理解为一个存储在浏览器里的一个小小的文本文件,它附着在 HTTP 请求上,在浏览器和服务器之间“飞来飞去”。它可以携带用户信息,当服务器检查 Cookie 的时候,便可以获取到客户端的状态。 在刚才的购物场景中,当用户选购了第一项商品,服务器在向用户发送网页的同时,还发送了一段Cookie,记录着那项商品的信息。当用户访问另一个页面,浏览器会把Cookie发送给服务器,于是服务器知道他之前选购了什么。用户继续选购饮料,服务器就在原来那段Cookie里追加新的商品信息。结帐时,服务器读取发送来的Cookie就行了。 2、什么是Cookie及应用场景?Cookie指某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。 cookie是服务端生成,客户端进行维护和存储。通过cookie,可以让服务器知道请求是来源哪个客户端,就可以进行客户端状态的维护,比如登陆后刷新,请求头就会携带登陆时response header中的set-cookie,Web服务器接到请求时也能读出cookie的值,根据cookie值的内容就可以判断和恢复一些用户的信息状态。 Cookie 以键值对的形式存在。 典型的应用场景有: 记住密码,下次自动登录; 购物车功能; 记录用户浏览数据,进行商品(广告)推荐。 3、Cookie的原理及生成方式Cookie的原理: 第一次访问网站的时候,浏览器发出请求,服务器响应请求后,会在响应头里面添加一个Set-Cookie选项,将cookie放入到响应请求中,在浏览器第二次发请求的时候,会通过Cookie请求头部将Cookie信息发送给服务器,服务端会辨别用户身份,另外,Cookie的过期时间、域、路径、有效期、适用站点都可以根据需要来指定。 Cookie的生成方式主要有两种: 生成方式一:http response header中的set-cookie 我们可以通过响应头里的 Set-Cookie 指定要存储的 Cookie 值。默认情况下,domain 被设置为设置 Cookie 页面的主机名,我们也可以手动设置 domain 的值。 1Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2018 07:28:00 GMT;//可以指定一个特定的过期时间(Expires)或有效期(Max-Age) 生成方式二:js中可以通过document.cookie可以读写cookie,以键值对的形式展示 例如我们在掘金社区控制台输入以下三句代码,便可以在Chrome 的 Application 面板查看生成的cookie: 123document.cookie=\"userName=hello\"document.cookie=\"gender=male\"document.cookie='age=20;domain=.baidu.com' Domain 标识指定了哪些域名可以接受Cookie。如果没有设置domain,就会自动绑定到执行语句的当前域。 如果设置为”.baidu.com”,则所有以”baidu.com”结尾的域名都可以访问该Cookie,所以在掘金社区上读取不到第三条代码存储Cookie值。 4、Cookie的缺陷 Cookie 不够大 Cookie的大小限制在4KB左右,对于复杂的存储需求来说是不够用的。当 Cookie 超过 4KB 时,它将面临被裁切的命运。这样看来,Cookie 只能用来存取少量的信息。此外很多浏览器对一个站点的cookie个数也是有限制的。 这里需注意:各浏览器的cookie每一个name=value的value值大概在4k,所以4k并不是一个域名下所有的cookie共享的,而是一个name的大小。 过多的 Cookie 会带来巨大的性能浪费 Cookie 是紧跟域名的。同一个域名下的所有请求,都会携带 Cookie。大家试想,如果我们此刻仅仅是请求一张图片或者一个 CSS 文件,我们也要携带一个 Cookie 跑来跑去(关键是 Cookie 里存储的信息并不需要),这是一件多么劳民伤财的事情。Cookie 虽然小,请求却可以有很多,随着请求的叠加,这样的不必要的 Cookie 带来的开销将是无法想象的。 cookie是用来维护用户信息的,而域名(domain)下所有请求都会携带cookie,但对于静态文件的请求,携带cookie信息根本没有用,此时可以通过cdn(存储静态文件的)的域名和主站的域名分开来解决。 - 由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题,除非用HTTPS。 5、Cookie与安全HttpOnly 不支持读写,浏览器不允许脚本操作document.cookie去更改cookie, 所以为避免跨域脚本 (XSS) 攻击,通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie,它们只应该发送给服务端。如果包含服务端 Session 信息的 Cookie 不想被客户端 JavaScript 脚本调用,那么就应该为其设置 HttpOnly 标记。 1Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly 标记为 Secure 的Cookie只应通过被HTTPS协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过Cookie传输,因为Cookie有其固有的不安全性,Secure 标记也无法提供确实的安全保障。 为了弥补 Cookie 的局限性,让“专业的人做专业的事情”,Web Storage 出现了。 HTML5中新增了本地存储的解决方案——Web Storage,它分成两类:sessionStorage和localStorage。这样有了WebStorage后,cookie能只做它应该做的事情了——作为客户端与服务器交互的通道,保持客户端状态。 LocalStorage1、LocalStorage的特点 保存的数据长期存在,下一次访问该网站的时候,网页可以直接读取以前保存的数据; 大小为5M左右; 仅在客户端使用,不和服务端进行通信; 接口封装较好。 基于上面的特点,LocalStorage可以作为浏览器本地缓存方案,用来提升网页首屏渲染速度(根据第一请求返回时,将一些不变信息直接存储在本地)。 2、存入/读取数据localStorage保存的数据,以“键值对”的形式存在。也就是说,每一项数据都有一个键名和对应的值。所有的数据都是以文本格式保存。 存入数据使用setItem方法。它接受两个参数,第一个是键名,第二个是保存的数据。 1localStorage.setItem(\"key\",\"value\"); 读取数据使用getItem方法。它只有一个参数,就是键名。 1var valueLocal = localStorage.getItem(\"key\"); 具体步骤,请看下面的例子: 12345678910111213141516<script>if(window.localStorage){ localStorage.setItem('name','world') localStorage.setItem(“gender','famale')}</script><body><div id=\"name\"></div><div id=\"gender\"></div><script>var name=localStorage.getItem('name')var gender=localStorage.getItem('gender')document.getElementById('name').innerHTML=namedocument.getElementById('gender').innerHTML=gender</script></body> 3、使用场景LocalStorage在存储方面没有什么特别的限制,理论上 Cookie 无法胜任的、可以用简单的键值对来存取的数据存储任务,都可以交给 LocalStorage 来做。 这里给大家举个例子,考虑到 LocalStorage 的特点之一是持久,有时我们更倾向于用它来存储一些内容稳定的资源。比如图片内容丰富的电商网站会用它来存储 Base64 格式的图片字符串: sessionStoragesessionStorage保存的数据用于浏览器的一次会话,当会话结束(通常是该窗口关闭),数据被清空;sessionStorage 特别的一点在于,即便是相同域名下的两个页面,只要它们不在同一个浏览器窗口中打开,那么它们的 sessionStorage 内容便无法共享;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。除了保存期限的长短不同,SessionStorage的属性和方法与LocalStorage完全一样。 1、sessionStorage的特点 会话级别的浏览器存储; 大小为5M左右; 仅在客户端使用,不和服务端进行通信; 接口封装较好。 基于上面的特点,sessionStorage 可以有效对表单信息进行维护,比如刷新时,表单信息不丢失。 2、使用场景sessionStorage 更适合用来存储生命周期和它同步的会话级别的信息。这些信息只适用于当前会话,当你开启新的会话时,它也需要相应的更新或释放。比如微博的 sessionStorage就主要是存储你本次会话的浏览足迹: lasturl 对应的就是你上一次访问的 URL 地址,这个地址是即时的。当你切换 URL 时,它随之更新,当你关闭页面时,留着它也确实没有什么意义了,干脆释放吧。这样的数据用 sessionStorage 来处理再合适不过。 3、sessionStorage 、localStorage 和 cookie 之间的区别 共同点:都是保存在浏览器端,且都遵循同源策略。 不同点:在于生命周期与作用域的不同 作用域:localStorage只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据。sessionStorage比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下。 生命周期:localStorage 是持久化的本地存储,存储在其中的数据是永远不会过期的,使其消失的唯一办法是手动删除;而 sessionStorage 是临时性的本地存储,它是会话级别的存储,当会话结束(页面被关闭)时,存储内容也随之被释放。 Web Storage 是一个从定义到使用都非常简单的东西。它使用键值对的形式进行存储,这种模式有点类似于对象,却甚至连对象都不是——它只能存储字符串,要想得到对象,我们还需要先对字符串进行一轮解析。对于对象存储 1234567891011121314if (COMMENT_CACHE != '') { // 异常不影响结果,继续往下执行 try { COMMENT = JSON.parse(COMMENT_CACHE); COMMENT_ARR = COMMENT[\"data\"]; } catch (e) { COMMENT_CACHE = ''; console.error(e); }}if (COMMENT_ARR.length > 0) { localStorage.setItem(COMMENT_CACHE_KEY, JSON.stringify(resultMap));} 说到底,Web Storage 是对 Cookie 的拓展,它只能用于存储少量的简单数据。当遇到大规模的、结构复杂的数据时,Web Storage 也爱莫能助了。这时候我们就要清楚我们的终极大 boss——IndexedDB! IndexedDBndexedDB 是一种低级API,**用于客户端存储大量结构化数据(包括文件和blobs)**。该API使用索引来实现对该数据的高性能搜索。IndexedDB 是一个运行在浏览器上的非关系型数据库。 既然是数据库了,那就不是 5M、10M 这样小打小闹级别了。理论上来说,IndexedDB 是没有存储上限的(一般来说不会小于 250M)。它不仅可以存储字符串,还可以存储二进制数据。 1、IndexedDB的特点 键值对储存 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以”键值对”的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。 异步 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。 支持事务 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。 同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。 储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。 支持二进制储存 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。 2、IndexedDB的常见操作在IndexedDB大部分操作并不是我们常用的调用方法,返回结果的模式,而是请求——响应的模式。 建立打开IndexedDB——window.indexedDB.open(\"testDB\") 这条指令并不会返回一个DB对象的句柄,我们得到的是一个IDBOpenDBRequest对象,而我们希望得到的DB对象在其result属性中。 除了result,IDBOpenDBRequest接口定义了几个重要属性: onerror: 请求失败的回调函数句柄; onsuccess:请求成功的回调函数句柄; onupgradeneeded:请求数据库版本变化句柄。 如下使用: 123456789101112131415161718<script>function openDB(name){ var request=window.indexedDB.open(name)//建立打开IndexedDB request.onerror=function (e){ console.log('open indexdb error')}request.onsuccess=function (e){ myDB.db=e.target.result//这是一个 IDBDatabase对象,这就是IndexedDB对象 console.log(myDB.db)//此处就可以获取到db实例}}var myDB={ name:'testDB', version:'1', db:null}openDB(myDB.name)</script> 控制台得到一个 IDBDatabase对象,这就是IndexedDB对象: 关闭IndexedDB: 123function closeDB(db){ db.close();} 删除IndexedDB: 123function deleteDB(name) { indexedDB.deleteDatabase(name)} 简单示例 object store有了数据库后我们自然希望创建一个表用来存储数据,但indexedDB中没有表的概念,而是objectStore,一个数据库中可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存储的每条数据和一个键相关联。 我们可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。选择键的类型不同,objectStore可以存储的数据结构也有差异 键类型 存储数据 不使用 任意值,但是没添加一条数据的时候需要指定键参数 keyPath Javascript对象,对象必须有一属性作为键值 keyGenerator 任意值 都使用 Javascript对象,如果对象中有keyPath指定的属性则不生成新的键值,如果没有自动生成递增键值,填充keyPath指定属性 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116// 调用var myDB={ name:'test', version:3, db:null }; openDB(myDB.name,myDB.version); setTimeout(function(){ closeDB(myDB.db); deleteDB(myDB.name); },500);//给object store添加数据function openDB (name,version) { var version=version || 1; var request=window.indexedDB.open(name,version); request.onerror=function(e){ console.log(e.currentTarget.error.message); }; request.onsuccess=function(e){ myDB.db=e.target.result; }; request.onupgradeneeded=function(e){ var db=e.target.result; if(!db.objectStoreNames.contains('students')){ db.createObjectStore('students',{keyPath:\"id\"}); } console.log('DB version changed to '+version); }; }// 数据var students=[{ id:1001, name:\"Byron\", age:24 },{ id:1002, name:\"Frank\", age:30 },{ id:1003, name:\"Aaron\", age:26 }];// 添加function addData(db,storeName){ var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); for(var i=0;i<students.length;i++){ store.add(students[i]); } }openDB(myDB.name,myDB.version); setTimeout(function(){ addData(myDB.db,'students'); },1000);// keyGeneratefunction openDB (name,version) { var version=version || 1; var request=window.indexedDB.open(name,version); request.onerror=function(e){ console.log(e.currentTarget.error.message); }; request.onsuccess=function(e){ myDB.db=e.target.result; }; request.onupgradeneeded=function(e){ var db=e.target.result; if(!db.objectStoreNames.contains('students')){ db.createObjectStore('students',{autoIncrement: true}); } console.log('DB version changed to '+version); }; }// 查找数据function getDataByKey(db,storeName,value){ var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); var request=store.get(value); request.onsuccess=function(e){ var student=e.target.result; console.log(student.name); };}// 更新数据function updateDataByKey(db,storeName,value){ var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); var request=store.get(value); request.onsuccess=function(e){ var student=e.target.result; student.age=35; store.put(student); };}//删除数据及object store 调用object store的delete方法根据键值删除记录function deleteDataByKey(db,storeName,value){ var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); store.delete(value); }// 调用object store的clear方法可以清空object storefunction clearObjectStore(db,storeName){ var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); store.clear();}// 调用数据库实例的deleteObjectStore方法可以删除一个object store,这个就得在onupgradeneeded里面调用了if(db.objectStoreNames.contains('students')){ db.deleteObjectStore('students'); } 总结正是浏览器存储、缓存技术的出现和发展,为我们的前端应用带来了无限的转机。近年来基于存储、缓存技术的第三方库层出不绝,此外还衍生出了 PWA 这样优秀的 Web 应用模型。 总结下本文几个核心观点: Cookie 的本职工作并非本地存储,而是“维持状态”; Web Storage 是 HTML5 专门为浏览器存储而提供的数据存储机制,不与服务端发生通信; IndexedDB 用于客户端存储大量结构化数据。 参考文章:参考链接1参考链接2","link":"/front/%E6%9B%BF%E4%BB%A3web-cookie%E5%AD%98%E5%82%A8%E6%96%B9%E6%A1%88%E5%AE%9E%E7%8E%B0.html"},{"title":"用栈实现队列/用队列实现栈","text":"队列是一种先进先出的数据结构,栈是一种先进后出的数据结构。 队列是一种先进先出的数据结构,栈是一种先进后出的数据结构,形象一点就是这样: 这两种数据结构底层其实都是数组或者链表实现的,只是 API 限定了它们的特性,那么今天就来看看如何使用「栈」的特性来实现一个「队列」,如何用「队列」实现一个「栈」。 用栈实现队列首先,队列的 API 如下: 1234567891011121314class MyQueue { /** 添加元素到队尾 */ public void push(int x); /** 删除队头的元素并返回 */ public int pop(); /** 返回队头元素 */ public int peek(); /** 判断队列是否为空 */ public boolean empty();} 我们使用两个栈s1, s2就能实现一个队列的功能(这样放置栈可能更容易理解): 123456789class MyQueue { private Stack<Integer> s1, s2; public MyQueue() { s1 = new Stack<>(); s2 = new Stack<>(); } // ...} 当调用push让元素入队时,只要把元素压入s1即可,比如说push进 3 个元素分别是 1,2,3,那么底层结构就是这样: 1234/** 添加元素到队尾 */public void push(int x) { s1.push(x);} 那么如果这时候使用peek查看队头的元素怎么办呢?按道理队头元素应该是 1,但是在s1中 1 被压在栈底,现在就要轮到s2起到一个中转的作用了: 当s2为空时,可以把s1的所有元素取出再添加进s2,这时候s2中元素就是先进先出顺序了。 12345678/** 返回队头元素 */public int peek() { if (s2.isEmpty()) // 把 s1 元素压入 s2 while (!s1.isEmpty()) s2.push(s1.pop()); return s2.peek();} 同理,对于pop操作,只要操作s2就可以了。 123456/** 删除队头的元素并返回 */public int pop() { // 先调用 peek 保证 s2 非空 peek(); return s2.pop();} 最后,如何判断队列是否为空呢?如果两个栈都为空的话,就说明队列为空: 1234/** 判断队列是否为空 */public boolean empty() { return s1.isEmpty() && s2.isEmpty();} 至此,就用栈结构实现了一个队列,核心思想是利用两个栈互相配合。 值得一提的是,这几个操作的时间复杂度是多少呢?其他操作都是 O(1),有点意思的是peek操作,调用它时可能触发while循环,这样的话时间复杂度是 O(N),但是大部分情况下while循环不会被触发,时间复杂度是 O(1)。由于pop操作调用了peek,它的时间复杂度和peek相同。 像这种情况,可以说它们的最坏时间复杂度是 O(N),因为包含while循环,可能需要从s1往s2搬移元素。 但是它们的均摊时间复杂度是 O(1),这个要这么理解:对于一个元素,最多只可能被搬运一次,也就是说peek操作平均到每个元素的时间复杂度是 O(1)。 用队列实现栈如果说双栈实现队列比较巧妙,那么用队列实现栈就比较简单粗暴了,只需要一个队列作为底层数据结构。首先看下栈的 API: 1234567891011121314class MyStack { /** 添加元素到栈顶 */ public void push(int x); /** 删除栈顶的元素并返回 */ public int pop(); /** 返回栈顶元素 */ public int top(); /** 判断栈是否为空 */ public boolean empty();} 先说pushAPI,直接将元素加入队列,同时记录队尾元素,因为队尾元素相当于栈顶元素,如果要top查看栈顶元素的话可以直接返回: 12345678910111213141516class MyStack { Queue<Integer> q = new LinkedList<>(); int top_elem = 0; /** 添加元素到栈顶 */ public void push(int x) { // x 是队列的队尾,是栈的栈顶 q.offer(x); top_elem = x; } /** 返回栈顶元素 */ public int top() { return top_elem; }} 我们的底层数据结构是先进先出的队列,每次pop只能从队头取元素;但是栈是后进先出,也就是说popAPI 要从队尾取元素。 解决方法简单粗暴,把队列前面的都取出来再加入队尾,让之前的队尾元素排到队头,这样就可以取出了: 12345678910/** 删除栈顶的元素并返回 */public int pop() { int size = q.size(); while (size > 1) { q.offer(q.poll()); size--; } // 之前的队尾元素已经到了队头 return q.poll();} 这样实现还有一点小问题就是,原来的队尾元素被提到队头并删除了,但是top_elem变量没有更新,我们还需要一点小修改: 1234567891011121314/** 删除栈顶的元素并返回 */public int pop() { int size = q.size(); // 留下队尾 2 个元素 while (size > 2) { q.offer(q.poll()); size--; } // 记录新的队尾元素 top_elem = q.peek(); q.offer(q.poll()); // 删除之前的队尾元素 return q.poll();} 最后,APIempty就很容易实现了,只要看底层的队列是否为空即可: 1234/** 判断栈是否为空 */public boolean empty() { return q.isEmpty();} 很明显,用队列实现栈的话,pop 操作时间复杂度是 O(N),其他操作都是 O(1)。 个人认为,用队列实现栈没啥亮点,但是用双栈实现队列是值得学习的。 出栈顺序本来就和入栈顺序相反,但是从栈s1搬运元素到s2之后,s2中元素出栈的顺序就变成了队列的先进先出顺序,这个特性有点类似「负负得正」,确实不容易想到。 参考文章:参考链接1","link":"/data-structure/%E7%94%A8%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97-%E7%94%A8%E9%98%9F%E5%88%97%E5%AE%9E%E7%8E%B0%E6%A0%88.html"},{"title":"Redis的内存淘汰策略问题","text":"Redis是基于内存的key-value数据库,因为系统的内存大小有限,所以我们在使用Redis的时候可以配置Redis能使用的最大的内存大小。 Redis配置内存1、通过配置文件配置通过在Redis安装目录下面的redis.conf配置文件中添加以下配置设置内存大小 123//设置Redis最大占用内存大小为100Mmaxmemory 100mb redis的配置文件不一定使用的是安装目录下面的redis.conf文件,启动redis服务的时候是可以传一个参数指定redis的配置文件的 2、通过命令修改Redis支持运行时通过命令动态修改内存大小 1234//设置Redis最大占用内存大小为100M127.0.0.1:6379> config set maxmemory 100mb//获取设置的Redis能使用的最大内存大小127.0.0.1:6379> config get maxmemory 如果不设置最大内存大小或者设置最大内存大小为0,在64位操作系统下不限制内存大小,在32位操作系统下最多使用3GB内存 Redis的内存淘汰既然可以设置Redis最大占用内存大小,那么配置的内存就有用完的时候。那在内存用完的时候,还继续往Redis里面添加数据不就没内存可用了吗? 实际上Redis定义了几种策略用来处理这种情况: **noeviction(默认策略)**:对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外) allkeys-lru:从所有key中使用LRU算法进行淘汰 volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰 allkeys-random:从所有key中随机淘汰数据 volatile-random:从设置了过期时间的key中随机淘汰 volatile-ttl:在设置了过期时间的key中,根据key的过期时间进行淘汰,越早过期的越优先被淘汰 当使用volatile-lru、volatile-random、volatile-ttl这三种策略时,如果没有key可以被淘汰,则和noeviction一样返回错误 如何获取及设置内存淘汰策略获取当前内存淘汰策略: 1127.0.0.1:6379> config get maxmemory-policy 通过配置文件设置淘汰策略(修改redis.conf文件): 1maxmemory-policy allkeys-lru 通过命令修改淘汰策略: 1127.0.0.1:6379> config set maxmemory-policy allkeys-lru LRU算法什么是LRU?上面说到了Redis可使用最大内存使用完了,是可以使用LRU算法进行内存淘汰的,那么什么是LRU算法呢? **LRU(Least Recently Used)**,即最近最少使用,是一种缓存置换算法。在使用内存作为缓存的时候,缓存的大小一般是固定的。当缓存被占满,这个时候继续往缓存里面添加数据,就需要淘汰一部分老的数据,释放内存空间用来存储新的数据。这个时候就可以使用LRU算法了。其核心思想是:如果一个数据在最近一段时间没有被用到,那么将来被使用到的可能性也很小,所以就可以被淘汰掉。 使用java实现一个简单的LRU算法123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102public class LRUCache<k, v> { //容量 private int capacity; //当前有多少节点的统计 private int count; //缓存节点 private Map<k, Node<k, v>> nodeMap; private Node<k, v> head; private Node<k, v> tail; public LRUCache(int capacity) { if (capacity < 1) { throw new IllegalArgumentException(String.valueOf(capacity)); } this.capacity = capacity; this.nodeMap = new HashMap<>(); //初始化头节点和尾节点,利用哨兵模式减少判断头结点和尾节点为空的代码 Node headNode = new Node(null, null); Node tailNode = new Node(null, null); headNode.next = tailNode; tailNode.pre = headNode; this.head = headNode; this.tail = tailNode; } public void put(k key, v value) { Node<k, v> node = nodeMap.get(key); if (node == null) { if (count >= capacity) { //先移除一个节点 removeNode(); } node = new Node<>(key, value); //添加节点 addNode(node); } else { //移动节点到头节点 moveNodeToHead(node); } } public Node<k, v> get(k key) { Node<k, v> node = nodeMap.get(key); if (node != null) { moveNodeToHead(node); } return node; } private void removeNode() { Node node = tail.pre; //从链表里面移除 removeFromList(node); nodeMap.remove(node.key); count--; } private void removeFromList(Node<k, v> node) { Node pre = node.pre; Node next = node.next; pre.next = next; next.pre = pre; node.next = null; node.pre = null; } private void addNode(Node<k, v> node) { //添加节点到头部 addToHead(node); nodeMap.put(node.key, node); count++; } private void addToHead(Node<k, v> node) { Node next = head.next; next.pre = node; node.next = next; node.pre = head; head.next = node; } public void moveNodeToHead(Node<k, v> node) { //从链表里面移除 removeFromList(node); //添加节点到头部 addToHead(node); } class Node<k, v> { k key; v value; Node pre; Node next; public Node(k key, v value) { this.key = key; this.value = value; } }} 上面这段代码实现了一个简单的LUR算法,代码很简单,也加了注释,仔细看一下很容易就看懂。 LRU在Redis中的实现近似LRU算法Redis使用的是近似LRU算法,它跟常规的LRU算法还不太一样。近似LRU算法通过随机采样法淘汰数据,每次随机出5(默认)个key,从里面淘汰掉最近最少使用的key。 可以通过maxmemory-samples参数修改采样数量:例:maxmemory-samples 10 maxmenory-samples配置的越大,淘汰的结果越接近于严格的LRU算法 Redis为了实现近似LRU算法,给每个key增加了一个额外增加了一个24bit的字段,用来存储该key最后一次被访问的时间。 Redis3.0对近似LRU的优化Redis3.0对近似LRU算法进行了一些优化。新算法会维护一个候选池(大小为16),池中的数据根据访问时间进行排序,第一次随机选取的key都会放入池中,随后每次随机选取的key只有在访问时间小于池中最小的时间才会放入池中,直到候选池被放满。当放满后,如果有新的key需要放入,则将池中最后访问时间最大(最近被访问)的移除。 当需要淘汰的时候,则直接从池中选取最近访问时间最小(最久没被访问)的key淘汰掉就行。 LRU算法的对比我们可以通过一个实验对比各LRU算法的准确率,先往Redis里面添加一定数量的数据n,使Redis可用内存用完,再往Redis里面添加n/2的新数据,这个时候就需要淘汰掉一部分的数据,如果按照严格的LRU算法,应该淘汰掉的是最先加入的n/2的数据。生成如下各LRU算法的对比图 你可以看到图中有三种不同颜色的点: 浅灰色是被淘汰的数据 灰色是没有被淘汰掉的老数据 绿色是新加入的数据 我们能看到Redis3.0采样数是10生成的图最接近于严格的LRU。而同样使用5个采样数,Redis3.0也要优于Redis2.8。 LFU算法LFU算法是Redis4.0里面新加的一种淘汰策略。它的全称是Least Frequently Used,它的核心思想是根据key的最近被访问的频率进行淘汰,很少被访问的优先被淘汰,被访问的多的则被留下来。LFU算法能更好的表示一个key被访问的热度。假如你使用的是LRU算法,一个key很久没有被访问到,只刚刚是偶尔被访问了一次,那么它就被认为是热点数据,不会被淘汰,而有些key将来是很有可能被访问到的则被淘汰了。如果使用LFU算法则不会出现这种情况,因为使用一次并不会使一个key成为热点数据。LFU一共有两种策略: volatile-lfu:在设置了过期时间的key中使用LFU算法淘汰keyallkeys-lfu:在所有的key中使用LFU算法淘汰数据设置使用这两种淘汰策略跟前面讲的一样,不过要注意的一点是这两周策略只能在Redis4.0及以上设置,如果在Redis4.0以下设置会报错 参考文章:参考链接1","link":"/database/redis/Redis%E7%9A%84%E5%86%85%E5%AD%98%E6%B7%98%E6%B1%B0%E7%AD%96%E7%95%A5%E9%97%AE%E9%A2%98.html"},{"title":"原码补码异或与位运算移位知识点","text":"异或,英文为exclusive OR,缩写成xor异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:a⊕b = (¬a ∧ b) ∨ (a ∧¬b)如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法。 byte、bit字节(Byte)/比特位(bit) 123456789B是Byte的缩写,B就是Byte,也就是字节(Byte);b是bit的缩写,b就是bit,也就是比特位(bit)。B与b不同,注意区分,KB是千字节,Kb是千比特位。1MB(兆字节) = 1024KB(千字节)= 1024*1024B(字节) = 1048576B(字节);8bit(比特位)= 1Byte(字节);1024Byte(字节)= 1KB(千字节);1024KB(千字节)= 1MB(兆字节);1024MB = 1GB;1024GB = 1TB; 原码、反码、补码其实数据存储在内存中都是存储的二进制,二进制又可分为原码、反码、补码。最终存储在内存中的是“补码”。 一个正数的原码、反码、补码都是它的二进制表现形式。(无符号数没有原码、反码和补码一说。只有带符号数才存在不同的编码方式。) 1234567例如:9 == int == 4个字节 == 1个字节等于8位 == 整形有32位正数的原码:0000 0000 0000 0000 0000 0000 0000 1001正数的反码就是正数的原码:0000 0000 0000 0000 0000 0000 0000 1001正数的补码也是整数的原码:0000 0000 0000 0000 0000 0000 0000 1001 二进制的第一位是符号位,0代表整数,1代表负数。 一个负数的原码是首位为1的二进制数。反码是符号位不变,其他位取反。补码是反码加1。 1234567例如:-9原码为首位为1的二进制数:1000 0000 0000 0000 0000 0000 0000 1001反码为符号位不变,其他位取反:1111 1111 1111 1111 1111 1111 1111 0110补码是反码加1:1111 1111 1111 1111 1111 1111 1111 0111 为什么会有原码反码补码? 由于最高位是符号位,如果是0就代表正数,1就代表是负数。 那么直接存储原码,计算机在计算的时候还需要先判断最高位才能计算,效率比较低 为了方便计算机计算,所以有了反码和补码,然后计算机就不需要判断符号位了,只做加法运算就可以了。 计算十进制的表达式:1 - 1 = 0 123451 - 1 == 1 + (-1) 0000 0001(原码)+1000 0001(原码)---------------- 1000 0010(原码) == -2 如果用原码表示,让符号位参与计算,显然对于减法来说是不正确的。这也是计算机内部不以原码表示的原因。 为了解决原码做减法的问题,出现了反码: 123451 - 1 == 1 + (-1) 0000 0001(反码)+1111 1110(反码)---------------- 1111 1111(反码) 转成原码 -> 1000 0000 == -0 通常我们用最高的有效位来表示数的符号(当用8位来表示一个整数时,第8位即为最高有效位,当用16位来表示一个整数时,第16位即为最高有效位。)0表示正号、1表示负号,这种正负号数字化的机内表示形式就称为“机器数”,而相应的机器外部用正负号表示的数称为“真值”。将一个真值表示成二进制字串的机器数的过程就称为编码。 于是补码出现了,解决了0的符号问题以及两个编码的问题,0的编码就只有+0,-0已经等于-128了。 1234561 - 1 == 1 + (-1) 0000 0001(补码)+1111 1111(补码)----------------10000 0000(补码) 第一位溢出后转成原码 -> 0000 0000 == 0 与、或、异或运算1.与运算(&)参加运算的两个数据,按二进制位进行“与”运算。 1234567运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1; 即:两位同时为“1”,结果才为“1”,否则为0例如:3&5 即 0000 0011 & 0000 0101 = 0000 0001 因此,3&5的值得1。例如:9&5 即 0000 1001 (9的二进制补码)&00000101 (5的二进制补码) =00000001 (1的二进制补码)可见9&5=1。 2.或运算(|)参加运算的两个对象,按二进制位进行“或”运算。 12345 运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1; 即 :参加运算的两个对象只要有一个为1,其值为1。例如:3|5 即 0000 0011 | 0000 0101 = 0000 0111 因此,3|5的值得7。 例如:9|5可写算式如下: 00001001|00000101 =00001101 (十进制为13)可见9|5=13 3.异或运算(^)参加运算的两个数据,按二进制位进行“异或”运算。 1运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0; 即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。 1例如:9^5可写成算式如下: 00001001^00000101=00001100 (十进制为12)可见9^5=12 位、移位运算一个字节数占 8 位,将 a,b 转换为二进制: 12a = 0000 1111b = 1111 0001 Note:计算机使用补码表示 位与运算符:仅当两个操作数同一下标的值均为 1 时,结果才为 1 1a & b = 0000 1111 & 1111 0001 = 0000 0001(补) = 0000 0001(原) = 1 位或运算符:只要两个操作数同一下标的值有一个为 1 时,结果就为 1 1a | b = 0000 1111 & 1111 0001 = 1111 1111(补) = 1000 0001(原) = -1 位异或运算符:只有两个操作数同意下标的值不相等时,结果才为 1 1a ^ b = 0000 1111 ^ 1111 0001 = 1111 1110(补) = 1000 0010(原) = -2 位取反运算符:按位取反每一位 12~a = ~0000 1111 = 1111 0000(补) = 1001 0000(原) = -16~b = ~1111 0001 = 0000 1110(补) = 0000 1110(原) = 14 Note 1:byte 或者 short 类型数值进行位运算后,返回的是 int 类型数值(没有找到资料说明在位运算之前是否已经进行了转换,不过先将 a,b 转换为 int 类型二进制再进行计算的结果和上面一致) Note 2:位运算符的操作不排除符号位 移位运算符Java 提供了 3 种移位运算符 左移运算符(left shift operator):<< 右移运算符(right shift operator):>> 无符号右移运算符(unsigned right shift operator):>>> 对于移位运算符而言,左侧操作数表示要移动的二进制数,右侧操作数表示要移动的位数 进行移位操作时,需要注意以下几点: 对于 byte 或者 short 类型数值,进行移位操作时,会先转换为 int 类型,然后进行移位(如果是 long 类型,则不变) 对于右侧操作数而言,在进行移位之前,先转换为二进制数(补码)。如果左侧数是 int 类型,则取右侧操作数最右端 5 位数值进行移动;如果是 long 类型数值,则取右侧操作数最右端 6 位数值进行移动 左移运算符:数值位向左移动指定位数123456715 << 3 = 0x0000000f << 3 = 0x00000078(补,原) = 12015 << -61 = 0x0000000f << 0xffffffc3(左侧是 int 类型,取右侧 5 位) = 0x0000000f << 3 = 0x00000078(补,原) = 12015 << 35 = 0x0000000f << 0x00000023(左侧是 int 类型,取右侧 5 位) = 0x0000000f << 3 = 0x00000078(补,原) = 120-15 << 3 = 0xfffffff1 << 3 = 0xffffff88(补) = 0x80000078(原) = -120-15 << -61 = 0xfffffff1 << 0xffffffc3(左侧是 int 类型,取右侧 5 位) = 0xfffffff1 << 3 = 0xffffff88(补) = 0x80000078(原) = -120-15 << 35 = 0xfffffff1 << 0x00000023(左侧是 int 类型,取右侧 5 位) = 0xfffffff1 << 3 = 0xffffff88(补) = 0x80000078(原) = -120 右移运算符:数字位向右移动指定位数(如果左操作数是正数,高位补 0 ;如果是负数,高位补 1)1215 >> 3 = 0x0000000f >> 3 = 0x00000001 = 1-15 >> 3 = 0xfffffff1 >> 3 = 0xfffffffe(补) = 0x80000002(原) = -2 无符号右移运算符:功能和右移运算符一样,不过无论正负,高位均补 01215 >>> 3 = 0x0000000f >>> 3 = 0x00000001 = 1-15 >> 3 = 0xfffffff1 >>> 3 = 0x1ffffffe(补,原) = 2^29 - 2 = 536870910 Note 1:移位运算时,从符号位开始操作 Note 2:由结果可知,左移一位相当于乘以2,右移一位相当于除以 2 参考文章:参考链接1参考链接2","link":"/java/basic/%E5%8E%9F%E7%A0%81%E8%A1%A5%E7%A0%81%E5%BC%82%E6%88%96%E4%B8%8E%E4%BD%8D%E8%BF%90%E7%AE%97%E7%A7%BB%E4%BD%8D%E7%9F%A5%E8%AF%86%E7%82%B9.html"},{"title":"中华人民共和国国旗法","text":"基本信息 发文字号:主席令第18号 效力级别:法律 时效性:现行有效 发布日期:2009-08-27 实施日期:2009-08-27 发布机关:全国人大常委会 法律修订 1990年6月28日第七届全国人民代表大会常务委员会第十四次会议通过 1990年6月28日中华人民共和国主席令第28号公布 自1990年10月1日起施行 根据2009年8月27日第十一届全国人民代表大会常务委员会第十次会议通过的《全国人民代表大会常务委员会关于修改部分法律的决定》修正 中华人民共和国国旗法(1990修正) 正文 第一条 为了维护国旗的尊严,增强公民的国家观念,发扬爱国主义精神,根据宪法,制定本法。 第二条 中华人民共和国国旗是五星红旗。 中华人民共和国国旗按照中国人民政治协商会议第一届全体会议主席团公布的国旗制法说明制作。 第三条 中华人民共和国国旗是中华人民共和国的象征和标志。 每个公民和组织,都应当尊重和爱护国旗。 第四条 地方各级人民政府对本行政区域内国旗的升挂和使用,实施监督管理。 外交部、国务院交通主管部门、中国人民解放军总政治部对各自管辖范围内国旗的升挂和使用,实施监督管理。 国旗由省、自治区、直辖市的人民政府指定的企业制作。 第五条 下列场所或者机构所在地,应当每日升挂国旗: (一)北京天安门广场、新华门; (二)全国人民代表大会常务委员会,国务院,中央军事委员会,最高人民法院,最高人民检察院; 中国人民政治协商会议全国委员会; (三)外交部; (四)出境入境的机场、港口、火车站和其他边境口岸,边防海防哨所。 第六条 国务院各部门,地方各级人民代表大会常务委员会、人民政府、人民法院、人民检察院,中国人民政治协商会议地方各级委员会,应当在工作日升挂国旗。 全日制学校,除寒假、暑假和星期日外,应当每日升挂国旗。 第七条 国庆节、国际劳动节、元旦和春节,各级国家机关和各人民团体应当升挂国旗;企业事业组织,村民委员会、居民委员会,城镇居民院(楼)以及广场、公园等公共活动场所,有条件的可以升挂国旗。 不以春节为传统节日的少数民族地区,春节是否升挂国旗,由民族自治地方的自治机关规定。 民族自治地方在民族自治地方成立纪念日和主要传统民族节日,可以升挂国旗。 第八条 举行重大庆祝、纪念活动,大型文化、体育活动,大型展览会,可以升挂国旗。 第九条 外交活动以及国家驻外使馆领馆和其他外交代表机构升挂、使用国旗的办法,由外交部规定。 第十条 军事机关、军队营区、军用舰船,按照中央军事委员会的有关规定升挂国旗。 第十一条 民用船舶和进入中国领水的外国船舶升挂国旗的办法,由国务院交通主管部门规定。 公安部门执行边防、治安、消防任务的船舶升挂国旗的办法,由国务院公安部门规定。 第十二条 依照本法第五条、第六条、第七条的规定升挂国旗的,应当早晨升起,傍晚降下。 依照本法规定应当升挂国旗的,遇有恶劣天气,可以不升挂。 第十三条 升挂国旗时,可以举行升旗仪式。 举行升旗仪式时,在国旗升起的过程中,参加者应当面向国旗肃立致敬,并可以奏国歌或者唱国歌。 全日制中学小学,除假期外,每周举行一次升旗仪式。 第十四条 下列人士逝世,下半旗志哀: (一)中华人民共和国主席、全国人民代表大会常务委员会委员长、国务院总理、中央军事委员会主席; (二)中国人民政治协商会议全国委员会主席; (三)对中华人民共和国作出杰出贡献的人; (四)对世界和平或者人类进步事业作出杰出贡献的人。 发生特别重大伤亡的不幸事件或者严重自然灾害造成重大伤亡时,可以下半旗志哀。 依照本条第一款(三)、(四)项和第二款的规定下半旗,由国务院决定。 依照本条规定下半旗的日期和场所,由国家成立的治丧机构或者国务院决定。 第十五条 升挂国旗,应当将国旗置于显著的位置。 列队举持国旗和其他旗帜行进时,国旗应当在其他旗帜之前。 国旗与其他旗帜同时升挂时,应当将国旗置于中心、较高或者突出的位置。 在外事活动中同时升挂两个以上国家的国旗时,应当按照外交部的规定或者国际惯例升挂。 第十六条 在直立的旗杆上升降国旗,应当徐徐升降。升起时,必须将国旗升至杆顶;降下时,不得使国旗落地。 下半旗时,应当先将国旗升至杆顶,然后降至旗顶与杆顶之间的距离为旗杆全长的三分之一处;降下时,应当先将国旗升至杆顶,然后再降下。 第十七条 不得升挂破损、污损、褪色或者不合规格的国旗。 第十八条 国旗及其图案不得用作商标和广告,不得用于私人丧事活动。 第十九条 在公共场合故意以焚烧、毁损、涂划、玷污、践踏等方式侮辱中华人民共和国国旗的,依法追究刑事责任;情节较轻的,由公安机关处以十五日以下拘留。 第二十条 本法自1990年10月1日起施行。","link":"/law/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%9B%BD%E6%97%97%E6%B3%95.html"},{"title":"中华人民共和国宪法","text":"基本信息 发文字号:全国人民代表大会公告第1号 效力级别:法律 时效性:现行有效 发布日期:2018-03-11 实施日期:2018-03-11 发布机关:全国人民代表大会 法律修订 1982年12月4日第五届全国人民代表大会第五次会议通过 1982年12月4日全国人民代表大会公告公布施行 根据1988年4月12日第七届全国人民代表大会第一次会议通过的《中华人民共和国宪法修正案》、1993年3月29日第八届全国人民代表大会第一次会议通过的《中华人民共和国宪法修正案》、1999年3月15日第九届全国人民代表大会第二次会议通过的《中华人民共和国宪法修正案》、2004年3月14日第十届全国人民代表大会第二次会议通过的《中华人民共和国宪法修正案》和2018年3月11日第十三届全国人民代表大会第一次会议通过的《中华人民共和国宪法修正案》修正 中华人民共和国宪法(2004修正) 中华人民共和国宪法(1999修正) 中华人民共和国宪法(1993修正) 中华人民共和国宪法(1982修正) 中华人民共和国宪法(1978修正) 中华人民共和国宪法(1975修正) 中华人民共和国宪法(1954修正) 正文 序 言中国是世界上历史最悠久的国家之一。中国各族人民共同创造了光辉灿烂的文化,具有光荣的革命传统。一八四〇年以后,封建的中国逐渐变成半殖民地、半封建的国家。中国人民为国家独立、民族解放和民主自由进行了前仆后继的英勇奋斗。二十世纪,中国发生了翻天覆地的伟大历史变革。一九一一年孙中山先生领导的辛亥革命,废除了封建帝制,创立了中华民国。但是,中国人民反对帝国主义和封建主义的历史任务还没有完成。一九四九年,以毛泽东主席为领袖的中国共产党领导中国各族人民,在经历了长期的艰难曲折的武装斗争和其他形式的斗争以后,终于推翻了帝国主义、封建主义和官僚资本主义的统治,取得了新民主主义革命的伟大胜利,建立了中华人民共和国。从此,中国人民掌握了国家的权力,成为国家的主人。中华人民共和国成立以后,我国社会逐步实现了由新民主主义到社会主义的过渡。生产资料私有制的社会主义改造已经完成,人剥削人的制度已经消灭,社会主义制度已经确立。工人阶级领导的、以工农联盟为基础的人民民主专政,实质上即无产阶级专政,得到巩固和发展。中国人民和中国人民解放军战胜了帝国主义、霸权主义的侵略、破坏和武装挑衅,维护了国家的独立和安全,增强了国防。经济建设取得了重大的成就,独立的、比较完整的社会主义工业体系已经基本形成,农业生产显著提高。教育、科学、文化等事业有了很大的发展,社会主义思想教育取得了明显的成效。广大人民的生活有了较大的改善。中国新民主主义革命的胜利和社会主义事业的成就,是中国共产党领导中国各族人民,在马克思列宁主义、毛泽东思想的指引下,坚持真理,修正错误,战胜许多艰难险阻而取得的。我国将长期处于社会主义初级阶段。国家的根本任务是,沿着中国特色社会主义道路,集中力量进行社会主义现代化建设。中国各族人民将继续在中国共产党领导下,在马克思列宁主义、毛泽东思想、邓小平理论、“三个代表”重要思想、科学发展观、习近平新时代中国特色社会主义思想指引下,坚持人民民主专政,坚持社会主义道路,坚持改革开放,不断完善社会主义的各项制度,发展社会主义市场经济,发展社会主义民主,健全社会主义法治,贯彻新发展理念,自力更生,艰苦奋斗,逐步实现工业、农业、国防和科学技术的现代化,推动物质文明、政治文明、精神文明、社会文明、生态文明协调发展,把我国建设成为富强民主文明和谐美丽的社会主义现代化强国,实现中华民族伟大复兴。在我国,剥削阶级作为阶级已经消灭,但是阶级斗争还将在一定范围内长期存在。中国人民对敌视和破坏我国社会主义制度的国内外的敌对势力和敌对分子,必须进行斗争。台湾是中华人民共和国的神圣领土的一部分。完成统一祖国的大业是包括台湾同胞在内的全中国人民的神圣职责。社会主义的建设事业必须依靠工人、农民和知识分子,团结一切可以团结的力量。在长期的革命、建设、改革过程中,已经结成由中国共产党领导的,有各民主党派和各人民团体参加的,包括全体社会主义劳动者、社会主义事业的建设者、拥护社会主义的爱国者、拥护祖国统一和致力于中华民族伟大复兴的爱国者的广泛的爱国统一战线,这个统一战线将继续巩固和发展。中国人民政治协商会议是有广泛代表性的统一战线组织,过去发挥了重要的历史作用,今后在国家政治生活、社会生活和对外友好活动中,在进行社会主义现代化建设、维护国家的统一和团结的斗争中,将进一步发挥它的重要作用。中国共产党领导的多党合作和政治协商制度将长期存在和发展。中华人民共和国是全国各族人民共同缔造的统一的多民族国家。平等团结互助和谐的社会主义民族关系已经确立,并将继续加强。在维护民族团结的斗争中,要反对大民族主义,主要是大汉族主义,也要反对地方民族主义。国家尽一切努力,促进全国各民族的共同繁荣。中国革命、建设、改革的成就是同世界人民的支持分不开的。中国的前途是同世界的前途紧密地联系在一起的。中国坚持独立自主的对外政策,坚持互相尊重主权和领土完整、互不侵犯、互不干涉内政、平等互利、和平共处的五项原则,坚持和平发展道路,坚持互利共赢开放战略,发展同各国的外交关系和经济、文化交流,推动构建人类命运共同体;坚持反对帝国主义、霸权主义、殖民主义,加强同世界各国人民的团结,支持被压迫民族和发展中国家争取和维护民族独立、发展民族经济的正义斗争,为维护世界和平和促进人类进步事业而努力。本宪法以法律的形式确认了中国各族人民奋斗的成果,规定了国家的根本制度和根本任务,是国家的根本法,具有最高的法律效力。全国各族人民、一切国家机关和武装力量、各政党和各社会团体、各企业事业组织,都必须以宪法为根本的活动准则,并且负有维护宪法尊严、保证宪法实施的职责。 第一章 总 纲第一条 中华人民共和国是工人阶级领导的、以工农联盟为基础的人民民主专政的社会主义国家。 社会主义制度是中华人民共和国的根本制度。中国共产党领导是中国特色社会主义最本质的特征。禁止任何组织或者个人破坏社会主义制度。 第二条 中华人民共和国的一切权力属于人民。 人民行使国家权力的机关是全国人民代表大会和地方各级人民代表大会。 人民依照法律规定,通过各种途径和形式,管理国家事务,管理经济和文化事业,管理社会事务。 第三条 中华人民共和国的国家机构实行民主集中制的原则。 全国人民代表大会和地方各级人民代表大会都由民主选举产生,对人民负责,受人民监督。 国家行政机关、监察机关、审判机关、检察机关都由人民代表大会产生,对它负责,受它监督。 中央和地方的国家机构职权的划分,遵循在中央的统一领导下,充分发挥地方的主动性、积极性的原则。 第四条 中华人民共和国各民族一律平等。国家保障各少数民族的合法的权利和利益,维护和发展各民族的平等团结互助和谐关系。禁止对任何民族的歧视和压迫,禁止破坏民族团结和制造民族分裂的行为。 国家根据各少数民族的特点和需要,帮助各少数民族地区加速经济和文化的发展。 各少数民族聚居的地方实行区域自治,设立自治机关,行使自治权。各民族自治地方都是中华人民共和国不可分离的部分。 各民族都有使用和发展自己的语言文字的自由,都有保持或者改革自己的风俗习惯的自由。 第五条 中华人民共和国实行依法治国,建设社会主义法治国家。 国家维护社会主义法制的统一和尊严。 一切法律、行政法规和地方性法规都不得同宪法相抵触。 一切国家机关和武装力量、各政党和各社会团体、各企业事业组织都必须遵守宪法和法律。一切违反宪法和法律的行为,必须予以追究。 任何组织或者个人都不得有超越宪法和法律的特权。 第六条 中华人民共和国的社会主义经济制度的基础是生产资料的社会主义公有制,即全民所有制和劳动群众集体所有制。社会主义公有制消灭人剥削人的制度,实行各尽所能、按劳分配的原则。 国家在社会主义初级阶段,坚持公有制为主体、多种所有制经济共同发展的基本经济制度,坚持按劳分配为主体、多种分配方式并存的分配制度。 第七条 国有经济,即社会主义全民所有制经济,是国民经济中的主导力量。国家保障国有经济的巩固和发展。 第八条 农村集体经济组织实行家庭承包经营为基础、统分结合的双层经营体制。农村中的生产、供销、信用、消费等各种形式的合作经济,是社会主义劳动群众集体所有制经济。参加农村集体经济组织的劳动者,有权在法律规定的范围内经营自留地、自留山、家庭副业和饲养自留畜。 城镇中的手工业、工业、建筑业、运输业、商业、服务业等行业的各种形式的合作经济,都是社会主义劳动群众集体所有制经济。 国家保护城乡集体经济组织的合法的权利和利益,鼓励、指导和帮助集体经济的发展。 第九条 矿藏、水流、森林、山岭、草原、荒地、滩涂等自然资源,都属于国家所有,即全民所有;由法律规定属于集体所有的森林和山岭、草原、荒地、滩涂除外。 国家保障自然资源的合理利用,保护珍贵的动物和植物。禁止任何组织或者个人用任何手段侵占或者破坏自然资源。 第十条 城市的土地属于国家所有。 农村和城市郊区的土地,除由法律规定属于国家所有的以外,属于集体所有;宅基地和自留地、自留山,也属于集体所有。 国家为了公共利益的需要,可以依照法律规定对土地实行征收或者征用并给予补偿。 任何组织或者个人不得侵占、买卖或者以其他形式非法转让土地。土地的使用权可以依照法律的规定转让。 一切使用土地的组织和个人必须合理地利用土地。 第十一条 在法律规定范围内的个体经济、私营经济等非公有制经济,是社会主义市场经济的重要组成部分。 国家保护个体经济、私营经济等非公有制经济的合法的权利和利益。国家鼓励、支持和引导非公有制经济的发展,并对非公有制经济依法实行监督和管理。 第十二条 社会主义的公共财产神圣不可侵犯。 国家保护社会主义的公共财产。禁止任何组织或者个人用任何手段侵占或者破坏国家的和集体的财产。 第十三条 公民的合法的私有财产不受侵犯。 国家依照法律规定保护公民的私有财产权和继承权。 国家为了公共利益的需要,可以依照法律规定对公民的私有财产实行征收或者征用并给予补偿。 第十四条 国家通过提高劳动者的积极性和技术水平,推广先进的科学技术,完善经济管理体制和企业经营管理制度,实行各种形式的社会主义责任制,改进劳动组织,以不断提高劳动生产率和经济效益,发展社会生产力。 国家厉行节约,反对浪费。 国家合理安排积累和消费,兼顾国家、集体和个人的利益,在发展生产的基础上,逐步改善人民的物质生活和文化生活。 国家建立健全同经济发展水平相适应的社会保障制度。 第十五条 国家实行社会主义市场经济。 国家加强经济立法,完善宏观调控。 国家依法禁止任何组织或者个人扰乱社会经济秩序。 第十六条 国有企业在法律规定的范围内有权自主经营。 国有企业依照法律规定,通过职工代表大会和其他形式,实行民主管理。 第十七条 集体经济组织在遵守有关法律的前提下,有独立进行经济活动的自主权。 集体经济组织实行民主管理,依照法律规定选举和罢免管理人员,决定经营管理的重大问题。 第十八条 中华人民共和国允许外国的企业和其他经济组织或者个人依照中华人民共和国法律的规定在中国投资,同中国的企业或者其他经济组织进行各种形式的经济合作。 在中国境内的外国企业和其他外国经济组织以及中外合资经营的企业,都必须遵守中华人民共和国的法律。它们的合法的权利和利益受中华人民共和国法律的保护。 第十九条 国家发展社会主义的教育事业,提高全国人民的科学文化水平。 国家举办各种学校,普及初等义务教育,发展中等教育、职业教育和高等教育,并且发展学前教育。 国家发展各种教育设施,扫除文盲,对工人、农民、国家工作人员和其他劳动者进行政治、文化、科学、技术、业务的教育,鼓励自学成才。 国家鼓励集体经济组织、国家企业事业组织和其他社会力量依照法律规定举办各种教育事业。 国家推广全国通用的普通话。 第二十条 国家发展自然科学和社会科学事业,普及科学和技术知识,奖励科学研究成果和技术发明创造。 第二十一条 国家发展医疗卫生事业,发展现代医药和我国传统医药,鼓励和支持农村集体经济组织、国家企业事业组织和街道组织举办各种医疗卫生设施,开展群众性的卫生活动,保护人民健康。 国家发展体育事业,开展群众性的体育活动,增强人民体质。 第二十二条 国家发展为人民服务、为社会主义服务的文学艺术事业、新闻广播电视事业、出版发行事业、图书馆博物馆文化馆和其他文化事业,开展群众性的文化活动。 国家保护名胜古迹、珍贵文物和其他重要历史文化遗产。 第二十三条 国家培养为社会主义服务的各种专业人才,扩大知识分子的队伍,创造条件,充分发挥他们在社会主义现代化建设中的作用。 第二十四条 国家通过普及理想教育、道德教育、文化教育、纪律和法制教育,通过在城乡不同范围的群众中制定和执行各种守则、公约,加强社会主义精神文明的建设。 国家倡导社会主义核心价值观,提倡爱祖国、爱人民、爱劳动、爱科学、爱社会主义的公德,在人民中进行爱国主义、集体主义和国际主义、共产主义的教育,进行辩证唯物主义和历史唯物主义的教育,反对资本主义的、封建主义的和其他的腐朽思想。 第二十五条 国家推行计划生育,使人口的增长同经济和社会发展计划相适应。 第二十六条 国家保护和改善生活环境和生态环境,防治污染和其他公害。 国家组织和鼓励植树造林,保护林木。 第二十七条 一切国家机关实行精简的原则,实行工作责任制,实行工作人员的培训和考核制度,不断提高工作质量和工作效率,反对官僚主义。 一切国家机关和国家工作人员必须依靠人民的支持,经常保持同人民的密切联系,倾听人民的意见和建议,接受人民的监督,努力为人民服务。 国家工作人员就职时应当依照法律规定公开进行宪法宣誓。 第二十八条 国家维护社会秩序,镇压叛国和其他危害国家安全的犯罪活动,制裁危害社会治安、破坏社会主义经济和其他犯罪的活动,惩办和改造犯罪分子。 第二十九条 中华人民共和国的武装力量属于人民。它的任务是巩固国防,抵抗侵略,保卫祖国,保卫人民的和平劳动,参加国家建设事业,努力为人民服务。 国家加强武装力量的革命化、现代化、正规化的建设,增强国防力量。 第三十条 中华人民共和国的行政区域划分如下: (一)全国分为省、自治区、直辖市; (二)省、自治区分为自治州、县、自治县、市; (三)县、自治县分为乡、民族乡、镇。 直辖市和较大的市分为区、县。自治州分为县、自治县、市。 自治区、自治州、自治县都是民族自治地方。 第三十一条 国家在必要时得设立特别行政区。在特别行政区内实行的制度按照具体情况由全国人民代表大会以法律规定。 第三十二条 中华人民共和国保护在中国境内的外国人的合法权利和利益,在中国境内的外国人必须遵守中华人民共和国的法律。 中华人民共和国对于因为政治原因要求避难的外国人,可以给予受庇护的权利。 第二章 公民的基本权利和义务第三十三条 凡具有中华人民共和国国籍的人都是中华人民共和国公民。 中华人民共和国公民在法律面前一律平等。 国家尊重和保障人权。 任何公民享有宪法和法律规定的权利,同时必须履行宪法和法律规定的义务。 第三十四条 中华人民共和国年满十八周岁的公民,不分民族、种族、性别、职业、家庭出身、宗教信仰、教育程度、财产状况、居住期限,都有选举权和被选举权;但是依照法律被剥夺政治权利的人除外。 第三十五条 中华人民共和国公民有言论、出版、集会、结社、游行、示威的自由。 第三十六条 中华人民共和国公民有宗教信仰自由。 任何国家机关、社会团体和个人不得强制公民信仰宗教或者不信仰宗教,不得歧视信仰宗教的公民和不信仰宗教的公民。 国家保护正常的宗教活动。任何人不得利用宗教进行破坏社会秩序、损害公民身体健康、妨碍国家教育制度的活动。 宗教团体和宗教事务不受外国势力的支配。 第三十七条 中华人民共和国公民的人身自由不受侵犯。 任何公民,非经人民检察院批准或者决定或者人民法院决定,并由公安机关执行,不受逮捕。 禁止非法拘禁和以其他方法非法剥夺或者限制公民的人身自由,禁止非法搜查公民的身体。 第三十八条 中华人民共和国公民的人格尊严不受侵犯。禁止用任何方法对公民进行侮辱、诽谤和诬告陷害。 第三十九条 中华人民共和国公民的住宅不受侵犯。禁止非法搜查或者非法侵入公民的住宅。 第四十条 中华人民共和国公民的通信自由和通信秘密受法律的保护。除因国家安全或者追查刑事犯罪的需要,由公安机关或者检察机关依照法律规定的程序对通信进行检查外,任何组织或者个人不得以任何理由侵犯公民的通信自由和通信秘密。 第四十一条 中华人民共和国公民对于任何国家机关和国家工作人员,有提出批评和建议的权利;对于任何国家机关和国家工作人员的违法失职行为,有向有关国家机关提出申诉、控告或者检举的权利,但是不得捏造或者歪曲事实进行诬告陷害。 对于公民的申诉、控告或者检举,有关国家机关必须查清事实,负责处理。任何人不得压制和打击报复。 由于国家机关和国家工作人员侵犯公民权利而受到损失的人,有依照法律规定取得赔偿的权利。 第四十二条 中华人民共和国公民有劳动的权利和义务。 国家通过各种途径,创造劳动就业条件,加强劳动保护,改善劳动条件,并在发展生产的基础上,提高劳动报酬和福利待遇。 劳动是一切有劳动能力的公民的光荣职责。国有企业和城乡集体经济组织的劳动者都应当以国家主人翁的态度对待自己的劳动。国家提倡社会主义劳动竞赛,奖励劳动模范和先进工作者。国家提倡公民从事义务劳动。 国家对就业前的公民进行必要的劳动就业训练。 第四十三条 中华人民共和国劳动者有休息的权利。 国家发展劳动者休息和休养的设施,规定职工的工作时间和休假制度。 第四十四条 国家依照法律规定实行企业事业组织的职工和国家机关工作人员的退休制度。退休人员的生活受到国家和社会的保障。 第四十五条 中华人民共和国公民在年老、疾病或者丧失劳动能力的情况下,有从国家和社会获得物质帮助的权利。国家发展为公民享受这些权利所需要的社会保险、社会救济和医疗卫生事业。 国家和社会保障残废军人的生活,抚恤烈士家属,优待军人家属。 国家和社会帮助安排盲、聋、哑和其他有残疾的公民的劳动、生活和教育。 第四十六条 中华人民共和国公民有受教育的权利和义务。 国家培养青年、少年、儿童在品德、智力、体质等方面全面发展。 第四十七条 中华人民共和国公民有进行科学研究、文学艺术创作和其他文化活动的自由。国家对于从事教育、科学、技术、文学、艺术和其他文化事业的公民的有益于人民的创造性工作,给以鼓励和帮助。 第四十八条 中华人民共和国妇女在政治的、经济的、文化的、社会的和家庭的生活等各方面享有同男子平等的权利。 国家保护妇女的权利和利益,实行男女同工同酬,培养和选拔妇女干部。 第四十九条 婚姻、家庭、母亲和儿童受国家的保护。 夫妻双方有实行计划生育的义务。 父母有抚养教育未成年子女的义务,成年子女有赡养扶助父母的义务。 禁止破坏婚姻自由,禁止虐待老人、妇女和儿童。 第五十条 中华人民共和国保护华侨的正当的权利和利益,保护归侨和侨眷的合法的权利和利益。 第五十一条 中华人民共和国公民在行使自由和权利的时候,不得损害国家的、社会的、集体的利益和其他公民的合法的自由和权利。 第五十二条 中华人民共和国公民有维护国家统一和全国各民族团结的义务。 第五十三条 中华人民共和国公民必须遵守宪法和法律,保守国家秘密,爱护公共财产,遵守劳动纪律,遵守公共秩序,尊重社会公德。 第五十四条 中华人民共和国公民有维护祖国的安全、荣誉和利益的义务,不得有危害祖国的安全、荣誉和利益的行为。 第五十五条 保卫祖国、抵抗侵略是中华人民共和国每一个公民的神圣职责。 依照法律服兵役和参加民兵组织是中华人民共和国公民的光荣义务。 第五十六条 中华人民共和国公民有依照法律纳税的义务。 第三章 国家机构第五十七条 中华人民共和国全国人民代表大会是最高国家权力机关。它的常设机关是全国人民代表大会常务委员会。 第五十八条 全国人民代表大会和全国人民代表大会常务委员会行使国家立法权。 第五十九条 全国人民代表大会由省、自治区、直辖市、特别行政区和军队选出的代表组成。各少数民族都应当有适当名额的代表。 全国人民代表大会代表的选举由全国人民代表大会常务委员会主持。 全国人民代表大会代表名额和代表产生办法由法律规定。 第六十条 全国人民代表大会每届任期五年。 全国人民代表大会任期届满的两个月以前,全国人民代表大会常务委员会必须完成下届全国人民代表大会代表的选举。如果遇到不能进行选举的非常情况,由全国人民代表大会常务委员会以全体组成人员的三分之二以上的多数通过,可以推迟选举,延长本届全国人民代表大会的任期。在非常情况结束后一年内,必须完成下届全国人民代表大会代表的选举。 第六十一条 全国人民代表大会会议每年举行一次,由全国人民代表大会常务委员会召集。如果全国人民代表大会常务委员会认为必要,或者有五分之一以上的全国人民代表大会代表提议,可以临时召集全国人民代表大会会议。 全国人民代表大会举行会议的时候,选举主席团主持会议。 第六十二条 全国人民代表大会行使下列职权: (一)修改宪法; (二)监督宪法的实施; (三)制定和修改刑事、民事、国家机构的和其他的基本法律; (四)选举中华人民共和国主席、副主席; (五)根据中华人民共和国主席的提名,决定国务院总理的人选;根据国务院总理的提名,决定国务院副总理、国务委员、各部部长、各委员会主任、审计长、秘书长的人选; (六)选举中央军事委员会主席;根据中央军事委员会主席的提名,决定中央军事委员会其他组成人员的人选; (七)选举国家监察委员会主任; (八)选举最高人民法院院长; (九)选举最高人民检察院检察长; (十)审查和批准国民经济和社会发展计划和计划执行情况的报告; (十一)审查和批准国家的预算和预算执行情况的报告; (十二)改变或者撤销全国人民代表大会常务委员会不适当的决定; (十三)批准省、自治区和直辖市的建置; (十四)决定特别行政区的设立及其制度; (十五)决定战争和和平的问题; (十六)应当由最高国家权力机关行使的其他职权。 第六十三条 全国人民代表大会有权罢免下列人员: (一)中华人民共和国主席、副主席; (二)国务院总理、副总理、国务委员、各部部长、各委员会主任、审计长、秘书长; (三)中央军事委员会主席和中央军事委员会其他组成人员; (四)国家监察委员会主任; (五)最高人民法院院长; (六)最高人民检察院检察长。 第六十四条 宪法的修改,由全国人民代表大会常务委员会或者五分之一以上的全国人民代表大会代表提议,并由全国人民代表大会以全体代表的三分之二以上的多数通过。 法律和其他议案由全国人民代表大会以全体代表的过半数通过。 第六十五条 全国人民代表大会常务委员会由下列人员组成: 委员长, 副委员长若干人, 秘书长, 委员若干人。 全国人民代表大会常务委员会组成人员中,应当有适当名额的少数民族代表。 全国人民代表大会选举并有权罢免全国人民代表大会常务委员会的组成人员。 全国人民代表大会常务委员会的组成人员不得担任国家行政机关、监察机关、审判机关和检察机关的职务。 第六十六条 全国人民代表大会常务委员会每届任期同全国人民代表大会每届任期相同,它行使职权到下届全国人民代表大会选出新的常务委员会为止。 委员长、副委员长连续任职不得超过两届。 第六十七条 全国人民代表大会常务委员会行使下列职权: (一)解释宪法,监督宪法的实施; (二)制定和修改除应当由全国人民代表大会制定的法律以外的其他法律; (三)在全国人民代表大会闭会期间,对全国人民代表大会制定的法律进行部分补充和修改,但是不得同该法律的基本原则相抵触; (四)解释法律; (五)在全国人民代表大会闭会期间,审查和批准国民经济和社会发展计划、国家预算在执行过程中所必须作的部分调整方案; (六)监督国务院、中央军事委员会、国家监察委员会、最高人民法院和最高人民检察院的工作; (七)撤销国务院制定的同宪法、法律相抵触的行政法规、决定和命令; (八)撤销省、自治区、直辖市国家权力机关制定的同宪法、法律和行政法规相抵触的地方性法规和决议; (九)在全国人民代表大会闭会期间,根据国务院总理的提名,决定部长、委员会主任、审计长、秘书长的人选; (十)在全国人民代表大会闭会期间,根据中央军事委员会主席的提名,决定中央军事委员会其他组成人员的人选; (十一)根据国家监察委员会主任的提请,任免国家监察委员会副主任、委员; (十二)根据最高人民法院院长的提请,任免最高人民法院副院长、审判员、审判委员会委员和军事法院院长; (十三)根据最高人民检察院检察长的提请,任免最高人民检察院副检察长、检察员、检察委员会委员和军事检察院检察长,并且批准省、自治区、直辖市的人民检察院检察长的任免; (十四)决定驻外全权代表的任免; (十五)决定同外国缔结的条约和重要协定的批准和废除; (十六)规定军人和外交人员的衔级制度和其他专门衔级制度; (十七)规定和决定授予国家的勋章和荣誉称号; (十八)决定特赦; (十九)在全国人民代表大会闭会期间,如果遇到国家遭受武装侵犯或者必须履行国际间共同防止侵略的条约的情况,决定战争状态的宣布; (二十)决定全国总动员或者局部动员; (二十一)决定全国或者个别省、自治区、直辖市进入紧急状态; (二十二)全国人民代表大会授予的其他职权。 第六十八条 全国人民代表大会常务委员会委员长主持全国人民代表大会常务委员会的工作,召集全国人民代表大会常务委员会会议。副委员长、秘书长协助委员长工作。 委员长、副委员长、秘书长组成委员长会议,处理全国人民代表大会常务委员会的重要日常工作。 第六十九条 全国人民代表大会常务委员会对全国人民代表大会负责并报告工作。 第七十条 全国人民代表大会设立民族委员会、宪法和法律委员会、财政经济委员会、教育科学文化卫生委员会、外事委员会、华侨委员会和其他需要设立的专门委员会。在全国人民代表大会闭会期间,各专门委员会受全国人民代表大会常务委员会的领导。 各专门委员会在全国人民代表大会和全国人民代表大会常务委员会领导下,研究、审议和拟订有关议案。 第七十一条 全国人民代表大会和全国人民代表大会常务委员会认为必要的时候,可以组织关于特定问题的调查委员会,并且根据调查委员会的报告,作出相应的决议。 调查委员会进行调查的时候,一切有关的国家机关、社会团体和公民都有义务向它提供必要的材料。 第七十二条 全国人民代表大会代表和全国人民代表大会常务委员会组成人员,有权依照法律规定的程序分别提出属于全国人民代表大会和全国人民代表大会常务委员会职权范围内的议案。 第七十三条 全国人民代表大会代表在全国人民代表大会开会期间,全国人民代表大会常务委员会组成人员在常务委员会开会期间,有权依照法律规定的程序提出对国务院或者国务院各部、各委员会的质询案。受质询的机关必须负责答复。 第七十四条 全国人民代表大会代表,非经全国人民代表大会会议主席团许可,在全国人民代表大会闭会期间非经全国人民代表大会常务委员会许可,不受逮捕或者刑事审判。 第七十五条 全国人民代表大会代表在全国人民代表大会各种会议上的发言和表决,不受法律追究。 第七十六条 全国人民代表大会代表必须模范地遵守宪法和法律,保守国家秘密,并且在自己参加的生产、工作和社会活动中,协助宪法和法律的实施。 全国人民代表大会代表应当同原选举单位和人民保持密切的联系,听取和反映人民的意见和要求,努力为人民服务。 第七十七条 全国人民代表大会代表受原选举单位的监督。原选举单位有权依照法律规定的程序罢免本单位选出的代表。 第七十八条 全国人民代表大会和全国人民代表大会常务委员会的组织和工作程序由法律规定。 第七十九条 中华人民共和国主席、副主席由全国人民代表大会选举。 有选举权和被选举权的年满四十五周岁的中华人民共和国公民可以被选为中华人民共和国主席、副主席。 中华人民共和国主席、副主席每届任期同全国人民代表大会每届任期相同。 第八十条 中华人民共和国主席根据全国人民代表大会的决定和全国人民代表大会常务委员会的决定,公布法律,任免国务院总理、副总理、国务委员、各部部长、各委员会主任、审计长、秘书长,授予国家的勋章和荣誉称号,发布特赦令,宣布进入紧急状态,宣布战争状态,发布动员令。 第八十一条 中华人民共和国主席代表中华人民共和国,进行国事活动,接受外国使节;根据全国人民代表大会常务委员会的决定,派遣和召回驻外全权代表,批准和废除同外国缔结的条约和重要协定。 第八十二条 中华人民共和国副主席协助主席工作。 中华人民共和国副主席受主席的委托,可以代行主席的部分职权。 第八十三条 中华人民共和国主席、副主席行使职权到下届全国人民代表大会选出的主席、副主席就职为止。 第八十四条 中华人民共和国主席缺位的时候,由副主席继任主席的职位。 中华人民共和国副主席缺位的时候,由全国人民代表大会补选。 中华人民共和国主席、副主席都缺位的时候,由全国人民代表大会补选;在补选以前,由全国人民代表大会常务委员会委员长暂时代理主席职位。 第八十五条 中华人民共和国国务院,即中央人民政府,是最高国家权力机关的执行机关,是最高国家行政机关。 第八十六条 国务院由下列人员组成: 总理, 副总理若干人, 国务委员若干人, 各部部长, 各委员会主任, 审计长, 秘书长。 国务院实行总理负责制。各部、各委员会实行部长、主任负责制。 国务院的组织由法律规定。 第八十七条 国务院每届任期同全国人民代表大会每届任期相同。 总理、副总理、国务委员连续任职不得超过两届。 第八十八条 总理领导国务院的工作。副总理、国务委员协助总理工作。 总理、副总理、国务委员、秘书长组成国务院常务会议。 总理召集和主持国务院常务会议和国务院全体会议。 第八十九条 国务院行使下列职权: (一)根据宪法和法律,规定行政措施,制定行政法规,发布决定和命令; (二)向全国人民代表大会或者全国人民代表大会常务委员会提出议案; (三)规定各部和各委员会的任务和职责,统一领导各部和各委员会的工作,并且领导不属于各部和各委员会的全国性的行政工作; (四)统一领导全国地方各级国家行政机关的工作,规定中央和省、自治区、直辖市的国家行政机关的职权的具体划分; (五)编制和执行国民经济和社会发展计划和国家预算; (六)领导和管理经济工作和城乡建设、生态文明建设; (七)领导和管理教育、科学、文化、卫生、体育和计划生育工作; (八)领导和管理民政、公安、司法行政等工作; (九)管理对外事务,同外国缔结条约和协定; (十)领导和管理国防建设事业; (十一)领导和管理民族事务,保障少数民族的平等权利和民族自治地方的自治权利; (十二)保护华侨的正当的权利和利益,保护归侨和侨眷的合法的权利和利益; (十三)改变或者撤销各部、各委员会发布的不适当的命令、指示和规章; (十四)改变或者撤销地方各级国家行政机关的不适当的决定和命令; (十五)批准省、自治区、直辖市的区域划分,批准自治州、县、自治县、市的建置和区域划分; (十六)依照法律规定决定省、自治区、直辖市的范围内部分地区进入紧急状态; (十七)审定行政机构的编制,依照法律规定任免、培训、考核和奖惩行政人员; (十八)全国人民代表大会和全国人民代表大会常务委员会授予的其他职权。 第九十条 国务院各部部长、各委员会主任负责本部门的工作;召集和主持部务会议或者委员会会议、委务会议,讨论决定本部门工作的重大问题。 各部、各委员会根据法律和国务院的行政法规、决定、命令,在本部门的权限内,发布命令、指示和规章。 第九十一条 国务院设立审计机关,对国务院各部门和地方各级政府的财政收支,对国家的财政金融机构和企业事业组织的财务收支,进行审计监督。 审计机关在国务院总理领导下,依照法律规定独立行使审计监督权,不受其他行政机关、社会团体和个人的干涉。 第九十二条 国务院对全国人民代表大会负责并报告工作;在全国人民代表大会闭会期间,对全国人民代表大会常务委员会负责并报告工作。 第九十三条 中华人民共和国中央军事委员会领导全国武装力量。 中央军事委员会由下列人员组成: 主席, 副主席若干人, 委员若干人。 中央军事委员会实行主席负责制。 中央军事委员会每届任期同全国人民代表大会每届任期相同。 第九十四条 中央军事委员会主席对全国人民代表大会和全国人民代表大会常务委员会负责。 第九十五条 省、直辖市、县、市、市辖区、乡、民族乡、镇设立人民代表大会和人民政府。 地方各级人民代表大会和地方各级人民政府的组织由法律规定。 自治区、自治州、自治县设立自治机关。自治机关的组织和工作根据宪法第三章第五节、第六节规定的基本原则由法律规定。 第九十六条 地方各级人民代表大会是地方国家权力机关。 县级以上的地方各级人民代表大会设立常务委员会。 第九十七条 省、直辖市、设区的市的人民代表大会代表由下一级的人民代表大会选举;县、不设区的市、市辖区、乡、民族乡、镇的人民代表大会代表由选民直接选举。 地方各级人民代表大会代表名额和代表产生办法由法律规定。 第九十八条 地方各级人民代表大会每届任期五年。 第九十九条 地方各级人民代表大会在本行政区域内,保证宪法、法律、行政法规的遵守和执行;依照法律规定的权限,通过和发布决议,审查和决定地方的经济建设、文化建设和公共事业建设的计划。 县级以上的地方各级人民代表大会审查和批准本行政区域内的国民经济和社会发展计划、预算以及它们的执行情况的报告;有权改变或者撤销本级人民代表大会常务委员会不适当的决定。 民族乡的人民代表大会可以依照法律规定的权限采取适合民族特点的具体措施。 第一百条 省、直辖市的人民代表大会和它们的常务委员会,在不同宪法、法律、行政法规相抵触的前提下,可以制定地方性法规,报全国人民代表大会常务委员会备案。 设区的市的人民代表大会和它们的常务委员会,在不同宪法、法律、行政法规和本省、自治区的地方性法规相抵触的前提下,可以依照法律规定制定地方性法规,报本省、自治区人民代表大会常务委员会批准后施行。 第一百零一条 地方各级人民代表大会分别选举并且有权罢免本级人民政府的省长和副省长、市长和副市长、县长和副县长、区长和副区长、乡长和副乡长、镇长和副镇长。 县级以上的地方各级人民代表大会选举并且有权罢免本级监察委员会主任、本级人民法院院长和本级人民检察院检察长。选出或者罢免人民检察院检察长,须报上级人民检察院检察长提请该级人民代表大会常务委员会批准。 第一百零二条 省、直辖市、设区的市的人民代表大会代表受原选举单位的监督;县、不设区的市、市辖区、乡、民族乡、镇的人民代表大会代表受选民的监督。 地方各级人民代表大会代表的选举单位和选民有权依照法律规定的程序罢免由他们选出的代表。 第一百零三条 县级以上的地方各级人民代表大会常务委员会由主任、副主任若干人和委员若干人组成,对本级人民代表大会负责并报告工作。 县级以上的地方各级人民代表大会选举并有权罢免本级人民代表大会常务委员会的组成人员。 县级以上的地方各级人民代表大会常务委员会的组成人员不得担任国家行政机关、监察机关、审判机关和检察机关的职务。 第一百零四条 县级以上的地方各级人民代表大会常务委员会讨论、决定本行政区域内各方面工作的重大事项;监督本级人民政府、监察委员会、人民法院和人民检察院的工作;撤销本级人民政府的不适当的决定和命令;撤销下一级人民代表大会的不适当的决议;依照法律规定的权限决定国家机关工作人员的任免;在本级人民代表大会闭会期间,罢免和补选上一级人民代表大会的个别代表。 第一百零五条 地方各级人民政府是地方各级国家权力机关的执行机关,是地方各级国家行政机关。 地方各级人民政府实行省长、市长、县长、区长、乡长、镇长负责制。 第一百零六条 地方各级人民政府每届任期同本级人民代表大会每届任期相同。 第一百零七条 县级以上地方各级人民政府依照法律规定的权限,管理本行政区域内的经济、教育、科学、文化、卫生、体育事业、城乡建设事业和财政、民政、公安、民族事务、司法行政、计划生育等行政工作,发布决定和命令,任免、培训、考核和奖惩行政工作人员。 乡、民族乡、镇的人民政府执行本级人民代表大会的决议和上级国家行政机关的决定和命令,管理本行政区域内的行政工作。 省、直辖市的人民政府决定乡、民族乡、镇的建置和区域划分。 第一百零八条 县级以上的地方各级人民政府领导所属各工作部门和下级人民政府的工作,有权改变或者撤销所属各工作部门和下级人民政府的不适当的决定。 第一百零九条 县级以上的地方各级人民政府设立审计机关。地方各级审计机关依照法律规定独立行使审计监督权,对本级人民政府和上一级审计机关负责。 第一百一十条 地方各级人民政府对本级人民代表大会负责并报告工作。县级以上的地方各级人民政府在本级人民代表大会闭会期间,对本级人民代表大会常务委员会负责并报告工作。 地方各级人民政府对上一级国家行政机关负责并报告工作。全国地方各级人民政府都是国务院统一领导下的国家行政机关,都服从国务院。 第一百一十一条 城市和农村按居民居住地区设立的居民委员会或者村民委员会是基层群众性自治组织。居民委员会、村民委员会的主任、副主任和委员由居民选举。居民委员会、村民委员会同基层政权的相互关系由法律规定。 居民委员会、村民委员会设人民调解、治安保卫、公共卫生等委员会,办理本居住地区的公共事务和公益事业,调解民间纠纷,协助维护社会治安,并且向人民政府反映群众的意见、要求和提出建议。 第一百一十二条 民族自治地方的自治机关是自治区、自治州、自治县的人民代表大会和人民政府。 第一百一十三条 自治区、自治州、自治县的人民代表大会中,除实行区域自治的民族的代表外,其他居住在本行政区域内的民族也应当有适当名额的代表。 自治区、自治州、自治县的人民代表大会常务委员会中应当有实行区域自治的民族的公民担任主任或者副主任。 第一百一十四条 自治区主席、自治州州长、自治县县长由实行区域自治的民族的公民担任。 第一百一十五条 自治区、自治州、自治县的自治机关行使宪法第三章第五节规定的地方国家机关的职权,同时依照宪法、民族区域自治法和其他法律规定的权限行使自治权,根据本地方实际情况贯彻执行国家的法律、政策。 第一百一十六条 民族自治地方的人民代表大会有权依照当地民族的政治、经济和文化的特点,制定自治条例和单行条例。自治区的自治条例和单行条例,报全国人民代表大会常务委员会批准后生效。自治州、自治县的自治条例和单行条例,报省或者自治区的人民代表大会常务委员会批准后生效,并报全国人民代表大会常务委员会备案。 第一百一十七条 民族自治地方的自治机关有管理地方财政的自治权。凡是依照国家财政体制属于民族自治地方的财政收入,都应当由民族自治地方的自治机关自主地安排使用。 第一百一十八条 民族自治地方的自治机关在国家计划的指导下,自主地安排和管理地方性的经济建设事业。 国家在民族自治地方开发资源、建设企业的时候,应当照顾民族自治地方的利益。 第一百一十九条 民族自治地方的自治机关自主地管理本地方的教育、科学、文化、卫生、体育事业,保护和整理民族的文化遗产,发展和繁荣民族文化。 第一百二十条 民族自治地方的自治机关依照国家的军事制度和当地的实际需要,经国务院批准,可以组织本地方维护社会治安的公安部队。 第一百二十一条 民族自治地方的自治机关在执行职务的时候,依照本民族自治地方自治条例的规定,使用当地通用的一种或者几种语言文字。 第一百二十二条 国家从财政、物资、技术等方面帮助各少数民族加速发展经济建设和文化建设事业。 国家帮助民族自治地方从当地民族中大量培养各级干部、各种专业人才和技术工人。 第一百二十三条 中华人民共和国各级监察委员会是国家的监察机关。 第一百二十四条 中华人民共和国设立国家监察委员会和地方各级监察委员会。 监察委员会由下列人员组成: 主任, 副主任若干人, 委员若干人。 监察委员会主任每届任期同本级人民代表大会每届任期相同。国家监察委员会主任连续任职不得超过两届。 监察委员会的组织和职权由法律规定。 第一百二十五条 中华人民共和国国家监察委员会是最高监察机关。 国家监察委员会领导地方各级监察委员会的工作,上级监察委员会领导下级监察委员会的工作。 第一百二十六条 国家监察委员会对全国人民代表大会和全国人民代表大会常务委员会负责。地方各级监察委员会对产生它的国家权力机关和上一级监察委员会负责。 第一百二十七条 监察委员会依照法律规定独立行使监察权,不受行政机关、社会团体和个人的干涉。 监察机关办理职务违法和职务犯罪案件,应当与审判机关、检察机关、执法部门互相配合,互相制约。 第一百二十八条 中华人民共和国人民法院是国家的审判机关。 第一百二十九条 中华人民共和国设立最高人民法院、地方各级人民法院和军事法院等专门人民法院。 最高人民法院院长每届任期同全国人民代表大会每届任期相同,连续任职不得超过两届。 人民法院的组织由法律规定。 第一百三十条 人民法院审理案件,除法律规定的特别情况外,一律公开进行。被告人有权获得辩护。 第一百三十一条 人民法院依照法律规定独立行使审判权,不受行政机关、社会团体和个人的干涉。 第一百三十二条 最高人民法院是最高审判机关。 最高人民法院监督地方各级人民法院和专门人民法院的审判工作,上级人民法院监督下级人民法院的审判工作。 第一百三十三条 最高人民法院对全国人民代表大会和全国人民代表大会常务委员会负责。地方各级人民法院对产生它的国家权力机关负责。 第一百三十四条 中华人民共和国人民检察院是国家的法律监督机关。 第一百三十五条 中华人民共和国设立最高人民检察院、地方各级人民检察院和军事检察院等专门人民检察院。 最高人民检察院检察长每届任期同全国人民代表大会每届任期相同,连续任职不得超过两届。 人民检察院的组织由法律规定。 第一百三十六条 人民检察院依照法律规定独立行使检察权,不受行政机关、社会团体和个人的干涉。 第一百三十七条 最高人民检察院是最高检察机关。 最高人民检察院领导地方各级人民检察院和专门人民检察院的工作,上级人民检察院领导下级人民检察院的工作。 第一百三十八条 最高人民检察院对全国人民代表大会和全国人民代表大会常务委员会负责。地方各级人民检察院对产生它的国家权力机关和上级人民检察院负责。 第一百三十九条 各民族公民都有用本民族语言文字进行诉讼的权利。人民法院和人民检察院对于不通晓当地通用的语言文字的诉讼参与人,应当为他们翻译。 在少数民族聚居或者多民族共同居住的地区,应当用当地通用的语言进行审理;起诉书、判决书、布告和其他文书应当根据实际需要使用当地通用的一种或者几种文字。 第一百四十条 人民法院、人民检察院和公安机关办理刑事案件,应当分工负责,互相配合,互相制约,以保证准确有效地执行法律。 第四章 国旗、国歌、国徽、首都第一百四十一条 中华人民共和国国旗是五星红旗。 中华人民共和国国歌是《义勇军进行曲》。 第一百四十二条 中华人民共和国国徽,中间是五星照耀下的天安门,周围是谷穗和齿轮。 第一百四十三条 中华人民共和国首都是北京。","link":"/law/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%AE%AA%E6%B3%95.html"},{"title":"Spring 如何解决循环依赖","text":"过程演练关于Spring bean的创建,其本质上还是一个对象的创建,既然是对象,读者朋友一定要明白一点就是,一个完整的对象包含两部分:当前对象实例化和对象属性的实例化。在Spring中,对象的实例化是通过反射实现的,而对象的属性则是在对象实例化之后通过一定的方式设置的。这个过程可以按照如下方式进行理解: 理解这一个点之后,对于循环依赖的理解就已经帮助一大步了,我们这里以两个类A和B为例进行讲解,如下是A和B的声明: 123456789101112131415@Componentpublic class A { private B b; public void setB(B b) { this.b = b; }}@Componentpublic class B { private A a; public void setA(A a) { this.a = a; }} 可以看到,这里A和B中各自都以对方为自己的全局属性。这里首先需要说明的一点,Spring实例化bean是通过ApplicationContext.getBean()方法来进行的。 如果要获取的对象依赖了另一个对象,那么其首先会创建当前对象,然后通过递归的调用ApplicationContext.getBean()方法来获取所依赖的对象,最后将获取到的对象注入到当前对象中。 这里我们以上面的首先初始化A对象实例为例进行讲解。 首先Spring尝试通过ApplicationContext.getBean()方法获取A对象的实例,由于Spring容器中还没有A对象实例,因而其会创建一个A对象 然后发现其依赖了B对象,因而会尝试递归的通过ApplicationContext.getBean()方法获取B对象的实例 但是Spring容器中此时也没有B对象的实例,因而其还是会先创建一个B对象的实例。 读者需要注意这个时间点,此时A对象和B对象都已经创建了,并且保存在Spring容器中了,只不过A对象的属性b和B对象的属性a都还没有设置进去。 在前面Spring创建B对象之后,Spring发现B对象依赖了属性A,因而还是会尝试递归的调用ApplicationContext.getBean()方法获取A对象的实例 因为Spring中已经有一个A对象的实例,虽然只是半成品(其属性b还未初始化),但其也还是目标bean,因而会将该A对象的实例返回。 此时,B对象的属性a就设置进去了,然后还是ApplicationContext.getBean()方法递归的返回,也就是将B对象的实例返回,此时就会将该实例设置到A对象的属性b中。 这个时候,注意A对象的属性b和B对象的属性a都已经设置了目标对象的实例了 读者朋友可能会比较疑惑的是,前面在为对象B设置属性a的时候,这个A类型属性还是个半成品。但是需要注意的是,这个A是一个引用,其本质上还是最开始就实例化的A对象。 而在上面这个递归过程的最后,Spring将获取到的B对象实例设置到了A对象的属性b中了 这里的A对象其实和前面设置到实例B中的半成品A对象是同一个对象,其引用地址是同一个,这里为A对象的b属性设置了值,其实也就是为那个半成品的a属性设置了值。 下面我们通过一个流程图来对这个过程进行讲解: 图中getBean()表示调用Spring的ApplicationContext.getBean()方法,而该方法中的参数,则表示我们要尝试获取的目标对象。 图中的黑色箭头表示一开始的方法调用走向,走到最后,返回了Spring中缓存的A对象之后,表示递归调用返回了,此时使用绿色的箭头表示。 从图中我们可以很清楚的看到,B对象的a属性是在第三步中注入的半成品A对象,而A对象的b属性是在第二步中注入的成品B对象,此时半成品的A对象也就变成了成品的A对象,因为其属性已经设置完成了。 源码讲解对于Spring处理循环依赖问题的方式,我们这里通过上面的流程图其实很容易就可以理解 需要注意的一个点,Spring是如何标记开始生成的A对象是一个半成品,并且是如何保存A对象的。 这里的标记工作Spring是使用ApplicationContext的属性SetsingletonsCurrentlyInCreation来保存的,而半成品的A对象则是通过MapsingletonFactories来保存的 这里的ObjectFactory是一个工厂对象,可通过调用其getObject()方法来获取目标对象。在AbstractBeanFactory.doGetBean()方法中获取对象的方法如下: 123456789101112131415161718192021protected T doGetBean(final String name, @Nullable final Class requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 尝试通过bean名称获取目标bean对象,比如这里的A对象 Object sharedInstance = getSingleton(beanName); // 我们这里的目标对象都是单例的 if (mbd.isSingleton()) { // 这里就尝试创建目标对象,第二个参数传的就是一个ObjectFactory类型的对象,这里是使用Java8的lamada // 表达式书写的,只要上面的getSingleton()方法返回值为空,则会调用这里的getSingleton()方法来创建 // 目标对象 sharedInstance = getSingleton(beanName, () -> { try { // 尝试创建目标对象 return createBean(beanName, mbd, args); } catch (BeansException ex) { throw ex; } }); } return (T) bean;} 这里的doGetBean()方法是非常关键的一个方法(中间省略了其他代码),上面也主要有两个步骤 第一个步骤的getSingleton()方法的作用是尝试从缓存中获取目标对象,如果没有获取到,则尝试获取半成品的目标对象;如果第一个步骤没有获取到目标对象的实例,那么就进入第二个步骤 第二个步骤的getSingleton()方法的作用是尝试创建目标对象,并且为该对象注入其所依赖的属性。 这里其实就是主干逻辑,我们前面图中已经标明,在整个过程中会调用三次doGetBean()方法 第一次调用的时候会尝试获取A对象实例,此时走的是第一个getSingleton()方法,由于没有已经创建的A对象的成品或半成品,因而这里得到的是null 然后就会调用第二个getSingleton()方法,创建A对象的实例,然后递归的调用doGetBean()方法,尝试获取B对象的实例以注入到A对象中 此时由于Spring容器中也没有B对象的成品或半成品,因而还是会走到第二个getSingleton()方法,在该方法中创建B对象的实例 创建完成之后,尝试获取其所依赖的A的实例作为其属性,因而还是会递归的调用doGetBean()方法 此时需要注意的是,在前面由于已经有了一个半成品的A对象的实例,因而这个时候,再尝试获取A对象的实例的时候,会走第一个getSingleton()方法 在该方法中会得到一个半成品的A对象的实例,然后将该实例返回,并且将其注入到B对象的属性a中,此时B对象实例化完成。 然后,将实例化完成的B对象递归的返回,此时就会将该实例注入到A对象中,这样就得到了一个成品的A对象。 我们这里可以阅读上面的第一个getSingleton()方法: 1234567891011121314151617181920212223242526272829@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) { // 尝试从缓存中获取成品的目标对象,如果存在,则直接返回 Object singletonObject = this.singletonObjects.get(beanName); // 如果缓存中不存在目标对象,则判断当前对象是否已经处于创建过程中,在前面的讲解中,第一次尝试获取A对象 // 的实例之后,就会将A对象标记为正在创建中,因而最后再尝试获取A对象的时候,这里的if判断就会为true if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 这里的singletonFactories是一个Map,其key是bean的名称,而值是一个ObjectFactory类型的 // 对象,这里对于A和B而言,调用图其getObject()方法返回的就是A和B对象的实例,无论是否是半成品 ObjectFactory singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 获取目标对象的实例 singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject;} 这里我们会存在一个问题就是A的半成品实例是如何实例化的,然后是如何将其封装为一个ObjectFactory类型的对象,并且将其放到上面的singletonFactories属性中的。 这主要是在前面的第二个getSingleton()方法中,其最终会通过其传入的第二个参数,从而调用createBean()方法,该方法的最终调用是委托给了另一个doCreateBean()方法进行的 这里面有如下一段代码: 12345678910111213141516171819202122232425262728293031323334protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // 实例化当前尝试获取的bean对象,比如A对象和B对象都是在这里实例化的 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } // 判断Spring是否配置了支持提前暴露目标bean,也就是是否支持提前暴露半成品的bean boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 如果支持,这里就会将当前生成的半成品的bean放到singletonFactories中,这个singletonFactories // 就是前面第一个getSingleton()方法中所使用到的singletonFactories属性,也就是说,这里就是 // 封装半成品的bean的地方。而这里的getEarlyBeanReference()本质上是直接将放入的第三个参数,也就是 // 目标bean直接返回 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } try { // 在初始化实例之后,这里就是判断当前bean是否依赖了其他的bean,如果依赖了, // 就会递归的调用getBean()方法尝试获取目标bean populateBean(beanName, mbd, instanceWrapper); } catch (Throwable ex) { // 省略... } return exposedObject;} 到这里,Spring整个解决循环依赖问题的实现思路已经比较清楚了。对于整体过程,读者朋友只要理解两点: Spring是通过递归的方式获取目标bean及其所依赖的bean的; Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。 结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。 参考文章:参考链接1","link":"/java/frame/Spring-%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96.html"},{"title":"Spring cloud feign重试问题排查","text":"Feign设置超时时间使用Feign调用接口分两层,ribbon的调用和hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间。 Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里。 配置超时时间: 1234567891011121314#hystrix的超时时间hystrix: command: default: execution: timeout: enabled: true isolation: thread: timeoutInMilliseconds: 9000#ribbon的超时时间ribbon: ReadTimeout: 3000 ConnectTimeout: 3000 要开启Feign的重试机制如下:(Feign默认重试五次 源码中有) 1234@BeanRetryer feignRetryer() { return new Retryer.Default();} ribbon的重试机制设置重试次数: 123456ribbon: ReadTimeout: 3000 ConnectTimeout: 3000 MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用 MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用 OkToRetryOnAllOperations: false #是否所有操作都重试 说明: 根据上面的参数计算重试的次数:MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries *MaxAutoRetriesNextServer) 即重试3次 则一共产生4次调用。如果在重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,调用fallback。所以要根据上面配置的参数计算hystrix的超时时间,使得在重试期间不能达到hystrix的超时时间,不然重试机制就会没有意义。hystrix超时时间的计算: (1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout 即按照以上的配置 hystrix的超时时间应该配置为 (1+1+1)*3=9秒。 当ribbon超时后且hystrix没有超时,便会采取重试机制。当OkToRetryOnAllOperations设置为false时,只会对get请求进行重试。如果设置为true,便会对所有的请求进行重试,如果是put或post等写操作,如果服务器接口没做幂等性,会产生不好的结果,所以OkToRetryOnAllOperations慎用。 1234567public RequestSpecificRetryHandler getRequestSpecificRetryHandler(FeignLoadBalancer.RibbonRequest request, IClientConfig requestConfig) { if ((Boolean)this.clientConfig.get(CommonClientConfigKey.OkToRetryOnAllOperations, false)) { return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(), requestConfig); } else { return !request.toRequest().method().equals(\"GET\") ? new RequestSpecificRetryHandler(true, false, this.getRetryHandler(), requestConfig) : new RequestSpecificRetryHandler(true, true, this.getRetryHandler(), requestConfig); }} 如果不配置ribbon的重试次数,默认会重试一次。默认情况下,GET方式请求无论是连接异常还是读取异常,都会进行重试非GET方式请求,只有连接异常时,才会进行重试 总结: 在使用重试机制的时候,对于接口尽量保证做到幂等性,对于多次的请求达同样的效果。 对于接口耗时比较久的,做好重复提交的验证,如redis锁住第一次提交,没处理完时,让后面的提交失败。避免重复提交。 计算好Hystrix的超时时间,以及Feign的超时以及重试时间,避免产生fallback。 当线上出现比较奇怪的问题时,排查半天都找不问题时,去查下框架的相关设置,如超时、重试的等机制。 参考文章:参考链接1","link":"/java/frame/Spring-cloud-feign%E9%87%8D%E8%AF%95%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5.html"},{"title":"github page网站cdn优化加速","text":"CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。——百度百科 放在Github的资源在国内加载速度比较慢,因此需要使用CDN加速来优化网站打开速度,jsDelivr + Github便是免费且好用的CDN,非常适合博客网站使用。 图片加速关于图传以及GitHub作为图库的使用方法请参考文章:博客图片上传picgo工具github图传使用。 在上面参考文章的基础之上只需要修改以下配置:(指定相关cdn域名) 原来项目中使用了原来的方式,进行全局替换,Mac idea直接快捷键command+shift+R全局替换 【ps:题外话】原来是统一用的GitHub的仓库中的图片,通过这样替换,可以看到图片统一管理是多么的重要,多么的方便管理操作。 至此,博客中的相关图片都加上了cdn。 其余资源文件用法: 1https://cdn.jsdelivr.net/gh/你的用户名/你的仓库名@发布的版本号/文件路径 例如: 123https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@1.0/images/trhx.pnghttps://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.0.1/css/style.csshttps://cdn.jsdelivr.net/gh/moezx/cdn@3.1.3//The%20Pet%20Girl%20of%20Sakurasou.mp4 注意:版本号不是必需的,是为了区分新旧资源,如果不使用版本号,将会直接引用最新资源,除此之外还可以使用某个范围内的版本,查看所有资源等,具体使用方法如下: 123456789101112131415161718// 加载任何Github发布、提交或分支https://cdn.jsdelivr.net/gh/user/repo@version/file// 加载 jQuery v3.2.1https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/dist/jquery.min.js// 使用版本范围而不是特定版本https://cdn.jsdelivr.net/gh/jquery/jquery@3.2/dist/jquery.min.jshttps://cdn.jsdelivr.net/gh/jquery/jquery@3/dist/jquery.min.js// 完全省略该版本以获取最新版本https://cdn.jsdelivr.net/gh/jquery/jquery/dist/jquery.min.js// 将“.min”添加到任何JS/CSS文件中以获取缩小版本,如果不存在,将为会自动生成https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js// 在末尾添加 / 以获取资源目录列表https://cdn.jsdelivr.net/gh/jquery/jquery/ 至此,github page 博客基本需要加速的完成。 参考文章:参考链接1参考链接2","link":"/theme/github-page%E7%BD%91%E7%AB%99cdn%E4%BC%98%E5%8C%96%E5%8A%A0%E9%80%9F.html"},{"title":"docker安装与使用","text":"简介Docker简介Docker 使用客户端-服务器 (C/S) 架构模式。Docker 客户端会与 Docker 守护进程进行通信。Docker 守护进程会处理复杂繁重的任务,例如建立、运行、发布你的 Docker 容器。Docker 客户端和守护进程可以运行在同一个系统上,当然你也可以使用 Docker 客户端去连接一个远程的 Docker 守护进程。Docker 客户端和守护进程之间通过 socket 或者 RESTful API 进行通信。 Docker: 开源的容器虚拟化平台 Docker Hub: 用于分享、管理 Docker 容器的 Docker SaaS 平台 – Docker Hub Docker 守护进程如上图所示,Docker 守护进程运行在一台主机上。用户并不直接和守护进程进行交互,而是通过 Docker 客户端间接和其通信。 Docker 客户端Docker 客户端,实际上是 docker 的二进制程序,是主要的用户与 Docker 交互方式。它接收用户指令并且与背后的 Docker 守护进程通信,如此来回往复。 Docker 内部要理解 Docker 内部构建,需要理解以下三种部件: Docker 镜像 - Docker images Docker 仓库 - Docker registeries Docker 容器 - Docker containers Docker 镜像Docker 镜像是 Docker 容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。UnionFS 允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。正因为有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,比如升级到某个程序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立(在使用虚拟机的时候你可能会这么做),只是一个新的层被添加或升级了。现在你不用重新发布整个镜像,只需要升级,层使得分发 Docker 镜像变得简单和快速。 Docker 仓库Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker 仓库也有公有和私有的概念。公有的 Docker 仓库名字是 Docker Hub。Docker Hub 提供了庞大的镜像集合供使用。这些镜像可以是自己创建,或者在别人的镜像基础上创建。Docker 仓库是 Docker 的分发部分。 Docker 容器Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。 Docker 从 0.9 版本开始使用 libcontainer 替代 lxc,libcontainer 和 Linux 系统的交互图如下 安装mac安装mac 的安装,一行代码,其余系统的安装方式,请自行搜索 12$ brew cask install docker$ docker was successfully installed! 镜像加速鉴于国内网络问题,后续拉取 Docker 镜像十分缓慢,我们可以需要配置加速器来解决,我使用的是网易的镜像地址:http://hub-mirror.c.163.com。 在任务栏点击 Docker for mac 应用图标 -> Perferences… -> Daemon -> Registry mirrors。在列表中填写加速器地址即可。修改完成之后,点击 Apply & Restart 按钮,Docker 就会重启并应用配置的镜像地址了。 通过 docker info 来查看是否配置成功。 12345678910111213141516171819$ docker infoContainers: 0 Running: 0 Paused: 0 Stopped: 0Images: 0Server Version: 18.09.2Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: true Native Overlay Diff: trueLogging Driver: json-fileCgroup Driver: cgroupfsPlugins: Volume: local Network: bridge host macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslogSwarm: inactive... 查看相关的使用命令 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374$ dockerUsage: docker [OPTIONS] COMMANDA self-sufficient runtime for containersOptions: --config string Location of client config files (default \"/Users/liyuechao/.docker\") -D, --debug Enable debug mode -H, --host list Daemon socket(s) to connect to -l, --log-level string Set the logging level (\"debug\"|\"info\"|\"warn\"|\"error\"|\"fatal\") (default \"info\") --tls Use TLS; implied by --tlsverify --tlscacert string Trust certs signed only by this CA (default \"/Users/liyuechao/.docker/ca.pem\") --tlscert string Path to TLS certificate file (default \"/Users/liyuechao/.docker/cert.pem\") --tlskey string Path to TLS key file (default \"/Users/liyuechao/.docker/key.pem\") --tlsverify Use TLS and verify the remote -v, --version Print version information and quitManagement Commands: builder Manage builds config Manage Docker configs container Manage containers image Manage images network Manage networks node Manage Swarm nodes plugin Manage plugins secret Manage Docker secrets service Manage services stack Manage Docker stacks swarm Manage Swarm system Manage Docker trust Manage trust on Docker images volume Manage volumesCommands: attach Attach local standard input, output, and error streams to a running container build Build an image from a Dockerfile commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container diff Inspect changes to files or directories on a container's filesystem events Get real time events from the server exec Run a command in a running container export Export a container's filesystem as a tar archive history Show the history of an image images List images import Import the contents from a tarball to create a filesystem image info Display system-wide information inspect Return low-level information on Docker objects kill Kill one or more running containers load Load an image from a tar archive or STDIN login Log in to a Docker registry logout Log out from a Docker registry logs Fetch the logs of a container pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container ps List containers pull Pull an image or a repository from a registry push Push an image or a repository to a registry rename Rename a container restart Restart one or more containers rm Remove one or more containers rmi Remove one or more images run Run a command in a new container save Save one or more images to a tar archive (streamed to STDOUT by default) search Search the Docker Hub for images start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers version Show the Docker version information wait Block until one or more containers stop, then print their exit codes 安装mysql实例docker search mysql 查看mysql相关的安装文件 docker pull mysql:5.7.21(这边是5.7.21指的是TAG版本,不指定的话默认会下载最新的LATEST版本) docker images查看所有镜像 简单新建容器docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql 接下来就可以使用NAVICAT连接127.0.0.1的ROOT账户了,密码是上面配置的123456 常用命令12345678910111213141516171819202122232425262728docker images : 列出本地镜像docker pull : 从镜像仓库中拉取或者更新指定镜像docker run :创建一个新的容器并运行一个命令-d: 后台运行容器,并返回容器ID-p: 端口映射,格式为:主机(宿主)端口:容器端口--name=\"nginx-lb\": 为容器指定一个名称-v:目录映射,格式为:主机目录:容器目录docker rm :删除一个或多个容器docker start :启动一个或多少已经被停止的容器docker stop :停止一个运行中的容器docker kill :杀掉一个运行中的容器(强制)docker restart :重启容器docker port :列出指定的容器的端口映射,或者查找将PRIVATE_PORT NAT到面向公众的端口。docker logs : 获取容器的日志-f : 跟踪日志输出--since :显示某个开始时间的所有日志-t : 显示时间戳--tail :仅列出最新N条容器日志docker exec -i -t mynginx /bin/bash:在容器mynginx中开启一个交互模式的终端,即通过SSH协议进入容器docker ps : 列出容器-a :显示所有的容器,包括未运行的。docker cp:拷贝主机docker cp /www/runoob 96f7f14e99ab:/www/ Docker 端口映射12# Find IP address of container with ID <container_id> 通过容器 id 获取 ip$ sudo docker inspect <container_id> | grep IPAddress | cut -d ’\"’ -f 4 无论如何,这些 ip 是基于本地系统的并且容器的端口非本地主机是访问不到的。此外,除了端口只能本地访问外,对于容器的另外一个问题是这些 ip 在容器每次启动的时候都会改变。 Docker 解决了容器的这两个问题,并且给容器内部服务的访问提供了一个简单而可靠的方法。Docker 通过端口绑定主机系统的接口,允许非本地客户端访问容器内部运行的服务。为了简便的使得容器间通信,Docker 提供了这种连接机制。 自动映射端口 -P 使用时需要指定 --expose 选项,指定需要对外提供服务的端口 1$ sudo docker run -t -P --expose 22 --name server ubuntu:14.04 使用 docker run -P 自动绑定所有对外提供服务的容器端口,映射的端口将会从没有使用的端口池中 (49000..49900) 自动选择,你可以通过 docker ps 、docker inspect <container_id> 或者 docker port <container_id> <port> 确定具体的绑定信息。 绑定端口到指定接口 基本语法 1$ sudo docker run -p [([<host_interface>:[host_port]])|(<host_port>):]<container_port>[/udp] <image> <cmd> 默认不指定绑定 ip 则监听所有网络接口。 绑定 TCP 端口 12345678# Bind TCP port 8080 of the container to TCP port 80 on 127.0.0.1 of the host machine.$ sudo docker run -p 127.0.0.1:80:8080 <image> <cmd># Bind TCP port 8080 of the container to a dynamically allocated TCP port on 127.0.0.1 of the host machine.$ sudo docker run -p 127.0.0.1::8080 <image> <cmd># Bind TCP port 8080 of the container to TCP port 80 on all available interfaces of the host machine.$ sudo docker run -p 80:8080 <image> <cmd># Bind TCP port 8080 of the container to a dynamically allocated TCP port on all available interfaces$ sudo docker run -p 8080 <image> <cmd> 绑定 UDP 端口 12# Bind UDP port 5353 of the container to UDP port 53 on 127.0.0.1 of the host machine.$ sudo docker run -p 127.0.0.1:53:5353/udp <image> <cmd> Docker 网络配置 Dokcer 通过使用 Linux 桥接提供容器之间的通信,docker0 桥接接口的目的就是方便 Docker 管理。当 Docker daemon 启动时需要做以下操作: creates the docker0 bridge if not present # 如果 docker0 不存在则创建 searches for an IP address range which doesn’t overlap with an existing route # 搜索一个与当前路由不冲突的 ip 段 picks an IP in the selected range # 在确定的范围中选择 ip assigns this IP to the docker0 bridge # 绑定 ip 到 docker0 Docker 四种网络模式docker run 创建 Docker 容器时,可以用 –net 选项指定容器的网络模式,Docker 有以下 4 种网络模式: host 模式,使用 –net=host 指定。 container 模式,使用 –net=container:NAME_or_ID 指定。 none 模式,使用 –net=none 指定。 bridge 模式,使用 –net=bridge 指定,默认设置。 桥接网络 不同容器之间的通信可以借助于 pipework 这个工具给 docker 容器新建虚拟网卡并绑定 IP 桥接到 br0 pipework 可以创建容器的 vlan 网络,这里不作过多的介绍了,官方文档已经写的很清楚了,可以查看以下两篇文章: Pipework 官方文档 Docker 网络详解及 pipework 源码解读与实践 开发容器镜像为了构建容器镜像,我们必须创建一个dockerfile,它将包含所有必要的信息。请参考这个文档(https://nodejs.org/en/docs/guides/nodejs-docker-webapp/)来开发dockerfile。 构建Docker容器1$docker build -t containername 这个命令将把Dockerfile放到当前的目录中。如果你的dockerfile名称不一样而且在不同的位置,可以使用-f 标签来指定dockerfile的名称。“docker build”命令将在“-t”标签指定的名称中构建容器镜像。 镜像命名惯例当在本地运行的时候,可以给Docker容器随便起什么名。可以简单的像上面提到的“myApp”。但是如果你想发布镜像到Docker Hub中,那么就需要遵循一个指定的命名惯例。这个惯例可以帮助Docker工具来发布容器镜像到正确的命名空间和资源库中。 格式:NameSpace/Repository:Version 1$docker build -t saravasu/techietweak:001 还能用“docker tag”命令从外部镜像创建镜像 在Docker中列出所有镜像1$docker images 运行容器启动Docker容器使用“docker run”命令来启动Docker容器。 1$docker run -d -p 8080:8080 saravasu/techietweak:001 “-d”选项在分离模式中运行容器,因此容器继续运行,甚至终端被关闭。 “-p”命令用来映射端口。在这个例子中,“-p 8080:8080”第一个端口号是Docker主机用的端口。第二个端口号是被Docker容器使用。根据这个命令,所有的流量到达Docker主机端口,将转到Docker容器端口。 检查当前运行的容器1$docker ps 一个Docker容器在名为“trusting_snyder.”中运行。 若要列出所有的容器,使用“- a”切换。 1$docker ps -a 展示运行容器的控制台日志1$docker logs <containerName> 容器名称可以通过 “docker ps” 命令发现。 登陆到容器1$docker exec -it containerId /bin/bash 上面的命令将提示你使用容器的“bash”。 停止运行的容器1$docker stop <containername> 从Docker移除容器镜像1$docker rm imageId 使用“docker images” 或“docker images -a.”命令发现容器的imageId。 1$docker rmi -f <List Of Image Ids> 上面的命令将强有力的删除指定的镜像。 发布容器镜像Docker容器镜像可以发布到本地dockyard或公共Docker Hub。这两个过程和命令都是一样的。要在Docker Hub中发布Docker映像,首先在http://hub.docker.com上创建名称空间和资源库。 我用了我的命名空间“saravasu”和资源库“techietweak”来进行这个练习。 登陆Docker Hub$docker login 如果你想登陆到本地的资源库,需要提供URL。如果URL不是特定的,那么这个命令将登陆到Docker Hub中。 $docker login http://localhost:8080 标记容器镜像要将Docker容器映像推到Docker Hub,它必须以特定的格式标记:< Namespace > / < Repository >:< Version >。如果未指定该版本,将被视为“默认”。在下面的命令中,我标记了镜像: 1$docker tag myapp:latest saravasu/techietweak:001 把Docker镜像推到Docker Hub中1$docker push saravasu/techietweak:001 在Docker Hub中检查容器镜像现在登陆你的Docker Hub账户,然后在各自的资源库中检查镜像。 部署容器拉出Docker容器镜像在目标环境中,从主机登陆到Docker Hub中,并且从Docker Hub中拉出容器镜像。如果你想从自己的dockyard拉出,使用“$docker login ”命令指定自己dockyard的主机名。 $docker login 上面的命令将登陆到https://hub.docker.com,因为主机名没有指定。 1$docker pull saravasu/techietweak:001 检查镜像docker pull命令从Docker Hub下载容器镜像。我们可以使用“docker images”命令来验证相同的结果。 $docker images 运行容器现在,我们可以用同样的方式运行Docker容器,就像在开发环境中运行一样,用我们以前做过的方式来测试它。 1$docker run -d -p 8080:8080 saravasu/techietweak:001 docker run命令启动容器。为了验证,可以使用“docker ps”命令。Docker创建了一个新的容器,以“naughty_lewin.的名字运行。 正如我们在上面看到的,Docker引擎为运行的容器提供了一个随机的名称,但这可能在自动化中是个问题,因此指定一个我们要参考的名称总是好的。这可以通过使用“- name”参数实现。 1$docker run -d -p 8080:8080 --name \"myNodeJsWebContainer\" saravasu/techietweak:001 参考链接: https://www.jianshu.com/p/83d360604619 https://www.jianshu.com/p/1c5fef69897f https://www.jianshu.com/p/a611fbe0d12b","link":"/tools/docker%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8.html"},{"title":"博客换肤的一种实现方式思路","text":"当博客内容很多的时候,比如需要加载很多资源文件,许多炫酷的东西的时候,可能相应的就是比较慢了(正可谓时间和空间不能兼得)。虽然目前也有很多方式手段可以提高访问速度,但是博客提供一个简洁模式还是很有必要的,萝卜青菜,各有所爱嘛。说不定很多网友就当纯的想看看文字,不需要那些花里胡哨的东西。这时候提供个清爽模式就相当有用了。 正常模式和精简模式hexo框架2仓2主题,采用正常模式一个仓库,一个主题;精简模式另一个仓库,另一个主题。 本博客采用的github Page部署网站。大家都知道,一个github的账户名,只能够指定一个username.github.io的网址,所以两个仓库,两个主题的话,就必须有一个挂在username.github.io之上,比如正常模式username.github.io,精简模式为username.github.io/name.io。 正常模式正常模式里面可以放各种炫酷的东西,提供丰富的页面。 精简模式只提供必要的文章,归档,分类,搜索基本的东西就够了。看个人需要,既然要简洁,就尽量的少弄一些。 配置方法关于**_config.yml**主配置文件的注意事项。 12345678910111213+ root: /remove.io/ #精简模式- root: / #正常模式deploy: type: git+ repo: https://github.com/removeif/remove.io.git #精简模式- repo: https://github.com/removeif/removeif.github.io.git #正常模式+ theme: icarus #正常模式- theme: nextn #精简模式 对于root 根节点的说明,因为精简模式的所有资源文件都是挂在 username.github.io/remove.io/ 所以相当于根节点为/remove.io/ 总结注意事项 对于页面中对于对应模式下资源文件的引用,一定加上域名地址 ,比如原来图片访问/image/tuizi.jpg,在精简模式的时候如果继续这样用,就找不到,对应模式下的图片了,需要加上前面的username.github.io/remove.io/ 地址。 对于精简模式下,能去掉的东西就尽量去掉,尽量少加载一些,速度更快。 对于冲突页面的处理,一般对于文章或者关于页面都是通用。文章一般没啥影响,但是关于页面,可能有些也有很炫酷的模块。对于精简模式,可能不需要,此时就需要多new 一个page页面,分开配置,比如下面主题中的_config.yml配置。 12+ /remove.io/abouta/ #精简模式- /abouta/ #正常模式 本博客正常模式 精简模式 以上只是提供了一种解决方法思路,肯定还有更好的方式。","link":"/theme/%E5%8D%9A%E5%AE%A2%E6%8D%A2%E8%82%A4%E7%9A%84%E4%B8%80%E7%A7%8D%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%E6%80%9D%E8%B7%AF.html"},{"title":"博客中gitalk最新评论的获取","text":"博客中,对于网友的评论以及每篇文章的评论数还是很重要的。但是基于静态的页面想要存储动态的评论数据是比较难的,一般博客主题中都内置了评论插件,但是博客主题中对于最新评论的支持显示还是很少的,至少目前我是没怎么发现。博客 Powered by Hexo & Icarus,采用Gitalk评论,再次感谢此三位作者的辛勤码代码,才有了以下的内容。基于此背景基础上,聊聊最新评论的实现。 博客的使用, Hexo & Icarus,采用Gitalk评论 的使用自行百度了。 使用场景 最新评论列表 最热文章列表(基于评论数判断是否最热,也比较片面,但是侧面也能反映,问题不大) 使用方法主要参考自官方文档 目前主要用到两个方法,一个是获取仓库下所有的issue,每个issue节点下有相关的评论数,以及对应issue下的评论的url;还有一个是根据issue下评论的URL获取相应的所有的评论 方法1:List issues for a repository1GET /orgs/:org/issues 参数列表 Name Type Description milestone integer or string If an integer is passed, it should refer to a milestone by its number field. If the string * is passed, issues with any milestone are accepted. If the string none is passed, issues without milestones are returned. state string Indicates the state of the issues to return. Can be either open, closed, or all. Default: open assignee string Can be the name of a user. Pass in none for issues with no assigned user, and * for issues assigned to any user. creator string The user that created the issue. mentioned string A user that’s mentioned in the issue. labels string A list of comma separated label names. Example: bug,ui,@high sort string What to sort results by. Can be either created, updated, comments. Default: created direction string The direction of the sort. Can be either asc or desc. Default: desc since string Only issues updated at or after this time are returned. This is a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ. 以上参数,主要用到 sort 排序,page页数,per_page每页数量,其余的参数看个人需要使用。注意文档中的说明,排序的字段和返回的稍许不太一样。 方法2:List comments on an issue1GET /repos/:owner/:repo/issues/:issue_number/comments Issue Comments are ordered by ascending ID. 排序根据 ascending (上升的,增长的;升(序)的)ID.也就是说,从老到新。这个比较坑,对于我们获取最新评论来说。 参数如下 Name Type Description since string Only comments updated at or after this time are returned. This is a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ. 根据尝试以及以上参数,试出不支持排序,但是支持分页,page,per_page参数,对于我们获取最新的评论来说可以根据评论数,算出分页数,拿到最后一条,即最新一条 123456//如果只有一页int page = 1;int per_page = 1;// 如果超出一页的话int page = 2;int per_page = commentsNumber-1;//commentsNumber:评论数 js代码中使用实例核心代码12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758var timesSet = [];var timesBodyMap = {};var timesSetMap = {};var resultArr = [];// 方法1:sort=comments可以按评论数排序,此处更适合按更新时间排序,可以根据updated排序,但是0条评论的也会出来,所以此处还是根据评论数排序全部查出来,过滤掉0条评论的,拿到每个issue下最新的一条评论详情和时间,根据时间内存排序// per_page 每页数量,根据需求配置$.getJSON(\"https://api.github.com/repos/{用户名}/{仓库}/issues?per_page=100&sort=comments\", function (result) { $.each(result, function (i, item) { var commentsCount = item.comments; if (commentsCount > 0) { $.ajaxSettings.async = false; // 此处保证是最后一条,api没有排序参数,只能分页取最后一条,保证最少的数据量传输,快速处理 var page = 2; var pageSize = commentsCount - 1; if (commentsCount == 1) { page = 1; pageSize = 1; } // 方法2:的使用 $.getJSON(item.comments_url + \"?page=\" + page + \"&per_page=\" + pageSize, function (commentResult) { var item1 = commentResult[0]; var contentStr = item1.body.trim(); if (contentStr.length > 50) { contentStr = contentStr.substr(0, 60); contentStr += \"...\"; } timesSet.push(new Date(item1.created_at).getTime()); timesBodyMap[item1.created_at] = { \"title\": item.title.substr(0, item.title.indexOf(\"-\") - 1), \"url\": item.body.substr(0, item.body.indexOf(\"\\n\") - 1), \"content\": contentStr, \"date\": item1.created_at, \"userName\": item1[\"user\"].login, \"userUrl\": item1[\"user\"].html_url, \"commentCount\": commentsCount }; timesSetMap[new Date(item1.created_at).getTime()] = item1.created_at; }); } });});// 排序if (timesSet.length > 0) { timesSet.sort();}// 根据需要取10条if (timesSet.length > 10) { for (var i = timesSet.length - 1; i >= 0 && resultArr.length < 10; i--) { resultArr.push(timesBodyMap[timesSetMap[timesSet[i]]]); }}else { for (var i = timesSet.length - 1; i >= 0; i--) { resultArr.push(timesBodyMap[timesSetMap[timesSet[i]]]); }} 方法1:请求接口地址示例1https://api.github.com/repos/removeif/blog_comment/issues?per_page=100&sort=comments 返回结果 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566[ { \"url\": \"https://api.github.com/repos/removeif/blog_comment/issues/3\", \"repository_url\": \"https://api.github.com/repos/removeif/blog_comment\", \"labels_url\": \"https://api.github.com/repos/removeif/blog_comment/issues/3/labels{/name}\", \"comments_url\": \"https://api.github.com/repos/removeif/blog_comment/issues/3/comments\", \"events_url\": \"https://api.github.com/repos/removeif/blog_comment/issues/3/events\", \"html_url\": \"https://github.com/removeif/blog_comment/issues/3\", \"id\": 458985510, \"node_id\": \"MDU6SXNzdWU0NTg5ODU1MTA=\", \"number\": 3, \"title\": \"留言板 - 辣椒の酱\", \"user\": { \"login\": \"removeif\", \"id\": 10427139, \"node_id\": \"MDQ6VXNlcjEwNDI3MTM5\", \"avatar_url\": \"https://avatars1.githubusercontent.com/u/10427139?v=4\", \"gravatar_id\": \"\", \"url\": \"https://api.github.com/users/removeif\", \"html_url\": \"https://github.com/removeif\", \"followers_url\": \"https://api.github.com/users/removeif/followers\", \"following_url\": \"https://api.github.com/users/removeif/following{/other_user}\", \"gists_url\": \"https://api.github.com/users/removeif/gists{/gist_id}\", \"starred_url\": \"https://api.github.com/users/removeif/starred{/owner}{/repo}\", \"subscriptions_url\": \"https://api.github.com/users/removeif/subscriptions\", \"organizations_url\": \"https://api.github.com/users/removeif/orgs\", \"repos_url\": \"https://api.github.com/users/removeif/repos\", \"events_url\": \"https://api.github.com/users/removeif/events{/privacy}\", \"received_events_url\": \"https://api.github.com/users/removeif/received_events\", \"type\": \"User\", \"site_admin\": false }, \"labels\": [ { \"id\": 1416043904, \"node_id\": \"MDU6TGFiZWwxNDE2MDQzOTA0\", \"url\": \"https://api.github.com/repos/removeif/blog_comment/labels/3306ea6632b94cc388b40cef9dda4a8f\", \"name\": \"3306ea6632b94cc388b40cef9dda4a8f\", \"color\": \"0e8a16\", \"default\": false }, { \"id\": 1415994590, \"node_id\": \"MDU6TGFiZWwxNDE1OTk0NTkw\", \"url\": \"https://api.github.com/repos/removeif/blog_comment/labels/Gitalk\", \"name\": \"Gitalk\", \"color\": \"5319e7\", \"default\": false } ], \"state\": \"open\", \"locked\": false, \"assignee\": null, \"assignees\": [ ], \"milestone\": null, \"comments\": 33, \"created_at\": \"2019-06-21T03:06:53Z\", \"updated_at\": \"2019-09-12T10:37:34Z\", \"closed_at\": null, \"author_association\": \"OWNER\", \"body\": \"https://removeif.github.io/message/\\r\\n\\r\\n留言板信息。\" }, {...} ] 方法2:请求接口地址示例1https://api.github.com/repos/removeif/blog_comment/issues/3/comments?per_page=32&page=2 返回结果 123456789101112131415161718192021222324252627282930313233[ { \"url\": \"https://api.github.com/repos/removeif/blog_comment/issues/comments/530767913\", \"html_url\": \"https://github.com/removeif/blog_comment/issues/3#issuecomment-530767913\", \"issue_url\": \"https://api.github.com/repos/removeif/blog_comment/issues/3\", \"id\": 530767913, \"node_id\": \"MDEyOklzc3VlQ29tbWVudDUzMDc2NzkxMw==\", \"user\": { \"login\": \"removeif\", \"id\": 10427139, \"node_id\": \"MDQ6VXNlcjEwNDI3MTM5\", \"avatar_url\": \"https://avatars1.githubusercontent.com/u/10427139?v=4\", \"gravatar_id\": \"\", \"url\": \"https://api.github.com/users/removeif\", \"html_url\": \"https://github.com/removeif\", \"followers_url\": \"https://api.github.com/users/removeif/followers\", \"following_url\": \"https://api.github.com/users/removeif/following{/other_user}\", \"gists_url\": \"https://api.github.com/users/removeif/gists{/gist_id}\", \"starred_url\": \"https://api.github.com/users/removeif/starred{/owner}{/repo}\", \"subscriptions_url\": \"https://api.github.com/users/removeif/subscriptions\", \"organizations_url\": \"https://api.github.com/users/removeif/orgs\", \"repos_url\": \"https://api.github.com/users/removeif/repos\", \"events_url\": \"https://api.github.com/users/removeif/events{/privacy}\", \"received_events_url\": \"https://api.github.com/users/removeif/received_events\", \"type\": \"User\", \"site_admin\": false }, \"created_at\": \"2019-09-12T10:37:34Z\", \"updated_at\": \"2019-09-12T10:37:34Z\", \"author_association\": \"OWNER\", \"body\": \"> 哇 大佬你博客弄的好厉害啊 可以指点指点吗\\n>> @xuelangjing 还好吧😂,简简单单的,可以多看下网页上的源码,有什么问题可以讨论讨论哦\" }] 博客中目前有两个页面使用,根据个人的需要放到各自的位置吧。 首页热门推荐 还有个最新评论页: 扩展一个方法上面的实例程序,每个issue(因为我的每个issue关联一个文章链接)只取了一条最新的评论,假如每个issue下有两个都是最新的评论,而我也不管是不是同一个issue下的评论,获取所有的最新评论,还有一个方法比较好用。 List comments in a repository1GET /repos/:owner/:repo/issues/comments By default, Issue Comments are ordered by ascending ID. 和上面一样,但是以下参数就不一样了 Name Type Description sort string Either created or updated. Default: created direction string Either asc or desc. Ignored without the sort parameter. since string Only comments updated at or after this time are returned. This is a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ. 多了排序字段和排序方式,也有per和per_page,这是相当的有用啊 扩展方法:请求接口地址示例1https://api.github.com/repos/removeif/blog_comment/issues/comments?sort=updated&direction=desc&per_page=10&page=1 返回结果 123456789101112131415161718192021222324252627282930313233343536[ { \"url\": \"https://api.github.com/repos/removeif/blog_comment/issues/comments/530767913\", \"html_url\": \"https://github.com/removeif/blog_comment/issues/3#issuecomment-530767913\", \"issue_url\": \"https://api.github.com/repos/removeif/blog_comment/issues/3\", \"id\": 530767913, \"node_id\": \"MDEyOklzc3VlQ29tbWVudDUzMDc2NzkxMw==\", \"user\": { \"login\": \"removeif\", \"id\": 10427139, \"node_id\": \"MDQ6VXNlcjEwNDI3MTM5\", \"avatar_url\": \"https://avatars1.githubusercontent.com/u/10427139?v=4\", \"gravatar_id\": \"\", \"url\": \"https://api.github.com/users/removeif\", \"html_url\": \"https://github.com/removeif\", \"followers_url\": \"https://api.github.com/users/removeif/followers\", \"following_url\": \"https://api.github.com/users/removeif/following{/other_user}\", \"gists_url\": \"https://api.github.com/users/removeif/gists{/gist_id}\", \"starred_url\": \"https://api.github.com/users/removeif/starred{/owner}{/repo}\", \"subscriptions_url\": \"https://api.github.com/users/removeif/subscriptions\", \"organizations_url\": \"https://api.github.com/users/removeif/orgs\", \"repos_url\": \"https://api.github.com/users/removeif/repos\", \"events_url\": \"https://api.github.com/users/removeif/events{/privacy}\", \"received_events_url\": \"https://api.github.com/users/removeif/received_events\", \"type\": \"User\", \"site_admin\": false }, \"created_at\": \"2019-09-12T10:37:34Z\", \"updated_at\": \"2019-09-12T10:37:34Z\", \"author_association\": \"OWNER\", \"body\": \"> 哇 大佬你博客弄的好厉害啊 可以指点指点吗\\n>> @xuelangjing 还好吧😂,简简单单的,可以多看下网页上的源码,有什么问题可以讨论讨论哦\" }, { ... } ] 总结此扩展方法优点:对于不在乎issue数量,只在乎最新评论的就比较适用,能够精准拿出前10条,很赞不足:一个issue下多个最新评论,如果想要显示的最新评论列表还包括文章标题,看起来可能不太好看,很多重复,但是看个人需要吧 注意事项,采坑环节 对应接口的请求限制,目前接口有请求的限制,所以使用中不能频繁请求,调试的时候一会儿又限制,一会儿又限制比较麻烦,限制十几分钟之后就解除了。 对于页面中,一般很多个地方可能都需要展示这个列表,所以不能每次都去请求,必须缓存起来,一般缓存到本地,我的是存的cookie中,十分钟去请求一次,所以调好后一般不会出现限制情况。但是马上评论了的就看不到,有10分钟的延迟,不过也还好。 对于如果issue以及评论太多的情况,尽量的少请求,比如上面的分页优化,取最后一条。以及页面中请求时做出异步请求的方式,不要阻止其他元素的渲染。 本人主要做后端,对前端的set/排序不太熟悉,上面实现排序代码比较繁琐😂,如果有什么更好的方法,麻烦也告知一下,互相学习共同进步。","link":"/theme/%E5%8D%9A%E5%AE%A2%E4%B8%ADgitalk%E6%9C%80%E6%96%B0%E8%AF%84%E8%AE%BA%E7%9A%84%E8%8E%B7%E5%8F%96.html"},{"title":"Java日志的正确使用方法","text":"使用slf4j 使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。 实现方式统一使用: Logback框架 打日志的正确方式什么时候应该打日志 当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统,是可以通过日志进行问题定为的。 当你碰到if…else 或者 switch这样的分支时,要在分支的首行打印日志,用来确定进入了哪个分支 经常以功能为核心进行开发,你应该在提交代码前,可以确定通过日志可以看到整个流程 基本格式必须使用参数化信息的方式: 1logger.debug(\"Processing trade with id:[{}] and symbol : [{}] \", id, symbol); 对于debug日志,必须判断是否为debug级别后,才进行使用: 123if (logger.isDebugEnabled()) { logger.debug(\"Processing trade with id: \" +id + \" symbol: \" + symbol);} 不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能。 反例(不要这么做): 1logger.debug(\"Processing trade with id: \" + id + \" symbol: \" + symbol); 使用[]进行参数变量隔离 如有参数变量,应该写成如下写法: 1logger.debug(\"Processing trade with id:[{}] and symbol : [{}] \", id, symbol); 这样的格式写法,可读性更好,对于排查问题更有帮助。 不同级别的使用ERROR:影响到程序正常运行、当前请求正常运行的异常情况: 打开配置文件失败 所有第三方对接的异常(包括第三方返回错误码) 所有影响功能使用的异常,包括:SQLException和除了业务异常之外的所有异常(RuntimeException和Exception) 不应该出现的情况: 比如要使用Azure传图片,但是Azure未响应 如果有Throwable信息,需要记录完成的堆栈信息: 1log.error(\"获取用户[{}]的用户信息时出错\",userName,e); 说明 如果进行了抛出异常操作,请不要记录error日志,由最终处理方进行处理: 反例(不要这么做): 1234567try{ ....}catch(Exception ex){ String errorMessage=String.format(\"Error while reading information of user [%s]\",userName); logger.error(errorMessage,ex); throw new UserServiceException(errorMessage,ex);} WARN基本概念 不应该出现但是不影响程序、当前请求正常运行的异常情况: 有容错机制的时候出现的错误情况 找不到配置文件,但是系统能自动创建配置文件 即将接近临界值的时候,例如: 缓存池占用达到警告线 业务异常的记录,比如: 当接口抛出业务异常时,应该记录此异常 INFO:系统运行信息 Service方法中对于系统/业务状态的变更 主要逻辑中的分步骤 外部接口部分 客户端请求参数(REST/WS) 调用第三方时的调用参数和调用结果 说明 1.并不是所有的service都进行出入口打点记录,单一、简单service是没有意义的(job除外,job需要记录开始和结束,)。 反例(不要这么做): 123456789public List listByBaseType(Integer baseTypeId) { log.info(\"开始查询基地\");BaseExample ex=new BaseExample();BaseExample.Criteria ctr = ex.createCriteria();ctr.andIsDeleteEqualTo(IsDelete.USE.getValue());Optionals.doIfPresent(baseTypeId, ctr::andBaseTypeIdEqualTo); log.info(\"查询基地结束\");return baseRepository.selectByExample(ex);} 2.对于复杂的业务逻辑,需要进行日志打点,以及埋点记录,比如电商系统中的下订单逻辑,以及OrderAction操作(业务状态变更)。 3.对于整个系统的提供出的接口(REST/WS),使用info记录入参 4.如果所有的service为SOA架构,那么可以看成是一个外部接口提供方,那么必须记录入参。 5.调用其他第三方服务时,所有的出参和入参是必须要记录的(因为你很难追溯第三方模块发生的问题) DEBUG 可以填写所有的想知道的相关信息(但不代表可以随便写,debug信息要有意义,最好有相关参数) 生产环境需要关闭DEBUG信息 如果在生产情况下需要开启DEBUG,需要使用开关进行管理,不能一直开启。 说明 如果代码中出现以下代码,可以进行优化: 12345//1. 获取用户基本薪资//2. 获取用户休假情况//3. 计算用户应得薪资 优化后的代码: 12345678logger.debug(\"开始获取员工[{}] [{}]年基本薪资\",employee,year);logger.debug(\"获取员工[{}] [{}]年的基本薪资为[{}]\",employee,year,basicSalary);logger.debug(\"开始获取员工[{}] [{}]年[{}]月休假情况\",employee,year,month);logger.debug(\"员工[{}][{}]年[{}]月年假/病假/事假为[{}]/[{}]/[{}]\",employee,year,month,annualLeaveDays,sickLeaveDays,noPayLeaveDays);logger.debug(\"开始计算员工[{}][{}]年[{}]月应得薪资\",employee,year,month);logger.debug(\"员工[{}] [{}]年[{}]月应得薪资为[{}]\",employee,year,month,actualSalary); TRACE 特别详细的系统运行完成信息,业务代码中,不要使用.(除非有特殊用意,否则请使用DEBUG级别替代) 规范示例说明 1234567891011121314151617181920212223242526272829@Override@Transactionalpublic void createUserAndBindMobile(@NotBlank String mobile, @NotNull User user) throws CreateConflictException{ boolean debug = log.isDebugEnabled(); if(debug){ log.debug(\"开始创建用户并绑定手机号. args[mobile=[{}],user=[{}]]\", mobile, LogObjects.toString(user)); } try { user.setCreateTime(new Date()); user.setUpdateTime(new Date()); userRepository.insertSelective(user); if(debug){ log.debug(\"创建用户信息成功. insertedUser=[{}]\",LogObjects.toString(user)); } UserMobileRelationship relationship = new UserMobileRelationship(); relationship.setMobile(mobile); relationship.setOpenId(user.getOpenId()); relationship.setCreateTime(new Date()); relationship.setUpdateTime(new Date()); userMobileRelationshipRepository.insertOnDuplicateKey(relationship); if(debug){ log.debug(\"绑定手机成功. relationship=[{}]\",LogObjects.toString(relationship)); } log.info(\"创建用户并绑定手机号. userId=[{}],openId=[{}],mobile=[{}]\",user.getId(),user.getOpenId(),mobile); }catch(DuplicateKeyException e){ log.info(\"创建用户并绑定手机号失败,已存在相同的用户. openId=[{}],mobile=[{}]\",user.getOpenId(),mobile); throw new CreateConflictException(\"创建用户发生冲突, openid=[%s]\",user.getOpenId()); }} 文章来源.","link":"/java/basic/Java%E6%97%A5%E5%BF%97%E7%9A%84%E6%AD%A3%E7%A1%AE%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95.html"},{"title":"并发扣款相关问题","text":"继续解答星球水友提问。沈老师,我们有个业务,同一个用户在并发“查询,逻辑计算,扣款”的情况下,余额可能出现不一致,请问有什么优化方法么? 并发扣款,如何保证数据的一致性?扣款的业务场景是怎样的? 用户购买商品的过程中,要对余额进行查询与修改,大致的业务流程如下: 第一步,从数据库查询用户现有余额: 1SELECT money FROM t_yue WHERE uid=$uid 不妨设查询出来的$old_money=100元。 第二步,业务层实施业务逻辑计算,比如:(1)先查询购买商品的价格,例如是80元;(2)再查询产品是否有活动,以及活动折扣,例如是9折;(3)比对余额是否足够,足够时才往下走; 12345if($old_money> 80\\*0.9){ $new_money=$old_money-80\\*0.9=28; } else { return \"Not enough minerals\"; } 第三步,将数据库中的余额进行修改。 1UPDATE t_yue SET money=new_money WHERE uid=uid; 在并发量低的情况下,这个流程没有任何问题,原有金额100元,购买了80元的九折商品(72元),剩余28元。 同一个用户,并发扣款可能出现什么问题? 在分布式环境中,如果并发量很大,这种“查询+修改”的业务有一定概率出现数据不一致。 极限情况下,可能出现这样的异常流程: 步骤一,业务1和业务2并发查询余额,是100元。 画外音:这些并发查询,是在不同的站点实例/服务实例上完成的,进程内互斥锁肯定解决不了。步骤二,业务1和业务2并发进行逻辑计算,算出各自业务的余额,假设业务1算出的余额是28元,业务2算出的余额是38元。 步骤三,业务1对数据库中的余额先进行修改,设置成28元。 业务2对数据库中的余额后进行修改,设置成38元。 此时异常出现了,原有金额100元,业务1扣除了72元,业务2扣除了62元,最后剩余38元。画外音:假设业务1先写回余额,业务2再写回余额。 常见的解决方案? 对于此案例,同一个用户,并发扣款时,有小概率会出现异常,可以对每一个用户进行分布式锁互斥,例如:在redis/zk里抢到一个key才能继续操作,否则禁止操作。 这种悲观锁方案确实可行,但要引入额外的组件(redis/zk),并且会降低吞吐量。 对于小概率的不一致,有没有乐观锁的方案呢? 对并发扣款进行进一步的分析发现: (1)业务1写回时,旧余额100,这是一个初始状态;新余额28,这是一个结束状态。理论上只有在旧余额为100时,新余额才应该写回成功。 而业务1并发写回时,旧余额确实是100,理应写回成功。 (2)业务2写回时,旧余额100,这是一个初始状态;新余额28,这是一个结束状态。理论上只有在旧余额为100时,新余额才应该写回成功。 可实际上,这个时候数据库中的金额已经变为28了,所以业务2的并发写回,不应该成功。 如何低成本实施乐观锁? 在set写回的时候,加上初始状态的条件compare,只有初始状态不变时,才允许set写回成功,Compare And Set(CAS),是一种常见的降低读写锁冲突,保证数据一致性的方法。 此时业务要怎么改? 使用CAS解决高并发时数据一致性问题,只需要在进行set操作时,compare初始值,如果初始值变换,不允许set成功。 具体到这个case,只需要将: 1UPDATE t_yue SET money=$new_money WHERE uid=$uid; 升级为: 1UPDATE t_yue SET money=$new_money WHERE uid=$uid AND money=$old_money 并发操作发生时: 业务1执行: 1UPDATE t_yue SET money=28 WHERE uid=$uid AND money=100; 业务2执行: 1UPDATE t_yue SET money=38 WHERE uid=$uid AND money=100; 这两个操作同时进行时,只可能有一个执行成功。 怎么判断哪个并发执行成功,哪个并发执行失败呢? set操作,其实无所谓成功或者失败,业务能通过affect rows来判断: 写回成功的,affect rows为1 写回失败的,affect rows为0 总结 高并发“查询并修改”的场景,可以用CAS(Compare and Set)的方式解决数据一致性问题。对应到业务,即在set的时候,加上初始条件的比对即可。 优化不难,只改了半行SQL,但确实能解决问题。但希望大家有收获,思路比结论重要。 并发扣款一致性优化,CAS下ABA问题上文中提到:用CAS乐观锁,可以在尽量不影响吞吐量的情况下,保证数据的一致性。 大家有非常多的留言,大概有这么几类: (1)是否存在ABA问题? (2)为什么不能用: 1UPDATE t_yue SET money=money-$diff AND money>=$diff; (3)能否借助redis事务来扣减余额; 能,上文有讲。 问题比较多,今天先聊第一个问题,ABA。 什么是ABA问题? CAS乐观锁机制确实能够提升吞吐,并保证一致性,但在极端情况下可能会出现ABA问题。 考虑如下操作: 并发1(上):获取出数据的初始值是A,后续计划实施CAS乐观锁,期望数据仍是A的时候,修改才能成功 并发2:将数据修改成B 并发3:将数据修改回A 并发1(下):CAS乐观锁,检测发现初始值还是A,进行数据修改 上述并发环境下,并发1在修改数据时,虽然还是A,但已经不是初始条件的A了,中间发生了A变B,B又变A的变化,此A已经非彼A,数据却成功修改,可能导致错误,这就是CAS引发的所谓的ABA问题。 余额操作,出现ABA问题并不会对业务产生影响,因为对于“余额”属性来说,前一个A为100余额,与后一个A为100余额,本质是相同的。 但其他场景未必是这样,举一个堆栈操作的例子: A1 B C A1 F 并发1(上):读取栈顶的元素为“A1” 并发2:进行了2次出栈 并发3:又进行了1次出栈 并发1(下):实施CAS乐观锁,发现栈顶还是“A1”,于是修改为A2 此时会出现系统错误,因为此“A1”非彼“A1” ABA问题可以怎么优化? ABA问题导致的原因,是CAS过程中只简单进行了“值”的校验,再有些情况下,“值”相同不会引入错误的业务逻辑(例如余额),有些情况下,“值”虽然相同,却已经不是原来的数据了(例如堆栈)。 因此,CAS不能只比对“值”,还必须确保是原来的数据,才能修改成功。 常见的实践是,将“值”比对,升级为“版本号”的比对,一个数据一个版本,版本变化,即使值相同,也不应该修改成功。 余额并发读写例子,引入版本号的具体实践如下: (1)余额表要升级。 1t_yue(uid, money) 升级为: 1t_yue(uid, money, version) (2)查询余额时,同时查询版本号。 1SELECT money FROM t_yue WHERE sid=$sid 升级为: 1SELECT money,version FROM t_yue WHERE sid=$sid 假设有并发操作,都会将版本号查询出来。 (3)设置余额时,必须版本号相同,并且版本号要修改。 旧版本“值”比对: 1UPDATE t_yue SET money=38 WHERE uid=$uid AND money=100; 升级为“版本号”比对: 1UPDATE t_yue SET money=38,version=$version_new WHERE uid=$uid AND version=$version_old; 此时假设有并发操作,首先操作的请求会修改版本号,并发操作会执行失败。 画外音:version通用,本例是强行用version举例而已,实际上本例可以用余额“值”比对。 总结 select&set业务场景,在并发时会出现一致性问题 基于“值”的CAS乐观锁,可能导致ABA问题 CAS乐观锁,必须保证修改时的“此数据”就是“彼数据”,应该由“值”比对,优化为“版本号”比对 并发扣款一致性,幂等性问题分享了同一个用户并发扣款时,有一定概率出现数据不一致,可以使用CAS乐观锁的方式,在不降低吞吐量,并且只有少量修改的情况下,保证数据的一致性。 文章发布不到24小时,就有近200的评论。 其中,问的比较多的是ABA问题,这个问题已经在《并发扣款一致性优化,CAS下ABA问题,这个话题还没聊完!!!》中扩展。 其次,问的比较多的是作业题,为什么一定要用select&set的方式进行余额写回: 1UPDATE t_yue SET money=$new_money WHERE uid=$uid AND money=$old_money; 为什么不能采用直接扣减的方法: 1UPDATE t_yue SET money=money-$diff WHERE uid=$uid; 很人说,在并发情况下,会将money扣成负数。 为了保证余额不被扣成负数,再加一个where条件: 1UPDATE t_yue SET money=money-$diff WHERE uid=$uid* AND money-$diff>0; 这样是否可行? 画外音:额,撇开业务不谈,这个SQL用列做运算,其实是不好的,建议使用: 1UPDATE t_yue SET money=money-$diff WHERE uid=$uid AND money>$diff; 很遗憾,仍然不行。原因在《并发扣款,如何保证数据的一致性?》一文里点赞最多的评论,不幂等。 画外音:说明绝大部分同学,能够回答正确作业。 聊幂等性之前,先看另一个测试用例的case。 假设有一个服务接口,注册新用户: 123456789101112bool RegisterUser($uid, $name){​ //**查看uid是否已经存在***​ select uid from t_user where uid=$uid;​ //**不是新用户,返回失败***​ if(rows>0)return false;​ else{​ //**把新用户插入用户表***​ insert into t_user values($uid, $name);​ //**返回成功***​ return true;​ }} 有一个测试工程师,对该接口写了一个测试用例: 1234567891011bool TestCase_RegisterUser(){​ //**造一些假数据***​ long uid=123;​ String name='shenjian';​ //**调用被测试的接口***​ bool result= RegisterUser(uid,name);​ //预期注册成功,**对结果进行断言判断***​ Assert(result,true);​ //**返回测试结果***​ return result;} 这是不是一个好的测试用例?这个用例存在什么问题? 你会发现,相同条件下,这个测试用例执行两次,得到的结果不一样: (1)第一次执行,第一次造数据,调用接口,注册成功; (2)第二次执行,又造了一次相同的数据,调用接口,注册会失败; 这不是一个好的测试用例,多次执行结果不同。 什么是幂等性? 相同条件下,执行同一请求,得到的结果相同,才符合幂等性。 画外音:Google一下,比我解释得更好,但意思应该说清楚了。 如何将上面的测试用例改为符合“幂等性”的测试用例呢? 只需要加一行代码: 1234567891011121314bool TestCase_RegisterUser(){​ //造一些假数据*​ long uid=123;​ String name=’shenjian’;​ //**先删除这个伪造的用户***​ DeleteUser(uid);​ //调用被测试的接口*​ bool result= RegisterUser(uid,name);​ //预期注册成功,对结果进行断言判断*​ Assert(result,true);​ //返回测试结果*​ return result;} 这样,在相同条件下,不管这个用例执行多少次,得到的测试结果都是相同的。 是不是对幂等性有点感觉了。 读请求,一般是幂等的。 写请求,视情况而定: insert x,一般来说不是幂等的,重复插入得到的结果不一定一样 delete x,一般来说是幂等的,删除多次得到的结果仍相同 set a=x,是幂等的 set a=a-x,不是幂等的 … 因此,这么扣减余额: 1UPDATE t_yue SET money=$new_money WHERE uid=$uid AND money=$old_money; 是幂等操作。 要是这么扣减余额: 1UPDATE t_yue SET money=money-$diff WHERE uid=$uid AND money-$diff>0; 不是幂等操作。 聊到这里,或许有朋友要抬杠了,测试用例会重复执行,扣款怎么会重复执行呢? 重试。 重试,是异常处理里很常见的手段。 你在写业务的时候有没有写过这样的代码: 123456result = DoSomething();if(false==result || TIMEOUT){​ //**错误,或者超时,重试一次***​ result= DoSomething();}return result; 当然,又会有朋友抬杠了,我从来不重试!!! 画外音:额,这是合格,还是不合格呢? 你可以决定业务代码怎么写,你不能决定底层框架代码怎么写: (1)站点框架有没有自动重试? (2)服务框架有没有自动重试? (3)服务连接池,数据库连接池有没有自动重试? 画外音: (1)服务化分层的架构中,建议只入口层重试,服务层不要重试,防止雪崩; (2)dubbo底层,调用超时是默认重试的,这个设计不好; 因此,在有重试的架构体系里,幂等性是需要考虑的一个问题。 现在该懂了,为啥扣款和充值业务,一般使用: select&set,配合CAS方案 而不使用: set money-=X方案 画外音:充了100电话费,怎么多了200块? 参考自文章.","link":"/design-architecture/%E5%B9%B6%E5%8F%91%E6%89%A3%E6%AC%BE%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98.html"},{"title":"MyBatis二级缓存","text":"摘要我们在上一篇文章介绍了 MyBatis 的一级缓存的作用,如何开启,一级缓存的本质是什么,一级缓存失效的原因是什么?MyBatis 只有一级缓存吗?来找找答案吧! MyBatis 二级缓存介绍 上一篇文章中我们介绍到了 MyBatis 一级缓存其实就是 SqlSession 级别的缓存,什么是 SqlSession 级别的缓存呢?一级缓存的本质是什么呢?以及一级缓存失效的原因?我希望你在看下文之前能够回想起来这些内容。 MyBatis 一级缓存最大的共享范围就是一个SqlSession内部,那么如果多个 SqlSession 需要共享缓存,则需要开启二级缓存,开启二级缓存后,会使用 CachingExecutor 装饰 Executor,进入一级缓存的查询流程前,先在CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示 当二级缓存开启后,同一个命名空间(namespace) 所有的操作语句,都影响着一个 共同的 cache,也就是二级缓存被多个 SqlSession 共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。 二级缓存开启条件 二级缓存默认是不开启的,需要手动开启二级缓存,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。开启二级缓存的条件也是比较简单,通过直接在 MyBatis 配置文件中通过 1<settings> <setting name = \"cacheEnabled\" value = \"true\" /></settings> 来开启二级缓存,还需要在 Mapper 的xml 配置文件中加入 标签 设置 cache 标签的属性 cache 标签有多个属性,一起来看一些这些属性分别代表什么意义 eviction: 缓存回收策略,有这几种回收策略 LRU - 最近最少回收,移除最长时间不被使用的对象 FIFO - 先进先出,按照缓存进入的顺序来移除它们 SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象 WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象 默认是 LRU 最近最少回收策略 flushinterval 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值 readOnly: 是否只读;true 只读 ,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。**读写(默认)**:MyBatis 觉得数据可能会被修改 size : 缓存存放多少个元素 type: 指定自定义缓存的全类名(实现Cache 接口即可) blocking:若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。 探究二级缓存 我们继续以 MyBatis 一级缓存文章中的例子为基础,搭建一个满足二级缓存的例子,来对二级缓存进行探究,例子如下(对 一级缓存的例子部分源码进行修改): Dept.java //存放在共享缓存中数据进行序列化操作和反序列化操作 //因此数据对应实体类必须实现【序列化接口】并提供 无参数的构造方法 1public class Dept implements Serializable myBatis-config.xml 在myBatis-config 中添加开启二级缓存的条件 1<setting name=\"cacheEnabled\" value=\"true\"/> DeptDao.xml 还需要在 Mapper 对应的xml中添加 cache 标签,表示对哪个mapper 开启缓存 对应的二级缓存测试类如下: 12345678910111213141516171819202122232425262728293031323334353637public class MyBatisSecondCacheTest { private SqlSession sqlSession; SqlSessionFactory factory; @Before public void start() throws IOException { InputStream is = Resources.getResourceAsStream(\"myBatis-config.xml\"); SqlSessionFactoryBuilder builderObj = new SqlSessionFactoryBuilder(); factory = builderObj.build(is); sqlSession = factory.openSession(); } @After public void destory(){ if(sqlSession!=null){ sqlSession.close(); } } @Test public void testSecondCache(){ //会话过程中第一次发送请求,从数据库中得到结果 //得到结果之后,mybatis自动将这个查询结果放入到当前用户的一级缓存 DeptDao dao = sqlSession.getMapper(DeptDao.class); Dept dept = dao.findByDeptNo(1); System.out.println(\"第一次查询得到部门对象 = \"+dept); //触发MyBatis框架从当前一级缓存中将Dept对象保存到二级缓存 sqlSession.commit(); // 改成 sqlSession.close(); 效果相同 SqlSession session2 = factory.openSession(); DeptDao dao2 = session2.getMapper(DeptDao.class); Dept dept2 = dao2.findByDeptNo(1); System.out.println(\"第二次查询得到部门对象 = \"+dept2); }} 测试二级缓存效果,提交事务,sqlSession 查询完数据后,sqlSession2相同的查询是否会从缓存中获取数据。 测试结果如下: 通过结果可以得知,首次执行的SQL语句是从数据库中查询得到的结果,然后第一个 SqlSession 执行提交,第二个 SqlSession 执行相同的查询后是从缓存中查取的。 用一下这幅图能够比较直观的反映两次 SqlSession 的缓存命中 二级缓存失效的条件 与一级缓存一样,二级缓存也会存在失效的条件的,下面我们就来探究一下哪些情况会造成二级缓存失效 第一次SqlSession 未提交 SqlSession 在未提交的时候,SQL 语句产生的查询结果还没有放入二级缓存中,这个时候 SqlSession2 在查询的时候是感受不到二级缓存的存在的,修改对应的测试类,结果如下: 1234567891011121314@Testpublic void testSqlSessionUnCommit(){ //会话过程中第一次发送请求,从数据库中得到结果 //得到结果之后,mybatis自动将这个查询结果放入到当前用户的一级缓存 DeptDao dao = sqlSession.getMapper(DeptDao.class); Dept dept = dao.findByDeptNo(1); System.out.println(\"第一次查询得到部门对象 = \"+dept); //触发MyBatis框架从当前一级缓存中将Dept对象保存到二级缓存 SqlSession session2 = factory.openSession(); DeptDao dao2 = session2.getMapper(DeptDao.class); Dept dept2 = dao2.findByDeptNo(1); System.out.println(\"第二次查询得到部门对象 = \"+dept2);} 产生的输出结果: 更新对二级缓存影响 与一级缓存一样,更新操作很可能对二级缓存造成影响,下面用三个 SqlSession来进行模拟,第一个 SqlSession 只是单纯的提交,第二个 SqlSession 用于检验二级缓存所产生的影响,第三个 SqlSession 用于执行更新操作,测试如下: 1234567891011121314151617181920212223242526@Testpublic void testSqlSessionUpdate(){ SqlSession sqlSession = factory.openSession(); SqlSession sqlSession2 = factory.openSession(); SqlSession sqlSession3 = factory.openSession(); // 第一个 SqlSession 执行更新操作 DeptDao deptDao = sqlSession.getMapper(DeptDao.class); Dept dept = deptDao.findByDeptNo(1); System.out.println(\"dept = \" + dept); sqlSession.commit(); // 判断第二个 SqlSession 是否从缓存中读取 DeptDao deptDao2 = sqlSession2.getMapper(DeptDao.class); Dept dept2 = deptDao2.findByDeptNo(1); System.out.println(\"dept2 = \" + dept2); // 第三个 SqlSession 执行更新操作 DeptDao deptDao3 = sqlSession3.getMapper(DeptDao.class); deptDao3.updateDept(new Dept(1,\"ali\",\"hz\")); sqlSession3.commit(); // 判断第二个 SqlSession 是否从缓存中读取 dept2 = deptDao2.findByDeptNo(1); System.out.println(\"dept2 = \" + dept2);} 对应的输出结果如下 ​ 探究多表操作对二级缓存的影响 现有这样一个场景,有两个表,部门表dept(deptNo,dname,loc)和 部门数量表deptNum(id,name,num),其中部门表的名称和部门数量表的名称相同,通过名称能够联查两个表可以知道其坐标(loc)和数量(num),现在我要对部门数量表的 num 进行更新,然后我再次关联dept 和 deptNum 进行查询,你认为这个 SQL 语句能够查询到的 num 的数量是多少?来看一下代码探究一下 12345678public class DeptNum { private int id; private String name; private int num; get and set...} 12345678910111213141516171819202122public class DeptVo { private Integer deptNo; private String dname; private String loc; private Integer num; public DeptVo(Integer deptNo, String dname, String loc, Integer num) { this.deptNo = deptNo; this.dname = dname; this.loc = loc; this.num = num; } public DeptVo(String dname, Integer num) { this.dname = dname; this.num = num; } get and set... toString()...} 12345678910public interface DeptDao { // ...其他方法 DeptVo selectByDeptVo(String name); DeptVo selectByDeptVoName(String name); int updateDeptVoNum(DeptVo deptVo);} 12345678910111213<select id=\"selectByDeptVo\" resultType=\"com.mybatis.beans.DeptVo\"> select d.deptno,d.dname,d.loc,dn.num from dept d,deptNum dn where dn.name = d.dname and d.dname = #{name}</select><select id=\"selectByDeptVoName\" resultType=\"com.mybatis.beans.DeptVo\"> select * from deptNum where name = #{name}</select><update id=\"updateDeptVoNum\" parameterType=\"com.mybatis.beans.DeptVo\"> update deptNum set num = #{num} where name = #{dname}</update> DeptNum 数据库初始值: 12345678910111213141516171819202122/** * 探究多表操作对二级缓存的影响 */@Testpublic void testOtherMapper(){ // 第一个mapper 先执行联查操作 SqlSession sqlSession = factory.openSession(); DeptDao deptDao = sqlSession.getMapper(DeptDao.class); DeptVo deptVo = deptDao.selectByDeptVo(\"ali\"); System.out.println(\"deptVo = \" + deptVo); // 第二个mapper 执行更新操作 并提交 SqlSession sqlSession2 = factory.openSession(); DeptDao deptDao2 = sqlSession2.getMapper(DeptDao.class); deptDao2.updateDeptVoNum(new DeptVo(\"ali\",1000)); sqlSession2.commit(); sqlSession2.close(); // 第一个mapper 再次进行查询,观察查询结果 deptVo = deptDao.selectByDeptVo(\"ali\"); System.out.println(\"deptVo = \" + deptVo);} 测试结果如下: 在对DeptNum 表执行了一次更新后,再次进行联查,发现数据库中查询出的还是 num 为 1050 的值,也就是说,实际上 1050 -> 1000 ,最后一次联查实际上查询的是第一次查询结果的缓存,而不是从数据库中查询得到的值,这样就读到了脏数据。 解决办法 如果是两个mapper命名空间的话,可以使用 <cache-ref>来把一个命名空间指向另外一个命名空间,从而消除上述的影响,再次执行,就可以查询到正确的数据 二级缓存源码解析 源码模块主要分为两个部分:二级缓存的创建和二级缓存的使用,首先先对二级缓存的创建进行分析: 二级缓存的创建 二级缓存的创建是使用 Resource 读取 XML 配置文件开始的 1234InputStream is = Resources.getResourceAsStream(\"myBatis-config.xml\");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();factory = builder.build(is); 读取配置文件后,需要对XML创建 Configuration并初始化 123XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);return build(parser.parse()); 调用 parser.parse() 解析根目录 /configuration 下面的标签,依次进行解析 123456789public Configuration parse() { if (parsed) { throw new BuilderException(\"Each XMLConfigBuilder can only be used once.\"); } parsed = true; parseConfiguration(parser.evalNode(\"/configuration\")); return configuration;} 12345678910111213141516171819202122private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode(\"properties\")); Properties settings = settingsAsProperties(root.evalNode(\"settings\")); loadCustomVfs(settings); typeAliasesElement(root.evalNode(\"typeAliases\")); pluginElement(root.evalNode(\"plugins\")); objectFactoryElement(root.evalNode(\"objectFactory\")); objectWrapperFactoryElement(root.evalNode(\"objectWrapperFactory\")); reflectorFactoryElement(root.evalNode(\"reflectorFactory\")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode(\"environments\")); databaseIdProviderElement(root.evalNode(\"databaseIdProvider\")); typeHandlerElement(root.evalNode(\"typeHandlers\")); mapperElement(root.evalNode(\"mappers\")); } catch (Exception e) { throw new BuilderException(\"Error parsing SQL Mapper Configuration. Cause: \" + e, e); }} 其中有一个二级缓存的解析就是 12mapperElement(root.evalNode(\"mappers\")); 然后进去 mapperElement 方法中 123XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); 继续跟 mapperParser.parse() 方法 123456789101112public void parse() { if (!configuration.isResourceLoaded(resource)) { configurationElement(parser.evalNode(\"/mapper\")); configuration.addLoadedResource(resource); bindMapperForNamespace(); } parsePendingResultMaps(); parsePendingCacheRefs(); parsePendingStatements();} 这其中有一个 configurationElement 方法,它是对二级缓存进行创建,如下 12345678910111213141516171819private void configurationElement(XNode context) { try { String namespace = context.getStringAttribute(\"namespace\"); if (namespace == null || namespace.equals(\"\")) { throw new BuilderException(\"Mapper's namespace cannot be empty\"); } builderAssistant.setCurrentNamespace(namespace); cacheRefElement(context.evalNode(\"cache-ref\")); cacheElement(context.evalNode(\"cache\")); parameterMapElement(context.evalNodes(\"/mapper/parameterMap\")); resultMapElements(context.evalNodes(\"/mapper/resultMap\")); sqlElement(context.evalNodes(\"/mapper/sql\")); buildStatementFromContext(context.evalNodes(\"select|insert|update|delete\")); } catch (Exception e) { throw new BuilderException(\"Error parsing Mapper XML. Cause: \" + e, e); }} 有两个二级缓存的关键点 123cacheRefElement(context.evalNode(\"cache-ref\"));cacheElement(context.evalNode(\"cache\")); 也就是说,mybatis 首先进行解析的是 cache-ref 标签,其次进行解析的是 cache 标签。 根据上面我们的 — 多表操作对二级缓存的影响 一节中提到的解决办法,采用 cache-ref 来进行命名空间的依赖能够避免二级缓存,但是总不能每次写一个 XML 配置都会采用这种方式吧,最有效的方式还是避免多表操作使用二级缓存 然后我们再来看一下cacheElement(context.evalNode(“cache”)) 这个方法 123456789101112131415private void cacheElement(XNode context) throws Exception { if (context != null) { String type = context.getStringAttribute(\"type\", \"PERPETUAL\"); Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type); String eviction = context.getStringAttribute(\"eviction\", \"LRU\"); Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction); Long flushInterval = context.getLongAttribute(\"flushInterval\"); Integer size = context.getIntAttribute(\"size\"); boolean readWrite = !context.getBooleanAttribute(\"readOnly\", false); boolean blocking = context.getBooleanAttribute(\"blocking\", false); Properties props = context.getChildrenAsProperties(); builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props); }} 认真看一下其中的属性的解析,是不是感觉很熟悉?这不就是对 cache 标签属性的解析吗?!!! 上述最后一句代码 12builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props); 123456789101112131415161718192021public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) { Cache cache = new CacheBuilder(currentNamespace) .implementation(valueOrDefault(typeClass, PerpetualCache.class)) .addDecorator(valueOrDefault(evictionClass, LruCache.class)) .clearInterval(flushInterval) .size(size) .readWrite(readWrite) .blocking(blocking) .properties(props) .build(); configuration.addCache(cache); currentCache = cache; return cache; } 这段代码使用了构建器模式,一步一步构建Cache 标签的所有属性,最终把 cache 返回。 二级缓存的使用 在 mybatis 中,使用 Cache 的地方在 CachingExecutor中,来看一下 CachingExecutor 中缓存做了什么工作,我们以查询为例 1234567891011121314151617181920212223@Overridepublic <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { // 得到缓存 Cache cache = ms.getCache(); if (cache != null) { // 如果需要的话刷新缓存 flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, parameterObject, boundSql); @SuppressWarnings(\"unchecked\") List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } // 委托模式,交给SimpleExecutor等实现类去实现方法。 return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);} 其中,先从 MapperStatement 取出缓存。只有通过,或@CacheNamespace,@CacheNamespaceRef标记使用缓存的Mapper.xml或Mapper接口(同一个namespace,不能同时使用)才会有二级缓存。 如果缓存不为空,说明是存在缓存。如果cache存在,那么会根据sql配置(<insert>,<select>,<update>,<delete>的flushCache属性来确定是否清空缓存。 12flushCacheIfRequired(ms); 然后根据xml配置的属性useCache来判断是否使用缓存(resultHandler一般使用的默认值,很少会null)。 12if (ms.isUseCache() && resultHandler == null) 确保方法没有Out类型的参数,mybatis不支持存储过程的缓存,所以如果是存储过程,这里就会报错。 12345678910private void ensureNoOutParams(MappedStatement ms, Object parameter, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { if (parameterMapping.getMode() != ParameterMode.IN) { throw new ExecutorException(\"Caching stored procedures with OUT params is not supported. Please configure useCache=false in \" + ms.getId() + \" statement.\"); } } }} 然后根据在 TransactionalCacheManager 中根据 key 取出缓存,如果没有缓存,就会执行查询,并且将查询结果放到缓存中并返回取出结果,否则就执行真正的查询方法。 1234567List<E> list = (List<E>) tcm.getObject(cache, key);if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116}return list; 是否应该使用二级缓存? 那么究竟应该不应该使用二级缓存呢?先来看一下二级缓存的注意事项: 缓存是以namespace为单位的,不同namespace下的操作互不影响。 insert,update,delete操作会清空所在namespace下的全部缓存。 通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。 多表操作一定不要使用二级缓存,因为多表操作进行更新操作,一定会产生脏数据。 如果你遵守二级缓存的注意事项,那么你就可以使用二级缓存。 但是,如果不能使用多表操作,二级缓存不就可以用一级缓存来替换掉吗?而且二级缓存是表级缓存,开销大,没有一级缓存直接使用 HashMap 来存储的效率更高,所以二级缓存并不推荐使用。 文章来源.","link":"/database/mysql/MyBatis%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98.html"},{"title":"Vim基本入门操作","text":"简介 Vim(Vi[Improved])编辑器是功能强大的跨平台文本文件编辑工具,继承自Unix系统的Vi编辑器,支持Linux/Mac OS X/Windows系统,利用它可以建立、修改文本文件。进入Vim编辑程序,可以在终端输入下面的命令: 1$vim [filename] 其中filename是要编辑器的文件的路径名。如果文件不存在,它将为你建立一个新文件。Vim编辑程序有三种操作模式,分别称为 编辑模式、插入模式 和 命令模式,当运行Vim时,首先进入编辑模式。 编辑模式Vim编辑方式的主要用途是在被编辑的文件中移动光标的位置。一旦光标移到到所要的位置,就可以进行剪切和粘贴正文块,删除正文和插入新的正文。当完成所有的编辑工作后,需要保存编辑器结果,退出编辑程序回到终端,可以发出ZZ命令,连续按两次大写的Z键。 跳转如果键盘上有上、下、左、右箭头的导航键,就由这些键来完成光标的移动。另外,可以用下面的键完成同样的 按字符移动 功能: 1234k 上移;j 下移;h 左移;l 右移。 上面这4个键将光标位置每次移动一行或一个 字符 。Vim还提供稍大范围移动光标的命令: 12ctrl+f 在文件中前移一页(相当于 page down);ctrl+b 在文件中后移一页(相当于 page up); 更大范围的移动:gg 起始位置, G最后一行,g_本行最后 123456789101112* 当光标停留在一个单词上,* 键会在文件内搜索该单词,并跳转到下一处;# 当光标停留在一个单词上,# 在文件内搜索该单词,并跳转到上一处;(/) 移动到 前/后 句 的开始;{/} 跳转到 当前/下一个 段落 的开始。g_ 到本行最后一个不是 blank 字符的位置。fa 到下一个为 a 的字符处,你也可以fs到下一个为s的字符。t, 到逗号前的第一个字符。逗号可以变成其它字符。3fa 在当前行查找第三个出现的 a。F/T 和 f 和 t 一样,只不过是相反方向;gg 将光标定位到文件第一行起始位置;G 将光标定位到文件最后一行起始位置;NG或Ngg 将光标定位到第 N 行的起始位置。 在屏幕中找到需要的 一页 时,可以用下面的命令快速移动光标:H起始行,M中间行,L最后行 123H 将光标移到屏幕上的起始行(或最上行);M 将光标移到屏幕中间;L 将光标移到屏幕最后一行。 同样需要注意字母的大小写。H 和 L 命令还可以加数字。如 2H 表示将光标移到屏幕的第2行,3L 表示将光标移到屏幕的倒数第3行。 当将光标移到所要的行是,行内移动 光标可以用下面的命令来实现:&末尾,^行头 123456w 右移光标到下一个字的开头;e 右移光标到一个字的末尾;b 左移光标到前一个字的开头;0 数字0,左移光标到本行的开始;$ 右移光标,到本行的末尾;^ 移动光标,到本行的第一个非空字符。 2.2 搜索匹配和许多先进的编辑器一样,Vim 提供了强大的字符串搜索功能。要查找文件中指定字或短语出现的位置,可以用Vim直接进行搜索,而不必以手工方式进行。搜索方法是:键入字符 / ,后面跟以要搜索的字符串,然后按回车键。编辑程序执行正向搜索(即朝文件末尾方向),并在找到指定字符串后,将光标停到该字符串的开头;键入 n 命令可以继续执行搜索,找出这一字符串下次出现的位置。用字符 ? 取代 / ,可以实现反向搜索。例如:/str ,n下次出现,n上次出现 1234/str1 正向搜索字符串 str1;n 继续搜索,找出 str1 字符串下次出现的位置;N 继续搜索,找出 str1 字符串上一次出现的位置;?str2 反向搜索字符串 str2 。 无论搜索方向如何,当到达文件末尾或开头时,搜索工作会循环到文件的另一端并继续执行。 Vim中执行搜索匹配最强大的地方是结合 正则表达式 来搜索,后续将会介绍。 2.3 替换和删除Vim常规的删除命令是 d、 x (前者删除 行 ,后者删除 字符 ),结合Vim的其他特性可以实现基础的删除功能。将光标定位于文件内指定位置后,可以用其他字符来替换光标所指向的字符,或从当前光标位置删除一个或多个字符或一行、多行。例如: 123456789101112131415rc 用 c 替换光标所指向的当前字符;nrc 用 c 替换光标所指向的前 n 个字符;5rA 用 A 替换光标所指向的前 5 个字符;x 删除光标所指向的当前字符;nx 删除光标所指向的前 n 个字符;3x 删除光标所指向的前 3 个字符;dw 删除光标右侧的字;ndw 删除光标右侧的 n 个字;3dw 删除光标右侧的 3 个字;db 删除光标左侧的字;ndb 删除光标左侧的 n 个字;5db 删除光标左侧的 5 个字;dd 删除光标所在行,并去除空隙;ndd 删除(剪切) n 行内容,并去除空隙;3dd 删除(剪切) 3 行内容,并去除空隙; 其他常用的删除命令有:d$删到行尾,d0删到行首,J合并下行 123d$ 从当前光标起删除字符直到行的结束;d0 从当前光标起删除字符直到行的开始;J 删除本行的回车符(CR),并和下一行合并。 Vim常规的替换命令有 c 和 s ,结合Vim的其他特性可以实现基础的替换功能,不过替换命令执行以后,通常会由 编辑模式 进入 插入模式 : 12345678910111213s 用输入的正文替换光标所指向的字符;S 删除当前行,并进入插入模式;ns 用输入的正文替换光标右侧 n 个字符;nS 删除当前行在内的 n 行,并进入插入模式;cw 用输入的正文替换光标右侧的字;cW 用输入的正文替换从光标到行尾的所有字符(同 c$ );ncw 用输入的正文替换光标右侧的 n 个字;cb 用输入的正文替换光标左侧的字;ncb 用输入的正文替换光标左侧的 n 个字;cd 用输入的正文替换光标的所在行;ncd 用输入的正文替换光标下面的 n 行;c$ 用输入的正文替换从光标开始到本行末尾的所有字符;c0 用输入的正文替换从本行开头到光标的所有字符。 2.4 复制粘贴从正文中删除的内容(如字符、字或行)并没有真正丢失,而是被剪切并复制到了一个内存缓冲区中。用户可将其粘贴到正文中的指定位置。完成这一操作的命令是:p粘到后面,P粘到前面 12p 小写字母 p,将缓冲区的内容粘贴到光标的后面;P 大写字母 P,将缓冲区的内容粘贴到光标的前面。 如果缓冲区的内容是字符或字,直接粘贴在光标的前面或后面;如果缓冲区的内容为整行正文,执行上述粘贴命令将会粘贴在当前光标所在行的上一行或下一行。 注意上述两个命令中字母的大小写。Vim 编辑器经常以一对大、小写字母(如 p 和 P)来提供一对相似的功能。通常,小写命令在光标的后面进行操作,大写命令在光标的前面进行操作。 有时需要复制一段正文到新位置,同时保留原有位置的内容。这种情况下,首先应当把指定内容复制(而不是剪切)到内存缓冲区。完成这一操作的命令是:yy 复制一行,nyy 复制n行 12345yy 复制当前行到内存缓冲区;nyy 复制 n 行内容到内存缓冲区;5yy 复制 5 行内容到内存缓冲区;“+y 复制 1 行到操作系统的粘贴板;“+nyy 复制 n 行到操作系统的粘贴板。 2.5 撤销和重复在编辑文档的过程中,为消除某个错误的编辑命令造成的后果,可以用撤消命令。另外,如果用户希望在新的光标位置重复前面执行过的编辑命令,可用重复命令。u撤销前一条,.重复最后一条命令 12u 撤消前一条命令的结果;. 重复最后一条修改正文的命令。 3. 插入模式3.1 进入插入模式在编辑模式下正确定位光标之后,可用以下命令切换到插入模式:i左,a右,o下一行,O上一行,I光标开头,A末尾 123456i 在光标左侧插入正文a 在光标右侧插入正文o 在光标所在行的下一行增添新行O 在光标所在行的上一行增添新行I 在光标所在行的开头插入A 在光标所在行的末尾插入 3.2 退出插入模式退出插入模式的方法是,按 ESC 键或组合键 Ctrl+[ ,退出插入模式之后,将会进入编辑模式 。 4. 命令模式在Vim的命令模式下,可以使用复杂的命令。在编辑模式下键入 : ,光标就跳到屏幕最后一行,并在那里显示冒号,此时已进入命令模式。命令模式又称 末行模式 ,用户输入的内容均显示在屏幕的最后一行,按回车键,Vim 执行命令。 4.1 打开、保存、退出在已经启动的Vim中打开一个文件需要用 :e 命令: 1:e path_to_file/filename 保存当前编辑的文件需要用 :w 命令(单词 write 的缩写): 1:w 将当前文件另存为 file_temp 则: 1:w file_temp 在编辑模式下可以用 ZZ 命令退出Vim编辑程序,该命令保存对正文所作的修改,覆盖原始文件。如果只需要退出编辑程序,而不打算保存编辑的内容,可用下面的命令: 12: q 在未作修改的情况下退出;: q! 放弃所有修改,退出编辑程序。 保存并退出则可以讲两条命令结合起来使用(注意命令顺序,先保存,后退出): 1:wq 4.2 行号与文件编辑中的每一行正文都有自己的行号,用下列命令可以移动光标到指定行(效果与 编辑模式 下的 ngg 或 nG 相同): 1: n 将光标移到第 n 行 命令模式下,可以规定命令操作的行号范围。数值用来指定绝对行号;字符“.”表示光标所在行的行号;字符符“$”表示正文最后一行的行号;简单的表达式,例如“.+5”表示当前行往下的第 5 行。例如: 1234567:345 将光标移到第 345 行:345w file 将第 345 行写入 file 文件:3,5w file 将第 3 行至第 5 行写入 file 文件:1,.w file 将第 1 行至当前行写入 file 文件:.,$w file 将当前行至最后一行写入 file 文件:.,.+5w file 从当前行开始将 6 行内容写入 file 文件:1,$w file 将所有内容写入 file 文件,相当于 :w file 命令 在命令模式下,允许从文件中读取正文,或将正文写入文件。例如: 12345678:w 将编辑的内容写入原始文件,用来保存编辑的中间结果:wq 将编辑的内容写入原始文件并退出编辑程序(相当于 ZZ 命令):w file 将编辑的内容写入 file 文件,保持原有文件的内容不变:a,bw file 将第 a 行至第 b 行的内容写入 file 文件:r file 读取 file 文件的内容,插入当前光标所在行的后面:e file 编辑新文件 file 代替原有内容:f file 将当前文件重命名为 file:f 打印当前文件名称和状态,如文件的行数、光标所在的行号等 4.3 字符串搜索在 编辑模式 讲过字符串的搜索,此处的 命令模式 也可以进行字符串搜索,给出一个字符串,可以通过搜索该字符串到达指定行。如果希望进行正向搜索,将待搜索的字符串置于两个 / 之间;如果希望反向搜索,则将字符串放在两个 ? 之间。例如: 1234:/str/ 正向搜索,将光标移到下一个包含字符串 str 的行:?str? 反向搜索,将光标移到上一个包含字符串 str 的行:/str/w file 正向搜索,并将第一个包含字符串 str 的行写入 file 文件:/str1/,/str2/w file 正向搜索,并将包含字符串 str1 的行至包含字符串 str2 的行写 4.4 Vim中的正则表达式当给Vim指定搜索字符串时,可以包含具有特殊含义的字符。包含这些特殊字符的搜索字符串称为正则表达式(Regular Expressions)。例如,要搜索一行正文,这行正文的开头包含 struct 字。下面的命令做不到这一点: 1:/struct/ 因为它只找出在行中任意位置包含 struct的第一行,并不一定在行的开始包含 struct 。解决问题的办法是在搜索字符串前面加上特殊字符^: 1:/^struct/ ^ 字符比较每行开头的字符串。所以上面的命令表示:找出以字符串 struct 开头的行。 也可以用类似办法在搜索字符串后面加上表示行的末尾的特殊字符 $ 来找出位于行末尾的字: 1:/^struct/ 下表给出大多数特殊字符和它们的含义: 12345678910^ 放在字符串前面,匹配行首的字;$ 放在字符串后面,匹配行尾的字;\\< 匹配一个字的字头;\\> 匹配一个字的字尾;. 匹配任何单个正文字符;[str] 匹配 str 中的任何单个字符;[^str] 匹配任何不在 str 中的单个字符;[a-b] 匹配 a 到 b 之间的任一字符;* 匹配前一个字符的 0 次或多次出现;\\ 转义后面的字符。 简单介绍这么多,正则表达式知识可以参考 《正则表达式30分钟入门》:http://deerchao.net/tutorials/regex/regex.htm 另外,进阶的Vim正则表达式还有对Magic 模式的介绍,可以参考 《Vim正则表达式详解》: http://blog.csdn.net/salc3k/article/details/8222397 4.5 正文替换利用 :s 命令可以实现字符串的替换。具体的用法包括: 123456:%s/str1/str2/ 用字符串 str2 替换行中首次出现的字符串 str1:s/str1/str2/g 用字符串 str2 替换行中所有出现的字符串 str1:.,$ s/str1/str2/g 用字符串 str2 替换正文当前行到末尾所有出现的字符串 str1:1,$ s/str1/str2/g 用字符串 str2 替换正文中所有出现的字符串 str1:g/str1/s//str2/g 功能同上:m,ns/str1/str2/g 将从m行到n行的str1替换成str2 从上述替换命令可以看到: 1`g` 放在命令末尾,表示对搜索字符串的每次出现进行替换,不止匹配每行中的第一次出现;不加 `g`,表示只对搜索字符串的首次出现进行替换;`g` 放在命令开头,表示对正文中所有包含搜索字符串的行进行替换操作; 1`s` 表示后面跟着一串替换的命令; 1`%` 表示替换范围是所有行,即全文。 另外一个实用的命令,在Vim中统计当前文件中字符串 str1 出现的次数,可用替换命令的变形: 1:%s/str1/&/gn 4.6 删除正文在命令模式下,同样可以删除正文中的内容。例如: 12345678:d 删除光标所在行:3d 删除 3 行:.,$d 删除当前行至正文的末尾:/str1/,/str2/d 删除从字符串 str1 到 str2 的所有行:g/^\\(.*\\)$\\n\\1$/d 删除连续相同的行,保留最后一行:g/\\%(^\\1$\\n\\)\\@<=\\(.*\\)$/d 删除连续相同的行,保留最开始一行:g/^\\s*$\\n\\s*$/d 删除连续多个空行,只保留一行空行:5,20s/^#//g 删除5到20行开头的 # 注释 总之,Vim的初级删除命令是用 d ,高级删除命令可以用 正则替换 的方式执行。 4.7 恢复文件Vim 在编辑某个文件时,会另外生成一个临时文件,这个文件的名称通常以 . 开头,并以 .swp 结尾。Vim 在正常退出时,该文件被删除,若意外退出,而没有保存文件的最新修改内容,则可以使用恢复命令 :recover 来恢复文件,也可以在启动Vim时用 -r 选项。 4.8 选项设置为控制不同的编辑功能,Vim 提供了很多内部选项。利用 :set 命令可以设置选项。基本语法为: 1:set option 设置选项 option 常见的功能选项包括: 123456autoindent 设置该选项,则正文自动缩进ignorecase 设置该选项,则忽略规则表达式中大小写字母的区别number 设置该选项,则显示正文行号ruler 设置该选项,则在屏幕底部显示光标所在行、列的位置tabstop 设置按 Tab 键跳过的空格数。例如 :set tabstop=n,n 默认值为 8mk 将选项保存在当前目录的 .exrc 文件中 4.9 Shell切换当处于编辑的对话过程中时,可能需要执行一些Linux命令。如果需要保存当前的结果,退出编辑程序,再执行所需的Linux命令,然后再回头继续编辑过程,就显得十分累赘。如果能在编辑的环境中运行Linux命令就要省事得多。在Vim中,可以用下面的命令来做到这一点: 1:!shell_command 执行完 shell_command 后回到Vim 这称为Shell切换。它允许执行任何可以在标准的Shell提示符下执行的命令。当这条命令执行完毕,控制返回给编辑程序。又可以继续编辑对话过程。 4.10 分屏与标签页分屏普通的Vim模式,打开一个Vim程序只能查看一个文件,如果想同时查看多个文件,就需要用到Vim分屏与标签页功能。 Vim的分屏,主要有两种方式:上下分屏(水平分屏)和左右分屏(垂直分屏),在命令模式分别敲入以下命令即可: :sp 上下分屏,:vsp左右分屏 12:split(可用缩写 :sp) 上下分屏;:vsplit(可用缩写 :vsp) 左右分屏。 另外,也可以在终端里启动vim时就开启分屏操作: 12vim -On file1 file2... 打开 file1 和 file2 ,垂直分屏vim -on file1 file2... 打开 file1 和 file2 ,水平分屏 理论上,一个Vim窗口,可以分为多个Vim屏幕,切换屏幕需要用键盘快捷键,命令分别有: 1234Ctrl+w+h 切换到当前分屏的左边一屏;Ctrl+w+l 切换到当前分屏的右边一屏;Ctrl+w+j 切换到当前分屏的下方一屏;Ctrl+w+k 切换到当前分屏的上方一屏。 即键盘上的h,j,k,l 四个Vim专用方向键,配合Ctrl键和w键(window的缩写),就能跳转到目标分屏。另外,也可以直接按 Ctrl+w+w 来跳转分屏,不过跳转方向则是在当前Vim窗口所有分屏中,按照逆时针方向跳转。 下面是改变尺寸的一些操作,主要是高度,对于宽度你可以使用 [Ctrl+W <] 或是 [Ctrl+W >] ,但这可能需要最新的版本才支持。 123Ctrl+W = 让所有的屏都有一样的高度;Ctrl+W + 增加高度;Ctrl+W - 减少高度。 标签页Vim的标签(Tab)页,类似浏览器的标签页,一个标签页打开一个Vim的窗口,一个Vim的窗口可以支持N个分屏。 在Vim中新建一个标签的命令是: 1:tabnew 如果要在新建标签页的同时打开一个文件,则可以在命令后面直接附带文件路径: 1:tabnew filename Vim中的每个标签页有一个唯一的数字序号,第一个标签页的序号是0,从左向右依次加一。关于标签页有一系列操作命令,简介如下: 1234567891011121314:tN[ext] 跳转到上一个匹配的标签:tabN[ext] 跳到上一个标签页:tabc[lose] 关闭当前标签页:tabdo 为每个标签页执行命令:tabe[dit] 在新标签页里编辑文件:tabf[ind] 寻找 'path' 里的文件,在新标签页里编辑之:tabfir[st] 转到第一个标签页:tabl[ast] 转到最后一个标签页:tabm[ove] N 把标签页移到序号为N位置:tabnew [filename] 在新标签页里编辑文件:tabn[ext] 转到下一个标签页:tabo[nly] 关闭所有除了当前标签页以外的所有标签页:tabp[revious] 转到前一个标签页:tabr[ewind] 转到第一个标签页 4.11 与外部工具集成Vim可以与许多外部程序集成,功能十分强大,比如 diff , ctags , sort , xxd 等等,下面选取几个简单介绍一下。 diffLinux命令 diff 用来对比两个文件的内容,不过对比结果显示在终端里,可读性比较差。结合Vim,在终端里可以直接输入命令 vimdiff,后面跟两个文件名作为参数: 1vimdiff file1 file2 即可在Vim里分屏显示两个文件内容的对比结果,对文件内容差异部分进行高亮标记,还可以同步滚动两个文件内容,更可以实时修改文件内容,方便程度和用户体验大大提高。 1vimdiff a.txt b.txt 如果直接给 -d 选项是一样的 1vim -d a.txt b.txt 除了在终端里开启vimdiff 功能,也可以在打开Vim后,在Vim的命令模式输入相关命令来开启 vimdiff 功能: 1:diffsplit abc.txt 如果你现在已经开启了一个文件,想Vim帮你区分你的文件跟 abc.txt 有什么区别,可以在Vim中用 diffsplit 的方式打开第二个文件,这个时 候Vim会用 split(分上下两屏)的方式开启第二个文件,并且通过颜色,fold来显示两个文件的区别 这样Vim就会用颜色帮你区分开2个文件的区别。如果文件比较大(源码)重复的部分会帮你折叠起来。 1:diffpatch filename 通过 :diffpatch 你的patch的文件名,就可以以当前文件加上你的patch来显示。vim会split一个新的屏,显示patch后的信息并且用颜色标明区别。 如果不喜欢上下对比,喜欢左右(比较符合视觉)可以在前面加 vert ,例如: 12:vert diffsplit abc.txt:vert diffpatch abc.txt 看完diff,用 :only 回到原本编辑的文件,觉得diff的讨厌颜色还是在哪里,只要用 :diffoff 关闭就好了。 还有个常用的diff中的就是 :diffu ,这个是 :diffupdate 的简写,更新的时候用。 Vim的diff功能显示效果如下所示: sortLinux命令 sort 可以对文本内容进行按行中的字符比较、排序,但在终端里使用 sort 命令处理文件,并不能实时查看文件内容。具体用法请自查手册。 xxdvim+xxd 是Linux下最常用的二进制文本编辑工具,xxd其实是Vim外部的一个转换程序,随Vim一起发布,在Vim里调用它来编辑二进制文本非常方便。 首先以二进制模式在终端里打开一个文件: 1vim -b filename Vim 的 -b 选项是告诉 Vim 打开的是一个二进制文件,不指定的话,会在后面加上 0x0a ,即一个换行符。 然后在Vim的命令模式下键入: 1:%!xxd 即可看到二进制模式显示出来的文本,看起来像这样: 1230000000: 1f8b 0808 39d7 173b 0203 7474 002b 4e49 ....9..;..tt.+NI 0000010: 4b2c 8660 eb9c ecac c462 eb94 345e 2e30 K,......b..4^.0 0000020: 373b 2731 0b22 0ca6 c1a2 d669 1035 39d9 7;'1.\".....i.59 然后就可以在二进制模式下编辑该文件,编辑后保存,然后用下面命令从二进制模式转换到普通模式: 1:%!xxd -r 另外,也可以调整二进制的显示模式,默认是 2 个字节为一组,可以通过 g 参数调整每组字节数: 123:%!xxd -g 1 表示每1个字节为1组 :%!xxd -g 2 表示每2个字节为1组(默认) :%!xxd -g 4 表示每4个字节为1组 5. Vim配置最初安装的Vim功能、特性支持比较少,用起来比较费劲,想要稍微“好用”一点,需做一些初步的配置。Vim的配置主要分为Vim本身特性的配置和外部插件的配置两部分。 Vim的配置是通常是存放在用户主目录的 .vimrc 的隐藏文件中的。就Vim本身特性来说,基础的配置有编程语言语法高亮、缩进设置、行号显示、搜索高亮、TAB键设置、字体设置、Vim主题设置等等,稍微高级一些的有编程语言缩进、自动补全设置等,具体配置项可以自行查资料,全面详细的配置项介绍可以参考: 《Vim Options》: http://vimcdoc.sourceforge.net/doc/options.html#%27completeopt%27 6. Vim插件Vim“编辑器之神”的称号并不是浪得虚名,然而,这个荣誉的背后,或许近半的功劳要归功于强大的插件支持特性,以及社区开发的各种各样功能强大的插件。 平时开发人员常用插件主要是目录(文件)查看和管理、编程语言缩进与自动补全、编程语言Docs支持、函数跳转、项目管理等等,简单配置可以参考下面: 《Vim插件简单介绍》: http://blog.segmentfault.com/xuelang/1190000000630547 《手把手教你把Vim改装成一个IDE编程环境(图文)》: http://blog.csdn.net/wooin/article/details/1858917 《将Vim改造为强大的IDE》: http://www.cnblogs.com/zhangsf/archive/2013/06/13/3134409.html 当然,这些插件都是拜Vim本身的插件支持特性所赐。Vim为了支持丰富的第三方插件,自身定义了一套简单的脚本开发语言,供程序员自行开发自己所需要的插件,插件开发介绍可以参考: 《Writing Vim Plugins》: http://stevelosh.com/blog/2011/09/writing-vim-plugins/ 7. Vim完整文档 Vim官方文档:http://vimdoc.sourceforge.net/ Vim中文用户手册7_3.pdf :http://pan.baidu.com/s/1jGzbTBo 文章来源 .","link":"/develop/Vim%E5%9F%BA%E6%9C%AC%E5%85%A5%E9%97%A8%E6%93%8D%E4%BD%9C.html"},{"title":"redis分布式锁Redlock的实现","text":"普通实现 说道Redis分布式锁大部分人都会想到:setnx+lua,或者知道set key value px milliseconds nx。后一种方式的核心实现命令如下: 123456789- 获取锁(unique_value可以是UUID等)SET resource_name unique_value NX PX 30000- 释放锁(lua脚本中,一定要比较value,防止误解锁)if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1])else return 0end 这种实现方式有3大要点(也是面试概率非常高的地方): set命令要用set key value px milliseconds nx; value要具有唯一性; 释放锁时要验证value值,不能误解锁; 事实上这类琐最大的缺点就是它加锁时只作用在一个Redis节点上,即使Redis通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况: 在Redis的master节点上拿到了锁; 但是这个加锁的key还没有同步到slave节点; master故障,发生故障转移,slave节点升级为master节点; 导致锁丢失。 正因为如此,Redis作者antirez基于分布式环境下提出了一种更高级的分布式锁的实现方式:Redlock。笔者认为,Redlock也是Redis所有分布式锁实现方式中唯一能让面试官高潮的方式。 Redlock实现antirez提出的redlock算法大概是这样的: 在Redis的分布式环境中,我们假设有N个Redis master。这些节点完全互相独立,不存在主从复制或者其他集群协调机制。我们确保将在N个实例上使用与在Redis单实例下相同方法获取和释放锁。现在我们假设有5个Redis master节点,同时我们需要在5台服务器上面运行这些Redis实例,这样保证他们不会同时都宕掉。 为了取到锁,客户端应该执行以下操作: 获取当前Unix时间,以毫秒为单位。 依次尝试从5个实例,使用相同的key和具有唯一性的value(例如UUID)获取锁。当向Redis请求获取锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试去另外一个Redis实例请求获取锁。 客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数(N/2+1,这里是3个节点)的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。 如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。 如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功,防止某些节点获取到锁但是客户端没有得到响应而导致接下来的一段时间不能被重新获取锁)。 Redlock源码redisson已经有对redlock算法封装,接下来对其用法进行简单介绍,并对核心源码进行分析(假设5个redis实例)。 POM依赖 123456<!-- https://mvnrepository.com/artifact/org.redisson/redisson --><dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.3.2</version></dependency> 用法首先,我们来看一下redission封装的redlock算法实现的分布式锁用法,非常简单,跟重入锁(ReentrantLock)有点类似: 1234567891011121314151617181920Config config = new Config();config.useSentinelServers().addSentinelAddress(\"127.0.0.1:6369\",\"127.0.0.1:6379\", \"127.0.0.1:6389\") .setMasterName(\"masterName\") .setPassword(\"password\").setDatabase(0);RedissonClient redissonClient = Redisson.create(config);// 还可以getFairLock(), getReadWriteLock()RLock redLock = redissonClient.getLock(\"REDLOCK_KEY\");boolean isLock;try { isLock = redLock.tryLock(); // 500ms拿不到锁, 就认为获取锁失败。10000ms即10s是锁失效时间。 isLock = redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS); if (isLock) { //TODO if get lock success, do something; }} catch (Exception e) {} finally { // 无论如何, 最后都要解锁 redLock.unlock();} 唯一ID实现分布式锁的一个非常重要的点就是set的value要具有唯一性,redisson的value是怎样保证value的唯一性呢?答案是UUID+threadId。入口在redissonClient.getLock(“REDLOCK_KEY”),源码在Redisson.java和RedissonLock.java中: 1234protected final UUID id = UUID.randomUUID();String getLockName(long threadId) { return id + \":\" + threadId;} 获取锁获取锁的代码为redLock.tryLock()或者redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS),两者的最终核心源码都是下面这段代码,只不过前者获取锁的默认租约时间(leaseTime)是LOCK_EXPIRATION_INTERVAL_SECONDS,即30s: 123456789101112131415161718192021<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) { internalLockLeaseTime = unit.toMillis(leaseTime); // 获取锁时向5个redis实例发送的命令 return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command, // 首先分布式锁的KEY不能存在,如果确实不存在,那么执行hset命令(hset REDLOCK_KEY uuid+threadId 1),并通过pexpire设置失效时间(也是锁的租约时间) \"if (redis.call('exists', KEYS[1]) == 0) then \" + \"redis.call('hset', KEYS[1], ARGV[2], 1); \" + \"redis.call('pexpire', KEYS[1], ARGV[1]); \" + \"return nil; \" + \"end; \" + // 如果分布式锁的KEY已经存在,并且value也匹配,表示是当前线程持有的锁,那么重入次数加1,并且设置失效时间 \"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then \" + \"redis.call('hincrby', KEYS[1], ARGV[2], 1); \" + \"redis.call('pexpire', KEYS[1], ARGV[1]); \" + \"return nil; \" + \"end; \" + // 获取分布式锁的KEY的失效时间毫秒数 \"return redis.call('pttl', KEYS[1]);\", // 这三个参数分别对应KEYS[1],ARGV[1]和ARGV[2] Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));} 获取锁的命令中, **KEYS[1]**就是Collections.singletonList(getName()),表示分布式锁的key,即REDLOCK_KEY; **ARGV[1]**就是internalLockLeaseTime,即锁的租约时间,默认30s; **ARGV[2]**就是getLockName(threadId),是获取锁时set的唯一值,即UUID+threadId: 释放锁释放锁的代码为redLock.unlock(),核心源码如下: 1234567891011121314151617181920212223242526272829protected RFuture<Boolean> unlockInnerAsync(long threadId) { // 向5个redis实例都执行如下命令 return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, // 如果分布式锁KEY不存在,那么向channel发布一条消息 \"if (redis.call('exists', KEYS[1]) == 0) then \" + \"redis.call('publish', KEYS[2], ARGV[1]); \" + \"return 1; \" + \"end;\" + // 如果分布式锁存在,但是value不匹配,表示锁已经被占用,那么直接返回 \"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then \" + \"return nil;\" + \"end; \" + // 如果就是当前线程占有分布式锁,那么将重入次数减1 \"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); \" + // 重入次数减1后的值如果大于0,表示分布式锁有重入过,那么只设置失效时间,还不能删除 \"if (counter > 0) then \" + \"redis.call('pexpire', KEYS[1], ARGV[2]); \" + \"return 0; \" + \"else \" + // 重入次数减1后的值如果为0,表示分布式锁只获取过1次,那么删除这个KEY,并发布解锁消息 \"redis.call('del', KEYS[1]); \" + \"redis.call('publish', KEYS[2], ARGV[1]); \" + \"return 1; \"+ \"end; \" + \"return nil;\", // 这5个参数分别对应KEYS[1],KEYS[2],ARGV[1],ARGV[2]和ARGV[3] Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId));} 文章来源 .","link":"/database/redis/redis%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81Redlock%E7%9A%84%E5%AE%9E%E7%8E%B0.html"},{"title":"中华人民共和国消费者权益保护法","text":"基本信息 发文字号:主席令第11号 效力级别:法律 时效性:已被修订 发布日期:1993-10-31 实施日期:1994-01-01 发布机关:全国人大常委会 法律修订 1993年10月31日第八届全国人民代表大会常务委员会第四次会议通过 中华人民共和国消费者权益保护法(2013修正) 中华人民共和国消费者权益保护法(2009修正) 正文 第一章 总则第一条 为保护消费者的合法权益,维护社会经济秩序,促进社会主义市场经济健康发展,制定本法。 第二条 消费者为生活消费需要购买、使用商品或者接受服务,其权益受本法保护;本法未作规定的,受其他有关法律、法规保护。 第三条 经营者为消费者提供其生产、销售的商品或者提供服务,应当遵守本法;本法未作出规定的,应当遵守其他有关法律、法规。 第四条 经营者与消费者进行交易,应当遵循自愿、平等、公平、诚实信用的原则。 第五条 国家保护消费者的合法权益不受侵害。 国家采取措施,保障消费者依法行使权利,维护消费者的合法权益。 第六条 保护消费者的合法权益是全社会的共同责任。 国家鼓励、支持一切组织和个人对损害消费者合法权益的行为进行社会监督。 大众传播媒介应当做好维护消费者合法权益的宣传,对损害消费者合法权益的行为进行舆论监督。 第二章 消费者的权利第七条 消费者在购买、使用商品和接受服务时享有人身、财产安全不受损害的权利。 消费者有权要求经营者提供的商品和服务,符合保障人身、财产安全的要求。 第八条 消费者享有知悉其购买、使用的商品或者接受的服务的真实情况的权利。 消费者有权根据商品或者服务的不同情况,要求经营者提供商品的价格、产地、生产者、用途、性能、规格、等级、主要成份、生产日期、有效期限、检验合格证明、使用方法说明书、售后服务,或者服务的内容、规格、费用等有关情况。 第九条 消费者享有自主选择商品或者服务的权利。 消费者有权自主选择提供商品或者服务的经营者,自主选择商品品种或者服务方式,自主决定购买或者不购买任何一种商品、接受或者不接受任何一项服务。 消费者在自主选择商品或者服务时,有权进行比较、鉴别和挑选。 第十条 消费者享有公平交易的权利。 消费者在购买商品或者接受服务时,有权获得质量保障、价格合理、计量正确等公平交易条件,有权拒绝经营者的强制交易行为。 第十一条 消费者因购买、使用商品或者接受服务受到人身、财产损害的,享有依法获得赔偿的权利。 第十二条 消费者享有依法成立维护自身合法权益的社会团体的权利。 第十三条 消费者享有获得有关消费和消费者权益保护方面的知识的权利。 消费者应当努力掌握所需商品或者服务的知识和使用技能,正确使用商品,提高自我保护意识。 第十四条 消费者在购买、使用商品和接受服务时,享有其人格尊严、民族风俗习惯得到尊重的权利。 第十五条 消费者享有对商品和服务以及保护消费者权益工作进行监督的权利。 消费者有权检举、控告侵害消费者权益的行为和国家机关及其工作人员在保护消费者权益工作中的违法失职行为,有权对保护消费者权益工作提出批评、建议。 第三章 经营者的义务第十六条 经营者向消费者提供商品或者服务,应当依照《中华人民共和国产品质量法》和其他有关法律、法规的规定履行义务。 经营者和消费者有约定的,应当按照约定履行义务,但双方的约定不得违背法律、法规的规定。 第十七条 经营者应当听取消费者对其提供的商品或者服务的意见,接受消费者的监督。 第十八条 经营者应当保证其提供的商品或者服务符合保障人身、财产安全的要求。对可能危及人身、财产安全的商品和服务,应当向消费者作出真实的说明和明确的警示,并说明和标明正确使用商品或者接受服务的方法以及防止危害发生的方法。 经营者发现其提供的商品或者服务存在严重缺陷,即使正确使用商品或者接受服务仍然可能对人身、财产安全造成危害的,应当立即向有关行政部门报告和告知消费者,并采取防止危害发生的措施。 第十九条 经营者应当向消费者提供有关商品或者服务的真实信息,不得作引人误解的虚假宣传。 经营者对消费者就其提供的商品或者服务的质量和使用方法等问题提出的询问,应当作为真实、明确的答复。 商店提供商品应当明码标价。 第二十条 经营者应当标明其真实名称和标记。 租赁他人柜台或者场地的经营者,应当标明其真实名称和标记。 第二十一条 经营者提供商品或者服务,应当按照国家有关规定或者商业惯例向消费者出具购货凭证或者服务单据;消费者索要购货凭证或者服务单据的,经营者必须出具。 第二十二条 经营者应当保证在正常使用商品或者接受服务的情况下其提供的商品或者服务应当具有的质量、性能、用途和有效期限;但消费者在购买该商品或者接受该服务前已经知道其存在瑕疵的除外。 经营者以广告、产品说明、实物样品或者其他方式表明商品或者服务的质量状况的,应当保证其提供的商品或者服务的实际质量与表明的质量状况相符。 第二十三条 经营者提供商品或者服务,按照国家规定或者与消费者的约定,承担包修、包换、包退或者其他责任的,应当按照国家规定或者约定履行,不得故意拖延或者无理拒绝。 第二十四条 经营者不得以格式合同、通知、声明、店堂告示等方式作出对消费者不公平、不合理的规定,或者减轻、免除其损害消费者合法权益应当承担的民事责任。 格式合同、通知、声明、店堂告示等含有前款所列内容的,其内容无效。 第二十五条 经营者不得对消费者进行侮辱、诽谤,不得搜查消费者的身体及其携带的物品,不得侵犯消费者的人身自由。 第四章 国家对消费者合法权益的保护第二十六条 国家制定有关消费者权益的法律、法规和政策时,应听取消费者的意见和要求。 第二十七条 各级人民政府应当加强领导,组织、协调、督促有关行政部门做好保护消费者合法权益的工作。 各级人民政府应当加强监督,预防危害消费者人身、财产安全行为的发生,及时制止危害消费者人身、财产安全的行为。 第二十八条 各级人民政府工商行政管理部门和其他有关行政部门应当依照法律、法规的规定,在各自的职责范围内,采取措施,保护消费者的合法权益。 有关行政部门应当听取消费者及其社会团体对经营者交易行为、商品和服务质量问题的意见,及时调查处理。 第二十九条 有关国家机关应当依照法律、法规的规定,惩处经营者在提供商品和服务中侵害消费者合法权益的违法犯罪行为。 第三十条 人民法院应当采取措施,方便消费者提起诉讼。对符合《中华人民共和国民事诉讼法》起诉条件的消费者权益争议,必须受理,及时审理。 第五章 消费者组织第三十一条 消费者协会和其他消费者组织是依法成立的对商品和服务进行社会监督的保护消费者合法权益的社会团体。 第三十二条 消费者协会履行下列职能: (一)向消费者提供消费信息和咨询服务; (二)参与有关行政部门对商品和服务的监督、检查; (三)就有关消费者合法权益的问题,向有关行政部门反映、查询,提出建议; (四)受理消费者的投诉,并对投诉事项进行调查、调解; (五)投诉事项涉及商品和服务质量问题的,可以提请鉴定部门鉴定,鉴定部门应当告知鉴定结论; (六)就损害消费者合法权益的行为,支持受损害的消费者提起诉讼; (七)对损害消费者合法权益的行为,通过大众传播媒介予以揭露、批评。 各级人民政府对消费者协会履行职能应当予以支持。 第三十三条 消费者组织不得从事商品经营和营利性服务,不得以牟利为目的向社会推荐商品和服务。 第六章 争议的解决第三十四条 消费者和经营者发生消费者权益争议的,可以通过下列途径解决: (一)与经营者协商和解; (二)请求消费者协会调解; (三)向有关行政部门申诉; (四)根据与经营者达成的仲裁协议提请仲裁机构仲裁; (五)向人民法院提起诉讼。 第三十五条 消费者在购买、使用商品时,其合法权益受到损害的,可以向销售者要求赔偿。销售者赔偿后,属于生产者的责任或者属于向销售者提供商品的其他销售者的责任的,销售者有权向生产者或者其他销售者追偿。 消费者或者其他受害人因商品缺陷造成人身、财产损害的,可以向销售者要求赔偿,也可以向生产者要求赔偿。属于生产者责任的,销售者赔偿后,有权向生产者追偿。属于销售者责任的,生产者赔偿后,有权向销售者追偿。 消费者在接受服务时,其合法权益受到损害的,可以向服务者要求赔偿。 第三十六条 消费者在购买、使用商品或者接受服务时,其合法权益受到损害,因原企业分立、合并的,可以向变更后承受其权利义务的企业要求赔偿。 第三十七条 使用他人营业执照的违法经营者提供商品或者服务,损害消费者合法权益的,消费者可以向其要求赔偿,也可以向营业执照的持有人要求赔偿。 第三十八条 消费者在展销会、租赁柜台购买商品或者接受服务,其合法权益受到损害的,可以向销售者或者服务者要求赔偿。展销会结束或者柜台租赁期满后,也可以向展销会的举办者、柜台的出租者要求赔偿。展销会的举办者、柜台的出租者赔偿后,有权向销售者或者服务者追偿。 第三十九条 消费者因经营者利用虚假广告提供商品或者服务,其合法权益受到损害的,可以向经营者要求赔偿。广告的经营者发布虚假广告的,消费者可以请求行政主管部门予以惩处。广告的经营者不得提供经营者的真实名称、地址的,应当承担赔偿责任。 第七章 法律责任第四十条 经营者提供商品或者服务有下列情形之一的,除本法另有规定外,应当依照《中华人民共和国产品质量法》和其他有关法律、法规的规定,承担民事责任: (一)商品存在缺陷的; (二)不具备商品应当具备的使用性能而出售时未作说明的; (三)不符合在商品或者其包装上注明采用的商品标准的; (四)不符合商品说明、实物样品等方式表明的质量状况的; (五)生产国家明令淘汰的商品或者销售失效、变质的商品的; (六)销售的商品数量不足的; (七)服务的内容和费用违反约定的; (八)对消费者提出的修理、重作、更换、退货、补足商品数量、退还货款和服务费用或者赔偿损失的要求,故意拖延或者无理拒绝的; (九)法律、法规规定的其他损害消费者权益的情形。 第四十一条 经营者提供商品或者服务,造成消费者或者其他受害人人身伤害的,应当支付医疗费、治疗期间的护理费、因误工减少的收入等费用,造成残疾的,还应当支付残疾者生活自助具费、生活补助费、残疾赔偿金以及由其扶养的人所必需的生活费等费用;构成犯罪的,依法追究刑事责任。 第四十二条 经营者提供商品或者服务,造成消费者或者其他受害人死亡的,应当支付丧葬费、死亡赔偿金以及由死者生前扶养的人所必需的生活费等费用;构成犯罪的,依法追究刑事责任。 第四十三条 经营者违反本法第二十五条规定,侵害消费者的人格尊严或者侵犯消费者人身自由的,应当停止侵害、恢复名誉、消除影响、赔礼道歉,并赔偿损失。 第四十四条 经营者提供商品或者服务,造成消费者财产损害的,应当按照消费者的要求,以修理、重作、更换、退货、补足商品数量、退还货款和服务费用或者赔偿损失等方式承担民事责任。消费者与经营者另有约定的,按照约定履行。 第四十五条 对国家规定或者经营者与消费者约定包修、包换、包退的商品,经营者应当负责修理、更换或者退货。在保修期内两次修理仍不能正常使用的,经营者应当负责更换或者退货。 对包修、包换、包退的大件商品,消费者要求经营者修理、更换、退货的,经营者应当承担运输等合理费用。 第四十六条 经营者以邮购方式提供商品的,应当按照约定提供。未按照约定提供的,应当按照消费者的要求履行约定或者退回货款;并应当承担消费者必须支付的合理费用。 第四十七条 经营者以预收款方式提供商品或者服务的,应当按照约定提供。未按照约定提供的,应当按照消费者的要求履行约定或者退回预付款;并应当承担预付款的利息、消费者必须支付的合理费用。 第四十八条 依法经有关行政部门认定为不合格的商品,消费者要求退货的,经营者应当负责退货。 第四十九条 经营者提供商品或者服务有欺诈行为的,应当按照消费者的要求增加赔偿其受到的损失,增加赔偿的金额为消费者购买商品的价款或者接受服务的费用的一倍。 第五十条 经营者有下列情形之一,《中华人民共和国产品质量法》和其他有关法律、法规对处罚机关和处罚方式有规定的,依照法律、法规的规定执行;法律、法规未作规定的,由工商行政管理部门责令改正,可以根据情节单处或者并处警告、没收违法所得、处以违法所得一倍以上五倍以下的罚款,没有违法所得的处以一万元以下的罚款;情节严重的,责令停业整顿、吊销营业执照: (一)生产、销售的商品不符合保障人身、财产安全要求的; (二)在商品中掺杂、掺假,以假充真,以次充好,或者以不合格商品冒充合格商品的; (三)生产国家明令淘汰的商品或者销售失效、变质的商品的; (四)伪造商品的产地,伪造或者冒用他人的厂名、厂址,伪造或者冒用认证标志、名优标志等质量标志的; (五)销售的商品应当检验、检疫而未检验、检疫或者伪造检验、检疫结果的; (六)对商品或者服务作引人误解的虚假宣传的; (七)对消费者提出的修理、重作、更换、退货、补足商品数量、退还货款和服务费用或者赔偿损失的要求,故意拖延或者无理拒绝的; (八)侵害消费者人格尊严或者侵犯消费者人身自由的; (九)法律、法规规定的对损害消费者权益应当予以处罚的其他情形。 第五十一条 经营者对行政处罚决定不服的,可以自收到处罚决定之日起十五日内向上一级机关申请复议,对复议决定不服的,可以自收到复议决定书之日起十五日内向人民法院提起诉讼;也可以直接向人民法院提起诉讼。 第五十二条 以暴力、威胁等方法阻碍有关行政部门工作人员依法执行职务的,依法追究刑事责任;拒绝、阻碍有关行政部门工作人员依法执行职务,未使用暴力、威胁方法的,由公安机关依照《中华人民共和国治安管理处罚条例》的规定处罚。 第五十三条 国家机关工作人员玩忽职守或者包庇经营者侵害消费者合法权益的行为的,由其所在单位或者上级机关给予行政处分;情节严重,构成犯罪的,依法追究刑事责任。 第八章 附则第五十四条 农民购买、使用直接用于农业生产的生产资料,参照本法执行。 第五十五条 本法自1994年1月1日起施行。","link":"/law/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E6%B6%88%E8%B4%B9%E8%80%85%E6%9D%83%E7%9B%8A%E4%BF%9D%E6%8A%A4%E6%B3%95.html"},{"title":"中华人民共和国刑事诉讼法","text":"基本信息 发文字号:中华人民共和国主席令第十号 效力级别法律:时效性现行有效 发布日期:2018-10-26 实施日期:2018-10-26 发布机关:全国人大常委会 法律修订 1979年7月1日第五届全国人民代表大会第二次会议通过 根据1996年3月17日第八届全国人民代表大会第四次会议《关于修改〈中华人民共和国刑事诉讼法〉的决定》第一次修正 根据2012年3月14日第十一届全国人民代表大会第五次会议《关于修改〈中华人民共和国刑事诉讼法〉的决定》第二次修正 根据2018年10月26日第十三届全国人民代表大会常务委员会第六次会议《关于修改〈中华人民共和国刑事诉讼法〉的决定》第三次修正 中华人民共和国刑事诉讼法(2012修正) 中华人民共和国刑事诉讼法(1996修正) 中华人民共和国刑事诉讼法(1979修正) 正文 第一编 总 则第一章 任务和基本原则第一条 为了保证刑法的正确实施,惩罚犯罪,保护人民,保障国家安全和社会公共安全,维护社会主义社会秩序,根据宪法,制定本法。 第二条 中华人民共和国刑事诉讼法的任务,是保证准确、及时地查明犯罪事实,正确应用法律,惩罚犯罪分子,保障无罪的人不受刑事追究,教育公民自觉遵守法律,积极同犯罪行为作斗争,维护社会主义法制,尊重和保障人权,保护公民的人身权利、财产权利、民主权利和其他权利,保障社会主义建设事业的顺利进行。 第三条 对刑事案件的侦查、拘留、执行逮捕、预审,由公安机关负责。检察、批准逮捕、检察机关直接受理的案件的侦查、提起公诉,由人民检察院负责。审判由人民法院负责。除法律特别规定的以外,其他任何机关、团体和个人都无权行使这些权力。 人民法院、人民检察院和公安机关进行刑事诉讼,必须严格遵守本法和其他法律的有关规定。 第四条 国家安全机关依照法律规定,办理危害国家安全的刑事案件,行使与公安机关相同的职权。 第五条 人民法院依照法律规定独立行使审判权,人民检察院依照法律规定独立行使检察权,不受行政机关、社会团体和个人的干涉。 第六条 人民法院、人民检察院和公安机关进行刑事诉讼,必须依靠群众,必须以事实为根据,以法律为准绳。对于一切公民,在适用法律上一律平等,在法律面前,不允许有任何特权。 第七条 人民法院、人民检察院和公安机关进行刑事诉讼,应当分工负责,互相配合,互相制约,以保证准确有效地执行法律。 第八条 人民检察院依法对刑事诉讼实行法律监督。 第九条 各民族公民都有用本民族语言文字进行诉讼的权利。人民法院、人民检察院和公安机关对于不通晓当地通用的语言文字的诉讼参与人,应当为他们翻译。 在少数民族聚居或者多民族杂居的地区,应当用当地通用的语言进行审讯,用当地通用的文字发布判决书、布告和其他文件。 第十条 人民法院审判案件,实行两审终审制。 第十一条 人民法院审判案件,除本法另有规定的以外,一律公开进行。被告人有权获得辩护,人民法院有义务保证被告人获得辩护。 第十二条 未经人民法院依法判决,对任何人都不得确定有罪。 第十三条 人民法院审判案件,依照本法实行人民陪审员陪审的制度。 第十四条 人民法院、人民检察院和公安机关应当保障犯罪嫌疑人、被告人和其他诉讼参与人依法享有的辩护权和其他诉讼权利。 诉讼参与人对于审判人员、检察人员和侦查人员侵犯公民诉讼权利和人身侮辱的行为,有权提出控告。 第十五条 犯罪嫌疑人、被告人自愿如实供述自己的罪行,承认指控的犯罪事实,愿意接受处罚的,可以依法从宽处理。 第十六条 有下列情形之一的,不追究刑事责任,已经追究的,应当撤销案件,或者不起诉,或者终止审理,或者宣告无罪: (一)情节显著轻微、危害不大,不认为是犯罪的; (二)犯罪已过追诉时效期限的; (三)经特赦令免除刑罚的; (四)依照刑法告诉才处理的犯罪,没有告诉或者撤回告诉的; (五)犯罪嫌疑人、被告人死亡的; (六)其他法律规定免予追究刑事责任的。 第十七条 对于外国人犯罪应当追究刑事责任的,适用本法的规定。 对于享有外交特权和豁免权的外国人犯罪应当追究刑事责任的,通过外交途径解决。 第十八条 根据中华人民共和国缔结或者参加的国际条约,或者按照互惠原则,我国司法机关和外国司法机关可以相互请求刑事司法协助。 第二章 管 辖第十九条 刑事案件的侦查由公安机关进行,法律另有规定的除外。 人民检察院在对诉讼活动实行法律监督中发现的司法工作人员利用职权实施的非法拘禁、刑讯逼供、非法搜查等侵犯公民权利、损害司法公正的犯罪,可以由人民检察院立案侦查。对于公安机关管辖的国家机关工作人员利用职权实施的重大犯罪案件,需要由人民检察院直接受理的时候,经省级以上人民检察院决定,可以由人民检察院立案侦查。 自诉案件,由人民法院直接受理。 第二十条 基层人民法院管辖第一审普通刑事案件,但是依照本法由上级人民法院管辖的除外。 第二十一条 中级人民法院管辖下列第一审刑事案件: (一)危害国家安全、恐怖活动案件; (二)可能判处无期徒刑、死刑的案件。 第二十二条 高级人民法院管辖的第一审刑事案件,是全省(自治区、直辖市)性的重大刑事案件。 第二十三条 最高人民法院管辖的第一审刑事案件,是全国性的重大刑事案件。 第二十四条 上级人民法院在必要的时候,可以审判下级人民法院管辖的第一审刑事案件;下级人民法院认为案情重大、复杂需要由上级人民法院审判的第一审刑事案件,可以请求移送上一级人民法院审判。 第二十五条 刑事案件由犯罪地的人民法院管辖。如果由被告人居住地的人民法院审判更为适宜的,可以由被告人居住地的人民法院管辖。 第二十六条 几个同级人民法院都有权管辖的案件,由最初受理的人民法院审判。在必要的时候,可以移送主要犯罪地的人民法院审判。 第二十七条 上级人民法院可以指定下级人民法院审判管辖不明的案件,也可以指定下级人民法院将案件移送其他人民法院审判。 第二十八条 专门人民法院案件的管辖另行规定。 第三章 回 避第二十九条 审判人员、检察人员、侦查人员有下列情形之一的,应当自行回避,当事人及其法定代理人也有权要求他们回避: (一)是本案的当事人或者是当事人的近亲属的; (二)本人或者他的近亲属和本案有利害关系的; (三)担任过本案的证人、鉴定人、辩护人、诉讼代理人的; (四)与本案当事人有其他关系,可能影响公正处理案件的。 第三十条 审判人员、检察人员、侦查人员不得接受当事人及其委托的人的请客送礼,不得违反规定会见当事人及其委托的人。 审判人员、检察人员、侦查人员违反前款规定的,应当依法追究法律责任。当事人及其法定代理人有权要求他们回避。 第三十一条 审判人员、检察人员、侦查人员的回避,应当分别由院长、检察长、公安机关负责人决定;院长的回避,由本院审判委员会决定;检察长和公安机关负责人的回避,由同级人民检察院检察委员会决定。 对侦查人员的回避作出决定前,侦查人员不能停止对案件的侦查。 对驳回申请回避的决定,当事人及其法定代理人可以申请复议一次。 第三十二条 本章关于回避的规定适用于书记员、翻译人员和鉴定人。 辩护人、诉讼代理人可以依照本章的规定要求回避、申请复议。 第四章 辩护与代理第三十三条 犯罪嫌疑人、被告人除自己行使辩护权以外,还可以委托一至二人作为辩护人。下列的人可以被委托为辩护人: (一)律师; (二)人民团体或者犯罪嫌疑人、被告人所在单位推荐的人; (三)犯罪嫌疑人、被告人的监护人、亲友。 正在被执行刑罚或者依法被剥夺、限制人身自由的人,不得担任辩护人。 被开除公职和被吊销律师、公证员执业证书的人,不得担任辩护人,但系犯罪嫌疑人、被告人的监护人、近亲属的除外。 第三十四条 犯罪嫌疑人自被侦查机关第一次讯问或者采取强制措施之日起,有权委托辩护人;在侦查期间,只能委托律师作为辩护人。被告人有权随时委托辩护人。 侦查机关在第一次讯问犯罪嫌疑人或者对犯罪嫌疑人采取强制措施的时候,应当告知犯罪嫌疑人有权委托辩护人。人民检察院自收到移送审查起诉的案件材料之日起三日以内,应当告知犯罪嫌疑人有权委托辩护人。人民法院自受理案件之日起三日以内,应当告知被告人有权委托辩护人。犯罪嫌疑人、被告人在押期间要求委托辩护人的,人民法院、人民检察院和公安机关应当及时转达其要求。 犯罪嫌疑人、被告人在押的,也可以由其监护人、近亲属代为委托辩护人。 辩护人接受犯罪嫌疑人、被告人委托后,应当及时告知办理案件的机关。 第三十五条 犯罪嫌疑人、被告人因经济困难或者其他原因没有委托辩护人的,本人及其近亲属可以向法律援助机构提出申请。对符合法律援助条件的,法律援助机构应当指派律师为其提供辩护。 犯罪嫌疑人、被告人是盲、聋、哑人,或者是尚未完全丧失辨认或者控制自己行为能力的精神病人,没有委托辩护人的,人民法院、人民检察院和公安机关应当通知法律援助机构指派律师为其提供辩护。 犯罪嫌疑人、被告人可能被判处无期徒刑、死刑,没有委托辩护人的,人民法院、人民检察院和公安机关应当通知法律援助机构指派律师为其提供辩护。 第三十六条 法律援助机构可以在人民法院、看守所等场所派驻值班律师。犯罪嫌疑人、被告人没有委托辩护人,法律援助机构没有指派律师为其提供辩护的,由值班律师为犯罪嫌疑人、被告人提供法律咨询、程序选择建议、申请变更强制措施、对案件处理提出意见等法律帮助。 人民法院、人民检察院、看守所应当告知犯罪嫌疑人、被告人有权约见值班律师,并为犯罪嫌疑人、被告人约见值班律师提供便利。 第三十七条 辩护人的责任是根据事实和法律,提出犯罪嫌疑人、被告人无罪、罪轻或者减轻、免除其刑事责任的材料和意见,维护犯罪嫌疑人、被告人的诉讼权利和其他合法权益。 第三十八条 辩护律师在侦查期间可以为犯罪嫌疑人提供法律帮助;代理申诉、控告;申请变更强制措施;向侦查机关了解犯罪嫌疑人涉嫌的罪名和案件有关情况,提出意见。 第三十九条 辩护律师可以同在押的犯罪嫌疑人、被告人会见和通信。其他辩护人经人民法院、人民检察院许可,也可以同在押的犯罪嫌疑人、被告人会见和通信。 辩护律师持律师执业证书、律师事务所证明和委托书或者法律援助公函要求会见在押的犯罪嫌疑人、被告人的,看守所应当及时安排会见,至迟不得超过四十八小时。 危害国家安全犯罪、恐怖活动犯罪案件,在侦查期间辩护律师会见在押的犯罪嫌疑人,应当经侦查机关许可。上述案件,侦查机关应当事先通知看守所。 辩护律师会见在押的犯罪嫌疑人、被告人,可以了解案件有关情况,提供法律咨询等;自案件移送审查起诉之日起,可以向犯罪嫌疑人、被告人核实有关证据。辩护律师会见犯罪嫌疑人、被告人时不被监听。 辩护律师同被监视居住的犯罪嫌疑人、被告人会见、通信,适用第一款、第三款、第四款的规定。 第四十条 辩护律师自人民检察院对案件审查起诉之日起,可以查阅、摘抄、复制本案的案卷材料。其他辩护人经人民法院、人民检察院许可,也可以查阅、摘抄、复制上述材料。 第四十一条 辩护人认为在侦查、审查起诉期间公安机关、人民检察院收集的证明犯罪嫌疑人、被告人无罪或者罪轻的证据材料未提交的,有权申请人民检察院、人民法院调取。 第四十二条 辩护人收集的有关犯罪嫌疑人不在犯罪现场、未达到刑事责任年龄、属于依法不负刑事责任的精神病人的证据,应当及时告知公安机关、人民检察院。 第四十三条 辩护律师经证人或者其他有关单位和个人同意,可以向他们收集与本案有关的材料,也可以申请人民检察院、人民法院收集、调取证据,或者申请人民法院通知证人出庭作证。 辩护律师经人民检察院或者人民法院许可,并且经被害人或者其近亲属、被害人提供的证人同意,可以向他们收集与本案有关的材料。 第四十四条 辩护人或者其他任何人,不得帮助犯罪嫌疑人、被告人隐匿、毁灭、伪造证据或者串供,不得威胁、引诱证人作伪证以及进行其他干扰司法机关诉讼活动的行为。 违反前款规定的,应当依法追究法律责任,辩护人涉嫌犯罪的,应当由办理辩护人所承办案件的侦查机关以外的侦查机关办理。辩护人是律师的,应当及时通知其所在的律师事务所或者所属的律师协会。 第四十五条 在审判过程中,被告人可以拒绝辩护人继续为他辩护,也可以另行委托辩护人辩护。 第四十六条 公诉案件的被害人及其法定代理人或者近亲属,附带民事诉讼的当事人及其法定代理人,自案件移送审查起诉之日起,有权委托诉讼代理人。自诉案件的自诉人及其法定代理人,附带民事诉讼的当事人及其法定代理人,有权随时委托诉讼代理人。 人民检察院自收到移送审查起诉的案件材料之日起三日以内,应当告知被害人及其法定代理人或者其近亲属、附带民事诉讼的当事人及其法定代理人有权委托诉讼代理人。人民法院自受理自诉案件之日起三日以内,应当告知自诉人及其法定代理人、附带民事诉讼的当事人及其法定代理人有权委托诉讼代理人。 第四十七条 委托诉讼代理人,参照本法第三十三条的规定执行。 第四十八条 辩护律师对在执业活动中知悉的委托人的有关情况和信息,有权予以保密。但是,辩护律师在执业活动中知悉委托人或者其他人,准备或者正在实施危害国家安全、公共安全以及严重危害他人人身安全的犯罪的,应当及时告知司法机关。 第四十九条 辩护人、诉讼代理人认为公安机关、人民检察院、人民法院及其工作人员阻碍其依法行使诉讼权利的,有权向同级或者上一级人民检察院申诉或者控告。人民检察院对申诉或者控告应当及时进行审查,情况属实的,通知有关机关予以纠正。 第五章 证 据第五十条 可以用于证明案件事实的材料,都是证据。 证据包括: (一)物证; (二)书证; (三)证人证言; (四)被害人陈述; (五)犯罪嫌疑人、被告人供述和辩解; (六)鉴定意见; (七)勘验、检查、辨认、侦查实验等笔录; (八)视听资料、电子数据。 证据必须经过查证属实,才能作为定案的根据。 第五十一条 公诉案件中被告人有罪的举证责任由人民检察院承担,自诉案件中被告人有罪的举证责任由自诉人承担。 第五十二条 审判人员、检察人员、侦查人员必须依照法定程序,收集能够证实犯罪嫌疑人、被告人有罪或者无罪、犯罪情节轻重的各种证据。严禁刑讯逼供和以威胁、引诱、欺骗以及其他非法方法收集证据,不得强迫任何人证实自己有罪。必须保证一切与案件有关或者了解案情的公民,有客观地充分地提供证据的条件,除特殊情况外,可以吸收他们协助调查。 第五十三条 公安机关提请批准逮捕书、人民检察院起诉书、人民法院判决书,必须忠实于事实真象。故意隐瞒事实真象的,应当追究责任。 第五十四条 人民法院、人民检察院和公安机关有权向有关单位和个人收集、调取证据。有关单位和个人应当如实提供证据。 行政机关在行政执法和查办案件过程中收集的物证、书证、视听资料、电子数据等证据材料,在刑事诉讼中可以作为证据使用。 对涉及国家秘密、商业秘密、个人隐私的证据,应当保密。 凡是伪造证据、隐匿证据或者毁灭证据的,无论属于何方,必须受法律追究。 第五十五条 对一切案件的判处都要重证据,重调查研究,不轻信口供。只有被告人供述,没有其他证据的,不能认定被告人有罪和处以刑罚;没有被告人供述,证据确实、充分的,可以认定被告人有罪和处以刑罚。 证据确实、充分,应当符合以下条件: (一)定罪量刑的事实都有证据证明; (二)据以定案的证据均经法定程序查证属实; (三)综合全案证据,对所认定事实已排除合理怀疑。 第五十六条 采用刑讯逼供等非法方法收集的犯罪嫌疑人、被告人供述和采用暴力、威胁等非法方法收集的证人证言、被害人陈述,应当予以排除。收集物证、书证不符合法定程序,可能严重影响司法公正的,应当予以补正或者作出合理解释;不能补正或者作出合理解释的,对该证据应当予以排除。 在侦查、审查起诉、审判时发现有应当排除的证据的,应当依法予以排除,不得作为起诉意见、起诉决定和判决的依据。 第五十七条 人民检察院接到报案、控告、举报或者发现侦查人员以非法方法收集证据的,应当进行调查核实。对于确有以非法方法收集证据情形的,应当提出纠正意见;构成犯罪的,依法追究刑事责任。 第五十八条 法庭审理过程中,审判人员认为可能存在本法第五十六条规定的以非法方法收集证据情形的,应当对证据收集的合法性进行法庭调查。 当事人及其辩护人、诉讼代理人有权申请人民法院对以非法方法收集的证据依法予以排除。申请排除以非法方法收集的证据的,应当提供相关线索或者材料。 第五十九条 在对证据收集的合法性进行法庭调查的过程中,人民检察院应当对证据收集的合法性加以证明。 现有证据材料不能证明证据收集的合法性的,人民检察院可以提请人民法院通知有关侦查人员或者其他人员出庭说明情况;人民法院可以通知有关侦查人员或者其他人员出庭说明情况。有关侦查人员或者其他人员也可以要求出庭说明情况。经人民法院通知,有关人员应当出庭。 第六十条 对于经过法庭审理,确认或者不能排除存在本法第五十六条规定的以非法方法收集证据情形的,对有关证据应当予以排除。 第六十一条 证人证言必须在法庭上经过公诉人、被害人和被告人、辩护人双方质证并且查实以后,才能作为定案的根据。法庭查明证人有意作伪证或者隐匿罪证的时候,应当依法处理。 第六十二条 凡是知道案件情况的人,都有作证的义务。 生理上、精神上有缺陷或者年幼,不能辨别是非、不能正确表达的人,不能作证人。 第六十三条 人民法院、人民检察院和公安机关应当保障证人及其近亲属的安全。 对证人及其近亲属进行威胁、侮辱、殴打或者打击报复,构成犯罪的,依法追究刑事责任;尚不够刑事处罚的,依法给予治安管理处罚。 第六十四条 对于危害国家安全犯罪、恐怖活动犯罪、黑社会性质的组织犯罪、毒品犯罪等案件,证人、鉴定人、被害人因在诉讼中作证,本人或者其近亲属的人身安全面临危险的,人民法院、人民检察院和公安机关应当采取以下一项或者多项保护措施: (一)不公开真实姓名、住址和工作单位等个人信息; (二)采取不暴露外貌、真实声音等出庭作证措施; (三)禁止特定的人员接触证人、鉴定人、被害人及其近亲属; (四)对人身和住宅采取专门性保护措施; (五)其他必要的保护措施。 证人、鉴定人、被害人认为因在诉讼中作证,本人或者其近亲属的人身安全面临危险的,可以向人民法院、人民检察院、公安机关请求予以保护。 人民法院、人民检察院、公安机关依法采取保护措施,有关单位和个人应当配合。 第六十五条 证人因履行作证义务而支出的交通、住宿、就餐等费用,应当给予补助。证人作证的补助列入司法机关业务经费,由同级政府财政予以保障。 有工作单位的证人作证,所在单位不得克扣或者变相克扣其工资、奖金及其他福利待遇。 第六章 强制措施第六十六条 人民法院、人民检察院和公安机关根据案件情况,对犯罪嫌疑人、被告人可以拘传、取保候审或者监视居住。 第六十七条 人民法院、人民检察院和公安机关对有下列情形之一的犯罪嫌疑人、被告人,可以取保候审: (一)可能判处管制、拘役或者独立适用附加刑的; (二)可能判处有期徒刑以上刑罚,采取取保候审不致发生社会危险性的; (三)患有严重疾病、生活不能自理,怀孕或者正在哺乳自己婴儿的妇女,采取取保候审不致发生社会危险性的; (四)羁押期限届满,案件尚未办结,需要采取取保候审的。 取保候审由公安机关执行。 第六十八条 人民法院、人民检察院和公安机关决定对犯罪嫌疑人、被告人取保候审,应当责令犯罪嫌疑人、被告人提出保证人或者交纳保证金。 第六十九条 保证人必须符合下列条件: (一)与本案无牵连; (二)有能力履行保证义务; (三)享有政治权利,人身自由未受到限制; (四)有固定的住处和收入。 第七十条 保证人应当履行以下义务: (一)监督被保证人遵守本法第七十一条的规定; (二)发现被保证人可能发生或者已经发生违反本法第七十一条规定的行为的,应当及时向执行机关报告。 被保证人有违反本法第七十一条规定的行为,保证人未履行保证义务的,对保证人处以罚款,构成犯罪的,依法追究刑事责任。 第七十一条 被取保候审的犯罪嫌疑人、被告人应当遵守以下规定: (一)未经执行机关批准不得离开所居住的市、县; (二)住址、工作单位和联系方式发生变动的,在二十四小时以内向执行机关报告; (三)在传讯的时候及时到案; (四)不得以任何形式干扰证人作证; (五)不得毁灭、伪造证据或者串供。 人民法院、人民检察院和公安机关可以根据案件情况,责令被取保候审的犯嫌疑人、被告人遵守以下一项或者多项规定: (一)不得进入特定的场所; (二)不得与特定的人员会见或者通信; (三)不得从事特定的活动; (四)将护照等出入境证件、驾驶证件交执行机关保存。 被取保候审的犯罪嫌疑人、被告人违反前两款规定,已交纳保证金的,没收部分或者全部保证金,并且区别情形,责令犯罪嫌疑人、被告人具结悔过,重新交纳保证金、提出保证人,或者监视居住、予以逮捕。 对违反取保候审规定,需要予以逮捕的,可以对犯罪嫌疑人、被告人先行拘留。 第七十二条 取保候审的决定机关应当综合考虑保证诉讼活动正常进行的需要,被取保候审人的社会危险性,案件的性质、情节,可能判处刑罚的轻重,被取保候审人的经济状况等情况,确定保证金的数额。 提供保证金的人应当将保证金存入执行机关指定银行的专门账户。 第七十三条 犯罪嫌疑人、被告人在取保候审期间未违反本法第七十一条规定的,取保候审结束的时候,凭解除取保候审的通知或者有关法律文书到银行领取退还的保证金。 第七十四条 人民法院、人民检察院和公安机关对符合逮捕条件,有下列情形之一的犯罪嫌疑人、被告人,可以监视居住: (一)患有严重疾病、生活不能自理的; (二)怀孕或者正在哺乳自己婴儿的妇女; (三)系生活不能自理的人的唯一扶养人; (四)因为案件的特殊情况或者办理案件的需要,采取监视居住措施更为适宜的; (五)羁押期限届满,案件尚未办结,需要采取监视居住措施的。 对符合取保候审条件,但犯罪嫌疑人、被告人不能提出保证人,也不交纳保证金的,可以监视居住。 监视居住由公安机关执行。 第七十五条 监视居住应当在犯罪嫌疑人、被告人的住处执行;无固定住处的,可以在指定的居所执行。对于涉嫌危害国家安全犯罪、恐怖活动犯罪,在住处执行可能有碍侦查的,经上一级公安机关批准,也可以在指定的居所执行。但是,不得在羁押场所、专门的办案场所执行。 指定居所监视居住的,除无法通知的以外,应当在执行监视居住后二十四小时以内,通知被监视居住人的家属。 被监视居住的犯罪嫌疑人、被告人委托辩护人,适用本法第三十四条的规定。 人民检察院对指定居所监视居住的决定和执行是否合法实行监督。 第七十六条 指定居所监视居住的期限应当折抵刑期。被判处管制的,监视居住一日折抵刑期一日;被判处拘役、有期徒刑的,监视居住二日折抵刑期一日。 第七十七条 被监视居住的犯罪嫌疑人、被告人应当遵守以下规定: (一)未经执行机关批准不得离开执行监视居住的处所; (二)未经执行机关批准不得会见他人或者通信; (三)在传讯的时候及时到案; (四)不得以任何形式干扰证人作证; (五)不得毁灭、伪造证据或者串供; (六)将护照等出入境证件、身份证件、驾驶证件交执行机关保存。 被监视居住的犯罪嫌疑人、被告人违反前款规定,情节严重的,可以予以逮捕;需要予以逮捕的,可以对犯罪嫌疑人、被告人先行拘留。 第七十八条 执行机关对被监视居住的犯罪嫌疑人、被告人,可以采取电子监控、不定期检查等监视方法对其遵守监视居住规定的情况进行监督;在侦查期间,可以对被监视居住的犯罪嫌疑人的通信进行监控。 第七十九条 人民法院、人民检察院和公安机关对犯罪嫌疑人、被告人取保候审最长不得超过十二个月,监视居住最长不得超过六个月。 在取保候审、监视居住期间,不得中断对案件的侦查、起诉和审理。对于发现不应当追究刑事责任或者取保候审、监视居住期限届满的,应当及时解除取保候审、监视居住。解除取保候审、监视居住,应当及时通知被取保候审、监视居住人和有关单位。 第八十条 逮捕犯罪嫌疑人、被告人,必须经过人民检察院批准或者人民法院决定,由公安机关执行。 第八十一条 对有证据证明有犯罪事实,可能判处徒刑以上刑罚的犯罪嫌疑人、被告人,采取取保候审尚不足以防止发生下列社会危险性的,应当予以逮捕: (一)可能实施新的犯罪的; (二)有危害国家安全、公共安全或者社会秩序的现实危险的; (三)可能毁灭、伪造证据,干扰证人作证或者串供的; (四)可能对被害人、举报人、控告人实施打击报复的; (五)企图自杀或者逃跑的。 批准或者决定逮捕,应当将犯罪嫌疑人、被告人涉嫌犯罪的性质、情节,认罪认罚等情况,作为是否可能发生社会危险性的考虑因素。 对有证据证明有犯罪事实,可能判处十年有期徒刑以上刑罚的,或者有证据证明有犯罪事实,可能判处徒刑以上刑罚,曾经故意犯罪或者身份不明的,应当予以逮捕。 被取保候审、监视居住的犯罪嫌疑人、被告人违反取保候审、监视居住规定,情节严重的,可以予以逮捕。 第八十二条 公安机关对于现行犯或者重大嫌疑分子,如果有下列情形之一的,可以先行拘留: (一)正在预备犯罪、实行犯罪或者在犯罪后即时被发觉的; (二)被害人或者在场亲眼看见的人指认他犯罪的; (三)在身边或者住处发现有犯罪证据的; (四)犯罪后企图自杀、逃跑或者在逃的; (五)有毁灭、伪造证据或者串供可能的; (六)不讲真实姓名、住址,身份不明的; (七)有流窜作案、多次作案、结伙作案重大嫌疑的。 第八十三条 公安机关在异地执行拘留、逮捕的时候,应当通知被拘留、逮捕人所在地的公安机关,被拘留、逮捕人所在地的公安机关应当予以配合。 第八十四条 对于有下列情形的人,任何公民都可以立即扭送公安机关、人民检察院或者人民法院处理: (一)正在实行犯罪或者在犯罪后即时被发觉的; (二)通缉在案的; (三)越狱逃跑的; (四)正在被追捕的。 第八十五条 公安机关拘留人的时候,必须出示拘留证。 拘留后,应当立即将被拘留人送看守所羁押,至迟不得超过二十四小时。除无法通知或者涉嫌危害国家安全犯罪、恐怖活动犯罪通知可能有碍侦查的情形以外,应当在拘留后二十四小时以内,通知被拘留人的家属。有碍侦查的情形消失以后,应当立即通知被拘留人的家属。 第八十六条 公安机关对被拘留的人,应当在拘留后的二十四小时以内进行讯问。在发现不应当拘留的时候,必须立即释放,发给释放证明。 第八十七条 公安机关要求逮捕犯罪嫌疑人的时候,应当写出提请批准逮捕书,连同案卷材料、证据,一并移送同级人民检察院审查批准。必要的时候,人民检察院可以派人参加公安机关对于重大案件的讨论。 第八十八条 人民检察院审查批准逮捕,可以讯问犯罪嫌疑人;有下列情形之一的,应当讯问犯罪嫌疑人: (一)对是否符合逮捕条件有疑问的; (二)犯罪嫌疑人要求向检察人员当面陈述的; (三)侦查活动可能有重大违法行为的。 人民检察院审查批准逮捕,可以询问证人等诉讼参与人,听取辩护律师的意见;辩护律师提出要求的,应当听取辩护律师的意见。 第八十九条 人民检察院审查批准逮捕犯罪嫌疑人由检察长决定。重大案件应当提交检察委员会讨论决定。 第九十条 人民检察院对于公安机关提请批准逮捕的案件进行审查后,应当根据情况分别作出批准逮捕或者不批准逮捕的决定。对于批准逮捕的决定,公安机关应当立即执行,并且将执行情况及时通知人民检察院。对于不批准逮捕的,人民检察院应当说明理由,需要补充侦查的,应当同时通知公安机关。 第九十一条 公安机关对被拘留的人,认为需要逮捕的,应当在拘留后的三日以内,提请人民检察院审查批准。在特殊情况下,提请审查批准的时间可以延长一日至四日。 对于流窜作案、多次作案、结伙作案的重大嫌疑分子,提请审查批准的时间可以延长至三十日。 人民检察院应当自接到公安机关提请批准逮捕书后的七日以内,作出批准逮捕或者不批准逮捕的决定。人民检察院不批准逮捕的,公安机关应当在接到通知后立即释放,并且将执行情况及时通知人民检察院。对于需要继续侦查,并且符合取保候审、监视居住条件的,依法取保候审或者监视居住。 第九十二条 公安机关对人民检察院不批准逮捕的决定,认为有错误的时候,可以要求复议,但是必须将被拘留的人立即释放。如果意见不被接受,可以向上一级人民检察院提请复核。上级人民检察院应当立即复核,作出是否变更的决定,通知下级人民检察院和公安机关执行。 第九十三条 公安机关逮捕人的时候,必须出示逮捕证。 逮捕后,应当立即将被逮捕人送看守所羁押。除无法通知的以外,应当在逮捕后二十四小时以内,通知被逮捕人的家属。 第九十四条 人民法院、人民检察院对于各自决定逮捕的人,公安机关对于经人民检察院批准逮捕的人,都必须在逮捕后的二十四小时以内进行讯问。在发现不应当逮捕的时候,必须立即释放,发给释放证明。 第九十五条 犯罪嫌疑人、被告人被逮捕后,人民检察院仍应当对羁押的必要性进行审查。对不需要继续羁押的,应当建议予以释放或者变更强制措施。有关机关应当在十日以内将处理情况通知人民检察院。 第九十六条 人民法院、人民检察院和公安机关如果发现对犯罪嫌疑人、被告人采取强制措施不当的,应当及时撤销或者变更。公安机关释放被逮捕的人或者变更逮捕措施的,应当通知原批准的人民检察院。 第九十七条 犯罪嫌疑人、被告人及其法定代理人、近亲属或者辩护人有权申请变更强制措施。人民法院、人民检察院和公安机关收到申请后,应当在三日以内作出决定;不同意变更强制措施的,应当告知申请人,并说明不同意的理由。 第九十八条 犯罪嫌疑人、被告人被羁押的案件,不能在本法规定的侦查羁押、审查起诉、一审、二审期限内办结的,对犯罪嫌疑人、被告人应当予以释放;需要继续查证、审理的,对犯罪嫌疑人、被告人可以取保候审或者监视居住。 第九十九条 人民法院、人民检察院或者公安机关对被采取强制措施法定期限届满的犯罪嫌疑人、被告人,应当予以释放、解除取保候审、监视居住或者依法变更强制措施。犯罪嫌疑人、被告人及其法定代理人、近亲属或者辩护人对于人民法院、人民检察院或者公安机关采取强制措施法定期限届满的,有权要求解除强制措施。 第一百条 人民检察院在审查批准逮捕工作中,如果发现公安机关的侦查活动有违法情况,应当通知公安机关予以纠正,公安机关应当将纠正情况通知人民检察院。 第七章 附带民事诉讼第一百零一条 被害人由于被告人的犯罪行为而遭受物质损失的,在刑事诉讼过程中,有权提起附带民事诉讼。被害人死亡或者丧失行为能力的,被害人的法定代理人、近亲属有权提起附带民事诉讼。 如果是国家财产、集体财产遭受损失的,人民检察院在提起公诉的时候,可以提起附带民事诉讼。 第一百零二条 人民法院在必要的时候,可以采取保全措施,查封、扣押或者冻结被告人的财产。附带民事诉讼原告人或者人民检察院可以申请人民法院采取保全措施。人民法院采取保全措施,适用民事诉讼法的有关规定。 第一百零三条 人民法院审理附带民事诉讼案件,可以进行调解,或者根据物质损失情况作出判决、裁定。 第一百零四条 附带民事诉讼应当同刑事案件一并审判,只有为了防止刑事案件审判的过分迟延,才可以在刑事案件审判后,由同一审判组织继续审理附带民事诉讼。 第八章 期间、送达第一百零五条 期间以时、日、月计算。 期间开始的时和日不算在期间以内。 法定期间不包括路途上的时间。上诉状或者其他文件在期满前已经交邮的,不算过期。 期间的最后一日为节假日的,以节假日后的第一日为期满日期,但犯罪嫌疑人、被告人或者罪犯在押期间,应当至期满之日为止,不得因节假日而延长。 第一百零六条 当事人由于不能抗拒的原因或者有其他正当理由而耽误期限的,在障碍消除后五日以内,可以申请继续进行应当在期满以前完成的诉讼活动。 前款申请是否准许,由人民法院裁定。 第一百零七条 送达传票、通知书和其他诉讼文件应当交给收件人本人;如果本人不在,可以交给他的成年家属或者所在单位的负责人员代收。 收件人本人或者代收人拒绝接收或者拒绝签名、盖章的时候,送达人可以邀请他的邻居或者其他见证人到场,说明情况,把文件留在他的住处,在送达证上记明拒绝的事由、送达的日期,由送达人签名,即认为已经送达。 第九章 其他规定第一百零八条 本法下列用语的含意是: (一)“侦查”是指公安机关、人民检察院对于刑事案件,依照法律进行的收集证据、查明案情的工作和有关的强制性措施; (二)“当事人”是指被害人、自诉人、犯罪嫌疑人、被告人、附带民事诉讼的原告人和被告人; (三)“法定代理人”是指被代理人的父母、养父母、监护人和负有保护责任的机关、团体的代表; (四)“诉讼参与人”是指当事人、法定代理人、诉讼代理人、辩护人、证人、鉴定人和翻译人员; (五)“诉讼代理人”是指公诉案件的被害人及其法定代理人或者近亲属、自诉案件的自诉人及其法定代理人委托代为参加诉讼的人和附带民事诉讼的当事人及其法定代理人委托代为参加诉讼的人; (六)“近亲属”是指夫、妻、父、母、子、女、同胞兄弟姊妹。 第二编 立案、侦查和提起公诉第一章 立案第一百零九条 公安机关或者人民检察院发现犯罪事实或者犯罪嫌疑人,应当按照管辖范围,立案侦查。 第一百一十条 任何单位和个人发现有犯罪事实或者犯罪嫌疑人,有权利也有义务向公安机关、人民检察院或者人民法院报案或者举报。 被害人对侵犯其人身、财产权利的犯罪事实或者犯罪嫌疑人,有权向公安机关、人民检察院或者人民法院报案或者控告。 公安机关、人民检察院或者人民法院对于报案、控告、举报,都应当接受。对于不属于自己管辖的,应当移送主管机关处理,并且通知报案人、控告人、举报人;对于不属于自己管辖而又必须采取紧急措施的,应当先采取紧急措施,然后移送主管机关。 犯罪人向公安机关、人民检察院或者人民法院自首的,适用第三款规定。 第一百一十一条 报案、控告、举报可以用书面或者口头提出。接受口头报案、控告、举报的工作人员,应当写成笔录,经宣读无误后,由报案人、控告人、举报人签名或者盖章。 接受控告、举报的工作人员,应当向控告人、举报人说明诬告应负的法律责任。但是,只要不是捏造事实,伪造证据,即使控告、举报的事实有出入,甚至是错告的,也要和诬告严格加以区别。 公安机关、人民检察院或者人民法院应当保障报案人、控告人、举报人及其近亲属的安全。报案人、控告人、举报人如果不愿公开自己的姓名和报案、控告、举报的行为,应当为他保守秘密。 第一百一十二条 人民法院、人民检察院或者公安机关对于报案、控告、举报和自首的材料,应当按照管辖范围,迅速进行审查,认为有犯罪事实需要追究刑事责任的时候,应当立案;认为没有犯罪事实,或者犯罪事实显著轻微,不需要追究刑事责任的时候,不予立案,并且将不立案的原因通知控告人。控告人如果不服,可以申请复议。 第一百一十三条 人民检察院认为公安机关对应当立案侦查的案件而不立案侦查的,或者被害人认为公安机关对应当立案侦查的案件而不立案侦查,向人民检察院提出的,人民检察院应当要求公安机关说明不立案的理由。人民检察院认为公安机关不立案理由不能成立的,应当通知公安机关立案,公安机关接到通知后应当立案。 第一百一十四条 对于自诉案件,被害人有权向人民法院直接起诉。被害人死亡或者丧失行为能力的,被害人的法定代理人、近亲属有权向人民法院起诉。人民法院应当依法受理。 第二章 侦查第一百一十五条 公安机关对已经立案的刑事案件,应当进行侦查,收集、调取犯罪嫌疑人有罪或者无罪、罪轻或者罪重的证据材料。对现行犯或者重大嫌疑分子可以依法先行拘留,对符合逮捕条件的犯罪嫌疑人,应当依法逮捕。 第一百一十六条 公安机关经过侦查,对有证据证明有犯罪事实的案件,应当进行预审,对收集、调取的证据材料予以核实。 第一百一十七条 当事人和辩护人、诉讼代理人、利害关系人对于司法机关及其工作人员有下列行为之一的,有权向该机关申诉或者控告 (一)采取强制措施法定期限届满,不予以释放、解除或者变更的; (二)应当退还取保候审保证金不退还的; (三)对与案件无关的财物采取查封、扣押、冻结措施的; (四)应当解除查封、扣押、冻结不解除的; (五)贪污、挪用、私分、调换、违反规定使用查封、扣押、冻结的财物的。 受理申诉或者控告的机关应当及时处理。对处理不服的,可以向同级人民检察院申诉;人民检察院直接受理的案件,可以向上一级人民检察院申诉。人民检察院对申诉应当及时进行审查,情况属实的,通知有关机关予以纠正。 第一百一十八条 讯问犯罪嫌疑人必须由人民检察院或者公安机关的侦查人员负责进行。讯问的时候,侦查人员不得少于二人。 犯罪嫌疑人被送交看守所羁押以后,侦查人员对其进行讯问,应当在看守所内进行。 第一百一十九条 对不需要逮捕、拘留的犯罪嫌疑人,可以传唤到犯罪嫌疑人所在市、县内的指定地点或者到他的住处进行讯问,但是应当出示人民检察院或者公安机关的证明文件。对在现场发现的犯罪嫌疑人,经出示工作证件,可以口头传唤,但应当在讯问笔录中注明。 传唤、拘传持续的时间不得超过十二小时;案情特别重大、复杂,需要采取拘留、逮捕措施的,传唤、拘传持续的时间不得超过二十四小时。 不得以连续传唤、拘传的形式变相拘禁犯罪嫌疑人。传唤、拘传犯罪嫌疑人,应当保证犯罪嫌疑人的饮食和必要的休息时间。 第一百二十条 侦查人员在讯问犯罪嫌疑人的时候,应当首先讯问犯罪嫌疑人是否有犯罪行为,让他陈述有罪的情节或者无罪的辩解,然后向他提出问题。犯罪嫌疑人对侦查人员的提问,应当如实回答。但是对与本案无关的问题,有拒绝回答的权利。 侦查人员在讯问犯罪嫌疑人的时候,应当告知犯罪嫌疑人享有的诉讼权利,如实供述自己罪行可以从宽处理和认罪认罚的法律规定。 第一百二十一条 讯问聋、哑的犯罪嫌疑人,应当有通晓聋、哑手势的人参加,并且将这种情况记明笔录。 第一百二十二条 讯问笔录应当交犯罪嫌疑人核对,对于没有阅读能力的,应当向他宣读。如果记载有遗漏或者差错,犯罪嫌疑人可以提出补充或者改正。犯罪嫌疑人承认笔录没有错误后,应当签名或者盖章。侦查人员也应当在笔录上签名。犯罪嫌疑人请求自行书写供述的,应当准许。必要的时候,侦查人员也可以要犯罪嫌疑人亲笔书写供词。 第一百二十三条 侦查人员在讯问犯罪嫌疑人的时候,可以对讯问过程进行录音或者录像;对于可能判处无期徒刑、死刑的案件或者其他重大犯罪案件,应当对讯问过程进行录音或者录像。 录音或者录像应当全程进行,保持完整性。 第一百二十四条 侦查人员询问证人,可以在现场进行,也可以到证人所在单位、住处或者证人提出的地点进行,在必要的时候,可以通知证人到人民检察院或者公安机关提供证言。在现场询问证人,应当出示工作证件,到证人所在单位、住处或者证人提出的地点询问证人,应当出示人民检察院或者公安机关的证明文件。 询问证人应当个别进行。 第一百二十五条 询问证人,应当告知他应当如实地提供证据、证言和有意作伪证或者隐匿罪证要负的法律责任。 第一百二十六条 本法第一百二十二条的规定,也适用于询问证人。 第一百二十七条 询问被害人,适用本节各条规定。 第一百二十八条 侦查人员对于与犯罪有关的场所、物品、人身、尸体应当进行勘验或者检查。在必要的时候,可以指派或者聘请具有专门知识的人,在侦查人员的主持下进行勘验、检查。 第一百二十九条 任何单位和个人,都有义务保护犯罪现场,并且立即通知公安机关派员勘验。 第一百三十条 侦查人员执行勘验、检查,必须持有人民检察院或者公安机关的证明文件。 第一百三十一条 对于死因不明的尸体,公安机关有权决定解剖,并且通知死者家属到场。 第一百三十二条 为了确定被害人、犯罪嫌疑人的某些特征、伤害情况或者生理状态,可以对人身进行检查,可以提取指纹信息,采集血液、尿液等生物样本。 犯罪嫌疑人如果拒绝检查,侦查人员认为必要的时候,可以强制检查。 检查妇女的身体,应当由女工作人员或者医师进行。 第一百三十三条 勘验、检查的情况应当写成笔录,由参加勘验、检查的人和见证人签名或者盖章。 第一百三十四条 人民检察院审查案件的时候,对公安机关的勘验、检查,认为需要复验、复查时,可以要求公安机关复验、复查,并且可以派检察人员参加。 第一百三十五条 为了查明案情,在必要的时候,经公安机关负责人批准,可以进行侦查实验。 侦查实验的情况应当写成笔录,由参加实验的人签名或者盖章。 侦查实验,禁止一切足以造成危险、侮辱人格或者有伤风化的行为。 第一百三十六条 为了收集犯罪证据、查获犯罪人,侦查人员可以对犯罪嫌疑人以及可能隐藏罪犯或者犯罪证据的人的身体、物品、住处和其他有关的地方进行搜查。 第一百三十七条 任何单位和个人,有义务按照人民检察院和公安机关的要求,交出可以证明犯罪嫌疑人有罪或者无罪的物证、书证、视听资料等证据。 第一百三十八条 进行搜查,必须向被搜查人出示搜查证。 在执行逮捕、拘留的时候,遇有紧急情况,不另用搜查证也可以进行搜查。 第一百三十九条 在搜查的时候,应当有被搜查人或者他的家属,邻居或者其他见证人在场。 搜查妇女的身体,应当由女工作人员进行。 第一百四十条 搜查的情况应当写成笔录,由侦查人员和被搜查人或者他的家属,邻居或者其他见证人签名或者盖章。如果被搜查人或者他的家属在逃或者拒绝签名、盖章,应当在笔录上注明。 第一百四十一条 在侦查活动中发现的可用以证明犯罪嫌疑人有罪或者无罪的各种财物、文件,应当查封、扣押;与案件无关的财物、文件,不得查封、扣押。 对查封、扣押的财物、文件,要妥善保管或者封存,不得使用、调换或者损毁。 第一百四十二条 对查封、扣押的财物、文件,应当会同在场见证人和被查封、扣押财物、文件持有人查点清楚,当场开列清单一式二份,由侦查人员、见证人和持有人签名或者盖章,一份交给持有人,另一份附卷备查。 第一百四十三条 侦查人员认为需要扣押犯罪嫌疑人的邮件、电报的时候,经公安机关或者人民检察院批准,即可通知邮电机关将有关的邮件、电报检交扣押。 不需要继续扣押的时候,应即通知邮电机关。 第一百四十四条 人民检察院、公安机关根据侦查犯罪的需要,可以依照规定查询、冻结犯罪嫌疑人的存款、汇款、债券、股票、基金份额等财产。有关单位和个人应当配合。 犯罪嫌疑人的存款、汇款、债券、股票、基金份额等财产已被冻结的,不得重复冻结。 第一百四十五条 对查封、扣押的财物、文件、邮件、电报或者冻结的存款、汇款、债券、股票、基金份额等财产,经查明确实与案件无关的,应当在三日以内解除查封、扣押、冻结,予以退还。 第一百四十六条 为了查明案情,需要解决案件中某些专门性问题的时候,应当指派、聘请有专门知识的人进行鉴定。 第一百四十七条 鉴定人进行鉴定后,应当写出鉴定意见,并且签名。 鉴定人故意作虚假鉴定的,应当承担法律责任。 第一百四十八条 侦查机关应当将用作证据的鉴定意见告知犯罪嫌疑人、被害人。如果犯罪嫌疑人、被害人提出申请,可以补充鉴定或者重新鉴定。 第一百四十九条 对犯罪嫌疑人作精神病鉴定的期间不计入办案期限。 第一百五十条 公安机关在立案后,对于危害国家安全犯罪、恐怖活动犯罪、黑社会性质的组织犯罪、重大毒品犯罪或者其他严重危害社会的犯罪案件,根据侦查犯罪的需要,经过严格的批准手续,可以采取技术侦查措施。 人民检察院在立案后,对于利用职权实施的严重侵犯公民人身权利的重大犯罪案件,根据侦查犯罪的需要,经过严格的批准手续,可以采取技术侦查措施,按照规定交有关机关执行。 追捕被通缉或者批准、决定逮捕的在逃的犯罪嫌疑人、被告人,经过批准,可以采取追捕所必需的技术侦查措施。 第一百五十一条 批准决定应当根据侦查犯罪的需要,确定采取技术侦查措施的种类和适用对象。批准决定自签发之日起三个月以内有效。对于不需要继续采取技术侦查措施的,应当及时解除;对于复杂、疑难案件,期限届满仍有必要继续采取技术侦查措施的,经过批准,有效期可以延长,每次不得超过三个月。 第一百五十二条 采取技术侦查措施,必须严格按照批准的措施种类、适用对象和期限执行。 侦查人员对采取技术侦查措施过程中知悉的国家秘密、商业秘密和个人隐私,应当保密;对采取技术侦查措施获取的与案件无关的材料,必须及时销毁。 采取技术侦查措施获取的材料,只能用于对犯罪的侦查、起诉和审判,不得用于其他用途。 公安机关依法采取技术侦查措施,有关单位和个人应当配合,并对有关情况予以保密。 第一百五十三条 为了查明案情,在必要的时候,经公安机关负责人决定,可以由有关人员隐匿其身份实施侦查。但是,不得诱使他人犯罪,不得采用可能危害公共安全或者发生重大人身危险的方法。 对涉及给付毒品等违禁品或者财物的犯罪活动,公安机关根据侦查犯罪的需要,可以依照规定实施控制下交付。 第一百五十四条 依照本节规定采取侦查措施收集的材料在刑事诉讼中可以作为证据使用。如果使用该证据可能危及有关人员的人身安全,或者可能产生其他严重后果的,应当采取不暴露有关人员身份、技术方法等保护措施,必要的时候,可以由审判人员在庭外对证据进行核实。 第一百五十五条 应当逮捕的犯罪嫌疑人如果在逃,公安机关可以发布通缉令,采取有效措施,追捕归案。 各级公安机关在自己管辖的地区以内,可以直接发布通缉令;超出自己管辖的地区,应当报请有权决定的上级机关发布。 第一百五十六条 对犯罪嫌疑人逮捕后的侦查羁押期限不得超过二个月。案情复杂、期限届满不能终结的案件,可以经上一级人民检察院批准延长一个月。 第一百五十七条 因为特殊原因,在较长时间内不宜交付审判的特别重大复杂的案件,由最高人民检察院报请全国人民代表大会常务委员会批准延期审理。 第一百五十八条 下列案件在本法第一百五十六条规定的期限届满不能侦查终结的,经省、自治区、直辖市人民检察院批准或者决定,可以延长二个月: (一)交通十分不便的边远地区的重大复杂案件; (二)重大的犯罪集团案件; (三)流窜作案的重大复杂案件; (四)犯罪涉及面广,取证困难的重大复杂案件。 第一百五十九条 对犯罪嫌疑人可能判处十年有期徒刑以上刑罚,依照本法第一百五十八条规定延长期限届满,仍不能侦查终结的,经省、自治区、直辖市人民检察院批准或者决定,可以再延长二个月。 第一百六十条 在侦查期间,发现犯罪嫌疑人另有重要罪行的,自发现之日起依照本法第一百五十六条的规定重新计算侦查羁押期限。 犯罪嫌疑人不讲真实姓名、住址,身份不明的,应当对其身份进行调查,侦查羁押期限自查清其身份之日起计算,但是不得停止对其犯罪行为的侦查取证。对于犯罪事实清楚,证据确实、充分,确实无法查明其身份的,也可以按其自报的姓名起诉、审判。 第一百六十一条 在案件侦查终结前,辩护律师提出要求的,侦查机关应当听取辩护律师的意见,并记录在案。辩护律师提出书面意见的,应当附卷。 第一百六十二条 公安机关侦查终结的案件,应当做到犯罪事实清楚,证据确实、充分,并且写出起诉意见书,连同案卷材料、证据一并移送同级人民检察院审查决定;同时将案件移送情况告知犯罪嫌疑人及其辩护律师。 犯罪嫌疑人自愿认罪的,应当记录在案,随案移送,并在起诉意见书中写明有关情况。 第一百六十三条 在侦查过程中,发现不应对犯罪嫌疑人追究刑事责任的,应当撤销案件;犯罪嫌疑人已被逮捕的,应当立即释放,发给释放证明,并且通知原批准逮捕的人民检察院。 第一百六十四条 人民检察院对直接受理的案件的侦查适用本章规定。 第一百六十五条 人民检察院直接受理的案件中符合本法第八十一条、第八十二条第四项、第五项规定情形,需要逮捕、拘留犯罪嫌疑人的,由人民检察院作出决定,由公安机关执行。 第一百六十六条 人民检察院对直接受理的案件中被拘留的人,应当在拘留后的二十四小时以内进行讯问。在发现不应当拘留的时候,必须立即释放,发给释放证明。 第一百六十七条 人民检察院对直接受理的案件中被拘留的人,认为需要逮捕的,应当在十四日以内作出决定。在特殊情况下,决定逮捕的时间可以延长一日至三日。对不需要逮捕的,应当立即释放;对需要继续侦查,并且符合取保候审、监视居住条件的,依法取保候审或者监视居住。 第一百六十八条 人民检察院侦查终结的案件,应当作出提起公诉、不起诉或者撤销案件的决定。 第三章 提起公诉第一百六十九条 凡需要提起公诉的案件,一律由人民检察院审查决定。 第一百七十条 人民检察院对于监察机关移送起诉的案件,依照本法和监察法的有关规定进行审查。人民检察院经审查,认为需要补充核实的,应当退回监察机关补充调查,必要时可以自行补充侦查。 对于监察机关移送起诉的已采取留置措施的案件,人民检察院应当对犯罪嫌疑人先行拘留,留置措施自动解除。人民检察院应当在拘留后的十日以内作出是否逮捕、取保候审或者监视居住的决定。在特殊情况下,决定的时间可以延长一日至四日。人民检察院决定采取强制措施的期间不计入审查起诉期限。 第一百七十一条 人民检察院审查案件的时候,必须查明: (一)犯罪事实、情节是否清楚,证据是否确实、充分,犯罪性质和罪名的认定是否正确; (二)有无遗漏罪行和其他应当追究刑事责任的人; (三)是否属于不应追究刑事责任的; (四)有无附带民事诉讼; (五)侦查活动是否合法。 第一百七十二条 人民检察院对于监察机关、公安机关移送起诉的案件,应当在一个月以内作出决定,重大、复杂的案件,可以延长十五日;犯罪嫌疑人认罪认罚,符合速裁程序适用条件的,应当在十日以内作出决定,对可能判处的有期徒刑超过一年的,可以延长至十五日。 人民检察院审查起诉的案件,改变管辖的,从改变后的人民检察院收到案件之日起计算审查起诉期限。 第一百七十三条 人民检察院审查案件,应当讯问犯罪嫌疑人,听取辩护人或者值班律师、被害人及其诉讼代理人的意见,并记录在案。辩护人或者值班律师、被害人及其诉讼代理人提出书面意见的,应当附卷。 犯罪嫌疑人认罪认罚的,人民检察院应当告知其享有的诉讼权利和认罪认罚的法律规定,听取犯罪嫌疑人、辩护人或者值班律师、被害人及其诉讼代理人对下列事项的意见,并记录在案: (一)涉嫌的犯罪事实、罪名及适用的法律规定; (二)从轻、减轻或者免除处罚等从宽处罚的建议; (三)认罪认罚后案件审理适用的程序; (四)其他需要听取意见的事项。 人民检察院依照前两款规定听取值班律师意见的,应当提前为值班律师了解案件有关情况提供必要的便利。 第一百七十四条 犯罪嫌疑人自愿认罪,同意量刑建议和程序适用的,应当在辩护人或者值班律师在场的情况下签署认罪认罚具结书。 犯罪嫌疑人认罪认罚,有下列情形之一的,不需要签署认罪认罚具结书: (一)犯罪嫌疑人是盲、聋、哑人,或者是尚未完全丧失辨认或者控制自己行为能力的精神病人的; (二)未成年犯罪嫌疑人的法定代理人、辩护人对未成年人认罪认罚有异议的; (三)其他不需要签署认罪认罚具结书的情形。 第一百七十五条 人民检察院审查案件,可以要求公安机关提供法庭审判所必需的证据材料;认为可能存在本法第五十六条规定的以非法方法收集证据情形的,可以要求其对证据收集的合法性作出说明。 人民检察院审查案件,对于需要补充侦查的,可以退回公安机关补充侦查,也可以自行侦查。 对于补充侦查的案件,应当在一个月以内补充侦查完毕。补充侦查以二次为限。补充侦查完毕移送人民检察院后,人民检察院重新计算审查起诉期限。 对于二次补充侦查的案件,人民检察院仍然认为证据不足,不符合起诉条件的,应当作出不起诉的决定。 第一百七十六条 人民检察院认为犯罪嫌疑人的犯罪事实已经查清,证据确实、充分,依法应当追究刑事责任的,应当作出起诉决定,按照审判管辖的规定,向人民法院提起公诉,并将案卷材料、证据移送人民法院。 犯罪嫌疑人认罪认罚的,人民检察院应当就主刑、附加刑、是否适用缓刑等提出量刑建议,并随案移送认罪认罚具结书等材料。 第一百七十七条 犯罪嫌疑人没有犯罪事实,或者有本法第十六条规定的情形之一的,人民检察院应当作出不起诉决定。 对于犯罪情节轻微,依照刑法规定不需要判处刑罚或者免除刑罚的,人民检察院可以作出不起诉决定。 人民检察院决定不起诉的案件,应当同时对侦查中查封、扣押、冻结的财物解除查封、扣押、冻结。对被不起诉人需要给予行政处罚、处分或者需要没收其违法所得的,人民检察院应当提出检察意见,移送有关主管机关处理。有关主管机关应当将处理结果及时通知人民检察院。 第一百七十八条 不起诉的决定,应当公开宣布,并且将不起诉决定书送达被不起诉人和他的所在单位。如果被不起诉人在押,应当立即释放。 第一百七十九条 对于公安机关移送起诉的案件,人民检察院决定不起诉的,应当将不起诉决定书送达公安机关。公安机关认为不起诉的决定有错误的时候,可以要求复议,如果意见不被接受,可以向上一级人民检察院提请复核。 第一百八十条 对于有被害人的案件,决定不起诉的,人民检察院应当将不起诉决定书送达被害人。被害人如果不服,可以自收到决定书后七日以内向上一级人民检察院申诉,请求提起公诉。人民检察院应当将复查决定告知被害人。对人民检察院维持不起诉决定的,被害人可以向人民法院起诉。被害人也可以不经申诉,直接向人民法院起诉。人民法院受理案件后,人民检察院应当将有关案件材料移送人民法院。 第一百八十一条 对于人民检察院依照本法第一百七十七条第二款规定作出的不起诉决定,被不起诉人如果不服,可以自收到决定书后七日以内向人民检察院申诉。人民检察院应当作出复查决定,通知被不起诉的人,同时抄送公安机关。 第一百八十二条 犯罪嫌疑人自愿如实供述涉嫌犯罪的事实,有重大立功或者案件涉及国家重大利益的,经最高人民检察院核准,公安机关可以撤销案件,人民检察院可以作出不起诉决定,也可以对涉嫌数罪中的一项或者多项不起诉。 根据前款规定不起诉或者撤销案件的,人民检察院、公安机关应当及时对查封、扣押、冻结的财物及其孳息作出处理。 第三编 审 判第一章 审判组织第一百八十三条 基层人民法院、中级人民法院审判第一审案件,应当由审判员三人或者由审判员和人民陪审员共三人或者七人组成合议庭进行,但是基层人民法院适用简易程序、速裁程序的案件可以由审判员一人独任审判。 高级人民法院审判第一审案件,应当由审判员三人至七人或者由审判员和人民陪审员共三人或者七人组成合议庭进行。 最高人民法院审判第一审案件,应当由审判员三人至七人组成合议庭进行。 人民法院审判上诉和抗诉案件,由审判员三人或者五人组成合议庭进行。 合议庭的成员人数应当是单数。 第一百八十四条 合议庭进行评议的时候,如果意见分歧,应当按多数人的意见作出决定,但是少数人的意见应当写入笔录。评议笔录由合议庭的组成人员签名。 第一百八十五条 合议庭开庭审理并且评议后,应当作出判决。对于疑难、复杂、重大的案件,合议庭认为难以作出决定的,由合议庭提请院长决定提交审判委员会讨论决定。审判委员会的决定,合议庭应当执行。 第二章 第一审程序第一百八十六条 人民法院对提起公诉的案件进行审查后,对于起诉书中有明确的指控犯罪事实的,应当决定开庭审判。 第一百八十七条 人民法院决定开庭审判后,应当确定合议庭的组成人员,将人民检察院的起诉书副本至迟在开庭十日以前送达被告人及其辩护人。 在开庭以前,审判人员可以召集公诉人、当事人和辩护人、诉讼代理人,对回避、出庭证人名单、非法证据排除等与审判相关的问题,了解情况,听取意见。 人民法院确定开庭日期后,应当将开庭的时间、地点通知人民检察院,传唤当事人,通知辩护人、诉讼代理人、证人、鉴定人和翻译人员,传票和通知书至迟在开庭三日以前送达。公开审判的案件,应当在开庭三日以前先期公布案由、被告人姓名、开庭时间和地点。 上述活动情形应当写入笔录,由审判人员和书记员签名。 第一百八十八条 人民法院审判第一审案件应当公开进行。但是有关国家秘密或者个人隐私的案件,不公开审理;涉及商业秘密的案件,当事人申请不公开审理的,可以不公开审理。 不公开审理的案件,应当当庭宣布不公开审理的理由。 第一百八十九条 人民法院审判公诉案件,人民检察院应当派员出席法庭支持公诉。 第一百九十条 开庭的时候,审判长查明当事人是否到庭,宣布案由;宣布合议庭的组成人员、书记员、公诉人、辩护人、诉讼代理人、鉴定人和翻译人员的名单;告知当事人有权对合议庭组成人员、书记员、公诉人、鉴定人和翻译人员申请回避;告知被告人享有辩护权利。 被告人认罪认罚的,审判长应当告知被告人享有的诉讼权利和认罪认罚的法律规定,审查认罪认罚的自愿性和认罪认罚具结书内容的真实性、合法性。 第一百九十一条 公诉人在法庭上宣读起诉书后,被告人、被害人可以就起诉书指控的犯罪进行陈述,公诉人可以讯问被告人。 被害人、附带民事诉讼的原告人和辩护人、诉讼代理人,经审判长许可,可以向被告人发问。 审判人员可以讯问被告人。 第一百九十二条 公诉人、当事人或者辩护人、诉讼代理人对证人证言有异议,且该证人证言对案件定罪量刑有重大影响,人民法院认为证人有必要出庭作证的,证人应当出庭作证。 人民警察就其执行职务时目击的犯罪情况作为证人出庭作证,适用前款规定。 公诉人、当事人或者辩护人、诉讼代理人对鉴定意见有异议,人民法院认为鉴定人有必要出庭的,鉴定人应当出庭作证。经人民法院通知,鉴定人拒不出庭作证的,鉴定意见不得作为定案的根据。 第一百九十三条 经人民法院通知,证人没有正当理由不出庭作证的,人民法院可以强制其到庭,但是被告人的配偶、父母、子女除外。 证人没有正当理由拒绝出庭或者出庭后拒绝作证的,予以训诫,情节严重的,经院长批准,处以十日以下的拘留。被处罚人对拘留决定不服的,可以向上一级人民法院申请复议。复议期间不停止执行。 第一百九十四条 证人作证,审判人员应当告知他要如实地提供证言和有意作伪证或者隐匿罪证要负的法律责任。公诉人、当事人和辩护人、诉讼代理人经审判长许可,可以对证人、鉴定人发问。审判长认为发问的内容与案件无关的时候,应当制止。 审判人员可以询问证人、鉴定人。 第一百九十五条 公诉人、辩护人应当向法庭出示物证,让当事人辨认,对未到庭的证人的证言笔录、鉴定人的鉴定意见、勘验笔录和其他作为证据的文书,应当当庭宣读。审判人员应当听取公诉人、当事人和辩护人、诉讼代理人的意见。 第一百九十六条 法庭审理过程中,合议庭对证据有疑问的,可以宣布休庭,对证据进行调查核实。 人民法院调查核实证据,可以进行勘验、检查、查封、扣押、鉴定和查询、冻结。 第一百九十七条 法庭审理过程中,当事人和辩护人、诉讼代理人有权申请通知新的证人到庭,调取新的物证,申请重新鉴定或者勘验。 公诉人、当事人和辩护人、诉讼代理人可以申请法庭通知有专门知识的人出庭,就鉴定人作出的鉴定意见提出意见。 法庭对于上述申请,应当作出是否同意的决定。 第二款规定的有专门知识的人出庭,适用鉴定人的有关规定。 第一百九十八条 法庭审理过程中,对与定罪、量刑有关的事实、证据都应当进行调查、辩论。 经审判长许可,公诉人、当事人和辩护人、诉讼代理人可以对证据和案件情况发表意见并且可以互相辩论。 审判长在宣布辩论终结后,被告人有最后陈述的权利。 第一百九十九条 在法庭审判过程中,如果诉讼参与人或者旁听人员违反法庭秩序,审判长应当警告制止。对不听制止的,可以强行带出法庭;情节严重的,处以一千元以下的罚款或者十五日以下的拘留。罚款、拘留必须经院长批准。被处罚人对罚款、拘留的决定不服的,可以向上一级人民法院申请复议。复议期间不停止执行。 对聚众哄闹、冲击法庭或者侮辱、诽谤、威胁、殴打司法工作人员或者诉讼参与人,严重扰乱法庭秩序,构成犯罪的,依法追究刑事责任。 第二百条 在被告人最后陈述后,审判长宣布休庭,合议庭进行评议,根据已经查明的事实、证据和有关的法律规定,分别作出以下判决: (一)案件事实清楚,证据确实、充分,依据法律认定被告人有罪的,应当作出有罪判决; (二)依据法律认定被告人无罪的,应当作出无罪判决; (三)证据不足,不能认定被告人有罪的,应当作出证据不足、指控的犯罪不能成立的无罪判决。 第二百零一条 对于认罪认罚案件,人民法院依法作出判决时,一般应当采纳人民检察院指控的罪名和量刑建议,但有下列情形的除外: (一)被告人的行为不构成犯罪或者不应当追究其刑事责任的; (二)被告人违背意愿认罪认罚的; (三)被告人否认指控的犯罪事实的; (四)起诉指控的罪名与审理认定的罪名不一致的; (五)其他可能影响公正审判的情形。 人民法院经审理认为量刑建议明显不当,或者被告人、辩护人对量刑建议提出异议的,人民检察院可以调整量刑建议。人民检察院不调整量刑建议或者调整量刑建议后仍然明显不当的,人民法院应当依法作出判决。 第二百零二条 宣告判决,一律公开进行。 当庭宣告判决的,应当在五日以内将判决书送达当事人和提起公诉的人民检察院;定期宣告判决的,应当在宣告后立即将判决书送达当事人和提起公诉的人民检察院。判决书应当同时送达辩护人、诉讼代理人。 第二百零三条 判决书应当由审判人员和书记员署名,并且写明上诉的期限和上诉的法院。 第二百零四条 在法庭审判过程中,遇有下列情形之一,影响审判进行的,可以延期审理: (一)需要通知新的证人到庭,调取新的物证,重新鉴定或者勘验的; (二)检察人员发现提起公诉的案件需要补充侦查,提出建议的; (三)由于申请回避而不能进行审判的。 第二百零五条 依照本法第二百零四条第二项的规定延期审理的案件,人民检察院应当在一个月以内补充侦查完毕。 第二百零六条 在审判过程中,有下列情形之一,致使案件在较长时间内无法继续审理的,可以中止审理: (一)被告人患有严重疾病,无法出庭的; (二)被告人脱逃的; (三)自诉人患有严重疾病,无法出庭,未委托诉讼代理人出庭的; (四)由于不能抗拒的原因。 中止审理的原因消失后,应当恢复审理。中止审理的期间不计入审理期限。 第二百零七条 法庭审判的全部活动,应当由书记员写成笔录,经审判长审阅后,由审判长和书记员签名。 法庭笔录中的证人证言部分,应当当庭宣读或者交给证人阅读。证人在承认没有错误后,应当签名或者盖章。 法庭笔录应当交给当事人阅读或者向他宣读。当事人认为记载有遗漏或者差错的,可以请求补充或者改正。当事人承认没有错误后,应当签名或者盖章。 第二百零八条 人民法院审理公诉案件,应当在受理后二个月以内宣判,至迟不得超过三个月。对于可能判处死刑的案件或者附带民事诉讼的案件,以及有本法第一百五十八条规定情形之一的,经上一级人民法院批准,可以延长三个月;因特殊情况还需要延长的,报请最高人民法院批准。 人民法院改变管辖的案件,从改变后的人民法院收到案件之日起计算审理期限。 人民检察院补充侦查的案件,补充侦查完毕移送人民法院后,人民法院重新计算审理期限。 第二百零九条 人民检察院发现人民法院审理案件违反法律规定的诉讼程序,有权向人民法院提出纠正意见。 第二百一十条 自诉案件包括下列案件: (一)告诉才处理的案件; (二)被害人有证据证明的轻微刑事案件; (三)被害人有证据证明对被告人侵犯自己人身、财产权利的行为应当依法追究刑事责任,而公安机关或者人民检察院不予追究被告人刑事责任的案件。 第二百一十一条 人民法院对于自诉案件进行审查后,按照下列情形分别处理: (一)犯罪事实清楚,有足够证据的案件,应当开庭审判; (二)缺乏罪证的自诉案件,如果自诉人提不出补充证据,应当说服自诉人撤回自诉,或者裁定驳回。 自诉人经两次依法传唤,无正当理由拒不到庭的,或者未经法庭许可中途退庭的,按撤诉处理。 法庭审理过程中,审判人员对证据有疑问,需要调查核实的,适用本法第一百九十六条的规定。 第二百一十二条 人民法院对自诉案件,可以进行调解;自诉人在宣告判决前,可以同被告人自行和解或者撤回自诉。本法第二百一十条第三项规定的案件不适用调解。 人民法院审理自诉案件的期限,被告人被羁押的,适用本法第二百零八条第一款、第二款的规定;未被羁押的,应当在受理后六个月以内宣判。 第二百一十三条 自诉案件的被告人在诉讼过程中,可以对自诉人提起反诉。反诉适用自诉的规定。 第二百一十四条 基层人民法院管辖的案件,符合下列条件的,可以适用简易程序审判: (一)案件事实清楚、证据充分的; (二)被告人承认自己所犯罪行,对指控的犯罪事实没有异议的; (三)被告人对适用简易程序没有异议的。 人民检察院在提起公诉的时候,可以建议人民法院适用简易程序。 第二百一十五条 有下列情形之一的,不适用简易程序: (一)被告人是盲、聋、哑人,或者是尚未完全丧失辨认或者控制自己行为能力的精神病人的; (二)有重大社会影响的; (三)共同犯罪案件中部分被告人不认罪或者对适用简易程序有异议的; (四)其他不宜适用简易程序审理的。 第二百一十六条 适用简易程序审理案件,对可能判处三年有期徒刑以下刑罚的,可以组成合议庭进行审判,也可以由审判员一人独任审判;对可能判处的有期徒刑超过三年的,应当组成合议庭进行审判。 适用简易程序审理公诉案件,人民检察院应当派员出席法庭。 第二百一十七条 适用简易程序审理案件,审判人员应当询问被告人对指控的犯罪事实的意见,告知被告人适用简易程序审理的法律规定,确认被告人是否同意适用简易程序审理。 第二百一十八条 适用简易程序审理案件,经审判人员许可,被告人及其辩护人可以同公诉人、自诉人及其诉讼代理人互相辩论。 第二百一十九条 适用简易程序审理案件,不受本章第一节关于送达期限、讯问被告人、询问证人、鉴定人、出示证据、法庭辩论程序规定的限制。但在判决宣告前应当听取被告人的最后陈述意见。 第二百二十条 适用简易程序审理案件,人民法院应当在受理后二十日以内审结;对可能判处的有期徒刑超过三年的,可以延长至一个半月。 第二百二十一条 人民法院在审理过程中,发现不宜适用简易程序的,应当按照本章第一节或者第二节的规定重新审理。 第二百二十二条 基层人民法院管辖的可能判处三年有期徒刑以下刑罚的案件,案件事实清楚,证据确实、充分,被告人认罪认罚并同意适用速裁程序的,可以适用速裁程序,由审判员一人独任审判。 人民检察院在提起公诉的时候,可以建议人民法院适用速裁程序。 第二百二十三条 有下列情形之一的,不适用速裁程序: (一)被告人是盲、聋、哑人,或者是尚未完全丧失辨认或者控制自己行为能力的精神病人的; (二)被告人是未成年人的; (三)案件有重大社会影响的; (四)共同犯罪案件中部分被告人对指控的犯罪事实、罪名、量刑建议或者适用速裁程序有异议的; (五)被告人与被害人或者其法定代理人没有就附带民事诉讼赔偿等事项达成调解或者和解协议的; (六)其他不宜适用速裁程序审理的。 第二百二十四条 适用速裁程序审理案件,不受本章第一节规定的送达期限的限制,一般不进行法庭调查、法庭辩论,但在判决宣告前应当听取辩护人的意见和被告人的最后陈述意见。 适用速裁程序审理案件,应当当庭宣判。 第二百二十五条 适用速裁程序审理案件,人民法院应当在受理后十日以内审结;对可能判处的有期徒刑超过一年的,可以延长至十五日。 第二百二十六条 人民法院在审理过程中,发现有被告人的行为不构成犯罪或者不应当追究其刑事责任、被告人违背意愿认罪认罚、被告人否认指控的犯罪事实或者其他不宜适用速裁程序审理的情形的,应当按照本章第一节或者第三节的规定重新审理。 第三章 第二审程序第二百二十七条 被告人、自诉人和他们的法定代理人,不服地方各级人民法院第一审的判决、裁定,有权用书状或者口头向上一级人民法院上诉。被告人的辩护人和近亲属,经被告人同意,可以提出上诉。 附带民事诉讼的当事人和他们的法定代理人,可以对地方各级人民法院第一审的判决、裁定中的附带民事诉讼部分,提出上诉。 对被告人的上诉权,不得以任何借口加以剥夺。 第二百二十八条 地方各级人民检察院认为本级人民法院第一审的判决、裁定确有错误的时候,应当向上一级人民法院提出抗诉。 第二百二十九条 被害人及其法定代理人不服地方各级人民法院第一审的判决的,自收到判决书后五日以内,有权请求人民检察院提出抗诉。人民检察院自收到被害人及其法定代理人的请求后五日以内,应当作出是否抗诉的决定并且答复请求人。 第二百三十条 不服判决的上诉和抗诉的期限为十日,不服裁定的上诉和抗诉的期限为五日,从接到判决书、裁定书的第二日起算。 第二百三十一条 被告人、自诉人、附带民事诉讼的原告人和被告人通过原审人民法院提出上诉的,原审人民法院应当在三日以内将上诉状连同案卷、证据移送上一级人民法院,同时将上诉状副本送交同级人民检察院和对方当事人。 被告人、自诉人、附带民事诉讼的原告人和被告人直接向第二审人民法院提出上诉的,第二审人民法院应当在三日以内将上诉状交原审人民法院送交同级人民检察院和对方当事人。 第二百三十二条 地方各级人民检察院对同级人民法院第一审判决、裁定的抗诉,应当通过原审人民法院提出抗诉书,并且将抗诉书抄送上一级人民检察院。原审人民法院应当将抗诉书连同案卷、证据移送上一级人民法院,并且将抗诉书副本送交当事人。 上级人民检察院如果认为抗诉不当,可以向同级人民法院撤回抗诉,并且通知下级人民检察院。 第二百三十三条 第二审人民法院应当就第一审判决认定的事实和适用法律进行全面审查,不受上诉或者抗诉范围的限制。 共同犯罪的案件只有部分被告人上诉的,应当对全案进行审查,一并处理。 第二百三十四条 第二审人民法院对于下列案件,应当组成合议庭,开庭审理: (一)被告人、自诉人及其法定代理人对第一审认定的事实、证据提出异议,可能影响定罪量刑的上诉案件; (二)被告人被判处死刑的上诉案件; (三)人民检察院抗诉的案件; (四)其他应当开庭审理的案件。 第二审人民法院决定不开庭审理的,应当讯问被告人,听取其他当事人、辩护人、诉讼代理人的意见。 第二审人民法院开庭审理上诉、抗诉案件,可以到案件发生地或者原审人民法院所在地进行。 第二百三十五条 人民检察院提出抗诉的案件或者第二审人民法院开庭审理的公诉案件,同级人民检察院都应当派员出席法庭。第二审人民法院应当在决定开庭审理后及时通知人民检察院查阅案卷。人民检察院应当在一个月以内查阅完毕。人民检察院查阅案卷的时间不计入审理期限。 第二百三十六条 第二审人民法院对不服第一审判决的上诉、抗诉案件,经过审理后,应当按照下列情形分别处理: (一)原判决认定事实和适用法律正确、量刑适当的,应当裁定驳回上诉或者抗诉,维持原判; (二)原判决认定事实没有错误,但适用法律有错误,或者量刑不当的,应当改判; (三)原判决事实不清楚或者证据不足的,可以在查清事实后改判;也可以裁定撤销原判,发回原审人民法院重新审判。 原审人民法院对于依照前款第三项规定发回重新审判的案件作出判决后,被告人提出上诉或者人民检察院提出抗诉的,第二审人民法院应当依法作出判决或者裁定,不得再发回原审人民法院重新审判。 第二百三十七条 第二审人民法院审理被告人或者他的法定代理人、辩护人、近亲属上诉的案件,不得加重被告人的刑罚。第二审人民法院发回原审人民法院重新审判的案件,除有新的犯罪事实,人民检察院补充起诉的以外,原审人民法院也不得加重被告人的刑罚。 人民检察院提出抗诉或者自诉人提出上诉的,不受前款规定的限制。 第二百三十八条 第二审人民法院发现第一审人民法院的审理有下列违反法律规定的诉讼程序的情形之一的,应当裁定撤销原判,发回原审人民法院重新审判: (一)违反本法有关公开审判的规定的; (二)违反回避制度的; (三)剥夺或者限制了当事人的法定诉讼权利,可能影响公正审判的; (四)审判组织的组成不合法的; (五)其他违反法律规定的诉讼程序,可能影响公正审判的。 第二百三十九条 原审人民法院对于发回重新审判的案件,应当另行组成合议庭,依照第一审程序进行审判。对于重新审判后的判决,依照本法第二百二十七条、第二百二十八条、第二百二十九条的规定可以上诉、抗诉。 第二百四十条 第二审人民法院对不服第一审裁定的上诉或者抗诉,经过审查后,应当参照本法第二百三十六条、第二百三十八条和第二百三十九条的规定,分别情形用裁定驳回上诉、抗诉,或者撤销、变更原裁定。 第二百四十一条 第二审人民法院发回原审人民法院重新审判的案件,原审人民法院从收到发回的案件之日起,重新计算审理期限。 第二百四十二条 第二审人民法院审判上诉或者抗诉案件的程序,除本章已有规定的以外,参照第一审程序的规定进行。 第二百四十三条 第二审人民法院受理上诉、抗诉案件,应当在二个月以内审结。对于可能判处死刑的案件或者附带民事诉讼的案件,以及有本法第一百五十八条规定情形之一的,经省、自治区、直辖市高级人民法院批准或者决定,可以延长二个月;因特殊情况还需要延长的,报请最高人民法院批准。 最高人民法院受理上诉、抗诉案件的审理期限,由最高人民法院决定。 第二百四十四条 第二审的判决、裁定和最高人民法院的判决、裁定,都是终审的判决、裁定。 第二百四十五条 公安机关、人民检察院和人民法院对查封、扣押、冻结的犯罪嫌疑人、被告人的财物及其孳息,应当妥善保管,以供核查,并制作清单,随案移送。任何单位和个人不得挪用或者自行处理。对被害人的合法财产,应当及时返还。对违禁品或者不宜长期保存的物品,应当依照国家有关规定处理。 对作为证据使用的实物应当随案移送,对不宜移送的,应当将其清单、照片或者其他证明文件随案移送。 人民法院作出的判决,应当对查封、扣押、冻结的财物及其孳息作出处理。 人民法院作出的判决生效以后,有关机关应当根据判决对查封、扣押、冻结的财物及其孳息进行处理。对查封、扣押、冻结的赃款赃物及其孳息,除依法返还被害人的以外,一律上缴国库。 司法工作人员贪污、挪用或者私自处理查封、扣押、冻结的财物及其孳息的,依法追究刑事责任;不构成犯罪的,给予处分。 第四章 死刑复核程序第二百四十六条 死刑由最高人民法院核准。 第二百四十七条 中级人民法院判处死刑的第一审案件,被告人不上诉的,应当由高级人民法院复核后,报请最高人民法院核准。高级人民法院不同意判处死刑的,可以提审或者发回重新审判。 高级人民法院判处死刑的第一审案件被告人不上诉的,和判处死刑的第二审案件,都应当报请最高人民法院核准。 第二百四十八条 中级人民法院判处死刑缓期二年执行的案件,由高级人民法院核准。 第二百四十九条 最高人民法院复核死刑案件,高级人民法院复核死刑缓期执行的案件,应当由审判员三人组成合议庭进行。 第二百五十条 最高人民法院复核死刑案件,应当作出核准或者不核准死刑的裁定。对于不核准死刑的,最高人民法院可以发回重新审判或者予以改判。 第二百五十一条 最高人民法院复核死刑案件,应当讯问被告人,辩护律师提出要求的,应当听取辩护律师的意见。 在复核死刑案件过程中,最高人民检察院可以向最高人民法院提出意见。最高人民法院应当将死刑复核结果通报最高人民检察院。 第五章 审判监督程序第二百五十二条 当事人及其法定代理人、近亲属,对已经发生法律效力的判决、裁定,可以向人民法院或者人民检察院提出申诉,但是不能停止判决、裁定的执行。 第二百五十三条 当事人及其法定代理人、近亲属的申诉符合下列情形之一的,人民法院应当重新审判: (一)有新的证据证明原判决、裁定认定的事实确有错误,可能影响定罪量刑的; (二)据以定罪量刑的证据不确实、不充分、依法应当予以排除,或者证明案件事实的主要证据之间存在矛盾的; (三)原判决、裁定适用法律确有错误的; (四)违反法律规定的诉讼程序,可能影响公正审判的; (五)审判人员在审理该案件的时候,有贪污受贿,徇私舞弊,枉法裁判行为的。 第二百五十四条 各级人民法院院长对本院已经发生法律效力的判决和裁定,如果发现在认定事实上或者在适用法律上确有错误,必须提交审判委员会处理。 最高人民法院对各级人民法院已经发生法律效力的判决和裁定,上级人民法院对下级人民法院已经发生法律效力的判决和裁定,如果发现确有错误,有权提审或者指令下级人民法院再审。 最高人民检察院对各级人民法院已经发生法律效力的判决和裁定,上级人民检察院对下级人民法院已经发生法律效力的判决和裁定,如果发现确有错误,有权按照审判监督程序向同级人民法院提出抗诉。 人民检察院抗诉的案件,接受抗诉的人民法院应当组成合议庭重新审理,对于原判决事实不清楚或者证据不足的,可以指令下级人民法院再审。 第二百五十五条 上级人民法院指令下级人民法院再审的,应当指令原审人民法院以外的下级人民法院审理;由原审人民法院审理更为适宜的,也可以指令原审人民法院审理。 第二百五十六条 人民法院按照审判监督程序重新审判的案件,由原审人民法院审理的,应当另行组成合议庭进行。如果原来是第一审案件,应当依照第一审程序进行审判,所作的判决、裁定,可以上诉、抗诉;如果原来是第二审案件,或者是上级人民法院提审的案件,应当依照第二审程序进行审判,所作的判决、裁定,是终审的判决、裁定。 人民法院开庭审理的再审案件,同级人民检察院应当派员出席法庭。 第二百五十七条 人民法院决定再审的案件,需要对被告人采取强制措施的,由人民法院依法决定;人民检察院提出抗诉的再审案件,需要对被告人采取强制措施的,由人民检察院依法决定。 人民法院按照审判监督程序审判的案件,可以决定中止原判决、裁定的执行。 第二百五十八条 人民法院按照审判监督程序重新审判的案件,应当在作出提审、再审决定之日起三个月以内审结,需要延长期限的,不得超过六个月。 接受抗诉的人民法院按照审判监督程序审判抗诉的案件,审理期限适用前款规定;对需要指令下级人民法院再审的,应当自接受抗诉之日起一个月以内作出决定,下级人民法院审理案件的期限适用前款规定。 第四编 执 行第二百五十九条 判决和裁定在发生法律效力后执行。 下列判决和裁定是发生法律效力的判决和裁定: (一)已过法定期限没有上诉、抗诉的判决和裁定; (二)终审的判决和裁定; (三)最高人民法院核准的死刑的判决和高级人民法院核准的死刑缓期二年执行的判决。 第二百六十条 第一审人民法院判决被告人无罪、免除刑事处罚的,如果被告人在押,在宣判后应当立即释放。 第二百六十一条 最高人民法院判处和核准的死刑立即执行的判决,应当由最高人民法院院长签发执行死刑的命令。 被判处死刑缓期二年执行的罪犯,在死刑缓期执行期间,如果没有故意犯罪,死刑缓期执行期满,应当予以减刑的,由执行机关提出书面意见,报请高级人民法院裁定;如果故意犯罪,情节恶劣,查证属实,应当执行死刑的,由高级人民法院报请最高人民法院核准;对于故意犯罪未执行死刑的,死刑缓期执行的期间重新计算,并报最高人民法院备案。 第二百六十二条 下级人民法院接到最高人民法院执行死刑的命令后,应当在七日以内交付执行。但是发现有下列情形之一的,应当停止执行,并且立即报告最高人民法院,由最高人民法院作出裁定: (一)在执行前发现判决可能有错误的; (二)在执行前罪犯揭发重大犯罪事实或者有其他重大立功表现,可能需要改判的; (三)罪犯正在怀孕。 前款第一项、第二项停止执行的原因消失后,必须报请最高人民法院院长再签发执行死刑的命令才能执行;由于前款第三项原因停止执行的,应当报请最高人民法院依法改判。 第二百六十三条 人民法院在交付执行死刑前,应当通知同级人民检察院派员临场监督。 死刑采用枪决或者注射等方法执行。 死刑可以在刑场或者指定的羁押场所内执行。 指挥执行的审判人员,对罪犯应当验明正身,讯问有无遗言、信札,然后交付执行人员执行死刑。在执行前,如果发现可能有错误,应当暂停执行,报请最高人民法院裁定。 执行死刑应当公布,不应示众。 执行死刑后,在场书记员应当写成笔录。交付执行的人民法院应当将执行死刑情况报告最高人民法院。 执行死刑后,交付执行的人民法院应当通知罪犯家属。 第二百六十四条 罪犯被交付执行刑罚的时候,应当由交付执行的人民法院在判决生效后十日以内将有关的法律文书送达公安机关、监狱或者其他执行机关。 对被判处死刑缓期二年执行、无期徒刑、有期徒刑的罪犯,由公安机关依法将该罪犯送交监狱执行刑罚。对被判处有期徒刑的罪犯,在被交付执行刑罚前,剩余刑期在三个月以下的,由看守所代为执行。对被判处拘役的罪犯,由公安机关执行。 对未成年犯应当在未成年犯管教所执行刑罚。 执行机关应当将罪犯及时收押,并且通知罪犯家属。 判处有期徒刑、拘役的罪犯,执行期满,应当由执行机关发给释放证明书。 第二百六十五条 对被判处有期徒刑或者拘役的罪犯,有下列情形之一的,可以暂予监外执行: (一)有严重疾病需要保外就医的; (二)怀孕或者正在哺乳自己婴儿的妇女; (三)生活不能自理,适用暂予监外执行不致危害社会的。 对被判处无期徒刑的罪犯,有前款第二项规定情形的,可以暂予监外执行。 对适用保外就医可能有社会危险性的罪犯,或者自伤自残的罪犯,不得保外就医。 对罪犯确有严重疾病,必须保外就医的,由省级人民政府指定的医院诊断并开具证明文件。 在交付执行前,暂予监外执行由交付执行的人民法院决定;在交付执行后,暂予监外执行由监狱或者看守所提出书面意见,报省级以上监狱管理机关或者设区的市一级以上公安机关批准。 第二百六十六条 监狱、看守所提出暂予监外执行的书面意见的,应当将书面意见的副本抄送人民检察院。人民检察院可以向决定或者批准机关提出书面意见。 第二百六十七条 决定或者批准暂予监外执行的机关应当将暂予监外执行决定抄送人民检察院。人民检察院认为暂予监外执行不当的,应当自接到通知之日起一个月以内将书面意见送交决定或者批准暂予监外执行的机关,决定或者批准暂予监外执行的机关接到人民检察院的书面意见后,应当立即对该决定进行重新核查。 第二百六十八条 对暂予监外执行的罪犯,有下列情形之一的,应当及时收监: (一)发现不符合暂予监外执行条件的; (二)严重违反有关暂予监外执行监督管理规定的; (三)暂予监外执行的情形消失后,罪犯刑期未满的。 对于人民法院决定暂予监外执行的罪犯应当予以收监的,由人民法院作出决定,将有关的法律文书送达公安机关、监狱或者其他执行机关。 不符合暂予监外执行条件的罪犯通过贿赂等非法手段被暂予监外执行的,在监外执行的期间不计入执行刑期。罪犯在暂予监外执行期间脱逃的,脱逃的期间不计入执行刑期。 罪犯在暂予监外执行期间死亡的,执行机关应当及时通知监狱或者看守所。 第二百六十九条 对被判处管制、宣告缓刑、假释或者暂予监外执行的罪犯,依法实行社区矫正,由社区矫正机构负责执行。 第二百七十条 对被判处剥夺政治权利的罪犯,由公安机关执行。执行期满,应当由执行机关书面通知本人及其所在单位、居住地基层组织。 第二百七十一条 被判处罚金的罪犯,期满不缴纳的,人民法院应当强制缴纳;如果由于遭遇不能抗拒的灾祸等原因缴纳确实有困难的,经人民法院裁定,可以延期缴纳、酌情减少或者免除。 第二百七十二条 没收财产的判决,无论附加适用或者独立适用,都由人民法院执行;在必要的时候,可以会同公安机关执行。 第二百七十三条 罪犯在服刑期间又犯罪的,或者发现了判决的时候所没有发现的罪行,由执行机关移送人民检察院处理。 被判处管制、拘役、有期徒刑或者无期徒刑的罪犯,在执行期间确有悔改或者立功表现,应当依法予以减刑、假释的时候,由执行机关提出建议书,报请人民法院审核裁定,并将建议书副本抄送人民检察院。人民检察院可以向人民法院提出书面意见。 第二百七十四条 人民检察院认为人民法院减刑、假释的裁定不当,应当在收到裁定书副本后二十日以内,向人民法院提出书面纠正意见。人民法院应当在收到纠正意见后一个月以内重新组成合议庭进行审理,作出最终裁定。 第二百七十五条 监狱和其他执行机关在刑罚执行中,如果认为判决有错误或者罪犯提出申诉,应当转请人民检察院或者原判人民法院处理。 第二百七十六条 人民检察院对执行机关执行刑罚的活动是否合法实行监督。如果发现有违法的情况,应当通知执行机关纠正。 第五编 特别程序第一章 未成年人刑事案件诉讼程序第二百七十七条 对犯罪的未成年人实行教育、感化、挽救的方针,坚持教育为主、惩罚为辅的原则。 人民法院、人民检察院和公安机关办理未成年人刑事案件,应当保障未成年人行使其诉讼权利,保障未成年人得到法律帮助,并由熟悉未成年人身心特点的审判人员、检察人员、侦查人员承办。 第二百七十八条 未成年犯罪嫌疑人、被告人没有委托辩护人的,人民法院、人民检察院、公安机关应当通知法律援助机构指派律师为其提供辩护。 第二百七十九条 公安机关、人民检察院、人民法院办理未成年人刑事案件,根据情况可以对未成年犯罪嫌疑人、被告人的成长经历、犯罪原因、监护教育等情况进行调查。 第二百八十条 对未成年犯罪嫌疑人、被告人应当严格限制适用逮捕措施。人民检察院审查批准逮捕和人民法院决定逮捕,应当讯问未成年犯罪嫌疑人、被告人,听取辩护律师的意见。 对被拘留、逮捕和执行刑罚的未成年人与成年人应当分别关押、分别管理、分别教育。 第二百八十一条 对于未成年人刑事案件,在讯问和审判的时候,应当通知未成年犯罪嫌疑人、被告人的法定代理人到场。无法通知、法定代理人不能到场或者法定代理人是共犯的,也可以通知未成年犯罪嫌疑人、被告人的其他成年亲属,所在学校、单位、居住地基层组织或者未成年人保护组织的代表到场,并将有关情况记录在案。到场的法定代理人可以代为行使未成年犯罪嫌疑人、被告人的诉讼权利。 到场的法定代理人或者其他人员认为办案人员在讯问、审判中侵犯未成年人合法权益的,可以提出意见。讯问笔录、法庭笔录应当交给到场的法定代理人或者其他人员阅读或者向他宣读。 讯问女性未成年犯罪嫌疑人,应当有女工作人员在场。 审判未成年人刑事案件,未成年被告人最后陈述后,其法定代理人可以进行补充陈述。 询问未成年被害人、证人,适用第一款、第二款、第三款的规定。 第二百八十二条 对于未成年人涉嫌刑法分则第四章、第五章、第六章规定的犯罪,可能判处一年有期徒刑以下刑罚,符合起诉条件,但有悔罪表现的,人民检察院可以作出附条件不起诉的决定。人民检察院在作出附条件不起诉的决定以前,应当听取公安机关、被害人的意见。 对附条件不起诉的决定,公安机关要求复议、提请复核或者被害人申诉的,适用本法第一百七十九条、第一百八十条的规定。 未成年犯罪嫌疑人及其法定代理人对人民检察院决定附条件不起诉有异议的,人民检察院应当作出起诉的决定。 第二百八十三条 在附条件不起诉的考验期内,由人民检察院对被附条件不起诉的未成年犯罪嫌疑人进行监督考察。未成年犯罪嫌疑人的监护人,应当对未成年犯罪嫌疑人加强管教,配合人民检察院做好监督考察工作。 附条件不起诉的考验期为六个月以上一年以下,从人民检察院作出附条件不起诉的决定之日起计算。 被附条件不起诉的未成年犯罪嫌疑人,应当遵守下列规定: (一)遵守法律法规,服从监督; (二)按照考察机关的规定报告自己的活动情况; (三)离开所居住的市、县或者迁居,应当报经考察机关批准; (四)按照考察机关的要求接受矫治和教育。 第二百八十四条 被附条件不起诉的未成年犯罪嫌疑人,在考验期内有下列情形之一的,人民检察院应当撤销附条件不起诉的决定,提起公诉: (一)实施新的犯罪或者发现决定附条件不起诉以前还有其他犯罪需要追诉的; (二)违反治安管理规定或者考察机关有关附条件不起诉的监督管理规定,情节严重的。 被附条件不起诉的未成年犯罪嫌疑人,在考验期内没有上述情形,考验期满的,人民检察院应当作出不起诉的决定。 第二百八十五条 审判的时候被告人不满十八周岁的案件,不公开审理。但是,经未成年被告人及其法定代理人同意,未成年被告人所在学校和未成年人保护组织可以派代表到场。 第二百八十六条 犯罪的时候不满十八周岁,被判处五年有期徒刑以下刑罚的,应当对相关犯罪记录予以封存。 犯罪记录被封存的,不得向任何单位和个人提供,但司法机关为办案需要或者有关单位根据国家规定进行查询的除外。依法进行查询的单位,应当对被封存的犯罪记录的情况予以保密。 第二百八十七条 办理未成年人刑事案件,除本章已有规定的以外,按照本法的其他规定进行。 第二章 当事人和解的公诉案件诉讼程序第二百八十八条 下列公诉案件,犯罪嫌疑人、被告人真诚悔罪,通过向被害人赔偿损失、赔礼道歉等方式获得被害人谅解,被害人自愿和解的,双方当事人可以和解: (一)因民间纠纷引起,涉嫌刑法分则第四章、第五章规定的犯罪案件,可能判处三年有期徒刑以下刑罚的; (二)除渎职犯罪以外的可能判处七年有期徒刑以下刑罚的过失犯罪案件。 犯罪嫌疑人、被告人在五年以内曾经故意犯罪的,不适用本章规定的程序。 第二百八十九条 双方当事人和解的,公安机关、人民检察院、人民法院应当听取当事人和其他有关人员的意见,对和解的自愿性、合法性进行审查,并主持制作和解协议书。 第二百九十条 对于达成和解协议的案件,公安机关可以向人民检察院提出从宽处理的建议。人民检察院可以向人民法院提出从宽处罚的建议;对于犯罪情节轻微,不需要判处刑罚的,可以作出不起诉的决定。人民法院可以依法对被告人从宽处罚。 第三章 缺席审判程序第二百九十一条 对于贪污贿赂犯罪案件,以及需要及时进行审判,经最高人民检察院核准的严重危害国家安全犯罪、恐怖活动犯罪案件,犯罪嫌疑人、被告人在境外,监察机关、公安机关移送起诉,人民检察院认为犯罪事实已经查清,证据确实、充分,依法应当追究刑事责任的,可以向人民法院提起公诉。人民法院进行审查后,对于起诉书中有明确的指控犯罪事实,符合缺席审判程序适用条件的,应当决定开庭审判。 前款案件,由犯罪地、被告人离境前居住地或者最高人民法院指定的中级人民法院组成合议庭进行审理。 第二百九十二条 人民法院应当通过有关国际条约规定的或者外交途径提出的司法协助方式,或者被告人所在地法律允许的其他方式,将传票和人民检察院的起诉书副本送达被告人。传票和起诉书副本送达后,被告人未按要求到案的,人民法院应当开庭审理,依法作出判决,并对违法所得及其他涉案财产作出处理。 第二百九十三条 人民法院缺席审判案件,被告人有权委托辩护人,被告人的近亲属可以代为委托辩护人。被告人及其近亲属没有委托辩护人的,人民法院应当通知法律援助机构指派律师为其提供辩护。 第二百九十四条 人民法院应当将判决书送达被告人及其近亲属、辩护人。被告人或者其近亲属不服判决的,有权向上一级人民法院上诉。辩护人经被告人或者其近亲属同意,可以提出上诉。 人民检察院认为人民法院的判决确有错误的,应当向上一级人民法院提出抗诉。 第二百九十五条 在审理过程中,被告人自动投案或者被抓获的,人民法院应当重新审理。 罪犯在判决、裁定发生法律效力后到案的,人民法院应当将罪犯交付执行刑罚。交付执行刑罚前,人民法院应当告知罪犯有权对判决、裁定提出异议。罪犯对判决、裁定提出异议的,人民法院应当重新审理。 依照生效判决、裁定对罪犯的财产进行的处理确有错误的,应当予以返还、赔偿。 第二百九十六条 因被告人患有严重疾病无法出庭,中止审理超过六个月,被告人仍无法出庭,被告人及其法定代理人、近亲属申请或者同意恢复审理的,人民法院可以在被告人不出庭的情况下缺席审理,依法作出判决。 第二百九十七条 被告人死亡的,人民法院应当裁定终止审理,但有证据证明被告人无罪,人民法院经缺席审理确认无罪的,应当依法作出判决。 人民法院按照审判监督程序重新审判的案件,被告人死亡的,人民法院可以缺席审理,依法作出判决。 第四章 犯罪嫌疑人、被告人逃匿、死亡案件违法所得的没收程序第二百九十八条 对于贪污贿赂犯罪、恐怖活动犯罪等重大犯罪案件,犯罪嫌疑人、被告人逃匿,在通缉一年后不能到案,或者犯罪嫌疑人、被告人死亡,依照刑法规定应当追缴其违法所得及其他涉案财产的,人民检察院可以向人民法院提出没收违法所得的申请。 公安机关认为有前款规定情形的,应当写出没收违法所得意见书,移送人民检察院。 没收违法所得的申请应当提供与犯罪事实、违法所得相关的证据材料,并列明财产的种类、数量、所在地及查封、扣押、冻结的情况。 人民法院在必要的时候,可以查封、扣押、冻结申请没收的财产。 第二百九十九条 没收违法所得的申请,由犯罪地或者犯罪嫌疑人、被告人居住地的中级人民法院组成合议庭进行审理。 人民法院受理没收违法所得的申请后,应当发出公告。公告期间为六个月。犯罪嫌疑人、被告人的近亲属和其他利害关系人有权申请参加诉讼,也可以委托诉讼代理人参加诉讼。 人民法院在公告期满后对没收违法所得的申请进行审理。利害关系人参加诉讼的,人民法院应当开庭审理。 第三百条 人民法院经审理,对经查证属于违法所得及其他涉案财产,除依法返还被害人的以外,应当裁定予以没收;对不属于应当追缴的财产的,应当裁定驳回申请,解除查封、扣押、冻结措施。 对于人民法院依照前款规定作出的裁定,犯罪嫌疑人、被告人的近亲属和其他利害关系人或者人民检察院可以提出上诉、抗诉。 第三百零一条 在审理过程中,在逃的犯罪嫌疑人、被告人自动投案或者被抓获的,人民法院应当终止审理。 没收犯罪嫌疑人、被告人财产确有错误的,应当予以返还、赔偿。 第五章 依法不负刑事责任的精神病人的强制医疗程序第三百零二条 实施暴力行为,危害公共安全或者严重危害公民人身安全,经法定程序鉴定依法不负刑事责任的精神病人,有继续危害社会可能的,可以予以强制医疗。 第三百零三条 根据本章规定对精神病人强制医疗的,由人民法院决定。 公安机关发现精神病人符合强制医疗条件的,应当写出强制医疗意见书,移送人民检察院。对于公安机关移送的或者在审查起诉过程中发现的精神病人符合强制医疗条件的,人民检察院应当向人民法院提出强制医疗的申请。人民法院在审理案件过程中发现被告人符合强制医疗条件的,可以作出强制医疗的决定。 对实施暴力行为的精神病人,在人民法院决定强制医疗前,公安机关可以采取临时的保护性约束措施。 第三百零四条 人民法院受理强制医疗的申请后,应当组成合议庭进行审理。 人民法院审理强制医疗案件,应当通知被申请人或者被告人的法定代理人到场。被申请人或者被告人没有委托诉讼代理人的,人民法院应当通知法律援助机构指派律师为其提供法律帮助。 第三百零五条 人民法院经审理,对于被申请人或者被告人符合强制医疗条件的,应当在一个月以内作出强制医疗的决定。 被决定强制医疗的人、被害人及其法定代理人、近亲属对强制医疗决定不服的,可以向上一级人民法院申请复议。 第三百零六条 强制医疗机构应当定期对被强制医疗的人进行诊断评估。对于已不具有人身危险性,不需要继续强制医疗的,应当及时提出解除意见,报决定强制医疗的人民法院批准。 被强制医疗的人及其近亲属有权申请解除强制医疗。 第三百零七条 人民检察院对强制医疗的决定和执行实行监督。 附则第三百零八条 军队保卫部门对军队内部发生的刑事案件行使侦查权。 中国海警局履行海上维权执法职责,对海上发生的刑事案件行使侦查权。 对罪犯在监狱内犯罪的案件由监狱进行侦查。 军队保卫部门、中国海警局、监狱办理刑事案件,适用本法的有关规定。","link":"/law/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%88%91%E4%BA%8B%E8%AF%89%E8%AE%BC%E6%B3%95.html"},{"title":"中华人民共和国劳动法","text":"《中华人民共和国劳动法》已由中华人民共和国第八届全国人民代表大会常务委员会第八次会议于1994年7月5日通过,现予公布,自1995年1月1日起施行。 中华人民共和国主席令 (第二十八号) 《中华人民共和国劳动法》已由中华人民共和国第八届全国人民代表大会常务委员会第八次会议于1994年7月5日通过,现予公布,自1995年1月1日起施行。 中华人民共和国主席 江泽民 1994年7月5日 中华人民共和国劳动法 (1994年7月5日第八届全国人民代表大会常务委员会第八次会议通过) 目录 第一章 总则 第二章 促进就业 第三章 劳动合同和集体合同 第四章 工作时间和休息休假 第五章 工资 第六章 劳动安全卫生 第七章 女职工和未成年工特殊保护 第八章 职业培训 第九章 社会保险和福利 第十章 劳动争议 第十一章 监督检查 第十二章 法律责任 第十三章 附则 第一章 总则 第一 为了保护劳动者的合法权益,调整劳动关系,建立和维护适应社会主义市场经济的劳动制度,促进经济发展和社会进步,根据宪法,制定本法。 第二 在中华人民共和国境内的企业、个体经济组织(以下统称用人单位)和与之形成劳动关系的劳动者,适用本法。 国家机关、事业组织、社会团体和与之建立劳动合同关系的劳动者,依照本法执行。 第三 劳动者享有平等就业和选择职业的权利、取得劳动报酬的权利、休息休假的权利、获得劳动安全卫生保护的权利、接受职业技能培训的权利、享受社会保险和福利的权利、提请劳动争议处理的权利以及法律规定的其他劳动权利。 劳动者应当完成劳动任务,提高职业技能,执行劳动安全卫生规程,遵守劳动纪律和职业道德。 第四 用人单位应当依法建立和完善规章制度,保障劳动者享有劳动权利和履行劳动义务。 第五 国家采取各种措施,促进劳动就业,发展职业教育,制定劳动标准,调节社会收入,完善社会保险,协调劳动关系,逐步提高劳动者的生活水平。 第六 国家提倡劳动者参加社会义务劳动,开展劳动竞赛和合理化建议活动,鼓励和保护劳动者进行科学研究、技术革新和发明创造,表彰和奖励劳动模范和先进工作者。 第七条 劳动者有权依法参加和组织工会。 工会代表和维护劳动者的合法权益,依法独立自主地开展活动。 第八 劳动者依照法律规定,通过职工大会、职工代表大会或者其他形式,参与民主管理或者就保护劳动者合法权益与用人单位进行平等协商。 第九条 国务院劳动行政部门主管全国劳动工作。 县级以上地方人民政府劳动行政部门主管本行政区域内的劳动工作。 第二章 促进就业 第十 国家通过促进经济和社会发展,创造就业条件,扩大就业机会。 国家鼓励企业、事业组织、社会团体在法律、行政法规规定的范围内兴办产业或者拓展经营,增加就业。 国家支持劳动者自愿组织起来就业和从事个体经营实现就业。 第十一 地方各级人民政府应当采取措施,发展多种类型的职业介绍机构,提供就业服务。 第十二 劳动者就业,不因民族、种族、性别、宗教信仰不同而受歧视。 第十三 妇女享有与男子平等的就业权利。在录用职工时,除国家规定的不适合妇女的工种或者岗位外,不得以性别为由拒绝录用妇女或者提高对妇女的录用标准。 第十四 残疾人、少数民族人员、退出现役的军人的就业,法律、法规有特别规定的,从其规定。 第十五条 禁止用人单位招用未满十六周岁的未成年人。 文艺、体育和特种工艺单位招用未满十六周岁的未成年人,必须依照国家有关规定,履行审批手续,并保障其接受义务教育的权利。 第三章 劳动合同和集体合同 第十六 劳动合同是劳动者与用人单位确立劳动关系、明确双方权利和义务的协议。 建立劳动关系应当订立劳动合同。 第十七 订立和变更劳动合同,应当遵循平等自愿、协商一致的原则,不得违反法律、行政法规的规定。 劳动合同依法订立即具有法律约束力,当事人必须履行劳动合同规定的义务。 第十八条 下列劳动合同无效: (一)违反法律、行政法规的劳动合同; (二)采取欺诈、威胁等手段订立的劳动合同。 无效的劳动合同,从订立的时候起,就没有法律约束力。确认劳动合同部分无效的,如果不影响其余部分的效力,其余部分仍然有效。 劳动合同的无效,由劳动争议仲裁委员会或者人民法院确认。 第十九条 劳动合同应当以书面形式订立,并具备以下条款: (一)劳动合同期限; (二)工作内容; (三)劳动保护和劳动条件; (四)劳动报酬; (五)劳动纪律; (六)劳动合同终止的条件; (七)违反劳动合同的责任。 劳动合同除前款规定的必备条款外,当事人可以协商约定其他内容。 第二十 劳动合同的期限分为有固定期限、无固定期限和以完成一定的工作为期限。 劳动者在同一用人单位连续工作满十年以上,当事人双方同意延续劳动合同的,如果劳动者提出订立无固定期限的劳动合同,应当订立无固定期限的劳动合同。 第二十一 劳动合同可以约定试用期。试用期最长不得超过六个月。 第二十二 劳动合同当事人可以在劳动合同中约定保守用人单位商业秘密的有关事项。 第二十三 劳动合同期满或者当事人约定的劳动合同终止条件出现,劳动合同即行终止。 第二十四条 经劳动合同当事人协商一致,劳动合同可以解除。 第二十五 劳动者有下列情形之一的,用人单位可以解除劳动合同: (一)在试用期间被证明不符合录用条件的; (二)严重违反劳动纪律或者用人单位规章制度的; (三)严重失职,营私舞弊,对用人单位利益造成重大损害的; (四)被依法追究刑事责任的。 第二十六 有下列情形之一的,用人单位可以解除劳动合同,但是应当提前三十日以书面形式通知劳动者本人: (一)劳动者患病或者非因工负伤,医疗期满后,不能从事原工作也不能从事由用人单位另行安排的工作的; (二)劳动者不能胜任工作,经过培训或者调整工作岗位,仍不能胜任工作的; (三)劳动合同订立时所依据的客观情况发生重大变化,致使原劳动合同无法履行,经当事人协商不能就变更劳动合同达成协议的。 第二十七 用人单位濒临破产进行法定整顿期间或者生产经营状况发生严重困难,确需裁减人员的,应当提前三十日向工会或者全体职工说明情况,听取工会或者职工的意见,经向劳动行政部门报告后,可以裁减人员。 用人单位依据本条规定裁减人员,在六个月内录用人员的,应当优先录用被裁减的人员。 第二十八 用人单位依据本法第二十四条、第二十六条、第二十七条的规定解除劳动合同的,应当依照国家有关规定给予经济补偿。 第二十九 劳动者有下列情形之一的,用人单位不得依据本法第二十六条、第二十七条的规定解除劳动合同: (一)患职业病或者因工负伤并被确认丧失或者部分丧失劳动能力的; (二)患病或者负伤,在规定的医疗期内的; (三)女职工在孕期、产假、哺乳期内的; (四)法律、行政法规规定的其他情形。 第三十 用人单位解除劳动合同,工会认为不适当的,有权提出意见。如果用人单位违反法律、法规或者劳动合同,工会有权要求重新处理;劳动者申请仲裁或者提起诉讼的,工会应当依法给予支持和帮助。 第三十一 劳动者解除劳动合同,应当提前三十日以书面形式通知用人单位。 第三十二 有下列情形之一的,劳动者可以随时通知用人单位解除劳动合同: (一)在试用期内的; (二)用人单位以暴力、威胁或者非法限制人身自由的手段强迫劳动的; (三)用人单位未按照劳动合同约定支付劳动报酬或者提供劳动条件的。 第三十三 企业职工一方与企业可以就劳动报酬、工作时间、休息休假、劳动安全卫生、保险福利等事项,签订集体合同。集体合同草案应当提交职工代表大会或者全体职工讨论通过。 集体合同由工会代表职工与企业签订;没有建立工会的企业,由职工推举的代表与企业签订。 第三十四 集体合同签订后应当报送劳动行政部门;劳动行政部门自收到集体合同文本之日起十五日内未提出异议的,集体合同即行生效。 第三十五 依法签订的集体合同对企业和企业全体职工具有约束力。职工个人与企业订立的劳动合同中劳动条件和劳动报酬等标准不得低于集体合同的规定。 第四章 工作时间和休息休假 第三十六 国家实行劳动者每日工作时间不超过八小时、平均每周工作时间不超过四十四小时的工时制度。 第三十七 对实行计件工作的劳动者,用人单位应当根据本法第三十六条规定的工时制度合理确定其劳动定额和计件报酬标准。 第三十八条 用人单位应当保证劳动者每周至少休息一日。 第三十九 企业因生产特点不能实行本法第三十六条、第三十八条规定的,经劳动行政部门批准,可以实行其他工作和休息办法。 第四十条 用人单位在下列节日期间应当依法安排劳动者休假: (一)元旦; (二)春节; (三)国际劳动节; (四)国庆节; (五)法律、法规规定的其他休假节日。 第四十一 用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。 第四十二 有下列情形之一的,延长工作时间不受本法第四十一条规定的限制: (一)发生自然灾害、事故或者因其他原因,威胁劳动者生命健康和财产安全,需要紧急处理的; (二)生产设备、交通运输线路、公共设施发生故障,影响生产和公众利益,必须及时抢修的; (三)法律、行政法规规定的其他情形。 第四十三条 用人单位不得违反本法规定延长劳动者的工作时间。 第四十四 有下列情形之一的,用人单位应当按照下列标准支付高于劳动者正常工作时间工资的工资报酬: (一)安排劳动者延长工作时间的,支付不低于工资的百分之一百五十的工资报酬; (二)休息日安排劳动者工作又不能安排补休的,支付不低于工资的百分之二百的工资报酬; (三)法定休假日安排劳动者工作的,支付不低于工资的百分之三百的工资报酬。 第四十五条 国家实行带薪年休假制度。 劳动者连续工作一年以上的,享受带薪年休假。具体办法由国务院规定。 第五章 工资 第四十六条 工资分配应当遵循按劳分配原则,实行同工同酬。 工资水平在经济发展的基础上逐步提高。国家对工资总量实行宏观调控。 第四十七 用人单位根据本单位的生产经营特点和经济效益,依法自主确定本单位的工资分配方式和工资水平。 第四十八 国家实行最低工资保障制度。最低工资的具体标准由省、自治区、直辖市人民政府规定,报国务院备案。 用人单位支付劳动者的工资不得低于当地最低工资标准。 第四十九条 确定和调整最低工资标准应当综合参考下列因素: (一)劳动者本人及平均赡养人口的最低生活费用; (二)社会平均工资水平; (三)劳动生产率; (四)就业状况; (五)地区之间经济发展水平的差异。 第五十 工资应当以货币形式按月支付给劳动者本人。不得克扣或者无故拖欠劳动者的工资。 第五十一 劳动者在法定休假日和婚丧假期间以及依法参加社会活动期间,用人单位应当依法支付工资。 第六章 劳动安全卫生 第五十二 用人单位必须建立、健全劳动安全卫生制度,严格执行国家劳动安全卫生规程和标准,对劳动者进行劳动安全卫生教育,防止劳动过程中的事故,减少职业危害。 第五十三条 劳动安全卫生设施必须符合国家规定的标准。 新建、改建、扩建工程的劳动安全卫生设施必须与主体工程同时设计、同时施工、同时投入生产和使用。 第五十四 用人单位必须为劳动者提供符合国家规定的劳动安全卫生条件和必要的劳动防护用品,对从事有职业危害作业的劳动者应当定期进行健康检查。 第五十五 从事特种作业的劳动者必须经过专门培训并取得特种作业资格。 第五十六条 劳动者在劳动过程中必须严格遵守安全操作规程。 劳动者对用人单位管理人员违章指挥、强令冒险作业,有权拒绝执行;对危害生命安全和身体健康的行为,有权提出批评、检举和控告。 第五十七 国家建立伤亡事故和职业病统计报告和处理制度。县级以上各级人民政府劳动行政部门、有关部门和用人单位应当依法对劳动者在劳动过程中发生的伤亡事故和劳动者的职业病状况,进行统计、报告和处理。 第七章 女职工和未成年工特殊保护 第五十八条 国家对女职工和未成年工实行特殊劳动保护。 未成年工是指年满十六周岁未满十八周岁的劳动者。 第五十九 禁止安排女职工从事矿山井下、国家规定的第四级体力劳动强度的劳动和其他禁忌从事的劳动。 第六十 不得安排女职工在经期从事高处、低温、冷水作业和国家规定的第三级体力劳动强度的劳动。 第六十一 不得安排女职工在怀孕期间从事国家规定的第三级体力劳动强度的劳动和孕期禁忌从事的活动。对怀孕七个月以上的女职工,不得安排其延长工作时间和夜班劳动。 第六十二条 女职工生育享受不少于九十天的产假。 第六十三 不得安排女职工在哺乳未满一周岁的婴儿期间从事国家规定的第三级体力劳动强度的劳动和哺乳期禁忌从事的其他劳动,不得安排其延长工作时间和夜班劳动。 第六十四 不得安排未成年工从事矿山井下、有毒有害、国家规定的第四级体力劳动强度的劳动和其他禁忌从事的劳动。 第六十五条 用人单位应当对未成年工定期进行健康检查。 第八章 职业培训 第六十六 国家通过各种途径,采取各种措施,发展职业培训事业,开发劳动者的职业技能,提高劳动者素质,增强劳动者的就业能力和工作能力。 第六十七 各级人民政府应当把发展职业培训纳入社会经济发展的规划,鼓励和支持有条件的企业、事业组织、社会团体和个人进行各种形式的职业培训。 第六十八 用人单位应当建立职业培训制度,按照国家规定提取和使用职业培训经费,根据本单位实际,有计划地对劳动者进行职业培训。 从事技术工种的劳动者,上岗前必须经过培训。 第六十九 国家确定职业分类,对规定的职业制定职业技能标准,实行职业资格证书制度,由经过政府批准的考核鉴定机构负责对劳动者实施职业技能考核鉴定。 第九章 社会保险和福利 第七十 国家发展社会保险事业,建立社会保险制度,设立社会保险基金,使劳动者在年老、患病、工伤、失业、生育等情况下获得帮助和补偿。 第七十一 社会保险水平应当与社会经济发展水平和社会承受能力相适应。 第七十二 社会保险基金按照保险类型确定资金来源,逐步实行社会统筹。用人单位和劳动者必须依法参加社会保险,缴纳社会保险费。 第七十三条 劳动者在下列情形下,依法享受社会保险待遇: (一)退休; (二)患病、负伤; (三)因工伤残或者患职业病; (四)失业; (五)生育。 劳动者死亡后,其遗属依法享受遗属津贴。 劳动者享受社会保险待遇的条件和标准由法律、法规规定。 劳动者享受的社会保险金必须按时足额支付。 第七十四 社会保险基金经办机构依照法律规定收支、管理和运营社会保险基金,并负有使社会保险基金保值增值的责任。 社会保险基金监督机构依照法律规定,对社会保险基金的收支、管理和运营实施监督。 社会保险基金经办机构和社会保险基金监督机构的设立和职能由法律规定。 任何组织和个人不得挪用社会保险基金。 第七十五 国家鼓励用人单位根据本单位实际情况为劳动者建立补充保险。 国家提倡劳动者个人进行储蓄性保险。 第七十六 国家发展社会福利事业,兴建公共福利设施,为劳动者休息、休养和疗养提供条件。 用人单位应当创造条件,改善集体福利,提高劳动者的福利待遇。 第十章 劳动争议 第七十七 用人单位与劳动者发生劳动争议,当事人可以依法申请调解、仲裁、提起诉讼,也可以协商解决。 调解原则适用于仲裁和诉讼程序。 第七十八 解决劳动争议,应当根据合法、公正、及时处理的原则,依法维护劳动争议当事人的合法权益。 第七十九 劳动争议发生后,当事人可以向本单位劳动争议调解委员会申请调解;调解不成,当事人一方要求仲裁的,可以向劳动争议仲裁委员会申请仲裁。当事人一方也可以直接向劳动争议仲裁委员会申请仲裁。对仲裁裁决不服的,可以向人民法院提起诉讼。 第八十 在用人单位内,可以设立劳动争议调解委员会。劳动争议调解委员会由职工代表、用人单位代表和工会代表组成。劳动争议调解委员会主任由工会代表担任。 劳动争议经调解达成协议的,当事人应当履行。 第八十一 劳动争议仲裁委员会由劳动行政部门代表、同级工会代表、用人单位方面的代表组成。劳动争议仲裁委员会主任由劳动行政部门代表担任。 第八十二 提出仲裁要求的一方应当自劳动争议发生之日起六十日内向劳动争议仲裁委员会提出书面申请。仲裁裁决一般应在收到仲裁申请的六十日内作出。对仲裁裁决无异议的,当事人必须履行。 第八十三 劳动争议当事人对仲裁裁决不服的,可以自收到仲裁裁决书之日起十五日内向人民法院提起诉讼。一方当事人在法定期限内不起诉又不履行仲裁裁决的,另一方当事人可以申请人民法院强制执行。 第八十四 因签订集体合同发生争议,当事人协商解决不成的,当地人民政府劳动行政部门可以组织有关各方协调处理。 因履行集体合同发生争议,当事人协商解决不成的,可以向劳动争议仲裁委员会申请仲裁;对仲裁裁决不服的,可以自收到仲裁裁决书之日起十五日内向人民法院提起诉讼。 第十一章 监督检查 第八十五 县级以上各级人民政府劳动行政部门依法对用人单位遵守劳动法律、法规的情况进行监督检查,对违反劳动法律、法规的行为有权制止,并责令改正。 第八十六 县级以上各级人民政府劳动行政部门监督检查人员执行公务,有权进入用人单位了解执行劳动法律、法规的情况,查阅必要的资料,并对劳动场所进行检查。 县级以上各级人民政府劳动行政部门监督检查人员执行公务,必须出示证件,秉公执法并遵守有关规定。 第八十七 县级以上各级人民政府有关部门在各自职责范围内,对用人单位遵守劳动法律、法规的情况进行监督。 第八十八 各级工会依法维护劳动者的合法权益,对用人单位遵守劳动法律、法规的情况进行监督。 任何组织和个人对于违反劳动法律、法规的行为有权检举和控告。 第十二章 法律责任 第八十九 用人单位制定的劳动规章制度违反法律、法规规定的,由劳动行政部门给予警告,责令改正;对劳动者造成损害的,应当承担赔偿责任。 第九十 用人单位违反本法规定,延长劳动者工作时间的,由劳动行政部门给予警告,责令改正,并可以处以罚款。 第九十一 用人单位有下列侵害劳动者合法权益情形之一的,由劳动行政部门责令支付劳动者的工资报酬、经济补偿,并可以责令支付赔偿金: (一)克扣或者无故拖欠劳动者工资的; (二)拒不支付劳动者延长工作时间工资报酬的; (三)低于当地最低工资标准支付劳动者工资的; (四)解除劳动合同后,未依照本法规定给予劳动者经济补偿的。 第九十二 用人单位的劳动安全设施和劳动卫生条件不符合国家规定或者未向劳动者提供必要的劳动防护用品和劳动保护设施的,由劳动行政部门或者有关部门责令改正,可以处以罚款;情节严重的,提请县级以上人民政府决定责令停产整顿;对事故隐患不采取措施,致使发生重大事故,造成劳动者生命和财产损失的,对责任人员比照刑法第一百八十七条的规定追究刑事责任。 第九十三 用人单位强令劳动者违章冒险作业,发生重大伤亡事故,造成严重后果的,对责任人员依法追究刑事责任。 第九十四 用人单位非法招用未满十六周岁的未成年人的,由劳动行政部门责令改正,处以罚款;情节严重的,由工商行政管理部门吊销营业执照。 第九十五 用人单位违反本法对女职工和未成年工的保护规定,侵害其合法权益的,由劳动行政部门责令改正,处以罚款;对女职工或者未成年工造成损害的,应当承担赔偿责任。 第九十六 用人单位有下列行为之一,由公安机关对责任人员处以十五日以下拘留、罚款或者警告;构成犯罪的,对责任人员依法追究刑事责任: (一)以暴力、威胁或者非法限制人身自由的手段强迫劳动的; (二)侮辱、体罚、殴打、非法搜查和拘禁劳动者的。 第九十七 由于用人单位的原因订立的无效合同,对劳动者造成损害的,应当承担赔偿责任。 第九十八 用人单位违反本法规定的条件解除劳动合同或者故意拖延不订立劳动合同的,由劳动行政部门责令改正;对劳动者造成损害的,应当承担赔偿责任。 第九十九 用人单位招用尚未解除劳动合同的劳动者,对原用人单位造成经济损失的,该用人单位应当依法承担连带赔偿责任。 第一百 用人单位无故不缴纳社会保险费的,由劳动行政部门责令其限期缴纳;逾期不缴的,可以加收滞纳金。 第一百零一 用人单位无理阻挠劳动行政部门、有关部门及其工作人员行使监督检查权,打击报复举报人员的,由劳动行政部门或者有关部门处以罚款;构成犯罪的,对责任人员依法追究刑事责任。 第一百零二 劳动者违反本法规定的条件解除劳动合同或者违反劳动合同中约定的保密事项,对用人单位造成经济损失的,应当依法承担赔偿责任。 第一百零三 劳动行政部门或者有关部门的工作人员滥用职权、玩忽职守、徇私舞弊,构成犯罪的,依法追究刑事责任;不构成犯罪的,给予行政处分。 第一百零四 国家工作人员和社会保险基金经办机构的工作人员挪用社会保险基金,构成犯罪的,依法追究刑事责任。 第一百零五 违反本法规定侵害劳动者合法权益,其他法律、行政法规已规定处罚的,依照该法律、行政法规的规定处罚。 第十三章 附则 第一百零六 省、自治区、直辖市人民政府根据本法和本地区的实际情况,规定劳动合同制度的实施步骤,报国务院备案。 第一百零七条 本法自1995年1月1日起施行","link":"/law/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%8A%B3%E5%8A%A8%E6%B3%95.html"},{"title":"中华人民共和国婚姻法","text":"基本信息 效力级别法律:时效性现行有效 发布日期:2001-04-28 实施日期:2001-04-28 发布机关:全国人大常委会 法律修订 1980年9月10日第五届全国人民代表大会第三次会议通过 根据2001年4月28日第九届全国人民代表大会常务委员会第二十一次会议《关于修改〈中华人民共和国婚姻法〉的决定》修正 中华人民共和国婚姻法(1980修正) 中华人民共和国婚姻法(1950修正) 正文 第一章 总则第一条 立法目的 本法是婚姻家庭关系的基本准则。 第二条 婚姻制度 实行婚姻自由、一夫一妻、男女平等的婚姻制度。 保护妇女、儿童和老人的合法权益。 实行计划生育。 第三条 禁止的婚姻行为 禁止包办、买卖婚姻和其他干涉婚姻自由的行为。禁止借婚姻索取财物。 禁止重婚。禁止有配偶者与他人同居。禁止家庭暴力。禁止家庭成员间的虐待和遗弃。 第四条 家庭关系 夫妻应当互相忠实,互相尊重;家庭成员间应当敬老爱幼,互相帮助,维护平等、和睦、文明的婚姻家庭关系。 第二章 结婚第五条 结婚自愿 结婚必须男女双方完全自愿,不许任何一方对他方加以强迫或任何第三者加以干涉。 第六条 法定婚龄 结婚年龄,男不得早于二十二周岁,女不得早于二十周岁。晚婚晚育应予鼓励。 第七条 禁止结婚 有下列情形之一的,禁止结婚: (一)直系血亲和三代以内的旁系血亲; (二)患有医学上认为不应当结婚的疾病。 第八条 结婚登记 要求结婚的男女双方必须亲自到婚姻登记机关进行结婚登记。符合本法规定的,予以登记,发给结婚证。取得结婚证,即确立夫妻关系。未办理结婚登记的,应当补办登记。 第九条 互为家庭成员 登记结婚后,根据男女双方约定,女方可以成为男方家庭的成员,男方可以成为女方家庭的成员。 第十条 婚姻无效 有下列情形之一的,婚姻无效: (一)重婚的; (二)有禁止结婚的亲属关系的; (三)婚前患有医学上认为不应当结婚的疾病,婚后尚未治愈的; (四)未到法定婚龄的。 第十一条 胁迫结婚 因胁迫结婚的,受胁迫的一方可以向婚姻登记机关或人民法院请求撤销该婚姻。受胁迫的一方撤销婚姻的请求,应当自结婚登记之日起一年内提出。被非法限制人身自由的当事人请求撤销婚姻的,应当自恢复人身自由之日起一年内提出。 第十二条 婚姻的无效 无效或被撤销的婚姻,自始无效。当事人不具有夫妻的权利和义务。同居期间所得的财产,由当事人协议处理;协议不成时,由人民法院根据照顾无过错方的原则判决。对重婚导致的婚姻无效的财产处理,不得侵害合法婚姻当事人的财产权益。当事人所生的子女,适用本法有关父母子女的规定。 第三章 家庭关系第十三条 夫妻平等 夫妻在家庭中地位平等。 第十四条 夫妻姓名权 夫妻双方都有各用自己姓名的权利。 第十五条 夫妻的自由 夫妻双方都有参加生产、工作、学习和社会活动的自由,一方不得对他方加以限制或干涉。 第十六条 计划生育义务 夫妻双方都有实行计划生育的义务。 第十七条 夫妻共有财产 夫妻在婚姻关系存续期间所得的下列财产,归夫妻共同所有: (一)工资、奖金; (二)生产、经营的收益; (三)知识产权的收益; (四)继承或赠与所得的财产,但本法第十八条第三项规定的除外; (五)其他应当归共同所有的财产。 夫妻对共同所有的财产,有平等的处理权。 第十八条 夫妻一方的财产 有下列情形之一的,为夫妻一方的财产: (一)一方的婚前财产; (二)一方因身体受到伤害获得的医疗费、残疾人生活补助费等费用; (三)遗嘱或赠与合同中确定只归夫或妻一方的财产; (四)一方专用的生活用品; (五)其他应当归一方的财产。 第十九条 夫妻财产约定 夫妻可以约定婚姻关系存续期间所得的财产以及婚前财产归各自所有、共同所有或部分各自所有、部分共同所有。约定应当采用书面形式。没有约定或约定不明确的,适用本法第十七条、第十八条的规定。 夫妻对婚姻关系存续期间所得的财产以及婚前财产的约定,对双方具有约束力。 夫妻对婚姻关系存续期间所得的财产约定归各自所有的,夫或妻一方对外所负的债务,第三人知道该约定的,以夫或妻一方所有的财产清偿。 第二十条 夫妻扶养义务 夫妻有互相扶养的义务。 一方不履行扶养义务时,需要扶养的一方,有要求对方付给扶养费的权利。 第二十一条 父母与子女 父母对子女有抚养教育的义务;子女对父母有赡养扶助的义务。 父母不履行抚养义务时,未成年的或不能独立生活的子女,有要求父母付给抚养费的权利。 子女不履行赡养义务时,无劳动能力的或生活困难的父母,有要求子女付给赡养费的权利。 禁止溺婴、弃婴和其他残害婴儿的行为。 第二十二条 子女的姓 子女可以随父姓,可以随母姓。 第二十三条 父母对子女的保护和教育 父母有保护和教育未成年子女的权利和义务。在未成年子女对国家、集体或他人造成损害时,父母有承担民事责任的义务。 第二十四条 继承遗产 夫妻有相互继承遗产的权利。 父母和子女有相互继承遗产的权利。 第二十五条 非婚生子女 非婚生子女享有与婚生子女同等的权利,任何人不得加以危害和歧视。 不直接抚养非婚生子女的生父或生母,应当负担子女的生活费和教育费,直至子女能独立生活为止。 第二十六条 收养关系 国家保护合法的收养关系。养父母和养子女间的权利和义务,适用本法对父母子女关系的有关规定。 养子女和生父母间的权利和义务,因收养关系的成立而消除。 第二十七条 继父母与继子女 继父母与继子女间,不得虐待或歧视。 继父或继母和受其抚养教育的继子女间的权利和义务,适用本法对父母子女关系的有关规定。 第二十八条 祖与孙 有负担能力的祖父母、外祖父母,对于父母已经死亡或父母无力抚养的未成年的孙子女、外孙子女,有抚养的义务。有负担能力的孙子女、外孙子女,对于子女已经死亡或子女无力赡养的祖父母、外祖父母,有赡养的义务。 第二十九条 兄姐与弟妹 有负担能力的兄、姐,对于父母已经死亡或父母无力抚养的未成年的弟、妹,有扶养的义务。由兄、姐扶养长大的有负担能力的弟、妹,对于缺乏劳动能力又缺乏生活来源的兄、姐,有扶养的义务。 第三十条 尊重父母婚姻 子女应当尊重父母的婚姻权利,不得干涉父母再婚以及婚后的生活。子女对父母的赡养义务,不因父母的婚姻关系变化而终止。 第四章 离婚第三十一条 自愿离婚 男女双方自愿离婚的,准予离婚。双方必须到婚姻登记机关申请离婚。婚姻登记机关查明双方确实是自愿并对子女和财产问题已有适当处理时,发给离婚证。 第三十二条 离婚诉讼 男女一方要求离婚的,可由有关部门进行调解或直接向人民法院提出离婚诉讼。 人民法院审理离婚案件,应当进行调解;如感情确已破裂,调解无效,应准予离婚。 有下列情形之一,调解无效的,应准予离婚: (一)重婚或有配偶者与他人同居的; (二)实施家庭暴力或虐待、遗弃家庭成员的; (三)有赌博、吸毒等恶习屡教不改的; (四)因感情不和分居满二年的; (五)其他导致夫妻感情破裂的情形。 一方被宣告失踪,另一方提出离婚诉讼的,应准予离婚。 第三十三条 军人配偶要求离婚 现役军人的配偶要求离婚,须得军人同意,但军人一方有重大过错的除外。 第三十四条 不得提出离婚 女方在怀孕期间、分娩后一年内或中止妊娠后六个月内,男方不得提出离婚。女方提出离婚的,或人民法院认为确有必要受理男方离婚请求的,不在此限。 第三十五条 复婚 离婚后,男女双方自愿恢复夫妻关系的,必须到婚姻登记机关进行复婚登记。 第三十六条 离婚与子女 父母与子女间的关系,不因父母离婚而消除。离婚后,子女无论由父或母直接抚养,仍是父母双方的子女。 离婚后,父母对于子女仍有抚养和教育的权利和义务。 离婚后,哺乳期内的子女,以随哺乳的母亲抚养为原则。哺乳期后的子女,如双方因抚养问题发生争执不能达成协议时,由人民法院根据子女的权益和双方的具体情况判决。 第三十七条 离婚后的子女抚养 离婚后,一方抚养的子女,另一方应负担必要的生活费和教育费的一部或全部,负担费用的多少和期限的长短,由双方协议;协议不成时,由人民法院判决。 关于子女生活费和教育费的协议或判决,不妨碍子女在必要时向父母任何一方提出超过协议或判决原定数额的合理要求。 第三十八条 离婚后的子女探望 离婚后,不直接抚养子女的父或母,有探望子女的权利,另一方有协助的义务。 行使探望权利的方式、时间由当事人协议;协议不成时,由人民法院判决。 父或母探望子女,不利于子女身心健康的,由人民法院依法中止探望的权利;中止的事由消失后,应当恢复探望的权利。 第三十九条 夫妻共同财产的离婚处理 离婚时,夫妻的共同财产由双方协议处理;协议不成时,由人民法院根据财产的具体情况,照顾子女和女方权益的原则判决。 夫或妻在家庭土地承包经营中享有的权益等,应当依法予以保护。 第四十条 补偿 夫妻书面约定婚姻关系存续期间所得的财产归各自所有,一方因抚育子女、照料老人、协助另一方工作等付出较多义务的,离婚时有权向另一方请求补偿,另一方应当予以补偿。 第四十一条 共同债务 离婚时,原为夫妻共同生活所负的债务,应当共同偿还。共同财产不足清偿的,或财产归各自所有的,由双方协议清偿;协议不成时,由人民法院判决。 第四十二条 适当帮助 离婚时,如一方生活困难,另一方应从其住房等个人财产中给予适当帮助。具体办法由双方协议;协议不成时,由人民法院判决。 第五章 救助措施与法律责任第四十三条 家庭暴力与虐待 实施家庭暴力或虐待家庭成员,受害人有权提出请求,居民委员会、村民委员会以及所在单位应当予以劝阻、调解。 对正在实施的家庭暴力,受害人有权提出请求,居民委员会、村民委员会应当予以劝阻;公安机关应当予以制止。 实施家庭暴力或虐待家庭成员,受害人提出请求的,公安机关应当依照治安管理处罚的法律规定予以行政处罚。 第四十四条 遗弃 对遗弃家庭成员,受害人有权提出请求,居民委员会、村民委员会以及所在单位应当予以劝阻、调解。 对遗弃家庭成员,受害人提出请求的,人民法院应当依法作出支付扶养费、抚养费、赡养费的判决。 第四十五条 家庭暴力、虐待、遗弃犯罪 对重婚的,对实施家庭暴力或虐待、遗弃家庭成员构成犯罪的,依法追究刑事责任。受害人可以依照刑事诉讼法的有关规定,向人民法院自诉;公安机关应当依法侦查,人民检察院应当依法提起公诉。 第四十六条 损害赔偿 有下列情形之一,导致离婚的,无过错方有权请求损害赔偿: (一)重婚的; (二)有配偶者与他人同居的; (三)实施家庭暴力的; (四)虐待、遗弃家庭成员的。 第四十七条 隐藏、转移共同财产等 离婚时,一方隐藏、转移、变卖、毁损夫妻共同财产,或伪造债务企图侵占另一方财产的,分割夫妻共同财产时,对隐藏、转移、变卖、毁损夫妻共同财产或伪造债务的一方,可以少分或不分。离婚后,另一方发现有上述行为的,可以向人民法院提起诉讼,请求再次分割夫妻共同财产。 人民法院对前款规定的妨害民事诉讼的行为,依照民事诉讼法的规定予以制裁。 第四十八条 强制执行 对拒不执行有关扶养费、抚养费、赡养费、财产分割、遗产继承、探望子女等判决或裁定的,由人民法院依法强制执行。有关个人和单位应负协助执行的责任。 第四十九条 婚姻家庭的其他违法 其他法律对有关婚姻家庭的违法行为和法律责任另有规定的,依照其规定。 第六章 附则第五十条 变通规定 民族自治地方的人民代表大会有权结合当地民族婚姻家庭的具体情况,制定变通规定。自治州、自治县制定的变通规定,报省、自治区、直辖市人民代表大会常务委员会批准后生效。自治区制定的变通规定,报全国人民代表大会常务委员会批准后生效。","link":"/law/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%A9%9A%E5%A7%BB%E6%B3%95.html"},{"title":"mysql高性能优化规范方法","text":"数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 **临时库表必须以tmp_为前缀并以日期为后缀,备份表必须以bak_**为前缀并以日期(时间戳)为后缀 所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低) 数据库基本设计规范所有表必须使用Innodb存储引擎没有特殊要求(即Innodb无法满足的功能如:列存储,存储空间数据等)的情况下,所有表必须使用Innodb存储引擎(mysql5.5之前默认使用Myisam,5.6以后默认的为Innodb)。 Innodb 支持事务,支持行级锁,更好的恢复性,高并发下性能更好。 数据库和表的字符集统一使用UTF8兼容性更好,统一字符集可以避免由于字符集转换产生的乱码,不同的字符集进行比较前需要进行转换会造成索引失效,如果数据库中有存储emoji表情的需要,字符集需要采用utf8mb4字符集。 所有表和字段都需要添加注释使用comment从句添加表和列的备注,从一开始就进行数据字典的维护 尽量控制单表数据量的大小,建议控制在500万以内。500万并不是Mysql数据库的限制,过大会造成修改表结构,备份,恢复都会有很大的问题。 可以用历史数据归档(应用于日志数据),分库分表(应用于业务数据)等手段来控制数据量大小 谨慎使用Mysql分区表分区表在物理上表现为多个文件,在逻辑上表现为一个表; 谨慎选择分区键,跨分区查询效率可能更低; 建议采用物理分表的方式管理大数据。 尽量做到冷热数据分离,减小表的宽度Mysql限制每个表最多存储4096列,并且每一行数据的大小不能超过65535字节。 减少磁盘IO,保证热数据的内存缓存命中率(表越宽,把表装载进内存缓冲池时所占用的内存也就越大,也会消耗更多的IO); 更有效的利用缓存,避免读入无用的冷数据; 经常一起使用的列放到一个表中(避免更多的关联操作)。 禁止在表中建立预留字段预留字段的命名很难做到见名识义。 预留字段无法确认存储的数据类型,所以无法选择合适的类型。 对预留字段类型的修改,会对表进行锁定。 禁止在数据库中存储图片,文件等大的二进制数据通常文件很大,会短时间内造成数据量快速增长,数据库进行数据库读取时,通常会进行大量的随机IO操作,文件很大时,IO操作很耗时。 通常存储于文件服务器,数据库只存储文件地址信息 禁止在线上做数据库压力测试禁止从开发环境,测试环境直接连接生产环境数据库 数据库字段设计规范优先选择符合存储需要的最小的数据类型原因: 列的字段越大,建立索引时所需要的空间也就越大,这样一页中所能存储的索引节点的数量也就越少也越少,在遍历时所需要的IO次数也就越多,索引的性能也就越差。 方法: 将字符串转换成数字类型存储,如:将IP地址转换成整形数据mysql提供了两个方法来处理ip地址 inet_aton 把ip转为无符号整型(4-8位) inet_ntoa 把整型的ip转为地址 插入数据前,先用inet_aton把ip地址转为整型,可以节省空间,显示数据时,使用inet_ntoa把整型的ip地址转为地址显示即可。 对于非负型的数据(如自增ID、整型IP)来说,要优先使用无符号整型来存储原因: 无符号相对于有符号可以多出一倍的存储空间 12SIGNED INT -2147483648~2147483647UNSIGNED INT 0~4294967295 VARCHAR(N)中的N代表的是字符数,而不是字节数,使用UTF8存储255个汉字 Varchar(255)=765个字节。过大的长度会消耗更多的内存。 避免使用TEXT、BLOB数据类型,最常见的TEXT类型可以存储64k的数据建议把BLOB或是TEXT列分离到单独的扩展表中Mysql内存临时表不支持TEXT、BLOB这样的大数据类型,如果查询中包含这样的数据,在排序等操作时,就不能使用内存临时表,必须使用磁盘临时表进行。而且对于这种数据,Mysql还是要进行二次查询,会使sql性能变得很差,但是不是说一定不能使用这样的数据类型。 如果一定要使用,建议把BLOB或是TEXT列分离到单独的扩展表中,查询时一定不要使用select * 而只需要取出必要的列,不需要TEXT列的数据时不要对该列进行查询。 TEXT或BLOB类型只能使用前缀索引因为MySQL对索引字段长度是有限制的,所以TEXT类型只能使用前缀索引,并且TEXT列上是不能有默认值的 避免使用ENUM类型修改ENUM值需要使用ALTER语句 ENUM类型的ORDER BY操作效率低,需要额外操作 禁止使用数值作为ENUM的枚举值 尽可能把所有列定义为NOT NULL原因: 索引NULL列需要额外的空间来保存,所以要占用更多的空间 进行比较和计算时要对NULL值做特别的处理 使用TIMESTAMP(4个字节)或DATETIME类型(8个字节)存储时间TIMESTAMP 存储的时间范围 1970-01-01 00:00:01 ~ 2038-01-19-03:14:07 TIMESTAMP 占用4字节和INT相同,但比INT可读性高 超出TIMESTAMP取值范围的使用DATETIME类型存储 经常会有人用字符串存储日期型的数据(不正确的做法) 缺点1:无法用日期函数进行计算和比较 缺点2:用字符串存储日期要占用更多的空间 同财务相关的金额类数据必须使用decimal类型 非精准浮点:float,double 精准浮点:decimal Decimal类型为精准浮点数,在计算时不会丢失精度 占用空间由定义的宽度决定,每4个字节可以存储9位数字,并且小数点要占用一个字节 可用于存储比bigint更大的整型数据 索引设计规范限制每张表上的索引数量,建议单张表索引不超过5个索引并不是越多越好!索引可以提高效率同样可以降低效率。 索引可以增加查询效率,但同样也会降低插入和更新的效率,甚至有些情况下会降低查询效率。 因为mysql优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,就会增加mysql优化器生成执行计划的时间,同样会降低查询性能。 禁止给表中的每一列都建立单独的索引5.6版本之前,一个sql只能使用到一个表中的一个索引,5.6以后,虽然有了合并索引的优化方式,但是还是远远没有使用一个联合索引的查询方式好。 每个Innodb表必须有个主键Innodb是一种索引组织表:数据的存储的逻辑顺序和索引的顺序是相同的。每个表都可以有多个索引,但是表的存储顺序只能有一种。 Innodb是按照主键索引的顺序来组织表的 不要使用更新频繁的列作为主键,不适用多列主键(相当于联合索引) 不要使用UUID,MD5,HASH,字符串列作为主键(无法保证数据的顺序增长) 主键建议使用自增ID值 常见索引列建议 出现在SELECT、UPDATE、DELETE语句的WHERE从句中的列 包含在ORDER BY、GROUP BY、DISTINCT中的字段 并不要将符合1和2中的字段的列都建立一个索引, 通常将1、2中的字段建立联合索引效果更好 多表join的关联列 如何选择索引列的顺序建立索引的目的是:希望通过索引进行数据查找,减少随机IO,增加查询性能 ,索引能过滤出越少的数据,则从磁盘中读入的数据也就越少。 区分度最高的放在联合索引的最左侧(区分度=列中不同值的数量/列的总行数) 尽量把字段长度小的列放在联合索引的最左侧(因为字段长度越小,一页能存储的数据量越大,IO性能也就越好) 使用最频繁的列放到联合索引的左侧(这样可以比较少的建立一些索引) 避免建立冗余索引和重复索引(增加了查询优化器生成执行计划的时间) 重复索引示例:primary key(id)、index(id)、unique index(id) 冗余索引示例:index(a,b,c)、index(a,b)、index(a) 对于频繁的查询优先考虑使用覆盖索引覆盖索引:就是包含了所有查询字段(where,select,ordery by,group by包含的字段)的索引 覆盖索引的好处: 避免Innodb表进行索引的二次查询Innodb是以聚集索引的顺序来存储的,对于Innodb来说,二级索引在叶子节点中所保存的是行的主键信息,如果是用二级索引查询数据的话,在查找到相应的键值后,还要通过主键进行二次查询才能获取我们真实所需要的数据。 而在覆盖索引中,二级索引的键值中可以获取所有的数据,避免了对主键的二次查询 ,减少了IO操作,提升了查询效率。 可以把随机IO变成顺序IO加快查询效率由于覆盖索引是按键值的顺序存储的,对于IO密集型的范围查找来说,对比随机从磁盘读取每一行的数据IO要少的多,因此利用覆盖索引在访问时也可以把磁盘的随机读取的IO转变成索引查找的顺序IO。 索引SET规范尽量避免使用外键约束 不建议使用外键约束(foreign key),但一定要在表与表之间的关联键上建立索引 外键可用于保证数据的参照完整性,但建议在业务端实现 外键会影响父表和子表的写操作从而降低性能 数据库SQL开发规范建议使用预编译语句进行数据库操作预编译语句可以重复使用这些计划,减少SQL编译所需要的时间,还可以解决动态SQL所带来的SQL注入的问题。 只传参数,比传递SQL语句更高效。 相同语句可以一次解析,多次使用,提高处理效率。 避免数据类型的隐式转换隐式转换会导致索引失效如: 1select name,phone from customer where id = '111'; 充分利用表上已经存在的索引s避免使用双%号的查询条件。如:a like '%123%',(如果无前置%,只有后置%,是可以用到列上的索引的) 一个SQL只能利用到复合索引中的一列进行范围查询。如:有 a,b,c列的联合索引,在查询条件中有a列的范围查询,则在b,c列上的索引将不会被用到。 在定义联合索引时,如果a列要用到范围查找的话,就要把a列放到联合索引的右侧,使用left join 或 not exists来优化not in 操作,因为not in 也通常会使用索引失效。 数据库设计时,应该要对以后扩展进行考虑程序连接不同的数据库使用不同的账号,进制跨库查询 为数据库迁移和分库分表留出余地 降低业务耦合度 避免权限过大而产生的安全风险 禁止使用SELECT * 必须使用SELECT <字段列表> 查询原因: 消耗更多的CPU和IO以网络带宽资源 无法使用覆盖索引 可减少表结构变更带来的影响 禁止使用不含字段列表的INSERT语句如: 1insert into values ('a','b','c'); 应使用: 1insert into t(c1,c2,c3) values ('a','b','c'); 避免使用子查询,可以把子查询优化为join操作通常子查询在in子句中,且b中为简单SQL(不包含union、group by、order by、limit从句)时,才可以把子查询转化为关联查询进行优化。 子查询性能差的原因: 子查询的结果集无法使用索引,通常子查询的结果集会被存储到临时表中,不论是内存临时表还是磁盘临时表都不会存在索引,所以查询性能会受到一定的影响。特别是对于返回结果集比较大的子查询,其对查询性能的影响也就越大。 由于子查询会产生大量的临时表也没有索引,所以会消耗过多的CPU和IO资源,产生大量的慢查询。 避免使用JOIN关联太多的表对于Mysql来说,是存在关联缓存的,缓存的大小可以由join_buffer_size参数进行设置。 在Mysql中,对于同一个SQL多关联(join)一个表,就会多分配一个关联缓存,如果在一个SQL中关联的表越多,所占用的内存也就越大。 如果程序中大量的使用了多表关联的操作,同时join_buffer_size设置的也不合理的情况下,就容易造成服务器内存溢出的情况,就会影响到服务器数据库性能的稳定性。 同时对于关联操作来说,会产生临时表操作,影响查询效率,Mysql最多允许关联61个表,建议不超过5个。 减少同数据库的交互次数数据库更适合处理批量操作,合并多个相同的操作到一起,可以提高处理效率。 对应同一列进行or判断时,使用in代替orin 的值不要超过500个,in 操作可以更有效的利用索引,or大多数情况下很少能利用到索引。 禁止使用order by rand() 进行随机排序order by rand()会把表中所有符合条件的数据装载到内存中,然后在内存中对所有数据根据随机生成的值进行排序,并且可能会对每一行都生成一个随机值,如果满足条件的数据集非常大,就会消耗大量的CPU和IO及内存资源。 推荐在程序中获取一个随机值,然后从数据库中获取数据的方式。 WHERE从句中禁止对列进行函数转换和计算对列进行函数转换或计算时会导致无法使用索引 不推荐: 1where date(create_time)='20190101' 推荐: 1where create_time >= '20190101' and create_time < '20190102' 在明显不会有重复值时使用UNION ALL 而不是UNION UNION 会把两个结果集的所有数据放到临时表中后再进行去重操作 UNION ALL 不会再对结果集进行去重操作 拆分复杂的大SQL为多个小SQL 大SQL逻辑上比较复杂,需要占用大量CPU进行计算的SQL MySQL中,一个SQL只能使用一个CPU进行计算 SQL拆分后可以通过并行执行来提高处理效率 数据库操作行为规范超100万行的批量写(UPDATE、DELETE、INSERT)操作,要分批多次进行操作大批量操作可能会造成严重的主从延迟 主从环境中,大批量操作可能会造成严重的主从延迟,大批量的写操作一般都需要执行一定长的时间,而只有当主库上执行完成后,才会在其他从库上执行,所以会造成主库与从库长时间的延迟情况 binlog日志为row格式时会产生大量的日志 大批量写操作会产生大量日志,特别是对于row格式二进制数据而言,由于在row格式中会记录每一行数据的修改,我们一次修改的数据越多,产生的日志量也就会越多,日志的传输和恢复所需要的时间也就越长,这也是造成主从延迟的一个原因。 避免产生大事务操作 大批量修改数据,一定是在一个事务中进行的,这就会造成表中大批量数据进行锁定,从而导致大量的阻塞,阻塞会对MySQL的性能产生非常大的影响。 特别是长时间的阻塞会占满所有数据库的可用连接,这会使生产环境中的其他应用无法连接到数据库,因此一定要注意大批量写操作要进行分批 对于大表使用pt-online-schema-change修改表结构 避免大表修改产生的主从延迟 避免在对表字段进行修改时进行锁表 对大表数据结构的修改一定要谨慎,会造成严重的锁表操作,尤其是生产环境,是不能容忍的。 pt-online-schema-change它会首先建立一个与原表结构相同的新表,并且在新表上进行表结构的修改,然后再把原表中的数据复制到新表中,并在原表中增加一些触发器。把原表中新增的数据也复制到新表中,在行所有数据复制完成之后,把新表命名成原表,并把原来的表删除掉。把原来一个DDL操作,分解成多个小的批次进行。 禁止为程序使用的账号赋予super权限 当达到最大连接数限制时,还运行1个有super权限的用户连接 super权限只能留给DBA处理问题的账号使用 对于程序连接数据库账号,遵循权限最小原则 程序使用数据库账号只能在一个DB下使用,不准跨库 程序使用的账号原则上不准有drop权限 文章来源 .","link":"/database/mysql/mysql%E9%AB%98%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E8%A7%84%E8%8C%83%E6%96%B9%E6%B3%95.html"},{"title":"Java容器集合","text":"容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。 概览容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。 Collection 1. Set TreeSet:基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。 HashSet:基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。 LinkedHashSet:具有 HashSet 的查找效率,且内部使用双向链表维护元素的插入顺序。 2. List ArrayList:基于动态数组实现,支持随机访问。 Vector:和 ArrayList 类似,但它是线程安全的。 LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。 3. Queue LinkedList:可以用它来实现双向队列。 PriorityQueue:基于堆结构实现,可以用它来实现优先队列。 Map TreeMap:基于红黑树实现。 HashMap:基于哈希表实现。 HashTable:和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。它是遗留类,不应该去使用它。现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁。 LinkedHashMap:使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。 容器中的设计模式迭代器模式 Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。 从 JDK 1.5 之后可以使用 foreach 方法来遍历实现了 Iterable 接口的聚合对象。 123456List<String> list = new ArrayList<>();list.add(\"a\");list.add(\"b\");for (String item : list) { System.out.println(item);} 适配器模式java.util.Arrays#asList() 可以把数组类型转换为 List 类型。 12@SafeVarargspublic static <T> List<T> asList(T... a) 应该注意的是 asList() 的参数为泛型的变长参数,不能使用基本类型数组作为参数,只能使用相应的包装类型数组。 12Integer[] arr = {1, 2, 3};List list = Arrays.asList(arr); 也可以使用以下方式调用 asList(): 1List list = Arrays.asList(1, 2, 3); 源码分析如果没有特别说明,以下源码分析基于 JDK 1.8。 在 IDEA 中 double shift 调出 Search EveryWhere,查找源码文件,找到之后就可以阅读源码。 ArrayList1. 概览因为 ArrayList 是基于数组实现的,所以支持快速随机访问。RandomAccess 接口标识着该类支持快速随机访问。 12public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable 数组的默认大小为 10。 1private static final int DEFAULT_CAPACITY = 10; 2. 扩容添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够时,需要使用 grow() 方法进行扩容,新容量的大小为 oldCapacity + (oldCapacity >> 1),也就是旧容量的 1.5 倍。 扩容操作需要调用 Arrays.copyOf() 把原数组整个复制到新数组中,这个操作代价很高,因此最好在创建 ArrayList 对象时就指定大概的容量大小,减少扩容操作的次数。 12345678910111213141516171819202122232425262728293031public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true;}private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity);}private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity);}private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);} 3. 删除元素需要调用 System.arraycopy() 将 index+1 后面的元素都复制到 index 位置上,该操作的时间复杂度为 O(N),可以看出 ArrayList 删除元素的代价是非常高的。 12345678910public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue;} 4. Fail-FastmodCount 用来记录 ArrayList 结构发生变化的次数。结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化。 在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了需要抛出 ConcurrentModificationException。 123456789101112131415161718private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); // Write out size as capacity for behavioural compatibility with clone() s.writeInt(size); // Write out all elements in the proper order. for (int i=0; i<size; i++) { s.writeObject(elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); }} 5. 序列化ArrayList 基于数组实现,并且具有动态扩容特性,因此保存元素的数组不一定都会被使用,那么就没必要全部进行序列化。 保存元素的数组 elementData 使用 transient 修饰,该关键字声明数组默认不会被序列化。 1transient Object[] elementData; // non-private to simplify nested class access ArrayList 实现了 writeObject() 和 readObject() 来控制只序列化数组中有元素填充那部分内容。 123456789101112131415161718192021222324252627282930313233343536373839private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { elementData = EMPTY_ELEMENTDATA; // Read in size, and any hidden stuff s.defaultReadObject(); // Read in capacity s.readInt(); // ignored if (size > 0) { // be like clone(), allocate array based upon size not capacity ensureCapacityInternal(size); Object[] a = elementData; // Read in all elements in the proper order. for (int i=0; i<size; i++) { a[i] = s.readObject(); } }}private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); // Write out size as capacity for behavioural compatibility with clone() s.writeInt(size); // Write out all elements in the proper order. for (int i=0; i<size; i++) { s.writeObject(elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); }} 序列化时需要使用 ObjectOutputStream 的 writeObject() 将对象转换为字节流并输出。而 writeObject() 方法在传入的对象存在 writeObject() 的时候会去反射调用该对象的 writeObject() 来实现序列化。反序列化使用的是 ObjectInputStream 的 readObject() 方法,原理类似。 123ArrayList list = new ArrayList();ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));oos.writeObject(list); Vector1. 同步它的实现与 ArrayList 类似,但是使用了 synchronized 进行同步。 12345678910111213public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true;}public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index);} 2. 与 ArrayList 的比较 Vector 是同步的,因此开销就比 ArrayList 要大,访问速度更慢。最好使用 ArrayList 而不是 Vector,因为同步操作完全可以由程序员自己来控制; Vector 每次扩容请求其大小的 2 倍空间,而 ArrayList 是 1.5 倍。 3. 替代方案可以使用 Collections.synchronizedList(); 得到一个线程安全的 ArrayList。 12List<String> list = new ArrayList<>();List<String> synList = Collections.synchronizedList(list); 也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。 1List<String> list = new CopyOnWriteArrayList<>(); CopyOnWriteArrayList读写分离写操作在一个复制的数组上进行,读操作还是在原始数组中进行,读写分离,互不影响。 写操作需要加锁,防止并发写入时导致写入数据丢失。 写操作结束之后需要把原始数组指向新的复制数组。 12345678910111213141516171819202122public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); }}final void setArray(Object[] a) { array = a;}@SuppressWarnings(\"unchecked\")private E get(Object[] a, int index) { return (E) a[index];} 适用场景CopyOnWriteArrayList 在写操作的同时允许读操作,大大提高了读操作的性能,因此很适合读多写少的应用场景。 但是 CopyOnWriteArrayList 有其缺陷: 内存占用:在写操作时需要复制一个新的数组,使得内存占用为原来的两倍左右; 数据不一致:读操作不能读取实时性的数据,因为部分写操作的数据还未同步到读数组中。 所以 CopyOnWriteArrayList 不适合内存敏感以及对实时性要求很高的场景。 LinkedList1. 概览基于双向链表实现,使用 Node 存储链表节点信息。 12345private static class Node<E> { E item; Node<E> next; Node<E> prev;} 每个链表存储了 first 和 last 指针: 12transient Node<E> first;transient Node<E> last; 2. 与 ArrayList 的比较 ArrayList 基于动态数组实现,LinkedList 基于双向链表实现; ArrayList 支持随机访问,LinkedList 不支持; LinkedList 在任意位置添加删除元素更快。 HashMap为了便于理解,以下源码分析以 JDK 1.7 为主。 1. 存储结构内部包含了一个 Entry 类型的数组 table。 1transient Entry[] table; Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值和散列桶取模运算结果相同的 Entry。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; int hash; Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; } public final K getKey() { return key; } public final V getValue() { return value; } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } public final boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; } public final int hashCode() { return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue()); } public final String toString() { return getKey() + \"=\" + getValue(); }} 2. 拉链法的工作原理1234HashMap<String, String> map = new HashMap<>();map.put(\"K1\", \"V1\");map.put(\"K2\", \"V2\");map.put(\"K3\", \"V3\"); 新建一个 HashMap,默认大小为 16; 插入 <K1,V1> 键值对,先计算 K1 的 hashCode 为 115,使用除留余数法得到所在的桶下标 115%16=3。 插入 <K2,V2> 键值对,先计算 K2 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6。 插入 <K3,V3> 键值对,先计算 K3 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6,插在 <K2,V2> 前面。 应该注意到链表的插入是以头插法方式进行的,例如上面的 <K3,V3> 不是插在 <K2,V2> 后面,而是插入在链表头部。 查找需要分成两步进行: 计算键值对所在的桶; 在链表上顺序查找,时间复杂度显然和链表的长度成正比。 3. put 操作1234567891011121314151617181920212223242526public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } // 键为 null 单独处理 if (key == null) return putForNullKey(value); int hash = hash(key); // 确定桶下标 int i = indexFor(hash, table.length); // 先找出是否已经存在键为 key 的键值对,如果存在的话就更新这个键值对的值为 value for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; // 插入新键值对 addEntry(hash, key, value, i); return null;} HashMap 允许插入键为 null 的键值对。但是因为无法调用 null 的 hashCode() 方法,也就无法确定该键值对的桶下标,只能通过强制指定一个桶下标来存放。HashMap 使用第 0 个桶存放键为 null 的键值对。 12345678910111213private V putForNullKey(V value) { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(0, null, value, 0); return null;} 使用链表的头插法,也就是新的键值对插在链表的头部,而不是链表的尾部。 12345678910111213141516171819202122void addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex);}void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; // 头插法,链表头部指向新的键值对 table[bucketIndex] = new Entry<>(hash, key, value, e); size++;}Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h;} 4. 确定桶下标很多操作都需要先确定一个键值对所在的桶下标。 12int hash = hash(key);int i = indexFor(hash, table.length); 4.1 计算 hash 值 1234567891011121314151617final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4);}public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value);} 4.2 取模 令 x = 1<<4,即 x 为 2 的 4 次方,它具有以下性质: 12x : 00010000x-1 : 00001111 令一个数 y 与 x-1 做与运算,可以去除 y 位级表示的第 4 位以上数: 123y : 10110010x-1 : 00001111y&(x-1) : 00000010 这个性质和 y 对 x 取模效果是一样的: 123y : 10110010x : 00010000y%x : 00000010 我们知道,位运算的代价比求模运算小的多,因此在进行这种计算时用位运算的话能带来更高的性能。 确定桶下标的最后一步是将 key 的 hash 值对桶个数取模:hash%capacity,如果能保证 capacity 为 2 的 n 次方,那么就可以将这个操作转换为位运算。 123static int indexFor(int h, int length) { return h & (length-1);} 5. 扩容-基本原理设 HashMap 的 table 长度为 M,需要存储的键值对数量为 N,如果哈希函数满足均匀性的要求,那么每条链表的长度大约为 N/M,因此平均查找次数的复杂度为 O(N/M)。 为了让查找的成本降低,应该尽可能使得 N/M 尽可能小,因此需要保证 M 尽可能大,也就是说 table 要尽可能大。HashMap 采用动态扩容来根据当前的 N 值来调整 M 值,使得空间效率和时间效率都能得到保证。 和扩容相关的参数主要有:capacity、size、threshold 和 load_factor。 参数 含义 capacity table 的容量大小,默认为 16。需要注意的是 capacity 必须保证为 2 的 n 次方。 size 键值对数量。 threshold size 的临界值,当 size 大于等于 threshold 就必须进行扩容操作。 loadFactor 装载因子,table 能够使用的比例,threshold = capacity * loadFactor。 123456789101112131415static final int DEFAULT_INITIAL_CAPACITY = 16;static final int MAXIMUM_CAPACITY = 1 << 30;static final float DEFAULT_LOAD_FACTOR = 0.75f;transient Entry[] table;transient int size;int threshold;final float loadFactor;transient int modCount; 从下面的添加元素代码中可以看出,当需要扩容时,令 capacity 为原来的两倍。 123456void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e); if (size++ >= threshold) resize(2 * table.length);} 扩容使用 resize() 实现,需要注意的是,扩容操作同样需要把 oldTable 的所有键值对重新插入 newTable 中,因此这一步是很费时的。 123456789101112131415161718192021222324252627282930void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor);}void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null) { src[j] = null; do { Entry<K,V> next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } }} 6. 扩容-重新计算桶下标在进行扩容时,需要把键值对重新放到对应的桶上。HashMap 使用了一个特殊的机制,可以降低重新计算桶下标的操作。 假设原数组长度 capacity 为 16,扩容之后 new capacity 为 32: 12capacity : 00010000new capacity : 00100000 对于一个 Key, 它的哈希值如果在第 5 位上为 0,那么取模得到的结果和之前一样; 如果为 1,那么得到的结果为原来的结果 +16。 7. 计算数组容量HashMap 构造函数允许用户传入的容量不是 2 的 n 次方,因为它可以自动地将传入的容量转换为 2 的 n 次方。 先考虑如何求一个数的掩码,对于 10010000,它的掩码为 11111111,可以使用以下方法得到: 123mask |= mask >> 1 11011000mask |= mask >> 2 11111110mask |= mask >> 4 11111111 mask+1 是大于原始数字的最小的 2 的 n 次方。 12num 10010000mask+1 100000000 以下是 HashMap 中计算数组容量的代码: 123456789static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;} 8. 链表转红黑树从 JDK 1.8 开始,一个桶存储的链表长度大于 8 时会将链表转换为红黑树。 应该是:从 JDK 1.8 开始, table的长度也就是HashMap的capacity(不是size)不能小于64而且在桶存储的链表长度为8时(准确的说是长度为7并且在继续塞第8个时),转换成红黑树,而不是超过8。 9. 与 HashTable 的比较 HashTable 使用 synchronized 来进行同步。 HashMap 可以插入键为 null 的 Entry。 HashMap 的迭代器是 fail-fast 迭代器。 HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。 ConcurrentHashMap1. 存储结构123456static final class HashEntry<K,V> { final int hash; final K key; volatile V value; volatile HashEntry<K,V> next;} ConcurrentHashMap 和 HashMap 实现上类似,最主要的差别是 ConcurrentHashMap 采用了分段锁(Segment),每个分段锁维护着几个桶(HashEntry),多个线程可以同时访问不同分段锁上的桶,从而使其并发度更高(并发度就是 Segment 的个数)。 Segment 继承自 ReentrantLock。 123456789101112131415161718static final class Segment<K,V> extends ReentrantLock implements Serializable { private static final long serialVersionUID = 2249069246763182397L; static final int MAX_SCAN_RETRIES = Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1; transient volatile HashEntry<K,V>[] table; transient int count; transient int modCount; transient int threshold; final float loadFactor;}final Segment<K,V>[] segments; 默认的并发级别为 16,也就是说默认创建 16 个 Segment。 1static final int DEFAULT_CONCURRENCY_LEVEL = 16; 2. size 操作每个 Segment 维护了一个 count 变量来统计该 Segment 中的键值对个数。 12345/** * The number of elements. Accessed only either within locks * or among other volatile reads that maintain visibility. */transient int count; 在执行 size 操作时,需要遍历所有 Segment 然后把 count 累计起来。 ConcurrentHashMap 在执行 size 操作时先尝试不加锁,如果连续两次不加锁操作得到的结果一致,那么可以认为这个结果是正确的。 尝试次数使用 RETRIES_BEFORE_LOCK 定义,该值为 2,retries 初始值为 -1,因此尝试次数为 3。 如果尝试的次数超过 3 次,就需要对每个 Segment 加锁。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849/** * Number of unsynchronized retries in size and containsValue * methods before resorting to locking. This is used to avoid * unbounded retries if tables undergo continuous modification * which would make it impossible to obtain an accurate result. */static final int RETRIES_BEFORE_LOCK = 2;public int size() { // Try a few times to get accurate count. On failure due to // continuous async changes in table, resort to locking. final Segment<K,V>[] segments = this.segments; int size; boolean overflow; // true if size overflows 32 bits long sum; // sum of modCounts long last = 0L; // previous sum int retries = -1; // first iteration isn't retry try { for (;;) { // 超过尝试次数,则对每个 Segment 加锁 if (retries++ == RETRIES_BEFORE_LOCK) { for (int j = 0; j < segments.length; ++j) ensureSegment(j).lock(); // force creation } sum = 0L; size = 0; overflow = false; for (int j = 0; j < segments.length; ++j) { Segment<K,V> seg = segmentAt(segments, j); if (seg != null) { sum += seg.modCount; int c = seg.count; if (c < 0 || (size += c) < 0) overflow = true; } } // 连续两次得到的结果一致,则认为这个结果是正确的 if (sum == last) break; last = sum; } } finally { if (retries > RETRIES_BEFORE_LOCK) { for (int j = 0; j < segments.length; ++j) segmentAt(segments, j).unlock(); } } return overflow ? Integer.MAX_VALUE : size;} 3. JDK 1.8 的改动JDK 1.7 使用分段锁机制来实现并发更新操作,核心类为 Segment,它继承自重入锁 ReentrantLock,并发度与 Segment 数量相等。 JDK 1.8 使用了 CAS 操作来支持更高的并发度,在 CAS 操作失败时使用内置锁 synchronized。 并且 JDK 1.8 的实现也在链表过长时会转换为红黑树。 LinkedHashMap存储结构继承自 HashMap,因此具有和 HashMap 一样的快速查找特性。 1public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 内部维护了一个双向链表,用来维护插入顺序或者 LRU 顺序。 123456789/** * The head (eldest) of the doubly linked list. */transient LinkedHashMap.Entry<K,V> head;/** * The tail (youngest) of the doubly linked list. */transient LinkedHashMap.Entry<K,V> tail; accessOrder 决定了顺序,默认为 false,此时维护的是插入顺序。 1final boolean accessOrder; LinkedHashMap 最重要的是以下用于维护顺序的函数,它们会在 put、get 等方法中调用。 12void afterNodeAccess(Node<K,V> p) { }void afterNodeInsertion(boolean evict) { } afterNodeAccess()当一个节点被访问时,如果 accessOrder 为 true,则会将该节点移到链表尾部。也就是说指定为 LRU 顺序之后,在每次访问一个节点时,会将这个节点移到链表尾部,保证链表尾部是最近访问的节点,那么链表首部就是最近最久未使用的节点。 123456789101112131415161718192021222324void afterNodeAccess(Node<K,V> e) { // move node to last LinkedHashMap.Entry<K,V> last; if (accessOrder && (last = tail) != e) { LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; p.after = null; if (b == null) head = a; else b.after = a; if (a != null) a.before = b; else last = b; if (last == null) head = p; else { p.before = last; last.after = p; } tail = p; ++modCount; }} afterNodeInsertion()在 put 等操作之后执行,当 removeEldestEntry() 方法返回 true 时会移除最晚的节点,也就是链表首部节点 first。 evict 只有在构建 Map 的时候才为 false,在这里为 true。 1234567void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry<K,V> first; if (evict && (first = head) != null && removeEldestEntry(first)) { K key = first.key; removeNode(hash(key), key, null, false, true); }} removeEldestEntry() 默认为 false,如果需要让它为 true,需要继承 LinkedHashMap 并且覆盖这个方法的实现,这在实现 LRU 的缓存中特别有用,通过移除最近最久未使用的节点,从而保证缓存空间足够,并且缓存的数据都是热点数据。 123protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false;} LRU 缓存以下是使用 LinkedHashMap 实现的一个 LRU 缓存: 设定最大缓存空间 MAX_ENTRIES 为 3; 使用 LinkedHashMap 的构造函数将 accessOrder 设置为 true,开启 LRU 顺序; 覆盖 removeEldestEntry() 方法实现,在节点多于 MAX_ENTRIES 就会将最近最久未使用的数据移除。 123456789101112131415161718192021class LRUCache<K, V> extends LinkedHashMap<K, V> { private static final int MAX_ENTRIES = 3; protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; } LRUCache() { super(MAX_ENTRIES, 0.75f, true); }}public static void main(String[] args) { LRUCache<Integer, String> cache = new LRUCache<>(); cache.put(1, \"a\"); cache.put(2, \"b\"); cache.put(3, \"c\"); cache.get(1); cache.put(4, \"d\"); System.out.println(cache.keySet());}[3, 1, 4] WeakHashMap存储结构WeakHashMap 的 Entry 继承自 WeakReference,被 WeakReference 关联的对象在下一次垃圾回收时会被回收。 WeakHashMap 主要用来实现缓存,通过使用 WeakHashMap 来引用缓存对象,由 JVM 对这部分缓存进行回收。 1private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> ConcurrentCacheTomcat 中的 ConcurrentCache 使用了 WeakHashMap 来实现缓存功能。 ConcurrentCache 采取的是分代缓存: 经常使用的对象放入 eden 中,eden 使用 ConcurrentHashMap 实现,不用担心会被回收(伊甸园); 不常用的对象放入 longterm,longterm 使用 WeakHashMap 实现,这些老对象会被垃圾收集器回收。 当调用 get() 方法时,会先从 eden 区获取,如果没有找到的话再到 longterm 获取,当从 longterm 获取到就把对象放入 eden 中,从而保证经常被访问的节点不容易被回收。 当调用 put() 方法时,如果 eden 的大小超过了 size,那么就将 eden 中的所有对象都放入 longterm 中,利用虚拟机回收掉一部分不经常使用的对象。 1234567891011121314151617181920212223242526272829303132public final class ConcurrentCache<K, V> { private final int size; private final Map<K, V> eden; private final Map<K, V> longterm; public ConcurrentCache(int size) { this.size = size; this.eden = new ConcurrentHashMap<>(size); this.longterm = new WeakHashMap<>(size); } public V get(K k) { V v = this.eden.get(k); if (v == null) { v = this.longterm.get(k); if (v != null) this.eden.put(k, v); } return v; } public void put(K k, V v) { if (this.eden.size() >= size) { this.longterm.putAll(this.eden); this.eden.clear(); } this.eden.put(k, v); }} [文章来源]([https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20%E5%AE%B9%E5%99%A8.md](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java 容器.md)) .","link":"/java/basic/Java%E5%AE%B9%E5%99%A8%E9%9B%86%E5%90%88.html"},{"title":"中华人民共和国网络安全法","text":"《中华人民共和国网络安全法》是为保障网络安全,维护网络空间主权和国家安全、社会公共利益,保护公民、法人和其他组织的合法权益,促进经济社会信息化健康发展制定。由全国人民代表大会常务委员会于2016年11月7日发布,自2017年6月1日起施行。 中华人民共和国网络安全法中文名:中华人民共和国网络安全法 外文名:People’s Republic of China Network Security Law 发布机构:全国人民代表大会常务委员会 发布日期:2016年11月7日 实施日期:2017年6月1日 ​ 第一章 总 则 ​ 第二章 网络安全支持与促进 ​ 第三章 网络运行安全 ​ 第一节 一般规定 ​ 第二节 关键信息基础设施的运行安全 ​ 第四章 网络信息安全 ​ 第五章 监测预警与应急处置 ​ 第六章 法律责任 ​ 第七章 附 则 ### 第一章 总 则 **第一条** 为了保障网络安全,维护网络空间主权和国家安全、社会公共利益,保护公民、法人和其他组织的合法权益,促进经济社会信息化健康发展,制定本法。 第二条 在中华人民共和国境内建设、运营、维护和使用网络,以及网络安全的监督管理,适用本法。 第三条 国家坚持网络安全与信息化发展并重,遵循积极利用、科学发展、依法管理、确保安全的方针,推进网络基础设施建设和互联互通,鼓励网络技术创新和应用,支持培养网络安全人才,建立健全网络安全保障体系,提高网络安全保护能力。 第四条 国家制定并不断完善网络安全战略,明确保障网络安全的基本要求和主要目标,提出重点领域的网络安全政策、工作任务和措施。 第五条 国家采取措施,监测、防御、处置来源于中华人民共和国境内外的网络安全风险和威胁,保护关键信息基础设施免受攻击、侵入、干扰和破坏,依法惩治网络违法犯罪活动,维护网络空间安全和秩序。 第六条 国家倡导诚实守信、健康文明的网络行为,推动传播社会主义核心价值观,采取措施提高全社会的网络安全意识和水平,形成全社会共同参与促进网络安全的良好环境。 第七条 国家积极开展网络空间治理、网络技术研发和标准制定、打击网络违法犯罪等方面的国际交流与合作,推动构建和平、安全、开放、合作的网络空间,建立多边、民主、透明的网络治理体系。 第八条 国家网信部门负责统筹协调网络安全工作和相关监督管理工作。国务院电信主管部门、公安部门和其他有关机关依照本法和有关法律、行政法规的规定,在各自职责范围内负责网络安全保护和监督管理工作。 县级以上地方人民政府有关部门的网络安全保护和监督管理职责,按照国家有关规定确定。 第九条 网络运营者开展经营和服务活动,必须遵守法律、行政法规,尊重社会公德,遵守商业道德,诚实信用,履行网络安全保护义务,接受政府和社会的监督,承担社会责任。 第十条 建设、运营网络或者通过网络提供服务,应当依照法律、行政法规的规定和国家标准的强制性要求,采取技术措施和其他必要措施,保障网络安全、稳定运行,有效应对网络安全事件,防范网络违法犯罪活动,维护网络数据的完整性、保密性和可用性。 第十一条 网络相关行业组织按照章程,加强行业自律,制定网络安全行为规范,指导会员加强网络安全保护,提高网络安全保护水平,促进行业健康发展。 第十二条 国家保护公民、法人和其他组织依法使用网络的权利,促进网络接入普及,提升网络服务水平,为社会提供安全、便利的网络服务,保障网络信息依法有序自由流动。 任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得危害网络安全,不得利用网络从事危害国家安全、荣誉和利益,煽动颠覆国家政权、推翻社会主义制度,煽动分裂国家、破坏国家统一,宣扬恐怖主义、极端主义,宣扬民族仇恨、民族歧视,传播暴力、淫秽色情信息,编造、传播虚假信息扰乱经济秩序和社会秩序,以及侵害他人名誉、隐私、知识产权和其他合法权益等活动。 第十三条 国家支持研究开发有利于未成年人健康成长的网络产品和服务,依法惩治利用网络从事危害未成年人身心健康的活动,为未成年人提供安全、健康的网络环境。 第十四条 任何个人和组织有权对危害网络安全的行为向网信、电信、公安等部门举报。收到举报的部门应当及时依法作出处理;不属于本部门职责的,应当及时移送有权处理的部门。 有关部门应当对举报人的相关信息予以保密,保护举报人的合法权益。 第二章 网络安全支持与促进第十五条 国家建立和完善网络安全标准体系。国务院标准化行政主管部门和国务院其他有关部门根据各自的职责,组织制定并适时修订有关网络安全管理以及网络产品、服务和运行安全的国家标准、行业标准。 国家支持企业、研究机构、高等学校、网络相关行业组织参与网络安全国家标准、行业标准的制定。 第十六条 国务院和省、自治区、直辖市人民政府应当统筹规划,加大投入,扶持重点网络安全技术产业和项目,支持网络安全技术的研究开发和应用,推广安全可信的网络产品和服务,保护网络技术知识产权,支持企业、研究机构和高等学校等参与国家网络安全技术创新项目。 第十七条 国家推进网络安全社会化服务体系建设,鼓励有关企业、机构开展网络安全认证、检测和风险评估等安全服务。 第十八条 国家鼓励开发网络数据安全保护和利用技术,促进公共数据资源开放,推动技术创新和经济社会发展。 国家支持创新网络安全管理方式,运用网络新技术,提升网络安全保护水平。 第十九条 各级人民政府及其有关部门应当组织开展经常性的网络安全宣传教育,并指导、督促有关单位做好网络安全宣传教育工作。 大众传播媒介应当有针对性地面向社会进行网络安全宣传教育。 第二十条 国家支持企业和高等学校、职业学校等教育培训机构开展网络安全相关教育与培训,采取多种方式培养网络安全人才,促进网络安全人才交流。 第三章 网络运行安全 #### 第一节 一般规定 第二十一条 国家实行网络安全等级保护制度。网络运营者应当按照网络安全等级保护制度的要求,履行下列安全保护义务,保障网络免受干扰、破坏或者未经授权的访问,防止网络数据泄露或者被窃取、篡改: (一)制定内部安全管理制度和操作规程,确定网络安全负责人,落实网络安全保护责任; (二)采取防范计算机病毒和网络攻击、网络侵入等危害网络安全行为的技术措施; (三)采取监测、记录网络运行状态、网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月; (四)采取数据分类、重要数据备份和加密等措施; (五)法律、行政法规规定的其他义务。 第二十二条 网络产品、服务应当符合相关国家标准的强制性要求。网络产品、服务的提供者不得设置恶意程序;发现其网络产品、服务存在安全缺陷、漏洞等风险时,应当立即采取补救措施,按照规定及时告知用户并向有关主管部门报告。 网络产品、服务的提供者应当为其产品、服务持续提供安全维护;在规定或者当事人约定的期限内,不得终止提供安全维护。 网络产品、服务具有收集用户信息功能的,其提供者应当向用户明示并取得同意;涉及用户个人信息的,还应当遵守本法和有关法律、行政法规关于个人信息保护的规定。 第二十三条 网络关键设备和网络安全专用产品应当按照相关国家标准的强制性要求,由具备资格的机构安全认证合格或者安全检测符合要求后,方可销售或者提供。国家网信部门会同国务院有关部门制定、公布网络关键设备和网络安全专用产品目录,并推动安全认证和安全检测结果互认,避免重复认证、检测。 第二十四条 网络运营者为用户办理网络接入、域名注册服务,办理固定电话、移动电话等入网手续,或者为用户提供信息发布、即时通讯等服务,在与用户签订协议或者确认提供服务时,应当要求用户提供真实身份信息。用户不提供真实身份信息的,网络运营者不得为其提供相关服务。 国家实施网络可信身份战略,支持研究开发安全、方便的电子身份认证技术,推动不同电子身份认证之间的互认。 第二十五条 网络运营者应当制定网络安全事件应急预案,及时处置系统漏洞、计算机病毒、网络攻击、网络侵入等安全风险;在发生危害网络安全的事件时,立即启动应急预案,采取相应的补救措施,并按照规定向有关主管部门报告。 第二十六条 开展网络安全认证、检测、风险评估等活动,向社会发布系统漏洞、计算机病毒、网络攻击、网络侵入等网络安全信息,应当遵守国家有关规定。 第二十七条 任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序、工具;明知他人从事危害网络安全的活动的,不得为其提供技术支持、广告推广、支付结算等帮助。 第二十八条 网络运营者应当为公安机关、国家安全机关依法维护国家安全和侦查犯罪的活动提供技术支持和协助。 第二十九条 国家支持网络运营者之间在网络安全信息收集、分析、通报和应急处置等方面进行合作,提高网络运营者的安全保障能力。 有关行业组织建立健全本行业的网络安全保护规范和协作机制,加强对网络安全风险的分析评估,定期向会员进行风险警示,支持、协助会员应对网络安全风险。 第三十条 网信部门和有关部门在履行网络安全保护职责中获取的信息,只能用于维护网络安全的需要,不得用于其他用途。 第二节 关键信息基础设施的运行安全第三十一条 国家对公共通信和信息服务、能源、交通、水利、金融、公共服务、电子政务等重要行业和领域,以及其他一旦遭到破坏、丧失功能或者数据泄露,可能严重危害国家安全、国计民生、公共利益的关键信息基础设施,在网络安全等级保护制度的基础上,实行重点保护。关键信息基础设施的具体范围和安全保护办法由国务院制定。 国家鼓励关键信息基础设施以外的网络运营者自愿参与关键信息基础设施保护体系。 第三十二条 按照国务院规定的职责分工,负责关键信息基础设施安全保护工作的部门分别编制并组织实施本行业、本领域的关键信息基础设施安全规划,指导和监督关键信息基础设施运行安全保护工作。 第三十三条 建设关键信息基础设施应当确保其具有支持业务稳定、持续运行的性能,并保证安全技术措施同步规划、同步建设、同步使用。 第三十四条 除本法第二十一条的规定外,关键信息基础设施的运营者还应当履行下列安全保护义务: (一)设置专门安全管理机构和安全管理负责人,并对该负责人和关键岗位的人员进行安全背景审查; (二)定期对从业人员进行网络安全教育、技术培训和技能考核; (三)对重要系统和数据库进行容灾备份; (四)制定网络安全事件应急预案,并定期进行演练; (五)法律、行政法规规定的其他义务。 第三十五条 关键信息基础设施的运营者采购网络产品和服务,可能影响国家安全的,应当通过国家网信部门会同国务院有关部门组织的国家安全审查。 第三十六条 关键信息基础设施的运营者采购网络产品和服务,应当按照规定与提供者签订安全保密协议,明确安全和保密义务与责任。 第三十七条 关键信息基础设施的运营者在中华人民共和国境内运营中收集和产生的个人信息和重要数据应当在境内存储。因业务需要,确需向境外提供的,应当按照国家网信部门会同国务院有关部门制定的办法进行安全评估;法律、行政法规另有规定的,依照其规定。 第三十八条 关键信息基础设施的运营者应当自行或者委托网络安全服务机构对其网络的安全性和可能存在的风险每年至少进行一次检测评估,并将检测评估情况和改进措施报送相关负责关键信息基础设施安全保护工作的部门。 第三十九条 国家网信部门应当统筹协调有关部门对关键信息基础设施的安全保护采取下列措施: (一)对关键信息基础设施的安全风险进行抽查检测,提出改进措施,必要时可以委托网络安全服务机构对网络存在的安全风险进行检测评估; (二)定期组织关键信息基础设施的运营者进行网络安全应急演练,提高应对网络安全事件的水平和协同配合能力; (三)促进有关部门、关键信息基础设施的运营者以及有关研究机构、网络安全服务机构等之间的网络安全信息共享; (四)对网络安全事件的应急处置与网络功能的恢复等,提供技术支持和协助。 第四章 网络信息安全第四十条 网络运营者应当对其收集的用户信息严格保密,并建立健全用户信息保护制度。 第四十一条 网络运营者收集、使用个人信息,应当遵循合法、正当、必要的原则,公开收集、使用规则,明示收集、使用信息的目的、方式和范围,并经被收集者同意。 网络运营者不得收集与其提供的服务无关的个人信息,不得违反法律、行政法规的规定和双方的约定收集、使用个人信息,并应当依照法律、行政法规的规定和与用户的约定,处理其保存的个人信息。 第四十二条 网络运营者不得泄露、篡改、毁损其收集的个人信息;未经被收集者同意,不得向他人提供个人信息。但是,经过处理无法识别特定个人且不能复原的除外。 网络运营者应当采取技术措施和其他必要措施,确保其收集的个人信息安全,防止信息泄露、毁损、丢失。在发生或者可能发生个人信息泄露、毁损、丢失的情况时,应当立即采取补救措施,按照规定及时告知用户并向有关主管部门报告。 第四十三条 个人发现网络运营者违反法律、行政法规的规定或者双方的约定收集、使用其个人信息的,有权要求网络运营者删除其个人信息;发现网络运营者收集、存储的其个人信息有错误的,有权要求网络运营者予以更正。网络运营者应当采取措施予以删除或者更正。 第四十四条 任何个人和组织不得窃取或者以其他非法方式获取个人信息,不得非法出售或者非法向他人提供个人信息。 第四十五条 依法负有网络安全监督管理职责的部门及其工作人员,必须对在履行职责中知悉的个人信息、隐私和商业秘密严格保密,不得泄露、出售或者非法向他人提供。 第四十六条 任何个人和组织应当对其使用网络的行为负责,不得设立用于实施诈骗,传授犯罪方法,制作或者销售违禁物品、管制物品等违法犯罪活动的网站、通讯群组,不得利用网络发布涉及实施诈骗,制作或者销售违禁物品、管制物品以及其他违法犯罪活动的信息。 第四十七条 网络运营者应当加强对其用户发布的信息的管理,发现法律、行政法规禁止发布或者传输的信息的,应当立即停止传输该信息,采取消除等处置措施,防止信息扩散,保存有关记录,并向有关主管部门报告。 第四十八条 任何个人和组织发送的电子信息、提供的应用软件,不得设置恶意程序,不得含有法律、行政法规禁止发布或者传输的信息。 电子信息发送服务提供者和应用软件下载服务提供者,应当履行安全管理义务,知道其用户有前款规定行为的,应当停止提供服务,采取消除等处置措施,保存有关记录,并向有关主管部门报告。 第四十九条 网络运营者应当建立网络信息安全投诉、举报制度,公布投诉、举报方式等信息,及时受理并处理有关网络信息安全的投诉和举报。 网络运营者对网信部门和有关部门依法实施的监督检查,应当予以配合。 第五十条 国家网信部门和有关部门依法履行网络信息安全监督管理职责,发现法律、行政法规禁止发布或者传输的信息的,应当要求网络运营者停止传输,采取消除等处置措施,保存有关记录;对来源于中华人民共和国境外的上述信息,应当通知有关机构采取技术措施和其他必要措施阻断传播。 第五章 监测预警与应急处置第五十一条 国家建立网络安全监测预警和信息通报制度。国家网信部门应当统筹协调有关部门加强网络安全信息收集、分析和通报工作,按照规定统一发布网络安全监测预警信息。 第五十二条 负责关键信息基础设施安全保护工作的部门,应当建立健全本行业、本领域的网络安全监测预警和信息通报制度,并按照规定报送网络安全监测预警信息。 第五十三条 国家网信部门协调有关部门建立健全网络安全风险评估和应急工作机制,制定网络安全事件应急预案,并定期组织演练。 负责关键信息基础设施安全保护工作的部门应当制定本行业、本领域的网络安全事件应急预案,并定期组织演练。 网络安全事件应急预案应当按照事件发生后的危害程度、影响范围等因素对网络安全事件进行分级,并规定相应的应急处置措施。 第五十四条 网络安全事件发生的风险增大时,省级以上人民政府有关部门应当按照规定的权限和程序,并根据网络安全风险的特点和可能造成的危害,采取下列措施: (一)要求有关部门、机构和人员及时收集、报告有关信息,加强对网络安全风险的监测; (二)组织有关部门、机构和专业人员,对网络安全风险信息进行分析评估,预测事件发生的可能性、影响范围和危害程度; (三)向社会发布网络安全风险预警,发布避免、减轻危害的措施。 第五十五条 发生网络安全事件,应当立即启动网络安全事件应急预案,对网络安全事件进行调查和评估,要求网络运营者采取技术措施和其他必要措施,消除安全隐患,防止危害扩大,并及时向社会发布与公众有关的警示信息。 第五十六条 省级以上人民政府有关部门在履行网络安全监督管理职责中,发现网络存在较大安全风险或者发生安全事件的,可以按照规定的权限和程序对该网络的运营者的法定代表人或者主要负责人进行约谈。网络运营者应当按照要求采取措施,进行整改,消除隐患。 第五十七条 因网络安全事件,发生突发事件或者生产安全事故的,应当依照《中华人民共和国突发事件应对法》、《中华人民共和国安全生产法》等有关法律、行政法规的规定处置。 第五十八条 因维护国家安全和社会公共秩序,处置重大突发社会安全事件的需要,经国务院决定或者批准,可以在特定区域对网络通信采取限制等临时措施。 第六章 法律责任第五十九条 网络运营者不履行本法第二十一条、第二十五条规定的网络安全保护义务的,由有关主管部门责令改正,给予警告;拒不改正或者导致危害网络安全等后果的,处一万元以上十万元以下罚款,对直接负责的主管人员处五千元以上五万元以下罚款。 关键信息基础设施的运营者不履行本法第三十三条、第三十四条、第三十六条、第三十八条规定的网络安全保护义务的,由有关主管部门责令改正,给予警告;拒不改正或者导致危害网络安全等后果的,处十万元以上一百万元以下罚款,对直接负责的主管人员处一万元以上十万元以下罚款。 第六十条 违反本法第二十二条第一款、第二款和第四十八条第一款规定,有下列行为之一的,由有关主管部门责令改正,给予警告;拒不改正或者导致危害网络安全等后果的,处五万元以上五十万元以下罚款,对直接负责的主管人员处一万元以上十万元以下罚款: (一)设置恶意程序的; (二)对其产品、服务存在的安全缺陷、漏洞等风险未立即采取补救措施,或者未按照规定及时告知用户并向有关主管部门报告的; (三)擅自终止为其产品、服务提供安全维护的。 第六十一条 网络运营者违反本法第二十四条第一款规定,未要求用户提供真实身份信息,或者对不提供真实身份信息的用户提供相关服务的,由有关主管部门责令改正;拒不改正或者情节严重的,处五万元以上五十万元以下罚款,并可以由有关主管部门责令暂停相关业务、停业整顿、关闭网站、吊销相关业务许可证或者吊销营业执照,对直接负责的主管人员和其他直接责任人员处一万元以上十万元以下罚款。 第六十二条 违反本法第二十六条规定,开展网络安全认证、检测、风险评估等活动,或者向社会发布系统漏洞、计算机病毒、网络攻击、网络侵入等网络安全信息的,由有关主管部门责令改正,给予警告;拒不改正或者情节严重的,处一万元以上十万元以下罚款,并可以由有关主管部门责令暂停相关业务、停业整顿、关闭网站、吊销相关业务许可证或者吊销营业执照,对直接负责的主管人员和其他直接责任人员处五千元以上五万元以下罚款。 第六十三条 违反本法第二十七条规定,从事危害网络安全的活动,或者提供专门用于从事危害网络安全活动的程序、工具,或者为他人从事危害网络安全的活动提供技术支持、广告推广、支付结算等帮助,尚不构成犯罪的,由公安机关没收违法所得,处五日以下拘留,可以并处五万元以上五十万元以下罚款;情节较重的,处五日以上十五日以下拘留,可以并处十万元以上一百万元以下罚款。 单位有前款行为的,由公安机关没收违法所得,处十万元以上一百万元以下罚款,并对直接负责的主管人员和其他直接责任人员依照前款规定处罚。 违反本法第二十七条规定,受到治安管理处罚的人员,五年内不得从事网络安全管理和网络运营关键岗位的工作;受到刑事处罚的人员,终身不得从事网络安全管理和网络运营关键岗位的工作。 第六十四条 网络运营者、网络产品或者服务的提供者违反本法第二十二条第三款、第四十一条至第四十三条规定,侵害个人信息依法得到保护的权利的,由有关主管部门责令改正,可以根据情节单处或者并处警告、没收违法所得、处违法所得一倍以上十倍以下罚款,没有违法所得的,处一百万元以下罚款,对直接负责的主管人员和其他直接责任人员处一万元以上十万元以下罚款;情节严重的,并可以责令暂停相关业务、停业整顿、关闭网站、吊销相关业务许可证或者吊销营业执照。 违反本法第四十四条规定,窃取或者以其他非法方式获取、非法出售或者非法向他人提供个人信息,尚不构成犯罪的,由公安机关没收违法所得,并处违法所得一倍以上十倍以下罚款,没有违法所得的,处一百万元以下罚款。 第六十五条 关键信息基础设施的运营者违反本法第三十五条规定,使用未经安全审查或者安全审查未通过的网络产品或者服务的,由有关主管部门责令停止使用,处采购金额一倍以上十倍以下罚款;对直接负责的主管人员和其他直接责任人员处一万元以上十万元以下罚款。 第六十六条 关键信息基础设施的运营者违反本法第三十七条规定,在境外存储网络数据,或者向境外提供网络数据的,由有关主管部门责令改正,给予警告,没收违法所得,处五万元以上五十万元以下罚款,并可以责令暂停相关业务、停业整顿、关闭网站、吊销相关业务许可证或者吊销营业执照;对直接负责的主管人员和其他直接责任人员处一万元以上十万元以下罚款。 第六十七条 违反本法第四十六条规定,设立用于实施违法犯罪活动的网站、通讯群组,或者利用网络发布涉及实施违法犯罪活动的信息,尚不构成犯罪的,由公安机关处五日以下拘留,可以并处一万元以上十万元以下罚款;情节较重的,处五日以上十五日以下拘留,可以并处五万元以上五十万元以下罚款。关闭用于实施违法犯罪活动的网站、通讯群组。 单位有前款行为的,由公安机关处十万元以上五十万元以下罚款,并对直接负责的主管人员和其他直接责任人员依照前款规定处罚。 第六十八条 网络运营者违反本法第四十七条规定,对法律、行政法规禁止发布或者传输的信息未停止传输、采取消除等处置措施、保存有关记录的,由有关主管部门责令改正,给予警告,没收违法所得;拒不改正或者情节严重的,处十万元以上五十万元以下罚款,并可以责令暂停相关业务、停业整顿、关闭网站、吊销相关业务许可证或者吊销营业执照,对直接负责的主管人员和其他直接责任人员处一万元以上十万元以下罚款。 电子信息发送服务提供者、应用软件下载服务提供者,不履行本法第四十八条第二款规定的安全管理义务的,依照前款规定处罚。 第六十九条 网络运营者违反本法规定,有下列行为之一的,由有关主管部门责令改正;拒不改正或者情节严重的,处五万元以上五十万元以下罚款,对直接负责的主管人员和其他直接责任人员,处一万元以上十万元以下罚款: (一)不按照有关部门的要求对法律、行政法规禁止发布或者传输的信息,采取停止传输、消除等处置措施的; (二)拒绝、阻碍有关部门依法实施的监督检查的; (三)拒不向公安机关、国家安全机关提供技术支持和协助的。 第七十条 发布或者传输本法第十二条第二款和其他法律、行政法规禁止发布或者传输的信息的,依照有关法律、行政法规的规定处罚。 第七十一条 有本法规定的违法行为的,依照有关法律、行政法规的规定记入信用档案,并予以公示。 第七十二条 国家机关政务网络的运营者不履行本法规定的网络安全保护义务的,由其上级机关或者有关机关责令改正;对直接负责的主管人员和其他直接责任人员依法给予处分。 第七十三条 网信部门和有关部门违反本法第三十条规定,将在履行网络安全保护职责中获取的信息用于其他用途的,对直接负责的主管人员和其他直接责任人员依法给予处分。 网信部门和有关部门的工作人员玩忽职守、滥用职权、徇私舞弊,尚不构成犯罪的,依法给予处分。 第七十四条 违反本法规定,给他人造成损害的,依法承担民事责任。 违反本法规定,构成违反治安管理行为的,依法给予治安管理处罚;构成犯罪的,依法追究刑事责任。 第七十五条 境外的机构、组织、个人从事攻击、侵入、干扰、破坏等危害中华人民共和国的关键信息基础设施的活动,造成严重后果的,依法追究法律责任;国务院公安部门和有关部门并可以决定对该机构、组织、个人采取冻结财产或者其他必要的制裁措施。 第七章 附 则第七十六条 本法下列用语的含义: (一)网络,是指由计算机或者其他信息终端及相关设备组成的按照一定的规则和程序对信息进行收集、存储、传输、交换、处理的系统。 (二)网络安全,是指通过采取必要措施,防范对网络的攻击、侵入、干扰、破坏和非法使用以及意外事故,使网络处于稳定可靠运行的状态,以及保障网络数据的完整性、保密性、可用性的能力。 (三)网络运营者,是指网络的所有者、管理者和网络服务提供者。 (四)网络数据,是指通过网络收集、存储、传输、处理和产生的各种电子数据。 (五)个人信息,是指以电子或者其他方式记录的能够单独或者与其他信息结合识别自然人个人身份的各种信息,包括但不限于自然人的姓名、出生日期、身份证件号码、个人生物识别信息、住址、电话号码等。 第七十七条 存储、处理涉及国家秘密信息的网络的运行安全保护,除应当遵守本法外,还应当遵守保密法律、行政法规的规定。 第七十八条 军事网络的安全保护,由中央军事委员会另行规定。 第七十九条 本法自2017年6月1日起施行。","link":"/law/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E6%B3%95.html"},{"title":"Java并发相关知识点","text":"互斥同步最主要的问题就是线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步。 互斥同步属于一种悲观的并发策略,总是认为只要不去做正确的同步措施,那就肯定会出现问题。无论共享数据是否真的会出现竞争,它都要进行加锁(这里讨论的是概念模型,实际上虚拟机会优化掉很大一部分不必要的加锁)、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。 并发零碎知识点 线程状态转换 新建(New) 创建后尚未启动。 可运行(Runnable) 可能正在运行,也可能正在等待 CPU 时间片。 包含了操作系统线程状态中的 Running 和 Ready。 阻塞(Blocked) 等待获取一个排它锁,如果其线程释放了锁就会结束此状态。 无限期等待(Waiting) 等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。 进入方法 退出方法 没有设置 Timeout 参数的 Object.wait() 方法 Object.notify() / Object.notifyAll() 没有设置 Timeout 参数的 Thread.join() 方法 被调用的线程执行完毕 LockSupport.park() 方法 LockSupport.unpark(Thread) 限期等待(Timed Waiting) 无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。 调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用“使一个线程睡眠”进行描述。 调用 Object.wait() 方法使线程进入限期等待或者无限期等待时,常常用“挂起一个线程”进行描述。 睡眠和挂起是用来描述行为,而阻塞和等待用来描述状态。 阻塞和等待的区别在于,阻塞是被动的,它是在等待获取一个排它锁。而等待是主动的,通过调用 Thread.sleep() 和 Object.wait() 等方法进入。 进入方法 退出方法 Thread.sleep() 方法 时间结束 设置了 Timeout 参数的 Object.wait() 方法 时间结束 / Object.notify() / Object.notifyAll() 设置了 Timeout 参数的 Thread.join() 方法 时间结束 / 被调用的线程执行完毕 LockSupport.parkNanos() 方法 LockSupport.unpark(Thread) LockSupport.parkUntil() 方法 LockSupport.unpark(Thread) 死亡(Terminated) 可以是线程结束任务之后自己结束,或者产生了异常而结束。 使用线程有三种使用线程的方法: 实现 Runnable 接口; 实现 Callable 接口; 继承 Thread 类。 实现 Runnable 和 Callable 接口的类只能当做一个可以在线程中运行的任务,不是真正意义上的线程,因此最后还需要通过 Thread 来调用。可以说任务是通过线程驱动从而执行的。 实现 Runnable 接口需要实现 run() 方法。 通过 Thread 调用 start() 方法来启动线程。 1234567891011public class MyRunnable implements Runnable { public void run() { // ... }}public static void main(String[] args) { MyRunnable instance = new MyRunnable(); Thread thread = new Thread(instance); thread.start(); //调用 thread.run()并不是开启新线程,而是在当前线程里马上调用run()方法} 实现 Callable 接口与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。 123456789101112public class MyCallable implements Callable<Integer> { public Integer call() { return 123; }}public static void main(String[] args) throws ExecutionException, InterruptedException { MyCallable mc = new MyCallable(); FutureTask<Integer> ft = new FutureTask<>(mc); Thread thread = new Thread(ft); thread.start(); System.out.println(ft.get());} 继承 Thread 类同样也是需要实现 run() 方法,因为 Thread 类也实现了 Runable 接口。 当调用 start() 方法启动一个线程时,虚拟机会将该线程放入就绪队列中等待被调度,当一个线程被调度时会执行该线程的 run() 方法。 123456789public class MyThread extends Thread { public void run() { // ... }}public static void main(String[] args) { MyThread mt = new MyThread(); mt.start();} 实现接口 VS 继承 Thread实现接口会更好一些,因为: Java 不支持多重继承,因此继承了 Thread 类就无法继承其它类,但是可以实现多个接口; 类可能只要求可执行就行,继承整个 Thread 类开销过大。 基础线程机制ExecutorExecutor 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。 主要有三种 Executor: CachedThreadPool:一个任务创建一个线程; FixedThreadPool:所有任务只能使用固定大小的线程; SingleThreadExecutor:相当于大小为 1 的 FixedThreadPool。 1234567public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { executorService.execute(new MyRunnable()); } executorService.shutdown();} Daemon守护线程是程序运行时在后台提供服务的线程,不属于程序中不可或缺的部分。 当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程。 main() 属于非守护线程。 在线程启动之前使用 setDaemon() 方法可以将一个线程设置为守护线程。 1234public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.setDaemon(true);} sleep()Thread.sleep(millisec) 方法会休眠当前正在执行的线程,millisec 单位为毫秒。 sleep() 可能会抛出 InterruptedException,因为异常不能跨线程传播回 main() 中,因此必须在本地进行处理。线程中抛出的其它异常也同样需要在本地进行处理。 1234567public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }} yield()对静态方法 Thread.yield() 的调用声明了当前线程已经完成了生命周期中最重要的部分,可以切换给其它线程来执行。该方法只是对线程调度器的一个建议,而且也只是建议具有相同优先级的其它线程可以运行。 123public void run() { Thread.yield();} 中断一个线程执行完毕之后会自动结束,如果在运行过程中发生异常也会提前结束。 InterruptedException通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。 对于以下代码,在 main() 中启动一个线程之后再中断它,由于线程中调用了 Thread.sleep() 方法,因此会抛出一个 InterruptedException,从而提前结束线程,不执行之后的语句。 1234567891011121314151617181920212223242526public class InterruptExample { private static class MyThread1 extends Thread { @Override public void run() { try { Thread.sleep(2000); System.out.println(\"Thread run\"); } catch (InterruptedException e) { e.printStackTrace(); } } }}public static void main(String[] args) throws InterruptedException { Thread thread1 = new MyThread1(); thread1.start(); thread1.interrupt(); System.out.println(\"Main run\");}Main runjava.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at InterruptExample.lambda$main$0(InterruptExample.java:5) at InterruptExample$$Lambda$1/713338599.run(Unknown Source) at java.lang.Thread.run(Thread.java:745) interrupted()如果一个线程的 run() 方法执行一个无限循环,并且没有执行 sleep() 等会抛出 InterruptedException 的操作,那么调用线程的 interrupt() 方法就无法使线程提前结束。 但是调用 interrupt() 方法会设置线程的中断标记,此时调用 interrupted() 方法会返回 true。因此可以在循环体中使用 interrupted() 方法来判断线程是否处于中断状态,从而提前结束线程。 123456789101112131415161718public class InterruptExample { private static class MyThread2 extends Thread { @Override public void run() { while (!interrupted()) { // .. } System.out.println(\"Thread end\"); } }}public static void main(String[] args) throws InterruptedException { Thread thread2 = new MyThread2(); thread2.start(); thread2.interrupt();}Thread end Executor 的中断操作调用 Executor 的 shutdown() 方法会等待线程都执行完毕之后再关闭,但是如果调用的是 shutdownNow() 方法,则相当于调用每个线程的 interrupt() 方法。 以下使用 Lambda 创建线程,相当于创建了一个匿名内部线程。 123456789101112131415161718192021public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> { try { Thread.sleep(2000); System.out.println(\"Thread run\"); } catch (InterruptedException e) { e.printStackTrace(); } }); executorService.shutdownNow(); System.out.println(\"Main run\");}Main runjava.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at ExecutorInterruptExample.lambda$main$0(ExecutorInterruptExample.java:9) at ExecutorInterruptExample$$Lambda$1/1160460865.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) 如果只想中断 Executor 中的一个线程,可以通过使用 submit() 方法来提交一个线程,它会返回一个 Future<?> 对象,通过调用该对象的 cancel(true) 方法就可以中断线程。 1234Future<?> future = executorService.submit(() -> { // ..});future.cancel(true); 互斥同步Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问,第一个是 JVM 实现的 synchronized,而另一个是 JDK 实现的 ReentrantLock。 synchronized1. 同步一个代码块 12345public void func() { synchronized (this) { // ... }} 它只作用于同一个对象,如果调用两个对象上的同步代码块,就不会进行同步。 对于以下代码,使用 ExecutorService 执行了两个线程,由于调用的是同一个对象的同步代码块,因此这两个线程会进行同步,当一个线程进入同步语句块时,另一个线程就必须等待。 1234567891011121314151617public class SynchronizedExample { public void func1() { synchronized (this) { for (int i = 0; i < 10; i++) { System.out.print(i + \" \"); } } }}public static void main(String[] args) { SynchronizedExample e1 = new SynchronizedExample(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> e1.func1()); executorService.execute(() -> e1.func1());}0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 对于以下代码,两个线程调用了不同对象的同步代码块,因此这两个线程就不需要同步。从输出结果可以看出,两个线程交叉执行。 12345678public static void main(String[] args) { SynchronizedExample e1 = new SynchronizedExample(); SynchronizedExample e2 = new SynchronizedExample(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> e1.func1()); executorService.execute(() -> e2.func1());}0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 2. 同步一个方法 123public synchronized void func () { // ...} 它和同步代码块一样,作用于同一个对象。 3. 同步一个类 12345public void func() { synchronized (SynchronizedExample.class) { // ... }} 作用于整个类,也就是说两个线程调用同一个类的不同对象上的这种同步语句,也会进行同步。 123456789101112131415161718public class SynchronizedExample { public void func2() { synchronized (SynchronizedExample.class) { for (int i = 0; i < 10; i++) { System.out.print(i + \" \"); } } }}public static void main(String[] args) { SynchronizedExample e1 = new SynchronizedExample(); SynchronizedExample e2 = new SynchronizedExample(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> e1.func2()); executorService.execute(() -> e2.func2());}0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 4. 同步一个静态方法 123public synchronized static void fun() { // ...} 作用于整个类。 ReentrantLockReentrantLock 是 java.util.concurrent(J.U.C)包中的锁。 12345678910111213141516171819202122public class LockExample { private Lock lock = new ReentrantLock(); public void func() { lock.lock(); try { for (int i = 0; i < 10; i++) { System.out.print(i + \" \"); } } finally { lock.unlock(); // 确保释放锁,从而避免发生死锁。 } }}public static void main(String[] args) { LockExample lockExample = new LockExample(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> lockExample.func()); executorService.execute(() -> lockExample.func());}0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 比较1. 锁的实现 synchronized 是 JVM 实现的,而 ReentrantLock 是 JDK 实现的。 2. 性能 新版本 Java 对 synchronized 进行了很多优化,例如自旋锁等,synchronized 与 ReentrantLock 大致相同。 3. 等待可中断 当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。 ReentrantLock 可中断,而 synchronized 不行。 4. 公平锁 公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。 synchronized 中的锁是非公平的,ReentrantLock 默认情况下也是非公平的,但是也可以是公平的。 5. 锁绑定多个条件 一个 ReentrantLock 可以同时绑定多个 Condition 对象。 使用选择除非需要使用 ReentrantLock 的高级功能,否则优先使用 synchronized。这是因为 synchronized 是 JVM 实现的一种锁机制,JVM 原生地支持它,而 ReentrantLock 不是所有的 JDK 版本都支持。并且使用 synchronized 不用担心没有释放锁而导致死锁问题,因为 JVM 会确保锁的释放。 线程之间的协作当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调。 join()在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。 对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。 1234567891011121314151617181920212223242526272829303132333435363738394041public class JoinExample { private class A extends Thread { @Override public void run() { System.out.println(\"A\"); } } private class B extends Thread { private A a; B(A a) { this.a = a; } @Override public void run() { try { a.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(\"B\"); } } public void test() { A a = new A(); B b = new B(a); b.start(); a.start(); }}public static void main(String[] args) { JoinExample example = new JoinExample(); example.test();}AB wait() notify() notifyAll()调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。 它们都属于 Object 的一部分,而不属于 Thread。 只能用在同步方法或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateException。 使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。 123456789101112131415161718192021222324public class WaitNotifyExample { public synchronized void before() { System.out.println(\"before\"); notifyAll(); } public synchronized void after() { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(\"after\"); }}public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); WaitNotifyExample example = new WaitNotifyExample(); executorService.execute(() -> example.after()); executorService.execute(() -> example.before());}beforeafter wait() 和 sleep() 的区别 wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法; wait() 会释放锁,sleep() 不会。 await() signal() signalAll()java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。 相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活。 使用 Lock 来获取一个 Condition 对象。 1234567891011121314151617181920212223242526272829303132333435public class AwaitSignalExample { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void before() { lock.lock(); try { System.out.println(\"before\"); condition.signalAll(); } finally { lock.unlock(); } } public void after() { lock.lock(); try { condition.await(); System.out.println(\"after\"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }}public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); AwaitSignalExample example = new AwaitSignalExample(); executorService.execute(() -> example.after()); executorService.execute(() -> example.before());}beforeafter J.U.C - AQSjava.util.concurrent(J.U.C)大大提高了并发性能,AQS 被认为是 J.U.C 的核心。 CountDownLatch用来控制一个或者多个线程等待多个线程。 维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。 12345678910111213141516171819public class CountdownLatchExample { public static void main(String[] args) throws InterruptedException { final int totalThread = 10; CountDownLatch countDownLatch = new CountDownLatch(totalThread); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < totalThread; i++) { executorService.execute(() -> { System.out.print(\"run..\"); countDownLatch.countDown(); }); } countDownLatch.await(); System.out.println(\"end\"); executorService.shutdown(); }}run..run..run..run..run..run..run..run..run..run..end CyclicBarrier用来控制多个线程互相等待,只有当多个线程都到达时,这些线程才会继续执行。 和 CountdownLatch 相似,都是通过维护计数器来实现的。线程执行 await() 方法之后计数器会减 1,并进行等待,直到计数器为 0,所有调用 await() 方法而在等待的线程才能继续执行。 CyclicBarrier 和 CountdownLatch 的一个区别是,CyclicBarrier 的计数器通过调用 reset() 方法可以循环使用,所以它才叫做循环屏障。 CyclicBarrier 有两个构造函数,其中 parties 指示计数器的初始值,barrierAction 在所有线程都到达屏障的时候会执行一次。 12345678910public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction;}public CyclicBarrier(int parties) { this(parties, null);} 12345678910111213141516171819202122public class CyclicBarrierExample { public static void main(String[] args) { final int totalThread = 10; CyclicBarrier cyclicBarrier = new CyclicBarrier(totalThread); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < totalThread; i++) { executorService.execute(() -> { System.out.print(\"before..\"); try { cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } System.out.print(\"after..\"); }); } executorService.shutdown(); }}before..before..before..before..before..before..before..before..before..before..after..after..after..after..after..after..after..after..after..after.. SemaphoreSemaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。 以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。 1234567891011121314151617181920212223public class SemaphoreExample { public static void main(String[] args) { final int clientCount = 3; final int totalRequestCount = 10; Semaphore semaphore = new Semaphore(clientCount); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < totalRequestCount; i++) { executorService.execute(()->{ try { semaphore.acquire(); System.out.print(semaphore.availablePermits() + \" \"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } }); } executorService.shutdown(); }}2 1 2 2 2 2 2 1 2 2 J.U.C - 其它组件FutureTask在介绍 Callable 时我们知道它可以有返回值,返回值通过 Future 进行封装。FutureTask 实现了 RunnableFuture 接口,该接口继承自 Runnable 和 Future 接口,这使得 FutureTask 既可以当做一个任务执行,也可以有返回值。 12public class FutureTask<V> implements RunnableFuture<V>public interface RunnableFuture<V> extends Runnable, Future<V> FutureTask 可用于异步获取执行结果或取消执行任务的场景。当一个计算任务需要执行很长时间,那么就可以用 FutureTask 来封装这个任务,主线程在完成自己的任务之后再去获取结果。 1234567891011121314151617181920212223242526272829303132public class FutureTaskExample { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() { @Override public Integer call() throws Exception { int result = 0; for (int i = 0; i < 100; i++) { Thread.sleep(10); result += i; } return result; } }); Thread computeThread = new Thread(futureTask); computeThread.start(); Thread otherThread = new Thread(() -> { System.out.println(\"other task is running...\"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }); otherThread.start(); System.out.println(futureTask.get()); }}other task is running...4950 BlockingQueuejava.util.concurrent.BlockingQueue 接口有以下阻塞队列的实现: FIFO 队列 :LinkedBlockingQueue、ArrayBlockingQueue(固定长度) 优先级队列 :PriorityBlockingQueue 提供了阻塞的 take() 和 put() 方法:如果队列为空 take() 将阻塞,直到队列中有内容;如果队列为满 put() 将阻塞,直到队列有空闲位置。 使用 BlockingQueue 实现生产者消费者问题 1234567891011121314151617181920212223242526272829303132333435363738394041424344public class ProducerConsumer { private static BlockingQueue<String> queue = new ArrayBlockingQueue<>(5); private static class Producer extends Thread { @Override public void run() { try { queue.put(\"product\"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print(\"produce..\"); } } private static class Consumer extends Thread { @Override public void run() { try { String product = queue.take(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print(\"consume..\"); } }}public static void main(String[] args) { for (int i = 0; i < 2; i++) { Producer producer = new Producer(); producer.start(); } for (int i = 0; i < 5; i++) { Consumer consumer = new Consumer(); consumer.start(); } for (int i = 0; i < 3; i++) { Producer producer = new Producer(); producer.start(); }}produce..produce..consume..consume..produce..consume..produce..consume..produce..consume.. ForkJoin主要用于并行计算中,和 MapReduce 原理类似,都是把大的计算任务拆分成多个小任务并行计算。 12345678910111213141516171819202122232425262728293031323334353637public class ForkJoinExample extends RecursiveTask<Integer> { private final int threshold = 5; private int first; private int last; public ForkJoinExample(int first, int last) { this.first = first; this.last = last; } @Override protected Integer compute() { int result = 0; if (last - first <= threshold) { // 任务足够小则直接计算 for (int i = first; i <= last; i++) { result += i; } } else { // 拆分成小任务 int middle = first + (last - first) / 2; ForkJoinExample leftTask = new ForkJoinExample(first, middle); ForkJoinExample rightTask = new ForkJoinExample(middle + 1, last); leftTask.fork(); rightTask.fork(); result = leftTask.join() + rightTask.join(); } return result; }}public static void main(String[] args) throws ExecutionException, InterruptedException { ForkJoinExample example = new ForkJoinExample(1, 10000); ForkJoinPool forkJoinPool = new ForkJoinPool(); Future result = forkJoinPool.submit(example); System.out.println(result.get());} ForkJoin 使用 ForkJoinPool 来启动,它是一个特殊的线程池,线程数量取决于 CPU 核数。 1public class ForkJoinPool extends AbstractExecutorService ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列,用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务,避免和队列所属线程发生竞争。例如下图中,Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务,Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。 线程不安全示例如果多个线程对同一个共享数据进行访问而不采取同步操作的话,那么操作的结果是不一致的。 以下代码演示了 1000 个线程同时对 cnt 执行自增操作,操作结束之后它的值有可能小于 1000。 12345678910111213141516171819202122232425262728public class ThreadUnsafeExample { private int cnt = 0; public void add() { cnt++; } public int get() { return cnt; }}public static void main(String[] args) throws InterruptedException { final int threadSize = 1000; ThreadUnsafeExample example = new ThreadUnsafeExample(); final CountDownLatch countDownLatch = new CountDownLatch(threadSize); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < threadSize; i++) { executorService.execute(() -> { example.add(); countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); System.out.println(example.get());}997 Java 内存模型Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。 主内存与工作内存处理器上的寄存器的读写的速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存。 加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。 所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。 线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。 内存间交互操作Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。 内存模型三大特性1. 原子性 Java 内存模型保证了 read、load、use、assign、store、write、lock 和 unlock 操作具有原子性,例如对一个 int 类型的变量执行 assign 赋值操作,这个操作就是原子性的。但是 Java 内存模型允许虚拟机将没有被 volatile 修饰的 64 位数据(long,double)的读写操作划分为两次 32 位的操作来进行,即 load、store、read 和 write 操作可以不具备原子性。 有一个错误认识就是,int 等原子性的类型在多线程环境中不会出现线程安全问题。前面的线程不安全示例代码中,cnt 属于 int 类型变量,1000 个线程对它进行自增操作之后,得到的值为 997 而不是 1000。 为了方便讨论,将内存间的交互操作简化为 3 个:load、assign、store。 下图演示了两个线程同时对 cnt 进行操作,load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存,T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。 AtomicInteger 能保证多个线程修改的原子性。 使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现: 12345678910111213141516171819202122232425262728public class AtomicExample { private AtomicInteger cnt = new AtomicInteger(); public void add() { cnt.incrementAndGet(); } public int get() { return cnt.get(); }}public static void main(String[] args) throws InterruptedException { final int threadSize = 1000; AtomicExample example = new AtomicExample(); // 只修改这条语句 final CountDownLatch countDownLatch = new CountDownLatch(threadSize); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < threadSize; i++) { executorService.execute(() -> { example.add(); countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); System.out.println(example.get());}1000 除了使用原子类之外,也可以使用 synchronized 互斥锁来保证操作的原子性。它对应的内存间交互操作为:lock 和 unlock,在虚拟机实现上对应的字节码指令为 monitorenter 和 monitorexit。 12345678910111213141516171819202122232425262728public class AtomicSynchronizedExample { private int cnt = 0; public synchronized void add() { cnt++; } public synchronized int get() { return cnt; }}public static void main(String[] args) throws InterruptedException { final int threadSize = 1000; AtomicSynchronizedExample example = new AtomicSynchronizedExample(); final CountDownLatch countDownLatch = new CountDownLatch(threadSize); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < threadSize; i++) { executorService.execute(() -> { example.add(); countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); System.out.println(example.get());}1000 2. 可见性 可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。 主要有三种实现可见性的方式: volatile synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。 final,被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。 对前面的线程不安全示例中的 cnt 变量使用 volatile 修饰,不能解决线程不安全问题,因为 volatile 并不能保证操作的原子性。 3. 有序性 有序性是指:在本线程内观察,所有操作都是有序的。在一个线程观察另一个线程,所有操作都是无序的,无序是因为发生了指令重排序。在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。 volatile 关键字通过添加内存屏障的方式来禁止指令重排,即重排序时不能把后面的指令放到内存屏障之前。 也可以通过 synchronized 来保证有序性,它保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码。 先行发生原则上面提到了可以用 volatile 和 synchronized 来保证有序性。除此之外,JVM 还规定了先行发生原则,让一个操作无需控制就能先于另一个操作完成。 1. 单一线程原则 Single Thread rule 在一个线程内,在程序前面的操作先行发生于后面的操作。 2. 管程锁定规则 Monitor Lock Rule ​ 一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。 3.volatile 变量规则 Volatile Variable Rule 对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。 4. 线程启动规则 Thread Start Rule Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。 5. 线程加入规则 Thread Join Rule Thread 对象的结束先行发生于 join() 方法返回。 6. 线程中断规则 Thread Interruption Rule 对线程 interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 interrupted() 方法检测到是否有中断发生。 7. 对象终结规则 Finalizer Rule 一个对象的初始化完成(构造函数执行结束)先行发生于它的 finalize() 方法的开始。 8. 传递性 Transitivity 如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那么操作 A 先行发生于操作 C。 线程安全多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为。 线程安全有以下几种实现方式: 不可变不可变(Immutable)的对象一定是线程安全的,不需要再采取任何的线程安全保障措施。只要一个不可变的对象被正确地构建出来,永远也不会看到它在多个线程之中处于不一致的状态。多线程环境下,应当尽量使对象成为不可变,来满足线程安全。 不可变的类型: final 关键字修饰的基本数据类型 String 枚举类型 Number 部分子类,如 Long 和 Double 等数值包装类型,BigInteger 和 BigDecimal 等大数据类型。但同为 Number 的原子类 AtomicInteger 和 AtomicLong 则是可变的。 对于集合类型,可以使用 Collections.unmodifiableXXX() 方法来获取一个不可变的集合。 12345678910public class ImmutableExample { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); Map<String, Integer> unmodifiableMap = Collections.unmodifiableMap(map); unmodifiableMap.put(\"a\", 1); }}Exception in thread \"main\" java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableMap.put(Collections.java:1457) at ImmutableExample.main(ImmutableExample.java:9) Collections.unmodifiableXXX() 先对原始的集合进行拷贝,需要对集合进行修改的方法都直接抛出异常。 123public V put(K key, V value) { throw new UnsupportedOperationException();} 互斥同步synchronized 和 ReentrantLock。 非阻塞同步互斥同步最主要的问题就是线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步。 互斥同步属于一种悲观的并发策略,总是认为只要不去做正确的同步措施,那就肯定会出现问题。无论共享数据是否真的会出现竞争,它都要进行加锁(这里讨论的是概念模型,实际上虚拟机会优化掉很大一部分不必要的加锁)、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。 1. CAS 随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略:先进行操作,如果没有其它线程争用共享数据,那操作就成功了,否则采取补偿措施(不断地重试,直到成功为止)。这种乐观的并发策略的许多实现都不需要将线程阻塞,因此这种同步操作称为非阻塞同步。 乐观锁需要操作和冲突检测这两个步骤具备原子性,这里就不能再使用互斥同步来保证了,只能靠硬件来完成。硬件支持的原子性操作最典型的是:比较并交换(Compare-and-Swap,CAS)。CAS 指令需要有 3 个操作数,分别是内存地址 V、旧的预期值 A 和新值 B。当执行操作时,只有当 V 的值等于 A,才将 V 的值更新为 B。 2. AtomicInteger J.U.C 包里面的整数原子类 AtomicInteger 的方法调用了 Unsafe 类的 CAS 操作。 以下代码使用了 AtomicInteger 执行了自增的操作。 12345private AtomicInteger cnt = new AtomicInteger();public void add() { cnt.incrementAndGet();} 以下代码是 incrementAndGet() 的源码,它调用了 Unsafe 的 getAndAddInt() 。 123public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1;} 以下代码是 getAndAddInt() 源码,var1 指示对象内存地址,var2 指示该字段相对对象内存地址的偏移,var4 指示操作需要加的数值,这里为 1。通过 getIntVolatile(var1, var2) 得到旧的预期值,通过调用 compareAndSwapInt() 来进行 CAS 比较,如果该字段内存地址中的值等于 var5,那么就更新内存地址为 var1+var2 的变量为 var5+var4。 可以看到 getAndAddInt() 在一个循环中进行,发生冲突的做法是不断的进行重试。 12345678public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5;} 3. ABA 如果一个变量初次读取的时候是 A 值,它的值被改成了 B,后来又被改回为 A,那 CAS 操作就会误认为它从来没有被改变过。 J.U.C 包提供了一个带有标记的原子引用类 AtomicStampedReference 来解决这个问题,它可以通过控制变量值的版本来保证 CAS 的正确性。大部分情况下 ABA 问题不会影响程序并发的正确性,如果需要解决 ABA 问题,改用传统的互斥同步可能会比原子类更高效。 无同步方案要保证线程安全,并不是一定就要进行同步。如果一个方法本来就不涉及共享数据,那它自然就无须任何同步措施去保证正确性。 1. 栈封闭 多个线程访问同一个方法的局部变量时,不会出现线程安全问题,因为局部变量存储在虚拟机栈中,属于线程私有的。 123456789101112131415161718public class StackClosedExample { public void add100() { int cnt = 0; for (int i = 0; i < 100; i++) { cnt++; } System.out.println(cnt); }}public static void main(String[] args) { StackClosedExample example = new StackClosedExample(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> example.add100()); executorService.execute(() -> example.add100()); executorService.shutdown();}100100 2. 线程本地存储(Thread Local Storage) 如果一段代码中所需要的数据必须与其他代码共享,那就看看这些共享数据的代码是否能保证在同一个线程中执行。如果能保证,我们就可以把共享数据的可见范围限制在同一个线程之内,这样,无须同步也能保证线程之间不出现数据争用的问题。 符合这种特点的应用并不少见,大部分使用消费队列的架构模式(如“生产者-消费者”模式)都会将产品的消费过程尽量在一个线程中消费完。其中最重要的一个应用实例就是经典 Web 交互模型中的“一个请求对应一个服务器线程”(Thread-per-Request)的处理方式,这种处理方式的广泛应用使得很多 Web 服务端应用都可以使用线程本地存储来解决线程安全问题。 可以使用 java.lang.ThreadLocal 类来实现线程本地存储功能。 对于以下代码,thread1 中设置 threadLocal 为 1,而 thread2 设置 threadLocal 为 2。过了一段时间之后,thread1 读取 threadLocal 依然是 1,不受 thread2 的影响。 12345678910111213141516171819202122public class ThreadLocalExample { public static void main(String[] args) { ThreadLocal threadLocal = new ThreadLocal(); Thread thread1 = new Thread(() -> { threadLocal.set(1); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadLocal.get()); threadLocal.remove(); }); Thread thread2 = new Thread(() -> { threadLocal.set(2); threadLocal.remove(); }); thread1.start(); thread2.start(); }}1 为了理解 ThreadLocal,先看以下代码: 12345678910111213141516public class ThreadLocalExample1 { public static void main(String[] args) { ThreadLocal threadLocal1 = new ThreadLocal(); ThreadLocal threadLocal2 = new ThreadLocal(); Thread thread1 = new Thread(() -> { threadLocal1.set(1); threadLocal2.set(1); }); Thread thread2 = new Thread(() -> { threadLocal1.set(2); threadLocal2.set(2); }); thread1.start(); thread2.start(); }} 它所对应的底层结构图为: 每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。 123/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null; 当调用一个 ThreadLocal 的 set(T value) 方法时,先得到当前线程的 ThreadLocalMap 对象,然后将 ThreadLocal->value 键值对插入到该 Map 中。 12345678public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);} get() 方法类似。 12345678910111213public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings(\"unchecked\") T result = (T)e.value; return result; } } return setInitialValue();} ThreadLocal 从理论上讲并不是用来解决多线程并发问题的,因为根本不存在多线程竞争。 在一些场景 (尤其是使用线程池) 下,由于 ThreadLocal.ThreadLocalMap 的底层数据结构导致 ThreadLocal 有内存泄漏的情况,应该尽可能在每次使用 ThreadLocal 后手动调用 remove(),以避免出现 ThreadLocal 经典的内存泄漏甚至是造成自身业务混乱的风险。 3. 可重入代码(Reentrant Code) 这种代码也叫做纯代码(Pure Code),可以在代码执行的任何时刻中断它,转而去执行另外一段代码(包括递归调用它本身),而在控制权返回后,原来的程序不会出现任何错误。 可重入代码有一些共同的特征,例如不依赖存储在堆上的数据和公用的系统资源、用到的状态量都由参数中传入、不调用非可重入的方法等。 锁优化这里的锁优化主要是指 JVM 对 synchronized 的优化。 自旋锁互斥同步进入阻塞状态的开销都很大,应该尽量避免。在许多应用中,共享数据的锁定状态只会持续很短的一段时间。自旋锁的思想是让一个线程在请求一个共享数据的锁时执行忙循环(自旋)一段时间,如果在这段时间内能获得锁,就可以避免进入阻塞状态。 自旋锁虽然能避免进入阻塞状态从而减少开销,但是它需要进行忙循环操作占用 CPU 时间,它只适用于共享数据的锁定状态很短的场景。 在 JDK 1.6 中引入了自适应的自旋锁。自适应意味着自旋的次数不再固定了,而是由前一次在同一个锁上的自旋次数及锁的拥有者的状态来决定。 锁消除锁消除是指对于被检测出不可能存在竞争的共享数据的锁进行消除。 锁消除主要是通过逃逸分析来支持,如果堆上的共享数据不可能逃逸出去被其它线程访问到,那么就可以把它们当成私有数据对待,也就可以将它们的锁进行消除。 对于一些看起来没有加锁的代码,其实隐式的加了很多锁。例如下面的字符串拼接代码就隐式加了锁: 123public static String concatString(String s1, String s2, String s3) { return s1 + s2 + s3;} String 是一个不可变的类,编译器会对 String 的拼接自动优化。在 JDK 1.5 之前,会转化为 StringBuffer 对象的连续 append() 操作: 1234567public static String concatString(String s1, String s2, String s3) { StringBuffer sb = new StringBuffer(); sb.append(s1); sb.append(s2); sb.append(s3); return sb.toString();} 每个 append() 方法中都有一个同步块。虚拟机观察变量 sb,很快就会发现它的动态作用域被限制在 concatString() 方法内部。也就是说,sb 的所有引用永远不会逃逸到 concatString() 方法之外,其他线程无法访问到它,因此可以进行消除。 锁粗化如果一系列的连续操作都对同一个对象反复加锁和解锁,频繁的加锁操作就会导致性能损耗。 上一节的示例代码中连续的 append() 方法就属于这类情况。如果虚拟机探测到由这样的一串零碎的操作都对同一个对象加锁,将会把加锁的范围扩展(粗化)到整个操作序列的外部。对于上一节的示例代码就是扩展到第一个 append() 操作之前直至最后一个 append() 操作之后,这样只需要加锁一次就可以了。 轻量级锁JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:无锁状态(unlocked)、偏向锁状态(biasble)、轻量级锁状态(lightweight locked)和重量级锁状态(inflated)。 以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。 下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象,包含了 Mark Word 和其它信息。 轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。 当尝试获取一个锁对象时,如果锁对象标记为 0 01,说明锁对象的锁未锁定(unlocked)状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record,然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00,表示该对象处于轻量级锁状态。 如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。 偏向锁偏向锁的思想是偏向于让第一个获取锁对象的线程,这个线程在之后获取该锁就不再需要进行同步操作,甚至连 CAS 操作也不再需要。 当锁对象第一次被线程获得的时候,进入偏向状态,标记为 1 01。同时使用 CAS 操作将线程 ID 记录到 Mark Word 中,如果 CAS 操作成功,这个线程以后每次进入这个锁相关的同步块就不需要再进行任何同步操作。 当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定状态或者轻量级锁状态。 多线程开发良好的实践 给线程起个有意义的名字,这样可以方便找 Bug。 缩小同步范围,从而减少锁争用。例如对于 synchronized,应该尽量使用同步块而不是同步方法。 多用同步工具少用 wait() 和 notify()。首先,CountDownLatch, CyclicBarrier, Semaphore 和 Exchanger 这些同步类简化了编码操作,而用 wait() 和 notify() 很难实现复杂控制流;其次,这些同步类是由最好的企业编写和维护,在后续的 JDK 中还会不断优化和完善。 使用 BlockingQueue 实现生产者消费者问题。 多用并发集合少用同步集合,例如应该使用 ConcurrentHashMap 而不是 Hashtable。 使用本地变量和不可变类来保证线程安全。 使用线程池而不是直接创建线程,这是因为创建线程代价很高,线程池可以有效地利用有限的线程来启动任务。 参考自来源感谢作者的辛勤整理,转载收藏,如有侵权,请评论说明,立即处理。","link":"/java/basic/Java%E5%B9%B6%E5%8F%91%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E7%82%B9.html"},{"title":"Java 垃圾回收","text":"摘要之前上学的时候有这个一个梗,说在食堂里吃饭,吃完把餐盘端走清理的,是 C++ 程序员,吃完直接就走的,是 Java 程序员。🤔 之前上学的时候有这个一个梗,说在食堂里吃饭,吃完把餐盘端走清理的,是 C++ 程序员,吃完直接就走的,是 Java 程序员。🤔 确实,在 Java 的世界里,似乎我们不用对垃圾回收那么的专注,很多初学者不懂 GC,也依然能写出一个能用甚至还不错的程序或系统。但其实这并不代表 Java 的 GC 就不重要。相反,它是那么的重要和复杂,以至于出了问题,那些初学者除了打开 GC 日志,看着一堆0101的天文,啥也做不了。😯 今天我们就从头到尾完整地聊一聊 Java 的垃圾回收 什么是垃圾回收 垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。 Java 语言出来之前,大家都在拼命的写 C 或者 C++ 的程序,而此时存在一个很大的矛盾,C++ 等语言创建对象要不断的去开辟空间,不用的时候又需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都在重复的 allocated,然后不停的析构。于是,有人就提出,能不能写一段程序实现这块功能,每次创建,释放控件的时候复用这段代码,而无需重复的书写呢? 1960年,基于 MIT 的 Lisp 首先提出了垃圾回收的概念,而这时 Java 还没有出世呢!所以实际上 GC 并不是Java的专利,GC 的历史远远大于 Java 的历史! 怎么定义垃圾 既然我们要做垃圾回收,首先我们得搞清楚垃圾的定义是什么,哪些内存是需要回收的。 引用计数算法引用计数算法(Reachability Counting)是通过在对象头中分配一个空间来保存该对象被引用的次数(Reference Count)。如果该对象被其它对象引用,则它的引用计数加1,如果删除对该对象的引用,那么它的引用计数就减1,当该对象的引用计数为0时,那么该对象就会被回收。 1String m = new String(\"jack\"); 先创建一个字符串,这时候”jack”有一个引用,就是 m。 然后将 m 设置为 null,这时候”jack”的引用次数就等于0了,在引用计数算法中,意味着这块内容就需要被回收了。 1m = null; 引用计数算法是将垃圾回收分摊到整个应用程序的运行当中了,而不是在进行垃圾收集时,要挂起整个应用的运行,直到对堆中所有对象的处理都结束。因此,采用引用计数的垃圾收集不属于严格意义上的”Stop-The-World”的垃圾收集机制。 看似很美好,但我们知道JVM的垃圾回收就是”Stop-The-World”的,那是什么原因导致我们最终放弃了引用计数算法呢?看下面的例子。 1234567891011121314151617public class ReferenceCountingGC { public Object instance; public ReferenceCountingGC(String name){}}public static void testGC(){ ReferenceCountingGC a = new ReferenceCountingGC(\"objA\"); ReferenceCountingGC b = new ReferenceCountingGC(\"objB\"); a.instance = b; b.instance = a; a = null; b = null;} 定义2个对象 相互引用 置空各自的声明引用 我们可以看到,最后这2个对象已经不可能再被访问了,但由于他们相互引用着对方,导致它们的引用计数永远都不会为0,通过引用计数算法,也就永远无法通知GC收集器回收它们。 可达性分析算法 可达性分析算法(Reachability Analysis)的基本思路是,通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连时(即从 GC Roots 节点到该节点不可达),则证明该对象是不可用的。 通过可达性算法,成功解决了引用计数所无法解决的问题-“循环依赖”,只要你无法与 GC Root 建立直接或间接的连接,系统就会判定你为可回收对象。那这样就引申出了另一个问题,哪些属于 GC Root。 Java 内存区域在 Java 语言中,可作为 GC Root 的对象包括以下4种: 虚拟机栈(栈帧中的本地变量表)中引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象 虚拟机栈(栈帧中的本地变量表)中引用的对象此时的 s,即为 GC Root,当s置空时,localParameter 对象也断掉了与 GC Root 的引用链,将被回收。 12345678public class StackLocalParameter { public StackLocalParameter(String name){}}public static void testGC(){ StackLocalParameter s = new StackLocalParameter(\"localParameter\"); s = null;} 方法区中类静态属性引用的对象s 为 GC Root,s 置为 null,经过 GC 后,s 所指向的 properties 对象由于无法与 GC Root 建立关系被回收。 而 m 作为类的静态属性,也属于 GC Root,parameter 对象依然与 GC root 建立着连接,所以此时 parameter 对象并不会被回收。 12345678910public class MethodAreaStaicProperties { public static MethodAreaStaicProperties m; public MethodAreaStaicProperties(String name){}}public static void testGC(){ MethodAreaStaicProperties s = new MethodAreaStaicProperties(\"properties\"); s.m = new MethodAreaStaicProperties(\"parameter\"); s = null;} 方法区中常量引用的对象m 即为方法区中的常量引用,也为 GC Root,s 置为 null 后,final 对象也不会因没有与 GC Root 建立联系而被回收。 123456789public class MethodAreaStaicProperties { public static final MethodAreaStaicProperties m = MethodAreaStaicProperties(\"final\"); public MethodAreaStaicProperties(String name){}}public static void testGC(){ MethodAreaStaicProperties s = new MethodAreaStaicProperties(\"staticProperties\"); s = null;} 本地方法栈中引用的对象任何 Native 接口都会使用某种本地方法栈,实现的本地方法接口是使用 C 连接模型的话,那么它的本地方法栈就是 C 栈。当线程调用 Java 方法时,虚拟机会创建一个新的栈帧并压入 Java 栈。然而当它调用的是本地方法时,虚拟机会保持 Java 栈不变,不再在线程的 Java 栈中压入新的帧,虚拟机只是简单地动态连接并直接调用指定的本地方法。 怎么回收垃圾在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是开始进行垃圾回收,但是这里面涉及到一个问题是:如何高效地进行垃圾回收。由于Java虚拟机规范并没有对如何实现垃圾收集器做出明确的规定,因此各个厂商的虚拟机可以采用不同的方式来实现垃圾收集器,这里我们讨论几种常见的垃圾收集算法的核心思想。 标记 — 清除算法 标记清除算法(Mark-Sweep)是最基础的一种垃圾回收算法,它分为2部分,先把内存区域中的这些对象进行标记,哪些属于可回收标记出来,然后把这些垃圾拎出来清理掉。就像上图一样,清理掉的垃圾就变成未使用的内存区域,等待被再次使用。 这逻辑再清晰不过了,并且也很好操作,但它存在一个很大的问题,那就是内存碎片。 上图中等方块的假设是 2M,小一些的是 1M,大一些的是 4M。等我们回收完,内存就会切成了很多段。我们知道开辟内存空间时,需要的是连续的内存区域,这时候我们需要一个 2M的内存区域,其中有2个 1M 是没法用的。这样就导致,其实我们本身还有这么多的内存的,但却用不了。 复制算法 复制算法(Copying)是在标记清除算法上演化而来,解决标记清除算法的内存碎片问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。保证了内存的连续可用,内存分配时也就不用考虑内存碎片等复杂情况,逻辑清晰,运行高效。 上面的图很清楚,也很明显的暴露了另一个问题,合着我这140平的大三房,只能当70平米的小两房来使?代价实在太高。 标记整理算法 标记整理算法(Mark-Compact)标记过程仍然与标记 — 清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,再清理掉端边界以外的内存区域。 标记整理算法一方面在标记-清除算法上做了升级,解决了内存碎片的问题,也规避了复制算法只能利用一半内存区域的弊端。看起来很美好,但从上图可以看到,它对内存变动更频繁,需要整理所有存活对象的引用地址,在效率上比复制算法要差很多。 分代收集算法分代收集算法(Generational Collection)严格来说并不是一种思想或理论,而是融合上述3种基础的算法思想,而产生的针对不同情况所采用不同算法的一套组合拳。对象存活周期的不同将内存划分为几块。一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记-清理或者标记 — 整理算法来进行回收。so,另一个问题来了,那内存区域到底被分为哪几块,每一块又有什么特别适合什么算法呢? 内存模型与回收策略 Java 堆(Java Heap)是JVM所管理的内存中最大的一块,堆又是垃圾收集器管理的主要区域,这里我们主要分析一下 Java 堆的结构。 Java 堆主要分为2个区域-年轻代与老年代,其中年轻代又分 Eden 区和 Survivor 区,其中 Survivor 区又分 From 和 To 2个区。可能这时候大家会有疑问,为什么需要 Survivor 区,为什么Survivor 还要分2个区。不着急,我们从头到尾,看看对象到底是怎么来的,而它又是怎么没的。 Eden 区IBM 公司的专业研究表明,有将近98%的对象是朝生夕死,所以针对这一现状,大多数情况下,对象会在新生代 Eden 区中进行分配,当 Eden 区没有足够空间进行分配时,虚拟机会发起一次 Minor GC,Minor GC 相比 Major GC 更频繁,回收速度也更快。 通过 Minor GC 之后,Eden 会被清空,Eden 区中绝大部分对象会被回收,而那些无需回收的存活对象,将会进到 Survivor 的 From 区(若 From 区不够,则直接进入 Old 区)。 Survivor 区Survivor 区相当于是 Eden 区和 Old 区的一个缓冲,类似于我们交通灯中的黄灯。Survivor 又分为2个区,一个是 From 区,一个是 To 区。每次执行 Minor GC,会将 Eden 区和 From 存活的对象放到 Survivor 的 To 区(如果 To 区不够,则直接进入 Old 区)。 为啥需要?不就是新生代到老年代么,直接 Eden 到 Old 不好了吗,为啥要这么复杂。想想如果没有 Survivor 区,Eden 区每进行一次 Minor GC,存活的对象就会被送到老年代,老年代很快就会被填满。而有很多对象虽然一次 Minor GC 没有消灭,但其实也并不会蹦跶多久,或许第二次,第三次就需要被清除。这时候移入老年区,很明显不是一个明智的决定。 所以,Survivor 的存在意义就是减少被送到老年代的对象,进而减少 Major GC 的发生。Survivor 的预筛选保证,只有经历16次 Minor GC 还能在新生代中存活的对象,才会被送到老年代。 为啥需要俩?设置两个 Survivor 区最大的好处就是解决内存碎片化。 我们先假设一下,Survivor 如果只有一个区域会怎样。Minor GC 执行后,Eden 区被清空了,存活的对象放到了 Survivor 区,而之前 Survivor 区中的对象,可能也有一些是需要被清除的。问题来了,这时候我们怎么清除它们?在这种场景下,我们只能标记清除,而我们知道标记清除最大的问题就是内存碎片,在新生代这种经常会消亡的区域,采用标记清除必然会让内存产生严重的碎片化。因为 Survivor 有2个区域,所以每次 Minor GC,会将之前 Eden 区和 From 区中的存活对象复制到 To 区域。第二次 Minor GC 时,From 与 To 职责兑换,这时候会将 Eden 区和 To 区中的存活对象再复制到 From 区域,以此反复。 这种机制最大的好处就是,整个过程中,永远有一个 Survivor space 是空的,另一个非空的 Survivor space 是无碎片的。那么,Survivor 为什么不分更多块呢?比方说分成三个、四个、五个?显然,如果 Survivor 区再细分下去,每一块的空间就会比较小,容易导致 Survivor 区满,两块 Survivor 区可能是经过权衡之后的最佳方案。 Old 区老年代占据着2/3的堆内存空间,只有在 Major GC 的时候才会进行清理,每次 GC 都会触发“Stop-The-World”。内存越大,STW 的时间也越长,所以内存也不仅仅是越大就越好。由于复制算法在对象存活率较高的老年代会进行很多次的复制操作,效率很低,所以老年代这里采用的是标记 — 整理算法。 除了上述所说,在内存担保机制下,无法安置的对象会直接进到老年代,以下几种情况也会进入老年代。 大对象大对象指需要大量连续内存空间的对象,这部分对象不管是不是“朝生夕死”,都会直接进到老年代。这样做主要是为了避免在 Eden 区及2个 Survivor 区之间发生大量的内存复制。当你的系统有非常多“朝生夕死”的大对象时,得注意了。 长期存活对象虚拟机给每个对象定义了一个对象年龄(Age)计数器。正常情况下对象会不断的在 Survivor 的 From 区与 To 区之间移动,对象在 Survivor 区中每经历一次 Minor GC,年龄就增加1岁。当年龄增加到15岁时,这时候就会被转移到老年代。当然,这里的15,JVM 也支持进行特殊设置。 动态对象年龄虚拟机并不重视要求对象年龄必须到15岁,才会放入老年区,如果 Survivor 空间中相同年龄所有对象大小的总合大于 Survivor 空间的一半,年龄大于等于该年龄的对象就可以直接进去老年区,无需等你“成年”。 这其实有点类似于负载均衡,轮询是负载均衡的一种,保证每台机器都分得同样的请求。看似很均衡,但每台机的硬件不通,健康状况不同,我们还可以基于每台机接受的请求数,或每台机的响应时间等,来调整我们的负载均衡算法。 参考自 .","link":"/java/basic/Java-%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6.html"},{"title":"Java BIO NIO AIO区别与使用","text":"摘要BIO 全称Block-IO 是一种同步且阻塞的通信模式。是一个比较传统的通信方式,模式简单,使用方便。但并发处理能力低,通信耗时,依赖网速。 Java BIO使用BIO实现文件的读取和写入。 123456789101112131415161718192021222324252627282930313233343536//Initializes The ObjectUser1 user = new User1();user.setName(\"hollis\");user.setAge(23);System.out.println(user);//Write Obj to FileObjectOutputStream oos = null;try { oos = new ObjectOutputStream(new FileOutputStream(\"tempFile\")); oos.writeObject(user);} catch (IOException e) { e.printStackTrace();} finally { IOUtils.closeQuietly(oos);}//Read Obj from FileFile file = new File(\"tempFile\");ObjectInputStream ois = null;try { ois = new ObjectInputStream(new FileInputStream(file)); User1 newUser = (User1) ois.readObject(); System.out.println(newUser);} catch (IOException e) { e.printStackTrace();} catch (ClassNotFoundException e) { e.printStackTrace();} finally { IOUtils.closeQuietly(ois); try { FileUtils.forceDelete(file); } catch (IOException e) { e.printStackTrace(); }} Java NIOJava NIO,全程 Non-Block IO ,是Java SE 1.4版以后,针对网络传输效能优化的新功能。是一种非阻塞同步的通信模式。NIO 与原来的 I/O 有同样的作用和目的, 他们之间最重要的区别是数据打包和传输的方式。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。面向流的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。面向块的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364static void readNIO() { String pathname = \"C:\\\\Users\\\\adew\\\\Desktop\\\\jd-gui.cfg\"; FileInputStream fin = null; try { fin = new FileInputStream(new File(pathname)); FileChannel channel = fin.getChannel(); int capacity = 100;// 字节 ByteBuffer bf = ByteBuffer.allocate(capacity); int length = -1; while ((length = channel.read(bf)) != -1) { bf.clear(); byte[] bytes = bf.array(); System.out.write(bytes, 0, length); System.out.println(); } channel.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fin != null) { try { fin.close(); } catch (IOException e) { e.printStackTrace(); } } } } static void writeNIO() { String filename = \"out.txt\"; FileOutputStream fos = null; try { fos = new FileOutputStream(new File(filename)); FileChannel channel = fos.getChannel(); ByteBuffer src = Charset.forName(\"utf8\").encode(\"你好你好你好你好你好\"); int length = 0; while ((length = channel.write(src)) != 0) { System.out.println(\"写入长度:\" + length); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } Java AIOJava AIO,全程 Asynchronous IO,是异步非阻塞的IO。是一种非阻塞异步的通信模式。在NIO的基础上引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253public class ReadFromFile { public static void main(String[] args) throws Exception { Path file = Paths.get(\"/usr/a.txt\"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(file); ByteBuffer buffer = ByteBuffer.allocate(100_000); Future<Integer> result = channel.read(buffer, 0); while (!result.isDone()) { ProfitCalculator.calculateTax(); } Integer bytesRead = result.get(); System.out.println(\"Bytes read [\" + bytesRead + \"]\"); }}class ProfitCalculator { public ProfitCalculator() { } public static void calculateTax() { }}public class WriteToFile { public static void main(String[] args) throws Exception { AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open( Paths.get(\"/asynchronous.txt\"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); CompletionHandler<Integer, Object> handler = new CompletionHandler<Integer, Object>() { @Override public void completed(Integer result, Object attachment) { System.out.println(\"Attachment: \" + attachment + \" \" + result + \" bytes written\"); System.out.println(\"CompletionHandler Thread ID: \" + Thread.currentThread().getId()); } @Override public void failed(Throwable e, Object attachment) { System.err.println(\"Attachment: \" + attachment + \" failed with:\"); e.printStackTrace(); } }; System.out.println(\"Main Thread ID: \" + Thread.currentThread().getId()); fileChannel.write(ByteBuffer.wrap(\"Sample\".getBytes()), 0, \"First Write\", handler); fileChannel.write(ByteBuffer.wrap(\"Box\".getBytes()), 0, \"Second Write\", handler); }} 三种IO的区别首先,我们站在宏观的角度,重新画一下重点: BIO (Blocking I/O):同步阻塞I/O模式。 NIO (New I/O):同步非阻塞模式。 AIO (Asynchronous I/O):异步非阻塞I/O模型。 同步请求,A调用B,B的处理是同步的,在处理完之前他不会通知A,只有处理完之后才会明确的通知A。 异步请求,A调用B,B的处理是异步的,B在接到请求后先告诉A我已经接到请求了,然后异步去处理,处理完之后通过回调等方式再通知A。 所以说,同步和异步最大的区别就是被调用方的执行方式和返回时机。同步指的是被调用方做完事情之后再返回,异步指的是被调用方先返回,然后再做事情,做完之后再想办法通知调用方。 阻塞请求,A调用B,A一直等着B的返回,别的事情什么也不干。 非阻塞请求,A调用B,A不用一直等着B的返回,先去忙别的事情了。 所以说,阻塞非阻塞最大的区别就是在被调用方返回结果之前的这段时间内,调用方是否一直等待。阻塞指的是调用方一直等待别的事情什么都不做。非阻塞指的是调用方先去忙别的事情。 同步阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,并坐在水壶面前一直等着水烧开。 同步非阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,但是我们不一直坐在水壶前面等,而是回到客厅看电视,然后每隔几分钟到厨房看一下水有没有烧开。 异步非阻塞I/O模型:这种模式下,我们的工作模式是先来到厨房,开始烧水,我们不一一直坐在水壶前面等,也不隔一段时间去看一下,而是在客厅看电视,水壶上面有个开关,水烧开之后他会通知我。 阻塞VS非阻塞:人是否坐在水壶前面一直等。 同步VS异步:水壶是不是在水烧开之后主动通知人。 适用场景BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。 NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。 AIO方式适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。 参考自 .","link":"/java/basic/Java-BIO-NIO-AIO%E5%8C%BA%E5%88%AB%E4%B8%8E%E4%BD%BF%E7%94%A8.html"},{"title":"常见sql错误写法","text":"摘要sql语句应用不当,可能仅仅一个顺序的不同,往往会带来成千上万倍的耗时问题。 1、LIMIT 语句分页查询是最常用的场景之一,但也通常也是最容易出问题的地方。比如对于下面简单的语句,一般 DBA 想到的办法是在 type, name, create_time 字段上加组合索引。这样条件排序都能有效的利用到索引,性能迅速提升。 123456SELECT * FROM operation WHERE type = 'SQLStats' AND name = 'SlowLog' ORDER BY create_time LIMIT 1000, 10; 好吧,可能90%以上的 DBA 解决该问题就到此为止。但当 LIMIT 子句变成 “LIMIT 1000000,10” 时,程序员仍然会抱怨:我只取10条记录为什么还是慢? 要知道数据库也并不知道第1000000条记录从什么地方开始,即使有索引也需要从头计算一次。出现这种性能问题,多数情形下是程序员偷懒了。 在前端数据浏览翻页,或者大数据分批导出等场景下,是可以将上一页的最大值当成参数作为查询条件的。SQL 重新设计如下: 123456SELECT * FROM operation WHERE type = 'SQLStats' AND name = 'SlowLog' AND create_time > '2017-03-16 14:00:00' ORDER BY create_time limit 10; 在新设计下查询时间基本固定,不会随着数据量的增长而发生变化。 2、隐式转换SQL语句中查询变量和字段定义类型不匹配是另一个常见的错误。比如下面的语句: 123456mysql> explain extended SELECT * > FROM my_balance b > WHERE b.bpn = 14000000123 > AND b.isverified IS NULL ;mysql> show warnings;| Warning | 1739 | Cannot use ref access on index 'bpn' due to type or collation conversion on field 'bpn' 其中字段 bpn 的定义为 varchar(20),MySQL 的策略是将字符串转换为数字之后再比较。函数作用于表字段,索引失效。 上述情况可能是应用程序框架自动填入的参数,而不是程序员的原意。现在应用框架很多很繁杂,使用方便的同时也小心它可能给自己挖坑。 3、关联更新、删除虽然 MySQL5.6 引入了物化特性,但需要特别注意它目前仅仅针对查询语句的优化。对于更新或删除需要手工重写成 JOIN。 比如下面 UPDATE 语句,MySQL 实际执行的是循环/嵌套子查询(DEPENDENT SUBQUERY),其执行时间可想而知。 1234567891011UPDATE operation o SET status = 'applying' WHERE o.id IN (SELECT id FROM (SELECT o.id, o.status FROM operation o WHERE o.group = 123 AND o.status NOT IN ( 'done' ) ORDER BY o.parent, o.id LIMIT 1) t); 执行计划: 1234567+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+| 1 | PRIMARY | o | index | | PRIMARY | 8 | | 24 | Using where; Using temporary || 2 | DEPENDENT SUBQUERY | | | | | | | | Impossible WHERE noticed after reading const tables || 3 | DERIVED | o | ref | idx_2,idx_5 | idx_5 | 8 | const | 1 | Using where; Using filesort |+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+ 重写为 JOIN 之后,子查询的选择模式从 DEPENDENT SUBQUERY 变成 DERIVED,执行速度大大加快,从7秒降低到2毫秒。 1234567891011UPDATE operation o JOIN (SELECT o.id, o.status FROM operation o WHERE o.group = 123 AND o.status NOT IN ( 'done' ) ORDER BY o.parent, o.id LIMIT 1) t ON o.id = t.id SET status = 'applying' 执行计划简化为: 1234567+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+| 1 | PRIMARY | | | | | | | | Impossible WHERE noticed after reading const tables || 2 | DERIVED | o | ref | idx_2,idx_5 | idx_5 | 8 | const | 1 | Using where; Using filesort |+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+ 4、混合排序MySQL 不能利用索引进行混合排序。但在某些场景,还是有机会使用特殊方法提升性能的。 1234567SELECT * FROM my_order o INNER JOIN my_appraise a ON a.orderid = o.id ORDER BY a.is_reply ASC, a.appraise_time DESC LIMIT 0, 20 执行计划显示为全表扫描: 1234567+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra +----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+| 1 | SIMPLE | a | ALL | idx_orderid | NULL | NULL | NULL | 1967647 | Using filesort || 1 | SIMPLE | o | eq_ref | PRIMARY | PRIMARY | 122 | a.orderid | 1 | NULL |+----+-------------+-------+--------+---------+---------+---------+-----------------+---------+-+ 由于 is_reply 只有0和1两种状态,我们按照下面的方法重写后,执行时间从1.58秒降低到2毫秒。 12345678910111213141516171819SELECT * FROM ((SELECT * FROM my_order o INNER JOIN my_appraise a ON a.orderid = o.id AND is_reply = 0 ORDER BY appraise_time DESC LIMIT 0, 20) UNION ALL (SELECT * FROM my_order o INNER JOIN my_appraise a ON a.orderid = o.id AND is_reply = 1 ORDER BY appraise_time DESC LIMIT 0, 20)) t ORDER BY is_reply ASC, appraisetime DESC LIMIT 20; 5、EXISTS语句MySQL 对待 EXISTS 子句时,仍然采用嵌套子查询的执行方式。如下面的 SQL 语句: 1234567891011SELECT *FROM my_neighbor n LEFT JOIN my_neighbor_apply sra ON n.id = sra.neighbor_id AND sra.user_id = 'xxx' WHERE n.topic_status < 4 AND EXISTS(SELECT 1 FROM message_info m WHERE n.id = m.neighbor_id AND m.inuser = 'xxx') AND n.topic_type <> 5 执行计划为: 12345678+----+--------------------+-------+------+-----+------------------------------------------+---------+-------+---------+ -----+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+| 1 | PRIMARY | n | ALL | | NULL | NULL | NULL | 1086041 | Using where || 1 | PRIMARY | sra | ref | | idx_user_id | 123 | const | 1 | Using where || 2 | DEPENDENT SUBQUERY | m | ref | | idx_message_info | 122 | const | 1 | Using index condition; Using where |+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+ 去掉 exists 更改为 join,能够避免嵌套子查询,将执行时间从1.93秒降低为1毫秒。 12345678910SELECT *FROM my_neighbor n INNER JOIN message_info m ON n.id = m.neighbor_id AND m.inuser = 'xxx' LEFT JOIN my_neighbor_apply sra ON n.id = sra.neighbor_id AND sra.user_id = 'xxx' WHERE n.topic_status < 4 AND n.topic_type <> 5 新的执行计划: 12345678+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+| 1 | SIMPLE | m | ref | | idx_message_info | 122 | const | 1 | Using index condition || 1 | SIMPLE | n | eq_ref | | PRIMARY | 122 | ighbor_id | 1 | Using where || 1 | SIMPLE | sra | ref | | idx_user_id | 123 | const | 1 | Using where |+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+ 6、条件下推外部查询条件不能够下推到复杂的视图或子查询的情况有: 聚合子查询; 含有 LIMIT 的子查询; UNION 或 UNION ALL 子查询; 输出字段中的子查询; 如下面的语句,从执行计划可以看出其条件作用于聚合子查询之后: 123456SELECT * FROM (SELECT target, Count(*) FROM operation GROUP BY target) t WHERE target = 'rm-xxxx' 1234567+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+| 1 | PRIMARY | <derived2> | ref | <auto_key0> | <auto_key0> | 514 | const | 2 | Using where || 2 | DERIVED | operation | index | idx_4 | idx_4 | 519 | NULL | 20 | Using index |+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+ 确定从语义上查询条件可以直接下推后,重写如下: 12345SELECT target, Count(*) FROM operation WHERE target = 'rm-xxxx' GROUP BY target 执行计划变为: 123456+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+| 1 | SIMPLE | operation | ref | idx_4 | idx_4 | 514 | const | 1 | Using where; Using index |+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+ 关于 MySQL 外部条件不能下推的详细解释说明请参考文章: 7、提前缩小范围先上初始 SQL 语句: 12345678910SELECT * FROM my_order o LEFT JOIN my_userinfo u ON o.uid = u.uid LEFT JOIN my_productinfo p ON o.pid = p.pid WHERE ( o.display = 0 ) AND ( o.ostaus = 1 ) ORDER BY o.selltime DESC LIMIT 0, 15 该SQL语句原意是:先做一系列的左连接,然后排序取前15条记录。从执行计划也可以看出,最后一步估算排序记录数为90万,时间消耗为12秒。 12345678+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+| 1 | SIMPLE | o | ALL | NULL | NULL | NULL | NULL | 909119 | Using where; Using temporary; Using filesort || 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 4 | o.uid | 1 | NULL || 1 | SIMPLE | p | ALL | PRIMARY | NULL | NULL | NULL | 6 | Using where; Using join buffer (Block Nested Loop) |+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+ 由于最后 WHERE 条件以及排序均针对最左主表,因此可以先对 my_order 排序提前缩小数据量再做左连接。SQL 重写后如下,执行时间缩小为1毫秒左右。 123456789101112131415SELECT * FROM (SELECT * FROM my_order o WHERE ( o.display = 0 ) AND ( o.ostaus = 1 ) ORDER BY o.selltime DESC LIMIT 0, 15) o LEFT JOIN my_userinfo u ON o.uid = u.uid LEFT JOIN my_productinfo p ON o.pid = p.pid ORDER BY o.selltime DESClimit 0, 15 再检查执行计划:子查询物化后(select_type=DERIVED)参与 JOIN。虽然估算行扫描仍然为90万,但是利用了索引以及 LIMIT 子句后,实际执行时间变得很小。 123456789+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 15 | Using temporary; Using filesort || 1 | PRIMARY | u | eq_ref | PRIMARY | PRIMARY | 4 | o.uid | 1 | NULL || 1 | PRIMARY | p | ALL | PRIMARY | NULL | NULL | NULL | 6 | Using where; Using join buffer (Block Nested Loop) || 2 | DERIVED | o | index | NULL | idx_1 | 5 | NULL | 909112 | Using where |+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+ 8、中间结果集下推再来看下面这个已经初步优化过的例子(左连接中的主表优先作用查询条件): 1234567891011121314SELECT a.*, c.allocated FROM ( SELECT resourceid FROM my_distribute d WHERE isdelete = 0 AND cusmanagercode = '1234567' ORDER BY salecode limit 20) a LEFT JOIN ( SELECT resourcesid, sum(ifnull(allocation, 0) * 12345) allocated FROM my_resources GROUP BY resourcesid) c ON a.resourceid = c.resourcesid 那么该语句还存在其它问题吗?不难看出子查询 c 是全表聚合查询,在表数量特别大的情况下会导致整个语句的性能下降。 其实对于子查询 c,左连接最后结果集只关心能和主表 resourceid 能匹配的数据。因此我们可以重写语句如下,执行时间从原来的2秒下降到2毫秒。 123456789101112131415161718192021SELECT a.*, c.allocated FROM ( SELECT resourceid FROM my_distribute d WHERE isdelete = 0 AND cusmanagercode = '1234567' ORDER BY salecode limit 20) a LEFT JOIN ( SELECT resourcesid, sum(ifnull(allocation, 0) * 12345) allocated FROM my_resources r, ( SELECT resourceid FROM my_distribute d WHERE isdelete = 0 AND cusmanagercode = '1234567' ORDER BY salecode limit 20) a WHERE r.resourcesid = a.resourcesid GROUP BY resourcesid) c ON a.resourceid = c.resourcesid 但是子查询 a 在我们的SQL语句中出现了多次。这种写法不仅存在额外的开销,还使得整个语句显的繁杂。使用 WITH 语句再次重写: 123456789101112131415161718WITH a AS ( SELECT resourceid FROM my_distribute d WHERE isdelete = 0 AND cusmanagercode = '1234567' ORDER BY salecode limit 20)SELECT a.*, c.allocated FROM a LEFT JOIN ( SELECT resourcesid, sum(ifnull(allocation, 0) * 12345) allocated FROM my_resources r, a WHERE r.resourcesid = a.resourcesid GROUP BY resourcesid) c ON a.resourceid = c.resourcesid 总结数据库编译器产生执行计划,决定着SQL的实际执行方式。但是编译器只是尽力服务,所有数据库的编译器都不是尽善尽美的。 上述提到的多数场景,在其它数据库中也存在性能问题。了解数据库编译器的特性,才能避规其短处,写出高性能的SQL语句。 程序员在设计数据模型以及编写SQL语句时,要把算法的思想或意识带进来。 编写复杂SQL语句要养成使用 WITH 语句的习惯。简洁且思路清晰的SQL语句也能减小数据库的负担 。转自","link":"/database/%E5%B8%B8%E8%A7%81sql%E9%94%99%E8%AF%AF%E5%86%99%E6%B3%95.html"},{"title":"mysql索引优化方案","text":"摘要mysql自带优化:先执行explain sql,在执行explain extended sql,得到优化结果,show warnings显示优化后的结果sql. 索引基数基数是数据列所包含的不同值的数量,例如,某个数据列包含值 1、3、7、4、7、3,那么它的基数就是 4。索引的基数相对于数据表行数较高(也就是说,列中包含很多不同的值,重复的值很少)的时候,它的工作效果最好。如果某数据列含有很多不同的年龄,索引会很快地分辨数据行;如果某个数据列用于记录性别(只有“M”和“F”两种值),那么索引的用处就不大;如果值出现的几率几乎相等,那么无论搜索哪个值都可能得到一半的数据行。在这些情况下,最好根本不要使用索引,因为查询优化器发现某个值出现在表的数据行中的百分比很高的时候,它一般会忽略索引,进行全表扫描。惯用的百分比界线是“30%”。 索引失效原因索引失效的原因有如下几点: 对索引列运算,运算包括(+、-、*、/、!、<>、%、like’%_’(% 放在前面)。 类型错误,如字段类型为 varchar,where 条件用 number。 对索引应用内部函数,这种情况下应该要建立基于函数的索引。例如 select * from template t where ROUND (t.logicdb_id) = 1,此时应该建 ROUND (t.logicdb_id) 为索引。 MySQL 8.0 开始支持函数索引,5.7 可以通过虚拟列的方式来支持,之前只能新建一个 ROUND (t.logicdb_id) 列然后去维护。 如果条件有 or,即使其中有条件带索引也不会使用(这也是为什么建议少使用 or 的原因),如果想使用 or,又想索引有效,只能将 or 条件中的每个列加上索引。 如果列类型是字符串,那一定要在条件中数据使用引号,否则不使用索引。 B-tree 索引 is null 不会走,is not null 会走,位图索引 is null,is not null 都会走。 组合索引遵循最左原则。 索引的建立索引的建立需要注意以下几点: 最重要的肯定是根据业务经常查询的语句。 尽量选择区分度高的列作为索引,区分度的公式是$$COUNT(DISTINCT空格col) / COUNT(*):表示字段不重复的比率,比率越大我们扫描的记录数就越少。$$ 如果业务中唯一特性最好建立唯一键,一方面可以保证数据的正确性,另一方面索引的效率能大大提高。 EXPLIAN 中有用的信息EXPLIAN 基本用法如下: desc 或者 explain 加上你的 SQL。 explain extended 加上你的 SQL,然后通过 show warnings 可以查看实际执行的语句,这一点也是非常有用的,很多时候不同的写法经 SQL 分析后,实际执行的代码是一样的。 提高性能的特性EXPLIAN 提高性能的特性如下: 索引覆盖(covering index):需要查询的数据在索引上都可以查到不需要回表 EXTRA 列显示 using index。 ICP特性(Index Condition Pushdown):本来 index 仅仅是 data access 的一种访问模式,存数引擎通过索引回表获取的数据会传递到 MySQL Server 层进行 where 条件过滤。 5.6 版本开始当 ICP 打开时,如果部分 where 条件能使用索引的字段,MySQL Server 会把这部分下推到引擎层,可以利用 index 过滤的 where 条件在存储引擎层进行数据过滤。 EXTRA 显示 using index condition。需要了解 MySQL 的架构图分为 Server 和存储引擎层。 索引合并(index merge):对多个索引分别进行条件扫描,然后将它们各自的结果进行合并(intersect/union)。 一般用 or 会用到,如果是 AND 条件,考虑建立复合索引。EXPLAIN 显示的索引类型会显示 index_merge,EXTRA 会显示具体的合并算法和用到的索引。 Extra字段Extra 字段使用: using filesort:说明 MySQL 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。 MySQL 中无法利用索引完成的排序操作称为“文件排序”,其实不一定是文件排序,内部使用的是快排。 using temporary:使用了临时表保存中间结果,MySQL 在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by。 using index:表示相应的 SELECT 操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错。 impossible where:where 子句的值总是 false,不能用来获取任何元组。 select tables optimized away:在没有 group by 子句的情况下基于索引优化 MIN/MAX 操作或者对于 MyISAM 存储引擎优化 COUNT(*) 操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。 distinct:优化 distinct 操作,在找到第一匹配的元组后即停止找同样值的操作。 using filesort、using temporary 这两项出现时需要注意下,这两项是十分耗费性能的 在使用 group by 的时候,虽然没有使用 order by,如果没有索引,是可能同时出现 using filesort,using temporary 的。因为 group by 就是先排序在分组,如果没有排序的需要,可以加上一个 order by NULL 来避免排序,这样 using filesort 就会去除,能提升一点性能。 type字段 system:表只有一行记录(等于系统表),这是 const 类型的特例,平时不会出现。 const:如果通过索引依次就找到了,const 用于比较主键索引或者 unique 索引。因为只能匹配一行数据,所以很快。如果将主键置于 where 列表中,MySQL 就能将该查询转换为一个常量。 eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。 ref:非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体。 range:只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引,一般就是在你的 where 语句中出现 between、<、>、in 等的查询。 这种范围扫描索引比全表扫描要好,因为只需要开始于缩印的某一点,而结束于另一点,不用扫描全部索引。 index:Full Index Scan ,index 与 ALL 的区别为 index 类型只遍历索引树,这通常比 ALL 快,因为索引文件通常比数据文件小。 也就是说虽然 ALL 和 index 都是读全表,但 index 是从索引中读取的,而 ALL 是从硬盘读取的。 all:Full Table Scan,遍历全表获得匹配的行。 字段类型和编码 MySQL 返回字符串长度 CHARACTER_LENGTH(同CHAR_LENGTH)方法返回的是字符数,LENGTH 函数返回的是字节数,一个汉字三个字节。 varchar 等字段建立索引长度计算语句 select count(distinct left(test,5))/count(*) from table;越趋近 1 越好。 MySQL 的 utf8 MySQL 的 utf8 最大是 3 个字节不支持 emoji 表情符号,必须只用 utf8mb4。需要在 MySQL 配置文件中配置客户端字符集为 utf8mb4。 JDBC 的连接串不支持配置 characterEncoding=utf8mb4,最好的办法是在连接池中指定初始化 SQL。例如:hikari 连接池,其他连接池类似 spring . datasource . hikari . connection - init - sql =set names utf8mb4。否则需要每次执行 SQL 前都先执行 set names utf8mb4。 MySQL 排序规则一般使用 _bin 和 _genera_ci: utf8_genera_ci 不区分大小写,ci 为 case insensitive 的缩写,即大小写不敏感。 utf8_general_cs 区分大小写,cs 为 case sensitive 的缩写,即大小写敏感,但是目前 MySQL 版本中已经不支持类似于 _genera_cs 的排序规则,直接使用 utf8_bin 替代。 utf8_bin 将字符串中的每一个字符用二进制数据存储,区分大小写。 那么,同样是区分大小写,utf8_general_cs 和 utf8_bin 有什么区别? cs 为 case sensitive 的缩写,即大小写敏感;bin 的意思是二进制,也就是二进制编码比较。 utf8_general_cs 排序规则下,即便是区分了大小写,但是某些西欧的字符和拉丁字符是不区分的,比如 ä=a,但是有时并不需要 ä=a,所以才有 utf8_bin。 utf8_bin 的特点在于使用字符的二进制的编码进行运算,任何不同的二进制编码都是不同的,因此在 utf8_bin 排序规则下:ä<>a。 SQL语句总结常用但容易忘的 如果有主键或者唯一键冲突则不插入:insert ignore into。 如果有主键或者唯一键冲突则更新,注意这个会影响自增的增量:INSERT INTO room_remarks(room_id,room_remarks)VALUE(1,”sdf”) ON DUPLICATE KEY UPDATE room_remarks = “234”。 如果有就用新的替代,values 如果不包含自增列,自增列的值会变化:REPLACE INTO room_remarks(room_id,room_remarks) VALUE(1,”sdf”)。 备份表:CREATE TABLE user_info SELECT * FROM user_info。 复制表结构:CREATE TABLE user_v2 LIKE user。 从查询语句中导入:INSERT INTO user_v2 SELECT * FROM user 或者 INSERT INTO user_v2(id,num) SELECT id,num FROM user。 连表更新:UPDATE user a, room b SET a.num=a.num+1 WHERE a.room_id=b.id。 连表删除:DELETE user FROM user,black WHERE user.id=black.id。 锁相关锁相关(作为了解,很少用): 共享锁:select id from tb_test where id = 1 lock in share mode。 排它锁:select id from tb_test where id = 1 for update。 优化时用到 强制使用某个索引:select * from table force index(idx_user) limit 2。 禁止使用某个索引:select * from table ignore index(idx_user) limit 2。 禁用缓存(在测试时去除缓存的影响):select SQL_NO_CACHE from table limit 2。 查看状态 查看字符集:SHOW VARIABLES LIKE ‘character_set%’。 查看排序规则:SHOW VARIABLES LIKE ‘collation%’。 SQL编写注意 where 语句的解析顺序是从右到左,条件尽量放 where 不要放 having。 采用延迟关联(deferred join)技术优化超多分页场景,比如 limit 10000,10,延迟关联可以避免回表。 distinct 语句非常损耗性能,可以通过 group by 来优化。 连表尽量不要超过三个表。 踩坑 如果有自增列,truncate 语句会把自增列的基数重置为 0,有些场景用自增列作为业务上的 ID 需要十分重视。 聚合函数会自动滤空,比如 a 列的类型是 int 且全部是 NULL,则 SUM(a) 返回的是 NULL 而不是 0。 MySQL 判断 null 相等不能用 “a=null”,这个结果永远为 UnKnown,where 和 having 中,UnKnown 永远被视为 false,check 约束中,UnKnown 就会视为 true 来处理。所以要用“a is null”处理。 千万大表在线修改MySQL 在表数据量很大的时候,如果修改表结构会导致锁表,业务请求被阻塞。MySQL 在 5.6 之后引入了在线更新,但是在某些情况下还是会锁表,所以一般都采用 PT 工具( Percona Toolkit)。如对表添加索引: 1234pt-online-schema-change --user='root' --host='localhost' --ask-pass --alter \"add index idx_user_id(room_id,create_time)\" D=fission_show_room_v2,t=room_favorite_info --execute 慢查询日志 有时候如果线上请求超时,应该去关注下慢查询日志,慢查询的分析很简单,先找到慢查询日志文件的位置,然后利用 mysqldumpslow 去分析。 查询慢查询日志信息可以直接通过执行 SQL 命令查看相关变量,常用的 SQL 如下: mysqldumpslow 的工具十分简单,我主要用到的参数如下: -t:限制输出的行数,我一般取前十条就够了。 -s:根据什么来排序默认是平均查询时间 at,我还经常用到 c 查询次数,因为查询次数很频繁但是时间不高也是有必要优化的,还有 t 查询时间,查看那个语句特别卡。 -v:输出详细信息。 例子:mysqldumpslow -v -s t -t 10 mysql_slow.log.2018-11-20-0500。 一些数据库性能的思考 在对公司慢查询日志做优化的时候,很多时候可能是忘了建索引,像这种问题很容易解决,加个索引就行了。但是有几种情况就不是简单加索引能解决了 业务代码循环读数据库 ​ 考虑这样一个场景,获取用户粉丝列表信息,加入分页是十个,其实像这样的 SQL 是十分简单的,通过连表查询性能也很高。 ​ 但是有时候,很多开发采用了取出一串 ID,然后循环读每个 ID 的信息,这样如果 ID 很多对数据库的压力是很大的,而且性能也很低。 统计 SQL ​ 很多时候,业务上都会有排行榜这种,发现公司有很多地方直接采用数据库做计算,在对一些大表做聚合运算的时候,经常超过五秒,这些 SQL 一般很长而且很难优化。像这种场景,如果业务允许(比如一致性要求不高或者是隔一段时间才统计的),可以专门在从库里面做统计。另外我建议还是采用 Redis 缓存来处理这种业务。 超大分页 ​ 在慢查询日志中发现了一些超大分页的慢查询如 Limit 40000,1000,因为 MySQL 的分页是在 Server 层做的,可以采用延迟关联在减少回表。但是看了相关的业务代码正常的业务逻辑是不会出现这样的请求的,所以很有可能是有恶意用户在刷接口,最好在开发的时候也对接口加上校验拦截这些恶意请求。","link":"/database/mysql/mysql%E7%B4%A2%E5%BC%95%E4%BC%98%E5%8C%96%E6%96%B9%E6%A1%88.html"},{"title":"一次数据库的死锁问题排查过程","text":"摘要某天晚上,同事正在发布,突然线上大量报警,很多是关于数据库死锁的,报警提示信息如下: 现象某天晚上,同事正在发布,突然线上大量报警,很多是关于数据库死锁的,报警提示信息如下: 123456789{\"errorCode\":\"SYSTEM_ERROR\",\"errorMsg\":\"nested exception is org.apache.ibatis.exceptions.PersistenceException: Error updating database. Cause: ERR-CODE: [TDDL-4614][ERR_EXECUTE_ON_MYSQL] Deadlock found when trying to get lock; The error occurred while setting parameters\\n### SQL: update fund_transfer_stream set gmt_modified=now(),state = ? where fund_transfer_order_no = ? and seller_id = ? and state = 'NEW' 通过报警,我们基本可以定位到发生死锁的数据库以及数据库表。先来介绍下本文案例中涉及到的数据库相关信息。 背景情况我们使用的数据库是Mysql 5.7,引擎是InnoDB,事务隔离级别是READ-COMMITED。 数据库版本查询方法: 1SELECT version(); 引擎查询方法: 1show create table fund_transfer_stream; 建表语句中会显示存储引擎信息,形如:ENGINE=InnoDB 事务隔离级别查询方法: 1select @@tx_isolation; 事务隔离级别设置方法(只对当前Session生效): 1set session transaction isolation level read committed; PS:注意,如果数据库是分库的,以上几条SQL语句需要在单库上执行,不要在逻辑库执行。 发生死锁的表结构及索引情况(隐去了部分无关字段和索引): 1234567891011121314CREATE TABLE `fund_transfer_stream` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `gmt_create` datetime NOT NULL COMMENT '创建时间', `gmt_modified` datetime NOT NULL COMMENT '修改时间', `pay_scene_name` varchar(256) NOT NULL COMMENT '支付场景名称', `pay_scene_version` varchar(256) DEFAULT NULL COMMENT '支付场景版本', `identifier` varchar(256) NOT NULL COMMENT '唯一性标识', `seller_id` varchar(64) NOT NULL COMMENT '卖家Id', `state` varchar(64) DEFAULT NULL COMMENT '状态', `fund_transfer_order_no` varchar(256) DEFAULT NULL COMMENT '资金平台返回的状态', PRIMARY KEY (`id`),UNIQUE KEY `uk_scene_identifier` (KEY `idx_seller` (`seller_id`), KEY `idx_seller_transNo` (`seller_id`,`fund_transfer_order_no`(20)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资金流水'; 该数据库共有三个索引,1个聚簇索引(主键索引),2个非聚簇索(非主键索引)引。 聚簇索引: 1PRIMARY KEY (`id`) 非聚簇索引: 123KEY `idx_seller` (`seller_id`),KEY `idx_seller_transNo` (`seller_id`,`fund_transfer_order_no`(20)) 以上两个索引,其实idx_seller_transNo已经覆盖到了idx_seller,由于历史原因,因为该表以seller_id分表,所以是先有的idx_seller,后有的idx_seller_transNo 死锁日志当数据库发生死锁时,可以通过以下命令获取死锁日志: 12show engine innodb status 发生死锁,第一时间查看死锁日志,得到死锁日志内容如下: 12345678910111213141516171819202122232425262728293031323334353637383940414243Transactions deadlock detected, dumping detailed information.2019-03-19T21:44:23.516263+08:00 5877341 [Note] InnoDB: *** (1) TRANSACTION:TRANSACTION 173268495, ACTIVE 0 sec fetching rowsmysql tables in use 1, locked 1LOCK WAIT 304 lock struct(s), heap size 41168, 6 row lock(s), undo log entries 1MySQL thread id 5877358, OS thread handle 47356539049728, query id 557970181 11.183.244.150 fin_instant_app updatingupdate `fund_transfer_stream` set `gmt_modified` = NOW(), `state` = 'PROCESSING' where ((`state` = 'NEW') AND (`seller_id` = '38921111') AND (`fund_transfer_order_no` = '99010015000805619031958363857'))2019-03-19T21:44:23.516321+08:00 5877341 [Note] InnoDB: *** (1) HOLDS THE LOCK(S):RECORD LOCKS space id 173 page no 13726 n bits 248 index idx_seller_transNo of table `xxx`.`fund_transfer_stream` trx id 173268495 lock_mode X locks rec but not gapRecord lock, heap no 168 PHYSICAL RECORD: n_fields 3; compact format; info bits 02019-03-19T21:44:23.516565+08:00 5877341 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 173 page no 12416 n bits 128 index PRIMARY of table `xxx`.`fund_transfer_stream` trx id 173268495 lock_mode X locks rec but not gap waitingRecord lock, heap no 56 PHYSICAL RECORD: n_fields 17; compact format; info bits 02019-03-19T21:44:23.517793+08:00 5877341 [Note] InnoDB: *** (2) TRANSACTION:TRANSACTION 173268500, ACTIVE 0 sec fetching rows, thread declared inside InnoDB 81mysql tables in use 1, locked 1302 lock struct(s), heap size 41168, 2 row lock(s), undo log entries 1MySQL thread id 5877341, OS thread handle 47362313119488, query id 557970189 11.131.81.107 fin_instant_app updatingupdate `fund_transfer_stream_0056` set `gmt_modified` = NOW(), `state` = 'PROCESSING' where ((`state` = 'NEW') AND (`seller_id` = '38921111') AND (`fund_transfer_order_no` = '99010015000805619031957477256'))2019-03-19T21:44:23.517855+08:00 5877341 [Note] InnoDB: *** (2) HOLDS THE LOCK(S):RECORD LOCKS space id 173 page no 12416 n bits 128 index PRIMARY of table `fin_instant_0003`.`fund_transfer_stream_0056` trx id 173268500 lock_mode X locks rec but not gapRecord lock, heap no 56 PHYSICAL RECORD: n_fields 17; compact format; info bits 02019-03-19T21:44:23.519053+08:00 5877341 [Note] InnoDB: *** (2) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 173 page no 13726 n bits 248 index idx_seller_transNo of table `fin_instant_0003`.`fund_transfer_stream_0056` trx id 173268500 lock_mode X locks rec but not gap waitingRecord lock, heap no 168 PHYSICAL RECORD: n_fields 3; compact format; info bits 02019-03-19T21:44:23.519297+08:00 5877341 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2) 简单解读一下死锁日志,可以得到以下信息: 1、导致死锁的两条SQL语句分别是: 123update `fund_transfer_stream_0056` set `gmt_modified` = NOW(), `state` = 'PROCESSING' where ((`state` = 'NEW') AND (`seller_id` = '38921111') AND (`fund_transfer_order_no` = '99010015000805619031957477256')) 和 1234update `fund_transfer_stream_0056` set `gmt_modified` = NOW(), `state` = 'PROCESSING' where ((`state` = 'NEW') AND (`seller_id` = '38921111') AND (`fund_transfer_order_no` = '99010015000805619031958363857')) 2、事务1,持有索引idx_seller_transNo的锁,在等待获取PRIMARY的锁。 3、事务2,持有PRIMARY的锁,在等待获取idx_seller_transNo的锁。 4、因事务1和事务2之间发生循环等待,故发生死锁。 5、事务1和事务2当前持有的锁均为:lock_mode X locks rec but not gap 两个事务对记录加的都是X 锁,No Gap锁,即对当行记录加锁,并为加间隙锁。 X锁:排他锁、又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。 与之对应的是S锁:共享锁,又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。 Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。 Next-Key Lock:1+2,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。 详见:https://www.cnblogs.com/zhoujinyi/p/3435982.html 、 https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html 问题排查根据我们目前已知的数据库相关信息,以及死锁的日志,我们基本可以做一些简单的判定。 首先,此次死锁一定是和Gap锁以及Next-Key Lock没有关系的。因为我们的数据库隔离级别是RC(READ-COMMITED)的,这种隔离级别是不会添加Gap锁的。前面的死锁日志也提到这一点。 然后,就要翻代码了,看看我们的代码中事务到底是怎么做的。核心代码及SQL如下: 123456@Transactional(rollbackFor = Exception.class)public int doProcessing(String sellerId, Long id, String fundTransferOrderNo) { fundTreansferStreamDAO.updateFundStreamId(sellerId, id, fundTransferOrderNo); return fundTreansferStreamDAO.updateStatus(sellerId, fundTransferOrderNo, FundTransferStreamState.PROCESSING.name());} 该代码的目的是先后修改同一条记录的两个不同字段,updateFundStreamId SQL: 1234update fund_transfer_stream set gmt_modified=now(),fund_transfer_order_no = #{fundTransferOrderNo} where id = #{id} and seller_id = #{sellerId} updateStatus SQL: 12345update fund_transfer_stream set gmt_modified=now(),state = #{state} where fund_transfer_order_no = #{fundTransferOrderNo} and seller_id = #{sellerId} and state = 'NEW' 可以看到,我们的同一个事务中执行了两条Update语句,这里分别查看下两条SQL的执行计划: updateFundStreamId执行的时候使用到的是PRIMARY索引。 updateStatus执行的时候使用到的是idx_seller_transNo索引。 通过执行计划,我们发现updateStatus其实是有两个索引可以用的,执行的时候真正使用的是idx_seller_transNo索引。这是因为MySQL查询优化器是基于代价(cost-based)的查询方式。因此,在查询过程中,最重要的一部分是根据查询的SQL语句,依据多种索引,计算查询需要的代价,从而选择最优的索引方式生成查询计划。 我们查询执行计划是在死锁发生之后做的,事后查询的执行计划和发绳死锁那一刻的索引使用情况并不一定相同的。但是,我们结合死锁日志,也可以定位到以上两条SQL语句执行的时候使用到的索引。即updateFundStreamId执行的时候使用到的是PRIMARY索引,updateStatus执行的时候使用到的是idx_seller_transNo索引。 有了以上这些已知信息,我们就可以开始排查死锁原因及其背后的原理了。通过分析死锁日志,再结合我们的代码以及数据库建表语句,我们发现主要问题出在我们的idx_seller_transNo索引上面: 1KEY `idx_seller_transNo` (`seller_id`,`fund_transfer_order_no`(20)) 索引创建语句中,我们使用了前缀索引,为了节约索引空间,提高索引效率,我们只选择了fund_transfer_order_no字段的前20位作为索引值。 因为fund_transfer_order_no只是普通索引,而非唯一性索引。又因为在一种特殊情况下,会有同一个用户的两个fund_transfer_order_no的前20位相同,这就导致两条不同的记录的索引值一样(因为seller_id 和fund_transfer_order_no(20)都相同 )。 就如本文中的例子,发生死锁的两条记录的fund_transfer_order_no字段的值:99010015000805619031958363857和99010015000805619031957477256这两个就是前20位相同的。 那么为什么fund_transfer_order_no的前20位相同会导致死锁呢? 加锁原理我们就拿本次的案例来看一下MySql数据库加锁的原理是怎样的,本文的死锁背后又发生了什么。 我们在数据库上模拟死锁场景,执行顺序如下: 事务1 事务2 执行结果 begin update fund_transfer_stream set gmt_modified=now(),fund_transfer_order_no = ‘99010015000805619031958363857’ where id = 1 and seller_id = 3111095611; 执行成功 begin update fund_transfer_stream set gmt_modified=now(),fund_transfer_order_no = ‘99010015000805619031957477256’ where id = 2 and seller_id = 3111095611; 执行成功 update fund_transfer_stream set gmt_modified = NOW(), state = ‘PROCESSING’ where ((state = ‘NEW’) AND (seller_id = ‘3111095611’) AND (fund_transfer_order_no = ‘99010015000805619031958363857’)); 阻塞 update fund_transfer_stream set gmt_modified = NOW(), state = ‘PROCESSING’ where ((state = ‘NEW’) AND (seller_id = ‘3111095611’) AND (fund_transfer_order_no = ‘99010015000805619031957477256’)); 死锁 我们知道,在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。 主键索引的叶子节点存的是整行数据。在InnoDB中,主键索引也被称为聚簇索引(clustered index) 非主键索引的叶子节点的内容是主键的值,在InnoDB中,非主键索引也被称为非聚簇索引(secondary index) 所以,本文的示例中涉及到的索引结构(索引是B+树,简化成表格了)如图: 死锁的发生与否,并不在于事务中有多少条SQL语句,死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。那么接下来就看下上面的例子中两个事务的加锁顺序是怎样的: 下图是分解图,每一条SQL执行的时候加锁情况: 结合以上两张图,我们发现了导致死锁的原因: 事务1执行update1占用PRIMARY = 1的锁 ——> 事务2执行update1 占有PRIMARY = 2的锁; 事务1执行update2占有idx_seller_transNo = (3111095611,99010015000805619031)的锁,尝试占有PRIMARY = 2锁失败(阻塞); 事务2执行update2尝试占有idx_seller_transNo = (3111095611,99010015000805619031)的锁失败(死锁); 事务在以非主键索引为where条件进行Update的时候,会先对该非主键索引加锁,然后再查询该非主键索引对应的主键索引都有哪些,再对这些主键索引进行加锁。) 解决方法至此,我们分析清楚了导致死锁的根本原理以及其背后的原理。那么这个问题解决起来就不难了。 可以从两方面入手,分别是修改索引和修改代码(包含SQL语句)。 修改索引:只要我们把前缀索引 idx_seller_transNo中fund_transfer_order_no的前缀长度修改下就可以了。比如改成50。即可避免死锁。 但是,改了idx_seller_transNo的前缀长度后,可以解决死锁的前提条件是update语句真正执行的时候,会用到fund_transfer_order_no索引。如果MySQL查询优化器在代价分析之后,决定使用索引 KEY idx_seller(seller_id),那么还是会存在死锁问题。原理和本文类似。 所以,根本解决办法就是改代码: 123* 所有update都通过主键ID进行。* 在同一个事务中,避免出现多条update语句修改同一条记录。 总结与思考在死锁发生之后的一周内,我几乎每天都会抽空研究一会,问题早早的就定位到了,修改方案也有了,但是其中原理一直没搞清楚。 前前后后做过很多中种推断及假设,又都被自己一次次推翻。最终还是要靠实践来验证自己的想法。于是我自己在本地安装了数据库,实战的做了些测试,并实时查看数据库锁情况。show engine innodb status ;可以查看锁情况。最终才搞清楚原理。 简单说几点思考: 1、遇到问题,不要猜!!!亲手复现下问题,然后再来分析。 2、不要忽略上下文!!!我刚开始就是只关注死锁日志,一直忽略了代码中的事务其实还执行了另外一条SQL语句(updateFundStreamId)。 3、理论知识再充足,关键时刻不一定想的起来!!! 4、坑都是自己埋的!!! 参考资料:MySQL 加锁处理分析 innodb 事务隔离级别 《MySql实战45讲》 MySQL中的行级锁,表级锁,页级锁 查看原文","link":"/database/mysql/%E4%B8%80%E6%AC%A1%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E6%AD%BB%E9%94%81%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E8%BF%87%E7%A8%8B.html"},{"title":"博客图片上传picgo工具github图传使用","text":"摘要对于每一个写博客的人来说,图片是至关重要。这一路经历了多次图片的烦恼,之前选择了微博个人文章那里粘贴图片的方式上传,感觉也挺方便的。但是由于新浪的图片显示问题,如果header中不设置 标签就不能异步访问图片,导致图裂,那之恶心。然而设置之后又与网站访客统计的插件冲突,使之不能统计,真是神仙打架。无赖之下使用了PicGo工具,使用后感觉真XX方便! PicGo工具下载安装配置下载 .PicGo下载 github网站提供三个版本的下载,MacOs、linux、windows覆盖市面上90%系统,还是很给力了。 我是mac用户,直接使用brew cask来安装PicGo: brew cask install picgo,简直方便到爆。 配置 PicGo配置(使用github图传,免费方便,同时配合github.io博客真是方便) 选上必填的就ok,一开始不知道token的设置,附赠token获取方法 图片上传相关的设置 链接格式:选择适合自己的,一般用户md文件中,选第一个,然后就可以疯狂使用了。 使用github图传,获取token在github->setting->developer settings 选择generate new token 勾选好之后生成就好了 使用 PicGo使用,简直方便 1).默认网页上直接右键复制图片 2).点击等待中的图片,开始上传 3).上传完之后有个提示,同时粘贴板也会自动粘贴上 4).直接粘贴到想要的地方 或者也可以直接截图,然后点击图片里的图片上传,很方便 PicGo上传动图gif 如果直接复制网页上的动图,去上传的话是截取的某帧,是静图。应该下载到本地,然后在拖进去上传就可以了。","link":"/theme/%E5%8D%9A%E5%AE%A2%E5%9B%BE%E7%89%87%E4%B8%8A%E4%BC%A0picgo%E5%B7%A5%E5%85%B7github%E5%9B%BE%E4%BC%A0%E4%BD%BF%E7%94%A8.html"},{"title":"阿里一年的成长经历","text":"摘要任何工作一定对个人都是有提升的,但是不会总结的人,在每个项目/需求中成长的东西都是散的,久而久之就忘了。通过充分的总结之后,犯过的错误我们不会二次再犯,理清楚的业务的来龙去脉铭记在心,对自己是一种提升,分享给别人对别人也是很大的帮助。失败者失败的原因各有不同,成功者的做事方式总是相似的,从宏观角度去看,我认为总结就是成功者之所以能成功,很重要一个原因。 应当如何面对线上的异常/故障看起来毫无意义的一个问题,碰到线上异常/故障如何面对,排查解决了不就好了,但是这真的只是第一层 最近在想“消防”这个词语很有意思,它其实是两层意思: “消”是消除问题 “防”是防止问题 即“消防”这个词语表达的意思应该是先消除问题再防止相同的问题再次发生。其实线上的异常/故障也是同样的道理,我们应当先及时止血,把问题处理掉,然后深挖问题,探究根因,举几个例子: 假设是某段代码的空指针异常导致的,那么是否考虑加强Code Review,或者使用findbugs插件去自动扫描代码中可能的异常? 假设是线上某个配置修改导致的,那么是否今后变更的修改必须有人双重检查一遍才可以修改? 假设是本地内存中某些值因为系统重启丢失导致的,那么是否引入定时任务,定时把值写入本地内存中? 假设是某段代码逻辑没测试到导致的,那么是否可以反思总结为什么这段逻辑没有测试到,未来的测试应该如何改进? 根据我过往的经验,太多公司、太多团队处理线上的问题仅仅满足于把问题处理完就完事,忽略了对问题的复盘,这对团队/对公司的发展都是不利的。 什么是真正的技术能力之前加了几个技术微信群,看到很多技术朋友在兴高采烈地讨论各种源码,spring源码我彻底撸了一遍、最近深入学习了dubbo底层实现方式,当然曾经的我也是这样的,记得学习volatile的时候一直挖到了volatile在硬件层面上的实现方式,但是这真的说明技术能力强吗?从今天的思考去看这个问题,我认为这更多反应的是一个人的学习能力、钻研能力以及对技术的热情,除此之外再体现不出太多其他东西了。 这个话题,可能是这一年思考的最多个的一个点,钻研是好事,但是实际上大多时候的深入钻研并不在实际工作中有用,且研究得越深,忘得越快,因为研究得越深,那么这个技术点关联的技术点就越多,边边角角的忘了,核心的东西不容易串起来。那么什么是真正的技术能力,我画一张图概括一下: 技术能力=解决问题的能力(解决当下问题+解决长远问题) 简而言之,技术能力 = 解决问题的能力,那么同样都在解决问题,大家之间的技术高低又有什么区分呢?我认为有以下几个层次: 第一层级,解决当下问题 第二层级,以优雅且可复用的方式解决当下问题 第三层级,解决的问题不仅仅能满足当下,还能满足未来一段时间 其实从这个角度上来看,不同的技术能力,在工作过程中区分度是很明显的: 写的代码是否存在异常风险,多线程运行下是否存在线程安全问题,某段代码是否会导致内存泄露 写的代码是否优雅可复用,设计的框架是否足够符合开闭原则,代码结构层次是否清晰明了 针对特定的场景,技术选型、库表结构设计是否足够合理,今天你设计的框架是只能用一年,还是未来三年五年都可以持续使用 来了一个大的需求,就比如做一个App的会员体系功能好了,是否可以在充分分析需求后,精确将需求划分为几个特定的子模块并梳理清楚模块之间的关系 越厉害的人,在代码设计与开发过程中,越能看到想到一些别人看不到想不到的问题,这叫做高屋建瓴;当代码运行出现问题的时候,有人1小时排查出问题,有人1分钟发现问题,这叫做举重若轻。 因此我认为解决问题的能力才是技术能力的真正体现,这一年对技术的探究我也从研究源码更多的转变去学习设计模式、去学习分布式环境下各种NoSql的选型对比、去学习使用Lambda让代码更简洁,往真正在实际工作中解决问题的方向去努力。 另外,抛开这个点,这两天我在思考,还有一个体现技术能力的点,就是学习能力。现实中的全栈是很少的,互联网这个行业的程序员的方向通常有几类: 服务端 前端 移动端 AI 嵌入式 大数据 在同一类中,基础知识、基本概念、思维方向是一致的,更多可能差异在开发工具、语言上,我精通Java,但是如果明天有一个需求,使用nodejs、scala、go更好,那么是否可以快速学习、快速上手?甚至明天有一个需求需要写前端代码,是否可以快速开发、无bug上线? 所以,解决问题的能力 + 学习能力,是我认为真正的技术能力,不过说到底,学习能力某种程度上也只是为了解决问题而已。 不要造轮子曾几何时,当我们看着github上这么多优秀的源代码的时候,默默立誓,这辈子我一定要写出一个牛逼的框架,开源在网上。 曾几何时,公司招聘的时候,技术负责人激情满满地介绍着公司内部自研了多少系统并在线上投入使用。 很多对技术有追求的朋友,进入一家公司可能时时刻刻在寻找机会去做一些自己造轮子的事情,但是就如同前面所说的,衡量真正好技术的标准就是能否实实在在地解决问题,自己造轮子风险高、周期长,且需要长时间的验证、排坑才能达到比较好的效果。 随便举几个例子,在互联网发展的今天: 数据库连接池有dbcp、c3p0、druid 本地缓存有ehcache、要用中心缓存有redis、tail 服务化有dubbo、跨语言可以用thrift 分布式任务调度可以考虑schedulex 搜索可以选es、solr 更高级一点图片存储可以用七牛、im可以用融云/环信、音视频这块声网做得比较成熟,所有这些都提供了各个开发版本的sdk,接入简单 只要你有的技术方面的需求,绝大多数业界已经有了成熟的解决方案了,根本不需要去专门自己搞一套。因此我认为轻易一定不要造轮子,如果一定要造轮子,那么请想清楚下面几个问题: 你要做的事情是否当前已经有了类似解决方案? 如果有,那么你自己做的这一套东西和类似解决方案的差异点在哪里?假设不用你这套,基于已有的解决方案稍加改造是否就能达到目的? 如果没有,那么为什么之前没有?是你们公司这种场景是独一无二的?还是这种场景对应的解决方案根本就是不可行的所以之前没人去搞? 如果想清楚了这些问题,那么就去干吧。 去提升看问题的高度过去有太多人在我的公众号或者博客下反馈了一个问题:在这个公司,整天做着增删改查的工作,对自己一点都没有提高。 对于这种看法,说难听点就是四个字—-目光短浅。我们看:如果以普通的视角去看,那么一颗树那也就只是一棵树而已,但是如果跳脱出目前的视角,站在更高的角度去看,它其实是森林的一部分。你的主管并不是因为他是你的主管所以他就应该你比更高瞻远瞩,而是因为他看问题的高度比你更高、想得更远、做得更深,所以才成为了你的主管。 把这个问题说得实际点: 假设今天你负责的是一个系统,那么你仅仅是把这个系统的基本原理搞懂了?还是可以把上下游有几个系统、每个系统之间如何调用、依赖方式都理顺? 假设今天你负责的是一块业务,那么你仅仅把自己负责的功能点弄清楚了?还是你可以从最上游开始,到你负责的系统,再到最下游,都思考得非常透彻? 今天与其在抱怨没有机会、抱怨公司对自己能力没有提升,为什么不去思考机会为什么降临在别人头上不降临在你头上?为什么别人可以从小公司写着一样的增删改查走向BAT而你年复一年还在小公司写着增删改查?当你真正能转变自己的思维模式,跳脱出现在的圈子往更高一个层次去看问题、去提升自己,我相信总会有发光发热的一天的。 同样在阿里巴巴,马老师思考自然、思考环保、思考人类的发展,你的主管思考团队未来的方向和打法,我们在思考如何把某个客户需求完整落地,这就是高度,你未必能想到马老师想的,但是你对标层级高一点的人,一步一步尝试往他们的高度去靠。 总而言之:眼界决定高度,多看、多想、多保持好奇心、多问几个为什么,久而久之自然就迈上了一个新的台阶。 学会总结需求、项目的复盘是非常重要的一部分内容,然而我之前见过的太多团队、太多Leader,只顾着一个迭代接着一个迭代,一个版本接着一个版本,只满足于把需求做好,而忽略了总结的重要性。 我认为大到项目、小到需求,如果在完成之后缺乏总结那么某种程度上来说是失败的,可以总结的点非常多: 通过这个项目/需求,是否吃透了某一块业务,搞懂了来龙去脉 通过这个项目/需求,是否充分理解了公司某个技术框架/基础组件的用法 在整个项目的设计上,有哪些做的不好的地方 在整个项目的开发(针对程序员而言),是否踩了坑,犯了低级的错误 在整个项目的进度把控上、人员安排上、上下游协调上,是否存在不足之处 经历了某次大促的值班,是否对可以熟练使用公司的监控工具,遇到突发事件,是否快速有效地进行了解决 任何工作一定对个人都是有提升的,但是不会总结的人,在每个项目/需求中成长的东西都是散的,久而久之就忘了。通过充分的总结之后,犯过的错误我们不会二次再犯,理清楚的业务的来龙去脉铭记在心,对自己是一种提升,分享给别人对别人也是很大的帮助。 失败者失败的原因各有不同,成功者的做事方式总是相似的,从宏观角度去看,我认为总结就是成功者之所以能成功,很重要一个原因。 参考资料","link":"/think/%E9%98%BF%E9%87%8C%E4%B8%80%E5%B9%B4%E7%9A%84%E6%88%90%E9%95%BF%E7%BB%8F%E5%8E%86.html"},{"title":"mysql数据库索引解析","text":"摘要看了很多关于索引的博客,讲的大同小异。但是始终没有让我明白关于索引的一些概念,如B-Tree索引,Hash索引,唯一索引….或许有很多人和我一样,没搞清楚概念就开始研究B-Tree,B+Tree等结构,导致在面试的时候答非所问! 索引是什么?索引是帮助MySQL高效获取数据的数据结构。 索引能干什么?索引非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。 索引能够轻易将查询性能提高好几个数量级,总的来说就是可以明显的提高查询效率。 索引的分类? 从存储结构上来划分:BTree索引(B-Tree或B+Tree索引),Hash索引,full-index全文索引,R-Tree索引。这里所描述的是索引存储时保存的形式, 从应用层次来分:普通索引,唯一索引,复合索引 根据中数据的物理顺序与键值的逻辑(索引)顺序关系:聚集索引,非聚集索引。 平时讲的索引类型一般是指在应用层次的划分。就像手机分类:安卓手机,IOS手机 与 华为手机,苹果手机,OPPO手机一样。 普通索引****:即一个索引只包含单个列,一个表可以有多个单列索引 唯一索引:索引列的值必须唯一,但允许有空值 复合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并 聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B-Tree索引(技术上来说是B+Tree)和数据行。 非聚簇索引:不是聚簇索引,就是非聚簇索引 索引的底层实现mysql默认存储引擎innodb只显式支持B-Tree( 从技术上来说是B+Tree)索引,对于频繁访问的表,innodb会透明建立自适应hash索引,即在B树索引基础上建立hash索引,可以显著提高查找效率,对于客户端是透明的,不可控制的,隐式的。 不谈存储引擎,只讨论实现(抽象) Hash索引基于哈希表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),并且Hash索引将所有的哈希码存储在索引中,同时在索引表中保存指向每个数据行的指针。 B-Tree索引(MySQL使用B+Tree)B-Tree能加快数据的访问速度,因为存储引擎不再需要进行全表扫描来获取数据,数据分布在各个节点之中。 B+Tree索引 是B-Tree的改进版本,同时也是数据库索引索引所采用的存储结构。数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都指向相邻的叶子节点的地址。相比B-Tree来说,进行范围查找时只需要查找两个节点,进行遍历即可。而B-Tree需要获取所有节点,相比之下B+Tree效率更高。 结合存储引擎来讨论(一般默认使用B+Tree) 案例:假设有一张学生表,id为主键 id name birthday 1 Tom 1996-01-01 2 Jann 1996-01-04 3 Ray 1996-01-08 4 Michael 1996-01-10 5 Jack 1996-01-13 6 Steven 1996-01-23 7 Lily 1996-01-25 在MyISAM引擎中的实现(二级索引也是这样实现的) 在InnoDB中的实现 为什么索引结构默认使用B+Tree,而不是Hash,二叉树,红黑树?B+tree:因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出),指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低; Hash:虽然可以快速定位,但是没有顺序,IO复杂度高。 二叉树:树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高。 红黑树:树的高度随着数据量增加而增加,IO代价高。 红黑树: 每个节点或者是黑色,或者是红色。 根节点是黑色。 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!] 如果一个节点是红色的,则它的子节点必须是黑色的。 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。 为什么官方建议使用自增长主键作为索引?结合B+Tree的特点,自增主键是连续的,在插入过程中尽量减少页分裂,即使要进行页分裂,也只会分裂很少一部分。并且能减少数据的移动,每次插入都是插入到最后。总之就是减少分裂和移动的频率。 插入连续的数据: 插入非连续的数据 简单总结下 MySQL使用B+Tree作为索引数据结构。 B+Tree在新增数据时,会根据索引指定列的值对旧的B+Tree做调整。 从物理存储结构上说,B-Tree和B+Tree都以页(4K)来划分节点的大小,但是由于B+Tree中中间节点不存储数据,因此B+Tree能够在同样大小的节点中,存储更多的key,提高查找效率。 影响MySQL查找性能的主要还是磁盘IO次数,大部分是磁头移动到指定磁道的时间花费。 MyISAM存储引擎下索引和数据存储是分离的,InnoDB索引和数据存储在一起。 InnoDB存储引擎下索引的实现,(辅助索引)全部是依赖于主索引建立的(辅助索引中叶子结点存储的并不是数据的地址,还是主索引的值,因此,所有依赖于辅助索引的都是先根据辅助索引查到主索引,再根据主索引查数据的地址)。 由于InnoDB索引的特性,因此如果主索引不是自增的(id作主键),那么每次插入新的数据,都很可能对B+Tree的主索引进行重整,影响性能。因此,尽量以自增id作为InnoDB的主索引。 InnoDB一棵B+树能存多少行数据?为什么要用B+树?而不是其他树?InnoDB一棵B+树可以存放多少行数据?这个问题的简单回答是:约2千万。为什么是这么多呢?因为这是可以算出来的,要搞清楚这个问题,我们先从InnoDB索引数据结构、数据组织方式说起。 我们都知道计算机在存储数据的时候,有最小存储单元,这就好比我们今天进行现金的流通最小单位是一毛。在计算机中磁盘存储数据最小单元是扇区,一个扇区的大小是512字节,而文件系统(例如XFS/EXT4)他的最小单元是块,一个块的大小是4k,而对于我们的InnoDB存储引擎也有自己的最小储存单元——页(Page),一个页的大小是16K。 innodb的所有数据文件(后缀为ibd的文件),他的大小始终都是16384(16k)的整数倍。 磁盘扇区、文件系统、InnoDB存储引擎都有各自的最小存储单元。 在MySQL中我们的InnoDB页的大小默认是16k,当然也可以通过参数设置: 12345678mysql> show variables like 'innodb_page_size';+------------------+-------+| Variable_name| Value|+------------------+-------+| innodb_page_size | 16384|+------------------+-------+1 row in set(0.00sec) 数据表中的数据都是存储在页中的,所以一个页中能存储多少行数据呢?假设一行数据的大小是1k,那么一个页可以存放16行这样的数据。 如果数据库只按这样的方式存储,那么如何查找数据就成为一个问题,因为我们不知道要查找的数据存在哪个页中,也不可能把所有的页遍历一遍,那样太慢了。所以人们想了一个办法,用B+树的方式组织这些数据。如图所示: 我们先将数据记录按主键进行排序,分别存放在不同的页中(为了便于理解我们这里一个页中只存放3条记录,实际情况可以存放很多),除了存放数据的页以外,还有存放键值+指针的页,如图中page number=3的页,该页存放键值和指向数据页的指针,这样的页由N个键值+指针组成。当然它也是排好序的。这样的数据组织形式,我们称为索引组织表。现在来看下,要查找一条数据,怎么查? 如select * from user where id=5; 这里id是主键,我们通过这棵B+树来查找,首先找到根页,你怎么知道user表的根页在哪呢?其实每张表的根页位置在表空间文件中是固定的,即page number=3的页(这点我们下文还会进一步证明),找到根页后通过二分查找法,定位到id=5的数据应该在指针P5指向的页中,那么进一步去page number=5的页中查找,同样通过二分查询法即可找到id=5的记录: | 5 | zhao2 | 27 | 现在我们清楚了InnoDB中主键索引B+树是如何组织数据、查询数据的,我们总结一下: 1、InnoDB存储引擎的最小存储单元是页,页可以用于存放数据也可以用于存放键值+指针,在B+树中叶子节点存放数据,非叶子节点存放键值+指针。 2、索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中,进而在去数据页中查找到需要的数据; 那么回到我们开始的问题,通常一棵B+树可以存放多少行数据?这里我们先假设B+树高为2,即存在一个根节点和若干个叶子节点,那么这棵B+树的存放总记录数为:根节点指针数*单个叶子节点记录行数。 上文我们已经说明单个叶子节点(页)中的记录数=16K/1K=16。(这里假设一行记录的数据大小为1k,实际上现在很多互联网业务数据记录大小通常就是1K左右)。 那么现在我们需要计算出非叶子节点能存放多少指针? 其实这也很好算,我们假设主键ID为bigint类型,长度为8字节,而指针大小在InnoDB源码中设置为6字节,这样一共14字节,我们一个页中能存放多少这样的单元,其实就代表有多少指针,即16384/14=1170。那么可以算出一棵高度为2的B+树,能存放1170*16=18720条这样的数据记录。 根据同样的原理我们可以算出一个高度为3的B+树可以存放:1170*1170*16=21902400条这样的记录。 所以在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次IO操作即可查找到数据。 怎么得到InnoDB主键索引B+树的高度?上面我们通过推断得出B+树的高度通常是1-3,下面我们从另外一个侧面证明这个结论。在InnoDB的表空间文件中,约定page number为3的代表主键索引的根页,而在根页偏移量为64的地方存放了该B+树的page level。如果page level为1,树高为2,page level为2,则树高为3。即B+树的高度=page level+1;下面我们将从实际环境中尝试找到这个page level。 在实际操作之前,你可以通过InnoDB元数据表确认主键索引根页的page number为3,你也可以从《InnoDB存储引擎》这本书中得到确认。 1234567SELECTb.name, a.name, index_id, type, a.space, a.PAGE_NOFROMinformation_schema.INNODB_SYS_INDEXES a,information_schema.INNODB_SYS_TABLES bWHEREa.table_id = b.table_id AND a.space <> 0; 执行结果: 可以看出数据库dbt3下的customer表、lineitem表主键索引根页的page number均为3,而其他的二级索引page number为4。关于二级索引与主键索引的区别请参考MySQL相关书籍,本文不在此介绍。 下面我们对数据库表空间文件做想相关的解析: 因为主键索引B+树的根页在整个表空间文件中的第3个页开始,所以可以算出它在文件中的偏移量:16384*3=49152(16384为页大小)。 另外根据《InnoDB存储引擎》中描述在根页的64偏移量位置前2个字节,保存了page level的值,因此我们想要的page level的值在整个文件中的偏移量为:16384*3+64=49152+64=49216,前2个字节中。 接下来我们用hexdump工具,查看表空间文件指定偏移量上的数据: linetem表的page level为2,B+树高度为page level+1=3;region表的page level为0,B+树高度为page level+1=1;customer表的page level为2,B+树高度为page level+1=3; 这三张表的数据量如下: 小结lineitem表的数据行数为600多万,B+树高度为3,customer表数据行数只有15万,B+树高度也为3。可以看出尽管数据量差异较大,这两个表树的高度都是3,换句话说这两个表通过索引查询效率并没有太大差异,因为都只需要做3次IO。那么如果有一张表行数是一千万,那么他的B+树高度依旧是3,查询效率仍然不会相差太大。 region表只有5行数据,当然他的B+树高度为1。 最后回顾一道面试题有一道MySQL的面试题,为什么MySQL的索引要使用B+树而不是其它树形结构?比如B树? 现在这个问题的复杂版本可以参考本文; 他的简单版本回答是: 因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出),指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低; 总结本文从一个问题出发,逐步介绍了InnoDB索引组织表的原理、查询方式,并结合已有知识,回答该问题,结合实践来证明。当然为了表述简单易懂,文中忽略了一些细枝末节,比如一个页中不可能所有空间都用于存放数据,它还会存放一些少量的其他字段比如page level,index number等等,另外还有页的填充因子也导致一个页不可能全部用于保存数据。关于二级索引数据存取方式可以参考MySQL相关书籍,他的要点是结合主键索引进行回表查询。参考参考","link":"/database/mysql/mysql%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B4%A2%E5%BC%95%E8%A7%A3%E6%9E%90.html"},{"title":"java注解Annotation说明实例","text":"摘要Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。 什么是注解?对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。 Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。 注解的用处 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等 跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2 依赖注入,未来java 开发,将大量注解配置,具有很大用处; 在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。 注解原理注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。 元注解java.lang.annotation 提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要使用到元注解): @Documented – 注解是否将包含在JavaDoc中 @Retention – 什么时候使用该注解 @Target – 注解用于什么地方 @Inherited – 是否允许子类继承该注解 @Retention 定义该注解的生命周期 ● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。 ● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式 ● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。 @Target 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括 ● ElementType.CONSTRUCTOR: 用于描述构造器 ● ElementType.FIELD: 成员变量、对象、属性(包括enum实例) ● ElementType.LOCAL_VARIABLE: 用于描述局部变量 ● ElementType.METHOD: 用于描述方法 ● ElementType.PACKAGE: 用于描述包 ● ElementType.PARAMETER: 用于描述参数 ● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明 @Documented 一个简单的Annotations 标记注解,表示是否将注解信息添加在java 文档中。 @Inherited 定义该注释和子类的关系@Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited 修饰的annotation 类型被用于一个class,则这个annotation 将被用于该class 的子类。 常见标准的Annotation Override java.lang.Override 是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java 编译器将以一个编译错误来警示 Deprecated Deprecated 也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated 修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。 SuppressWarnings SuppressWarning 不是一个标记类型注解。它有一个类型为String[] 的成员,这个成员的值为被禁止的警告名。对于javac 编译器来讲,被-Xlint 选项有效的警告名也同样对@SuppressWarings 有效,同时编译器忽略掉无法识别的警告名。@SuppressWarnings(“unchecked”) 自定义注解自定义注解类编写的一些规则: Annotation 型定义为@interface, 所有的Annotation 会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口. 参数成员只能用public 或默认(default) 这两个访问权修饰 参数成员只能用基本类型byte、short、char、int、long、float、double、boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation 对象,因为你除此之外没有别的获取注解对象的方法 注解也可以没有定义成员,,不过这样注解就没啥用了PS:自定义注解需要使用到元注解 实例FruitName.java 123456789101112131415import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.RetentionPolicy.RUNTIME;/** * 水果名称注解 */@Target(FIELD)@Retention(RUNTIME)@Documentedpublic @interface FruitName { String value() default \"\";} FruitColor.java 123456789101112131415161718192021222324import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.RetentionPolicy.RUNTIME;/** * 水果颜色注解 */@Target(FIELD)@Retention(RUNTIME)@Documentedpublic @interface FruitColor { /** * 颜色枚举 */ public enum Color{ BLUE,RED,GREEN}; /** * 颜色属性 */ Color fruitColor() default Color.GREEN;} FruitProvider.java 12345678910111213141516171819202122232425262728import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.RetentionPolicy.RUNTIME;/** * 水果供应者注解 */@Target(FIELD)@Retention(RUNTIME)@Documentedpublic @interface FruitProvider { /** * 供应商编号 */ public int id() default -1; /** * 供应商名称 */ public String name() default \"\"; /** * 供应商地址 */ public String address() default \"\";} FruitInfoUtil.java 1234567891011121314151617181920212223242526272829303132import java.lang.reflect.Field;/** * 注解处理器 */public class FruitInfoUtil { public static void getFruitInfo(Class<?> clazz){ String strFruitName=\" 水果名称:\"; String strFruitColor=\" 水果颜色:\"; String strFruitProvicer=\"供应商信息:\"; Field[] fields = clazz.getDeclaredFields(); for(Field field :fields){ if(field.isAnnotationPresent(FruitName.class)){ FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class); strFruitName=strFruitName+fruitName.value(); System.out.println(strFruitName); } else if(field.isAnnotationPresent(FruitColor.class)){ FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class); strFruitColor=strFruitColor+fruitColor.fruitColor().toString(); System.out.println(strFruitColor); } else if(field.isAnnotationPresent(FruitProvider.class)){ FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class); strFruitProvicer=\" 供应商编号:\"+fruitProvider.id()+\" 供应商名称:\"+fruitProvider.name()+\" 供应商地址:\"+fruitProvider.address(); System.out.println(strFruitProvicer); } } }} Apple.java 1234567891011121314151617181920212223242526272829303132333435363738394041import test.FruitColor.Color;/** * 注解使用 */public class Apple { @FruitName(\"Apple\") private String appleName; @FruitColor(fruitColor=Color.RED) private String appleColor; @FruitProvider(id=1,name=\"陕西红富士集团\",address=\"陕西省西安市延安路89号红富士大厦\") private String appleProvider; public void setAppleColor(String appleColor) { this.appleColor = appleColor; } public String getAppleColor() { return appleColor; } public void setAppleName(String appleName) { this.appleName = appleName; } public String getAppleName() { return appleName; } public void setAppleProvider(String appleProvider) { this.appleProvider = appleProvider; } public String getAppleProvider() { return appleProvider; } public void displayName(){ System.out.println(\"水果的名字是:苹果\"); }} FruitRun.java 12345678/** * 输出结果 */public class FruitRun { public static void main(String[] args) { FruitInfoUtil.getFruitInfo(Apple.class); }} 运行结果: 123水果名称:Apple水果颜色:RED供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦 参考资料","link":"/java/basic/java%E6%B3%A8%E8%A7%A3Annotation%E8%AF%B4%E6%98%8E%E5%AE%9E%E4%BE%8B.html"},{"title":"elasticsearch6.x倒排索引和分词","text":"摘要倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key。 倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key。 倒排索引 正排索引:文档id到单词的关联关系 倒排索引:单词到文档id的关联关系 示例:对以下三个文档去除停用词后构造倒排索引 倒排索引-查询过程查询包含“搜索引擎”的文档 通过倒排索引获得“搜索引擎”对应的文档id列表,有1,3 通过正排索引查询1和3的完整内容 返回最终结果 倒排索引-组成 单词词典(Term Dictionary) 倒排列表(Posting List) 单词词典(Term Dictionary)单词词典的实现一般用B+树,B+树构造的可视化过程网址: B+ Tree Visualization 关于B树和B+树 维基百科-B树 维基百科-B+树 B树和B+树的插入、删除图文详解 倒排列表(Posting List) 倒排列表记录了单词对应的文档集合,有倒排索引项(Posting)组成 倒排索引项主要包含如下信息: 文档id用于获取原始信息 单词频率(TF,Term Frequency),记录该单词在该文档中出现的次数,用于后续相关性算分 位置(Posting),记录单词在文档中的分词位置(多个),用于做词语搜索(Phrase Query) 偏移(Offset),记录单词在文档的开始和结束位置,用于高亮显示 B+树内部结点存索引,叶子结点存数据,这里的 单词词典就是B+树索引,倒排列表就是数据,整合在一起后如下所示 ES存储的是一个JSON格式的文档,其中包含多个字段,每个字段会有自己的倒排索引 分词分词是将文本转换成一系列单词(Term or Token)的过程,也可以叫文本分析,在ES里面称为Analysis 分词器分词器是ES中专门处理分词的组件,英文为Analyzer,它的组成如下: Character Filters:针对原始文本进行处理,比如去除html标签 Tokenizer:将原始文本按照一定规则切分为单词 Token Filters:针对Tokenizer处理的单词进行再加工,比如转小写、删除或增新等处理 分词器调用顺序 Analyze APIES提供了一个可以测试分词的API接口,方便验证分词效果,endpoint是_analyze 可以直接指定analyzer进行测试 可以直接指定索引中的字段进行测试 1234567891011POST test_index/doc{ \"username\": \"whirly\", \"age\":22}POST test_index/_analyze{ \"field\": \"username\", \"text\": [\"hello world\"]} 可以自定义分词器进行测试 123456POST _analyze{ \"tokenizer\": \"standard\", \"filter\": [\"lowercase\"], \"text\": [\"Hello World\"]} 预定义的分词器ES自带的分词器有如下: Standard Analyzer 默认分词器 按词切分,支持多语言 小写处理 Simple Analyzer 按照非字母切分 小写处理 Whitespace Analyzer 空白字符作为分隔符 Stop Analyzer 相比Simple Analyzer多了去除请用词处理 停用词指语气助词等修饰性词语,如the, an, 的, 这等 Keyword Analyzer 不分词,直接将输入作为一个单词输出 Pattern Analyzer 通过正则表达式自定义分隔符 默认是\\W+,即非字词的符号作为分隔符 Language Analyzer 提供了30+种常见语言的分词器 示例:停用词分词器 12345POST _analyze{ \"analyzer\": \"stop\", \"text\": [\"The 2 QUICK Brown Foxes jumped over the lazy dog's bone.\"]} 结果 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667{ \"tokens\": [ { \"token\": \"quick\", \"start_offset\": 6, \"end_offset\": 11, \"type\": \"word\", \"position\": 1 }, { \"token\": \"brown\", \"start_offset\": 12, \"end_offset\": 17, \"type\": \"word\", \"position\": 2 }, { \"token\": \"foxes\", \"start_offset\": 18, \"end_offset\": 23, \"type\": \"word\", \"position\": 3 }, { \"token\": \"jumped\", \"start_offset\": 24, \"end_offset\": 30, \"type\": \"word\", \"position\": 4 }, { \"token\": \"over\", \"start_offset\": 31, \"end_offset\": 35, \"type\": \"word\", \"position\": 5 }, { \"token\": \"lazy\", \"start_offset\": 40, \"end_offset\": 44, \"type\": \"word\", \"position\": 7 }, { \"token\": \"dog\", \"start_offset\": 45, \"end_offset\": 48, \"type\": \"word\", \"position\": 8 }, { \"token\": \"s\", \"start_offset\": 49, \"end_offset\": 50, \"type\": \"word\", \"position\": 9 }, { \"token\": \"bone\", \"start_offset\": 51, \"end_offset\": 55, \"type\": \"word\", \"position\": 10 } ]} 中文分词 难点 中文分词指的是将一个汉字序列切分为一个一个的单独的词。在英文中,单词之间以空格作为自然分界词,汉语中词没有一个形式上的分界符 上下文不同,分词结果迥异,比如交叉歧义问题 常见分词系统 IK:实现中英文单词的切分,可自定义词库,支持热更新分词词典 jieba:支持分词和词性标注,支持繁体分词,自定义词典,并行分词等 Hanlp:由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用 THUAC:中文分词和词性标注 安装ik中文分词插件12345# 在Elasticsearch安装目录下执行命令,然后重启esbin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.3.0/elasticsearch-analysis-ik-6.3.0.zip# 如果由于网络慢,安装失败,可以先下载好zip压缩包,将下面命令改为实际的路径,执行,然后重启esbin/elasticsearch-plugin install file:///path/to/elasticsearch-analysis-ik-6.3.0.zip ik测试 - ik_smart 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667POST _analyze{ \"analyzer\": \"ik_smart\", \"text\": [\"公安部:各地校车将享最高路权\"]}# 结果{ \"tokens\": [ { \"token\": \"公安部\", \"start_offset\": 0, \"end_offset\": 3, \"type\": \"CN_WORD\", \"position\": 0 }, { \"token\": \"各地\", \"start_offset\": 4, \"end_offset\": 6, \"type\": \"CN_WORD\", \"position\": 1 }, { \"token\": \"校车\", \"start_offset\": 6, \"end_offset\": 8, \"type\": \"CN_WORD\", \"position\": 2 }, { \"token\": \"将\", \"start_offset\": 8, \"end_offset\": 9, \"type\": \"CN_CHAR\", \"position\": 3 }, { \"token\": \"享\", \"start_offset\": 9, \"end_offset\": 10, \"type\": \"CN_CHAR\", \"position\": 4 }, { \"token\": \"最高\", \"start_offset\": 10, \"end_offset\": 12, \"type\": \"CN_WORD\", \"position\": 5 }, { \"token\": \"路\", \"start_offset\": 12, \"end_offset\": 13, \"type\": \"CN_CHAR\", \"position\": 6 }, { \"token\": \"权\", \"start_offset\": 13, \"end_offset\": 14, \"type\": \"CN_CHAR\", \"position\": 7 } ]} ik测试 - ik_max_word 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081POST _analyze{ \"analyzer\": \"ik_max_word\", \"text\": [\"公安部:各地校车将享最高路权\"]}# 结果{ \"tokens\": [ { \"token\": \"公安部\", \"start_offset\": 0, \"end_offset\": 3, \"type\": \"CN_WORD\", \"position\": 0 }, { \"token\": \"公安\", \"start_offset\": 0, \"end_offset\": 2, \"type\": \"CN_WORD\", \"position\": 1 }, { \"token\": \"部\", \"start_offset\": 2, \"end_offset\": 3, \"type\": \"CN_CHAR\", \"position\": 2 }, { \"token\": \"各地\", \"start_offset\": 4, \"end_offset\": 6, \"type\": \"CN_WORD\", \"position\": 3 }, { \"token\": \"校车\", \"start_offset\": 6, \"end_offset\": 8, \"type\": \"CN_WORD\", \"position\": 4 }, { \"token\": \"将\", \"start_offset\": 8, \"end_offset\": 9, \"type\": \"CN_CHAR\", \"position\": 5 }, { \"token\": \"享\", \"start_offset\": 9, \"end_offset\": 10, \"type\": \"CN_CHAR\", \"position\": 6 }, { \"token\": \"最高\", \"start_offset\": 10, \"end_offset\": 12, \"type\": \"CN_WORD\", \"position\": 7 }, { \"token\": \"路\", \"start_offset\": 12, \"end_offset\": 13, \"type\": \"CN_CHAR\", \"position\": 8 }, { \"token\": \"权\", \"start_offset\": 13, \"end_offset\": 14, \"type\": \"CN_CHAR\", \"position\": 9 } ]} ik两种分词模式ik_max_word 和 ik_smart 什么区别? ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合; ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。 自定义分词当自带的分词无法满足需求时,可以自定义分词,通过定义Character Filters、Tokenizer和Token Filters实现 Character Filters 在Tokenizer之前对原始文本进行处理,比如增加、删除或替换字符等 自带的如下: HTML Strip Character Filter:去除HTML标签和转换HTML实体 Mapping Character Filter:进行字符替换操作 Pattern Replace Character Filter:进行正则匹配替换 会影响后续tokenizer解析的position和offset信息 Character Filters测试1234567891011121314151617181920212223POST _analyze{ \"tokenizer\": \"keyword\", \"char_filter\": [\"html_strip\"], \"text\": [\"<p>I&apos;m so <b>happy</b>!</p>\"]}# 结果{ \"tokens\": [ { \"token\": \"\"\"I'm so happy!\"\"\", \"start_offset\": 0, \"end_offset\": 32, \"type\": \"word\", \"position\": 0 } ]} Tokenizers 将原始文本按照一定规则切分为单词(term or token) 自带的如下: standard 按照单词进行分割 letter 按照非字符类进行分割 whitespace 按照空格进行分割 UAX URL Email 按照standard进行分割,但不会分割邮箱和URL Ngram 和 Edge NGram 连词分割 Path Hierarchy 按照文件路径进行分割 Tokenizers 测试1234567891011121314151617181920212223242526272829303132POST _analyze{ \"tokenizer\": \"path_hierarchy\", \"text\": [\"/path/to/file\"]}# 结果{ \"tokens\": [ { \"token\": \"/path\", \"start_offset\": 0, \"end_offset\": 5, \"type\": \"word\", \"position\": 0 }, { \"token\": \"/path/to\", \"start_offset\": 0, \"end_offset\": 8, \"type\": \"word\", \"position\": 0 }, { \"token\": \"/path/to/file\", \"start_offset\": 0, \"end_offset\": 13, \"type\": \"word\", \"position\": 0 } ]} Token Filters 对于tokenizer输出的单词(term)进行增加、删除、修改等操作 自带的如下: lowercase 将所有term转为小写 stop 删除停用词 Ngram 和 Edge NGram 连词分割 Synonym 添加近义词的term Token Filters测试1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950POST _analyze{ \"text\": [ \"a Hello World!\" ], \"tokenizer\": \"standard\", \"filter\": [ \"stop\", \"lowercase\", { \"type\": \"ngram\", \"min_gram\": 4, \"max_gram\": 4 } ]}# 结果{ \"tokens\": [ { \"token\": \"hell\", \"start_offset\": 2, \"end_offset\": 7, \"type\": \"<ALPHANUM>\", \"position\": 1 }, { \"token\": \"ello\", \"start_offset\": 2, \"end_offset\": 7, \"type\": \"<ALPHANUM>\", \"position\": 1 }, { \"token\": \"worl\", \"start_offset\": 8, \"end_offset\": 13, \"type\": \"<ALPHANUM>\", \"position\": 2 }, { \"token\": \"orld\", \"start_offset\": 8, \"end_offset\": 13, \"type\": \"<ALPHANUM>\", \"position\": 2 } ]} 自定义分词自定义分词需要在索引配置中设定 char_filter、tokenizer、filter、analyzer等 自定义分词示例: 分词器名称:my_custom\\ 过滤器将token转为大写 1234567891011121314151617181920PUT test_index_1{ \"settings\": { \"analysis\": { \"analyzer\": { \"my_custom_analyzer\": { \"type\": \"custom\", \"tokenizer\": \"standard\", \"char_filter\": [ \"html_strip\" ], \"filter\": [ \"uppercase\", \"asciifolding\" ] } } } }} 12345678910111213141516171819202122232425262728293031323334353637383940// javaXContentFactory.jsonBuilder() .startObject().startObject(\"analysis\") .startObject(\"normalizer\").startObject(Normalizers.CASE_INSENSITIVE) .field(\"type\", \"custom\") .field(\"filter\", \"lowercase\") .endObject().endObject() // 动态同义词 .startObject(\"filter\") .startObject(\"dynamic_synonym\").field(\"type\", \"dynamic_synonym\").field(\"tokenizer\", \"ik_smart\").endObject().endObject() .startObject(\"analyzer\") // 自定义分词器 .startObject(\"ik\") .field(\"filter\", \"\") .field(\"char_filter\", Arrays.asList(\"char_mapper\")) .field(\"type\", \"custom\") .field(\"tokenizer\", \"ik_max_word\") .endObject() // 搜索时处理同义词 .startObject(\"ikt\") .field(\"filter\", Arrays.asList(\"dynamic_synonym\")) .field(\"char_filter\", Arrays.asList(\"char_mapper\")) .field(\"type\", \"custom\") .field(\"tokenizer\", \"ik_smart\") .endObject() .endObject() // 自定义字符过滤 .startObject(\"char_filter\") .startObject(\"char_mapper\") .field(\"type\", \"mapping\") .field(\"mappings_path\", \"analysis/mapping.txt\") .endObject() .endObject() .endObject().endObject(); 自定义分词器测试1234567891011121314151617181920212223242526272829303132POST test_index_1/_analyze{ \"analyzer\": \"my_custom_analyzer\", \"text\": [\"<p>I&apos;m so <b>happy</b>!</p>\"]}# 结果{ \"tokens\": [ { \"token\": \"I'M\", \"start_offset\": 3, \"end_offset\": 11, \"type\": \"<ALPHANUM>\", \"position\": 0 }, { \"token\": \"SO\", \"start_offset\": 12, \"end_offset\": 14, \"type\": \"<ALPHANUM>\", \"position\": 1 }, { \"token\": \"HAPPY\", \"start_offset\": 18, \"end_offset\": 27, \"type\": \"<ALPHANUM>\", \"position\": 2 } ]} 分词使用说明分词会在如下两个时机使用: 创建或更新文档时(Index Time),会对相应的文档进行分词处理 查询时(Search Time),会对查询语句进行分词 查询时通过analyzer指定分词器 通过index mapping设置search_analyzer实现 一般不需要特别指定查询时分词器,直接使用索引分词器即可,否则会出现无法匹配的情况 分词使用建议 明确字段是否需要分词,不需要分词的字段就将type设置为keyword,可以节省空间和提高写性能 善用_analyze API,查看文档的分词结果 参考自","link":"/java/elasticsearch/elasticsearch6-x%E5%80%92%E6%8E%92%E7%B4%A2%E5%BC%95%E5%92%8C%E5%88%86%E8%AF%8D.html"},{"title":"Java版常用正则表达式说明","text":"摘要正则表达式在几乎所有语言中都可以使用,无论是前端的JavaScript、还是后端的Java、c#。他们都提供相应的接口/函数支持正则表达式。 元字符元字符说明:匹配除换行符以外的任意字符 w:匹配字母或数字或下划线或汉字 s:匹配任意的空白符 d:匹配数字匹配单词的开始或结束 ^:匹配字符串的开始 $:匹配字符串的结束 eg:匹配有abc开头的字符串:abc或者^abc 匹配8位数字的QQ号码:^dddddddd$ 匹配1开头11位数字的手机号码:^1dddddddddd$ 重复限定符为了处理这些重复问题,正则表达式中一些重复限定符,把重复部分用合适的限定符替代 语法说明: *重复零次或更多次 +重复一次或更多次 ?重复零次或一次 {n}重复n次 {n,}重复n次或更多次 {n,m}重复n到m次 匹配8位数字的QQ号码:^d{8}$ 匹配1开头11位数字的手机号码:^1d{10}$ 匹配银行卡号是14~18位的数字:^d{14,18}$ 匹配以a开头的,0个或多个b结尾的字符串^ab*$ 分组正则表达式中用小括号()来做分组,也就是括号中的内容作为一个整体。 因此当我们要匹配多个ab时,我们可以这样。 如匹配字符串中包含0到多个ab开头:^(ab)* 转义我们看到正则表达式用小括号来做分组,那么问题来了: 如果要匹配的字符串中本身就包含小括号,那是不是冲突?应该怎么办? 针对这种情况,正则提供了转义的方式,也就是要把这些元字符、限定符或者关键字转义成普通的字符,做法很简答,就是在要转义的字符前面加个斜杠,也就是\\即可。 如要匹配以(ab)开头:^\\(ab\\)* 条件或回到我们刚才的手机号匹配,我们都知道:国内号码都来自三大网,它们都有属于自己的号段,比如联通有130/131/132/155/156/185/186/145/176等号段,假如让我们匹配一个联通的号码,那按照我们目前所学到的正则,应该无从下手的,因为这里包含了一些并列的条件,也就是“或”,那么在正则中是如何表示“或”的呢? 正则用符号 | 来表示或,也叫做分支条件,当满足正则里的分支条件的任何一种条件时,都会当成是匹配成功。 那么我们就可以用“或”条件来处理这个问题:^(130|131|132|155|156|185|186|145|176)d{8}$ 区间正则提供一个元字符中括号 [] 来表示区间条件。 限定0到9 可以写成[0-9] 限定A-Z 写成[A-Z] 限定某些数字 [165] 那上面的正则我们还改成这样: ^((13[0-2])|(15[56])|(18[5-6])|145|176)d{8}$ 好了,正则表达式的基本用法就讲到这里了,其实它还有非常多的知识点以及元字符,我们在此只列举了部分元字符和语法来讲,旨在给那些不懂正则或者想学正则但有看不下去文档的人做一个快速入门级的教程,看完本教程,即使你不能写出高大上的正则,至少也能写一些简单的正则或者看得懂别人写的正则了。 正则进阶知识点1.零宽断言断言:俗话的断言就是“我断定什么什么”,而正则中的断言,就是说正则可以指明在指定的内容的前面或后面会出现满足指定规则的内容,意思正则也可以像人类那样断定什么什么,比如”ss1aa2bb3”,正则可以用断言找出aa2前面有bb3,也可以找出aa2后面有ss1. 零宽:就是没有宽度,在正则中,断言只是匹配位置,不占字符,也就是说,匹配结果里是不会返回断言本身。 eg:假设我们要用爬虫抓取csdn里的文章阅读量。通过查看源代码可以看到文章阅读量这个内容是这样的结构 “阅读数:641“ 其中也就‘641’这个是变量,也就是说不同文章不同的值,当我们拿到这个字符串时,需要获得这里边的‘641’有很多种办法,但如果正则应该怎么匹配呢? 正向先行断言(正前瞻)语法:(?=pattern) 作用:匹配pattern表达式的前面内容,不返回本身。 这样子说,还是一脸懵逼,好吧,回归刚才那个栗子,要取到阅读量,在正则表达式中就意味着要能匹配到‘’前面的数字内容。 按照上所说的正向先行断言可以匹配表达式前面的内容,那意思就是**:(?=)** 就可以匹配到前面的内容了。 匹配什么内容呢?如果要所有内容那就是: 12345678910 String reg=\".+(?=</span>)\";String test = \"<span class=\"read-count\">阅读数:641</span>\"; Pattern pattern = Pattern.compile(reg); Matcher mc= pattern.matcher(test); while(mc.find()){ System.out.println(\"匹配结果:\") System.out.println(mc.group()); } //匹配结果://<span class=\"read-count\">阅读数:641 可是老哥我们要的只是前面的数字呀,那也简单咯,匹配数字 d,那可以改成: 123456789String reg=\"\\d+(?=</span>)\";String test = \"<span class=\\\"read-count\\\">阅读数:641</span>\";Pattern pattern = Pattern.compile(reg);Matcher mc= pattern.matcher(test);while(mc.find()){ System.out.println(mc.group());}//匹配结果://641 大功告成! 正向后行断言(正后顾)语法:(?<=pattern) 作用:匹配pattern表达式的后面的内容,不返回本身。 有先行就有后行,先行是匹配前面的内容,那后行就是匹配后面的内容啦。 上面的栗子,我们也可以用后行断言来处理。 12345678910//(?<=<span class=\"read-count\">阅读数:)d+String reg=\"(?<=<span class=\\\"read-count\\\">阅读数:)\\d+\";String test = \"<span class=\\\"read-count\\\">阅读数:641</span>\"; Pattern pattern = Pattern.compile(reg); Matcher mc= pattern.matcher(test); while(mc.find()){ System.out.println(mc.group()); }//匹配结果://641 就这么简单。 负向先行断言(负前瞻)语法:**(?!pattern)** 作用:匹配非pattern表达式的前面内容,不返回本身。 有正向也有负向,负向在这里其实就是非的意思。 举个栗子:比如有一句 “我爱祖国,我是祖国的花朵” 现在要找到不是’的花朵’前面的祖国 用正则就可以这样写:祖国**(?!的花朵)**。 负向后行断言(负后顾)语法:(?<!pattern) 作用:匹配非pattern表达式的后面内容,不返回本身。 2.捕获和非捕获单纯说到捕获,他的意思是匹配表达式,但捕获通常和分组联系在一起,也就是“捕获组”。 捕获组:匹配子表达式的内容,把匹配结果保存到内存中中数字编号或显示命名的组里,以深度优先进行编号,之后可以通过序号或名称来使用这些匹配结果。 而根据命名方式的不同,又可以分为两种组。 数字编号捕获组 语法:**(exp)** 解释:从表达式左侧开始,每出现一个左括号和它对应的右括号之间的内容为一个分组,在分组中,第0组为整个表达式,第一组开始为分组。 比如固定电话的:020-85653333 他的正则表达式为:(0d{2})-(d{8}) 按照左括号的顺序,这个表达式有如下分组: 序号编号分组内容00(0d{2})-(d{8})020-8565333311(0d{2})02022(d{8})85653333 我们用Java来验证一下: 12345678910String test = \"020-85653333\"; String reg=\"(0\\d{2})-(\\d{8})\"; Pattern pattern = Pattern.compile(reg); Matcher mc= pattern.matcher(test); if(mc.find()){ System.out.println(\"分组的个数有:\"+mc.groupCount()); for(int i=0;i<=mc.groupCount();i++){ System.out.println(\"第\"+i+\"个分组为:\"+mc.group(i)); } } 输出结果: 1234分组的个数有:2第0个分组为:020-85653333第1个分组为:020第2个分组为:85653333 可见,分组个数是2,但是因为第0个为整个表达式本身,因此也一起输出了。 命名编号捕获组 语法:**(?exp)** 解释:分组的命名由表达式中的name指定 比如区号也可以这样写:(?d{2})-(?d{8}) 按照左括号的顺序,这个表达式有如下分组:序号名称分组内容00(0d{2})-(d{8})020-856533331quhao(0d{2})0202haoma(d{8})85653333 用代码来验证一下: 123456789String test = \"020-85653333\";String reg=\"(?<quhao>0\\d{2})-(?<haoma>\\d{8})\";Pattern pattern = Pattern.compile(reg);Matcher mc= pattern.matcher(test);if(mc.find()){ System.out.println(\"分组的个数有:\"+mc.groupCount()); System.out.println(mc.group(\"quhao\")); System.out.println(mc.group(\"haoma\"));} 输出结果: 123分组的个数有:2分组名称为:quhao,匹配内容为:020分组名称为:haoma,匹配内容为:85653333 非捕获组 语法:**(?:exp)** 解释:和捕获组刚好相反,它用来标识那些不需要捕获的分组,说的通俗一点,就是你可以根据需要去保存你的分组。 比如上面的正则表达式,程序不需要用到第一个分组,那就可以这样写:(?:d{2})-(d{8}) 序号编号分组内容00(0d{2})-(d{8})020-8565333311(d{8})85653333 验证一下: 12345678910String test = \"020-85653333\";String reg=\"(?:0\\d{2})-(\\d{8})\";Pattern pattern = Pattern.compile(reg);Matcher mc= pattern.matcher(test);if(mc.find()){ System.out.println(\"分组的个数有:\"+mc.groupCount()); for(inti=0;i<=mc.groupCount();i++){ System.out.println(\"第\"+i+\"个分组为:\"+mc.group(i)); }} 输出结果: 123分组的个数有:1第0个分组为:020-85653333第1个分组为:85653333 3.反向引用上面讲到捕获,我们知道:捕获会返回一个捕获组,这个分组是保存在内存中,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用。 根据捕获组的命名规则,反向引用可分为: 数字编号组反向引用:k或 umber 命名编号组反向引用:k或者’name’ 好了 讲完了,懂吗?不懂!!! 可能连前面讲的捕获有什么用都还不懂吧? 其实只是看完捕获不懂不会用是很正常的! 因为捕获组通常是和反向引用一起使用的。 上面说到捕获组是匹配子表达式的内容按序号或者命名保存起来以便使用。 注意两个字眼:“内容” 和 “使用”。 这里所说的“内容”,是匹配结果,而不是子表达式本身,强调这个有什么用?嗯,先记住。 那这里所说的“使用”是怎样使用呢? 因为它的作用主要是用来查找一些重复的内容或者做替换指定字符。 还是举栗子吧。 比如要查找一串字母”aabbbbgbddesddfiid”里成对的字母 如果按照我们之前学到的正则,什么区间啊限定啊断言啊可能是办不到的, 现在我们先用程序思维理一下思路: 1)匹配到一个字母 2)匹配第下一个字母,检查是否和上一个字母是否一样 3)如果一样,则匹配成功,否则失败 这里的思路2中匹配下一个字母时,需要用到上一个字母,那怎么记住上一个字母呢??? 这下子捕获就有用处啦,我们可以利用捕获把上一个匹配成功的内容用来作为本次匹配的条件 好了,有思路就要实践 首先匹配一个字母:w 我们需要做成分组才能捕获,因此写成这样:(w) 那这个表达式就有一个捕获组:(w) 然后我们要用这个捕获组作为条件,那就可以:(w) 这样就大功告成了 可能有人不明白了,是什么意思呢? 还记得捕获组有两种命名方式吗,一种是是根据捕获分组顺序命名,一种是自定义命名来作为捕获组的命名 在默认情况下都是以数字来命名,而且数字命名的顺序是从1开始的 因此要引用第一个捕获组,根据反向引用的数字命名规则 就需要 k<1>或者 当然,通常都是是后者。 我们来测试一下: 1234567String test = \"aabbbbgbddesddfiid\";Pattern pattern = Pattern.compile(\"(\\w)\\1\");Matcher mc= pattern.matcher(test);while(mc.find()){ System.out.println(mc.group());} 输出结果: 1aabbbbddddii 嗯,这就是我们想要的了。 在举个替换的例子,假如想要把字符串中abc换成a。 123String test = \"abcbbabcbcgbddesddfiid\";String reg=\"(a)(b)c\";System.out.println(test.replaceAll(reg, \"$1\")); 输出结果: 1abbabcgbddesddfiid 4.贪婪和非贪婪 贪婪 我们都知道,贪婪就是不满足,尽可能多的要。 在正则中,贪婪也是差不多的意思: 贪婪匹配:当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符,这匹配方式叫做贪婪匹配。 特性:一次性读入整个字符串进行匹配,每当不匹配就舍弃最右边一个字符,继续匹配,依次匹配和舍弃(这种匹配-舍弃的方式也叫做回溯),直到匹配成功或者把整个字符串舍弃完为止,因此它是一种最大化的数据返回,能多不会少。 前面我们讲过重复限定符,其实这些限定符就是贪婪量词,比如表达式:d{3,6}。 用来匹配3到6位数字,在这种情况下,它是一种贪婪模式的匹配,也就是假如字符串里有6个个数字可以匹配,那它就是全部匹配到。 如下面的代码。 123456789String reg=\"\\d{3,6}\";String test=\"61762828 176 2991 871\";System.out.println(\"文本:\"+test);System.out.println(\"贪婪模式:\"+reg);Pattern p1 =Pattern.compile(reg);Matcher m1 = p1.matcher(test);while(m1.find()){ System.out.println(\"匹配结果:\"+m1.group(0));} 输出结果: 123456文本:61762828 176 2991 44 871贪婪模式:d{3,6}匹配结果:617628匹配结果:176匹配结果:2991匹配结果:871 由结果可见:本来字符串中的“61762828”这一段,其实只需要出现3个(617)就已经匹配成功了的,但是他并不满足,而是匹配到了最大能匹配的字符,也就是6个。 一个量词就如此贪婪了, 那有人会问,如果多个贪婪量词凑在一起,那他们是如何支配自己的匹配权的呢? 是这样的,多个贪婪在一起时,如果字符串能满足他们各自最大程度的匹配时,就互不干扰,但如果不能满足时,会根据深度优先原则,也就是从左到右的每一个贪婪量词,优先最大数量的满足,剩余再分配下一个量词匹配。 123456789String reg=\"(\\d{1,2})(\\d{3,4})\";String test=\"61762828 176 2991 87321\";System.out.println(\"文本:\"+test);System.out.println(\"贪婪模式:\"+reg);Pattern p1 =Pattern.compile(reg);Matcher m1 = p1.matcher(test);while(m1.find()){ System.out.println(\"匹配结果:\"+m1.group(0));} 输出结果: 12345文本:61762828 176 2991 87321贪婪模式:(d{1,2})(d{3,4})匹配结果:617628匹配结果:2991匹配结果:87321 “617628” 是前面的d{1,2}匹配出了61,后面的匹配出了7628 “2991” 是前面的d{1,2}匹配出了29 ,后面的匹配出了91 “87321”是前面的d{1,2}匹配出了87,后面的匹配出了321 懒惰(非贪婪) 懒惰匹配:当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能少的字符,这匹配方式叫做懒惰匹配。 特性:从左到右,从字符串的最左边开始匹配,每次试图不读入字符匹配,匹配成功,则完成匹配,否则读入一个字符再匹配,依此循环(读入字符、匹配)直到匹配成功或者把字符串的字符匹配完为止。 懒惰量词是在贪婪量词后面加个“?” 代码说明 *?重复任意次,但尽可能少重复 +?重复1次或更多次,但尽可能少重复 ??重复0次或1次,但尽可能少重复 {n,m}?重复n到m次,但尽可能少重复 {n,}?重复n次以上,但尽可能少重复。 123456789String reg=\"(\\d{1,2}?)(\\d{3,4})\";String test=\"61762828 176 2991 87321\";System.out.println(\"文本:\"+test);System.out.println(\"贪婪模式:\"+reg);Pattern p1 =Pattern.compile(reg);Matcher m1 = p1.matcher(test);while(m1.find()){ System.out.println(\"匹配结果:\"+m1.group(0));} 输出结果: 12345文本:61762828 176 2991 87321贪婪模式:(d{1,2}?)(d{3,4})匹配结果:61762匹配结果:2991匹配结果:87321 “61762” 是左边的懒惰匹配出6,右边的贪婪匹配出1762 “2991” 是左边的懒惰匹配出2,右边的贪婪匹配出991 “87321” 左边的懒惰匹配出8,右边的贪婪匹配出7321 5.反义前面说到元字符的都是要匹配什么什么,当然如果你想反着来,不想匹配某些字符,正则也提供了一些常用的反义元字符。 元字符解释: W匹配任意不是字母,数字,下划线,汉字的字符 S匹配任意不是空白符的字符 D匹配任意非数字的字符 B匹配不是单词开头或结束的位置 [x]匹配除了x以外的任意字符 [aeiou]匹配除了aeiou这几个字母以外的任意字符 正则进阶知识就讲到这里,正则是一门博大精深的语言,其实学会它的一些语法和知识点还算不太难,但想要做到真正学以致用能写出非常6的正则,还有很远的距离,只有真正对它感兴趣的,并且经常研究和使用它,才会渐渐的理解它的博大精深之处,我就带你们走到这,剩下的,靠自己啦。 参考资料","link":"/java/basic/Java%E7%89%88%E5%B8%B8%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%AF%B4%E6%98%8E.html"},{"title":"Elasticsearch常用工具api","text":"摘要Elasticsearch 是一个高度可扩展且开源的全文检索和分析引擎。它可以让您快速且近实时地存储,检索以及分析海量数据。它通常用作那些具有复杂搜索功能和需求的应用的底层引擎或者技术。 下面是 Elasticsearch 一些简单的使用案例 : 您运行一个可以让您顾客来搜索您所售产品的在线的网络商店。在这种情况下,您可以使用 Elasticsearch 来存储您的整个产品的目录和库存,并且为他们提供搜索和自动完成的建议。 您想要去收集日志或交易数据,并且您还想要去分析和挖掘这些数据以来找出趋势,统计,概述,或者异常现。在这种情况下,您可以使用 Logstash(Elasticsearch/Logstash/Kibana 技术栈中的一部分)来收集,聚合,以及解析数据,然后让 Logstash 发送这些数据到 Elasticsearch。如果这些数据存在于 Elasticsearch 中,那么您就可以执行搜索和聚合以挖掘出任何您感兴趣的信息。 您运行一个价格警告平台,它允许客户指定精确的价格,如“我感兴趣的是购买指定的电子产品,如果任何供应商该产品的价格在未来一个月内低于 $X 这个价钱的话我应该被通知到”。在这种情况下,您可以收集供应商的价格,推送它们到 Elasticsearch 中去,然后使用 reverse-search(Percolator)(反向搜索(过滤器))功能以匹配客户查询价格的变动,最后如果发现匹配成功就给客户发出通知。 您必须分析/商业智能的需求,并希望快速的研究,分析,可视化,并且需要 ad-hoc(即席查询)海量数据(像数百万或者数十亿条记录)上的质疑。在这种情况下,您可以使用 Elasticsearch 来存储数据,然后使用 Kibana(Elasticsearch/Logstash/Kibana 技术栈中的一部分)以建立一个能够可视化的对您很重要的数据方面的定制的 dashboards(面板)。此外,您还可以使用 Elasticsearch 的聚合功能对您的数据执行复杂的商业智能查询 对于本教程的其余部分,我将引导您完成 Elasticsearch 的启动和运行的过程,同时了解其原理,并执行像 indexing(索引),searching(查询)和 modifing(修改)数据的基础操作。在本教程的最后一部分,您应该可以清楚的了解到 Elasticsearch 是什么,它是如何工作的,并有希望获得启发。看您如何使用它来构建复杂的搜索应用程序或者从数据中挖掘出想要的信息。 常用实例 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238# 常用kibana脚本(可以自动填充,比较好用)PUT /test_business/data/1 #更改数据{ \"name\":\"zhe\"}}POST _analyze #实时分词{ \"text\": \"张月超\", \"analyzer\": \"ik_max_word\"}DELETE /analyze_index #删除索引GET analyze_index/_settings #查看索引_settingsGET analyze_index/_mapping #查看索引_mappingPOST /analyze_index/data/_mapping #设置mapping{ \"dynamic\": \"false\", \"properties\": { \"name\": { \"type\": \"text\", \"analyzer\": \"ik\" } }}POST /analyze_index #设置settings{ \"settings\": { \"index\": { \"analysis\": { \"normalizer\": { \"case_insensitive_normalizer\": { \"type\": \"custom\", \"filter\": \"lowercase\" } }, \"filter\": { \"my_synonym\": { \"type\": \"synonym\", \"synonyms_path\": \"analysis-ik/extra/synonyms.dic\" } }, \"analyzer\": { \"ik\": { \"filter\": [ \"my_synonym\" ], \"char_filter\": [ \"my_char_mapper\" ], \"type\": \"custom\", \"tokenizer\": \"ik_max_word\" } }, \"char_filter\": { \"my_char_mapper\": { \"type\": \"mapping\", \"mappings_path\": \"analysis-ik/extra/pre_filter_mapping.dic\" } } } } }, \"mapping\": { \"data\": { \"properties\": { \"name\": { \"type\": \"text\", \"analyzer\": \"ik\" } } } }}GET /es_test_analyzer/_settingsGET /es_test_analyzer/_mappingGET /analyze_index/data/1POST /es_test_analyzer/_analyze{ \"text\": \"超越\", \"analyzer\": \"ik_max_word\"}POST /es_test_analyzer/data/1{ \"name\": \"张月超666哈哈张月超\", \"nick_name\":\"张月超666哈哈张月超\"}POST /es_test_analyzer/data/2{ \"name\": \"王月\", \"nick_name\":\"王月\"}POST /es_test_analyzer/data/3{ \"name\": \"超越\", \"nick_name\":\"超越\"}GET /es_test_analyzer/data/1GET /es_test_analyzer/data/3/_termvectors?fields=nick_name # 查看索引中分词情况GET /es_test_analyzer/data/_search{ \"query\": { \"multi_match\": { \"query\": \"超越\", \"fields\": [ \"nick_name\" ], \"analyzer\": \"ik\", \"operator\": \"or\", \"type\": \"best_fields\" } }, \"highlight\": { \"fields\": { \"name\": { } } }}DELETE /es_test_analyzer/GET /analyze_index/data/_mappingGET /test/data/_search{ \"query\": { \"bool\": { \"should\": [ { \"multi_match\": { \"query\": \"餐饮\", \"fields\": [\"title^2\",\"tags\"] } },{ \"wildcard\": { \"name\": { \"value\": \"*中国*\" } } } ] } }}GET /user/data/9969/_explain # 查看详细id:9969 得分情况{ \"query\": { \"bool\": { \"must\": [ { \"multi_match\": { \"query\": \"tacos n frankies\", \"fields\": [ \"name^1.0\", \"info^1.0\" ], \"type\": \"best_fields\", \"operator\": \"or\", \"analyzer\": \"ik_max_word\", \"slop\": 0, \"prefix_length\": 0, \"max_expansions\": 50, \"zero_terms_query\": \"NONE\", \"auto_generate_synonyms_phrase_query\": true, \"fuzzy_transpositions\": true, \"boost\": 1 } } \"adjust_pure_negative\": true, \"boost\": 1 } } , \"highlight\": { \"fields\": { \"name\": {}, \"info\": {} } }}GET /user/data/_search{ \"query\": { \"bool\": { \"must\": [ { \"multi_match\": { \"query\": \"tacos n frankies\", \"fields\": [ \"name^1.0\", \"info^1.0\" ], \"type\": \"best_fields\", \"operator\": \"or\", \"analyzer\": \"ik_max_word\", \"slop\": 0, \"prefix_length\": 0, \"max_expansions\": 50, \"zero_terms_query\": \"NONE\", \"auto_generate_synonyms_phrase_query\": true, \"fuzzy_transpositions\": true, \"boost\": 1 } } \"adjust_pure_negative\": true, \"boost\": 1 } } , \"highlight\": { \"fields\": { \"name\": {}, \"info\": {} } }} 查看健康信息 curl -XGET ‘localhost:9200/_cat/health?v&pretty’ 我们可以获得 green,yellow,或者 red 的 status。Green 表示一切正常(集群功能齐全), yellow 表示所有数据可用,但是有些副本尚未分配(集群功能齐全),red 意味着由于某些原因有些数据不可用。注意,集群是 red,它仍然具有部分功能(例如,它将继续从可用的分片中服务搜索请求),但是您可能需要尽快去修复它,因为您已经丢失数据了。 查看所有的索引 curl -XGET ‘localhost:9200/_cat/indices?v&pretty’ Document APISindex api 索引 API 在特定索引中 add ( 添加 ) 或 update *( 更新 ) *a typed JSON document ( 类型化的 JSON 文档 ),使其可搜索。以下示例将 JSON 文档插入到 “twitter” 索引中,ID 为1 : 123456789101112131415161718192021curl -XPUT 'localhost:9200/twitter/tweet/1?pretty' -H 'Content-Type: application/json' -d'{ \"user\" : \"kimchy\", \"post_date\" : \"2009-11-15T14:12:12\", \"message\" : \"trying out Elasticsearch\"}'结果:{ \"_shards\" : { \"total\" : 2, \"failed\" : 0, \"successful\" : 2 }, \"_index\" : \"twitter\", \"_type\" : \"tweet\", \"_id\" : \"1\", \"_version\" : 1, \"created\" : true, \"result\" : created} total - 指示应对多少 shard copies ( 分片副本 )( \\primary ( 主 )分片和 replica ( 副本 ) 分片)执行索引操作。 successful - 表示索引操作成功的分片副本的数量。 failed - 在索引操作在副本碎片上失败的情况下包含与复制相关的错误的数组。 当索引操作 successful 返回时,可能不会全部启动副本碎片(默认情况下,只需要主索引,但可以更改此行为)。在这种情况下, total 将等于基于 number_of_replicas 设置的总分片,并且 successful 将等于已启动的分片数(主副本和副本)。如果没有失败, failed 将是 0 。 get apiget api 允许从一个基于其id的 index 中获取一个 JSON格式的 document,下面的示例是从一个在名称为tweet的 type \\下的id为1,名称为twitter的 \\index \\中获取一个JSON格式的 \\document。 1curl -XGET 'http://localhost:9200/twitter/tweet/1' update api1234567891011121314151617181920212223242526272829303132333435363738394041# 更新api PUT test/type1/1{ \"counter\" : 1, \"tags\" : [\"red\"]}# 脚本更新POST test/type1/1/_update{ \"script\" : { \"inline\": \"ctx._source.counter += params.count\", \"lang\": \"painless\", \"params\" : { \"count\" : 4 } }}# 将新字段添加到文档:POST test/type1/1/_update{ \"script\" : \"ctx._source.new_field = \\\"value_of_new_field\\\"\"}# 删除字段POST test/type1/1/_update{ \"script\" : \"ctx._source.remove(\\\"new_field\\\")\"}# 甚至可以改变已执行的操作。这个例子就是删除文档,如果 tags包含 green,否则就什么也不做(noop):POST test/type1/1/_update{ \"script\" : { \"inline\": \"if (ctx._source.tags.contains(params.tag)) { ctx.op = \\\"delete\\\" } else { ctx.op = \\\"none\\\" }\", \"lang\": \"painless\", \"params\" : { \"tag\" : \"green\" } }} 通过查询api更新123456789101112POST twitter/_update_by_query{ \"script\": { \"inline\": \"ctx._source.likes++\", \"lang\": \"painless\" }, \"query\": { \"term\": { \"user\": \"kimchy\" } }} bulk apiBulk API,能够在一个单一的API调用执行多项索引/删除操作。这可以大大提高索引速度。 该 REST API 端点/_bulk,它遵循JSON结构: 1234567action_and_meta_data\\noptional_source\\naction_and_meta_data\\noptional_source\\n....action_and_meta_data\\noptional_source\\n 注意:数据的最终行必须以换行符结束\\n。 可能的操作有 index,create,delete和 update, index 和 ``create期望在下一行的作为源,并与索引 API 有相同的语义。(如果文件具有相同的索引和类型的文件已经存在,就会创建失败,必要时候而索引回添加或替换文件)。delete不会作为下一行的源,并与 delete API 中具有相同的语义。update 是希望部分文档,upsert 和脚本及其选项能够在下一行指定。 delete apidelete API允许基于指定的ID来从索引库中删除一个JSON文件。下面演示了从一个叫twitter的索引库的tweettype下删除文档,id是1: 1$ curl -XDELETE 'http://localhost:9200/twitter/tweet/1' 索引的每个文档都被标记了版本。当删除文档时, 可以通过指定version来确保我们试图删除一个实际上已被删除的文档时,它在此期间并没有改变。在文档中执行的每个写入操作,包括删除,都会使其版本递增。 delete by query api最简单的用法是使用_delete_by_query对每个查询匹配的文档执行删除。这是API: 12345678POST twitter/_delete_by_query{ \"query\": { //① \"match\": { \"message\": \"some message\" } }} term vectors返回有关特定文档字段中的词条的信息和统计信息。文档可以存储在索引中或由用户人工提供。词条向量默认为实时,不是近实时。这可以通过将realtime参数设置为false来更改。 1GET /twitter/tweet/1/_termvectors 可选的,您可以使用url中的参数指定检索信息的字段: 1GET /twitter/tweet/1/_termvectors?fields=message searchquery api结果的分页可以通过使用 from 和 size 参数来完成。 from 参数定义了您要提取的第一个结果的偏移量。 size 参数允许您配置要返回的最大匹配数。 虽然 from 和 size 可以设置为请求参数,但它们也可以在搜索正文中设置。from 默认值为 0,size 默认为 10。 1234567GET /_search{ \"from\" : 0, \"size\" : 10, \"query\" : { \"term\" : { \"user\" : \"kimchy\" } }} 注意 from + size 不能超过 index.max_result_window 索引设置,默认为 10,000。 有关深入滚动的更有效方法,请参阅 Scroll 或 Search After API。 sort排序选项可以有以下值: | asc | 按升序排序 | | desc | 按倒序排序 | 在对 _score 进行排序时,该顺序默认为 desc,在对其他事物进行排序时默认为 asc。 Sort mode Option Elasticsearch支持按数组或多值字段排序。 mode 选项控制选择用于对其所属文档进行排序的数组值。 mode 选项可以具有以下值: | min | 选择最低值。 | | max | 选择最高值。 | | sum | 使用所有值的和作为排序值。 仅适用于基于数字的数组字段。 | | avg | 使用所有值的平均值作为排序值。 仅适用于基于数字的数组字段。 | | median | 使用所有值的中值作为排序值。 仅适用于基于数字的数组字段。 | Elasticsearch 还支持根据一个或多个嵌套对象内的字段进行排序。 通过嵌套字段支持进行的排序在已经存在的排序选项之上具有以下参数: nested_path 定义要排序的嵌套对象。 实际排序字段必须是此嵌套对象内的直接字段。 当通过嵌套字段排序时,此字段是必需的。 nested_filter 嵌套路径中的内部对象应与其匹配的过滤器,以便通过排序考虑其字段值。 常见的情况是在嵌套的过滤器或查询中重复查询/过滤。 默认情况下,没有 nested_filter 是激活的。 Nested sorting example 在下面的示例中,offer是一个类型为嵌套的字段。 需要指定nested_path; 否则,elasticsearch不知道需要捕获哪个嵌套级排序值。 123456789101112131415161718POST /_search{ \"query\" : { \"term\" : { \"product\" : \"chocolate\" } }, \"sort\" : [ { \"offer.price\" : { \"mode\" : \"avg\", \"order\" : \"asc\", \"nested_path\" : \"offer\", \"nested_filter\" : { \"term\" : { \"offer.color\" : \"blue\" } } } } ]} 当通过脚本排序和按地理距离排序时,也支持嵌套排序。 Missing Values 缺少的参数指定应如何处理缺少字段的文档:缺少的值可以设置为 last,first 或自定义值(将用于缺少文档作为排序值)。 123456789GET /_search{ \"sort\" : [ { \"price\" : {\"missing\" : \"_last\"} } ], \"query\" : { \"term\" : { \"product\" : \"chocolate\" } }} Note:如果嵌套的内部对象与 nested_filter 不匹配,则使用缺少的值。 Geo Distance Sorting 允许按 geodistance 排序。 下面是一个例子,假设 pin.location 是一个类型为 geo_point 的字段: 1234567891011121314151617GET /_search{ \"sort\" : [ { \"_geo_distance\" : { \"pin.location\" : [-70, 40], \"order\" : \"asc\", \"unit\" : \"km\", \"mode\" : \"min\", \"distance_type\" : \"sloppy_arc\" } } ], \"query\" : { \"term\" : { \"user\" : \"kimchy\" } }} distance_type 如何计算距离。 可以是 sloppy_arc(默认),弧(稍微更精确但显着更慢)或平面(更快,但不准确在长距离和接近极点)。 mode 如果字段有多个地理点,该怎么办。 默认情况下,按升序排序时考虑最短距离,按降序排序时最长距离。 支持的值为 min,max,median 和 avg。 unit 计算排序值时使用的单位。 默认值为 m(米)。 geo distance sorting 不支持可配置的缺失值:当文档没有用于距离计算的字段的值时,距离将始终被视为等于 Infinity。 在提供坐标时支持以下格式: highlighting允许突出显示一个或多个字段的搜索结果。 实现使用 lucene 普通荧光笔,快速向量荧光笔(fvh)或 postings 荧光笔。 以下是一个搜索请求正文的示例: 1234567891011GET /_search{ \"query\" : { \"match\": { \"user\": \"kimchy\" } }, \"highlight\" : { \"fields\" : { \"content\" : {} } }} 在上述情况下,内容字段将为每个搜索命中突出显示(每个搜索命中内将有另一个元素,称为突出显示,其中包括突出显示的字段和突出显示的片段)。 Note: 为了执行突出显示,需要字段的实际内容。 如果有问题的字段被存储(在映射中存储设置为 true),它将被使用,否则,实际的 _source 将被加载,并且相关字段将从中提取。 _all 字段不能从 _source 中提取,因此它只能用于突出显示,如果它映射到将 store 设置为 true。 字段名称支持通配符符号。 例如,使用 comment_ * 将导致所有与表达式匹配的文本和关键字字段(以及 5.0 之前的字符串)被突出显示。 请注意,所有其他字段将不会突出显示。 如果您使用自定义映射器并要在字段上突出显示,则必须显式提供字段名称。 Plain highlighte(有多种类型选择、根据实际情况使用) 荧光笔的默认选择是普通类型,并使用Lucene荧光笔。 它试图在理解词重要性和短语查询中的任何词定位标准方面反映查询匹配逻辑。 warning: 如果你想突出很多文档中的大量字段与复杂的查询,这个荧光笔不会快。 在努力准确地反映查询逻辑,它创建一个微小的内存索引,并通过 Lucene 的查询执行计划程序重新运行原始查询条件,以获取当前文档的低级别匹配信息。 这对于每个字段和需要突出显示的每个文档重复。 如果这在您的系统中出现性能问题,请考虑使用替代荧光笔。 search typeQuery Then Fetch 参数值: query_then_fetch。 请求分两个阶段处理。 在第一阶段,查询被转发到所有涉及的分片。 每个分片执行搜索并生成对该分片本地的结果的排序列表。 每个分片只向协调节点返回足够的信息,以允许其合并并将分片级结果重新排序为全局排序的最大长度大小的结果集。 在第二阶段期间,协调节点仅从相关分片请求文档内容(以及高亮显示的片段,如果有的话)。 Note: 如果您未在请求中指定 search_type,那么这是默认设置。 Dfs, Query Then Fetch 参数值:dfs_query_then_fetch 与 “Query Then Fetch” 相同,除了初始分散阶段,其计算分布项频率用于更准确的计分。 scroll 游标(多数据深度分页问题解决)从滚动请求返回的结果反映了进行初始搜索请求时索引的状态,如时间快照。 对文档(索引,更新或删除)的后续更改只会影响以后的搜索请求。 为了使用滚动,初始搜索请求应该在查询字符串中指定滚动参数,它告诉 Elasticsearch 应保持“搜索上下文”活动的时间(见保持搜索上下文),例如 ?scroll=1m。 123456789POST /twitter/tweet/_search?scroll=1m{ \"size\": 100, \"query\": { \"match\" : { \"title\" : \"elasticsearch\" } }} 上述请求的结果包括一个 scrollid,它应该被传递给滚动 API,以便检索下一批结果。 12345POST ①/_search/scroll ②{ \"scroll\" : \"1m\", ③ \"scroll_id\" : \"DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==\" ④} | ① | 可以使用GET或POST。 | | ② | 网址不应包含索引或类型名称 - 而是在原始搜索请求中指定的。 | | ③ | scroll 参数告诉 Elasticsearch 将搜索上下文打开另一个1m。 | | ④ | scroll_id参数 | size 参数允许您配置每批结果返回的最大命中数。 每次调用 scroll API 都会返回下一批结果,直到没有更多结果要返回,即 hits 数组为空。 explan启用每次匹配对其评分计算方式的说明。 1234567GET /_search{ \"explain\": true, \"query\" : { \"term\" : { \"user\" : \"kimchy\" } }} suggesters (共有四种方式) Completion Suggester Context Suggester Phrase Suggester Term suggester completion suggester完全(completion)suggester 提供自动完成/按需搜索功能。 这是一种导航功能,可在用户输入时引导用户查看相关结果,从而提高搜索精度。 它不是用于拼写校正或平均值功能,如术语或短语 **suggesters **。 理想地,自动完成功能应当与用户键入的速度一样快,以提供与用户已经键入的内容相关的即时反馈。因此,完成 suggester 针对速度进行优化。 suggester 使用允许快速查找的数据结构,但是构建成本高并且存储在存储器中。 要使用此功能,请为此字段指定一个特殊映射,为快速完成的字段值编制索引。 123456789101112131415PUT music{ \"mappings\": { \"song\" : { \"properties\" : { \"suggest\" : { \"type\" : \"completion\" }, \"title\" : { \"type\": \"keyword\" } } } }} 映射支持以下参数: analyzer 使用索引分析器,默认为简单。 如果你想知道为什么我们没有选择标准分析器:我们尝试在这里很容易理解的行为,如果你索引字段内容在Drive-in,你不会得到任何建议, (第一个非停用词) search_analyzer 要使用的搜索分析器,默认为分析器的值。 preserve_separators 保留分隔符,默认为true。 如果禁用,你可以找到一个以Foo Fighters开头的字段,如果你推荐foof。 preserve_position_increments 启用位置增量,默认为true。 如果禁用和使用停用分析器,您可以得到一个字段从披头士开始,如果你 suggest b。 注意:你也可以通过索引两个输入,Beatles和披头士,不需要改变一个简单的分析器,如果你能够丰富你的数据。 max_input_length 限制单个输入的长度,默认为50个UTF-16代码点。 此限制仅在索引时使用,以减少每个输入字符串的字符总数,以防止大量输入膨胀底层数据结构。 大多数用例不会受默认值的影响,因为前缀完成很少超过前缀长度超过少数几个字符。 索引 您像任何其他字段一样索引 suggestion 。 suggestion 由输入和可选的权重属性组成。 输入是要由 suggestion 查询匹配的期望文本,并且权重确定如何对 suggestion 进行评分。 索引 suggestion 如下: 1234567PUT music/song/1?refresh{ \"suggest\" : { \"input\": [ \"Nevermind\", \"Nirvana\" ], \"weight\" : 34 }} 以下参数被支持: input 输入存储,这可以是字符串数组或只是一个字符串。 此字段是必填字段。 weight 正整数或包含正整数的字符串,用于定义权重并允许对 suggestions 进行排名。 此字段是可选的。 查询 suggest 像往常一样工作,除了您必须指定 suggest 类型为完成。 suggestions 接近实时,这意味着可以通过刷新显示新 suggestions ,并且一旦删除就不会显示文档。 此请求: 123456789POST music/_suggest?pretty{ \"song-suggest\" : { \"prefix\" : \"nir\", \"completion\" : { \"field\" : \"suggest\" } }} 返回这个响应: 12345678910111213141516171819202122{ \"_shards\" : { \"total\" : 5, \"successful\" : 5, \"failed\" : 0 }, \"song-suggest\" : [ { \"text\" : \"nir\", \"offset\" : 0, \"length\" : 3, \"options\" : [ { \"text\" : \"Nirvana\", \"_index\": \"music\", \"_type\": \"song\", \"_id\": \"1\", \"_score\": 1.0, \"_source\": { \"suggest\": [\"Nevermind\", \"Nirvana\"] } } ] } ]} 模糊查询 完成 suggester 还支持模糊查询 - 这意味着,您可以在搜索中输入错误,并仍然返回结果。 123456789101112POST music/_suggest?pretty{ \"song-suggest\" : { \"prefix\" : \"nor\", \"completion\" : { \"field\" : \"suggest\", \"fuzzy\" : { \"fuzziness\" : 2 } } }} 与查询前缀共享最长前缀的 suggestion 将得分更高。 模糊查询可以采用特定的模糊参数。 支持以下参数: | fuzziness | 模糊系数,默认为AUTO。 有关允许的设置,请参阅 “Fuzzinessedit”一节。 | | transpositions | 如果设置为true,则换位计数为一个更改而不是两个,默认为true | | min_length | 返回模糊 suggestions 前的输入的最小长度,默认值3 | | prefix_length | 输入的最小长度(未针对模糊替代项进行检查)默认为1 | | unicode_aware | 如果为true,则所有度量(如模糊编辑距离,置换和长度)都以Unicode代码点而不是字节为单位。 这比原始字节稍慢,因此默认情况下设置为false。 | 如果你想坚持使用默认值,但仍然使用模糊,你可以使用 fuzzy:{}或fuzzy:true。 Explan apiExplain API 计算查询和特定文档的分数说明。 这可以提供有用的反馈,无论文档是否匹配特定查询。 index 和 type 参数分别期望单个索引和单个类型。 用法完整查询示例: 123456GET /twitter/tweet/0/_explain{ \"query\" : { \"match\" : { \"message\" : \"elasticsearch\" } }} 这将产生以下结果: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748{ \"_index\" : \"twitter\", \"_type\" : \"tweet\", \"_id\" : \"0\", \"matched\" : true, \"explanation\" : { \"value\" : 1.55077, \"description\" : \"sum of:\", \"details\" : [ { \"value\" : 1.55077, \"description\" : \"weight(message:elasticsearch in 0) [PerFieldSimilarity], result of:\", \"details\" : [ { \"value\" : 1.55077, \"description\" : \"score(doc=0,freq=1.0 = termFreq=1.0\\n), product of:\", \"details\" : [ { \"value\" : 1.3862944, \"description\" : \"idf(docFreq=1, docCount=5)\", \"details\" : [ ] }, { \"value\" : 1.1186441, \"description\" : \"tfNorm, computed from:\", \"details\" : [ { \"value\" : 1.0, \"description\" : \"termFreq=1.0\", \"details\" : [ ] }, { \"value\" : 1.2, \"description\" : \"parameter k1\", \"details\" : [ ] }, { \"value\" : 0.75, \"description\" : \"parameter b\", \"details\" : [ ] }, { \"value\" : 5.4, \"description\" : \"avgFieldLength\", \"details\" : [ ] }, { \"value\" : 4.0, \"description\" : \"fieldLength\", \"details\" : [ ] } ] } ] } ] }, { \"value\" : 0.0, \"description\" : \"match on required clause, product of:\", \"details\" : [ { \"value\" : 0.0, \"description\" : \"# clause\", \"details\" : [ ] }, { \"value\" : 1.0, \"description\" : \"_type:tweet, product of:\", \"details\" : [ { \"value\" : 1.0, \"description\" : \"boost\", \"details\" : [ ] }, { \"value\" : 1.0, \"description\" : \"queryNorm\", \"details\" : [ ] } ] } ] } ] }} 还有一种更简单的通过 q 参数指定查询的方法。 然后解析指定的 q 参数值,就像使用 query_string 查询一样。 在api中的 q 参数的用法示例: 1GET /twitter/tweet/0/_explain?q=message:search 这将产生与先前请求相同的结果。 参考资料","link":"/java/elasticsearch/Elasticsearch%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7api.html"},{"title":"restful api 设计以及幂等性相关设计","text":"摘要针对项目中部分使用restful-api接口,总结文档如下,没有规矩不成方圆。写代码亦是,设计restful-api接口亦是。 RESTful 的核心思想就是,客户端发出的数据操作指令都是”动词 + 宾语”的结构。比如,GET /articles这个命令,GET是动词,/articles是宾语。 动词通常就是五种 HTTP 方法,对应 CRUD 操作。 GET:读取(Read) POST:新建(Create) PUT:更新(Update) PATCH:更新(Update),通常是部分更新 DELETE:删除(Delete) 根据 HTTP 规范,动词一律大写 话不多说,先上代码,一份完整的restful-api示例 12345678910111213141516171819202122232425262728293031323334353637383940414243444546@RestController@RequestMapping(\"admin/biz-name/v1/user\") //@RequestMapping(\"api/biz-name/v1/city\")public class AdminUserController { @Autowired private UserService service; @GetMapping(\"{id}/county/list\") public List<UserView> getUsersByCategoryId(@PathVariable(\"id\") Integer id) { return service.getUsersByCategoryId(id); } @GetMapping(\"{id}\") public UserView userInfoById(@PathVariable(\"id\") Integer id) { return service.getUserInfoById(id); } @PostMapping public Object create(@RequestBody UserEntityForm form) { // 相关验证valid 设置默认值 service.valid(form); if (StringUtil.isEmpty(form.getCsEmail())) { form.setCsEmail(\"980099577@qq.com\"); } Integer id = service.ceate(form); return Collections.singletonMap(\"id\", id); } @PutMapping public Result update(@RequestBody UserEntityForm form) { // 相关验证 valid service.valid(form); service.update(form); return Result.SUCCEED; } @DeleteMapping(\"{id}\") public Result delete(@PathVariable(\"id\") Integer id) { // 相关验证 valid service.valid(form); service.delete(id); return Result.SUCCEED; }} 针对以上restful-api 代码需要注意一下几点:@RestController 注解此注解加在类的上面,返回的结果以json格式,标注此为RestController。不同于Controller注解。Controller非json格式返回。 @RequestMapping此注解标识api请求的路劲,可指定相应的请求方法,例如@RequestMapping(“admin/biz-name/v1/user”):http://localhost:8080/admin/biz-name/v1/user 有如下定义参数: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic @interface RequestMapping { /** * Assign a name to this mapping. * <p><b>Supported at the type level as well as at the method level!</b> * When used on both levels, a combined name is derived by concatenation * with \"#\" as separator. * @see org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder * @see org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy */ String name() default \"\"; /** * The primary mapping expressed by this annotation. * <p>In a Servlet environment this is an alias for {@link #path}. * For example {@code @RequestMapping(\"/foo\")} is equivalent to * {@code @RequestMapping(path=\"/foo\")}. * <p>In a Portlet environment this is the mapped portlet modes * (i.e. \"EDIT\", \"VIEW\", \"HELP\" or any custom modes). * <p><b>Supported at the type level as well as at the method level!</b> * When used at the type level, all method-level mappings inherit * this primary mapping, narrowing it for a specific handler method. */ @AliasFor(\"path\") String[] value() default {}; /** * In a Servlet environment only: the path mapping URIs (e.g. \"/myPath.do\"). * Ant-style path patterns are also supported (e.g. \"/myPath/*.do\"). * At the method level, relative paths (e.g. \"edit.do\") are supported within * the primary mapping expressed at the type level. Path mapping URIs may * contain placeholders (e.g. \"/${connect}\") * <p><b>Supported at the type level as well as at the method level!</b> * When used at the type level, all method-level mappings inherit * this primary mapping, narrowing it for a specific handler method. * @see org.springframework.web.bind.annotation.ValueConstants#DEFAULT_NONE * @since 4.2 */ @AliasFor(\"value\") String[] path() default {}; /** * The HTTP request methods to map to, narrowing the primary mapping: * GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. * <p><b>Supported at the type level as well as at the method level!</b> * When used at the type level, all method-level mappings inherit * this HTTP method restriction (i.e. the type-level restriction * gets checked before the handler method is even resolved). * <p>Supported for Servlet environments as well as Portlet 2.0 environments. */ RequestMethod[] method() default {}; /** * The parameters of the mapped request, narrowing the primary mapping. * <p>Same format for any environment: a sequence of \"myParam=myValue\" style * expressions, with a request only mapped if each such parameter is found * to have the given value. Expressions can be negated by using the \"!=\" operator, * as in \"myParam!=myValue\". \"myParam\" style expressions are also supported, * with such parameters having to be present in the request (allowed to have * any value). Finally, \"!myParam\" style expressions indicate that the * specified parameter is <i>not</i> supposed to be present in the request. * <p><b>Supported at the type level as well as at the method level!</b> * When used at the type level, all method-level mappings inherit * this parameter restriction (i.e. the type-level restriction * gets checked before the handler method is even resolved). * <p>In a Servlet environment, parameter mappings are considered as restrictions * that are enforced at the type level. The primary path mapping (i.e. the * specified URI value) still has to uniquely identify the target handler, with * parameter mappings simply expressing preconditions for invoking the handler. * <p>In a Portlet environment, parameters are taken into account as mapping * differentiators, i.e. the primary portlet mode mapping plus the parameter * conditions uniquely identify the target handler. Different handlers may be * mapped onto the same portlet mode, as long as their parameter mappings differ. */ String[] params() default {}; /** * The headers of the mapped request, narrowing the primary mapping. * <p>Same format for any environment: a sequence of \"My-Header=myValue\" style * expressions, with a request only mapped if each such header is found * to have the given value. Expressions can be negated by using the \"!=\" operator, * as in \"My-Header!=myValue\". \"My-Header\" style expressions are also supported, * with such headers having to be present in the request (allowed to have * any value). Finally, \"!My-Header\" style expressions indicate that the * specified header is <i>not</i> supposed to be present in the request. * <p>Also supports media type wildcards (*), for headers such as Accept * and Content-Type. For instance, * <pre class=\"code\"> * &#064;RequestMapping(value = \"/something\", headers = \"content-type=text/*\") * </pre> * will match requests with a Content-Type of \"text/html\", \"text/plain\", etc. * <p><b>Supported at the type level as well as at the method level!</b> * When used at the type level, all method-level mappings inherit * this header restriction (i.e. the type-level restriction * gets checked before the handler method is even resolved). * <p>Maps against HttpServletRequest headers in a Servlet environment, * and against PortletRequest properties in a Portlet 2.0 environment. * @see org.springframework.http.MediaType */ String[] headers() default {}; /** * The consumable media types of the mapped request, narrowing the primary mapping. * <p>The format is a single media type or a sequence of media types, * with a request only mapped if the {@code Content-Type} matches one of these media types. * Examples: * <pre class=\"code\"> * consumes = \"text/plain\" * consumes = {\"text/plain\", \"application/*\"} * </pre> * Expressions can be negated by using the \"!\" operator, as in \"!text/plain\", which matches * all requests with a {@code Content-Type} other than \"text/plain\". * <p><b>Supported at the type level as well as at the method level!</b> * When used at the type level, all method-level mappings override * this consumes restriction. * @see org.springframework.http.MediaType * @see javax.servlet.http.HttpServletRequest#getContentType() */ String[] consumes() default {}; /** * The producible media types of the mapped request, narrowing the primary mapping. * <p>The format is a single media type or a sequence of media types, * with a request only mapped if the {@code Accept} matches one of these media types. * Examples: * <pre class=\"code\"> * produces = \"text/plain\" * produces = {\"text/plain\", \"application/*\"} * produces = \"application/json; charset=UTF-8\" * </pre> * <p>It affects the actual content type written, for example to produce a JSON response * with UTF-8 encoding, {@code \"application/json; charset=UTF-8\"} should be used. * <p>Expressions can be negated by using the \"!\" operator, as in \"!text/plain\", which matches * all requests with a {@code Accept} other than \"text/plain\". * <p><b>Supported at the type level as well as at the method level!</b> * When used at the type level, all method-level mappings override * this produces restriction. * @see org.springframework.http.MediaType */ String[] produces() default {};} @GetMapping此注解,接收前端为get请求的相关方法,接口返回天生具有幂等性,每次请求参数一致返回的结果也一致 此注解请求一般为获取相关信息的方法 有如下参数, 12345678910111213141516171819202122232425262728293031323334353637383940414243@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documented@RequestMapping(method = RequestMethod.GET)public @interface GetMapping { /** * Alias for {@link RequestMapping#name}. */ @AliasFor(annotation = RequestMapping.class) String name() default \"\"; /** * Alias for {@link RequestMapping#value}. */ @AliasFor(annotation = RequestMapping.class) String[] value() default {}; /** * Alias for {@link RequestMapping#path}. */ @AliasFor(annotation = RequestMapping.class) String[] path() default {}; /** * Alias for {@link RequestMapping#params}. */ @AliasFor(annotation = RequestMapping.class) String[] params() default {}; /** * Alias for {@link RequestMapping#headers}. */ @AliasFor(annotation = RequestMapping.class) String[] headers() default {}; /** * Alias for {@link RequestMapping#produces}. */ @AliasFor(annotation = RequestMapping.class) String[] produces() default {};} @PostMapping此注解,接收前端为post请求的相关方法 一般为保存,创建信息的方法,save…,create… @putMapping此注解,接收前端为put请求的相关方法 一般为更新数据的接口方法,update… @deleteMapping此注解,接收前端为delete请求的相关方法 一般为删除数据的方法 @RequestBody此注解放入接口方法的参数前面,对应请求中的body里的内容,要求body内容为json格式 例如: 1public Object create(@RequestBody UserEntityForm form) {}; @PathVariable此注解放入接口方法的参数前面,要求里面的值出现在Mapping中,以{}包裹,如下 接受参数required,设置判断此字段是否必须 12@GetMapping(\"{id}\")public UserView userInfoById(@PathVariable(\"id\",required = true) Integer id) {} @RequestParam此注解放入接口方法的参数前面,前端放入请求参数中,非body里面 接受参数required,设置判断此字段是否必须 defaultValue 设置此字段的默认值 1public UserView userInfoById(@RequestParam(value = \"id\", required = false, defaultValue = \"1\") Integer id){} 所有的接口方法都应该设计为幂等性,即接口请求多次或一次都应该达到同样的效果。此特性在高并发下面非常适用。 高并发的核心技术 - 幂等的实现方案一、背景我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。 例如: 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果。 2. 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱; 3. 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的; 4. 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题。 等等很多重要的情况,这些逻辑都需要幂等的特性来支持。 二、幂等性概念幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数. 更复杂的操作幂等保证是利用唯一交易号(流水号)实现. 我的理解:幂等就是一个操作,不论执行多少次,产生的效果和返回的结果都是一样的 三、技术方案 查询操作 查询一次和查询多次,在数据不变的情况下,查询结果是一样的。select是天然的幂等操作 删除操作 删除操作也是幂等的,删除一次和多次删除都是把数据删除。(注意可能返回结果不一样,删除的数据不存在,返回0,删除的数据多条,返回结果多个) 3.唯一索引,防止新增脏数据 比如:支付宝的资金账户,支付宝也有用户账户,每个用户只能有一个资金账户,怎么防止给用户创建资金账户多个,那么给资金账户表中的用户ID加唯一索引,所以一个用户新增成功一个资金账户记录 要点: 唯一索引或唯一组合索引来防止新增数据存在脏数据 (当表存在唯一索引,并发时新增报错时,再查询一次就可以了,数据应该已经存在了,返回结果即可) token机制,防止页面重复提交 业务要求: 页面的数据只能被点击提交一次 发生原因: 由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交 解决办法: 集群环境:采用token加redis(redis单线程的,处理需要排队) 单JVM环境:采用token加redis或token加jvm内存 处理流程: 1. 数据提交前要向服务的申请token,token放到redis或jvm内存,token有效时间 2. 提交后后台校验token,同时删除token,生成新的token返回 token特点: 要申请,一次有效性,可以限流 注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用 悲观锁 获取数据的时候加锁获取 select * from table_xxx where id=’xxx’ for update; 注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的 悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用 乐观锁 乐观锁只是在更新数据那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高。 乐观锁的实现方式多种多样可以通过version或者其他状态条件: 1. 通过版本号实现 update table_xxx set name=#name#,version=version+1 where version=#version# 如下图(来自网上): 通过条件限制 update tablexxx set avaiamount=avaiamount-#subAmount# where avaiamount-#subAmount# >= 0 要求:quality-#subQuality# >= ,这个情景适合不用版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高 注意:乐观锁的更新操作,最好用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表,上面两个sql改成下面的两个更好 update tablexxx set name=#name#,version=version+1 where id=#id# and version=#version# update tablexxx set avaiamount=avaiamount-#subAmount# where id=#id# and avai_amount-#subAmount# >= 0 分布式锁 还是拿插入数据的例子,如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。 要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供) select + insert 并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了 注意:核心高并发流程不要用这种方法 状态机幂等 在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。 注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助 对外提供接口的api如何保证幂等 如银联提供的付款接口:需要接入商户提交付款请求时附带:source来源,seq序列号 source+seq在数据库里面做唯一索引,防止多次付款,(并发时,只能处理一个请求) 重点对外提供接口为了支持幂等调用,接口有两个字段必须传,一个是来源source,一个是来源方序列号seq,这个两个字段在提供方系统里面做联合唯一索引,这样当第三方调用时,先在本方系统里面查询一下,是否已经处理过,返回相应处理结果;没有处理过,进行相应处理,返回结果。注意,为了幂等友好,一定要先查询一下,是否处理过该笔业务,不查询直接插入业务系统,会报错,但实际已经处理了。 总结幂等性应该是合格程序员的一个基因,在设计系统时,是首要考虑的问题,尤其是在像支付宝,银行,互联网金融公司等涉及的都是钱的系统,既要高效,数据也要准确,所以不能出现多扣款,多打款等问题,这样会很难处理,用户体验也不好 参考自","link":"/design-architecture/restful-api-%E8%AE%BE%E8%AE%A1%E4%BB%A5%E5%8F%8A%E5%B9%82%E7%AD%89%E6%80%A7%E7%9B%B8%E5%85%B3%E8%AE%BE%E8%AE%A1.html"},{"title":"一千行 MySQL 学习笔记(转载)","text":"摘要以下为本人初学 MySQL 时做的笔记,也从那时起没再更新过,但还是囊括了基本的知识点,有时还翻出来查查。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044/* Windows服务 */-- 启动MySQL net start mysql-- 创建Windows服务 sc create mysql binPath= mysqld_bin_path(注意:等号与值之间有空格)/* 连接与断开服务器 */mysql -h 地址 -P 端口 -u 用户名 -p 密码SHOW PROCESSLIST -- 显示哪些线程正在运行SHOW VARIABLES -- 显示系统变量信息/* 数据库操作 */ -------------------- 查看当前数据库 SELECT DATABASE();-- 显示当前时间、用户名、数据库版本 SELECT now(), user(), version();-- 创建库 CREATE DATABASE[ IF NOT EXISTS] 数据库名 数据库选项 数据库选项: CHARACTER SET charset_name COLLATE collation_name-- 查看已有库 SHOW DATABASES[ LIKE 'PATTERN']-- 查看当前库信息 SHOW CREATE DATABASE 数据库名-- 修改库的选项信息 ALTER DATABASE 库名 选项信息-- 删除库 DROP DATABASE[ IF EXISTS] 数据库名 同时删除该数据库相关的目录及其目录内容/* 表的操作 */ -------------------- 创建表 CREATE [TEMPORARY] TABLE[ IF NOT EXISTS] [库名.]表名 ( 表的结构定义 )[ 表选项] 每个字段必须有数据类型 最后一个字段后不能有逗号 TEMPORARY 临时表,会话结束时表自动消失 对于字段的定义: 字段名 数据类型 [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string']-- 表选项 -- 字符集 CHARSET = charset_name 如果表没有设定,则使用数据库字符集 -- 存储引擎 ENGINE = engine_name 表在管理数据时采用的不同的数据结构,结构不同会导致处理方式、提供的特性操作等不同 常见的引擎:InnoDB MyISAM Memory/Heap BDB Merge Example CSV MaxDB Archive 不同的引擎在保存表的结构和数据时采用不同的方式 MyISAM表文件含义:.frm表定义,.MYD表数据,.MYI表索引 InnoDB表文件含义:.frm表定义,表空间数据和日志文件 SHOW ENGINES -- 显示存储引擎的状态信息 SHOW ENGINE 引擎名 {LOGS|STATUS} -- 显示存储引擎的日志或状态信息 -- 自增起始数 AUTO_INCREMENT = 行数 -- 数据文件目录 DATA DIRECTORY = '目录' -- 索引文件目录 INDEX DIRECTORY = '目录' -- 表注释 COMMENT = 'string' -- 分区选项 PARTITION BY ... (详细见手册)-- 查看所有表 SHOW TABLES[ LIKE 'pattern'] SHOW TABLES FROM 表名-- 查看表机构 SHOW CREATE TABLE 表名 (信息更详细) DESC 表名 / DESCRIBE 表名 / EXPLAIN 表名 / SHOW COLUMNS FROM 表名 [LIKE 'PATTERN'] SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']-- 修改表 -- 修改表本身的选项 ALTER TABLE 表名 表的选项 eg: ALTER TABLE 表名 ENGINE=MYISAM; -- 对表进行重命名 RENAME TABLE 原表名 TO 新表名 RENAME TABLE 原表名 TO 库名.表名 (可将表移动到另一个数据库) -- RENAME可以交换两个表名 -- 修改表的字段机构(13.1.2. ALTER TABLE语法) ALTER TABLE 表名 操作名 -- 操作名 ADD[ COLUMN] 字段定义 -- 增加字段 AFTER 字段名 -- 表示增加在该字段名后面 FIRST -- 表示增加在第一个 ADD PRIMARY KEY(字段名) -- 创建主键 ADD UNIQUE [索引名] (字段名)-- 创建唯一索引 ADD INDEX [索引名] (字段名) -- 创建普通索引 DROP[ COLUMN] 字段名 -- 删除字段 MODIFY[ COLUMN] 字段名 字段属性 -- 支持对字段属性进行修改,不能修改字段名(所有原有属性也需写上) CHANGE[ COLUMN] 原字段名 新字段名 字段属性 -- 支持对字段名修改 DROP PRIMARY KEY -- 删除主键(删除主键前需删除其AUTO_INCREMENT属性) DROP INDEX 索引名 -- 删除索引 DROP FOREIGN KEY 外键 -- 删除外键-- 删除表 DROP TABLE[ IF EXISTS] 表名 ...-- 清空表数据 TRUNCATE [TABLE] 表名-- 复制表结构 CREATE TABLE 表名 LIKE 要复制的表名-- 复制表结构和数据 CREATE TABLE 表名 [AS] SELECT * FROM 要复制的表名-- 检查表是否有错误 CHECK TABLE tbl_name [, tbl_name] ... [option] ...-- 优化表 OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...-- 修复表 REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]-- 分析表 ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] .../* 数据操作 */ -------------------- 增 INSERT [INTO] 表名 [(字段列表)] VALUES (值列表)[, (值列表), ...] -- 如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表。 -- 可同时插入多条数据记录! REPLACE 与 INSERT 完全一样,可互换。 INSERT [INTO] 表名 SET 字段名=值[, 字段名=值, ...]-- 查 SELECT 字段列表 FROM 表名[ 其他子句] -- 可来自多个表的多个字段 -- 其他子句可以不使用 -- 字段列表可以用*代替,表示所有字段-- 删 DELETE FROM 表名[ 删除条件子句] 没有条件子句,则会删除全部-- 改 UPDATE 表名 SET 字段名=新值[, 字段名=新值] [更新条件]/* 字符集编码 */ -------------------- MySQL、数据库、表、字段均可设置编码-- 数据编码与客户端编码不需一致SHOW VARIABLES LIKE 'character_set_%' -- 查看所有字符集编码项 character_set_client 客户端向服务器发送数据时使用的编码 character_set_results 服务器端将结果返回给客户端所使用的编码 character_set_connection 连接层编码SET 变量名 = 变量值 SET character_set_client = gbk; SET character_set_results = gbk; SET character_set_connection = gbk;SET NAMES GBK; -- 相当于完成以上三个设置-- 校对集 校对集用以排序 SHOW CHARACTER SET [LIKE 'pattern']/SHOW CHARSET [LIKE 'pattern'] 查看所有字符集 SHOW COLLATION [LIKE 'pattern'] 查看所有校对集 CHARSET 字符集编码 设置字符集编码 COLLATE 校对集编码 设置校对集编码/* 数据类型(列类型) */ ------------------1. 数值类型-- a. 整型 ---------- 类型 字节 范围(有符号位) tinyint 1字节 -128 ~ 127 无符号位:0 ~ 255 smallint 2字节 -32768 ~ 32767 mediumint 3字节 -8388608 ~ 8388607 int 4字节 bigint 8字节 int(M) M表示总位数 - 默认存在符号位,unsigned 属性修改 - 显示宽度,如果某个数不够定义字段时设置的位数,则前面以0补填,zerofill 属性修改 例:int(5) 插入一个数'123',补填后为'00123' - 在满足要求的情况下,越小越好。 - 1表示bool值真,0表示bool值假。MySQL没有布尔类型,通过整型0和1表示。常用tinyint(1)表示布尔型。-- b. 浮点型 ---------- 类型 字节 范围 float(单精度) 4字节 double(双精度) 8字节 浮点型既支持符号位 unsigned 属性,也支持显示宽度 zerofill 属性。 不同于整型,前后均会补填0. 定义浮点型时,需指定总位数和小数位数。 float(M, D) double(M, D) M表示总位数,D表示小数位数。 M和D的大小会决定浮点数的范围。不同于整型的固定范围。 M既表示总位数(不包括小数点和正负号),也表示显示宽度(所有显示符号均包括)。 支持科学计数法表示。 浮点数表示近似值。-- c. 定点数 ---------- decimal -- 可变长度 decimal(M, D) M也表示总位数,D表示小数位数。 保存一个精确的数值,不会发生数据的改变,不同于浮点数的四舍五入。 将浮点数转换为字符串来保存,每9位数字保存为4个字节。2. 字符串类型-- a. char, varchar ---------- char 定长字符串,速度快,但浪费空间 varchar 变长字符串,速度慢,但节省空间 M表示能存储的最大长度,此长度是字符数,非字节数。 不同的编码,所占用的空间不同。 char,最多255个字符,与编码无关。 varchar,最多65535字符,与编码有关。 一条有效记录最大不能超过65535个字节。 utf8 最大为21844个字符,gbk 最大为32766个字符,latin1 最大为65532个字符 varchar 是变长的,需要利用存储空间保存 varchar 的长度,如果数据小于255个字节,则采用一个字节来保存长度,反之需要两个字节来保存。 varchar 的最大有效长度由最大行大小和使用的字符集确定。 最大有效长度是65532字节,因为在varchar存字符串时,第一个字节是空的,不存在任何数据,然后还需两个字节来存放字符串的长度,所以有效长度是64432-1-2=65532字节。 例:若一个表定义为 CREATE TABLE tb(c1 int, c2 char(30), c3 varchar(N)) charset=utf8; 问N的最大值是多少? 答:(65535-1-2-4-30*3)/3-- b. blob, text ---------- blob 二进制字符串(字节字符串) tinyblob, blob, mediumblob, longblob text 非二进制字符串(字符字符串) tinytext, text, mediumtext, longtext text 在定义时,不需要定义长度,也不会计算总长度。 text 类型在定义时,不可给default值-- c. binary, varbinary ---------- 类似于char和varchar,用于保存二进制字符串,也就是保存字节字符串而非字符字符串。 char, varchar, text 对应 binary, varbinary, blob.3. 日期时间类型 一般用整型保存时间戳,因为PHP可以很方便的将时间戳进行格式化。 datetime 8字节 日期及时间 1000-01-01 00:00:00 到 9999-12-31 23:59:59 date 3字节 日期 1000-01-01 到 9999-12-31 timestamp 4字节 时间戳 19700101000000 到 2038-01-19 03:14:07 time 3字节 时间 -838:59:59 到 838:59:59 year 1字节 年份 1901 - 2155datetime YYYY-MM-DD hh:mm:sstimestamp YY-MM-DD hh:mm:ss YYYYMMDDhhmmss YYMMDDhhmmss YYYYMMDDhhmmss YYMMDDhhmmssdate YYYY-MM-DD YY-MM-DD YYYYMMDD YYMMDD YYYYMMDD YYMMDDtime hh:mm:ss hhmmss hhmmssyear YYYY YY YYYY YY4. 枚举和集合-- 枚举(enum) ----------enum(val1, val2, val3...) 在已知的值中进行单选。最大数量为65535. 枚举值在保存时,以2个字节的整型(smallint)保存。每个枚举值,按保存的位置顺序,从1开始逐一递增。 表现为字符串类型,存储却是整型。 NULL值的索引是NULL。 空字符串错误值的索引值是0。-- 集合(set) ----------set(val1, val2, val3...) create table tab ( gender set('男', '女', '无') ); insert into tab values ('男, 女'); 最多可以有64个不同的成员。以bigint存储,共8个字节。采取位运算的形式。 当创建表时,SET成员值的尾部空格将自动被删除。/* 选择类型 */-- PHP角度1. 功能满足2. 存储空间尽量小,处理效率更高3. 考虑兼容问题-- IP存储 ----------1. 只需存储,可用字符串2. 如果需计算,查找等,可存储为4个字节的无符号int,即unsigned 1) PHP函数转换 ip2long可转换为整型,但会出现携带符号问题。需格式化为无符号的整型。 利用sprintf函数格式化字符串 sprintf(\"%u\", ip2long('192.168.3.134')); 然后用long2ip将整型转回IP字符串 2) MySQL函数转换(无符号整型,UNSIGNED) INET_ATON('127.0.0.1') 将IP转为整型 INET_NTOA(2130706433) 将整型转为IP/* 列属性(列约束) */ ------------------1. PRIMARY 主键 - 能唯一标识记录的字段,可以作为主键。 - 一个表只能有一个主键。 - 主键具有唯一性。 - 声明字段时,用 primary key 标识。 也可以在字段列表之后声明 例:create table tab ( id int, stu varchar(10), primary key (id)); - 主键字段的值不能为null。 - 主键可以由多个字段共同组成。此时需要在字段列表后声明的方法。 例:create table tab ( id int, stu varchar(10), age int, primary key (stu, age));2. UNIQUE 唯一索引(唯一约束) 使得某字段的值也不能重复。3. NULL 约束 null不是数据类型,是列的一个属性。 表示当前列是否可以为null,表示什么都没有。 null, 允许为空。默认。 not null, 不允许为空。 insert into tab values (null, 'val'); -- 此时表示将第一个字段的值设为null, 取决于该字段是否允许为null4. DEFAULT 默认值属性 当前字段的默认值。 insert into tab values (default, 'val'); -- 此时表示强制使用默认值。 create table tab ( add_time timestamp default current_timestamp ); -- 表示将当前时间的时间戳设为默认值。 current_date, current_time5. AUTO_INCREMENT 自动增长约束 自动增长必须为索引(主键或unique) 只能存在一个字段为自动增长。 默认为1开始自动增长。可以通过表属性 auto_increment = x进行设置,或 alter table tbl auto_increment = x;6. COMMENT 注释 例:create table tab ( id int ) comment '注释内容';7. FOREIGN KEY 外键约束 用于限制主表与从表数据完整性。 alter table t1 add constraint `t1_t2_fk` foreign key (t1_id) references t2(id); -- 将表t1的t1_id外键关联到表t2的id字段。 -- 每个外键都有一个名字,可以通过 constraint 指定 存在外键的表,称之为从表(子表),外键指向的表,称之为主表(父表)。 作用:保持数据一致性,完整性,主要目的是控制存储在外键表(从表)中的数据。 MySQL中,可以对InnoDB引擎使用外键约束: 语法: foreign key (外键字段) references 主表名 (关联字段) [主表记录删除时的动作] [主表记录更新时的动作] 此时需要检测一个从表的外键需要约束为主表的已存在的值。外键在没有关联的情况下,可以设置为null.前提是该外键列,没有not null。 可以不指定主表记录更改或更新时的动作,那么此时主表的操作被拒绝。 如果指定了 on update 或 on delete:在删除或更新时,有如下几个操作可以选择: 1. cascade,级联操作。主表数据被更新(主键值更新),从表也被更新(外键值更新)。主表记录被删除,从表相关记录也被删除。 2. set null,设置为null。主表数据被更新(主键值更新),从表的外键被设置为null。主表记录被删除,从表相关记录外键被设置成null。但注意,要求该外键列,没有not null属性约束。 3. restrict,拒绝父表删除和更新。 注意,外键只被InnoDB存储引擎所支持。其他引擎是不支持的。/* 建表规范 */ ------------------ -- Normal Format, NF - 每个表保存一个实体信息 - 每个具有一个ID字段作为主键 - ID主键 + 原子表 -- 1NF, 第一范式 字段不能再分,就满足第一范式。 -- 2NF, 第二范式 满足第一范式的前提下,不能出现部分依赖。 消除符合主键就可以避免部分依赖。增加单列关键字。 -- 3NF, 第三范式 满足第二范式的前提下,不能出现传递依赖。 某个字段依赖于主键,而有其他字段依赖于该字段。这就是传递依赖。 将一个实体信息的数据放在一个表内实现。/* SELECT */ ------------------SELECT [ALL|DISTINCT] select_expr FROM -> WHERE -> GROUP BY [合计函数] -> HAVING -> ORDER BY -> LIMITa. select_expr -- 可以用 * 表示所有字段。 select * from tb; -- 可以使用表达式(计算公式、函数调用、字段也是个表达式) select stu, 29+25, now() from tb; -- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。 - 使用 as 关键字,也可省略 as. select stu+10 as add10 from tb;b. FROM 子句 用于标识查询来源。 -- 可以为表起别名。使用as关键字。 SELECT * FROM tb1 AS tt, tb2 AS bb; -- from子句后,可以同时出现多个表。 -- 多个表会横向叠加到一起,而数据会形成一个笛卡尔积。 SELECT * FROM tb1, tb2; -- 向优化符提示如何选择索引 USE INDEX、IGNORE INDEX、FORCE INDEX SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3; SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3;c. WHERE 子句 -- 从from获得的数据源中进行筛选。 -- 整型1表示真,0表示假。 -- 表达式由运算符和运算数组成。 -- 运算数:变量(字段)、值、函数返回值 -- 运算符: =, <=>, <>, !=, <=, <, >=, >, !, &&, ||, in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor is/is not 加上ture/false/unknown,检验某个值的真假 <=>与<>功能相同,<=>可用于null比较d. GROUP BY 子句, 分组子句 GROUP BY 字段/别名 [排序方式] 分组后会进行排序。升序:ASC,降序:DESC 以下[合计函数]需配合 GROUP BY 使用: count 返回不同的非NULL值数目 count(*)、count(字段) sum 求和 max 求最大值 min 求最小值 avg 求平均值 group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。e. HAVING 子句,条件子句 与 where 功能、用法相同,执行时机不同。 where 在开始时执行检测数据,对原数据进行过滤。 having 对筛选出的结果再次进行过滤。 having 字段必须是查询出来的,where 字段必须是数据表存在的。 where 不可以使用字段的别名,having 可以。因为执行WHERE代码时,可能尚未确定列值。 where 不可以使用合计函数。一般需用合计函数才会用 having SQL标准要求HAVING必须引用GROUP BY子句中的列或用于合计函数中的列。f. ORDER BY 子句,排序子句 order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]... 升序:ASC,降序:DESC 支持多个字段的排序。g. LIMIT 子句,限制结果数量子句 仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。 limit 起始位置, 获取条数 省略第一个参数,表示从索引0开始。limit 获取条数h. DISTINCT, ALL 选项 distinct 去除重复记录 默认为 all, 全部记录/* UNION */ ------------------ 将多个select查询的结果组合成一个结果集合。 SELECT ... UNION [ALL|DISTINCT] SELECT ... 默认 DISTINCT 方式,即所有返回的行都是唯一的 建议,对每个SELECT查询加上小括号包裹。 ORDER BY 排序时,需加上 LIMIT 进行结合。 需要各select查询的字段数量一样。 每个select查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条select语句为准。/* 子查询 */ ------------------ - 子查询需用括号包裹。-- from型 from后要求是一个表,必须给子查询结果取个别名。 - 简化每个查询内的条件。 - from型需将结果生成一个临时表格,可用以原表的锁定的释放。 - 子查询返回一个表,表型子查询。 select * from (select * from tb where id>0) as subfrom where id>1;-- where型 - 子查询返回一个值,标量子查询。 - 不需要给子查询取别名。 - where子查询内的表,不能直接用以更新。 select * from tb where money = (select max(money) from tb); -- 列子查询 如果子查询结果返回的是一列。 使用 in 或 not in 完成查询 exists 和 not exists 条件 如果子查询返回数据,则返回1或0。常用于判断条件。 select column1 from t1 where exists (select * from t2); -- 行子查询 查询条件是一个行。 select * from t1 where (id, gender) in (select id, gender from t2); 行构造符:(col1, col2, ...) 或 ROW(col1, col2, ...) 行构造符通常用于与对能返回两个或两个以上列的子查询进行比较。 -- 特殊运算符 != all() 相当于 not in = some() 相当于 in。any 是 some 的别名 != some() 不等同于 not in,不等于其中某一个。 all, some 可以配合其他运算符一起使用。/* 连接查询(join) */ ------------------ 将多个表的字段进行连接,可以指定连接条件。-- 内连接(inner join) - 默认就是内连接,可省略inner。 - 只有数据存在时才能发送连接。即连接结果不能出现空行。 on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真) 也可用where表示连接条件。 还有 using, 但需字段名相同。 using(字段名) -- 交叉连接 cross join 即,没有条件的内连接。 select * from tb1 cross join tb2;-- 外连接(outer join) - 如果数据不存在,也会出现在连接结果中。 -- 左外连接 left join 如果数据不存在,左表记录会出现,而右表为null填充 -- 右外连接 right join 如果数据不存在,右表记录会出现,而左表为null填充-- 自然连接(natural join) 自动判断连接条件完成连接。 相当于省略了using,会自动查找相同字段名。 natural join natural left join natural right joinselect info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;/* 导入导出 */ ------------------select * into outfile 文件地址 [控制格式] from 表名; -- 导出表数据load data [local] infile 文件地址 [replace|ignore] into table 表名 [控制格式]; -- 导入数据 生成的数据默认的分隔符是制表符 local未指定,则数据文件必须在服务器上 replace 和 ignore 关键词控制对现有的唯一键记录的重复的处理-- 控制格式fields 控制字段格式默认:fields terminated by '\\t' enclosed by '' escaped by '\\\\' terminated by 'string' -- 终止 enclosed by 'char' -- 包裹 escaped by 'char' -- 转义 -- 示例: SELECT a,b,a+b INTO OUTFILE '/tmp/result.text' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\\n' FROM test_table;lines 控制行格式默认:lines terminated by '\\n' terminated by 'string' -- 终止/* INSERT */ ------------------select语句获得的数据可以用insert插入。可以省略对列的指定,要求 values () 括号内,提供给了按照列顺序出现的所有字段的值。 或者使用set语法。 INSERT INTO tbl_name SET field=value,...;可以一次性使用多个值,采用(), (), ();的形式。 INSERT INTO tbl_name VALUES (), (), ();可以在列值指定时,使用表达式。 INSERT INTO tbl_name VALUES (field_value, 10+10, now());可以使用一个特殊值 DEFAULT,表示该列使用默认值。 INSERT INTO tbl_name VALUES (field_value, DEFAULT);可以通过一个查询的结果,作为需要插入的值。 INSERT INTO tbl_name SELECT ...;可以指定在插入的值出现主键(或唯一索引)冲突时,更新其他非主键列的信息。 INSERT INTO tbl_name VALUES/SET/SELECT ON DUPLICATE KEY UPDATE 字段=值, …;/* DELETE */ ------------------DELETE FROM tbl_name [WHERE where_definition] [ORDER BY ...] [LIMIT row_count]按照条件删除。where指定删除的最多记录数。limit可以通过排序条件删除。order by + limit支持多表删除,使用类似连接语法。delete from 需要删除数据多表1,表2 using 表连接操作 条件。/* TRUNCATE */ ------------------TRUNCATE [TABLE] tbl_name清空数据删除重建表区别:1,truncate 是删除表再创建,delete 是逐条删除2,truncate 重置auto_increment的值。而delete不会3,truncate 不知道删除了几条,而delete知道。4,当被用于带分区的表时,truncate 会保留分区/* 备份与还原 */ ------------------备份,将数据的结构与表内数据保存起来。利用 mysqldump 指令完成。-- 导出mysqldump [options] db_name [tables]mysqldump [options] ---database DB1 [DB2 DB3...]mysqldump [options] --all--database1. 导出一张表 mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)2. 导出多张表 mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql)3. 导出所有表 mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)4. 导出一个库 mysqldump -u用户名 -p密码 --lock-all-tables --database 库名 > 文件名(D:/a.sql)可以-w携带WHERE条件-- 导入1. 在登录mysql的情况下: source 备份文件2. 在不登录的情况下 mysql -u用户名 -p密码 库名 < 备份文件/* 视图 */ ------------------什么是视图: 视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。 视图具有表结构文件,但不存在数据文件。 对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。 视图是存储在数据库中的查询的sql语句,它主要出于两种原因:安全原因,视图可以隐藏一些数据,如:社会保险基金表,可以用视图只显示姓名,地址,而不显示社会保险号和工资数等,另一原因是可使复杂的查询易于理解和使用。-- 创建视图CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement - 视图名必须唯一,同时不能与表重名。 - 视图可以使用select语句查询到的列名,也可以自己指定相应的列名。 - 可以指定视图执行的算法,通过ALGORITHM指定。 - column_list如果存在,则数目必须等于SELECT语句检索的列数-- 查看结构 SHOW CREATE VIEW view_name-- 删除视图 - 删除视图后,数据依然存在。 - 可同时删除多个视图。 DROP VIEW [IF EXISTS] view_name ...-- 修改视图结构 - 一般不修改视图,因为不是所有的更新视图都会映射到表上。 ALTER VIEW view_name [(column_list)] AS select_statement-- 视图作用 1. 简化业务逻辑 2. 对客户端隐藏真实的表结构-- 视图算法(ALGORITHM) MERGE 合并 将视图的查询语句,与外部查询需要先合并再执行! TEMPTABLE 临时表 将视图执行完毕后,形成临时表,再做外层查询! UNDEFINED 未定义(默认),指的是MySQL自主去选择相应的算法。/* 事务(transaction) */ ------------------事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。 - 支持连续SQL的集体成功或集体撤销。 - 事务是数据库在数据晚自习方面的一个功能。 - 需要利用 InnoDB 或 BDB 存储引擎,对自动提交的特性支持完成。 - InnoDB被称为事务安全型引擎。-- 事务开启 START TRANSACTION; 或者 BEGIN; 开启事务后,所有被执行的SQL语句均被认作当前事务内的SQL语句。-- 事务提交 COMMIT;-- 事务回滚 ROLLBACK; 如果部分操作发生问题,映射到事务开启前。-- 事务的特性 1. 原子性(Atomicity) 事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 2. 一致性(Consistency) 事务前后数据的完整性必须保持一致。 - 事务开始和结束时,外部数据一致 - 在整个事务过程中,操作是连续的 3. 隔离性(Isolation) 多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。 4. 持久性(Durability) 一个事务一旦被提交,它对数据库中的数据改变就是永久性的。-- 事务的实现 1. 要求是事务支持的表类型 2. 执行一组相关的操作前开启事务 3. 整组操作完成后,都成功,则提交;如果存在失败,选择回滚,则会回到事务开始的备份点。-- 事务的原理 利用InnoDB的自动提交(autocommit)特性完成。 普通的MySQL执行语句后,当前的数据提交操作均可被其他客户端可见。 而事务是暂时关闭“自动提交”机制,需要commit提交持久化数据操作。-- 注意 1. 数据定义语言(DDL)语句不能被回滚,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。 2. 事务不能被嵌套-- 保存点 SAVEPOINT 保存点名称 -- 设置一个事务保存点 ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点 RELEASE SAVEPOINT 保存点名称 -- 删除保存点-- InnoDB自动提交特性设置 SET autocommit = 0|1; 0表示关闭自动提交,1表示开启自动提交。 - 如果关闭了,那普通操作的结果对其他客户端也不可见,需要commit提交后才能持久化数据操作。 - 也可以关闭自动提交来开启事务。但与START TRANSACTION不同的是, SET autocommit是永久改变服务器的设置,直到下次再次修改该设置。(针对当前连接) 而START TRANSACTION记录开启前的状态,而一旦事务提交或回滚后就需要再次开启事务。(针对当前事务)/* 锁表 */表锁定只用于防止其它客户端进行不正当地读取和写入MyISAM 支持表锁,InnoDB 支持行锁-- 锁定 LOCK TABLES tbl_name [AS alias]-- 解锁 UNLOCK TABLES/* 触发器 */ ------------------ 触发程序是与表有关的命名数据库对象,当该表出现特定事件时,将激活该对象 监听:记录的增加、修改、删除。-- 创建触发器CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt 参数: trigger_time是触发程序的动作时间。它可以是 before 或 after,以指明触发程序是在激活它的语句之前或之后触发。 trigger_event指明了激活触发程序的语句的类型 INSERT:将新行插入表时激活触发程序 UPDATE:更改某一行时激活触发程序 DELETE:从表中删除某一行时激活触发程序 tbl_name:监听的表,必须是永久性的表,不能将触发程序与TEMPORARY表或视图关联起来。 trigger_stmt:当触发程序激活时执行的语句。执行多个语句,可使用BEGIN...END复合语句结构-- 删除DROP TRIGGER [schema_name.]trigger_name可以使用old和new代替旧的和新的数据 更新操作,更新前是old,更新后是new. 删除操作,只有old. 增加操作,只有new.-- 注意 1. 对于具有相同触发程序动作时间和事件的给定表,不能有两个触发程序。-- 字符连接函数concat(str1,str2,...])concat_ws(separator,str1,str2,...)-- 分支语句if 条件 then 执行语句elseif 条件 then 执行语句else 执行语句end if;-- 修改最外层语句结束符delimiter 自定义结束符号 SQL语句自定义结束符号delimiter ; -- 修改回原来的分号-- 语句块包裹begin 语句块end-- 特殊的执行1. 只要添加记录,就会触发程序。2. Insert into on duplicate key update 语法会触发: 如果没有重复记录,会触发 before insert, after insert; 如果有重复记录并更新,会触发 before insert, before update, after update; 如果有重复记录但是没有发生更新,则触发 before insert, before update3. Replace 语法 如果有记录,则执行 before insert, before delete, after delete, after insert/* SQL编程 */ --------------------// 局部变量 ------------ 变量声明 declare var_name[,...] type [default value] 这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个default子句。值可以被指定为一个表达式,不需要为一个常数。如果没有default子句,初始值为null。-- 赋值 使用 set 和 select into 语句为变量赋值。 - 注意:在函数内是可以使用全局变量(用户自定义的变量)--// 全局变量 ------------ 定义、赋值set 语句可以定义并为变量赋值。set @var = value;也可以使用select into语句为变量初始化并赋值。这样要求select语句只能返回一行,但是可以是多个字段,就意味着同时为多个变量进行赋值,变量的数量需要与查询的列数一致。还可以把赋值语句看作一个表达式,通过select执行完成。此时为了避免=被当作关系运算符看待,使用:=代替。(set语句可以使用= 和 :=)。select @var:=20;select @v1:=id, @v2=name from t1 limit 1;select * from tbl_name where @var:=30;select into 可以将表中查询获得的数据赋给变量。 -| select max(height) into @max_height from tb;-- 自定义变量名为了避免select语句中,用户自定义的变量与系统标识符(通常是字段名)冲突,用户自定义变量在变量名前使用@作为开始符号。@var=10; - 变量被定义后,在整个会话周期都有效(登录到退出)--// 控制结构 ------------ if语句if search_condition then statement_list [elseif search_condition then statement_list]...[else statement_list]end if;-- case语句CASE value WHEN [compare-value] THEN result[WHEN [compare-value] THEN result ...][ELSE result]END-- while循环[begin_label:] while search_condition do statement_listend while [end_label];- 如果需要在循环内提前终止 while循环,则需要使用标签;标签需要成对出现。 -- 退出循环 退出整个循环 leave 退出当前循环 iterate 通过退出的标签决定退出哪个循环--// 内置函数 ------------ 数值函数abs(x) -- 绝对值 abs(-10.9) = 10format(x, d) -- 格式化千分位数值 format(1234567.456, 2) = 1,234,567.46ceil(x) -- 向上取整 ceil(10.1) = 11floor(x) -- 向下取整 floor (10.1) = 10round(x) -- 四舍五入去整mod(m, n) -- m%n m mod n 求余 10%3=1pi() -- 获得圆周率pow(m, n) -- m^nsqrt(x) -- 算术平方根rand() -- 随机数truncate(x, d) -- 截取d位小数-- 时间日期函数now(), current_timestamp(); -- 当前日期时间current_date(); -- 当前日期current_time(); -- 当前时间date('yyyy-mm-dd hh:ii:ss'); -- 获取日期部分time('yyyy-mm-dd hh:ii:ss'); -- 获取时间部分date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j'); -- 格式化时间unix_timestamp(); -- 获得unix时间戳from_unixtime(); -- 从时间戳获得时间-- 字符串函数length(string) -- string长度,字节char_length(string) -- string的字符个数substring(str, position [,length]) -- 从str的position开始,取length个字符replace(str ,search_str ,replace_str) -- 在str中用replace_str替换search_strinstr(string ,substring) -- 返回substring首次在string中出现的位置concat(string [,...]) -- 连接字串charset(str) -- 返回字串字符集lcase(string) -- 转换成小写left(string, length) -- 从string2中的左边起取length个字符load_file(file_name) -- 从文件读取内容locate(substring, string [,start_position]) -- 同instr,但可指定开始位置lpad(string, length, pad) -- 重复用pad加在string开头,直到字串长度为lengthltrim(string) -- 去除前端空格repeat(string, count) -- 重复count次rpad(string, length, pad) --在str后用pad补充,直到长度为lengthrtrim(string) -- 去除后端空格strcmp(string1 ,string2) -- 逐字符比较两字串大小-- 流程函数case when [condition] then result [when [condition] then result ...] [else result] end 多分支if(expr1,expr2,expr3) 双分支。-- 聚合函数count()sum();max();min();avg();group_concat()-- 其他常用函数md5();default();--// 存储函数,自定义函数 ------------ 新建 CREATE FUNCTION function_name (参数列表) RETURNS 返回值类型 函数体 - 函数名,应该合法的标识符,并且不应该与已有的关键字冲突。 - 一个函数应该属于某个数据库,可以使用db_name.funciton_name的形式执行当前函数所属数据库,否则为当前数据库。 - 参数部分,由\"参数名\"和\"参数类型\"组成。多个参数用逗号隔开。 - 函数体由多条可用的mysql语句,流程控制,变量声明等语句构成。 - 多条语句应该使用 begin...end 语句块包含。 - 一定要有 return 返回值语句。-- 删除 DROP FUNCTION [IF EXISTS] function_name;-- 查看 SHOW FUNCTION STATUS LIKE 'partten' SHOW CREATE FUNCTION function_name;-- 修改 ALTER FUNCTION function_name 函数选项--// 存储过程,自定义功能 ------------ 定义存储存储过程 是一段代码(过程),存储在数据库中的sql组成。一个存储过程通常用于完成一段业务逻辑,例如报名,交班费,订单入库等。而一个函数通常专注与某个功能,视为其他程序服务的,需要在其他语句中调用函数才可以,而存储过程不能被其他调用,是自己执行 通过call执行。-- 创建CREATE PROCEDURE sp_name (参数列表) 过程体参数列表:不同于函数的参数列表,需要指明参数类型IN,表示输入型OUT,表示输出型INOUT,表示混合型注意,没有返回值。/* 存储过程 */ ------------------存储过程是一段可执行性代码的集合。相比函数,更偏向于业务逻辑。调用:CALL 过程名-- 注意- 没有返回值。- 只能单独调用,不可夹杂在其他语句中-- 参数IN|OUT|INOUT 参数名 数据类型IN 输入:在调用过程中,将数据输入到过程体内部的参数OUT 输出:在调用过程中,将过程体处理完的结果返回到客户端INOUT 输入输出:既可输入,也可输出-- 语法CREATE PROCEDURE 过程名 (参数列表)BEGIN 过程体END/* 用户和权限管理 */ -------------------- root密码重置1. 停止MySQL服务2. [Linux] /usr/local/mysql/bin/safe_mysqld --skip-grant-tables & [Windows] mysqld --skip-grant-tables3. use mysql;4. UPDATE `user` SET PASSWORD=PASSWORD(\"密码\") WHERE `user` = \"root\";5. FLUSH PRIVILEGES;用户信息表:mysql.user-- 刷新权限FLUSH PRIVILEGES;-- 增加用户CREATE USER 用户名 IDENTIFIED BY [PASSWORD] 密码(字符串) - 必须拥有mysql数据库的全局CREATE USER权限,或拥有INSERT权限。 - 只能创建用户,不能赋予权限。 - 用户名,注意引号:如 'user_name'@'192.168.1.1' - 密码也需引号,纯数字密码也要加引号 - 要在纯文本中指定密码,需忽略PASSWORD关键词。要把密码指定为由PASSWORD()函数返回的混编值,需包含关键字PASSWORD-- 重命名用户RENAME USER old_user TO new_user-- 设置密码SET PASSWORD = PASSWORD('密码') -- 为当前用户设置密码SET PASSWORD FOR 用户名 = PASSWORD('密码') -- 为指定用户设置密码-- 删除用户DROP USER 用户名-- 分配权限/添加用户GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password'] - all privileges 表示所有权限 - *.* 表示所有库的所有表 - 库名.表名 表示某库下面的某表 GRANT ALL PRIVILEGES ON `pms`.* TO 'pms'@'%' IDENTIFIED BY 'pms0817';-- 查看权限SHOW GRANTS FOR 用户名 -- 查看当前用户权限 SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER();-- 撤消权限REVOKE 权限列表 ON 表名 FROM 用户名REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用户名 -- 撤销所有权限-- 权限层级-- 要使用GRANT或REVOKE,您必须拥有GRANT OPTION权限,并且您必须用于您正在授予或撤销的权限。全局层级:全局权限适用于一个给定服务器中的所有数据库,mysql.user GRANT ALL ON *.*和 REVOKE ALL ON *.*只授予和撤销全局权限。数据库层级:数据库权限适用于一个给定数据库中的所有目标,mysql.db, mysql.host GRANT ALL ON db_name.*和REVOKE ALL ON db_name.*只授予和撤销数据库权限。表层级:表权限适用于一个给定表中的所有列,mysql.talbes_priv GRANT ALL ON db_name.tbl_name和REVOKE ALL ON db_name.tbl_name只授予和撤销表权限。列层级:列权限适用于一个给定表中的单一列,mysql.columns_priv 当使用REVOKE时,您必须指定与被授权列相同的列。-- 权限列表ALL [PRIVILEGES] -- 设置除GRANT OPTION之外的所有简单权限ALTER -- 允许使用ALTER TABLEALTER ROUTINE -- 更改或取消已存储的子程序CREATE -- 允许使用CREATE TABLECREATE ROUTINE -- 创建已存储的子程序CREATE TEMPORARY TABLES -- 允许使用CREATE TEMPORARY TABLECREATE USER -- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。CREATE VIEW -- 允许使用CREATE VIEWDELETE -- 允许使用DELETEDROP -- 允许使用DROP TABLEEXECUTE -- 允许用户运行已存储的子程序FILE -- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILEINDEX -- 允许使用CREATE INDEX和DROP INDEXINSERT -- 允许使用INSERTLOCK TABLES -- 允许对您拥有SELECT权限的表使用LOCK TABLESPROCESS -- 允许使用SHOW FULL PROCESSLISTREFERENCES -- 未被实施RELOAD -- 允许使用FLUSHREPLICATION CLIENT -- 允许用户询问从属服务器或主服务器的地址REPLICATION SLAVE -- 用于复制型从属服务器(从主服务器中读取二进制日志事件)SELECT -- 允许使用SELECTSHOW DATABASES -- 显示所有数据库SHOW VIEW -- 允许使用SHOW CREATE VIEWSHUTDOWN -- 允许使用mysqladmin shutdownSUPER -- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。UPDATE -- 允许使用UPDATEUSAGE -- “无权限”的同义词GRANT OPTION -- 允许授予权限/* 表维护 */-- 分析和存储表的关键字分布ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...-- 检查一个或多个表是否有错误CHECK TABLE tbl_name [, tbl_name] ... [option] ...option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}-- 整理数据文件的碎片OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] .../* 杂项 */ ------------------1. 可用反引号(`)为标识符(库名、表名、字段名、索引、别名)包裹,以避免与关键字重名!中文也可以作为标识符!2. 每个库目录存在一个保存当前数据库的选项文件db.opt。3. 注释: 单行注释 # 注释内容 多行注释 /* 注释内容 */ 单行注释 -- 注释内容 (标准SQL注释风格,要求双破折号后加一空格符(空格、TAB、换行等))4. 模式通配符: _ 任意单个字符 % 任意多个字符,甚至包括零字符 单引号需要进行转义 \\'5. CMD命令行内的语句结束符可以为 \";\", \"\\G\", \"\\g\",仅影响显示结果。其他地方还是用分号结束。delimiter 可修改当前对话的语句结束符。6. SQL对大小写不敏感7. 清除已有语句:\\c","link":"/database/mysql/%E4%B8%80%E5%8D%83%E8%A1%8C-MySQL-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E8%BD%AC%E8%BD%BD.html"},{"title":"安装、部分配置icarus主题中文版","text":"摘要发现icarus主题还不错,花了一两个小时研究了下安装、部分配置icarus主题中文版 安装icarus 直接下载主题模块放到blog项目 ,blog项目根目录执行 1git clone https://github.com/ppoffice/hexo-theme-icarus.git themes/icarus 此时已经下载到项目中。 顶级_config.yml中选择icarus主题 1234# Extensions## Plugins: https://hexo.io/plugins/## Themes: https://hexo.io/themes/theme: icarus 此时主题已经安装好,清除、编译、部署可以看到效果了 配置icarus 完全参照官网配置,进行翻译解说 配置文章部分顶部图片添加icarus 主题中的配置_config.yml中开启图片开关 12article: thumbnail: true 文章.md文件头中添加图片绝对/相对地址 12345title: Getting Started with Icarusthumbnail: /gallery/thumbnails/desert.jpg// thumbnail:https://cdn.jsdelivr.net/gh/removeif/blog_image/20190620152744.png---Post content... 配置完成后部署显示效果如下(最新文章列表显示缩略图、文章开头显示一张设置图片) 左边文章导航栏开启icarus 主题中的配置_config.yml中开关 1234widgets: - type: toc position: left 同事文章顶部加入标签 1234title: Table of Contents Exampletoc: true---Post content... 配置效果 评论系统开启icarus 主题中的配置_config.yml中开启(部分评论系统需要翻墙才能使用,valine不用翻墙个人推荐,valine安装参考) 1234567comment: type: valine app_id: xxxxxxxx # (required) LeanCloud application id app_key: xxxxxxxx # (required) LeanCloud application key notify: false # (optional) receive email notification verify: false # (optional) show verification code placeholder: xxxxxxxx # (optional) comment box placeholder text 开启效果 捐赠收款开启icarus 主题中的配置_config.yml中开启 注意如果默认不配置,编译时有报错,可以# 把它注释掉,不启用功能 1234567891011donate: - # Donation entry name type: alipay # Qrcode image URL qrcode: 'https://wx2.sinaimg.cn/large/b5d1b710gy1g0lvxdcwm0j20p011i4bg.jpg' - # Donation entry name type: wechat # Qrcode image URL qrcode: 'https://wx2.sinaimg.cn/large/b5d1b710gy1g0lvwdcpb5j20u014qgy2.jpg' 开启配置效果如下 全局搜索开启icarus 主题中的配置_config.yml中开启,不同的搜索类型需要安装插件参考官网,type: insight此类型不需要安装,已经内置 123search: type: insight 效果如下 更多配置请参考官网配置目前配置基本已经够使用,还需要更多配置请参考连接 参考自","link":"/theme/%E5%AE%89%E8%A3%85%E3%80%81%E9%83%A8%E5%88%86%E9%85%8D%E7%BD%AEicarus%E4%B8%BB%E9%A2%98%E4%B8%AD%E6%96%87%E7%89%88.html"},{"title":"java基础-static关键字","text":"static用法 static和final是两个我们必须掌握的关键字。不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优化程序的结构。下面我们先来了解一下static关键字及其用法。 修饰成员变量在我们平时的使用当中,static最常用的功能就是修饰类的属性和方法,让他们成为类的成员属性和方法,我们通常将用static修饰的成员称为类成员或者静态成员。 1234567891011121314151617181920212223public class Person { String name; int age; public String toString() { return \"Name:\" + name + \", Age:\" + age; } public static void main(String[] args) { Person p1 = new Person(); p1.name = \"zhangsan\"; p1.age = 10; Person p2 = new Person(); p2.name = \"lisi\"; p2.age = 12; System.out.println(p1); System.out.println(p2); } /**Output * Name:zhangsan, Age:10 * Name:lisi, Age:12 *///~} 根据Person构造出的每一个对象都是独立存在的,保存有自己独立的成员变量,相互不会影响,他们在内存中的示意如下: 从上图中可以看出,p1和p2两个变量引用的对象分别存储在内存中堆区域的不同地址中,所以他们之间相互不会干扰。但其实,在这当中,我们省略了一些重要信息,相信大家也都会想到,对象的成员属性都在这了,由每个对象自己保存,那么他们的方法呢?实际上,不论一个类创建了几个对象,他们的方法都是一样的: 从上面的图中我们可以看到,两个Person对象的方法实际上只是指向了同一个方法定义。这个方法定义是位于内存中的一块不变区域(由jvm划分),我们暂称它为静态存储区。这一块存储区不仅存放了方法的定义,实际上从更大的角度而言,它存放的是各种类的定义,当我们通过new来生成对象时,会根据这里定义的类的定义去创建对象。多个对象仅会对应同一个方法,这里有一个让我们充分信服的理由,那就是不管多少的对象,他们的方法总是相同的,尽管最后的输出会有所不同,但是方法总是会按照我们预想的结果去操作,即不同的对象去调用同一个方法,结果会不尽相同。 static关键字可以修饰成员变量和方法,来让它们变成类的所属,而不是对象的所属,比如我们将Person的age属性用static进行修饰,结果会是什么样呢? 1234567891011public class Person { String name; static int age; /* 其余代码不变... */ /**Output * Name:zhangsan, Age:12 * Name:lisi, Age:12 *///~} 我们发现,结果发生了一点变化,在给p2的age属性赋值时,干扰了p1的age属性,这是为什么呢?我们还是来看他们在内存中的示意: 我们发现,给age属性加了static关键字之后,Person对象就不再拥有age属性了,age属性会统一交给Person类去管理,即多个Person对象只会对应一个age属性,一个对象如果对age属性做了改变,其他的对象都会受到影响。我们看到此时的age和toString()方法一样,都是交由类去管理。 虽然我们看到static可以让对象共享属性,但是实际中我们很少这么用,也不推荐这么使用。因为这样会让该属性变得难以控制,因为它在任何地方都有可能被改变。如果我们想共享属性,一般我们会采用其他的办法: 1234567891011121314151617181920212223242526272829public class Person { private static int count = 0; int id; String name; int age; public Person() { id = ++count; } public String toString() { return \"Id:\" + id + \", Name:\" + name + \", Age:\" + age; } public static void main(String[] args) { Person p1 = new Person(); p1.name = \"zhangsan\"; p1.age = 10; Person p2 = new Person(); p2.name = \"lisi\"; p2.age = 12; System.out.println(p1); System.out.println(p2); } /**Output * Id:1, Name:zhangsan, Age:10 * Id:2, Name:lisi, Age:12 *///~} 上面的代码起到了给Person的对象创建一个唯一id以及记录总数的作用,其中count由static修饰,是Person类的成员属性,每次创建一个Person对象,就会使该属性自加1然后赋给对象的id属性,这样,count属性记录了创建Person对象的总数,由于count使用了private修饰,所以从类外面无法随意改变。 修饰成员方法static的另一个作用,就是修饰成员方法。相比于修饰成员属性,修饰成员方法对于数据的存储上面并没有多大的变化,因为我们从上面可以看出,方法本来就是存放在类的定义当中的。static修饰成员方法最大的作用,就是可以使用”类名.方法名“的方式操作方法,避免了先要new出对象的繁琐和资源消耗,我们可能会经常在帮助类中看到它的使用: 12345678910public class PrintHelper { public static void print(Object o){ System.out.println(o); } public static void main(String[] args) { PrintHelper.print(\"Hello world\"); }} 上面便是一个例子(现在还不太实用),但是我们可以看到它的作用,使得static修饰的方法成为类的方法,使用时通过“类名.方法名”的方式就可以方便的使用了,相当于定义了一个全局的函数(只要导入该类所在的包即可)。不过它也有使用的局限,一个static修饰的类中,不能使用非static修饰的成员变量和方法,这很好理解,因为static修饰的方法是属于类的,如果去直接使用对象的成员变量,它会不知所措(不知该使用哪一个对象的属性)。 静态块在说明static关键字的第三个用法时,我们有必要重新梳理一下一个对象的初始化过程。以下面的代码为例: 1234567891011121314151617181920212223242526272829class Book{ public Book(String msg) { System.out.println(msg); }}public class Person { Book book1 = new Book(\"book1成员变量初始化\"); static Book book2 = new Book(\"static成员book2成员变量初始化\"); public Person(String msg) { System.out.println(msg); } Book book3 = new Book(\"book3成员变量初始化\"); static Book book4 = new Book(\"static成员book4成员变量初始化\"); public static void main(String[] args) { Person p1 = new Person(\"p1初始化\"); } /**Output * static成员book2成员变量初始化 * static成员book4成员变量初始化 * book1成员变量初始化 * book3成员变量初始化 * p1初始化 *///~} 上面的例子中,Person类中组合了四个Book成员变量,两个是普通成员,两个是static修饰的类成员。我们可以看到,当我们new一个Person对象时,static修饰的成员变量首先被初始化,随后是普通成员,最后调用Person类的构造方法完成初始化。也就是说,在创建对象时,static修饰的成员会首先被初始化,而且我们还可以看到,如果有多个static修饰的成员,那么会按照他们的先后位置进行初始化。 实际上,static修饰的成员的初始化可以更早的进行,请看下面的例子: 12345678910111213141516171819202122232425262728293031323334353637class Book{ public Book(String msg) { System.out.println(msg); }}public class Person { Book book1 = new Book(\"book1成员变量初始化\"); static Book book2 = new Book(\"static成员book2成员变量初始化\"); public Person(String msg) { System.out.println(msg); } Book book3 = new Book(\"book3成员变量初始化\"); static Book book4 = new Book(\"static成员book4成员变量初始化\"); public static void funStatic() { System.out.println(\"static修饰的funStatic方法\"); } public static void main(String[] args) { Person.funStatic(); System.out.println(\"****************\"); Person p1 = new Person(\"p1初始化\"); } /**Output * static成员book2成员变量初始化 * static成员book4成员变量初始化 * static修饰的funStatic方法 * *************** * book1成员变量初始化 * book3成员变量初始化 * p1初始化 *///~} 在上面的例子中我们可以发现两个有意思的地方,第一个是当我们没有创建对象,而是通过类去调用类方法时,尽管该方法没有使用到任何的类成员,类成员还是在方法调用之前就初始化了,这说明,当我们第一次去使用一个类时,就会触发该类的成员初始化。第二个是当我们使用了类方法,完成类的成员的初始化后,再new该类的对象时,static修饰的类成员没有再次初始化,这说明,static修饰的类成员,在程序运行过程中,只需要初始化一次即可,不会进行多次的初始化。 回顾了对象的初始化以后,我们再来看static的第三个作用就非常简单了,那就是当我们初始化static修饰的成员时,可以将他们统一放在一个以static开始,用花括号包裹起来的块状语句中: 123456789101112131415161718192021222324252627282930313233343536373839404142class Book{ public Book(String msg) { System.out.println(msg); }}public class Person { Book book1 = new Book(\"book1成员变量初始化\"); static Book book2; static { book2 = new Book(\"static成员book2成员变量初始化\"); book4 = new Book(\"static成员book4成员变量初始化\"); } public Person(String msg) { System.out.println(msg); } Book book3 = new Book(\"book3成员变量初始化\"); static Book book4; public static void funStatic() { System.out.println(\"static修饰的funStatic方法\"); } public static void main(String[] args) { Person.funStatic(); System.out.println(\"****************\"); Person p1 = new Person(\"p1初始化\"); } /**Output * static成员book2成员变量初始化 * static成员book4成员变量初始化 * static修饰的funStatic方法 * *************** * book1成员变量初始化 * book3成员变量初始化 * p1初始化 *///~} 我们将上一个例子稍微做了一下修改,可以看到,结果没有二致。 静态导包相比于上面的三种用途,第四种用途可能了解的人就比较少了,但是实际上它很简单,而且在调用类方法时会更方便。以上面的“PrintHelper”的例子为例,做一下稍微的变化,即可使用静态导包带给我们的方便: 123456789/* PrintHelper.java文件 */package com.dotgua.study;public class PrintHelper { public static void print(Object o){ System.out.println(o); }} 123456789101112import static com.dotgua.study.PrintHelper.*; // 导入上面的包public class App { public static void main( String[] args ) { print(\"Hello World!\"); } /**Output * Hello World! *///~} 上面的代码来自于两个java文件,其中的PrintHelper很简单,包含了一个用于打印的static方法。而在App.java文件中,我们首先将PrintHelper类导入,这里在导入时,我们使用了static关键字,而且在引入类的最后还加上了“.*”,它的作用就是将PrintHelper类中的所有类方法直接导入。不同于非static导入,采用static导入包后,在不与当前类的方法名冲突的情况下,无需使用“类名.方法名”的方法去调用类方法了,直接可以采用”方法名“去调用类方法,就好像是该类自己的方法一样使用即可。 总结static是java中非常重要的一个关键字,而且它的用法也很丰富,主要有四种用法: 用来修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享; 用来修饰成员方法,将其变为类方法,可以直接使用“类名.方法名”的方式调用,常用于工具类; 静态块用法,将多个类成员放在一起初始化,使得程序更加规整,其中理解对象的初始化过程非常关键; 静态导包用法,将类的方法直接导入到当前类中,从而直接使用“方法名”即可调用类方法,更加方便。 参考自","link":"/java/basic/java%E5%9F%BA%E7%A1%80-static%E5%85%B3%E9%94%AE%E5%AD%97.html"},{"title":"java基础-final关键字","text":"final 关键字 在java的关键字中,static和final是两个我们必须掌握的关键字。不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优化程序的结构。下面我们来了解一下final关键字及其用法。 修饰数据在编写程序时,我们经常需要说明一个数据是不可变的,我们成为常量。在java中,用final关键字修饰的变量,只能进行一次赋值操作,并且在生存期内不可以改变它的值。更重要的是,final会告诉编译器,这个数据是不会修改的,那么编译器就可能会在编译时期就对该数据进行替换甚至执行计算,这样可以对我们的程序起到一点优化。不过在针对基本类型和引用类型时,final关键字的效果存在细微差别。我们来看下面的例子: 123456789101112131415161718192021222324 class Value { int v; public Value(int v) { this.v = v; }}public class FinalTest { final int f1 = 1; final int f2; public FinalTest() { f2 = 2; } public static void main(String[] args) { final int value1 = 1; // value1 = 4; final double value2; value2 = 2.0; final Value value3 = new Value(1); value3.v = 4; }} 上面的例子中,我们先来看一下main方法中的几个final修饰的数据,在给value1赋初始值之后,我们无法再对value1的值进行修改,final关键字起到了常量的作用。从value2我们可以看到,final修饰的变量可以不在声明时赋值,即可以先声明,后赋值。value3时一个引用变量,这里我们可以看到final修饰引用变量时,只是限定了引用变量的引用不可改变,即不能将value3再次引用另一个Value对象,但是引用的对象的值是可以改变的,从内存模型中我们看的更加清晰: 上图中,final修饰的值用粗线条的边框表示它的值是不可改变的,我们知道引用变量的值实际上是它所引用的对象的地址,也就是说该地址的值是不可改变的,从而说明了为什么引用变量不可以改变引用对象。而实际引用的对象实际上是不受final关键字的影响的,所以它的值是可以改变的。 另一方面,我们看到了用final修饰成员变量时的细微差别,因为final修饰的数据的值是不可改变的,所以我们必须确保在使用前就已经对成员变量赋值了。因此对于final修饰的成员变量,我们有且只有两个地方可以给它赋值,一个是声明该成员时赋值,另一个是在构造方法中赋值,在这两个地方我们必须给它们赋初始值。 最后我们需要注意的一点是,同时使用static和final修饰的成员在内存中只占据一段不能改变的存储空间。 修饰方法参数前面我们可以看到,如果变量是我们自己创建的,那么使用final修饰表示我们只会给它赋值一次且不会改变变量的值。那么如果变量是作为参数传入的,我们怎么保证它的值不会改变呢?这就用到了final的第二种用法,即在我们编写方法时,可以在参数前面添加final关键字,它表示在整个方法中,我们不会(实际上是不能)改变参数的值: 12345678910public class FinalTest { /* ... */ public void finalFunc(final int i, final Value value) { // i = 5; 不能改变i的值 // v = new Value(); 不能改变v的值 value.v = 5; // 可以改变引用对象的值 }} 修饰方法第三种方式,即用final关键字修饰方法,它表示该方法不能被覆盖。这种使用方式主要是从设计的角度考虑,即明确告诉其他可能会继承该类的程序员,不希望他们去覆盖这个方法。这种方式我们很容易理解,然而,关于private和final关键字还有一点联系,这就是类中所有的private方法都隐式地指定为是final的,由于无法在类外使用private方法,所以也就无法覆盖它。 修饰类了解了final关键字的其他用法,我们很容易可以想到使用final关键字修饰类的作用,那就是用final修饰的类是无法被继承的。 上面我们讲解了final的四种用法,然而,对于第三种和第四种用法,我们却甚少使用。这不是没有道理的,从final的设计来讲,这两种用法甚至可以说是鸡肋,因为对于开发人员来讲,如果我们写的类被继承的越多,就说明我们写的类越有价值,越成功。即使是从设计的角度来讲,也没有必要将一个类设计为不可继承的。Java标准库就是一个很好的反例,特别是Java 1.0/1.1中Vector类被如此广泛的运用,如果所有的方法均未被指定为final的话,它可能会更加有用。如此有用的类,我们很容易想到去继承和重写他们,然而,由于final的作用,导致我们对Vector类的扩展受到了一些阻碍,导致了Vector并没有完全发挥它应有的全部价值。 总结final关键字是我们经常使用的关键字之一,它的用法有很多,但是并不是每一种用法都值得我们去广泛使用。它的主要用法有以下四种: 用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来讲,我们必须在声明时或者构造方法中对它赋值; 用来修饰方法参数,表示在变量的生存期中它的值不能被改变; 修饰方法,表示该方法无法被重写; 修饰类,表示该类无法被继承。 上面的四种方法中,第三种和第四种方法需要谨慎使用,因为在大多数情况下,如果是仅仅为了一点设计上的考虑,我们并不需要使用final来修饰方法和类。 参考自","link":"/java/basic/java%E5%9F%BA%E7%A1%80-final%E5%85%B3%E9%94%AE%E5%AD%97.html"},{"title":"Java设计模式之代理模式","text":"代理模式代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法 举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子. 图片表示如下: 代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象 静态代理静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类. eg:模拟保存动作,定义一个保存动作的接口:IUserDao.java,然后目标对象实现这个接口的方法UserDao.java,此时如果使用静态代理方式,就需要在代理对象(UserDaoProxy.java)中也实现IUserDao接口.调用的时候通过调用代理对象的方法来调用目标对象.需要注意的是,代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法 示例代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354/** * @desc 用户保存接口 */public interface IUserDao { // 保存方法 void save();}/** * @desc 用户保存 */public class UserDao implements IUserDao { @Override public void save() { System.out.println(\"OK,已保存数据!\"); }}/** * @desc 代理对象,静态代理 */public class UserDaoProxy implements IUserDao { // 目标对象 private IUserDao target; public UserDaoProxy(IUserDao user) { this.target = user; } @Override public void save() { System.out.println(\"开始事物.\"); target.save(); System.out.println(\"提交事物.\"); }}/** * @desc 静态代理测试方法 */public class MainTest { public static void main(String[] args) { // 目标对象 IUserDao userDao = new UserDao(); // 代理对象,把目标对象传给代理,建立代理关系 UserDaoProxy proxy = new UserDaoProxy(userDao); proxy.save(); }} 结果: 静态代理总结:1.可以做到在不修改目标对象的功能前提下,对目标功能扩展.2.缺点: 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护. 如何解决静态代理中的缺点呢?答案是可以使用动态代理方式 动态代理动态代理有以下特点: 代理对象,不需要实现接口 .代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型) 动态代理也叫做:JDK代理,接口代理 JDK中生成代理对象的API代理类所在包:java.lang.reflect.ProxyJDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是: 1static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h ) 注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为: ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的 Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型 InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入 代码示例:接口类IUserDao.java以及接口实现类,目标对象UserDao是一样的,没有做修改.在这个基础上,增加一个代理工厂类(ProxyFactory.java),将代理类写在这个地方,然后在测试类(需要使用到代理的代码)中先建立目标对象和代理对象的联系,然后代用代理对象的中同名方法 示例代码代理工厂类:ProxyFactory.java 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * @desc 动态代理工厂 */public class ProxyFactory { private Object target; /** * 维护一个目标对象 * * @param target */ public ProxyFactory(Object target) { this.target = target; } public Object getProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(\"开始事物2.\"); // 执行目标方法 Object returnValue = method.invoke(target, args); System.out.println(\"提交事物2.\"); return returnValue; } }); }}/** * @desc 动态代理测试方法 */public class MainTest { public static void main(String[] args) { // 目标对象 IUserDao userDao = new UserDao(); // 原始类型 System.out.println(userDao.getClass()); // 给目标对象,创建代理对象 IUserDao proxy = (IUserDao) new ProxyFactory(userDao).getProxyInstance(); // 内存中动态生成的代理对象 System.out.println(proxy.getClass()); // 执行方法 proxy.save(); }} 结果: 总结代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理 Cglib代理上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理 一. Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展. JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现. Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop为他们提供方法的interception(拦截) Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉. 二. Cglib子类代理实现方法: 需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入spring-core-3.2.5.jar即可. 引入功能包后,就可以在内存中动态构建子类 代理的类不能为final,否则报错 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法. 示例代码1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465/** * 目标对象,没有实现任何接口 */public class UserDao { public void save() { System.out.println(\"----已经保存数据!----\"); }}/** * Cglib子类代理工厂 * 对UserDao在内存中动态构建一个子类对象 */public class ProxyFactory implements MethodInterceptor{ //维护目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } //给目标对象创建一个代理对象 public Object getProxyInstance(){ //1.工具类 Enhancer en = new Enhancer(); //2.设置父类 en.setSuperclass(target.getClass()); //3.设置回调函数 en.setCallback(this); //4.创建子类(代理对象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println(\"开始事务...\"); //执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println(\"提交事务...\"); return returnValue; }}/** * 测试类 */public class App { @Test public void test(){ //目标对象 UserDao target = new UserDao(); //代理对象 UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance(); //执行代理对象的方法 proxy.save(); }} 总结动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理。在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样对每一个方法或方法组合进行处理。Proxy 很美很强大,但是仅支持 interface 代理。Java 的单继承机制注定了这些动态代理类们无法实现对 class 的动态代理。好在有cglib为Proxy提供了弥补。class与interface的区别本来就模糊,在java8中更是增加了一些新特性,使得interface越来越接近class,当有一日,java突破了单继承的限制,动态代理将会更加强大。 参考:http://www.cnblogs.com/cenyu/p/6289209.html http://blog.csdn.net/goskalrie/article/details/52458773","link":"/java/design-mode/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F.html"},{"title":"Java设计模式之命令模式","text":"目的 将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或记录日志,以及支持可撤销的操作。 将”发出请求的对象”和”接收与执行这些请求的对象”分隔开来。 效果 command模式将调用操作的对象和实现该操作的对象解耦 可以将多个命令装配成一个复合命令,复合命令是Composite模式的一个实例 增加新的command很容易,无需改变已有的类 适用性 抽象出待执行的动作以参数化某对象 在不同的时刻指定、排列和执行请求。如请求队列 支持取消操作 支持修改日志 用构建在原语操作上的高层操作构造一个系统。支持事物 参与者 Command声明执行操作的接口 ConcreteCommand将一个接收者对象绑定于一个动作 调用接收者相应的操作,以实现execute Client创建一个具体命令对象并设定它的接收者 Invoker要求该命令执行这个请求 Receiver知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者 结构图 协作: 1)、client创建一个ConcreteCommand对象并指定它的Receiver对象 2)、某Invoker对象存储该ConcreteCommand对象 3)、该Invoker通过调用Command对象的execute操作来提交一个请求。若该命令是可撤销的,ConcreteCommand在执行execute操作前存储当前状态以用于取消该命令 4)、ConcreteCommand对象调用它的Receiver的操作以执行该请求 命令对象将动作和接受者包进对象中,这个对象只暴露出一个execute()方法,当此方法被调用的时候,接收者就会进行这些动作。从外面来看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用execute()方法,请求的目的就能达到。 java 实现源码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102/** * @desc 命令接口 */public interface Command { /** * 执行命令 */ void excute(); /** * 撤销命令 */ void undo();}/** * @desc 真正命令执行者,接收者 */public class Receiver { public void action() { System.out.println(\"正在执行命令...\"); } public void unAction() { System.out.println(\"正在撤销命令...\"); }}/** * @desc 创建命令(可实现多条命令以及多个命令执行人) */public class CreateCommand implements Command { private Receiver receiver; /** * 初始化命令接收人 * * @param receiver */ public CreateCommand(Receiver receiver) { this.receiver = receiver; } @Override public void excute() { receiver.action(); } @Override public void undo() { receiver.unAction(); }}/** * @desc 命令调用者 */public class Invoker { private Command command; /** * 命令调用者持有该命令 * * @param command */ public Invoker(Command command) { this.command = command; } /** * 执行命令 */ public void runCommand() { command.excute(); } /** * 撤销命令 */ public void unRunCommand() { command.undo(); }}/** * @desc 命令模式测试 */public class TestMain { public static void main(String[] args) { // new 一个命令执行人 Receiver receiver = new Receiver(); // new 一条命令 Command command = new CreateCommand(receiver); // 开始调用命令 Invoker invoker = new Invoker(command); invoker.runCommand(); invoker.unRunCommand(); }} 执行结果 常见应用: 1、工作队列,线程池,日程安排 2、日志请求(系统恢复)要点: 1、命令模式将发出请求的对象和执行请求的对象解耦 2、在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作 3、调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用 4、调用者可以接受命令当作参数,甚至在运行时动态的进行 5、命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态 6、宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销 7、实际操作时,很常见使用”聪明”命令对象,也就是直接实现了请求,而不是将工作委托给接受者(弊端?) 8、命令也可以用来实现日志和事物系统 参考:http://www.cnblogs.com/ikuman/archive/2013/08/06/3233092.html","link":"/java/design-mode/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F.html"},{"title":"java 8部分读书笔记","text":"Lambda 表达式 Lambda 表达式引用的是值,不是变量。 Lambda 表达式中的变量只能是final类型,只能给变量赋值一次。 123String name = getUserName();name = formatUesrName();button.addActionListener(event -> System.out.println(\"Hi\" + name)) 如上代码将不会编译通过,name被赋值多次。 函数接口:只有一个抽象方法的接口,用作Lambda表达式的类型。 Java中重要的几个函数接口 名称 解释 返回值 eg 参数 Predicate 断言 boolean 这张唱片已经发行了吗 T Consumer 消费 void 输出一个值 T Function<T,R> 运行 R 获得Artist对象的名字 T Supplier 供应 T 工厂方法 None UnaryOperator 一元运算 T 逻辑非(!) T BinaryOperator 二元运算 T 求两个数的乘积 (T,T) 所有的都有泛型没有的话值代码编译不过 123Predicate<Integer> atLeast5 = x -> x > 5;// 编译通过Predicate atLeast5 = x -> x > 5;// 编译不通过BinaryOperator<Long> addLongs = (x , y) -> x + y;// 编译通过 流 Stream(针对于集合) 惰性求值 和及早求值 1allArtists.stream().filter(artist -> artist.isFrom(\"London\")); 这行代码并没有做什么实质性工作,filter只是刻画出了Stream,没有产生新的集合。像filter这种只描述Stream,不产生新集合的方法叫做惰性求值方法,而像count这样最终会从Stream产生值的方法叫做及早求值方法。 123456789allArtists.stream().filter(artist - >{ System.out.println(artist.getName()); return artist.isFrom(\"London\");});// 此段代码并不会输出 艺术家名字allArtists.stream().filter(artist - >{ System.out.println(artist.getName()); return artist.isFrom(\"London\");}).count();// 此段代码并会输出 艺术家名字 判断一个操作是惰性求值还是及早求值,只需看它的返回值,返回值是Stream,那么就是惰性求值,返回值是另一个值或者是空,则是及早求值。最终达到的效果:通过这些方法形成一个惰性求值的链,最终调用一个及早求值方法得到我们需要的最终结果。 常用的流操作 collect(toList()) :由Stream里的值生成一个列表 Stream的of 方法使用一组初始值生成新的Stream 12List<String> collected = Stream.of(\"a\",\"b\",\"c\").collect(Collectors.toList());assertEquals(Arrays.asList(\"a\",\"b\",\"c\"),collected);//判断结果和预期值是否一样 map 将一种类型转换为另一种类型,将一个流中的值转换为一个新的流。mapToInt/mapToDouble/mapToLong 123List<String> collected = Stream.of(\"a\",\"b\",\"hello\") .map(string -> string.toUpperCase()) .collect(Collectors.toList());//将小写转换为大写 filter filter模式,保留Stream中的一些元素,过滤掉其他的。返回true保留,返回false过滤。 123List<String> beginWithNumbers = Stream.of(\"a\",\"1adf\",\"abc1\") .filter(value -> isDigit(value.chartAt(0))) .collect(toList());//返回数据开头的字符串 flatMap :可用Stream替换值,将多个Stream连接成一个Stream 123List<Integer> together = Stream.of(asList(1,2), asList(3,4)) .flatMap(numbers -> numbers.stream()) .collect(toList()); 它会把原流中的每一个元素经过指定函数处理之后,返回一个Stream对象,并将之展开到原父流中。 max和min 1234List<Track> tracks = asList(new Track(\"Bakai\",524), new Track(\"Violets\",378), new Track(\"Time\",451));Track shortestTrack = tracks.stream().min(Commparator.comparing(track -> track.getLength())).get();// 查找距离最短的 reduce 聚合归纳:操作中可以实现从一组值生成一个值 使用reduce求和 12int count = Stream.of(1,2,3) .reduce(0, (acc, element) -> acc + element); 展开reduce操作 123456BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;int count = accumulator.apply( accumulator.apply( accumulator.apply(0, 1), 2), 3); 1collections.stream().map(Entity::getNum).reduce(0, Integer::sum); // collections求和num 1234//根据typeId分组 entities[{typeId:1,name:\"火锅\"},{typeId:1,name:\"烧烤\"},{typeId:2,name:\"律师\"}]Map<Integer, List<Entity>> groups = entities.stream() .collect(Collectors.groupingBy(Entity::getTypeId));List<Entity> list = groups.get(typeId); //拿到对应的分组数据 找出长度大于一分钟的曲目 1234567public Set<String> findLongTracks(List<Album> albums){ return albums.stream() .flatMap(album -> album.getTracks()) .filter(track -> track.getLength() > 60) .map(track -> track.getName) .collect(toSet());}","link":"/java/basic/java-8%E9%83%A8%E5%88%86%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0.html"},{"title":"Java设计模式之适配器模式","text":"定义 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。 适配器模式的用途用电器做例子,笔记本电脑的插头一般都是三相的,即除了阳极、阴极外,还有一个地极。而有些地方的电源插座却只有两极,没有地极。电源插座与笔记本电脑的电源插头不匹配使得笔记本电脑无法使用。这时候一个三相到两相的转换器(适配器)就能解决此问题,而这正像是本模式所做的事情。 适配器模式的结构适配器模式有类的适配器模式和对象的适配器模式两种不同的形式。 类适配器模式类的适配器模式把适配的类的API转换成为目标类的API。 在上图中可以看出,Adaptee类并没有sampleOperation2()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,提供一个中间环节,即类Adapter,把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是继承关系,这决定了这个适配器模式是类的: 模式所涉及的角色有: ● 目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类。 ● 源(Adapee)角色:现在需要适配的接口。 ● 适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。 java源码123456789101112131415161718192021222324252627282930313233343536public interface Target { /** * 这是源类Adaptee也有的方法 */ public void sampleOperation1(); /** * 这是源类Adapteee没有的方法 */ public void sampleOperation2(); }/**上面给出的是目标角色的源代码,这个角色是以一个JAVA接口的形式实现的。可以看出,这个接口声明了两个方法:*sampleOperation1()和sampleOperation2()。而源角色Adaptee是一个具体类,它有一个sampleOperation1()方法,但是没有sampleOperation2()方法。*/public class Adaptee { public void sampleOperation1(){}}/**适配器角色Adapter扩展了Adaptee,同时又实现了目标(Target)接口。由于Adaptee没有提供sampleOperation2()方法,而目标接口又要求这个方法,因此适配器角色Adapter实现了这个方法。*/public class Adapter extends Adaptee implements Target { /** * 由于源类Adaptee没有方法sampleOperation2() * 因此适配器补充上这个方法 */ @Override public void sampleOperation2() { //写相关的代码 }} 对象适配器模式与类的适配器模式一样,对象的适配器模式把被适配的类的API转换成为目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。 从上图可以看出,Adaptee类并没有sampleOperation2()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。 java 源码实现1234567891011121314151617181920212223242526272829303132333435363738public interface Target { /** * 这是源类Adaptee也有的方法 */ public void sampleOperation1(); /** * 这是源类Adapteee没有的方法 */ public void sampleOperation2(); }public class Adaptee { public void sampleOperation1(){} }public class Adapter { private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } /** * 源类Adaptee有方法sampleOperation1 * 因此适配器类直接委派即可 */ public void sampleOperation1(){ this.adaptee.sampleOperation1(); } /** * 源类Adaptee没有方法sampleOperation2 * 因此由适配器类需要补充此方法 */ public void sampleOperation2(){ //写相关的代码 }} 类适配器模式和对象适配器模式的权衡 类适配器,使用对象继承的方式,是静态的定义方式;对象适配器,使用对象组合的方式,是动态组合的方式。 对于类适配器,由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系 对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓。 对于类适配器,适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。 对于对象适配器,要重定义Adaptee的行为比较困难,这种情况下,需要定义Adaptee的子类来实现重定义,然后让适配器组合子类。虽然重定义Adaptee的行为比较困难,但是想要增加一些新的行为则方便的很,而且新增加的行为可同时适用于所有的源。 对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee。 对于对象适配器,需要额外的引用来间接得到Adaptee。 建议尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。当然,具体问题具体分析,根据需要来选用实现方式,最适合的才是最好的。 适配器模式的优点 更好的复用性 系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。 更好的扩展性 在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。 适配器模式的缺点过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 缺省适配器模式缺省适配(Default Adapter)模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。作为适配器模式的一个特例,缺省是适配模式在JAVA语言中有着特殊的应用。 实例1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768/***鲁智深的故事* 和尚要做什么呢?吃斋、念经、打坐、撞钟、习武等。如果设计一个和尚*接口,*给出所有的和尚都需要实现的方法,那么这个接口应当如下:*/public interface 和尚 { public void 吃斋(); public void 念经(); public void 打坐(); public void 撞钟(); public void 习武(); public String getName();}/**显然,所有的和尚类都应当实现接口所定义的全部方法,不然就根本通不过JAVA语言编辑器。像下面的鲁智深类就不行。*/public class 鲁智深 implements 和尚{ public void 习武(){ 拳打镇关西; 大闹五台山; 大闹桃花村; 火烧瓦官寺; 倒拔垂杨柳; } public String getName(){ return \"鲁智深\"; }}/*** 由于鲁智深只实现了getName()和习武()方法,而没有实现任何其他的方法。因此,它根本就通不过Java语言编译器。*鲁智深类只有实现和尚接口的所有的方法才可以通过Java语言编译器,但是这样一来鲁智深就不再是鲁智深了。*以史为鉴,可以知天下。研究一下几百年前鲁智深是怎么剃度成和尚的,会对Java编程有很大的启发。*不错,当初鲁达剃度,众僧说:“此人形容丑恶、相貌凶顽,不可剃度他\",但是长老却说:*”此人上应天星、心地刚直。虽然时下凶顽,命中驳杂,久后却得清净。证果非凡,汝等皆不及他。”*原来如此!看来只要这里也应上一个天星的话,问题就解决了!使用面向对象的语言来说,“应”者,实现也;“天星”者,抽象类也。*/public abstract class 天星 implements 和尚 { public void 吃斋(){} public void 念经(){} public void 打坐(){} public void 撞钟(){} public void 习武(){} public String getName(){ return null; }}/**鲁智深类继承抽象类“天星”*/public class 鲁智深 extends 和尚{ public void 习武(){ 拳打镇关西; 大闹五台山; 大闹桃花村; 火烧瓦官寺; 倒拔垂杨柳; } public String getName(){ return \"鲁智深\"; }} ​ 这个抽象的天星类便是一个适配器类,鲁智深实际上借助于适配器模式达到了剃度的目的。此适配器类实现了和尚接口所要求的所有方法。但是与通常的适配器模式不同的是,此适配器类给出的所有的方法的实现都是“平庸”的。这种“平庸化”的适配器模式称作缺省适配模式。 ​ 在很多情况下,必须让一个具体类实现某一个接口,但是这个类又用不到接口所规定的所有的方法。通常的处理方法是,这个具体类要实现所有的方法,那些有用的方法要有实现,那些没有用的方法也要有空的、平庸的实现。 这些空的方法是一种浪费,有时也是一种混乱。除非看过这些空方法的代码,程序员可能会以为这些方法不是空的。即便他知道其中有一些方法是空的,也不一定知道哪些方法是空的,哪些方法不是空的,除非看过这些方法的源代码或是文档。 缺省适配模式可以很好的处理这一情况。可以设计一个抽象的适配器类实现接口,此抽象类要给接口所要求的每一种方法都提供一个空的方法。就像帮助了鲁智深的“上应天星”一样,此抽象类可以使它的具体子类免于被迫实现空的方法。 缺省适配器模式的结构缺省适配模式是一种“平庸”化的适配器模式。 实现代码12345678910111213141516171819202122public interface AbstractService { public void serviceOperation1(); public int serviceOperation2(); public String serviceOperation3();}public abstract class ServiceAdapter implements AbstractService{ @Override public void serviceOperation1() { } @Override public int serviceOperation2() { return 0; } @Override public String serviceOperation3() { return null; }} 可以看到,接口AbstractService要求定义三个方法,分别是serviceOperation1()、serviceOperation2()、serviceOperation3();而抽象适配器类ServiceAdapter则为这三种方法都提供了平庸的实现。因此,任何继承自抽象类ServiceAdapter的具体类都可以选择它所需要的方法实现,而不必理会其他的不需要的方法。 适配器模式的用意是要改变源的接口,以便于目标接口相容。缺省适配的用意稍有不同,它是为了方便建立一个不平庸的适配器类而提供的一种平庸实现。 在任何时候,如果不准备实现一个接口的所有方法时,就可以使用“缺省适配模式”制造一个抽象类,给出所有方法的平庸的具体实现。这样,从这个抽象类再继承下去的子类就不必实现所有的方法了。 参考:http://www.cnblogs.com/java-my-life/archive/2012/04/13/2442795.html","link":"/java/design-mode/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F.html"},{"title":"支付系统设计(转载)","text":"支付系统概述支付系统是连接消费者、商家(或平台)和金融机构的桥梁,管理支付数据,调用第三方支付平台接口,记录支付信息(对应订单号,支付金额等),金额对账等功能,根据不同公司对于支付业务的定位不同大概有几个阶段:第一阶段:支付作为一个(封闭)的、独立的应用系统,为各系统提供支付功能支持。一般来说,这个系统仅限于为公司内部的业务提供支付支持,并且和业务紧密耦合。第二阶段:支付作为一个开发的系统,为公司内外部系统、各种业务提供支付服务,支付服务本身应该是和具体的业务解耦合。 支付系统架构模块组成图 我们先来看一下用户完成一次购物需要进行那些操作: 通常消费者在手机APP或者网站都会涉及到支付相关的业务场景,用户只需要简单点击支付按钮输入支付密码,就可以完成整个支付过程,那么我就和大家一起来看看一个完整的支付系统有什么功能组成和设计时需要考虑那些问题。 支付系统的作用 从上图中我们可以看出真实的资金流向。首先当用户产生支付行为时,资金从用户端流向支付系统,退款时则相反,从支付系统回流至用户端。因此在整个交易过程中用户端与支付系统是双向资金的流动方式。对于支付系统而言,资金有进有出。从支付系统到商户端就比较简单了,在清算完成后支付系统负责将代收的资金结算给商户,通常结算的操作可以在线上来完成(采用支付公司代付接口或者银企直连接口来完成),也可以由公司财务通过线下手工转账的方式来完成,因此这种资金流动的方式是单向的。出于资金安全考虑,大多数公司通常这部分采用线下方式实现。 真实的资金流由支付公司按照约定期限(通常 T+1 )结算到平台公司对公账户中,然后再由平台公司再按照交易明细进行二次清算后结算给对应的商户。 支付系统支付系统模块组成 完整的支付系统包括如下的功能 应用管理: 同时支持公司多个业务系统对接。 商户管理: 支持商户入驻,商户需要向平台方提供相关的资料备案。 渠道管理: 支持微信、支付宝、银联、京东支付等多种渠道。 账户管理: 渠道账户管理,支持共享账户(个人商户)及自有账户。 支付交易: 生成预支付订单、提供退款服务。 对账管理: 实现支付系统的交易数据与第三方支付渠道交易明细的自动核对(通常T+1),确保交易数据的准确性和一致性。 清算管理: 计算收款交易中商户的应收与支付系统收益。 结算管理: 根据清算结果,将资金划拨至商户对应的资金帐户中。 核心流程支付系统有几个关键的核心流程:支付流程、对账流程、结算流程 支付流程说明 用户在商城选购商品并发起支付请求; 商城将支付订单通过B2C网关收款接口传送至支付网关; 用户选择网银支付及银行,支付平台将订单转送至指定银行网关界面; 用户支付完成,银行处理结果并向平台返回处理结果; 支付平台接收处理结果,落地处理并向商户返回结果; 商城接收到支付公司返回结果,落地处理(更改订单状态)并通知用户。 一般而言支付系统会给商户设置有“可用余额”账户、“待结算”账户;系统在接收到银行返回支付成功信息会进行落地处理,一方面更改对应订单状态,另一方面在商户待结算账户记入一笔金额;该笔金额,系统会根据结算周期从待结算账户—>“可用余额”账户。 退款流程说明 用户在商户平台发起退款申请,商户核实退款信息及申请; 商户登录支付平台账户/或者通过支付公司提供的退款接口向支付平台发起退款; 支付系统会对退款信息校验(退款订单对应的原订单是否支付成功?退款金额是否少于等于原订单金额?),校验商户账户余额是否充足等;校验不通过,则无法退款; 支付系统在商户可用余额账户扣除金额,并将退款订单发送至银行,银行完成退款操作。注意:对于网关收款的订单退款,各银行要求不一,有些银行提供的退款接口要求原订单有效期在90或180天,有些银行不提供退款接口;针对超期或者不支持接口退款的订单,支付公司通过代付通道完成退款操作。 对于收单金额未结算,还在“待结算”账户的订单,如果出现退款情况,业务流程和上述流程差不多,只是从待结算账户进行扣款。 对账说明​ 对账,我们一般称为勾兑,支付系统的对账,包含着两个层面: 支付系统内部间的对账,支付系统一般是分布式的,整个支付系统被拆分成了多个子系统,如交易系统、账户系统、会计系统、账户系统,每个子系统在处理各自的业务,系统间的对账,就是以上系统的核对,用于修正内部系统的数据不一致。 支付系统与渠道的对账,这里的渠道泛指所有为支付系统提供代收付业务的渠道,如:第三方支付公司、银行、清算中心、网联、银联等。 对账简易流程 支付系统与渠道间的对账系统间的对账比较好理解,这里主要讲支付系统与渠道间的对账。支付系统与渠道间的对账,又包含2个维度: 信息流勾对:即业务对账/交易对账,主要是就收单交易的支付信息与银行提供的信息流文件进行勾兑。信息流的勾地能发现支付系统与银行系统间的掉单、两边由于系统间的原因导致的同一笔交易支付金额不一致(可能性很小)或者支付状态不一致。信息流勾兑一般用来恢复掉单数据,可通过补单或者具体系统问题排查解决。 资金流勾对:即资金对账,主要就收单交易的支付信息与银行提供的资金流信息进行勾兑。资金流的勾兑能发现支付系统在银行的帐户资金实际发生的变动与应该发生的变动的差异,比如长款(银行多结算给支付系统)和短款(银行少结算给支付系统)。 说了这么多,就出现来4个对账文件,支付系统信息流文件、支付系统资金流文件、银行信息流文件、银行资金流文件。业务对账(勾兑)就是支付系统的信息流文件与银行的信息流文件勾兑,资金对账即支付系统的资金流文件与银行的资金流文件勾兑。 核对的差异处理1、信息流勾对的差异处理 支付系统信息流没有,而银行有的差异,可能是因为支付系统交易数据的丢失、银行的掉单,如果是银行的掉单,由支付公司的运营登录银行网银确认后,做补单处理,并将差异表中该记录核销。 支付系统信息流有,而银行没有的差异,此种情况一般不会发生,因为支付系统所有的交易数据都是取银行返回状态的数据。 2、资金流勾对对差异处理 支付系统资金流没有,而银行有的差异。可能原因如下:1、银行日切晚与支付系统核心账务系统;2、支付系统账务核心系统与其他系统间的掉单。一旦出现,则会出现长款(即银行不应该结算而实际结算)的现象,对于因日切导致的差异,在第二天的对账中系统会对平,其他原因的,需要技术排查。 支付系统资金流有,而银行没有的差异,可能是因为银行日切早于支付系统的核心账务系统,一旦出现,会出现短款(银行应结算而实际未结算)的现象,银行日切导致段差异,会在下一天与银行的勾对中,将此笔差异勾对上,如果是非日切导致的原因,就需要找银行追款了。 总结就是,业务对账,即信息流对账,支付系统的交易流水与银行的交易流水间核对,保障支付交易完整入账。资金对账,即资金流对账,支付系统的入账流水与银行的结算流水间核对,保障银行入账流水与实际入账资金的匹配。 结算结算流程 在清结算部分,系统按照设定好的清结算规则自动将钱款结算给商户。完善的运营会计体系帮助财务进行精细化核算,提高财务效率。与支付渠道自动进行对账,确保账务正确,在异常情况下能及时定位问题并处理。系统更是能对商户进行个性化的费率配置或账期配置,方便灵活。系统的价值不仅体现在支付清结算方面,同时更是提升了运营管理效率。支付清结算系统可以有效帮助运营、财务、开发以及管理人员。对于运营人员,系统可帮助处理平台的运营工作,包括各类支付管理,商户、会员管理,营销活动的数据统计等,全面提高运营效率。针对财务人员,可以协助完成资金对账、会计处理,出入款管理,账务差错处理等,大部分工作由系统自动处理,减少人工处理,提高资金处理效率。一套灵活便捷的配置后台供开发人员快速调整系统以适应新的业务,并能方便对系统进行维护,如渠道接入、费率配置、账期调整等,提高开发效率。系统提供资金流转过程中各个环节的数据,能够从各个维度进行核算和分析,形成对管理人员的决策支持,从而提高决策效率。 关键表设计 支付系统要点在支付系统中,支付网关和支付渠道的对接是最繁琐重要的功能之一,其中支付网关是对外提供服务的接口,所有需要渠道支持的资金操作都需要通过网关分发到对应的渠道模块上。一旦定型,后续就很少,也很难调整。而支付渠道模块是接收网关的请求,调用渠道接口执行真正的资金操作。每个渠道的接口,传输方式都不尽相同,所以在这里,支付网关相对于支付渠道模块的作用,类似设计模式中的wrapper,封装各个渠道的差异,对网关呈现统一的接口。而网关的功能是为业务提供通用接口,一些和渠道交互的公共操作,也会放置到网关中。 支付系统对其他系统,特别是交易系统,提供的支付服务包括签约,支付,退款,充值,转帐,解约等。有些地方还会额外提供签约并支付的接口,用于支持在支付过程中绑卡。 每个服务实现的流程也是基本类似,包括下单,取消订单,退单,查单等操作。每个操作实现,都包括参数校验,支付路由,生成订单,风险评估,调用渠道服务,更新订单和发送消息这7步,对于一些比较复杂的渠道服务,还会涉及到异步同通知处理的步骤。 网关前置支付网关前置是对接业务系统,为其提供支付服务的模块。它是所有支付服务接口的集成前置,将不同支付渠道提供的接口通过统一的方式呈现给业务方。这样接入方就只需要对接支付网关,增加和调整支付渠道对业务方是透明的。 支付网关前置的设计对整个支付系统的稳定性、功能、性能以及其他非功能性需求有着直接的影响。 在支付网关中需要完成大量的操作,为了保证性能,这些操作都尽量异步化来处理。支付网关前置应保持稳定,尽量减少系统重启等操作对业务方的影响。支付网关也避免不了升级和重启。这可通过基于Nginx的LBS(Load Balance System)网关来解决。LBS在这里有两个作用: 一个是实现负载均衡,一个是隔离支付网关重启对调用的影响。 支付网关也采用多台机器分布式部署,重启时,每个服务器逐个启动。某台服务器重启时,首先从LBS系统中取消注册,重启完成后,再重新注册到LBS上。这个过程对调用方是无感知的。 为了避免接口受攻击,在安全上,还得要求业务方通过HTTPS来访问接口,并提供防篡改机制。防篡改则通过接口参数签名来处理。现在主流的签名是对接口参数按照参数名称排序后,做加密和散列,参考微信的签名规范。 参数校验 所有的支付操作,都需要对输入执行参数校验,避免接口受到攻击。 验证输入参数中各字段的有效性验证,比如用户ID,商户ID,价格,返回地址等参数。 验证账户状态。交易主体、交易对手等账户的状态是处于可交易的状态。 验证订单:如果涉及到预单,还需要验证订单号的有效性,订单状态是未支付。为了避免用户缓存某个URL地址,还需要校验下单时间和支付时间是否超过预定的间隔。 验证签名。签名也是为了防止支付接口被伪造。 一般签名是使用分发给商户的key来对输入参数拼接成的字符串做MD5 Hash或者RSA加密,然后作为一个参数随其他参数一起提交到服务器端。 路由选择根据用户选择的支付方式确定用来完成该操作的合适的支付渠道。用户指定的支付方式不一定是最终的执行支付的渠道。比如用户选择通过工行信用卡来执行支付,但是我们没有实现和工行的对接,而是可以通过第三方支付,比如支付宝、微信支付、易宝支付,或者银联来完成。那如何选择合适的支付渠道,就通过支付路由来实现。支付路由会综合考虑收费、渠道的可用性等因素来选择最优方案 风险评估检查本次交易是否有风险。风控接口返回三种结果:阻断交易、增强验证和放行交易。 阻断交易,说明该交易是高风险的,需要终止,不执行第5个步骤; 增强验证,说明该交易有一定的风险,需要确认下是不是用户本人在操作。这可以通过发送短信验证码或者其他可以验证用户身份的方式来做校验,验证通过后,可以继续执行该交易。 放行交易,即本次交易是安全的,可以继续往下走。 发送消息通过消息来通知相关系统关于订单的变更。风控,信用BI等,都需要依赖这数据做准实时计算。 更新订单对于同步返回的结果,需要在主线程中更新订单的状态,标记是支付成功还是失败。对于异步返回的渠道,需要在异步程序中处理。 异步通知其中涉及到调用远程接口,其延迟不可控。如果调用方一直阻塞等待,很容易超时。引入异步通知机制,可以让调用方在主线程中尽快返回,通过异步线程来得到支付结果。对于通过异步来获取支付结果的渠道接口,也需要对应的在异步通知中将结果返回给调用方。 异步通知需要调用方提供一个回调地址,一般以http或者https的方式。这就有技术风险,如果调用失败,还需要重试。而重试不能过于频繁,需要逐步拉大每一次重试的时间间隔。 在异步处理程序中,订单根据处理结果变更状态后,也要发消息通知相关系统。 生成交易订单将订单信息持久化到数据库中。当访问压力大的时候,数据库写入会成为一个瓶颈。 交易流水和记账每一笔交易都需要记录流水,并登记到个人和机构的分户账户上,统计和分析也需要根据交易流水来更新相关数据。 而个人和机构账户总额更新、交易流水记录以及库存的处理,更是需要事务处理机制的支持。 从性能角度, 可以弱化了事务处理的要求,采用消息机制来异步化和交易相关的数据处理。 在支付网关前置的主流程中,仅记录交易流水,即将当前的请求保存到数据库中。 完成数据记录后,发送MQ出来,记账、统计、分析,都是接收MQ来完成数据处理。 涉及到本地资金支付,比如钱包支付,会需要分布式事务处理,扣减账号余额,记账,扣减库存等,每个操作失败,都要回滚。阿里有很不错的分享,这里不详细描述。 当交易量上来后,需要考虑交易表的分表分库的事情。分表分库有两个策略,按照流水号或者交易主体id来走。后者可以支持按用户来获取交易记录。我们用的是前者。后者可以走elastic,确保数据库专用。风控,信用和统计所需要的数据,通过MQ同步到历史库里面。作为支付系统最有价值的数据,在存储上做到专库专用,无可厚非,毕竟存储成本还是廉价的。 支付路由支付路由是一个复杂的话题。对支付系统来说,能支持的支付方式越多越好,不能由于支付方式的不支持断了财路。现实中的支付方式多得难以置信。用户随时甩出一张你听都没听说过的卡。如果一个银行卡只有几个用户在用,那针对这个卡开发个对接有点得不尝失。现在第三方支付的爆发,确实给开发支付系统省了不少事。但是公司不可能只对接一个第三方支付,如果这个渠道出问题了,或者闹矛盾了,把链接给掐了,老板还不欲哭无泪。总之,得对接多个渠道。对于交易量大的银行,还得考虑直联。 渠道接入对于支付渠道,首先考虑的是接入哪些渠道。要对接的渠道按优先级有: 第三方支付,对大部分应用来说,支付宝和微信支付都是必须的,一般来说,这两者可以占到90%以上的交易量。用户不需要绑卡,授权后直接支付就行。各种平台都支持,性能和稳定性都不错。对于一些特殊业务,比如游戏,企业支付,可以查看一些专用的第三方支付平台。 银联,它的存在,极大方便了和银行的对接。和第三方支付主要不同在两个地方一是需要绑卡,也就是用户先把卡号,手机,身份证号提供出来。这一步会折损不少用户。绑卡后,以后的支付操作就简单了,用户只需要输入密码就行。手机客户端不需要像第三方支付那样安装SDK,都在服务器端完成。当然,这是针对快捷支付。网银支付还是挺麻烦的。银联接入也需要ADSS认证。 银行:2018年2月9日银监会公布了最新权威数字:一共【4549家】开发性金融机构1家:国家开发银行;政策性银行2家:进出口银行、农业发展银行;5大国有银行:工、建、农、中、交;邮储银行1家;全国性股份制商业银行12家:招行、中信、兴业、民生、浦发、光大、广发、华夏、平安、浙商、渤海、恒丰;金融资产管理公司4家:信达、华融、长城、东方四大AMC;城商行134家;住房储蓄银行1家;民营银行17家,如网商银行;农商行1262家;农村合作银行33家;农村信用社965家;村镇银行1562家;贷款公司13家;农村资金互助社48家;外资法人银行39家;信托公司68家;金融租赁公司69家;企业集团财务公司247家;汽车金融公司25家;消费金融公司22家;货币经纪公司5家;其他金融机构14家。一般对接一个银行预计有3周左右的工作量,大部分银行需要专线接入,费用和带宽有关,一年也得几万费用。不同银行对接入环境有不同要求,这也是成本。 手机支付:比如苹果的In-App支付, 三星支付、华为支付等, 这些支付仅针对特定的手机型号, 支持NFC等,根据业务需要也可以接入。 总结支付系统是一个繁杂的系统,其中涉及了各种错综复杂的业务流程,以上只是简单介绍了支付系统我们能看见的一些问题和设计,还有后续的系统保障没有写出来,没写出来的才是关键部分,比如:支付系统监控(业务监控分类、渠道监控、商户监控、账户监控)文章只是引子, 架构不是静态的,而是动态演化的。只有能够不断应对环境变化的系统,才是有生命力的系统。所以即使你掌握了以上所有的业务细节,仍然需要演化式思维,在设计的同时,借助反馈和进化的力量推动架构的持续演进。 原文转载自","link":"/design-architecture/%E6%94%AF%E4%BB%98%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1-%E8%BD%AC%E8%BD%BD.html"},{"title":"Java设计模式之装饰者模式","text":"问题引入咖啡店的类设计: 一个饮料基类,各种饮料类继承这个基类,并且计算各自的价钱。 饮料中需要加入各种调料,考虑在基类中加入一些布尔值变量代表是否加入各种调料,基类的cost()中的计算各种调料的价钱,子类覆盖cost(),并且在其中调用超类的cost(),加上特定饮料的价钱,计算出子类特定饮料的价钱。 缺点:类数量爆炸、基类加入的新功能并不适用于所有的子类、调料价钱的改变、新调料的出现都会要求改变现有代码;有的子类并不适合某些调料等情况…… 设计原则 类应该对扩展开放,对修改关闭。 我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。 如能实现这样的目标,有什么好处呢?这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。 要让OO设计同时具备开放性和关闭性,不是一件容易的事,通常来说,没有必要把设计的每个部分都这么设计。 遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度。 我们需要把注意力集中在设计中最有可能改变的地方,然后应用开放-关闭原则。 用装饰者模式解决问题解决咖啡店饮料问题的方法: 以饮料为主体,然后在运行时以调料来“装饰”饮料。 比如,顾客想要摩卡(Mocha)和奶泡(Whip)深焙咖啡(DarkRoast): DarkRoast继承自Beverage,有一个cost()方法。 第一步,以DarkRoast对象开始; 第二步,顾客想要摩卡,所以建立一个Mocha装饰者对象,并用它将DarkRoast对象包装(wrap)起来; 第三步,顾客想要奶泡,所以建立一个Whip装饰者对象,并用它将Mocha对象包起来;(Mocha和Whip也继承自Beverage,有一个cost()方法); 最后,为顾客算钱,通过调用最外圈装饰者(Whip)的cost()就可以。Whip()的cost()会先委托它装饰的对象(Mocha)计算出价钱,然后在加上奶泡的价钱。Mocha的cost()也是类似。 装饰者模式的特点 装饰者和被装饰对象有相同的超类型。 可以用一个或多个装饰者包装一个对象。 因为装饰者和被装饰者具有相同的类型,所以任何需要原始对象的场合,可以用装饰过的对象代替。 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。 装饰者模式的定义装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。 装饰者模式的实现实现类图 装饰者和被装饰者具有共同的超类,利用继承达到“类型匹配”,而不是利用继承获得“行为”;将装饰者和被装饰者组合时,加入新的行为。 实现Java代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133// 抽象饮料类(抽象组件)public abstract class Beverage { String description = \"Unkown Beverage\"; public String getDescription() { return description; } /** * 抽象价格计算方法 * @return */ public abstract double cost();}// 浓缩饮料public class Espresso extends Beverage { public Espresso() { description = \"Espresso\"; } @Override public double cost() { return 1.99; }}// 又一饮料public class HouseBlend extends Beverage { public HouseBlend() { description = \"House Blend\"; } @Override public double cost() { return .20; }}// 抽象装饰者类public abstract class CondimentDecorator extends Beverage { /** * 为了后面的调料都能够获取到自己调料的描述 */ public abstract String getDescription();}/** * @desc Mocha调料(具体装饰者) */public class Mocha extends CondimentDecorator { Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() + \",Mocha\"; } @Override public double cost() { return .20 + beverage.cost(); }}/** * @desc Soy调料(具体装饰者) */public class Soy extends CondimentDecorator { Beverage beverage; public Soy(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() + \",Soy\"; } @Override public double cost() { return .60 + beverage.cost(); }}/** * @desc Whip调料(具体装饰者) */public class Whip extends CondimentDecorator { Beverage beverage; public Whip(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() + \",Whip\"; } @Override public double cost() { return .40 + beverage.cost(); }}/** * @desc 测试装饰者模式 */public class MainTest { public static void main(String[] args) { // 创建一种调料 Beverage beverage = new Espresso(); // 描述和价格 System.out.println(beverage.getDescription() + \" $\" + beverage.cost()); Beverage beverage1 = new HouseBlend(); beverage1 = new Mocha(beverage1); beverage1 = new Whip(beverage1); beverage1 = new Soy(beverage1); System.out.println(beverage1.getDescription() + \" $\" + beverage1.cost()); Beverage beverage2 = new Espresso(); beverage2 = new Mocha(beverage2); beverage2 = new Whip(beverage2); beverage2 = new Soy(beverage2); beverage2 = new Mocha(beverage2); System.out.println(beverage2.getDescription() + \" $\" + beverage2.cost()); }} 测试结果 装饰者和被装饰者具有共同的超类,利用继承达到“类型匹配”,而不是利用继承获得“行为”;将装饰者和被装饰者组合时,加入新的行为。 解决本文中饮料的具体问题时,图中Component即为Beverage(可以是抽象类或者接口),而ConcreteComponent为各种饮料,Decorator(抽象装饰者)为调料的抽象类或接口,ConcreteDecoratorX则为各种具体的调料。 因为使用对象组合,可以把饮料和调料更有弹性地加以混合与匹配。 代码外部细节: 代码中实现的时候,通过构造函数将被装饰者传入装饰者中即可,如最后的调用形式如下: 123Beverage beverage = new DarkRoast();beverage = new Mocha(beverage);beverage = new Whip(beverage); 即完成了两层包装,此时再调用beverage的cost()函数即可得到总价。 java.io包内的装饰者模式 装饰者模式的缺点:在设计中加入大量的小类,如果过度使用,会让程序变得复杂。 参考:http://www.cnblogs.com/mengdd/archive/2013/01/03/2843439.html","link":"/java/design-mode/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E8%A3%85%E9%A5%B0%E8%80%85%E6%A8%A1%E5%BC%8F.html"},{"title":"Java设计模式之工厂模式","text":"工厂模式序言工厂模式在《Java与模式》中分为三类: 简单工厂模式(Simple Factory):不利于产生系列产品; 工厂方法模式(Factory Method):又称为多形性工厂; 抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品; 这三种模式从上到下逐步抽象,并且更具一般性。GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。 简单工厂模式 简单工厂模式又称静态工厂方法模式。从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。 组成角色: 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。 简单工厂模式的UML图 简单工厂模式的Java代码1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374// 抽象接口 人类public interface Human { public void say();}// 男人public class Man implements Human { @Override public void say() { System.out.println(\"男人\"); }}// 女人public class Woman implements Human { @Override public void say() { System.out.println(\"女人\"); }}// 简单工厂public class SampleFactory { public static Human makeHuman(String type){ if(type.equals(\"man\")){ Human man = new Man(); return man; }else if(type.equals(\"womman\")){ Human woman = new Woman(); return woman; }else{ System.out.println(\"生产不出来\"); return null; } }}// 简单工厂模式反射实现public class SampleFactory1 { public static Human makeHuman(Class c){ Human human = null; try { human = (Human) Class.forName(c.getName()).newInstance(); } catch (InstantiationException e) { // TODO Auto-generated catch block System.out.println(\"不支持抽象类或接口\"); e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println(\"没有足够权限,即不能访问私有对象\"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block System.out.println(\"类不存在\"); e.printStackTrace(); } return human; }}// 简单工厂测试public class Client { public static void main(String[] args) { Human man = SampleFactory.makeHuman(\"man\"); man.say(); Human womman = SampleFactory.makeHuman(\"womman\"); womman.say(); Human test = SampleFactory.makeHuman(\"tttt\"); Human man = SampleFactory1.makeHuman(Man.class); man.say(); Human woman = SampleFactory1.makeHuman(Woman.class); woman.say(); }} 优缺点: 优点:工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。 缺点:由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利; 工厂方法模式 工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。 组成角色: 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。 工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代 码。可以看出工厂角色的结构也是符合开闭原则的! 工厂方法模式Java代码12345678910111213141516171819202122232425262728293031323334353637383940414243444546//抽象产品角色public interface Moveable { void run();}//具体产品角色public class Plane implements Moveable { @Override public void run() { System.out.println(\"plane....\"); }}public class Broom implements Moveable { @Override public void run() { System.out.println(\"broom.....\"); }}//抽象工厂public abstract class VehicleFactory { abstract Moveable create();}//具体工厂public class PlaneFactory extends VehicleFactory{ public Moveable create() { return new Plane(); }}public class BroomFactory extends VehicleFactory{ public Moveable create() { return new Broom(); }}//测试类public class Test { public static void main(String[] args) { VehicleFactory factory = new BroomFactory(); Moveable m = factory.create(); m.run(); }} 可以看出工厂方法的加入,使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。因为如果不能避免这种情 况,可以考虑使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实 现。 简单工厂和工厂方法模式的比较 工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。 反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了。 抽象工厂模式1234567891011121314151617181920212223242526272829303132333435//抽象工厂类public abstract class AbstractFactory { public abstract Vehicle createVehicle(); public abstract Weapon createWeapon(); public abstract Food createFood();}//具体工厂类,其中Food,Vehicle,Weapon是抽象类,public class DefaultFactory extends AbstractFactory{ @Override public Food createFood() { return new Apple(); } @Override public Vehicle createVehicle() { return new Car(); } @Override public Weapon createWeapon() { return new AK47(); }}//测试类public class Test { public static void main(String[] args) { AbstractFactory f = new DefaultFactory(); Vehicle v = f.createVehicle(); v.run(); Weapon w = f.createWeapon(); w.shoot(); Food a = f.createFood(); a.printName(); }} 在抽象工厂模式中,抽象产品 (AbstractProduct) 可能是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式。 总结 简单工厂模式是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。 工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。 参考:http://www.cnblogs.com/liaoweipeng/p/5768197.html http://www.cnblogs.com/forlina/archive/2011/06/21/2086114.html","link":"/java/design-mode/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F.html"},{"title":"Effective-Java-2-遇到多个构造器参数时考虑用构建器","text":"遇到多个构造器参数时考虑用构建器静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。当有超过20个可选域是必须的时候,对于此种情况,程序员一般考虑采用重叠构造器模式。这种模式下,提供第一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,以此类推,最后一个构造器包含所有的参数。 重叠构造器模式 含有四个可选域的情况 1234567891011121314151617181920212223242526272829public class NutritionFacts{ private final int servingSize; // required private final int servings; // required private final int calories; // optional private final int fat; // optional private final int sodium; // optional private final int carbohydrate; // optional public NutritionFacts(int servingSize, int servings){ this(servingSize, servings, 0); } public NutritionFacts(int servingSize, int servings, int calories){ this(servingSize, servings, calories, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat){ this(servingSize, servings, calories, fat, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium){ this(servingSize, servings, calories, fat, sodium, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate){ this(servingSize, servings, calories, fat, sodium, carbohydrate); } } 当你想创建实例的时候,就利用参数列表最短的构造器。 重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且较难阅读,使用的时候容易混淆部分参数容易出错 JavaBeans模式这种模式调用一个无参构造器来创建对象,然后用setter方法来设置必要的参数以及相关参数的值。 1234567891011121314151617181920public class NutritionFacts { private int servingSize = -1; // required private int servings = -1; // required private int calories = 0; // optional private int fat = 0; // optional private int sodium = 0; // optional private int carbohydrate = 0; // optional public NutritionFacts(){ } public void setServingSize(int val) { servingSize = val; } public void setServings(int val) { servings = val; } public void setCalories(int val) { calories = val; } public void setFat(int val) { fat = val; } public void setSodium(int val) { sodium = val; } public void setCarbohydrate(int val) { carbohydrate = val; }} 这种方式弥补了重叠构造器模式的不足,创建实例容易,阅读代码也容易。 12345NutritionFacts cocaCola = new NutritionFacts();cocaCola.setServingSize(10);cocaCola.setServings(10);cocaCola.setCalories(10);cocaCola.setFat(10); 遗憾的是自身有严重的缺陷。构造过程被分到了几个调用中,构造过程中JavaBean可能处于不一致状态的对象,将会导致失败。类无法仅仅通难过校验构造器参数的有效性来保证一致性,Javabeans模式阻止了把类做成不可变的可能,需要付出额外的努力来确保它的线程安全。 Builder模式既能保证像重叠构造器模式那样的安全性,也能保证像JavaBeans模式那样的可读性。 不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或静态工厂),得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用无参的build方法来生成不可变的对象,这个builder是它构建的类的静态成员类。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455public class NutritionFacts{ private final int servingSize; // required private final int servings; // required private final int calories; // optional private final int fat; // optional private final int sodium; // optional private final int carbohydrate; // optional public static class Builder{ private final int servingSize; // required private final int servings; // required private final int calories = 0; // optional private final int fat = 0; // optional private final int sodium = 0; // optional private final int carbohydrate = 0; // optional public Builder(int servingSize, int servings){ this.servingSize = servingSize; this.servings =servings; } public Builder calories(int val){ calories = val; return this; } public Builder fat(int val){ fat = val; return this; } public Builder sodium(int val){ sodium = val; return this; } public Builder carbohydrate(int val){ carbohydrate = val; return this; } public NutritionFacts build(){ return new NutritionFacts(this); } } private NutritionFacts(Builder builder){ servingSize = builder.servingSize; servings = builder.servingSize; calories = builder.servingSize; fat = builder.servingSize; sodium = builder.servingSize; carbohydrate = builder.servingSize; }} 注意NutritionFacts是不可变的,所有的默认参数值都单独放一个地方。builder的setter方法返回builder本身,以便可以把调用用调用链连接起来。 1NutritionFacts cocaCola = new NutritionFacts.Builder(200,20).calories(10).fat(15).sodium(10).build(); builder像个构造器一样,可以对其参数强加约束条件。build方法可以检验这些约束条件,将参数从builder拷贝到对象中之后,并在对象域而不是builder域中对他们进行校验,这一点很重要。如果违反了任何约束条件,build方法就应该抛出IllegalStateException,显示违背了哪个约束条件。 对多个参数强加约束条件的另一个方法,用多个setter方法对某个约束条件必须持有的所有参数进行检查。如果该约束条件没有得到满足,setter方法就抛出IllegalStateException,不用等到在build的时候。 设置了参数的builder生成了一个很好的抽象工厂,客户端可以将这样一个builder传给方法,使该方法能够为客户端创建一个或者多个对象。要使用这种用法,需要有个类型来表示builder,只要一个泛型就能满足所有的builder,无论他们在构建哪种类型的对象: 123public interface Builder<T>{ public T build();} 可以声明NutritionFacts.Builder类来实现Builder<NutritionFacts> 。 带有Builder实例的方法通常利用有限制的通配符类型来约束构建器的类型参数。eg.下面就是构建每个节点的方法,它利用一个客户端提供的Builder实例来构建树: 1Tree buildTree(Builder<? extends Node> nodeBuilder){ ... } **Builder模式还比重叠构造器模式更加冗长,因此它只有在很难参数的时候才使用,比如4个或者更多。但是你要记住,将来可能添加参数。简而言之,如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是种不错的选择,特别是大多参数都是可选的时候。代码易于阅读编写,构建器也比JavaBeans更加安全。","link":"/read-record/Effective-Java-2-%E9%81%87%E5%88%B0%E5%A4%9A%E4%B8%AA%E6%9E%84%E9%80%A0%E5%99%A8%E5%8F%82%E6%95%B0%E6%97%B6%E8%80%83%E8%99%91%E7%94%A8%E6%9E%84%E5%BB%BA%E5%99%A8.html"},{"title":"Java设计模式之单例模式","text":"单例模式 确保一个类只有一个实例,并提供一个全局访问点! 饿汉式:线程安全,但效率比较低 123456789101112131415161718/** * 单例模式的实现:饿汉式,线程安全 但效率比较低 */ public class SingletonTest { // 定义一个私有的构造方法 private SingletonTest() { } // 将自身的实例对象设置为一个属性,并加上Static和final修饰符 private static final SingletonTest instance = new SingletonTest(); // 静态方法返回该类的实例 public static SingletonTest getInstancei() { return instance; } } 单例模式的实现:饱汉式,非线程安全12345678910111213141516171819/** * 单例模式的实现:饱汉式,非线程安全 * */ public class SingletonTest { // 定义私有构造方法(防止通过 new SingletonTest()去实例化) private SingletonTest() { } // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字) private static SingletonTest instance; // 定义一个静态的方法(调用时再初始化SingletonTest,但是多线程访问时,可能造成重复初始化问题) public static SingletonTest getInstance() { if (instance == null) instance = new SingletonTest(); return instance; } } 饱汉式,线程安全简单实现1234567891011121314151617181920/** * 单例模式的实现:饱汉式,线程安全简单实现 * */ public class SingletonTest { // 定义私有构造方法(防止通过 new SingletonTest()去实例化) private SingletonTest() { } // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字) private static SingletonTest instance; // 定义一个静态的方法(调用时再初始化SingletonTest,使用synchronized 避免多线程访问时,可能造成重的复初始化问题) public static synchronized SingletonTest getInstance() { if (instance == null) instance = new SingletonTest(); return instance; } } 双重锁机制:线程安全,效率高,单例模式最优方案12345678910111213141516171819202122232425262728/** * 单例模式最优方案 * 线程安全 并且效率高 * */ public class SingletonTest { // 定义一个私有构造方法 private SingletonTest() { } //定义一个静态私有变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时instance变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用) private static volatile SingletonTest instance; //定义一个共有的静态方法,返回该类型实例 public static SingletonTest getIstance() { // 对象实例化时与否判断(不使用同步代码块,instance不等于null时,直接返回对象,提高运行效率) if (instance == null) { //同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不再重复被创建) synchronized (SingletonTest.class) { //未初始化,则初始instance变量 if (instance == null) { instance = new SingletonTest(); } } } return instance; } } 静态内部类方式12345678910111213/** * 静态内部类方式 * */ public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } } 这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。 总结【以上单例模式】传统的两私有一公开(私有构造方法、私有静态实例(懒实例化/直接实例化)、公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破坏单例)目前最为安全的实现单例的方法是通过内部静态enum的方法来实现,因为JVM会保证enum不能被反射并且构造器方法只执行一次。 利用反射模式获取1234567891011121314151617181920212223242526272829303132333435363738// 饿汉试单例模式public class HelloWorld {    private HelloWorld(){};    private static HelloWorld hell = new HelloWorld();    public static HelloWorld getHello(){        return hell;    }    public void getWorld(){        System.out.println(\"hahahahah\");    }}// java反射机制  调用getWorld()方法public class HelloJava{    public static void main(String[] args){ /* HelloWorld hell = HelloWorld.getHello();        hell.getWorld(); */        try          {              Class class1 = Class.forName(\"cn.jr.text.HelloWorld\");              Constructor[] constructors = class1.getDeclaredConstructors();              AccessibleObject.setAccessible(constructors, true);              for (Constructor con : constructors)              {                  if (con.isAccessible())                  {                      Object classObject = con.newInstance();                      Method method = class1.getMethod(\"getWorld\");                      method.invoke(classObject);                  }              }          }          catch (Exception e)          {              e.printStackTrace();          }     }} 使用枚举的单例模式123456789101112131415161718public class EnumSingleton{ private EnumSingleton(){} public static EnumSingleton getInstance(){ return Singleton.INSTANCE.getInstance(); } private static enum Singleton{ INSTANCE; private EnumSingleton singleton; //JVM会保证此方法绝对只调用一次 private Singleton(){ singleton = new EnumSingleton(); } public EnumSingleton getInstance(){ return singleton; } }} 使用枚举,static处调用,初始化一次123456789101112131415161718192021222324public class StaticInitTest { private static List<Integer> dataList = null; static{ dataList = Singleton.INSTANCE.init(); } private static enum Singleton { INSTANCE; private List<Integer> list; private Singleton(){ fillData(); } private void fillData(){ list = new ArrayList<Integer>(5); for(int i =1; i<6; i++){ list.add(i); } } public List<Integer> init(){ return list; } }} 借助CAS(AtomicReference)实现单例模式:12345678910111213141516171819public class Singleton { private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>(); private Singleton() {} public static Singleton getInstance() { for (;;) { Singleton singleton = INSTANCE.get(); if (null != singleton) { return singleton; } singleton = new Singleton(); if (INSTANCE.compareAndSet(null, singleton)) { return singleton; } } }} 用CAS的好处在于不需要使用传统的锁机制来保证线程安全,CAS是一种基于忙等待的算法,依赖底层硬件的实现,相对于锁它没有线程切换和阻塞的额外消耗,可以支持较大的并行度。使用CAS实现单例只是个思路而已,只是拓展一下帮助读者熟练掌握CAS以及单例等知识、千万不要在代码中使用!!!这个代码其实有很大的优化空间。聪明的你,知道以上代码存在哪些隐患吗? 最终总结有两个问题需要注意: 如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类 装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。 如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。 对第一个问题修复的办法是: 123456789private static Class getClass(String classname) throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if(classLoader == null) classLoader = Singleton.class.getClassLoader(); return (classLoader.loadClass(classname)); } } 对第二个问题修复的办法是: 12345678910public class Singleton implements java.io.Serializable { public static Singleton INSTANCE = new Singleton(); protected Singleton() { } private Object readResolve() { return INSTANCE; } } 对我来说,我比较喜欢第a和e种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下,我会使用第a种方式,只有在要明确实现lazy loading效果时才会使用第e种方式,另外,如果涉及到反序列化创建对象时我会试着使用枚举的方式来实现单例,不过,我一直会保证我的程序是线程安全的,如果有其他特殊的需求,我可能会使用第七种方式,毕竟,JDK1.5已经没有双重检查锁定的问题了。 参考资料:java单例之enum实现方式 设计模式 java设计模式–单例模式","link":"/java/design-mode/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F.html"},{"title":"leetcode-2-Add Two Numbers","text":"Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Example:Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = 807. common 1234567891011121314151617181920212223242526272829/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode dummyHead = new ListNode(0); // 一点要赋值一个节点,进行操作 ListNode p = l1, q = l2, curr = dummyHead; int carry = 0; while (p != null || q != null) { int x = (p != null) ? p.val : 0; int y = (q != null) ? q.val : 0; int sum = carry + x + y; carry = sum / 10; curr.next = new ListNode(sum % 10); curr = curr.next; if (p != null) p = p.next; if (q != null) q = q.next; } if (carry > 0) { curr.next = new ListNode(carry); } return dummyHead.next; }} best123456789101112131415161718192021222324252627282930/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode head = new ListNode(0); int carry = 0; while(l1!=null||l2!=null||carry>0) { ListNode itr = head; while(itr.next!=null) itr = itr.next; // 寻找最后一个节点 int sum = ( (l1==null ? 0 : l1.val) + (l2==null ? 0 : l2.val) + carry); carry = sum/10; ListNode temp = new ListNode(sum%10); itr.next = temp; if(l1!=null) l1 = l1.next; if(l2!=null) l2 = l2.next; } return head.next; }}","link":"/algorithm/leetcode-2-Add-Two-Numbers.html"},{"title":"Java设计模式之观察者模式","text":"定义 在阎宏博士的《JAVA与模式》一书中开头是这样描述观察者(Observer)模式的:观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 推结构模式推模式相关结构说明一个软件系统里面包含了各种对象,就像一片欣欣向荣的森林充满了各种生物一样。在一片森林中,各种生物彼此依赖和约束,形成一个个生物链。一种生物的状态变化会造成其他一些生物的相应行动,每一个生物都处于别的生物的互动之中。 同样,一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其他的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。 下面以一个简单的示意性实现为例,讨论观察者模式的结构。 观察者模式所涉及的角色有: ● 抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。 ● 具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。 ● 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。 ● 具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。 主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。 抽象观察者角色1234public interface Observer { void update(String state); String getName();} 具体观察者1234567891011121314151617181920212223242526public class ConcreteObserver implements Observer { private String name; private String state; public ConcreteObserver(String name) { this.name = name; } public String getState() { return state; } public void setState(String state) { this.state = state; } @Override public void update(String state) { // 更新观察 着状态 this.state = state; System.out.println(getName() + \"观察者状态更新为:\" + state); } @Override public String getName() { return name; }} 抽象主题角色1234567891011121314151617181920212223242526272829303132public abstract class Subject { /** * 保存观察者的容器 */ private List<Observer> list = new ArrayList<Observer>(); /** * 注册观察者 */ public void register(Observer o) { list.add(o); System.out.println(\"增加了一个观察者:\" + o.getName()); } /** * 移除观察者 * * @param o */ public void remove(Observer o) { System.out.println(\"移除了一个观察者:\" + o.getName()); list.remove(o); } /** * 通知观察者 * * @param newState */ public void nodifyObservers(String newState) { for (Observer observer : list) { observer.update(newState); } }} 具体主题角色12345678910111213141516public class ConcreteSubject extends Subject { /** * 状态 */ private String state; public String getState() { return state; } public void change(String newState) { state = newState; System.out.println(\"状态变为:\" + newState); System.out.println(\"开始通知观察者...\"); this.nodifyObservers(state); }} 测试类12345678910111213public class MainTest { public static void main(String[] args) { Observer o1 = new ConcreteObserver(\"o1\"); Observer o2 = new ConcreteObserver(\"o2\"); Observer o3 = new ConcreteObserver(\"o3\"); ConcreteSubject csj = new ConcreteSubject(); csj.register(o1); csj.register(o2); csj.register(o3); csj.remove(o2); csj.change(\"new State!\"); }} 输出结果 在运行时,这个客户端首先创建了具体主题类的实例,以及一个观察者对象。然后,它调用主题对象的register()方法,将这个观察者对象向主题对象登记,也就是将它加入到主题对象的聚集中去。 这时,客户端调用主题的change()方法,改变了主题对象的内部状态。主题对象在状态发生变化时,调用超类的notifyObservers()方法,通知所有登记过的观察者对象 拉模式结构说明 主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。 抽象观察者角色12345678public interface Observer { /** * 传入主题,获取中的对象 * @param subject */ void update(Subject subject); String getName();} 具体观察者123456789101112131415161718192021222324252627public class ConcreteObserver implements Observer { private String name; private String state; public ConcreteObserver(String name) { this.name = name; } public String getState() { return state; } public void setState(String state) { this.state = state; } @Override public String getName() { return name; } @Override public void update(Subject subject) { // 主动去主题里拿数据 state = ((ConcreteSubject) subject).getState(); System.out.println(getName() + \"观察者状态更新为:\" + state); }} 抽象主题角色1234567891011121314151617181920212223242526272829303132333435public abstract class Subject { /** * 保存观察者的容器 */ private List<Observer> list = new ArrayList<Observer>(); /** * 注册观察者 */ public void register(Observer o) { list.add(o); System.out.println(\"增加了一个观察者:\" + o.getName()); } /** * 移除观察者 * * @param o */ public void remove(Observer o) { System.out.println(\"移除了一个观察者:\" + o.getName()); list.remove(o); } /** * 通知观察者 * * @param newState */ public void nodifyObservers() { for (Observer observer : list) { observer.update(this); } }} 具体主题角色123456789101112131415161718public class ConcreteSubject extends Subject { /** * 状态 */ private String state; public String getState() { return state; } public void change(String newState) { state = newState; System.out.println(\"状态变为:\" + newState); System.out.println(\"开始通知观察者...\"); this.nodifyObservers(); }} 测试12345678910111213public class MainTest { public static void main(String[] args) { Observer o1 = new ConcreteObserver(\"o1\"); Observer o2 = new ConcreteObserver(\"o2\"); Observer o3 = new ConcreteObserver(\"o3\"); ConcreteSubject csj = new ConcreteSubject(); csj.register(o1); csj.register(o2); csj.register(o3); csj.remove(o2); csj.change(\"new State!\"); }} 测试结果 两种模式的比较 推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值。 推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是主题对象本身,这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。 参考链接","link":"/java/design-mode/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F.html"},{"title":"Immutable Object(不可变对象)模式","text":"多线程下,一个对象会被多个线程共享,存在多线程并发地修改对象的属性,需要做些同步访问控制,如显示锁,CAS操作,会带来额外的开销和问题,如上下文切换、等待时间、ABA问题。Immutable Object模式意图通过使用对外可见的状态不可变的对象,使得天生具有线程安全性。 车辆管理系统状态可变的位置信息模型123456789101112131415161718192021public class Location { private double x; private double y; public Location(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public double getY() { return y; } public void setXY(double x, double y) { this.x = x; this.y = y; }} 管理系统中会调用Location的setXY方法来更新位置,因为是非线程安全,并非原子操作,导致调用时会出现数据不一致的情况 改进:状态不可变的位置信息模型123456789public final class Location{ public final double x; public final double y; public Location(double x,double y){ this.x = x; this.y = y; }} 使用状态不可变的对象时,更新信息模型时,如果车辆的位置发生变动,更新的是整个位置信息的对象 更新不可变对象的位置信息123456public class VehicleTracker{ private Map<String,Location> locMap = new ConcurrentHashMap<String, Location>(); public void updateLocation(String vehicleId,Location newLocation){ locMap.put(vehicleId,newLocation); } } 一个严格意义上的不可变对象应该满足以下所有条件 类本身用final修饰 所有字段都是用final修饰,这个语意在多线程环境下由JVM保证了被修饰字段所引用对象的初始化安全,即final修饰的字段在其他线程是可见的,必定是初始化完成的。 在对象的创建过程中,this关键字没有泄露给其他类,防止其他类在对象创建过程中修改其状态 任何字段如果引用其他状态可变的对象,如集合数组,这些字段必须是private修饰的,不能暴露给外部,所有相关方法要返回这些字段值,应该防止防御性复制 实例: 某彩信网关系统 在处理由增值业务提供商VASP下发给手机终端用户的彩信信息时,需要根据彩信接收方号码的前缀选择对应的彩信中心MMSC,然后转发消息给选中的彩信中心。由其他系统将彩信信息下发给手机终端用户。选择彩信中心的过程称为 路由 ,手机前缀和彩信中心对应的关系叫路由表,在系统中多线程共享,很少改变此数据,不希望访问这些数据时进行加锁并发访问控制,避免产生不必要的开销,所以选择immutable object模型。 彩信中心路由规则管理器1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253/***彩信中心路由规则管理器**/public final class MMSCRouter{ // 保证多线程环境下该变量的可见性 private static volatile MMSCRouter instance = new MMSCRouter(); // 维护手机号码前缀到彩信中心之间的映射关系 private final Map<String,MMSCInfo> routerMap; public MMSCRouter(){ // 将数据库表中的数据加载到内存,存为Map this.routerMap = MMSCRouter.retrieveRouterMapFromDB(); } private static Map<String,MMSCInfo> retrieveRouterMapFromDB(){ Map<String,MMSCInfo> map = new HashMap<>(); // 省略其余代码 return map; } public static MMSCRouter getInstance(){ return instance; } /** *根据手机号前缀获取彩信中心信息 **/ public MMSCInfo getMMSC(String msisdPrefix){ return routerMap.get(msisdPrefix); } /** *更新为指定的新实例 **/ public static void setInstance(MMSCRouter newInstance){ instance = newInstance; } /** *防御性复制 **/ private static Map<String,MMSCInfo> deepCopy(Map<String,MMSCInfo> m){ Map<String,MMSCInfo> result = new HashMap<String,MMSCInfo>(); for(String key : m.keySet()){ result.put(key, new MMSCInfo(m.get(key))); } return result; } // 防止外部代码修改可变数据routerMap的值 public Map<String,MMSCInfo> getRouterMap(){ return Collections.unmodifiableMap(deepCopy(routerMap)); }} 彩信中心信息123456789101112131415161718192021222324252627282930public final class MMSCInfo{ private final String deviceId; private final String url; private final int maxAttachmentSizeInBytes; public MMSCInfo(String deviceId, String url, int maxAttachmentSizeInBytes){ this.deviceId = deviceId; this.url = url; this.maxAttachmentSizeInBytes = maxAttachmentSizeInBytes; } public MMSCInfo(MMSCInfo protoType){ this.deviceId = protoType.deviceId; this.url = protoType.url; this.maxAttachmentSizeInBytes = protoType.maxAttachmentSizeInBytes; } public String getDeviceId(){ return deviceId; } public String getUrl(){ return url; } public int getMaxAttachmentSizeInBytes(){ return maxAttachmentSizeInBytes; } } 彩信中心信息变更的频率也同样不高。因此,当彩信网关系统通过网络被通知到这种彩信中心信息本身或者路由变更时,网关系统会重新生成新的MMSInfo和MMSRouter来反应变更。 彩信中心、路由表的变更123456789101112131415161718public class OMCAgent extends Thread{ @Override public void run(){ boolean isTableModificationMsg = false; String updatedTableName = null; while(true){ // 省略代码 从与OMC 连接中读取信息进行解析 // 解析到数据表更新信息后,重置MMSCRouter实例 if(isTableModificationMsg){ if(\"MMSCInfo\".equals(updatedTableName)){ // new MMSCRouter() 从数据库中加载变更的信息存入 MMSCRouter.setInstance(new MMSCRouter()); } } // 省略其他代码 } }} 本列中MMSCInfo 是一个严格意义上的不可变对象,虽然MMSCRouter对象对外提供了setInstance方法用于改变静态字段instance的值,但它仍然可被视作一个等效的不可变对象。因为setInstance仅仅改变instance变量指向的对象,而instance变量采用volatile修饰保证了其余线程的可见性,所以无需加锁其他线程也能获取到最新的instance 总结Immutable Object 模型使用场景 被建模对象的状态变化不频繁 同时对一组相关的数据进行写操作,因此需要保证原子性 使用某个对象作为安全的HashMap的可以key。由于final不可变对象不变所有hashcode不变,所以适合作为HashMap 的key。 参考文献java多线程编程实战指南(设计模式篇)黄文海/著","link":"/java/basic/Immutable-Object-%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%AF%B9%E8%B1%A1-%E6%A8%A1%E5%BC%8F.html"},{"title":"elasticsearch6 query 全文查询与词项查询","text":"query全文查询 QueryBuilders.matchQuery(“filed”,”value”).operator(Operator.AND); // 对查询的语句进行分词,分词后的词任意一个匹配doc都能查出来 term query 查询的是词项<分词后的> (eg:Java编程思想) Java编程 term query 不能查到 分词后变成(Java 编程 思想) matchQuery能查到 QueryBuilders.matchPhraseQuery(“field”,”value”);对value进行分词,可以自定义分词器,满足两个条件才能被搜到: 分词后的所有词项都要匹配原字段 顺序还需要一致 QueryBuilders.matchPhrasePrefixQuery(“field”,”value”);与matchPhraseQuery类似,最后一个term支持前缀匹配eg.matchPhraseQuery 查 “hello word” matchPhrasePrefixQuery只需要查 **”hello w”**即可 QueryBuilders.multiMatchQuery(“value”,”field1”,”field2”); 多字段支持查询,字段可以使用通配符eg,{\"中国\",\"tit*\",\"wor?\"} QueryBuilders.commonTermsQuery(“哇”,”hehe”);通用查询,会自动分词为低频和高频项,先查低频,可以控制低频、高频出现概率 eg.the word the就是高频 ,可以先查 word QueryBuilders.queryStringQuery(“”);支持lucene查询语法 QueryBuilders.simpleQueryStringQuery(“”);支持lucene查询语法,具有非常完善的语法查询,解析过程中出现异常不会抛错 QueryBuilders.matchAllQuery();查所有和不写同样效果 词项查询 term query 词项检索 terms query 词项检索,可以多个词项,查到一个都能匹配结果 range query 查询范围内的 gt 大于 gte 大于等于 lt 小于 lte 小于等于 exist query 查询会返回字段中至少有一个非空空字符串也返回的doc prefix query 查询字段中给定前缀的文档 eg.{\"title\":\"hel\"} wildcard query 查询字段通配符eg.\"{\"title\":\"hell?/ *ell*\"} regexp query 正则匹配查询eg.{\"title\":\"W[0-9].+\"} fuzzy query 模糊查询,最接近的查询,单词拼错一个字母的时候,消耗资源多 type query 指定类型的文档 ids query 查询具有指定id的文档","link":"/java/elasticsearch/elasticsearch6-query-%E5%85%A8%E6%96%87%E6%9F%A5%E8%AF%A2%E4%B8%8E%E8%AF%8D%E9%A1%B9%E6%9F%A5%E8%AF%A2.html"},{"title":"leetcode-1-Two Sum","text":"description Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice. Example: Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]. common method 1234567891011121314class Solution { public int[] twoSum(int[] nums, int target) { int[] ret = new int[2]; for(int i =0; i<nums.length-1 ;i++){ for (int j = i+1 ;j < nums.length ;j++ ){ if (nums[i] + nums[j] == target){ ret = new int[]{i, j}; return ret; } } } return ret ; }} best method1234567891011121314151617class Solution { public int[] twoSum(int[] nums, int target) { int len=nums.length; HashMap<Integer, Integer> map=new HashMap<>(); map.put(nums[0], 0); for(int i=1;i<len;i++){ if(map.containsKey(target-nums[i])){ int[] returnArray={map.get(target-nums[i]),i}; return returnArray; } else{ map.put(nums[i], i); } } int[] returnArray={0,0}; return returnArray; }}","link":"/algorithm/leetcode-1-Two-Sum.html"},{"title":"Hello blog","text":"this is a first blog.It's a very exciting time make a plan execute have a harvest come on 12345public void start(){ while(true){ System.out.println(\"struggle!\"); }}","link":"/think/Hello-blog.html"},{"title":"Hello World","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Deploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesDeploy to remote sitesQuick StartCreate a new post1$ hexo new \" My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment Quick StartCreate a new post1$ hexo new \" My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment Quick StartCreate a new post1$ hexo new \" My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment Quick StartCreate a new post1$ hexo new \" My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment Quick StartCreate a new post1$ hexo new \" My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment Quick StartCreate a new post1$ hexo new \" My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","link":"/think/hello-world.html"},{"title":"2019成长记01","text":"2019-10-30 星期三 十月初三己亥年 【猪年】甲戌月 庚子日 成都天气:晴 今日生辰。 回想这一年,有些事情过的跟电视剧一样。 关于生活 一个亲戚因涉毒,入狱,无期徒刑。 一个亲戚因网上赌博,欠了一屁股债,各种网贷,险些家破人亡。 以上两件事简直是电视剧才有的剧情,还是发生在现实中了。从中也想明白了很多道理,对以上结果也没什么悲愤的,出来混总是要还的。有些事情(黄、赌、毒)一辈子都不能碰,时刻警醒自己。 关于爱情 相了几次亲,加了几个微信好友,不是我没看上的,就是没看上我的。 追过一个同事,无果;因为性格或者家庭的原因最后没有继续。 关于爱情,随遇而安。有一段美好的爱情,有一个懂自己、互相照顾的伴侣固然很好,所有的事情都看缘分,不能强求,没有的时候也要过好每一天。有时候想想一辈子真的挺短的,死后一切都与自己无关,活着的时候还是要开心、淡然的度过每一天。现在觉得一个人也不是不能过,还是挺好的,有更多的时间做自己想做的事情。 关于亲情 父母、亲人都年纪大了,多抽些时间陪陪他们。 春节、国庆回家。 记得每次从家里走,妈妈都要让带很多吃的东西。每次呢,我又嫌懒的带,每次都争的各自不开心,今年开始能不争就不争了,真的没必要。本来是一件好事,都是出于爱,对家人们应该多一些耐心。 可能因为单身久了吧,觉得最关心自己的还是自己的家人。基本每隔一天都要给家里开微信视频,虽然每次也没啥说的,遇到事情时,最担心你的还是亲人。 关于运动 参加了2次半马(汶川、眉山),今年还有一次全马(西昌),一次半马(乐山),希望能够坚持跑完。 还是去了很多次健身房、游了很多次泳。基本学会了蛙泳。 晚上也有空的时候跑跑步。 关于运动还是要多运动,毕竟身体是革命的本钱。体重越来越重,可能年纪大了,也开始注重自己的身体了。碳酸饮料、冰冻食品、火锅烧烤也吃的少了。 关于工作 平平淡淡,也没有什么大起大落。 在北美省钱快报,没辞职。 关于工作中的技术更新迭代太快,平时还是得多积累学习,未雨绸缪,多掌握一些技能,为步入大龄程序员打好基础。 关于学习 断断续续的学了些单词。 买了1-4册哈利波特,算是送给自己的生日礼物。 微信读书基本快读了300个小时,每个星期基本5小时,后续继续保持。 学习使人进步,从读书中更能够看清生活的本质,能够找到更多的精神寄托,多读书,多读名著。 关于娱乐 楼下开了电影院,看了22场电影。 电视剧应该追了7、8部。 综艺节目也追了不少。 不管电影,电视剧还是综艺节目都能提高一个人的格局和观念,平时还是要多看些高质量的节目,也不能沉溺其中。 关于博客 github上搭建了自己的博客。 写了一些文章。 改了一些博客的源码。 多坚持发表原创文章,真正的理解某些东西,只有写出来,讲出来,让别人也能看懂或听懂才是真正的理解。","link":"/private/2019%E6%88%90%E9%95%BF%E8%AE%B001.html"}],"tags":[{"name":"二分查找","slug":"二分查找","link":"/tags/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/"},{"name":"动态规划","slug":"动态规划","link":"/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"},{"name":"dp","slug":"dp","link":"/tags/dp/"},{"name":"分治算法","slug":"分治算法","link":"/tags/%E5%88%86%E6%B2%BB%E7%AE%97%E6%B3%95/"},{"name":"字符串","slug":"字符串","link":"/tags/%E5%AD%97%E7%AC%A6%E4%B8%B2/"},{"name":"滑动窗口","slug":"滑动窗口","link":"/tags/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/"},{"name":"贪心算法","slug":"贪心算法","link":"/tags/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/"},{"name":"分治","slug":"分治","link":"/tags/%E5%88%86%E6%B2%BB/"},{"name":"双指针","slug":"双指针","link":"/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"},{"name":"递归回溯","slug":"递归回溯","link":"/tags/%E9%80%92%E5%BD%92%E5%9B%9E%E6%BA%AF/"},{"name":"栈","slug":"栈","link":"/tags/%E6%A0%88/"},{"name":"链表","slug":"链表","link":"/tags/%E9%93%BE%E8%A1%A8/"},{"name":"递归","slug":"递归","link":"/tags/%E9%80%92%E5%BD%92/"},{"name":"最长回文","slug":"最长回文","link":"/tags/%E6%9C%80%E9%95%BF%E5%9B%9E%E6%96%87/"},{"name":"Z字变换","slug":"Z字变换","link":"/tags/Z%E5%AD%97%E5%8F%98%E6%8D%A2/"},{"name":"反转整数","slug":"反转整数","link":"/tags/%E5%8F%8D%E8%BD%AC%E6%95%B4%E6%95%B0/"},{"name":"字符串转整数","slug":"字符串转整数","link":"/tags/%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%95%B4%E6%95%B0/"},{"name":"中心扩展","slug":"中心扩展","link":"/tags/%E4%B8%AD%E5%BF%83%E6%89%A9%E5%B1%95/"},{"name":"最优解","slug":"最优解","link":"/tags/%E6%9C%80%E4%BC%98%E8%A7%A3/"},{"name":"科普","slug":"科普","link":"/tags/%E7%A7%91%E6%99%AE/"},{"name":"数据结构","slug":"数据结构","link":"/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"},{"name":"sql","slug":"sql","link":"/tags/sql/"},{"name":"Kafka","slug":"Kafka","link":"/tags/Kafka/"},{"name":"幂等性","slug":"幂等性","link":"/tags/%E5%B9%82%E7%AD%89%E6%80%A7/"},{"name":"restful-api","slug":"restful-api","link":"/tags/restful-api/"},{"name":"支付系统","slug":"支付系统","link":"/tags/%E6%94%AF%E4%BB%98%E7%B3%BB%E7%BB%9F/"},{"name":"支付架构","slug":"支付架构","link":"/tags/%E6%94%AF%E4%BB%98%E6%9E%B6%E6%9E%84/"},{"name":"秒杀系统,支付设计","slug":"秒杀系统,支付设计","link":"/tags/%E7%A7%92%E6%9D%80%E7%B3%BB%E7%BB%9F%EF%BC%8C%E6%94%AF%E4%BB%98%E8%AE%BE%E8%AE%A1/"},{"name":"Git","slug":"Git","link":"/tags/Git/"},{"name":"rebase","slug":"rebase","link":"/tags/rebase/"},{"name":"vim","slug":"vim","link":"/tags/vim/"},{"name":"git","slug":"git","link":"/tags/git/"},{"name":"gpg sign","slug":"gpg-sign","link":"/tags/gpg-sign/"},{"name":"debug","slug":"debug","link":"/tags/debug/"},{"name":"调试代码","slug":"调试代码","link":"/tags/%E8%B0%83%E8%AF%95%E4%BB%A3%E7%A0%81/"},{"name":"English","slug":"English","link":"/tags/English/"},{"name":"grammar","slug":"grammar","link":"/tags/grammar/"},{"name":"前端技术","slug":"前端技术","link":"/tags/%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF/"},{"name":"health","slug":"health","link":"/tags/health/"},{"name":"ios","slug":"ios","link":"/tags/ios/"},{"name":"nfc","slug":"nfc","link":"/tags/nfc/"},{"name":"法律","slug":"法律","link":"/tags/%E6%B3%95%E5%BE%8B/"},{"name":"党章","slug":"党章","link":"/tags/%E5%85%9A%E7%AB%A0/"},{"name":"marathon","slug":"marathon","link":"/tags/marathon/"},{"name":"think","slug":"think","link":"/tags/think/"},{"name":"python3基础","slug":"python3基础","link":"/tags/python3%E5%9F%BA%E7%A1%80/"},{"name":"Effective-Java","slug":"Effective-Java","link":"/tags/Effective-Java/"},{"name":"读书笔记","slug":"读书笔记","link":"/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"},{"name":"自动部署Hexo博客","slug":"自动部署Hexo博客","link":"/tags/%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2Hexo%E5%8D%9A%E5%AE%A2/"},{"name":"工具教程","slug":"工具教程","link":"/tags/%E5%B7%A5%E5%85%B7%E6%95%99%E7%A8%8B/"},{"name":"博客统计插件","slug":"博客统计插件","link":"/tags/%E5%8D%9A%E5%AE%A2%E7%BB%9F%E8%AE%A1%E6%8F%92%E4%BB%B6/"},{"name":"icarus主题配置","slug":"icarus主题配置","link":"/tags/icarus%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE/"},{"name":"hexo主题","slug":"hexo主题","link":"/tags/hexo%E4%B8%BB%E9%A2%98/"},{"name":"hexo","slug":"hexo","link":"/tags/hexo/"},{"name":"hexo-theme","slug":"hexo-theme","link":"/tags/hexo-theme/"},{"name":"hexo-blog","slug":"hexo-blog","link":"/tags/hexo-blog/"},{"name":"经验成长","slug":"经验成长","link":"/tags/%E7%BB%8F%E9%AA%8C%E6%88%90%E9%95%BF/"},{"name":"docker","slug":"docker","link":"/tags/docker/"},{"name":"西安","slug":"西安","link":"/tags/%E8%A5%BF%E5%AE%89/"},{"name":"长安","slug":"长安","link":"/tags/%E9%95%BF%E5%AE%89/"},{"name":"旅行","slug":"旅行","link":"/tags/%E6%97%85%E8%A1%8C/"},{"name":"mybatis","slug":"mybatis","link":"/tags/mybatis/"},{"name":"b+tree","slug":"b-tree","link":"/tags/b-tree/"},{"name":"聚簇索引","slug":"聚簇索引","link":"/tags/%E8%81%9A%E7%B0%87%E7%B4%A2%E5%BC%95/"},{"name":"mysql","slug":"mysql","link":"/tags/mysql/"},{"name":"慢sql","slug":"慢sql","link":"/tags/%E6%85%A2sql/"},{"name":"like","slug":"like","link":"/tags/like/"},{"name":"模糊查询","slug":"模糊查询","link":"/tags/%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2/"},{"name":"like优化","slug":"like优化","link":"/tags/like%E4%BC%98%E5%8C%96/"},{"name":"索引","slug":"索引","link":"/tags/%E7%B4%A2%E5%BC%95/"},{"name":"死锁排查","slug":"死锁排查","link":"/tags/%E6%AD%BB%E9%94%81%E6%8E%92%E6%9F%A5/"},{"name":"sql优化","slug":"sql优化","link":"/tags/sql%E4%BC%98%E5%8C%96/"},{"name":"redis","slug":"redis","link":"/tags/redis/"},{"name":"java","slug":"java","link":"/tags/java/"},{"name":"并发","slug":"并发","link":"/tags/%E5%B9%B6%E5%8F%91/"},{"name":"多线程","slug":"多线程","link":"/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"},{"name":"集合","slug":"集合","link":"/tags/%E9%9B%86%E5%90%88/"},{"name":"正则表达式","slug":"正则表达式","link":"/tags/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/"},{"name":"hash冲突","slug":"hash冲突","link":"/tags/hash%E5%86%B2%E7%AA%81/"},{"name":"rehash","slug":"rehash","link":"/tags/rehash/"},{"name":"设计模式","slug":"设计模式","link":"/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"},{"name":"strategy","slug":"strategy","link":"/tags/strategy/"},{"name":"elasticsearch6","slug":"elasticsearch6","link":"/tags/elasticsearch6/"},{"name":"query","slug":"query","link":"/tags/query/"},{"name":"索引分词","slug":"索引分词","link":"/tags/%E7%B4%A2%E5%BC%95%E5%88%86%E8%AF%8D/"},{"name":"feign","slug":"feign","link":"/tags/feign/"},{"name":"spring cloud","slug":"spring-cloud","link":"/tags/spring-cloud/"},{"name":"spring","slug":"spring","link":"/tags/spring/"},{"name":"springboot","slug":"springboot","link":"/tags/springboot/"},{"name":"Valid","slug":"Valid","link":"/tags/Valid/"},{"name":"bean","slug":"bean","link":"/tags/bean/"},{"name":"Schedule","slug":"Schedule","link":"/tags/Schedule/"},{"name":"nacos","slug":"nacos","link":"/tags/nacos/"},{"name":"dubbo","slug":"dubbo","link":"/tags/dubbo/"},{"name":"swagger","slug":"swagger","link":"/tags/swagger/"},{"name":"websocket","slug":"websocket","link":"/tags/websocket/"},{"name":"websocket-server","slug":"websocket-server","link":"/tags/websocket-server/"}],"categories":[{"name":"algorithm","slug":"algorithm","link":"/categories/algorithm/"},{"name":"科普","slug":"科普","link":"/categories/%E7%A7%91%E6%99%AE/"},{"name":"数据结构","slug":"数据结构","link":"/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"},{"name":"数据库","slug":"数据库","link":"/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"},{"name":"架构","slug":"架构","link":"/categories/%E6%9E%B6%E6%9E%84/"},{"name":"mysql","slug":"数据库/mysql","link":"/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/"},{"name":"基础工具类","slug":"基础工具类","link":"/categories/%E5%9F%BA%E7%A1%80%E5%B7%A5%E5%85%B7%E7%B1%BB/"},{"name":"Kafka","slug":"架构/Kafka","link":"/categories/%E6%9E%B6%E6%9E%84/Kafka/"},{"name":"develop","slug":"develop","link":"/categories/develop/"},{"name":"设计","slug":"架构/设计","link":"/categories/%E6%9E%B6%E6%9E%84/%E8%AE%BE%E8%AE%A1/"},{"name":"English","slug":"English","link":"/categories/English/"},{"name":"Git","slug":"基础工具类/Git","link":"/categories/%E5%9F%BA%E7%A1%80%E5%B7%A5%E5%85%B7%E7%B1%BB/Git/"},{"name":"Vim","slug":"基础工具类/Vim","link":"/categories/%E5%9F%BA%E7%A1%80%E5%B7%A5%E5%85%B7%E7%B1%BB/Vim/"},{"name":"git","slug":"develop/git","link":"/categories/develop/git/"},{"name":"前端技术","slug":"前端技术","link":"/categories/%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF/"},{"name":"health","slug":"health","link":"/categories/health/"},{"name":"ios","slug":"ios","link":"/categories/ios/"},{"name":"法律","slug":"法律","link":"/categories/%E6%B3%95%E5%BE%8B/"},{"name":"grammar","slug":"English/grammar","link":"/categories/English/grammar/"},{"name":"marathon","slug":"marathon","link":"/categories/marathon/"},{"name":"private","slug":"private","link":"/categories/private/"},{"name":"python3","slug":"python3","link":"/categories/python3/"},{"name":"java","slug":"java","link":"/categories/java/"},{"name":"自动部署Hexo博客,Github Action","slug":"自动部署Hexo博客,Github-Action","link":"/categories/%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2Hexo%E5%8D%9A%E5%AE%A2%EF%BC%8CGithub-Action/"},{"name":"工具教程","slug":"工具教程","link":"/categories/%E5%B7%A5%E5%85%B7%E6%95%99%E7%A8%8B/"},{"name":"think","slug":"think","link":"/categories/think/"},{"name":"经验成长","slug":"经验成长","link":"/categories/%E7%BB%8F%E9%AA%8C%E6%88%90%E9%95%BF/"},{"name":"docker","slug":"基础工具类/docker","link":"/categories/%E5%9F%BA%E7%A1%80%E5%B7%A5%E5%85%B7%E7%B1%BB/docker/"},{"name":"travel","slug":"travel","link":"/categories/travel/"},{"name":"mybatis","slug":"数据库/mybatis","link":"/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/mybatis/"},{"name":"redis","slug":"数据库/redis","link":"/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/"},{"name":"正则","slug":"基础工具类/正则","link":"/categories/%E5%9F%BA%E7%A1%80%E5%B7%A5%E5%85%B7%E7%B1%BB/%E6%AD%A3%E5%88%99/"},{"name":"读书笔记","slug":"java/读书笔记","link":"/categories/java/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"},{"name":"主题工具","slug":"工具教程/主题工具","link":"/categories/%E5%B7%A5%E5%85%B7%E6%95%99%E7%A8%8B/%E4%B8%BB%E9%A2%98%E5%B7%A5%E5%85%B7/"},{"name":"博客统计插件","slug":"工具教程/博客统计插件","link":"/categories/%E5%B7%A5%E5%85%B7%E6%95%99%E7%A8%8B/%E5%8D%9A%E5%AE%A2%E7%BB%9F%E8%AE%A1%E6%8F%92%E4%BB%B6/"},{"name":"java基础","slug":"java/java基础","link":"/categories/java/java%E5%9F%BA%E7%A1%80/"},{"name":"JVM","slug":"java/JVM","link":"/categories/java/JVM/"},{"name":"并发","slug":"java/并发","link":"/categories/java/%E5%B9%B6%E5%8F%91/"},{"name":"设计模式","slug":"java/设计模式","link":"/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"},{"name":"elasticsearch6","slug":"java/elasticsearch6","link":"/categories/java/elasticsearch6/"},{"name":"框架","slug":"java/框架","link":"/categories/java/%E6%A1%86%E6%9E%B6/"},{"name":"springboot","slug":"java/springboot","link":"/categories/java/springboot/"},{"name":"spring","slug":"java/spring","link":"/categories/java/spring/"}],"pages":[{"title":"","text":"","link":"/404.html"},{"title":"","text":"","link":"/clock.html"},{"title":"","text":"个人简介 分享很喜欢的老罗的一段话: “每一个生命来到世间都注定改变世界,别无选择。要么变得好一点,要么变得坏一点。你如果走进社会为了生存为了什么不要脸的理由,变成了一个恶心的成年人社会中的一员,那你就把这个世界变得恶心了一点点。如果你一生刚正不阿,如果你一生耿直,没有做任何恶心的事情,没做对别人有害的事情,一辈子拼了老命勉强把自己身边的几个人照顾好了,没有成名没有发财,没有成就伟大的事业,然后耿着脖子一生正直,到了七八十岁耿着脖子去世了。你这一生是不是没有改变世界?你还是改变世界了,你把这个世界变得美好了一点点。因为世界上又多了一个好人。“ 善恶终有报,天道好轮回。不信抬头看,苍天饶过谁。无论何时何地,我们都要保持一颗积极乐观、善良感恩的心。但行好事莫问前程,永远年轻,永远热内盈眶,永远保持正能量。💪💪💪💪💪💪冲鸭!!!! ->>>>>>>>>>>>>>>>>>>>个人信息:计算机科学与技术专业从事JAVA后端开发码畜一枚坚信代码改变世界 博客信息 网站采用的Icarus主题 追求尽可能的简洁,清晰,易用。 在Icarus主题之上进行了部分修改。 更新日志:–2023.04.28:升级gitalk插件–2020.03.18:加入pjax支持–2020.03.01:独立出主题仓库hexo-theme-amazing–2020.01.18:适配icarus3.0代码–2019.11.17:增加深色主题开关–2019.10.30:去图,精简卡片–2019.10.22:改版部分显示,优化速度–2019.10.16:文章列表加上评论数显示–2019.10.13:改版评论–2019.09.25:图片、资源接入CDN免费jsDelivr、文章加入置顶–2019.09.19:开源博客代码–2019.09.19:修改布局,拉伸布局,更宽的展示–2019.09.18:修改友链ui为一行三个,并适配移动端,暗黑模式文章增加评论链接,增加留言链接–2019.09.14:增加精简next主题–2019.09.14:利用中秋节放假,重做了首页的热门推荐、加个widget最新评论框、归档页加入文章贡献概览面板 本站推荐索引 博客主题相关 github Issue 作为博客微型数据库的应用 github page网站cdn优化加速 博客源码分享 博客换肤的一种实现方式思路 博客中gitalk最新评论的获取 博客图片上传picgo工具github图传使用 安装、部分配置icarus主题中文版 技术知识点 Java并发知识点 法律法规 法律法规数据库 中华人民共和国国旗法 中华人民共和国宪法 中华人民共和国消费者权益保护法 中华人民共和国刑事诉讼法 中华人民共和国婚姻法 中华人名共和国网络安全法 中华人民共和国劳动法 其他 网易云音乐歌单分享 纪念页 捐赠 感觉博客不错、对你有帮助的话,欢迎捐赠,支持以下3种一次性捐赠,感谢! 点击浏览以下广告捐赠 (adsbygoogle = window.adsbygoogle || []).push({}); 计划2021计划 2021.01.02 2021-GOALS 跑两三场马拉松,平时定期每周至少运动一次 多学习,多写博文,至少沉淀10篇 多读书,平均每天1h,年底至少300h 去一次2-3天的旅行 多交朋友,多交流沟通 2020计划 2019.12.31->更新于2021.01.02 2020-GOALS 跑两三场马拉松 ->100% 1全,1半 多学习,多写博文,年终达到150篇 ->20% 年终119篇,差太远!!! 多读书,平均每天1h,年底至少300h ->95% 280h 晚上多跑步,一周至少两次,体重减少10斤 ->50% 去一次2-3天的旅行 ->0% 因为疫情等原因一次也没外出额外 换了工作总结 这一年经历了很多事情,看明白了很多事情,看清了自己的定位以及自身情况,确定了一些未来的计划以及目标,明白了当下重点该做的事情,以及交际中一些处事原则,生活礼仪,2021加油! 2019计划 2018.12.31/21:59:00->更新于2019.12.31 2019-GOALS 购买的专业书籍至少看完一遍(并发、重构、设计模式…)-> 95% 微信读书每天一个小时(目前时长:95h,年终总计300小时) -> 100%,405h 坚持每周去两次健身房(多练肚子、力量、学会蝶泳) -> 50%,蝶泳90%,其余30%左右 至少完成一项 前后端分离项目 -> 20%,烂尾 完成一项 微服务项目(类似公司使用相关技术) -> 20%,烂尾 不辞职 -> 100% 多交朋友、多换位思考、多与朋友交流沟通 -> 70% 居安思危,多思考关注相关专业前景,生活环境 -> 50% Java基础技能强化 -> 50% 多买书 -> 100% (新增哈利波特1-4汉英版) 学习更多的新菜(至少三项) -> 60% 少买电子产品,少网购,少逛数码产品 -> 60%(新增华米运动手表2二手,一加2二手,小米电纸书) 学英语记单词、学数学、多看视频教程 -> 20% 少玩游戏 -2019.06卸载游戏 -> 80%额外: 追了很多剧 写了好些博客文章,修改开源了博客源码 年末去了一趟西安旅行,看了一场移动的演出《驼铃传奇》,强烈安利! 入坑马拉松,跑了3场半程马拉松,一场全程马拉松总结: 有优点有缺点,没坚持下来的还是太多,追了太多剧。以后多学习,多思考! 时间轴记录","link":"/about/index.html"},{"title":"","text":"Since 2015.12.01 About her→    function show_date_time(){ window.setTimeout(\"show_date_time()\", 1000); BirthDay=new Date(\"12/01/2015 00:00:00\");//这个日期是可以修改的 today=new Date(); timeold=(today.getTime()-BirthDay.getTime()); sectimeold=timeold/1000 secondsold=Math.floor(sectimeold); msPerDay=24*60*60*1000 e_daysold=timeold/msPerDay daysold=Math.floor(e_daysold); e_hrsold=(e_daysold-daysold)*24; hrsold=Math.floor(e_hrsold); e_minsold=(e_hrsold-hrsold)*60; minsold=Math.floor((e_hrsold-hrsold)*60); seconds=Math.floor((e_minsold-minsold)*60); span_dt_dt.innerHTML=daysold+\"天\"+hrsold+\"小时\"+minsold+\"分\"+seconds+\"秒\"; } show_date_time(); var S = { init: function () { S.Drawing.init('.canvas'); document.body.classList.add('body--ready'); S.UI.simulate(\"Hello|I'm|removeif|Nice|To|Meet|You|Welcome|#countdown 5|#time\"); S.Drawing.loop(function () { S.Shape.render(); }); } }; S.Drawing = (function () { var canvas, context, renderFn, requestFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; return { init: function (el) { canvas = document.querySelector(el); context = canvas.getContext('2d'); this.adjustCanvas(); window.addEventListener('resize', function (e) { S.Drawing.adjustCanvas(); }); }, loop: function (fn) { renderFn = !renderFn ? fn : renderFn; this.clearFrame(); renderFn(); requestFrame.call(window, this.loop.bind(this)); }, adjustCanvas: function () { canvas.width = window.innerWidth - 100; canvas.height = window.innerHeight - 30; }, clearFrame: function () { context.clearRect(0, 0, canvas.width, canvas.height); }, getArea: function () { return {w: canvas.width, h: canvas.height}; }, drawCircle: function (p, c) { context.fillStyle = c.render(); context.beginPath(); context.arc(p.x, p.y, p.z, 0, 2 * Math.PI, true); context.closePath(); context.fill(); } }; }()); S.UI = (function () { var interval, currentAction, time, maxShapeSize = 30, sequence = [], cmd = '#'; function formatTime(date) { var h = date.getHours(), m = date.getMinutes(), m = m < 10 ? '0' + m : m; return h + ':' + m; } function getValue(value) { return value && value.split(' ')[1]; } function getAction(value) { value = value && value.split(' ')[0]; return value && value[0] === cmd && value.substring(1); } function timedAction(fn, delay, max, reverse) { clearInterval(interval); currentAction = reverse ? max : 1; fn(currentAction); if (!max || (!reverse && currentAction < max) || (reverse && currentAction > 0)) { interval = setInterval(function () { currentAction = reverse ? currentAction - 1 : currentAction + 1; fn(currentAction); if ((!reverse && max && currentAction === max) || (reverse && currentAction === 0)) { clearInterval(interval); } }, delay); } } function performAction(value) { var action, value, current; sequence = typeof (value) === 'object' ? value : sequence.concat(value.split('|')); timedAction(function (index) { current = sequence.shift(); action = getAction(current); value = getValue(current); switch (action) { case 'countdown': value = parseInt(value) || 10; value = value > 0 ? value : 10; timedAction(function (index) { if (index === 0) { if (sequence.length === 0) { S.Shape.switchShape(S.ShapeBuilder.letter('')); } else { performAction(sequence); } } else { S.Shape.switchShape(S.ShapeBuilder.letter(index), true); } }, 1000, value, true); break; case 'rectangle': value = value && value.split('x'); value = (value && value.length === 2) ? value : [maxShapeSize, maxShapeSize / 2]; S.Shape.switchShape(S.ShapeBuilder.rectangle(Math.min(maxShapeSize, parseInt(value[0])), Math.min(maxShapeSize, parseInt(value[1])))); break; case 'circle': value = parseInt(value) || maxShapeSize; value = Math.min(value, maxShapeSize); S.Shape.switchShape(S.ShapeBuilder.circle(value)); break; case 'time': var t = formatTime(new Date()); if (sequence.length > 0) { S.Shape.switchShape(S.ShapeBuilder.letter(t)); } else { timedAction(function () { t = formatTime(new Date()); if (t !== time) { time = t; S.Shape.switchShape(S.ShapeBuilder.letter(time)); } }, 1000); } break; default: S.Shape.switchShape(S.ShapeBuilder.letter(current[0] === cmd ? 'HacPai' : current)); } }, 3000, sequence.length); } return { simulate: function (action) { performAction(action); } }; }()); S.Point = function (args) { this.x = args.x; this.y = args.y; this.z = args.z; this.a = args.a; this.h = args.h; }; S.Color = function (r, g, b, a) { this.r = r; this.g = g; this.b = b; this.a = a; }; S.Color.prototype = { render: function () { return 'rgba(' + this.r + ',' + +this.g + ',' + this.b + ',' + this.a + ')'; } }; S.Dot = function (x, y) { this.p = new S.Point({ x: x, y: y, z: 5, a: 1, h: 0 }); this.e = 0.07; this.s = true; this.c = new S.Color(255, 255, 255, this.p.a); this.t = this.clone(); this.q = []; }; S.Dot.prototype = { clone: function () { return new S.Point({ x: this.x, y: this.y, z: this.z, a: this.a, h: this.h }); }, _draw: function () { this.c.a = this.p.a; S.Drawing.drawCircle(this.p, this.c); }, _moveTowards: function (n) { var details = this.distanceTo(n, true), dx = details[0], dy = details[1], d = details[2], e = this.e * d; if (this.p.h === -1) { this.p.x = n.x; this.p.y = n.y; return true; } if (d > 1) { this.p.x -= ((dx / d) * e); this.p.y -= ((dy / d) * e); } else { if (this.p.h > 0) { this.p.h--; } else { return true; } } return false; }, _update: function () { if (this._moveTowards(this.t)) { var p = this.q.shift(); if (p) { this.t.x = p.x || this.p.x; this.t.y = p.y || this.p.y; this.t.z = p.z || this.p.z; this.t.a = p.a || this.p.a; this.p.h = p.h || 0; } else { if (this.s) { this.p.x -= Math.sin(Math.random() * 3.142); this.p.y -= Math.sin(Math.random() * 3.142); } else { this.move(new S.Point({ x: this.p.x + (Math.random() * 50) - 25, y: this.p.y + (Math.random() * 50) - 25 })); } } } d = this.p.a - this.t.a; this.p.a = Math.max(0.1, this.p.a - (d * 0.05)); d = this.p.z - this.t.z; this.p.z = Math.max(1, this.p.z - (d * 0.05)); }, distanceTo: function (n, details) { var dx = this.p.x - n.x, dy = this.p.y - n.y, d = Math.sqrt(dx * dx + dy * dy); return details ? [dx, dy, d] : d; }, move: function (p, avoidStatic) { if (!avoidStatic || (avoidStatic && this.distanceTo(p) > 1)) { this.q.push(p); } }, render: function () { this._update(); this._draw(); } }; S.ShapeBuilder = (function () { var gap = 13, shapeCanvas = document.createElement('canvas'), shapeContext = shapeCanvas.getContext('2d'), fontSize = 500, fontFamily = 'Avenir, Helvetica Neue, Helvetica, Arial, sans-serif'; function fit() { shapeCanvas.width = Math.floor(window.innerWidth / gap) * gap; shapeCanvas.height = Math.floor(window.innerHeight / gap) * gap; shapeContext.fillStyle = 'red'; shapeContext.textBaseline = 'middle'; shapeContext.textAlign = 'center'; } function processCanvas() { var pixels = shapeContext.getImageData(0, 0, shapeCanvas.width, shapeCanvas.height).data; dots = [], pixels, x = 0, y = 0, fx = shapeCanvas.width, fy = shapeCanvas.height, w = 0, h = 0; for (var p = 0; p < pixels.length; p += (4 * gap)) { if (pixels[p + 3] > 0) { dots.push(new S.Point({ x: x, y: y })); w = x > w ? x : w; h = y > h ? y : h; fx = x < fx ? x : fx; fy = y < fy ? y : fy; } x += gap; if (x >= shapeCanvas.width) { x = 0; y += gap; p += gap * 4 * shapeCanvas.width; } } return {dots: dots, w: w + fx, h: h + fy}; } function setFontSize(s) { shapeContext.font = 'bold ' + s + 'px ' + fontFamily; } function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); } function init() { fit(); window.addEventListener('resize', fit); } // Init init(); return { imageFile: function (url, callback) { var image = new Image(), a = S.Drawing.getArea(); image.onload = function () { shapeContext.clearRect(0, 0, shapeCanvas.width, shapeCanvas.height); shapeContext.drawImage(this, 0, 0, a.h * 0.6, a.h * 0.6); callback(processCanvas()); }; image.onerror = function () { callback(S.ShapeBuilder.letter('What?')); }; image.src = url; }, circle: function (d) { var r = Math.max(0, d) / 2; shapeContext.clearRect(0, 0, shapeCanvas.width, shapeCanvas.height); shapeContext.beginPath(); shapeContext.arc(r * gap, r * gap, r * gap, 0, 2 * Math.PI, false); shapeContext.fill(); shapeContext.closePath(); return processCanvas(); }, letter: function (l) { var s = 0; setFontSize(fontSize); s = Math.min(fontSize, (shapeCanvas.width / shapeContext.measureText(l).width) * 0.8 * fontSize, (shapeCanvas.height / fontSize) * (isNumber(l) ? 1 : 0.45) * fontSize); setFontSize(s); shapeContext.clearRect(0, 0, shapeCanvas.width, shapeCanvas.height); shapeContext.fillText(l, shapeCanvas.width / 2, shapeCanvas.height / 2); return processCanvas(); }, rectangle: function (w, h) { var dots = [], width = gap * w, height = gap * h; for (var y = 0; y < height; y += gap) { for (var x = 0; x < width; x += gap) { dots.push(new S.Point({ x: x, y: y })); } } return {dots: dots, w: width, h: height}; } }; }()); S.Shape = (function () { var dots = [], width = 0, height = 0, cx = 0, cy = 0; function compensate() { var a = S.Drawing.getArea(); cx = a.w / 2 - width / 2; cy = a.h / 2 - height / 2; } return { shuffleIdle: function () { var a = S.Drawing.getArea(); for (var d = 0; d < dots.length; d++) { if (!dots[d].s) { dots[d].move({ x: Math.random() * a.w, y: Math.random() * a.h }); } } }, switchShape: function (n, fast) { var size, a = S.Drawing.getArea(); width = n.w; height = n.h; compensate(); if (n.dots.length > dots.length) { size = n.dots.length - dots.length; for (var d = 1; d 0) { i = Math.floor(Math.random() * n.dots.length); dots[d].e = fast ? 0.25 : (dots[d].s ? 0.14 : 0.11); if (dots[d].s) { dots[d].move(new S.Point({ z: Math.random() * 20 + 10, a: Math.random(), h: 18 })); } else { dots[d].move(new S.Point({ z: Math.random() * 5 + 5, h: fast ? 18 : 30 })); } dots[d].s = true; dots[d].move(new S.Point({ x: n.dots[i].x + cx, y: n.dots[i].y + cy, a: 1, z: 5, h: 0 })); n.dots = n.dots.slice(0, i).concat(n.dots.slice(i + 1)); d++; } for (var i = d; i < dots.length; i++) { if (dots[i].s) { dots[i].move(new S.Point({ z: Math.random() * 20 + 10, a: Math.random(), h: 20 })); dots[i].s = false; dots[i].e = 0.04; dots[i].move(new S.Point({ x: Math.random() * a.w, y: Math.random() * a.h, a: 0.3, //.4 z: Math.random() * 4, h: 0 })); } } }, render: function () { for (var d = 0; d < dots.length; d++) { dots[d].render(); } } }; }()); S.init();","link":"/anniversary.html"},{"title":"","text":"🎈🎈微笑墙🎈🎈 彭小苒 唐艺昕 李一桐 gakki 图片搜集于互联网,侵权请留言,马上处理😊。","link":"/album/index.html"},{"title":"categories","text":"","link":"/categories/index.html"},{"title":"","text":"申请友链须知 原则上只和技术类博客交换,但不包括含有和色情、暴力、政治敏感的网站。 不和剽窃、侵权、无诚信的网站交换,优先和具有原创作品的网站交换。 申请请提供:站点名称、站点链接、站点描述、logo或头像(不要设置防盗链)。 排名根据博客质量以及个人喜好加权排序,更新信息后请留言告知。 会定期清理很久很久不更新的、不符合要求的友链,不再另行通知。 本站不存储友链图片,如果友链图片换了无法更新。图片裂了的会替换成默认图,需要更换的请留言告知。 申请友链前请先添加本站信息。 友链会隔一段时间统一清理,添加,申请的朋友请耐心等等,上次更新时间:2021:01:02。 本站友链信息如下: 网站图标:https://removeif.github.io/images/avatar.jpg 网站名称:辣椒の酱 网站地址:https://removeif.github.io 网站简介:后端开发,技术分享 Github地址:欢迎互相follow 加载中,稍等几秒...","link":"/friend/index.html"},{"title":"","text":"  听听音乐 音乐播放器由mePlayer提供,布局参照网友博客所作,感谢作者的辛勤付出。更多音乐分享请查看歌单。   看看视频 ->点击以下条目开始播放视频,向下滑动查看更多<-","link":"/media/index.html"},{"title":"","text":"来而不往非礼也畅所欲言,有留必应","link":"/message/index.html"},{"title":"音乐歌单","text":"温馨提示:选择喜欢的音乐双击播放,由于版权原因部分不能播放。如果喜欢歌单收藏一下,去网易云都能播放哟!","link":"/music/index.html"},{"title":"tags","text":"","link":"/tags/index.html"},{"title":"","text":"碎碎念 tips:github登录后按时间正序查看、可点赞加❤️、本插件地址..「+99次查看」 碎碎念加载中,请稍等... // 碎碎念页面才会走到下面 $.getScript(\"https://cdn.jsdelivr.net/gh/removeif/removeif.github.io@v4.1.1/js/gitalk_self.min.js\", function () { var gitalk = new Gitalk({ clientID: clientId, clientSecret: clientSecret, id: '666666', repo: 'issue_database', owner: 'removeif', admin: \"removeif\", createIssueManually: true, distractionFreeMode: false }); gitalk.render('comment-container1'); });","link":"/self-talking/index.html"}]} \ No newline at end of file diff --git a/css/DPlayer.min.css b/css/DPlayer.min.css new file mode 100644 index 0000000000..878ba622f5 --- /dev/null +++ b/css/DPlayer.min.css @@ -0,0 +1,4 @@ +button[data-balloon]{overflow:visible}[data-balloon]{position:relative;cursor:pointer}[data-balloon]:after{font-family:sans-serif!important;font-weight:400!important;font-style:normal!important;text-shadow:none!important;font-size:12px!important;background:hsla(0,0%,7%,.9);border-radius:4px;color:#fff;content:attr(data-balloon);padding:.5em 1em;white-space:nowrap}[data-balloon]:after,[data-balloon]:before{filter:alpha(opactiy=0);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";-moz-opacity:0;-khtml-opacity:0;opacity:0;pointer-events:none;transition:all .18s ease-out .18s;position:absolute;z-index:10}[data-balloon]:before{background:no-repeat url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M2.658 0h32.004c-6 0-11.627 12.002-16.002 12.002C14.285 12.002 8.594 0 2.658 0z'/%3E%3C/svg%3E");background-size:100% auto;width:18px;height:6px;content:""}[data-balloon]:hover:after,[data-balloon]:hover:before,[data-balloon][data-balloon-visible]:after,[data-balloon][data-balloon-visible]:before{filter:alpha(opactiy=100);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";-moz-opacity:1;-khtml-opacity:1;opacity:1;pointer-events:auto}[data-balloon].font-awesome:after{font-family:FontAwesome}[data-balloon][data-balloon-break]:after{white-space:pre}[data-balloon][data-balloon-blunt]:after,[data-balloon][data-balloon-blunt]:before{transition:none}[data-balloon][data-balloon-pos=up]:after{margin-bottom:11px}[data-balloon][data-balloon-pos=up]:after,[data-balloon][data-balloon-pos=up]:before{bottom:100%;left:50%;-webkit-transform:translate(-50%,10px);transform:translate(-50%,10px);-webkit-transform-origin:top;transform-origin:top}[data-balloon][data-balloon-pos=up]:before{margin-bottom:5px}[data-balloon][data-balloon-pos=up]:hover:after,[data-balloon][data-balloon-pos=up]:hover:before,[data-balloon][data-balloon-pos=up][data-balloon-visible]:after,[data-balloon][data-balloon-pos=up][data-balloon-visible]:before{-webkit-transform:translate(-50%);transform:translate(-50%)}[data-balloon][data-balloon-pos=up-left]:after{left:0;margin-bottom:11px}[data-balloon][data-balloon-pos=up-left]:after,[data-balloon][data-balloon-pos=up-left]:before{bottom:100%;-webkit-transform:translateY(10px);transform:translateY(10px);-webkit-transform-origin:top;transform-origin:top}[data-balloon][data-balloon-pos=up-left]:before{left:5px;margin-bottom:5px}[data-balloon][data-balloon-pos=up-left]:hover:after,[data-balloon][data-balloon-pos=up-left]:hover:before,[data-balloon][data-balloon-pos=up-left][data-balloon-visible]:after,[data-balloon][data-balloon-pos=up-left][data-balloon-visible]:before{-webkit-transform:translate(0);transform:translate(0)}[data-balloon][data-balloon-pos=up-right]:after{right:0;margin-bottom:11px}[data-balloon][data-balloon-pos=up-right]:after,[data-balloon][data-balloon-pos=up-right]:before{bottom:100%;-webkit-transform:translateY(10px);transform:translateY(10px);-webkit-transform-origin:top;transform-origin:top}[data-balloon][data-balloon-pos=up-right]:before{right:5px;margin-bottom:5px}[data-balloon][data-balloon-pos=up-right]:hover:after,[data-balloon][data-balloon-pos=up-right]:hover:before,[data-balloon][data-balloon-pos=up-right][data-balloon-visible]:after,[data-balloon][data-balloon-pos=up-right][data-balloon-visible]:before{-webkit-transform:translate(0);transform:translate(0)}[data-balloon][data-balloon-pos=down]:after{margin-top:11px}[data-balloon][data-balloon-pos=down]:after,[data-balloon][data-balloon-pos=down]:before{left:50%;top:100%;-webkit-transform:translate(-50%,-10px);transform:translate(-50%,-10px)}[data-balloon][data-balloon-pos=down]:before{background:no-repeat url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M33.342 12H1.338c6 0 11.627-12.002 16.002-12.002C21.715-.002 27.406 12 33.342 12z'/%3E%3C/svg%3E");background-size:100% auto;width:18px;height:6px;margin-top:5px}[data-balloon][data-balloon-pos=down]:hover:after,[data-balloon][data-balloon-pos=down]:hover:before,[data-balloon][data-balloon-pos=down][data-balloon-visible]:after,[data-balloon][data-balloon-pos=down][data-balloon-visible]:before{-webkit-transform:translate(-50%);transform:translate(-50%)}[data-balloon][data-balloon-pos=down-left]:after{left:0;margin-top:11px;top:100%;-webkit-transform:translateY(-10px);transform:translateY(-10px)}[data-balloon][data-balloon-pos=down-left]:before{background:no-repeat url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M33.342 12H1.338c6 0 11.627-12.002 16.002-12.002C21.715-.002 27.406 12 33.342 12z'/%3E%3C/svg%3E");background-size:100% auto;width:18px;height:6px;left:5px;margin-top:5px;top:100%;-webkit-transform:translateY(-10px);transform:translateY(-10px)}[data-balloon][data-balloon-pos=down-left]:hover:after,[data-balloon][data-balloon-pos=down-left]:hover:before,[data-balloon][data-balloon-pos=down-left][data-balloon-visible]:after,[data-balloon][data-balloon-pos=down-left][data-balloon-visible]:before{-webkit-transform:translate(0);transform:translate(0)}[data-balloon][data-balloon-pos=down-right]:after{right:0;margin-top:11px;top:100%;-webkit-transform:translateY(-10px);transform:translateY(-10px)}[data-balloon][data-balloon-pos=down-right]:before{background:no-repeat url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M33.342 12H1.338c6 0 11.627-12.002 16.002-12.002C21.715-.002 27.406 12 33.342 12z'/%3E%3C/svg%3E");background-size:100% auto;width:18px;height:6px;right:5px;margin-top:5px;top:100%;-webkit-transform:translateY(-10px);transform:translateY(-10px)}[data-balloon][data-balloon-pos=down-right]:hover:after,[data-balloon][data-balloon-pos=down-right]:hover:before,[data-balloon][data-balloon-pos=down-right][data-balloon-visible]:after,[data-balloon][data-balloon-pos=down-right][data-balloon-visible]:before{-webkit-transform:translate(0);transform:translate(0)}[data-balloon][data-balloon-pos=left]:after{margin-right:11px;right:100%;top:50%;-webkit-transform:translate(10px,-50%);transform:translate(10px,-50%)}[data-balloon][data-balloon-pos=left]:before{background:no-repeat url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='36'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M0 33.342V1.338c0 6 12.002 11.627 12.002 16.002C12.002 21.715 0 27.406 0 33.342z'/%3E%3C/svg%3E");background-size:100% auto;width:6px;height:18px;margin-right:5px;right:100%;top:50%;-webkit-transform:translate(10px,-50%);transform:translate(10px,-50%)}[data-balloon][data-balloon-pos=left]:hover:after,[data-balloon][data-balloon-pos=left]:hover:before,[data-balloon][data-balloon-pos=left][data-balloon-visible]:after,[data-balloon][data-balloon-pos=left][data-balloon-visible]:before{-webkit-transform:translateY(-50%);transform:translateY(-50%)}[data-balloon][data-balloon-pos=right]:after{left:100%;margin-left:11px;top:50%;-webkit-transform:translate(-10px,-50%);transform:translate(-10px,-50%)}[data-balloon][data-balloon-pos=right]:before{background:no-repeat url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='36'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M12 2.658v32.004c0-6-12.002-11.627-12.002-16.002C-.002 14.285 12 8.594 12 2.658z'/%3E%3C/svg%3E");background-size:100% auto;width:6px;height:18px;left:100%;margin-left:5px;top:50%;-webkit-transform:translate(-10px,-50%);transform:translate(-10px,-50%)}[data-balloon][data-balloon-pos=right]:hover:after,[data-balloon][data-balloon-pos=right]:hover:before,[data-balloon][data-balloon-pos=right][data-balloon-visible]:after,[data-balloon][data-balloon-pos=right][data-balloon-visible]:before{-webkit-transform:translateY(-50%);transform:translateY(-50%)}[data-balloon][data-balloon-length=small]:after{white-space:normal;width:80px}[data-balloon][data-balloon-length=medium]:after{white-space:normal;width:150px}[data-balloon][data-balloon-length=large]:after{white-space:normal;width:260px}[data-balloon][data-balloon-length=xlarge]:after{white-space:normal;width:380px}@media screen and (max-width:768px){[data-balloon][data-balloon-length=xlarge]:after{white-space:normal;width:90vw}}[data-balloon][data-balloon-length=fit]:after{white-space:normal;width:100%} +@-webkit-keyframes my-face{2%{-webkit-transform:translateY(1.5px) rotate(1.5deg);transform:translateY(1.5px) rotate(1.5deg)}4%{-webkit-transform:translateY(-1.5px) rotate(-.5deg);transform:translateY(-1.5px) rotate(-.5deg)}6%{-webkit-transform:translateY(1.5px) rotate(-1.5deg);transform:translateY(1.5px) rotate(-1.5deg)}8%{-webkit-transform:translateY(-1.5px) rotate(-1.5deg);transform:translateY(-1.5px) rotate(-1.5deg)}10%{-webkit-transform:translateY(2.5px) rotate(1.5deg);transform:translateY(2.5px) rotate(1.5deg)}12%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}14%{-webkit-transform:translateY(-1.5px) rotate(1.5deg);transform:translateY(-1.5px) rotate(1.5deg)}16%{-webkit-transform:translateY(-.5px) rotate(-1.5deg);transform:translateY(-.5px) rotate(-1.5deg)}18%{-webkit-transform:translateY(.5px) rotate(-1.5deg);transform:translateY(.5px) rotate(-1.5deg)}20%{-webkit-transform:translateY(-1.5px) rotate(2.5deg);transform:translateY(-1.5px) rotate(2.5deg)}22%{-webkit-transform:translateY(.5px) rotate(-1.5deg);transform:translateY(.5px) rotate(-1.5deg)}24%{-webkit-transform:translateY(1.5px) rotate(1.5deg);transform:translateY(1.5px) rotate(1.5deg)}26%{-webkit-transform:translateY(.5px) rotate(.5deg);transform:translateY(.5px) rotate(.5deg)}28%{-webkit-transform:translateY(.5px) rotate(1.5deg);transform:translateY(.5px) rotate(1.5deg)}30%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}32%{-webkit-transform:translateY(1.5px) rotate(-.5deg);transform:translateY(1.5px) rotate(-.5deg)}34%{-webkit-transform:translateY(1.5px) rotate(-.5deg);transform:translateY(1.5px) rotate(-.5deg)}36%{-webkit-transform:translateY(-1.5px) rotate(2.5deg);transform:translateY(-1.5px) rotate(2.5deg)}38%{-webkit-transform:translateY(1.5px) rotate(-1.5deg);transform:translateY(1.5px) rotate(-1.5deg)}40%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}42%{-webkit-transform:translateY(2.5px) rotate(-1.5deg);transform:translateY(2.5px) rotate(-1.5deg)}44%{-webkit-transform:translateY(1.5px) rotate(.5deg);transform:translateY(1.5px) rotate(.5deg)}46%{-webkit-transform:translateY(-1.5px) rotate(2.5deg);transform:translateY(-1.5px) rotate(2.5deg)}48%{-webkit-transform:translateY(-.5px) rotate(.5deg);transform:translateY(-.5px) rotate(.5deg)}50%{-webkit-transform:translateY(.5px) rotate(.5deg);transform:translateY(.5px) rotate(.5deg)}52%{-webkit-transform:translateY(2.5px) rotate(2.5deg);transform:translateY(2.5px) rotate(2.5deg)}54%{-webkit-transform:translateY(-1.5px) rotate(1.5deg);transform:translateY(-1.5px) rotate(1.5deg)}56%{-webkit-transform:translateY(2.5px) rotate(2.5deg);transform:translateY(2.5px) rotate(2.5deg)}58%{-webkit-transform:translateY(.5px) rotate(2.5deg);transform:translateY(.5px) rotate(2.5deg)}60%{-webkit-transform:translateY(2.5px) rotate(2.5deg);transform:translateY(2.5px) rotate(2.5deg)}62%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}64%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}66%{-webkit-transform:translateY(1.5px) rotate(-.5deg);transform:translateY(1.5px) rotate(-.5deg)}68%{-webkit-transform:translateY(-1.5px) rotate(-.5deg);transform:translateY(-1.5px) rotate(-.5deg)}70%{-webkit-transform:translateY(1.5px) rotate(.5deg);transform:translateY(1.5px) rotate(.5deg)}72%{-webkit-transform:translateY(2.5px) rotate(1.5deg);transform:translateY(2.5px) rotate(1.5deg)}74%{-webkit-transform:translateY(-.5px) rotate(.5deg);transform:translateY(-.5px) rotate(.5deg)}76%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}78%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}80%{-webkit-transform:translateY(1.5px) rotate(1.5deg);transform:translateY(1.5px) rotate(1.5deg)}82%{-webkit-transform:translateY(-.5px) rotate(.5deg);transform:translateY(-.5px) rotate(.5deg)}84%{-webkit-transform:translateY(1.5px) rotate(2.5deg);transform:translateY(1.5px) rotate(2.5deg)}86%{-webkit-transform:translateY(-1.5px) rotate(-1.5deg);transform:translateY(-1.5px) rotate(-1.5deg)}88%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}90%{-webkit-transform:translateY(2.5px) rotate(-.5deg);transform:translateY(2.5px) rotate(-.5deg)}92%{-webkit-transform:translateY(.5px) rotate(-.5deg);transform:translateY(.5px) rotate(-.5deg)}94%{-webkit-transform:translateY(2.5px) rotate(.5deg);transform:translateY(2.5px) rotate(.5deg)}96%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}98%{-webkit-transform:translateY(-1.5px) rotate(-.5deg);transform:translateY(-1.5px) rotate(-.5deg)}0%,to{-webkit-transform:translate(0) rotate(0deg);transform:translate(0) rotate(0deg)}}@keyframes my-face{2%{-webkit-transform:translateY(1.5px) rotate(1.5deg);transform:translateY(1.5px) rotate(1.5deg)}4%{-webkit-transform:translateY(-1.5px) rotate(-.5deg);transform:translateY(-1.5px) rotate(-.5deg)}6%{-webkit-transform:translateY(1.5px) rotate(-1.5deg);transform:translateY(1.5px) rotate(-1.5deg)}8%{-webkit-transform:translateY(-1.5px) rotate(-1.5deg);transform:translateY(-1.5px) rotate(-1.5deg)}10%{-webkit-transform:translateY(2.5px) rotate(1.5deg);transform:translateY(2.5px) rotate(1.5deg)}12%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}14%{-webkit-transform:translateY(-1.5px) rotate(1.5deg);transform:translateY(-1.5px) rotate(1.5deg)}16%{-webkit-transform:translateY(-.5px) rotate(-1.5deg);transform:translateY(-.5px) rotate(-1.5deg)}18%{-webkit-transform:translateY(.5px) rotate(-1.5deg);transform:translateY(.5px) rotate(-1.5deg)}20%{-webkit-transform:translateY(-1.5px) rotate(2.5deg);transform:translateY(-1.5px) rotate(2.5deg)}22%{-webkit-transform:translateY(.5px) rotate(-1.5deg);transform:translateY(.5px) rotate(-1.5deg)}24%{-webkit-transform:translateY(1.5px) rotate(1.5deg);transform:translateY(1.5px) rotate(1.5deg)}26%{-webkit-transform:translateY(.5px) rotate(.5deg);transform:translateY(.5px) rotate(.5deg)}28%{-webkit-transform:translateY(.5px) rotate(1.5deg);transform:translateY(.5px) rotate(1.5deg)}30%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}32%{-webkit-transform:translateY(1.5px) rotate(-.5deg);transform:translateY(1.5px) rotate(-.5deg)}34%{-webkit-transform:translateY(1.5px) rotate(-.5deg);transform:translateY(1.5px) rotate(-.5deg)}36%{-webkit-transform:translateY(-1.5px) rotate(2.5deg);transform:translateY(-1.5px) rotate(2.5deg)}38%{-webkit-transform:translateY(1.5px) rotate(-1.5deg);transform:translateY(1.5px) rotate(-1.5deg)}40%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}42%{-webkit-transform:translateY(2.5px) rotate(-1.5deg);transform:translateY(2.5px) rotate(-1.5deg)}44%{-webkit-transform:translateY(1.5px) rotate(.5deg);transform:translateY(1.5px) rotate(.5deg)}46%{-webkit-transform:translateY(-1.5px) rotate(2.5deg);transform:translateY(-1.5px) rotate(2.5deg)}48%{-webkit-transform:translateY(-.5px) rotate(.5deg);transform:translateY(-.5px) rotate(.5deg)}50%{-webkit-transform:translateY(.5px) rotate(.5deg);transform:translateY(.5px) rotate(.5deg)}52%{-webkit-transform:translateY(2.5px) rotate(2.5deg);transform:translateY(2.5px) rotate(2.5deg)}54%{-webkit-transform:translateY(-1.5px) rotate(1.5deg);transform:translateY(-1.5px) rotate(1.5deg)}56%{-webkit-transform:translateY(2.5px) rotate(2.5deg);transform:translateY(2.5px) rotate(2.5deg)}58%{-webkit-transform:translateY(.5px) rotate(2.5deg);transform:translateY(.5px) rotate(2.5deg)}60%{-webkit-transform:translateY(2.5px) rotate(2.5deg);transform:translateY(2.5px) rotate(2.5deg)}62%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}64%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}66%{-webkit-transform:translateY(1.5px) rotate(-.5deg);transform:translateY(1.5px) rotate(-.5deg)}68%{-webkit-transform:translateY(-1.5px) rotate(-.5deg);transform:translateY(-1.5px) rotate(-.5deg)}70%{-webkit-transform:translateY(1.5px) rotate(.5deg);transform:translateY(1.5px) rotate(.5deg)}72%{-webkit-transform:translateY(2.5px) rotate(1.5deg);transform:translateY(2.5px) rotate(1.5deg)}74%{-webkit-transform:translateY(-.5px) rotate(.5deg);transform:translateY(-.5px) rotate(.5deg)}76%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}78%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}80%{-webkit-transform:translateY(1.5px) rotate(1.5deg);transform:translateY(1.5px) rotate(1.5deg)}82%{-webkit-transform:translateY(-.5px) rotate(.5deg);transform:translateY(-.5px) rotate(.5deg)}84%{-webkit-transform:translateY(1.5px) rotate(2.5deg);transform:translateY(1.5px) rotate(2.5deg)}86%{-webkit-transform:translateY(-1.5px) rotate(-1.5deg);transform:translateY(-1.5px) rotate(-1.5deg)}88%{-webkit-transform:translateY(-.5px) rotate(2.5deg);transform:translateY(-.5px) rotate(2.5deg)}90%{-webkit-transform:translateY(2.5px) rotate(-.5deg);transform:translateY(2.5px) rotate(-.5deg)}92%{-webkit-transform:translateY(.5px) rotate(-.5deg);transform:translateY(.5px) rotate(-.5deg)}94%{-webkit-transform:translateY(2.5px) rotate(.5deg);transform:translateY(2.5px) rotate(.5deg)}96%{-webkit-transform:translateY(-.5px) rotate(1.5deg);transform:translateY(-.5px) rotate(1.5deg)}98%{-webkit-transform:translateY(-1.5px) rotate(-.5deg);transform:translateY(-1.5px) rotate(-.5deg)}0%,to{-webkit-transform:translate(0) rotate(0deg);transform:translate(0) rotate(0deg)}}.dplayer{position:relative;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:1}.dplayer *{box-sizing:content-box}.dplayer svg{width:100%;height:100%}.dplayer svg circle,.dplayer svg path{fill:#fff}.dplayer:-webkit-full-screen{width:100%;height:100%;background:#000;position:fixed;z-index:100000;left:0;top:0;margin:0;padding:0;-webkit-transform:translate(0);transform:translate(0)}.dplayer:-webkit-full-screen .dplayer-danmaku .dplayer-danmaku-bottom.dplayer-danmaku-move,.dplayer:-webkit-full-screen .dplayer-danmaku .dplayer-danmaku-top.dplayer-danmaku-move{-webkit-animation:danmaku-center 6s linear;animation:danmaku-center 6s linear;-webkit-animation-play-state:inherit;animation-play-state:inherit}.dplayer:-webkit-full-screen .dplayer-danmaku .dplayer-danmaku-right.dplayer-danmaku-move{-webkit-animation:danmaku 8s linear;animation:danmaku 8s linear;-webkit-animation-play-state:inherit;animation-play-state:inherit}.dplayer.dplayer-live .dplayer-bar-wrap,.dplayer.dplayer-live.dplayer-no-danmaku .dplayer-setting,.dplayer.dplayer-live .dplayer-setting-loop,.dplayer.dplayer-live .dplayer-setting-speed,.dplayer.dplayer-live .dplayer-time,.dplayer.dplayer-no-danmaku .dplayer-controller .dplayer-icons .dplayer-comment,.dplayer.dplayer-no-danmaku .dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box .dplayer-setting-danmaku,.dplayer.dplayer-no-danmaku .dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box .dplayer-setting-danunlimit,.dplayer.dplayer-no-danmaku .dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box .dplayer-setting-showdan,.dplayer.dplayer-no-danmaku .dplayer-danmaku{display:none}.dplayer.dplayer-arrow .dplayer-danmaku{font-size:18px}.dplayer.dplayer-arrow .dplayer-icon{margin:0 -3px}.dplayer.dplayer-playing .dplayer-danmaku .dplayer-danmaku-move{-webkit-animation-play-state:running;animation-play-state:running}@media (min-width:900px){.dplayer.dplayer-playing .dplayer-controller,.dplayer.dplayer-playing .dplayer-controller-mask{opacity:0}.dplayer.dplayer-playing:hover .dplayer-controller,.dplayer.dplayer-playing:hover .dplayer-controller-mask{opacity:1}}.dplayer.dplayer-loading .dplayer-bezel .diplayer-loading-icon{display:block}.dplayer.dplayer-loading .dplayer-danmaku,.dplayer.dplayer-loading .dplayer-danmaku-move,.dplayer.dplayer-paused .dplayer-danmaku,.dplayer.dplayer-paused .dplayer-danmaku-move{-webkit-animation-play-state:paused;animation-play-state:paused}.dplayer.dplayer-hide-controller{cursor:none}.dplayer.dplayer-hide-controller .dplayer-controller,.dplayer.dplayer-hide-controller .dplayer-controller-mask{opacity:0;-webkit-transform:translateY(100%);transform:translateY(100%)}.dplayer.dplayer-show-controller .dplayer-controller,.dplayer.dplayer-show-controller .dplayer-controller-mask{opacity:1}.dplayer.dplayer-fulled{position:fixed;z-index:100000;left:0;top:0;width:100%;height:100%}.dplayer.dplayer-mobile .dplayer-controller .dplayer-icons .dplayer-camera-icon,.dplayer.dplayer-mobile .dplayer-controller .dplayer-icons .dplayer-volume{display:none}.dplayer.dplayer-mobile .dplayer-controller .dplayer-icons .dplayer-full .dplayer-full-in-icon{position:static;display:inline-block}.dplayer.dplayer-mobile .dplayer-bar-time{display:none}.dplayer-web-fullscreen-fix{position:fixed;top:0;left:0;margin:0;padding:0}[data-balloon]:before{display:none}[data-balloon]:after{padding:.3em .7em;background:hsla(0,0%,7%,.7)}[data-balloon][data-balloon-pos=up]:after{margin-bottom:0}.dplayer-bezel{position:absolute;left:0;right:0;top:0;bottom:0;font-size:22px;color:#fff;pointer-events:none}.dplayer-bezel .dplayer-bezel-icon{position:absolute;top:50%;left:50%;margin:-26px 0 0 -26px;height:52px;width:52px;padding:12px;box-sizing:border-box;background:rgba(0,0,0,.5);border-radius:50%;opacity:0;pointer-events:none}.dplayer-bezel .dplayer-bezel-icon.dplayer-bezel-transition{-webkit-animation:bezel-hide .5s linear;animation:bezel-hide .5s linear}@-webkit-keyframes bezel-hide{0%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}to{opacity:0;-webkit-transform:scale(2);transform:scale(2)}}@keyframes bezel-hide{0%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}to{opacity:0;-webkit-transform:scale(2);transform:scale(2)}}.dplayer-bezel .dplayer-danloading{position:absolute;top:50%;margin-top:-7px;width:100%;text-align:center;font-size:14px;line-height:14px;-webkit-animation:my-face 5s infinite ease-in-out;animation:my-face 5s infinite ease-in-out}.dplayer-bezel .diplayer-loading-icon{display:none;position:absolute;top:50%;left:50%;margin:-18px 0 0 -18px;height:36px;width:36px;pointer-events:none}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-hide{display:none}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot{-webkit-animation:diplayer-loading-dot-fade .8s ease infinite;animation:diplayer-loading-dot-fade .8s ease infinite;opacity:0;-webkit-transform-origin:4px 4px;transform-origin:4px 4px}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot.diplayer-loading-dot-7{-webkit-animation-delay:.7s;animation-delay:.7s}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot.diplayer-loading-dot-6{-webkit-animation-delay:.6s;animation-delay:.6s}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot.diplayer-loading-dot-5{-webkit-animation-delay:.5s;animation-delay:.5s}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot.diplayer-loading-dot-4{-webkit-animation-delay:.4s;animation-delay:.4s}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot.diplayer-loading-dot-3{-webkit-animation-delay:.3s;animation-delay:.3s}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot.diplayer-loading-dot-2{-webkit-animation-delay:.2s;animation-delay:.2s}.dplayer-bezel .diplayer-loading-icon .diplayer-loading-dot.diplayer-loading-dot-1{-webkit-animation-delay:.1s;animation-delay:.1s}@-webkit-keyframes diplayer-loading-dot-fade{0%{opacity:.7;-webkit-transform:scale(1.2);transform:scale(1.2)}50%{opacity:.25;-webkit-transform:scale(.9);transform:scale(.9)}to{opacity:.25;-webkit-transform:scale(.85);transform:scale(.85)}}@keyframes diplayer-loading-dot-fade{0%{opacity:.7;-webkit-transform:scale(1.2);transform:scale(1.2)}50%{opacity:.25;-webkit-transform:scale(.9);transform:scale(.9)}to{opacity:.25;-webkit-transform:scale(.85);transform:scale(.85)}}.dplayer-controller-mask{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==) repeat-x bottom;height:98px;width:100%}.dplayer-controller,.dplayer-controller-mask{position:absolute;bottom:0;transition:all .3s ease}.dplayer-controller{left:0;right:0;height:41px;padding:0 20px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.dplayer-controller.dplayer-controller-comment .dplayer-icons{display:none}.dplayer-controller.dplayer-controller-comment .dplayer-icons.dplayer-comment-box{display:block}.dplayer-controller .dplayer-bar-wrap{padding:5px 0;cursor:pointer;position:absolute;bottom:33px;width:calc(100% - 40px);height:3px}.dplayer-controller .dplayer-bar-wrap:hover .dplayer-bar .dplayer-played .dplayer-thumb{-webkit-transform:scale(1);transform:scale(1)}.dplayer-controller .dplayer-bar-wrap:hover .dplayer-highlight{display:block;width:8px;-webkit-transform:translateX(-4px);transform:translateX(-4px);top:4px;height:40%}.dplayer-controller .dplayer-bar-wrap .dplayer-highlight{z-index:12;position:absolute;top:5px;width:6px;height:20%;border-radius:6px;background-color:#fff;text-align:center;-webkit-transform:translateX(-3px);transform:translateX(-3px);transition:all .2s ease-in-out}.dplayer-controller .dplayer-bar-wrap .dplayer-highlight:hover .dplayer-highlight-text{display:block}.dplayer-controller .dplayer-bar-wrap .dplayer-highlight:hover~.dplayer-bar-preview,.dplayer-controller .dplayer-bar-wrap .dplayer-highlight:hover~.dplayer-bar-time{opacity:0}.dplayer-controller .dplayer-bar-wrap .dplayer-highlight .dplayer-highlight-text{display:none;position:absolute;left:50%;top:-24px;padding:5px 8px;background-color:rgba(0,0,0,.62);color:#fff;border-radius:4px;font-size:12px;white-space:nowrap;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.dplayer-controller .dplayer-bar-wrap .dplayer-bar-preview{position:absolute;background:#fff;pointer-events:none;display:none;background-size:16000px 100%}.dplayer-controller .dplayer-bar-wrap .dplayer-bar-preview-canvas{position:absolute;width:100%;height:100%;z-index:1;pointer-events:none}.dplayer-controller .dplayer-bar-wrap .dplayer-bar-time{position:absolute;left:0;top:-20px;border-radius:4px;padding:5px 7px;background-color:rgba(0,0,0,.62);color:#fff;font-size:12px;text-align:center;opacity:1;transition:opacity .1s ease-in-out;word-wrap:normal;word-break:normal;z-index:2;pointer-events:none}.dplayer-controller .dplayer-bar-wrap .dplayer-bar-time.hidden{opacity:0}.dplayer-controller .dplayer-bar-wrap .dplayer-bar{position:relative;height:3px;width:100%;background:hsla(0,0%,100%,.2);cursor:pointer}.dplayer-controller .dplayer-bar-wrap .dplayer-bar .dplayer-loaded{background:hsla(0,0%,100%,.4);transition:all .5s ease}.dplayer-controller .dplayer-bar-wrap .dplayer-bar .dplayer-loaded,.dplayer-controller .dplayer-bar-wrap .dplayer-bar .dplayer-played{position:absolute;left:0;top:0;bottom:0;height:3px;will-change:width}.dplayer-controller .dplayer-bar-wrap .dplayer-bar .dplayer-played .dplayer-thumb{position:absolute;top:0;right:5px;margin-top:-4px;margin-right:-10px;height:11px;width:11px;border-radius:50%;cursor:pointer;transition:all .3s ease-in-out;-webkit-transform:scale(0);transform:scale(0)}.dplayer-controller .dplayer-icons{height:38px;position:absolute;bottom:0}.dplayer-controller .dplayer-icons.dplayer-comment-box{display:none;position:absolute;transition:all .3s ease-in-out;z-index:2;height:38px;bottom:0;left:20px;right:20px;color:#fff}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-icon{padding:7px}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-icon{position:absolute;left:0;top:0}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-send-icon{position:absolute;right:0;top:0}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box{position:absolute;background:rgba(28,28,28,.9);bottom:41px;left:0;box-shadow:0 0 25px rgba(0,0,0,.3);border-radius:4px;padding:10px 10px 16px;font-size:14px;width:204px;transition:all .3s ease-in-out;-webkit-transform:scale(0);transform:scale(0)}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box.dplayer-comment-setting-open{-webkit-transform:scale(1);transform:scale(1)}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box input[type=radio]{display:none}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box label{cursor:pointer}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-title{font-size:13px;color:#fff;line-height:30px}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-type{font-size:0}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-type .dplayer-comment-setting-title{margin-bottom:6px}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-type label:nth-child(2) span{border-radius:4px 0 0 4px}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-type label:nth-child(4) span{border-radius:0 4px 4px 0}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-type span{width:33%;padding:4px 6px;line-height:16px;display:inline-block;font-size:12px;color:#fff;border:1px solid #fff;margin-right:-1px;box-sizing:border-box;text-align:center;cursor:pointer}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-type input:checked+span{background:#e4e4e6;color:#1c1c1c}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-color{font-size:0}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-color label{font-size:0;padding:6px;display:inline-block}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-color span{width:22px;height:22px;display:inline-block;border-radius:50%;box-sizing:border-box;cursor:pointer}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-setting-box .dplayer-comment-setting-color span:hover{-webkit-animation:my-face 5s infinite ease-in-out;animation:my-face 5s infinite ease-in-out}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-input{outline:none;border:none;padding:8px 31px;font-size:14px;line-height:18px;text-align:center;border-radius:4px;background:none;margin:0;height:100%;box-sizing:border-box;width:100%;color:#fff}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-input::-webkit-input-placeholder{color:#fff;opacity:.8}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-input:-ms-input-placeholder,.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-input::-ms-input-placeholder{color:#fff;opacity:.8}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-input::placeholder{color:#fff;opacity:.8}.dplayer-controller .dplayer-icons.dplayer-comment-box .dplayer-comment-input::-ms-clear{display:none}.dplayer-controller .dplayer-icons.dplayer-icons-left .dplayer-icon{padding:7px}.dplayer-controller .dplayer-icons.dplayer-icons-right{right:20px}.dplayer-controller .dplayer-icons.dplayer-icons-right .dplayer-icon{padding:8px}.dplayer-controller .dplayer-icons .dplayer-live-badge,.dplayer-controller .dplayer-icons .dplayer-time{line-height:38px;color:#eee;text-shadow:0 0 2px rgba(0,0,0,.5);vertical-align:middle;font-size:13px;cursor:default}.dplayer-controller .dplayer-icons .dplayer-live-dot{display:inline-block;width:6px;height:6px;vertical-align:4%;margin-right:5px;content:"";border-radius:6px}.dplayer-controller .dplayer-icons .dplayer-icon{width:40px;height:100%;border:none;background-color:transparent;outline:none;cursor:pointer;vertical-align:middle;box-sizing:border-box;display:inline-block}.dplayer-controller .dplayer-icons .dplayer-icon .dplayer-icon-content{transition:all .2s ease-in-out;opacity:.8}.dplayer-controller .dplayer-icons .dplayer-icon:hover .dplayer-icon-content{opacity:1}.dplayer-controller .dplayer-icons .dplayer-icon.dplayer-quality-icon{color:#fff;width:auto;line-height:22px;font-size:14px}.dplayer-controller .dplayer-icons .dplayer-icon.dplayer-comment-icon{padding:10px 9px 9px}.dplayer-controller .dplayer-icons .dplayer-icon.dplayer-setting-icon{padding-top:8.5px}.dplayer-controller .dplayer-icons .dplayer-icon.dplayer-volume-icon{width:43px}.dplayer-controller .dplayer-icons .dplayer-volume{position:relative;display:inline-block;cursor:pointer;height:100%}.dplayer-controller .dplayer-icons .dplayer-volume:hover .dplayer-volume-bar-wrap .dplayer-volume-bar{width:45px}.dplayer-controller .dplayer-icons .dplayer-volume:hover .dplayer-volume-bar-wrap .dplayer-volume-bar .dplayer-volume-bar-inner .dplayer-thumb{-webkit-transform:scale(1);transform:scale(1)}.dplayer-controller .dplayer-icons .dplayer-volume.dplayer-volume-active .dplayer-volume-bar-wrap .dplayer-volume-bar{width:45px}.dplayer-controller .dplayer-icons .dplayer-volume.dplayer-volume-active .dplayer-volume-bar-wrap .dplayer-volume-bar .dplayer-volume-bar-inner .dplayer-thumb{-webkit-transform:scale(1);transform:scale(1)}.dplayer-controller .dplayer-icons .dplayer-volume .dplayer-volume-bar-wrap{display:inline-block;margin:0 10px 0 -5px;vertical-align:middle;height:100%}.dplayer-controller .dplayer-icons .dplayer-volume .dplayer-volume-bar-wrap .dplayer-volume-bar{position:relative;top:17px;width:0;height:3px;background:#aaa;transition:all .3s ease-in-out}.dplayer-controller .dplayer-icons .dplayer-volume .dplayer-volume-bar-wrap .dplayer-volume-bar .dplayer-volume-bar-inner{position:absolute;bottom:0;left:0;height:100%;transition:all .1s ease;will-change:width}.dplayer-controller .dplayer-icons .dplayer-volume .dplayer-volume-bar-wrap .dplayer-volume-bar .dplayer-volume-bar-inner .dplayer-thumb{position:absolute;top:0;right:5px;margin-top:-4px;margin-right:-10px;height:11px;width:11px;border-radius:50%;cursor:pointer;transition:all .3s ease-in-out;-webkit-transform:scale(0);transform:scale(0)}.dplayer-controller .dplayer-icons .dplayer-setting,.dplayer-controller .dplayer-icons .dplayer-subtitle-btn{display:inline-block;height:100%}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box{position:absolute;right:0;bottom:50px;-webkit-transform:scale(0);transform:scale(0);width:150px;border-radius:2px;background:rgba(28,28,28,.9);padding:7px 0;transition:all .3s ease-in-out;overflow:hidden;z-index:2}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box>div{display:none}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box>div.dplayer-setting-origin-panel{display:block}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box.dplayer-setting-box-open{-webkit-transform:scale(1);transform:scale(1)}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box.dplayer-setting-box-narrow{width:70px;height:180px;text-align:center}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box.dplayer-setting-box-speed .dplayer-setting-origin-panel{display:none}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-box.dplayer-setting-box-speed .dplayer-setting-speed-panel{display:block}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-item,.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-speed-item{height:30px;padding:5px 10px;box-sizing:border-box;cursor:pointer;position:relative}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-item:hover,.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-speed-item:hover{background-color:hsla(0,0%,100%,.1)}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku{padding:5px 0}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku .dplayer-label{padding:0 10px;display:inline}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku:hover .dplayer-label{display:none}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku:hover .dplayer-danmaku-bar-wrap{display:inline-block}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku.dplayer-setting-danmaku-active .dplayer-label{display:none}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku.dplayer-setting-danmaku-active .dplayer-danmaku-bar-wrap{display:inline-block}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku .dplayer-danmaku-bar-wrap{padding:0 10px;box-sizing:border-box;display:none;vertical-align:middle;height:100%;width:100%}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku .dplayer-danmaku-bar-wrap .dplayer-danmaku-bar{position:relative;top:8.5px;width:100%;height:3px;background:#fff;transition:all .3s ease-in-out}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku .dplayer-danmaku-bar-wrap .dplayer-danmaku-bar .dplayer-danmaku-bar-inner{position:absolute;bottom:0;left:0;height:100%;transition:all .1s ease;background:#aaa;will-change:width}.dplayer-controller .dplayer-icons .dplayer-setting .dplayer-setting-danmaku .dplayer-danmaku-bar-wrap .dplayer-danmaku-bar .dplayer-danmaku-bar-inner .dplayer-thumb{position:absolute;top:0;right:5px;margin-top:-4px;margin-right:-10px;height:11px;width:11px;border-radius:50%;cursor:pointer;transition:all .3s ease-in-out;background:#aaa}.dplayer-controller .dplayer-icons .dplayer-full{display:inline-block;height:100%;position:relative}.dplayer-controller .dplayer-icons .dplayer-full:hover .dplayer-full-in-icon{display:block}.dplayer-controller .dplayer-icons .dplayer-full .dplayer-full-in-icon{position:absolute;top:-30px;z-index:1;display:none}.dplayer-controller .dplayer-icons .dplayer-quality{position:relative;display:inline-block;height:100%;z-index:2}.dplayer-controller .dplayer-icons .dplayer-quality:hover .dplayer-quality-list,.dplayer-controller .dplayer-icons .dplayer-quality:hover .dplayer-quality-mask{display:block}.dplayer-controller .dplayer-icons .dplayer-quality .dplayer-quality-mask{display:none;position:absolute;bottom:38px;left:-18px;width:80px;padding-bottom:12px}.dplayer-controller .dplayer-icons .dplayer-quality .dplayer-quality-list{display:none;font-size:12px;width:80px;border-radius:2px;background:rgba(28,28,28,.9);padding:5px 0;transition:all .3s ease-in-out;overflow:hidden;color:#fff;text-align:center}.dplayer-controller .dplayer-icons .dplayer-quality .dplayer-quality-item{height:25px;box-sizing:border-box;cursor:pointer;line-height:25px}.dplayer-controller .dplayer-icons .dplayer-quality .dplayer-quality-item:hover{background-color:hsla(0,0%,100%,.1)}.dplayer-controller .dplayer-icons .dplayer-comment{display:inline-block;height:100%}.dplayer-controller .dplayer-icons .dplayer-label{color:#eee;font-size:13px;display:inline-block;vertical-align:middle;white-space:nowrap}.dplayer-controller .dplayer-icons .dplayer-toggle{width:32px;height:20px;text-align:center;font-size:0;vertical-align:middle;position:absolute;top:5px;right:10px}.dplayer-controller .dplayer-icons .dplayer-toggle input{max-height:0;max-width:0;display:none}.dplayer-controller .dplayer-icons .dplayer-toggle input+label{display:inline-block;position:relative;box-shadow:inset 0 0 0 0 #dfdfdf;border:1px solid #dfdfdf;height:20px;width:32px;border-radius:10px;box-sizing:border-box;cursor:pointer;transition:.2s ease-in-out}.dplayer-controller .dplayer-icons .dplayer-toggle input+label:after,.dplayer-controller .dplayer-icons .dplayer-toggle input+label:before{content:"";position:absolute;display:block;height:18px;width:18px;top:0;left:0;border-radius:15px;transition:.2s ease-in-out}.dplayer-controller .dplayer-icons .dplayer-toggle input+label:after{background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.4)}.dplayer-controller .dplayer-icons .dplayer-toggle input:checked+label{border-color:hsla(0,0%,100%,.5)}.dplayer-controller .dplayer-icons .dplayer-toggle input:checked+label:before{width:30px;background:hsla(0,0%,100%,.5)}.dplayer-controller .dplayer-icons .dplayer-toggle input:checked+label:after{left:12px}.dplayer-danmaku{position:absolute;left:0;right:0;top:0;bottom:0;font-size:22px;color:#fff}.dplayer-danmaku .dplayer-danmaku-item{display:inline-block;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;white-space:nowrap;text-shadow:.5px .5px .5px rgba(0,0,0,.5)}.dplayer-danmaku .dplayer-danmaku-item--demo{position:absolute;visibility:hidden}.dplayer-danmaku .dplayer-danmaku-right{position:absolute;right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.dplayer-danmaku .dplayer-danmaku-right.dplayer-danmaku-move{will-change:transform;-webkit-animation:danmaku 5s linear;animation:danmaku 5s linear;-webkit-animation-play-state:paused;animation-play-state:paused}@-webkit-keyframes danmaku{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes danmaku{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}}.dplayer-danmaku .dplayer-danmaku-bottom,.dplayer-danmaku .dplayer-danmaku-top{position:absolute;width:100%;text-align:center;visibility:hidden}.dplayer-danmaku .dplayer-danmaku-bottom.dplayer-danmaku-move,.dplayer-danmaku .dplayer-danmaku-top.dplayer-danmaku-move{will-change:visibility;-webkit-animation:danmaku-center 4s linear;animation:danmaku-center 4s linear;-webkit-animation-play-state:paused;animation-play-state:paused}@-webkit-keyframes danmaku-center{0%{visibility:visible}to{visibility:visible}}@keyframes danmaku-center{0%{visibility:visible}to{visibility:visible}}.dplayer-logo{pointer-events:none;position:absolute;left:20px;top:20px;max-width:50px;max-height:50px}.dplayer-logo img{max-width:100%;max-height:100%;background:none}.dplayer-menu{position:absolute;width:170px;border-radius:2px;background:rgba(28,28,28,.85);padding:5px 0;overflow:hidden;z-index:3;display:none}.dplayer-menu.dplayer-menu-show{display:block}.dplayer-menu .dplayer-menu-item{height:30px;box-sizing:border-box;cursor:pointer}.dplayer-menu .dplayer-menu-item:hover{background-color:hsla(0,0%,100%,.1)}.dplayer-menu .dplayer-menu-item a{padding:0 10px;line-height:30px;color:#eee;font-size:13px;display:inline-block;vertical-align:middle;width:100%;box-sizing:border-box;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dplayer-menu .dplayer-menu-item a:hover{text-decoration:none}.dplayer-notice{opacity:0;position:absolute;bottom:60px;left:20px;font-size:14px;border-radius:2px;background:rgba(28,28,28,.9);padding:7px 20px;transition:all .3s ease-in-out;overflow:hidden;color:#fff;pointer-events:none}.dplayer-subtitle{position:absolute;bottom:40px;width:90%;left:5%;text-align:center;color:#fff;text-shadow:.5px .5px .5px rgba(0,0,0,.5);font-size:20px}.dplayer-subtitle.dplayer-subtitle-hide{display:none}.dplayer-mask{position:absolute;top:0;bottom:0;left:0;right:0;z-index:1;display:none}.dplayer-mask.dplayer-mask-show{display:block}.dplayer-video-wrap{position:relative;background:#000;font-size:0;width:100%;height:100%}.dplayer-video-wrap .dplayer-video{width:100%;height:100%;display:none}.dplayer-video-wrap .dplayer-video-current{display:block}.dplayer-video-wrap .dplayer-video-prepare{display:none}.dplayer-info-panel{position:absolute;top:10px;left:10px;width:400px;background:rgba(28,28,28,.8);padding:10px;color:#fff;font-size:12px;border-radius:2px}.dplayer-info-panel-hide{display:none}.dplayer-info-panel .dplayer-info-panel-close{cursor:pointer;position:absolute;right:10px;top:10px}.dplayer-info-panel .dplayer-info-panel-item>span{display:inline-block;vertical-align:middle;line-height:15px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dplayer-info-panel .dplayer-info-panel-item-title{width:100px;text-align:right;margin-right:10px}.dplayer-info-panel .dplayer-info-panel-item-data{width:260px} + +/*# sourceMappingURL=DPlayer.min.css.map*/ \ No newline at end of file diff --git a/css/clock.css b/css/clock.css new file mode 100644 index 0000000000..ee844013db --- /dev/null +++ b/css/clock.css @@ -0,0 +1,131 @@ +body { + background: black; +} + +.clock { + position: absolute; + opacity: 1; +} + +.fill .clock { + left: 50%; + top: 50%; +} + +.centre { + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; +} + +.expand { + position: absolute; + top: 0; + left: 0; + transform: translate(-50%, -50%); +} + +.anchor { + position: absolute; + top: 0; + left: 0; + width: 0; + height: 0; +} + +.element { + position: absolute; + top: 0; + left: 0; +} + +.round { + border-radius: 296px; +} + +.circle-1 { + background: white; + width: 12px; + height: 12px; +} + +.circle-2 { + background: #FA9F22; + width: 8px; + height: 8px; +} + +.circle-3 { + background: black; + width: 4px; + height: 4px; +} + +.second { + transform: rotate(180deg); +} + +.minute { + transform: rotate(54deg); +} + +.second-hand { + width: 2px; + height: 164px; + background: #FA9F22; + transform: translate(-50%,-100%) translateY(24px); +} + +.hour { + transform: rotate(304.5deg); +} + +.thin-hand { + width: 4px; + height: 50px; + background: white; + transform: translate(-50%,-100%); +} + +.fat-hand { + width: 10px; + height: 57px; + border-radius: 10px; + background: white; + transform: translate(-50%,-100%) translateY(-18px); +} + +.minute-hand { + height: 112px; +} + +.hour-text { + position: absolute; + font: 40px Hei, Helvetica, Arial, sans-serif; + color: white; + transform: translate(-50%,-50%); +} + +.hour-10 { + padding-left: 0.4ex; +} +.hour-11 { + padding-left: 0.25ex; +} + +.minute-text { + position: absolute; + font: 12px Avenir Next, Helvetica, Arial, sans-serif; + color: white; + transform: translate(-50%,-50%); +} + +.minute-line { + background: white; + width: 1px; + height: 9px; + transform: translate(-50%,-100%) translateY(-131px); + opacity: 0.34; +} \ No newline at end of file diff --git a/css/cyberpunk.css b/css/cyberpunk.css new file mode 100644 index 0000000000..a72b8079fe --- /dev/null +++ b/css/cyberpunk.css @@ -0,0 +1,13252 @@ +@-moz-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +@-webkit-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +@-o-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +@keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +.is-unselectable, +.breadcrumb, +.modal-close, +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, +.tabs, +.button, +.delete, +.file { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.navbar-link:not(.is-arrowless)::after, +.select:not(.is-multiple):not(.is-loading)::after { + border: 3px solid transparent; + border-radius: 2px; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + width: 0.625em; +} +.breadcrumb:not(:last-child), +.level:not(:last-child), +.list:not(:last-child), +.message:not(:last-child), +.pagination:not(:last-child), +.tabs:not(:last-child), +.box:not(:last-child), +.content:not(:last-child), +.notification:not(:last-child), +.progress:not(:last-child), +.table:not(:last-child), +.table-container:not(:last-child), +.title:not(:last-child), +.subtitle:not(:last-child), +.block:not(:last-child), +.highlight:not(:last-child) { + margin-bottom: 1.5rem; +} +.modal-close, +.delete { + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(0,0,0,0.2); + border: none; + border-radius: 290486px; + cursor: pointer; + pointer-events: auto; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; +} +.modal-close::before, +.delete::before, +.modal-close::after, +.delete::after { + background-color: #000; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} +.modal-close::before, +.delete::before { + height: 2px; + width: 50%; +} +.modal-close::after, +.delete::after { + height: 50%; + width: 2px; +} +.modal-close:hover, +.delete:hover, +.modal-close:focus, +.delete:focus { + background-color: rgba(0,0,0,0.3); +} +.modal-close:active, +.delete:active { + background-color: rgba(0,0,0,0.4); +} +.modal-close.is-small, +.delete.is-small { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; +} +.modal-close.is-medium, +.delete.is-medium { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; +} +.modal-close.is-large, +.delete.is-large { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; +} +.button.is-loading::after, +.loader, +.select.is-loading::after, +.control.is-loading::after { + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 290486px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; +} +.is-overlay, +.modal, +.modal-background, +.image.is-square img, +.image.is-1by1 img, +.image.is-5by4 img, +.image.is-4by3 img, +.image.is-3by2 img, +.image.is-5by3 img, +.image.is-16by9 img, +.image.is-2by1 img, +.image.is-3by1 img, +.image.is-4by5 img, +.image.is-3by4 img, +.image.is-2by3 img, +.image.is-3by5 img, +.image.is-9by16 img, +.image.is-1by2 img, +.image.is-1by3 img, +.image.is-square .has-ratio, +.image.is-1by1 .has-ratio, +.image.is-5by4 .has-ratio, +.image.is-4by3 .has-ratio, +.image.is-3by2 .has-ratio, +.image.is-5by3 .has-ratio, +.image.is-16by9 .has-ratio, +.image.is-2by1 .has-ratio, +.image.is-3by1 .has-ratio, +.image.is-4by5 .has-ratio, +.image.is-3by4 .has-ratio, +.image.is-2by3 .has-ratio, +.image.is-3by5 .has-ratio, +.image.is-9by16 .has-ratio, +.image.is-1by2 .has-ratio, +.image.is-1by3 .has-ratio, +.hero-video { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, +.button, +.input, +.textarea, +.select select, +.file-cta, +.file-name { + -moz-appearance: none; + -webkit-appearance: none; + align-items: center; + border: 1px solid transparent; + border-radius: 0; + box-shadow: none; + display: inline-flex; + font-size: 1rem; + height: 2.25em; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.5em - 1px); + padding-left: calc(0.75em - 1px); + padding-right: calc(0.75em - 1px); + padding-top: calc(0.5em - 1px); + position: relative; + vertical-align: top; +} +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus, +.pagination-ellipsis:focus, +.button:focus, +.input:focus, +.textarea:focus, +.select select:focus, +.file-cta:focus, +.file-name:focus, +.pagination-previous.is-focused, +.pagination-next.is-focused, +.pagination-link.is-focused, +.pagination-ellipsis.is-focused, +.button.is-focused, +.input.is-focused, +.textarea.is-focused, +.select select.is-focused, +.file-cta.is-focused, +.file-name.is-focused, +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active, +.pagination-ellipsis:active, +.button:active, +.input:active, +.textarea:active, +.select select:active, +.file-cta:active, +.file-name:active, +.pagination-previous.is-active, +.pagination-next.is-active, +.pagination-link.is-active, +.pagination-ellipsis.is-active, +.button.is-active, +.input.is-active, +.textarea.is-active, +.select select.is-active, +.file-cta.is-active, +.file-name.is-active { + outline: none; +} +.pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled], +.pagination-ellipsis[disabled], +.button[disabled], +.input[disabled], +.textarea[disabled], +.select select[disabled], +.file-cta[disabled], +.file-name[disabled], +fieldset[disabled] .pagination-previous, +fieldset[disabled] .pagination-next, +fieldset[disabled] .pagination-link, +fieldset[disabled] .pagination-ellipsis, +fieldset[disabled] .button, +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select, +fieldset[disabled] .file-cta, +fieldset[disabled] .file-name { + cursor: not-allowed; +} +/* minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} +ul { + list-style: none; +} +button, +input, +select, +textarea { + margin: 0; +} +html { + box-sizing: border-box; +} +*, +*::before, +*::after { + box-sizing: inherit; +} +img, +video { + height: auto; + max-width: 100%; +} +iframe { + border: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +td:not([align]), +th:not([align]) { + text-align: left; +} +html { + background-color: #000; + font-size: 14px; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + text-size-adjust: 100%; +} +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; +} +body, +button, +input, +select, +textarea { + font-family: 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif; +} +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: 'Roboto Mono', monospace, 'Microsoft YaHei'; +} +body { + color: #cdcdcd; + font-size: 1em; + font-weight: 400; + line-height: 1.5; +} +a { + color: #02d7f2; + cursor: pointer; + text-decoration: none; +} +a strong { + color: currentColor; +} +a:hover { + color: #fcee09; +} +code { + background-color: #f5f5f5; + color: #ff003c; + font-size: 0.875em; + font-weight: normal; + padding: 0.25em 0.5em 0.25em; +} +hr { + background-color: #f5f5f5; + border: none; + display: block; + height: 2px; + margin: 1.5rem 0; +} +img { + height: auto; + max-width: 100%; +} +input[type="checkbox"], +input[type="radio"] { + vertical-align: baseline; +} +small { + font-size: 0.875em; +} +span { + font-style: inherit; + font-weight: inherit; +} +strong { + color: #fcee09; + font-weight: 700; +} +fieldset { + border: none; +} +pre { + -webkit-overflow-scrolling: touch; + background-color: #f5f5f5; + color: #cdcdcd; + font-size: 0.875em; + overflow-x: auto; + padding: 1.25rem 1.5rem; + white-space: pre; + word-wrap: normal; +} +pre code { + background-color: transparent; + color: currentColor; + font-size: 1em; + padding: 0; +} +table td, +table th { + vertical-align: top; +} +table td:not([align]), +table th:not([align]) { + text-align: left; +} +table th { + color: #fcee09; +} +.is-clearfix::after { + clear: both; + content: " "; + display: table; +} +.is-pulled-left { + float: left !important; +} +.is-pulled-right { + float: right !important; +} +.is-clipped { + overflow: hidden !important; +} +.is-size-1 { + font-size: 3rem !important; +} +.is-size-2 { + font-size: 2.5rem !important; +} +.is-size-3 { + font-size: 2rem !important; +} +.is-size-4 { + font-size: 1.5rem !important; +} +.is-size-5 { + font-size: 1.25rem !important; +} +.is-size-6, +article.media .title { + font-size: 1rem !important; +} +.is-size-7, +article.media .date, +article.media .categories, +.article-licensing .licensing-title a, +.article-licensing .licensing-meta h6 { + font-size: 0.85rem !important; +} +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; + } + .is-size-2-mobile { + font-size: 2.5rem !important; + } + .is-size-3-mobile { + font-size: 2rem !important; + } + .is-size-4-mobile { + font-size: 1.5rem !important; + } + .is-size-5-mobile { + font-size: 1.25rem !important; + } + .is-size-6-mobile { + font-size: 1rem !important; + } + .is-size-7-mobile { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; + } + .is-size-2-tablet { + font-size: 2.5rem !important; + } + .is-size-3-tablet { + font-size: 2rem !important; + } + .is-size-4-tablet { + font-size: 1.5rem !important; + } + .is-size-5-tablet { + font-size: 1.25rem !important; + } + .is-size-6-tablet { + font-size: 1rem !important; + } + .is-size-7-tablet { + font-size: 0.85rem !important; + } +} +@media screen and (max-width: 1087px) { + .is-size-1-touch { + font-size: 3rem !important; + } + .is-size-2-touch { + font-size: 2.5rem !important; + } + .is-size-3-touch { + font-size: 2rem !important; + } + .is-size-4-touch { + font-size: 1.5rem !important; + } + .is-size-5-touch { + font-size: 1.25rem !important; + } + .is-size-6-touch { + font-size: 1rem !important; + } + .is-size-7-touch { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 1088px) { + .is-size-1-desktop { + font-size: 3rem !important; + } + .is-size-2-desktop { + font-size: 2.5rem !important; + } + .is-size-3-desktop { + font-size: 2rem !important; + } + .is-size-4-desktop { + font-size: 1.5rem !important; + } + .is-size-5-desktop { + font-size: 1.25rem !important; + } + .is-size-6-desktop { + font-size: 1rem !important; + } + .is-size-7-desktop { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 1280px) { + .is-size-1-widescreen { + font-size: 3rem !important; + } + .is-size-2-widescreen { + font-size: 2.5rem !important; + } + .is-size-3-widescreen { + font-size: 2rem !important; + } + .is-size-4-widescreen { + font-size: 1.5rem !important; + } + .is-size-5-widescreen { + font-size: 1.25rem !important; + } + .is-size-6-widescreen { + font-size: 1rem !important; + } + .is-size-7-widescreen { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 1472px) { + .is-size-1-fullhd { + font-size: 3rem !important; + } + .is-size-2-fullhd { + font-size: 2.5rem !important; + } + .is-size-3-fullhd { + font-size: 2rem !important; + } + .is-size-4-fullhd { + font-size: 1.5rem !important; + } + .is-size-5-fullhd { + font-size: 1.25rem !important; + } + .is-size-6-fullhd { + font-size: 1rem !important; + } + .is-size-7-fullhd { + font-size: 0.85rem !important; + } +} +.has-text-centered { + text-align: center !important; +} +.has-text-justified { + text-align: justify !important; +} +.has-text-left { + text-align: left !important; +} +.has-text-right { + text-align: right !important; +} +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-centered-tablet-only { + text-align: center !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-centered-touch { + text-align: center !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-centered-desktop { + text-align: center !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-centered-desktop-only { + text-align: center !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-centered-widescreen { + text-align: center !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-centered-widescreen-only { + text-align: center !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-centered-fullhd { + text-align: center !important; + } +} +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-justified-tablet-only { + text-align: justify !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-justified-touch { + text-align: justify !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-justified-desktop { + text-align: justify !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-justified-desktop-only { + text-align: justify !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-justified-widescreen { + text-align: justify !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-justified-widescreen-only { + text-align: justify !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-justified-fullhd { + text-align: justify !important; + } +} +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-left-tablet-only { + text-align: left !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-left-touch { + text-align: left !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-left-desktop { + text-align: left !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-left-desktop-only { + text-align: left !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-left-widescreen { + text-align: left !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-left-widescreen-only { + text-align: left !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-left-fullhd { + text-align: left !important; + } +} +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-right-tablet-only { + text-align: right !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-right-touch { + text-align: right !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-right-desktop { + text-align: right !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-right-desktop-only { + text-align: right !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-right-widescreen { + text-align: right !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-right-widescreen-only { + text-align: right !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-right-fullhd { + text-align: right !important; + } +} +.is-capitalized { + text-transform: capitalize !important; +} +.is-lowercase { + text-transform: lowercase !important; +} +.is-uppercase, +article.media .categories { + text-transform: uppercase !important; +} +.is-italic { + font-style: italic !important; +} +.has-text-white { + color: #fff !important; +} +a.has-text-white:hover, +a.has-text-white:focus { + color: #e6e6e6 !important; +} +.has-background-white { + background-color: #fff !important; +} +.has-text-black { + color: #000 !important; +} +a.has-text-black:hover, +a.has-text-black:focus { + color: #000 !important; +} +.has-background-black { + background-color: #000 !important; +} +.has-text-light { + color: #f5f5f5 !important; +} +a.has-text-light:hover, +a.has-text-light:focus { + color: #dbdbdb !important; +} +.has-background-light { + background-color: #f5f5f5 !important; +} +.has-text-dark { + color: #363636 !important; +} +a.has-text-dark:hover, +a.has-text-dark:focus { + color: #1c1c1c !important; +} +.has-background-dark { + background-color: #363636 !important; +} +.has-text-primary { + color: #fcee09 !important; +} +a.has-text-primary:hover, +a.has-text-primary:focus { + color: #cfc403 !important; +} +.has-background-primary { + background-color: #fcee09 !important; +} +.has-text-link { + color: #02d7f2 !important; +} +a.has-text-link:hover, +a.has-text-link:focus { + color: #02aabf !important; +} +.has-background-link { + background-color: #02d7f2 !important; +} +.has-text-info { + color: #02d7f2 !important; +} +a.has-text-info:hover, +a.has-text-info:focus { + color: #02aabf !important; +} +.has-background-info { + background-color: #02d7f2 !important; +} +.has-text-success { + color: #00ff41 !important; +} +a.has-text-success:hover, +a.has-text-success:focus { + color: #00cc34 !important; +} +.has-background-success { + background-color: #00ff41 !important; +} +.has-text-warning { + color: #ff8e3c !important; +} +a.has-text-warning:hover, +a.has-text-warning:focus { + color: #ff7009 !important; +} +.has-background-warning { + background-color: #ff8e3c !important; +} +.has-text-danger { + color: #ff003c !important; +} +a.has-text-danger:hover, +a.has-text-danger:focus { + color: #cc0030 !important; +} +.has-background-danger { + background-color: #ff003c !important; +} +.has-text-grey-lightest { + color: #ededed !important; +} +a.has-text-grey-lightest:hover, +a.has-text-grey-lightest:focus { + color: #d4d4d4 !important; +} +.has-background-grey-lightest { + background-color: #ededed !important; +} +.has-text-black-bis { + color: #050a0e !important; +} +.has-background-black-bis { + background-color: #050a0e !important; +} +.has-text-black-ter { + color: #242424 !important; +} +.has-background-black-ter { + background-color: #242424 !important; +} +.has-text-grey-darker { + color: #363636 !important; +} +.has-background-grey-darker { + background-color: #363636 !important; +} +.has-text-grey-dark { + color: #4a4a4a !important; +} +.has-background-grey-dark { + background-color: #4a4a4a !important; +} +.has-text-grey, +.article-licensing .licensing-title a { + color: #848484 !important; +} +.has-background-grey { + background-color: #848484 !important; +} +.has-text-grey-light { + color: #b5b5b5 !important; +} +.has-background-grey-light { + background-color: #b5b5b5 !important; +} +.has-text-grey-lighter { + color: #dbdbdb !important; +} +.has-background-grey-lighter { + background-color: #dbdbdb !important; +} +.has-text-white-ter { + color: #f5f5f5 !important; +} +.has-background-white-ter { + background-color: #f5f5f5 !important; +} +.has-text-white-bis { + color: #cdcdcd !important; +} +.has-background-white-bis { + background-color: #cdcdcd !important; +} +.has-text-weight-light { + font-weight: 300 !important; +} +.has-text-weight-normal { + font-weight: 400 !important; +} +.has-text-weight-medium { + font-weight: 500 !important; +} +.has-text-weight-semibold { + font-weight: 600 !important; +} +.has-text-weight-bold { + font-weight: 700 !important; +} +.is-family-primary { + font-family: 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.is-family-secondary { + font-family: 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.is-family-sans-serif { + font-family: 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.is-family-monospace { + font-family: monospace !important; +} +.is-family-code { + font-family: 'Roboto Mono', monospace, 'Microsoft YaHei' !important; +} +.is-block { + display: block !important; +} +@media screen and (max-width: 768px) { + .is-block-mobile { + display: block !important; + } +} +@media screen and (min-width: 769px), print { + .is-block-tablet { + display: block !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-block-tablet-only { + display: block !important; + } +} +@media screen and (max-width: 1087px) { + .is-block-touch { + display: block !important; + } +} +@media screen and (min-width: 1088px) { + .is-block-desktop { + display: block !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-block-desktop-only { + display: block !important; + } +} +@media screen and (min-width: 1280px) { + .is-block-widescreen { + display: block !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-block-widescreen-only { + display: block !important; + } +} +@media screen and (min-width: 1472px) { + .is-block-fullhd { + display: block !important; + } +} +.is-flex { + display: flex !important; +} +@media screen and (max-width: 768px) { + .is-flex-mobile { + display: flex !important; + } +} +@media screen and (min-width: 769px), print { + .is-flex-tablet { + display: flex !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-flex-tablet-only { + display: flex !important; + } +} +@media screen and (max-width: 1087px) { + .is-flex-touch { + display: flex !important; + } +} +@media screen and (min-width: 1088px) { + .is-flex-desktop { + display: flex !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-flex-desktop-only { + display: flex !important; + } +} +@media screen and (min-width: 1280px) { + .is-flex-widescreen { + display: flex !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-flex-widescreen-only { + display: flex !important; + } +} +@media screen and (min-width: 1472px) { + .is-flex-fullhd { + display: flex !important; + } +} +.is-inline { + display: inline !important; +} +@media screen and (max-width: 768px) { + .is-inline-mobile { + display: inline !important; + } +} +@media screen and (min-width: 769px), print { + .is-inline-tablet { + display: inline !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-tablet-only { + display: inline !important; + } +} +@media screen and (max-width: 1087px) { + .is-inline-touch { + display: inline !important; + } +} +@media screen and (min-width: 1088px) { + .is-inline-desktop { + display: inline !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-desktop-only { + display: inline !important; + } +} +@media screen and (min-width: 1280px) { + .is-inline-widescreen { + display: inline !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-inline-widescreen-only { + display: inline !important; + } +} +@media screen and (min-width: 1472px) { + .is-inline-fullhd { + display: inline !important; + } +} +.is-inline-block { + display: inline-block !important; +} +@media screen and (max-width: 768px) { + .is-inline-block-mobile { + display: inline-block !important; + } +} +@media screen and (min-width: 769px), print { + .is-inline-block-tablet { + display: inline-block !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-block-tablet-only { + display: inline-block !important; + } +} +@media screen and (max-width: 1087px) { + .is-inline-block-touch { + display: inline-block !important; + } +} +@media screen and (min-width: 1088px) { + .is-inline-block-desktop { + display: inline-block !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-block-desktop-only { + display: inline-block !important; + } +} +@media screen and (min-width: 1280px) { + .is-inline-block-widescreen { + display: inline-block !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-inline-block-widescreen-only { + display: inline-block !important; + } +} +@media screen and (min-width: 1472px) { + .is-inline-block-fullhd { + display: inline-block !important; + } +} +.is-inline-flex { + display: inline-flex !important; +} +@media screen and (max-width: 768px) { + .is-inline-flex-mobile { + display: inline-flex !important; + } +} +@media screen and (min-width: 769px), print { + .is-inline-flex-tablet { + display: inline-flex !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-flex-tablet-only { + display: inline-flex !important; + } +} +@media screen and (max-width: 1087px) { + .is-inline-flex-touch { + display: inline-flex !important; + } +} +@media screen and (min-width: 1088px) { + .is-inline-flex-desktop { + display: inline-flex !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-flex-desktop-only { + display: inline-flex !important; + } +} +@media screen and (min-width: 1280px) { + .is-inline-flex-widescreen { + display: inline-flex !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-inline-flex-widescreen-only { + display: inline-flex !important; + } +} +@media screen and (min-width: 1472px) { + .is-inline-flex-fullhd { + display: inline-flex !important; + } +} +.is-hidden { + display: none !important; +} +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; +} +@media screen and (max-width: 768px) { + .is-hidden-mobile { + display: none !important; + } +} +@media screen and (min-width: 769px), print { + .is-hidden-tablet { + display: none !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-hidden-tablet-only { + display: none !important; + } +} +@media screen and (max-width: 1087px) { + .is-hidden-touch { + display: none !important; + } +} +@media screen and (min-width: 1088px) { + .is-hidden-desktop { + display: none !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-hidden-desktop-only { + display: none !important; + } +} +@media screen and (min-width: 1280px) { + .is-hidden-widescreen { + display: none !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-hidden-widescreen-only { + display: none !important; + } +} +@media screen and (min-width: 1472px) { + .is-hidden-fullhd { + display: none !important; + } +} +.is-invisible { + visibility: hidden !important; +} +@media screen and (max-width: 768px) { + .is-invisible-mobile { + visibility: hidden !important; + } +} +@media screen and (min-width: 769px), print { + .is-invisible-tablet { + visibility: hidden !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-invisible-tablet-only { + visibility: hidden !important; + } +} +@media screen and (max-width: 1087px) { + .is-invisible-touch { + visibility: hidden !important; + } +} +@media screen and (min-width: 1088px) { + .is-invisible-desktop { + visibility: hidden !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-invisible-desktop-only { + visibility: hidden !important; + } +} +@media screen and (min-width: 1280px) { + .is-invisible-widescreen { + visibility: hidden !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-invisible-widescreen-only { + visibility: hidden !important; + } +} +@media screen and (min-width: 1472px) { + .is-invisible-fullhd { + visibility: hidden !important; + } +} +.is-marginless { + margin: 0 !important; +} +.is-paddingless { + padding: 0 !important; +} +.is-radiusless { + border-radius: 0 !important; +} +.is-shadowless { + box-shadow: none !important; +} +.is-relative { + position: relative !important; +} +.breadcrumb { + font-size: 1rem; + white-space: nowrap; +} +.breadcrumb a { + align-items: center; + color: #02d7f2; + display: flex; + justify-content: center; + padding: 0 0.75em; +} +.breadcrumb a:hover { + color: #fcee09; +} +.breadcrumb li { + align-items: center; + display: flex; +} +.breadcrumb li:first-child a { + padding-left: 0; +} +.breadcrumb li.is-active a { + color: #fcee09; + cursor: default; + pointer-events: none; +} +.breadcrumb li + li::before { + color: #b5b5b5; + content: "\0002f"; +} +.breadcrumb ul, +.breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.breadcrumb .icon:first-child { + margin-right: 0.5em; +} +.breadcrumb .icon:last-child { + margin-left: 0.5em; +} +.breadcrumb.is-centered ol, +.breadcrumb.is-centered ul { + justify-content: center; +} +.breadcrumb.is-right ol, +.breadcrumb.is-right ul { + justify-content: flex-end; +} +.breadcrumb.is-small { + font-size: 0.75rem; +} +.breadcrumb.is-medium { + font-size: 1.25rem; +} +.breadcrumb.is-large { + font-size: 1.5rem; +} +.breadcrumb.has-arrow-separator li + li::before { + content: "\02192"; +} +.breadcrumb.has-bullet-separator li + li::before { + content: "\02022"; +} +.breadcrumb.has-dot-separator li + li::before { + content: "\000b7"; +} +.breadcrumb.has-succeeds-separator li + li::before { + content: "\0227B"; +} +.card { + background-color: transparent; + box-shadow: none, 0 0 1px rgba(0,0,0,0.1); + color: #cdcdcd; + max-width: 100%; + position: relative; +} +.card-header { + background-color: transparent; + align-items: stretch; + box-shadow: 0 0.125em 0.25em rgba(0,0,0,0.1); + display: flex; +} +.card-header-title { + align-items: center; + color: #fcee09; + display: flex; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem 1rem; +} +.card-header-title.is-centered { + justify-content: center; +} +.card-header-icon { + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: 0.75rem 1rem; +} +.card-image { + display: block; + position: relative; +} +.card-content { + background-color: transparent; + padding: 1.5rem; +} +.card-footer { + background-color: transparent; + border-top: 1px solid #ededed; + align-items: stretch; + display: flex; +} +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: 0.75rem; +} +.card-footer-item:not(:last-child) { + border-right: 1px solid #ededed; +} +.card .media:not(:last-child) { + margin-bottom: 0.75rem; +} +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; +} +.dropdown.is-active .dropdown-menu, +.dropdown.is-hoverable:hover .dropdown-menu { + display: block; +} +.dropdown.is-right .dropdown-menu { + left: auto; + right: 0; +} +.dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: initial; + top: auto; +} +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; +} +.dropdown-content { + background-color: #000; + border-radius: 0; + box-shadow: 0 0.5em 1em -0.125em rgba(0,0,0,0.1), 0 0px 0 1px rgba(0,0,0,0.02); + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} +.dropdown-item { + color: #cdcdcd; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; +} +a.dropdown-item, +button.dropdown-item { + padding-right: 3rem; + text-align: left; + white-space: nowrap; + width: 100%; +} +a.dropdown-item:hover, +button.dropdown-item:hover { + background-color: #f5f5f5; + color: #000; +} +a.dropdown-item.is-active, +button.dropdown-item.is-active { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.dropdown-divider { + background-color: #ededed; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; +} +.level { + align-items: center; + justify-content: space-between; +} +.level code { + border-radius: 0; +} +.level img { + display: inline-block; + vertical-align: top; +} +.level.is-mobile { + display: flex; +} +.level.is-mobile .level-left, +.level.is-mobile .level-right { + display: flex; +} +.level.is-mobile .level-left + .level-right { + margin-top: 0; +} +.level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} +.level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; +} +@media screen and (min-width: 769px), print { + .level { + display: flex; + } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; + } +} +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; +} +.level-item .title, +.level-item .subtitle { + margin-bottom: 0; +} +@media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; + } +} +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} +.level-left .level-item.is-flexible, +.level-right .level-item.is-flexible { + flex-grow: 1; +} +@media screen and (min-width: 769px), print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; + } +} +.level-left { + align-items: center; + justify-content: flex-start; +} +@media screen and (max-width: 768px) { + .level-left + .level-right { + margin-top: 1.5rem; + } +} +@media screen and (min-width: 769px), print { + .level-left { + display: flex; + } +} +.level-right { + align-items: center; + justify-content: flex-end; +} +@media screen and (min-width: 769px), print { + .level-right { + display: flex; + } +} +.list { + background-color: #000; + border-radius: 0; + box-shadow: 0 2px 3px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.1); +} +.list-item { + display: block; + padding: 0.5em 1em; +} +.list-item:not(a) { + color: #cdcdcd; +} +.list-item:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.list-item:last-child { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +.list-item:not(:last-child) { + border-bottom: 1px solid #dbdbdb; +} +.list-item.is-active { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +a.list-item { + background-color: #f5f5f5; + cursor: pointer; +} +.media { + align-items: flex-start; + display: flex; + text-align: left; +} +.media .content:not(:last-child) { + margin-bottom: 0.75rem; +} +.media .media { + border-top: 1px solid rgba(219,219,219,0.5); + display: flex; + padding-top: 0.75rem; +} +.media .media .content:not(:last-child), +.media .media .control:not(:last-child) { + margin-bottom: 0.5rem; +} +.media .media .media { + padding-top: 0.5rem; +} +.media .media .media + .media { + margin-top: 0.5rem; +} +.media + .media { + border-top: 1px solid rgba(219,219,219,0.5); + margin-top: 1rem; + padding-top: 1rem; +} +.media.is-large + .media { + margin-top: 1.5rem; + padding-top: 1.5rem; +} +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} +.media-left { + margin-right: 1rem; +} +.media-right { + margin-left: 1rem; +} +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: left; +} +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; + } +} +.menu { + font-size: 1rem; +} +.menu.is-small { + font-size: 0.75rem; +} +.menu.is-medium { + font-size: 1.25rem; +} +.menu.is-large { + font-size: 1.5rem; +} +.menu-list { + line-height: 1.25; +} +.menu-list a { + border-radius: 0; + color: #cdcdcd; + display: block; + padding: 0.5em 0.75em; +} +.menu-list a:hover { + background-color: #fcee09; + color: #000; +} +.menu-list a.is-active { + background-color: #fcee09; + color: #000; +} +.menu-list li ul { + border-left: 1px solid #cdcdcd; + margin: 0.75em; + padding-left: 0.75em; +} +.menu-label { + color: #02d7f2; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; +} +.menu-label:not(:first-child) { + margin-top: 1em; +} +.menu-label:not(:last-child) { + margin-bottom: 1em; +} +.message { + background-color: #f5f5f5; + border-radius: 0; + font-size: 1rem; +} +.message strong { + color: currentColor; +} +.message a:not(.button):not(.tag):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} +.message.is-small { + font-size: 0.75rem; +} +.message.is-medium { + font-size: 1.25rem; +} +.message.is-large { + font-size: 1.5rem; +} +.message.is-white { + background-color: #fff; +} +.message.is-white .message-header { + background-color: #fff; + color: #000; +} +.message.is-white .message-body { + border-color: #fff; +} +.message.is-black { + background-color: #fafafa; +} +.message.is-black .message-header { + background-color: #000; + color: #fff; +} +.message.is-black .message-body { + border-color: #000; +} +.message.is-light { + background-color: #fafafa; +} +.message.is-light .message-header { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.message.is-light .message-body { + border-color: #f5f5f5; +} +.message.is-dark { + background-color: #fafafa; +} +.message.is-dark .message-header { + background-color: #363636; + color: #fff; +} +.message.is-dark .message-body { + border-color: #363636; +} +.message.is-primary { + background-color: #fffeeb; +} +.message.is-primary .message-header { + background-color: #fcee09; + color: #121617; +} +.message.is-primary .message-body { + border-color: #fcee09; + color: #928a02; +} +.message.is-link { + background-color: #ebfdff; +} +.message.is-link .message-header { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.message.is-link .message-body { + border-color: #02d7f2; + color: #018293; +} +.message.is-info { + background-color: #ebfdff; +} +.message.is-info .message-header { + background-color: #02d7f2; + color: #121617; +} +.message.is-info .message-body { + border-color: #02d7f2; + color: #018293; +} +.message.is-success { + background-color: #ebfff0; +} +.message.is-success .message-header { + background-color: #00ff41; + color: #121617; +} +.message.is-success .message-body { + border-color: #00ff41; + color: #009426; +} +.message.is-warning { + background-color: #fff3eb; +} +.message.is-warning .message-header { + background-color: #ff8e3c; + color: #121617; +} +.message.is-warning .message-body { + border-color: #ff8e3c; + color: #a84700; +} +.message.is-danger { + background-color: #ffebef; +} +.message.is-danger .message-header { + background-color: #ff003c; + color: #121617; +} +.message.is-danger .message-body { + border-color: #ff003c; + color: #eb0037; +} +.message.is-grey-lightest { + background-color: #fafafa; +} +.message.is-grey-lightest .message-header { + background-color: #ededed; + color: #363636; +} +.message.is-grey-lightest .message-body { + border-color: #ededed; +} +.message-header { + align-items: center; + background-color: #cdcdcd; + border-radius: 0 0 0 0; + color: rgba(0,0,0,0.7); + display: flex; + font-weight: 700; + justify-content: space-between; + line-height: 1.25; + padding: 0.75em 1em; + position: relative; +} +.message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-left: 0.75em; +} +.message-header + .message-body { + border-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.message-body { + border-color: #dbdbdb; + border-radius: 0; + border-style: solid; + border-width: 0 0 0 4px; + color: #cdcdcd; + padding: 1.25em 1.5em; +} +.message-body code, +.message-body pre { + background-color: #000; +} +.message-body pre code { + background-color: transparent; +} +.modal { + align-items: center; + display: none; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; +} +.modal.is-active { + display: flex; +} +.modal-background { + background-color: rgba(0,0,0,0.86); +} +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; +} +@media screen and (min-width: 769px), print { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; + } +} +.modal-close { + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; +} +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; + -ms-overflow-y: visible; +} +.modal-card-head, +.modal-card-foot { + align-items: center; + background-color: #f5f5f5; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: 20px; + position: relative; +} +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} +.modal-card-title { + color: #fcee09; + flex-grow: 1; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; +} +.modal-card-foot { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid #dbdbdb; +} +.modal-card-foot .button:not(:last-child) { + margin-right: 0.5em; +} +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: #000; + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; +} +.navbar { + background-color: #fcee09; + min-height: 3.25rem; + position: relative; + z-index: 30; +} +.navbar.is-white { + background-color: #fff; + color: #000; +} +.navbar.is-white .navbar-brand > .navbar-item, +.navbar.is-white .navbar-brand .navbar-link { + color: #000; +} +.navbar.is-white .navbar-brand > a.navbar-item:focus, +.navbar.is-white .navbar-brand .navbar-link:focus, +.navbar.is-white .navbar-brand > a.navbar-item:hover, +.navbar.is-white .navbar-brand .navbar-link:hover, +.navbar.is-white .navbar-brand > a.navbar-item.is-active, +.navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #000; +} +.navbar.is-white .navbar-brand .navbar-link::after { + border-color: #000; +} +.navbar.is-white .navbar-burger { + color: #000; +} +@media screen and (min-width: 1088px) { + .navbar.is-white .navbar-start > .navbar-item, + .navbar.is-white .navbar-end > .navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end .navbar-link { + color: #000; + } + .navbar.is-white .navbar-start > a.navbar-item:focus, + .navbar.is-white .navbar-end > a.navbar-item:focus, + .navbar.is-white .navbar-start .navbar-link:focus, + .navbar.is-white .navbar-end .navbar-link:focus, + .navbar.is-white .navbar-start > a.navbar-item:hover, + .navbar.is-white .navbar-end > a.navbar-item:hover, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-start > a.navbar-item.is-active, + .navbar.is-white .navbar-end > a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #000; + } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #000; + } + .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #000; + } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: #fff; + color: #000; + } +} +.navbar.is-black { + background-color: #000; + color: #fff; +} +.navbar.is-black .navbar-brand > .navbar-item, +.navbar.is-black .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-black .navbar-brand > a.navbar-item:focus, +.navbar.is-black .navbar-brand .navbar-link:focus, +.navbar.is-black .navbar-brand > a.navbar-item:hover, +.navbar.is-black .navbar-brand .navbar-link:hover, +.navbar.is-black .navbar-brand > a.navbar-item.is-active, +.navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: #000; + color: #fff; +} +.navbar.is-black .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-black .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-black .navbar-start > .navbar-item, + .navbar.is-black .navbar-end > .navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-black .navbar-start > a.navbar-item:focus, + .navbar.is-black .navbar-end > a.navbar-item:focus, + .navbar.is-black .navbar-start .navbar-link:focus, + .navbar.is-black .navbar-end .navbar-link:focus, + .navbar.is-black .navbar-start > a.navbar-item:hover, + .navbar.is-black .navbar-end > a.navbar-item:hover, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-start > a.navbar-item.is-active, + .navbar.is-black .navbar-end > a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: #000; + color: #fff; + } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #000; + color: #fff; + } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #000; + color: #fff; + } +} +.navbar.is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-brand > .navbar-item, +.navbar.is-light .navbar-brand .navbar-link { + color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-brand > a.navbar-item:focus, +.navbar.is-light .navbar-brand .navbar-link:focus, +.navbar.is-light .navbar-brand > a.navbar-item:hover, +.navbar.is-light .navbar-brand .navbar-link:hover, +.navbar.is-light .navbar-brand > a.navbar-item.is-active, +.navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-brand .navbar-link::after { + border-color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-burger { + color: rgba(0,0,0,0.7); +} +@media screen and (min-width: 1088px) { + .navbar.is-light .navbar-start > .navbar-item, + .navbar.is-light .navbar-end > .navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end .navbar-link { + color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-start > a.navbar-item:focus, + .navbar.is-light .navbar-end > a.navbar-item:focus, + .navbar.is-light .navbar-start .navbar-link:focus, + .navbar.is-light .navbar-end .navbar-link:focus, + .navbar.is-light .navbar-start > a.navbar-item:hover, + .navbar.is-light .navbar-end > a.navbar-item:hover, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-start > a.navbar-item.is-active, + .navbar.is-light .navbar-end > a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); + } +} +.navbar.is-dark { + background-color: #363636; + color: #fff; +} +.navbar.is-dark .navbar-brand > .navbar-item, +.navbar.is-dark .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-dark .navbar-brand > a.navbar-item:focus, +.navbar.is-dark .navbar-brand .navbar-link:focus, +.navbar.is-dark .navbar-brand > a.navbar-item:hover, +.navbar.is-dark .navbar-brand .navbar-link:hover, +.navbar.is-dark .navbar-brand > a.navbar-item.is-active, +.navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: #fff; +} +.navbar.is-dark .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-dark .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-dark .navbar-start > .navbar-item, + .navbar.is-dark .navbar-end > .navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-dark .navbar-start > a.navbar-item:focus, + .navbar.is-dark .navbar-end > a.navbar-item:focus, + .navbar.is-dark .navbar-start .navbar-link:focus, + .navbar.is-dark .navbar-end .navbar-link:focus, + .navbar.is-dark .navbar-start > a.navbar-item:hover, + .navbar.is-dark .navbar-end > a.navbar-item:hover, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-start > a.navbar-item.is-active, + .navbar.is-dark .navbar-end > a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: #fff; + } +} +.navbar.is-primary { + background-color: #fcee09; + color: #121617; +} +.navbar.is-primary .navbar-brand > .navbar-item, +.navbar.is-primary .navbar-brand .navbar-link { + color: #121617; +} +.navbar.is-primary .navbar-brand > a.navbar-item:focus, +.navbar.is-primary .navbar-brand .navbar-link:focus, +.navbar.is-primary .navbar-brand > a.navbar-item:hover, +.navbar.is-primary .navbar-brand .navbar-link:hover, +.navbar.is-primary .navbar-brand > a.navbar-item.is-active, +.navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #e9db03; + color: #121617; +} +.navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #121617; +} +.navbar.is-primary .navbar-burger { + color: #121617; +} +@media screen and (min-width: 1088px) { + .navbar.is-primary .navbar-start > .navbar-item, + .navbar.is-primary .navbar-end > .navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end .navbar-link { + color: #121617; + } + .navbar.is-primary .navbar-start > a.navbar-item:focus, + .navbar.is-primary .navbar-end > a.navbar-item:focus, + .navbar.is-primary .navbar-start .navbar-link:focus, + .navbar.is-primary .navbar-end .navbar-link:focus, + .navbar.is-primary .navbar-start > a.navbar-item:hover, + .navbar.is-primary .navbar-end > a.navbar-item:hover, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-start > a.navbar-item.is-active, + .navbar.is-primary .navbar-end > a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #e9db03; + color: #121617; + } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #121617; + } + .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e9db03; + color: #121617; + } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #fcee09; + color: #121617; + } +} +.navbar.is-link { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.navbar.is-link .navbar-brand > .navbar-item, +.navbar.is-link .navbar-brand .navbar-link { + color: rgba(0,0,0,0.7); +} +.navbar.is-link .navbar-brand > a.navbar-item:focus, +.navbar.is-link .navbar-brand .navbar-link:focus, +.navbar.is-link .navbar-brand > a.navbar-item:hover, +.navbar.is-link .navbar-brand .navbar-link:hover, +.navbar.is-link .navbar-brand > a.navbar-item.is-active, +.navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #02c1d9; + color: rgba(0,0,0,0.7); +} +.navbar.is-link .navbar-brand .navbar-link::after { + border-color: rgba(0,0,0,0.7); +} +.navbar.is-link .navbar-burger { + color: rgba(0,0,0,0.7); +} +@media screen and (min-width: 1088px) { + .navbar.is-link .navbar-start > .navbar-item, + .navbar.is-link .navbar-end > .navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end .navbar-link { + color: rgba(0,0,0,0.7); + } + .navbar.is-link .navbar-start > a.navbar-item:focus, + .navbar.is-link .navbar-end > a.navbar-item:focus, + .navbar.is-link .navbar-start .navbar-link:focus, + .navbar.is-link .navbar-end .navbar-link:focus, + .navbar.is-link .navbar-start > a.navbar-item:hover, + .navbar.is-link .navbar-end > a.navbar-item:hover, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-start > a.navbar-item.is-active, + .navbar.is-link .navbar-end > a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #02c1d9; + color: rgba(0,0,0,0.7); + } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: rgba(0,0,0,0.7); + } + .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #02c1d9; + color: rgba(0,0,0,0.7); + } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); + } +} +.navbar.is-info { + background-color: #02d7f2; + color: #121617; +} +.navbar.is-info .navbar-brand > .navbar-item, +.navbar.is-info .navbar-brand .navbar-link { + color: #121617; +} +.navbar.is-info .navbar-brand > a.navbar-item:focus, +.navbar.is-info .navbar-brand .navbar-link:focus, +.navbar.is-info .navbar-brand > a.navbar-item:hover, +.navbar.is-info .navbar-brand .navbar-link:hover, +.navbar.is-info .navbar-brand > a.navbar-item.is-active, +.navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #02c1d9; + color: #121617; +} +.navbar.is-info .navbar-brand .navbar-link::after { + border-color: #121617; +} +.navbar.is-info .navbar-burger { + color: #121617; +} +@media screen and (min-width: 1088px) { + .navbar.is-info .navbar-start > .navbar-item, + .navbar.is-info .navbar-end > .navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end .navbar-link { + color: #121617; + } + .navbar.is-info .navbar-start > a.navbar-item:focus, + .navbar.is-info .navbar-end > a.navbar-item:focus, + .navbar.is-info .navbar-start .navbar-link:focus, + .navbar.is-info .navbar-end .navbar-link:focus, + .navbar.is-info .navbar-start > a.navbar-item:hover, + .navbar.is-info .navbar-end > a.navbar-item:hover, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-start > a.navbar-item.is-active, + .navbar.is-info .navbar-end > a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #02c1d9; + color: #121617; + } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #121617; + } + .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #02c1d9; + color: #121617; + } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #02d7f2; + color: #121617; + } +} +.navbar.is-success { + background-color: #00ff41; + color: #121617; +} +.navbar.is-success .navbar-brand > .navbar-item, +.navbar.is-success .navbar-brand .navbar-link { + color: #121617; +} +.navbar.is-success .navbar-brand > a.navbar-item:focus, +.navbar.is-success .navbar-brand .navbar-link:focus, +.navbar.is-success .navbar-brand > a.navbar-item:hover, +.navbar.is-success .navbar-brand .navbar-link:hover, +.navbar.is-success .navbar-brand > a.navbar-item.is-active, +.navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #00e63a; + color: #121617; +} +.navbar.is-success .navbar-brand .navbar-link::after { + border-color: #121617; +} +.navbar.is-success .navbar-burger { + color: #121617; +} +@media screen and (min-width: 1088px) { + .navbar.is-success .navbar-start > .navbar-item, + .navbar.is-success .navbar-end > .navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end .navbar-link { + color: #121617; + } + .navbar.is-success .navbar-start > a.navbar-item:focus, + .navbar.is-success .navbar-end > a.navbar-item:focus, + .navbar.is-success .navbar-start .navbar-link:focus, + .navbar.is-success .navbar-end .navbar-link:focus, + .navbar.is-success .navbar-start > a.navbar-item:hover, + .navbar.is-success .navbar-end > a.navbar-item:hover, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-start > a.navbar-item.is-active, + .navbar.is-success .navbar-end > a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #00e63a; + color: #121617; + } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #121617; + } + .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #00e63a; + color: #121617; + } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #00ff41; + color: #121617; + } +} +.navbar.is-warning { + background-color: #ff8e3c; + color: #121617; +} +.navbar.is-warning .navbar-brand > .navbar-item, +.navbar.is-warning .navbar-brand .navbar-link { + color: #121617; +} +.navbar.is-warning .navbar-brand > a.navbar-item:focus, +.navbar.is-warning .navbar-brand .navbar-link:focus, +.navbar.is-warning .navbar-brand > a.navbar-item:hover, +.navbar.is-warning .navbar-brand .navbar-link:hover, +.navbar.is-warning .navbar-brand > a.navbar-item.is-active, +.navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ff7f22; + color: #121617; +} +.navbar.is-warning .navbar-brand .navbar-link::after { + border-color: #121617; +} +.navbar.is-warning .navbar-burger { + color: #121617; +} +@media screen and (min-width: 1088px) { + .navbar.is-warning .navbar-start > .navbar-item, + .navbar.is-warning .navbar-end > .navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end .navbar-link { + color: #121617; + } + .navbar.is-warning .navbar-start > a.navbar-item:focus, + .navbar.is-warning .navbar-end > a.navbar-item:focus, + .navbar.is-warning .navbar-start .navbar-link:focus, + .navbar.is-warning .navbar-end .navbar-link:focus, + .navbar.is-warning .navbar-start > a.navbar-item:hover, + .navbar.is-warning .navbar-end > a.navbar-item:hover, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-start > a.navbar-item.is-active, + .navbar.is-warning .navbar-end > a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ff7f22; + color: #121617; + } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: #121617; + } + .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ff7f22; + color: #121617; + } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ff8e3c; + color: #121617; + } +} +.navbar.is-danger { + background-color: #ff003c; + color: #121617; +} +.navbar.is-danger .navbar-brand > .navbar-item, +.navbar.is-danger .navbar-brand .navbar-link { + color: #121617; +} +.navbar.is-danger .navbar-brand > a.navbar-item:focus, +.navbar.is-danger .navbar-brand .navbar-link:focus, +.navbar.is-danger .navbar-brand > a.navbar-item:hover, +.navbar.is-danger .navbar-brand .navbar-link:hover, +.navbar.is-danger .navbar-brand > a.navbar-item.is-active, +.navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #e60036; + color: #121617; +} +.navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #121617; +} +.navbar.is-danger .navbar-burger { + color: #121617; +} +@media screen and (min-width: 1088px) { + .navbar.is-danger .navbar-start > .navbar-item, + .navbar.is-danger .navbar-end > .navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end .navbar-link { + color: #121617; + } + .navbar.is-danger .navbar-start > a.navbar-item:focus, + .navbar.is-danger .navbar-end > a.navbar-item:focus, + .navbar.is-danger .navbar-start .navbar-link:focus, + .navbar.is-danger .navbar-end .navbar-link:focus, + .navbar.is-danger .navbar-start > a.navbar-item:hover, + .navbar.is-danger .navbar-end > a.navbar-item:hover, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-start > a.navbar-item.is-active, + .navbar.is-danger .navbar-end > a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #e60036; + color: #121617; + } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #121617; + } + .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e60036; + color: #121617; + } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #ff003c; + color: #121617; + } +} +.navbar.is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.navbar.is-grey-lightest .navbar-brand > .navbar-item, +.navbar.is-grey-lightest .navbar-brand .navbar-link { + color: #363636; +} +.navbar.is-grey-lightest .navbar-brand > a.navbar-item:focus, +.navbar.is-grey-lightest .navbar-brand .navbar-link:focus, +.navbar.is-grey-lightest .navbar-brand > a.navbar-item:hover, +.navbar.is-grey-lightest .navbar-brand .navbar-link:hover, +.navbar.is-grey-lightest .navbar-brand > a.navbar-item.is-active, +.navbar.is-grey-lightest .navbar-brand .navbar-link.is-active { + background-color: #e0e0e0; + color: #363636; +} +.navbar.is-grey-lightest .navbar-brand .navbar-link::after { + border-color: #363636; +} +.navbar.is-grey-lightest .navbar-burger { + color: #363636; +} +@media screen and (min-width: 1088px) { + .navbar.is-grey-lightest .navbar-start > .navbar-item, + .navbar.is-grey-lightest .navbar-end > .navbar-item, + .navbar.is-grey-lightest .navbar-start .navbar-link, + .navbar.is-grey-lightest .navbar-end .navbar-link { + color: #363636; + } + .navbar.is-grey-lightest .navbar-start > a.navbar-item:focus, + .navbar.is-grey-lightest .navbar-end > a.navbar-item:focus, + .navbar.is-grey-lightest .navbar-start .navbar-link:focus, + .navbar.is-grey-lightest .navbar-end .navbar-link:focus, + .navbar.is-grey-lightest .navbar-start > a.navbar-item:hover, + .navbar.is-grey-lightest .navbar-end > a.navbar-item:hover, + .navbar.is-grey-lightest .navbar-start .navbar-link:hover, + .navbar.is-grey-lightest .navbar-end .navbar-link:hover, + .navbar.is-grey-lightest .navbar-start > a.navbar-item.is-active, + .navbar.is-grey-lightest .navbar-end > a.navbar-item.is-active, + .navbar.is-grey-lightest .navbar-start .navbar-link.is-active, + .navbar.is-grey-lightest .navbar-end .navbar-link.is-active { + background-color: #e0e0e0; + color: #363636; + } + .navbar.is-grey-lightest .navbar-start .navbar-link::after, + .navbar.is-grey-lightest .navbar-end .navbar-link::after { + border-color: #363636; + } + .navbar.is-grey-lightest .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-grey-lightest .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-grey-lightest .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e0e0e0; + color: #363636; + } + .navbar.is-grey-lightest .navbar-dropdown a.navbar-item.is-active { + background-color: #ededed; + color: #363636; + } +} +.navbar > .container { + align-items: stretch; + display: flex; + min-height: 3.25rem; + width: 100%; +} +.navbar.has-shadow { + box-shadow: 0 2px 0 0 #f5f5f5; +} +.navbar.is-fixed-bottom, +.navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; +} +.navbar.is-fixed-bottom { + bottom: 0; +} +.navbar.is-fixed-bottom.has-shadow { + box-shadow: 0 -2px 0 0 #f5f5f5; +} +.navbar.is-fixed-top { + top: 0; +} +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: 3.25rem; +} +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; +} +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: 3.25rem; +} +.navbar-brand a.navbar-item:focus, +.navbar-brand a.navbar-item:hover { + background-color: transparent; +} +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; +} +.navbar-burger { + color: #000; + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; +} +.navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + transform-origin: center; + transition-duration: 86ms; + transition-property: background-color, opacity, transform; + transition-timing-function: ease-out; + width: 16px; +} +.navbar-burger span:nth-child(1) { + top: calc(50% - 6px); +} +.navbar-burger span:nth-child(2) { + top: calc(50% - 1px); +} +.navbar-burger span:nth-child(3) { + top: calc(50% + 4px); +} +.navbar-burger:hover { + background-color: rgba(0,0,0,0.05); +} +.navbar-burger.is-active span:nth-child(1) { + transform: translateY(5px) rotate(45deg); +} +.navbar-burger.is-active span:nth-child(2) { + opacity: 0; +} +.navbar-burger.is-active span:nth-child(3) { + transform: translateY(-5px) rotate(-45deg); +} +.navbar-menu { + display: none; +} +.navbar-item, +.navbar-link { + color: #000; + display: block; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; +} +.navbar-item .icon:only-child, +.navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; +} +a.navbar-item, +.navbar-link { + cursor: pointer; +} +a.navbar-item:focus, +.navbar-link:focus, +a.navbar-item:focus-within, +.navbar-link:focus-within, +a.navbar-item:hover, +.navbar-link:hover, +a.navbar-item.is-active, +.navbar-link.is-active { + background-color: transparent; + color: #000; +} +.navbar-item { + display: block; + flex-grow: 0; + flex-shrink: 0; +} +.navbar-item img { + max-height: 1.75rem; +} +.navbar-item.has-dropdown { + padding: 0; +} +.navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); +} +.navbar-item.is-tab:focus, +.navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #02d7f2; +} +.navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #02d7f2; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #02d7f2; + padding-bottom: calc(0.5rem - 3px); +} +.navbar-content { + flex-grow: 1; + flex-shrink: 1; +} +.navbar-link:not(.is-arrowless) { + padding-right: 2.5em; +} +.navbar-link:not(.is-arrowless)::after { + border-color: #02d7f2; + margin-top: -0.375em; + right: 1.125em; +} +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} +.navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.navbar-divider { + background-color: #f5f5f5; + border: none; + display: none; + height: 2px; + margin: 0.5rem 0; +} +@media screen and (max-width: 1087px) { + .navbar > .container { + display: block; + } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; + } + .navbar-link::after { + display: none; + } + .navbar-menu { + background-color: #fcee09; + box-shadow: 0 8px 16px rgba(0,0,0,0.1); + padding: 0.5rem 0; + } + .navbar-menu.is-active { + display: block; + } + .navbar.is-fixed-bottom-touch, + .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-touch { + bottom: 0; + } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -2px 3px rgba(0,0,0,0.1); + } + .navbar.is-fixed-top-touch { + top: 0; + } + .navbar.is-fixed-top .navbar-menu, + .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; + } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; + } +} +@media screen and (min-width: 1088px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; + } + .navbar { + min-height: 3.25rem; + } + .navbar.is-spaced { + padding: 1rem 2rem; + } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; + } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: 0; + } + .navbar.is-transparent a.navbar-item:focus, + .navbar.is-transparent .navbar-link:focus, + .navbar.is-transparent a.navbar-item:hover, + .navbar.is-transparent .navbar-link:hover, + .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent .navbar-link.is-active { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, + .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link, + .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link, + .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item:focus, + .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: #f5f5f5; + color: #000; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: #f5f5f5; + color: #02d7f2; + } + .navbar-burger { + display: none; + } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; + } + .navbar-item { + display: flex; + } + .navbar-item.has-dropdown { + align-items: stretch; + } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); + } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 2px solid #dbdbdb; + border-radius: 6px 6px 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -8px 8px rgba(0,0,0,0.1); + top: auto; + } + .navbar-item.is-active .navbar-dropdown, + .navbar-item.is-hoverable:focus .navbar-dropdown, + .navbar-item.is-hoverable:focus-within .navbar-dropdown, + .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; + } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, + .navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown, + .navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown, + .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, + .navbar-item.is-active .navbar-dropdown.is-boxed, + .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed, + .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed, + .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; + } + .navbar-start { + justify-content: flex-start; + margin-right: auto; + } + .navbar-end { + justify-content: flex-end; + margin-left: auto; + } + .navbar-dropdown { + background-color: #000; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 2px solid #dbdbdb; + box-shadow: 0 8px 8px rgba(0,0,0,0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; + } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; + } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; + } + .navbar-dropdown a.navbar-item:focus, + .navbar-dropdown a.navbar-item:hover { + background-color: #f5f5f5; + color: #000; + } + .navbar-dropdown a.navbar-item.is-active { + background-color: #f5f5f5; + color: #02d7f2; + } + .navbar.is-spaced .navbar-dropdown, + .navbar-dropdown.is-boxed { + border-radius: 6px; + border-top: none; + box-shadow: 0 8px 8px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + -4px); + transform: translateY(-5px); + transition-duration: 86ms; + transition-property: opacity, transform; + } + .navbar-dropdown.is-right { + left: auto; + right: 0; + } + .navbar-divider { + display: block; + } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: -0.75rem; + } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: -0.75rem; + } + .navbar.is-fixed-bottom-desktop, + .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-desktop { + bottom: 0; + } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -2px 3px rgba(0,0,0,0.1); + } + .navbar.is-fixed-top-desktop { + top: 0; + } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; + } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: 5.25rem; + } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: 5.25rem; + } + a.navbar-item.is-active, + .navbar-link.is-active { + color: #000; + } + a.navbar-item.is-active:not(:focus):not(:hover), + .navbar-link.is-active:not(:focus):not(:hover) { + background-color: transparent; + } + .navbar-item.has-dropdown:focus .navbar-link, + .navbar-item.has-dropdown:hover .navbar-link, + .navbar-item.has-dropdown.is-active .navbar-link { + background-color: transparent; + } +} +.hero.is-fullheight-with-navbar { + min-height: calc(100vh - 3.25rem); +} +.pagination { + font-size: 1rem; + margin: -0.25rem; +} +.pagination.is-small { + font-size: 0.75rem; +} +.pagination.is-medium { + font-size: 1.25rem; +} +.pagination.is-large { + font-size: 1.5rem; +} +.pagination.is-rounded .pagination-previous, +.pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 290486px; +} +.pagination.is-rounded .pagination-link { + border-radius: 290486px; +} +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; +} +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + font-size: 1em; + justify-content: center; + margin: 0.25rem; + padding-left: 0.5em; + padding-right: 0.5em; + text-align: center; +} +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #fcee09; + min-width: 2.25em; +} +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover { + border-color: #b5b5b5; + color: #fcee09; +} +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus { + border-color: #02d7f2; +} +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active { + box-shadow: inset 0 1px 2px rgba(0,0,0,0.2); +} +.pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled] { + background-color: #dbdbdb; + border-color: #dbdbdb; + box-shadow: none; + color: #848484; + opacity: 0.5; +} +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} +.pagination-link.is-current { + background-color: #02d7f2; + border-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; +} +.pagination-list { + flex-wrap: wrap; +} +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; + } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; + } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; + } +} +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; + } + .pagination-previous { + order: 2; + } + .pagination-next { + order: 3; + } + .pagination { + justify-content: space-between; + } + .pagination.is-centered .pagination-previous, + .pagination .pagination-previous { + order: 1; + } + .pagination.is-centered .pagination-list, + .pagination .pagination-list { + justify-content: center; + order: 2; + } + .pagination.is-centered .pagination-next, + .pagination .pagination-next { + order: 3; + } + .pagination.is-right .pagination-previous { + order: 1; + } + .pagination.is-right .pagination-next { + order: 2; + } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; + } +} +.panel { + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(0,0,0,0.1), 0 0px 0 1px rgba(0,0,0,0.02); + font-size: 1rem; +} +.panel:not(:last-child) { + margin-bottom: 1.5rem; +} +.panel.is-white .panel-heading { + background-color: #fff; + color: #000; +} +.panel.is-white .panel-tabs a.is-active { + border-bottom-color: #fff; +} +.panel.is-white .panel-block.is-active .panel-icon { + color: #fff; +} +.panel.is-black .panel-heading { + background-color: #000; + color: #fff; +} +.panel.is-black .panel-tabs a.is-active { + border-bottom-color: #000; +} +.panel.is-black .panel-block.is-active .panel-icon { + color: #000; +} +.panel.is-light .panel-heading { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.panel.is-light .panel-tabs a.is-active { + border-bottom-color: #f5f5f5; +} +.panel.is-light .panel-block.is-active .panel-icon { + color: #f5f5f5; +} +.panel.is-dark .panel-heading { + background-color: #363636; + color: #fff; +} +.panel.is-dark .panel-tabs a.is-active { + border-bottom-color: #363636; +} +.panel.is-dark .panel-block.is-active .panel-icon { + color: #363636; +} +.panel.is-primary .panel-heading { + background-color: #fcee09; + color: #121617; +} +.panel.is-primary .panel-tabs a.is-active { + border-bottom-color: #fcee09; +} +.panel.is-primary .panel-block.is-active .panel-icon { + color: #fcee09; +} +.panel.is-link .panel-heading { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.panel.is-link .panel-tabs a.is-active { + border-bottom-color: #02d7f2; +} +.panel.is-link .panel-block.is-active .panel-icon { + color: #02d7f2; +} +.panel.is-info .panel-heading { + background-color: #02d7f2; + color: #121617; +} +.panel.is-info .panel-tabs a.is-active { + border-bottom-color: #02d7f2; +} +.panel.is-info .panel-block.is-active .panel-icon { + color: #02d7f2; +} +.panel.is-success .panel-heading { + background-color: #00ff41; + color: #121617; +} +.panel.is-success .panel-tabs a.is-active { + border-bottom-color: #00ff41; +} +.panel.is-success .panel-block.is-active .panel-icon { + color: #00ff41; +} +.panel.is-warning .panel-heading { + background-color: #ff8e3c; + color: #121617; +} +.panel.is-warning .panel-tabs a.is-active { + border-bottom-color: #ff8e3c; +} +.panel.is-warning .panel-block.is-active .panel-icon { + color: #ff8e3c; +} +.panel.is-danger .panel-heading { + background-color: #ff003c; + color: #121617; +} +.panel.is-danger .panel-tabs a.is-active { + border-bottom-color: #ff003c; +} +.panel.is-danger .panel-block.is-active .panel-icon { + color: #ff003c; +} +.panel.is-grey-lightest .panel-heading { + background-color: #ededed; + color: #363636; +} +.panel.is-grey-lightest .panel-tabs a.is-active { + border-bottom-color: #ededed; +} +.panel.is-grey-lightest .panel-block.is-active .panel-icon { + color: #ededed; +} +.panel-tabs:not(:last-child), +.panel-block:not(:last-child) { + border-bottom: 1px solid #ededed; +} +.panel-heading { + background-color: #ededed; + border-radius: 6px 6px 0 0; + color: #fcee09; + font-size: 1.25em; + font-weight: 700; + line-height: 1.25; + padding: 0.75em 1em; +} +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: 0.875em; + justify-content: center; +} +.panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; +} +.panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; +} +.panel-list a { + color: #cdcdcd; +} +.panel-list a:hover { + color: #02d7f2; +} +.panel-block { + align-items: center; + color: #fcee09; + display: flex; + justify-content: flex-start; + padding: 0.5em 0.75em; +} +.panel-block input[type="checkbox"] { + margin-right: 0.75em; +} +.panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; +} +.panel-block.is-wrapped { + flex-wrap: wrap; +} +.panel-block.is-active { + border-left-color: #02d7f2; + color: #363636; +} +.panel-block.is-active .panel-icon { + color: #02d7f2; +} +.panel-block:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; +} +a.panel-block, +label.panel-block { + cursor: pointer; +} +a.panel-block:hover, +label.panel-block:hover { + background-color: #f5f5f5; +} +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #848484; + margin-right: 0.75em; +} +.panel-icon .fa { + font-size: inherit; + line-height: inherit; +} +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: 1rem; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; +} +.tabs a { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #cdcdcd; + display: flex; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; +} +.tabs a:hover { + border-bottom-color: #fcee09; + color: #fcee09; +} +.tabs li { + display: block; +} +.tabs li.is-active a { + border-bottom-color: #02d7f2; + color: #02d7f2; +} +.tabs ul { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; +} +.tabs ul.is-left { + padding-right: 0.75em; +} +.tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; +} +.tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; +} +.tabs .icon:first-child { + margin-right: 0.5em; +} +.tabs .icon:last-child { + margin-left: 0.5em; +} +.tabs.is-centered ul { + justify-content: center; +} +.tabs.is-right ul { + justify-content: flex-end; +} +.tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 0 0 0 0; +} +.tabs.is-boxed a:hover { + background-color: #f5f5f5; + border-bottom-color: #dbdbdb; +} +.tabs.is-boxed li.is-active a { + background-color: #000; + border-color: #dbdbdb; + border-bottom-color: transparent !important; +} +.tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; +} +.tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; +} +.tabs.is-toggle a:hover { + background-color: #f5f5f5; + border-color: #b5b5b5; + z-index: 2; +} +.tabs.is-toggle li + li { + margin-left: -1px; +} +.tabs.is-toggle li:first-child a { + border-radius: 0 0 0 0; +} +.tabs.is-toggle li:last-child a { + border-radius: 0 0 0 0; +} +.tabs.is-toggle li.is-active a { + background-color: #02d7f2; + border-color: #02d7f2; + color: rgba(0,0,0,0.7); + z-index: 1; +} +.tabs.is-toggle ul { + border-bottom: none; +} +.tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 290486px; + border-top-left-radius: 290486px; + padding-left: 1.25em; +} +.tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 290486px; + border-top-right-radius: 290486px; + padding-right: 1.25em; +} +.tabs.is-small { + font-size: 0.75rem; +} +.tabs.is-medium { + font-size: 1.25rem; +} +.tabs.is-large { + font-size: 1.5rem; +} +.box { + background-color: #000; + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(0,0,0,0.1), 0 0px 0 1px rgba(0,0,0,0.02); + color: #cdcdcd; + display: block; + padding: 1.25rem; +} +a.box:hover, +a.box:focus { + box-shadow: 0 0.5em 1em -0.125em rgba(0,0,0,0.1), 0 0 0 1px #02d7f2; +} +a.box:active { + box-shadow: inset 0 1px 2px rgba(0,0,0,0.2), 0 0 0 1px #02d7f2; +} +.button { + background-color: #000; + border-color: #dbdbdb; + border-width: 1px; + color: #fcee09; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.375em - 1px); + padding-left: 1em; + padding-right: 1em; + padding-top: calc(0.375em - 1px); + text-align: center; + white-space: nowrap; +} +.button strong { + color: inherit; +} +.button .icon, +.button .icon.is-small, +.button .icon.is-medium, +.button .icon.is-large { + height: 1.5em; + width: 1.5em; +} +.button .icon:first-child:not(:last-child) { + margin-left: calc(-0.5em - 1px); + margin-right: 0.25em; +} +.button .icon:last-child:not(:first-child) { + margin-left: 0.25em; + margin-right: calc(-0.5em - 1px); +} +.button .icon:first-child:last-child { + margin-left: calc(-0.5em - 1px); + margin-right: calc(-0.5em - 1px); +} +.button:hover, +.button.is-hovered { + border-color: #b5b5b5; + color: #fcee09; +} +.button:focus, +.button.is-focused { + border-color: #02d7f2; + color: #363636; +} +.button:focus:not(:active), +.button.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.button:active, +.button.is-active { + border-color: #4a4a4a; + color: #363636; +} +.button.is-text { + background-color: transparent; + border-color: transparent; + color: #cdcdcd; + text-decoration: underline; +} +.button.is-text:hover, +.button.is-text.is-hovered, +.button.is-text:focus, +.button.is-text.is-focused { + background-color: #f5f5f5; + color: #fcee09; +} +.button.is-text:active, +.button.is-text.is-active { + background-color: #e8e8e8; + color: #fcee09; +} +.button.is-text[disabled], +fieldset[disabled] .button.is-text { + background-color: transparent; + border-color: transparent; + box-shadow: none; +} +.button.is-white { + background-color: #fff; + border-color: transparent; + color: #000; +} +.button.is-white:hover, +.button.is-white.is-hovered { + background-color: #f9f9f9; + border-color: transparent; + color: #000; +} +.button.is-white:focus, +.button.is-white.is-focused { + border-color: transparent; + color: #000; +} +.button.is-white:focus:not(:active), +.button.is-white.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,255,255,0.25); +} +.button.is-white:active, +.button.is-white.is-active { + background-color: #f2f2f2; + border-color: transparent; + color: #000; +} +.button.is-white[disabled], +fieldset[disabled] .button.is-white { + background-color: #fff; + border-color: transparent; + box-shadow: none; +} +.button.is-white.is-inverted { + background-color: #000; + color: #fff; +} +.button.is-white.is-inverted:hover, +.button.is-white.is-inverted.is-hovered { + background-color: #000; +} +.button.is-white.is-inverted[disabled], +fieldset[disabled] .button.is-white.is-inverted { + background-color: #000; + border-color: transparent; + box-shadow: none; + color: #fff; +} +.button.is-white.is-loading::after { + border-color: transparent transparent #000 #000 !important; +} +.button.is-white.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-white.is-outlined:hover, +.button.is-white.is-outlined.is-hovered, +.button.is-white.is-outlined:focus, +.button.is-white.is-outlined.is-focused { + background-color: #fff; + border-color: #fff; + color: #000; +} +.button.is-white.is-outlined.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-white.is-outlined.is-loading:hover::after, +.button.is-white.is-outlined.is-loading.is-hovered::after, +.button.is-white.is-outlined.is-loading:focus::after, +.button.is-white.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #000 #000 !important; +} +.button.is-white.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #000; + color: #000; +} +.button.is-white.is-inverted.is-outlined:hover, +.button.is-white.is-inverted.is-outlined.is-hovered, +.button.is-white.is-inverted.is-outlined:focus, +.button.is-white.is-inverted.is-outlined.is-focused { + background-color: #000; + color: #fff; +} +.button.is-white.is-inverted.is-outlined.is-loading:hover::after, +.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-white.is-inverted.is-outlined.is-loading:focus::after, +.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-white.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #000; + box-shadow: none; + color: #000; +} +.button.is-black { + background-color: #000; + border-color: transparent; + color: #fff; +} +.button.is-black:hover, +.button.is-black.is-hovered { + background-color: #000; + border-color: transparent; + color: #fff; +} +.button.is-black:focus, +.button.is-black.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-black:focus:not(:active), +.button.is-black.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0,0,0,0.25); +} +.button.is-black:active, +.button.is-black.is-active { + background-color: #000; + border-color: transparent; + color: #fff; +} +.button.is-black[disabled], +fieldset[disabled] .button.is-black { + background-color: #000; + border-color: transparent; + box-shadow: none; +} +.button.is-black.is-inverted { + background-color: #fff; + color: #000; +} +.button.is-black.is-inverted:hover, +.button.is-black.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-black.is-inverted[disabled], +fieldset[disabled] .button.is-black.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #000; +} +.button.is-black.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-black.is-outlined { + background-color: transparent; + border-color: #000; + color: #000; +} +.button.is-black.is-outlined:hover, +.button.is-black.is-outlined.is-hovered, +.button.is-black.is-outlined:focus, +.button.is-black.is-outlined.is-focused { + background-color: #000; + border-color: #000; + color: #fff; +} +.button.is-black.is-outlined.is-loading::after { + border-color: transparent transparent #000 #000 !important; +} +.button.is-black.is-outlined.is-loading:hover::after, +.button.is-black.is-outlined.is-loading.is-hovered::after, +.button.is-black.is-outlined.is-loading:focus::after, +.button.is-black.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-black.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-outlined { + background-color: transparent; + border-color: #000; + box-shadow: none; + color: #000; +} +.button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-black.is-inverted.is-outlined:hover, +.button.is-black.is-inverted.is-outlined.is-hovered, +.button.is-black.is-inverted.is-outlined:focus, +.button.is-black.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #000; +} +.button.is-black.is-inverted.is-outlined.is-loading:hover::after, +.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-black.is-inverted.is-outlined.is-loading:focus::after, +.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #000 #000 !important; +} +.button.is-black.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-light, +article.article .article-more { + background-color: #f5f5f5; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light:hover, +article.article .article-more:hover, +.button.is-light.is-hovered, +article.article .article-more.is-hovered { + background-color: #eee; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light:focus, +article.article .article-more:focus, +.button.is-light.is-focused, +article.article .article-more.is-focused { + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light:focus:not(:active), +article.article .article-more:focus:not(:active), +.button.is-light.is-focused:not(:active), +article.article .article-more.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(245,245,245,0.25); +} +.button.is-light:active, +article.article .article-more:active, +.button.is-light.is-active, +article.article .article-more.is-active { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light[disabled], +article.article .article-more[disabled], +fieldset[disabled] .button.is-light, +fieldset[disabled] article.article .article-more { + background-color: #f5f5f5; + border-color: transparent; + box-shadow: none; +} +.button.is-light.is-inverted, +article.article .article-more.is-inverted { + background-color: rgba(0,0,0,0.7); + color: #f5f5f5; +} +.button.is-light.is-inverted:hover, +article.article .article-more.is-inverted:hover, +.button.is-light.is-inverted.is-hovered, +article.article .article-more.is-inverted.is-hovered { + background-color: rgba(0,0,0,0.7); +} +.button.is-light.is-inverted[disabled], +article.article .article-more.is-inverted[disabled], +fieldset[disabled] .button.is-light.is-inverted, +fieldset[disabled] article.article .article-more.is-inverted { + background-color: rgba(0,0,0,0.7); + border-color: transparent; + box-shadow: none; + color: #f5f5f5; +} +.button.is-light.is-loading::after, +article.article .article-more.is-loading::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-light.is-outlined, +article.article .article-more.is-outlined { + background-color: transparent; + border-color: #f5f5f5; + color: #f5f5f5; +} +.button.is-light.is-outlined:hover, +article.article .article-more.is-outlined:hover, +.button.is-light.is-outlined.is-hovered, +article.article .article-more.is-outlined.is-hovered, +.button.is-light.is-outlined:focus, +article.article .article-more.is-outlined:focus, +.button.is-light.is-outlined.is-focused, +article.article .article-more.is-outlined.is-focused { + background-color: #f5f5f5; + border-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.button.is-light.is-outlined.is-loading::after, +article.article .article-more.is-outlined.is-loading::after { + border-color: transparent transparent #f5f5f5 #f5f5f5 !important; +} +.button.is-light.is-outlined.is-loading:hover::after, +article.article .article-more.is-outlined.is-loading:hover::after, +.button.is-light.is-outlined.is-loading.is-hovered::after, +article.article .article-more.is-outlined.is-loading.is-hovered::after, +.button.is-light.is-outlined.is-loading:focus::after, +article.article .article-more.is-outlined.is-loading:focus::after, +.button.is-light.is-outlined.is-loading.is-focused::after, +article.article .article-more.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-light.is-outlined[disabled], +article.article .article-more.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-outlined, +fieldset[disabled] article.article .article-more.is-outlined { + background-color: transparent; + border-color: #f5f5f5; + box-shadow: none; + color: #f5f5f5; +} +.button.is-light.is-inverted.is-outlined, +article.article .article-more.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + color: rgba(0,0,0,0.7); +} +.button.is-light.is-inverted.is-outlined:hover, +article.article .article-more.is-inverted.is-outlined:hover, +.button.is-light.is-inverted.is-outlined.is-hovered, +article.article .article-more.is-inverted.is-outlined.is-hovered, +.button.is-light.is-inverted.is-outlined:focus, +article.article .article-more.is-inverted.is-outlined:focus, +.button.is-light.is-inverted.is-outlined.is-focused, +article.article .article-more.is-inverted.is-outlined.is-focused { + background-color: rgba(0,0,0,0.7); + color: #f5f5f5; +} +.button.is-light.is-inverted.is-outlined.is-loading:hover::after, +article.article .article-more.is-inverted.is-outlined.is-loading:hover::after, +.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after, +article.article .article-more.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-light.is-inverted.is-outlined.is-loading:focus::after, +article.article .article-more.is-inverted.is-outlined.is-loading:focus::after, +.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after, +article.article .article-more.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #f5f5f5 #f5f5f5 !important; +} +.button.is-light.is-inverted.is-outlined[disabled], +article.article .article-more.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-inverted.is-outlined, +fieldset[disabled] article.article .article-more.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + box-shadow: none; + color: rgba(0,0,0,0.7); +} +.button.is-dark { + background-color: #363636; + border-color: transparent; + color: #fff; +} +.button.is-dark:hover, +.button.is-dark.is-hovered { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} +.button.is-dark:focus, +.button.is-dark.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-dark:focus:not(:active), +.button.is-dark.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(54,54,54,0.25); +} +.button.is-dark:active, +.button.is-dark.is-active { + background-color: #292929; + border-color: transparent; + color: #fff; +} +.button.is-dark[disabled], +fieldset[disabled] .button.is-dark { + background-color: #363636; + border-color: transparent; + box-shadow: none; +} +.button.is-dark.is-inverted { + background-color: #fff; + color: #363636; +} +.button.is-dark.is-inverted:hover, +.button.is-dark.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-dark.is-inverted[disabled], +fieldset[disabled] .button.is-dark.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #363636; +} +.button.is-dark.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; +} +.button.is-dark.is-outlined:hover, +.button.is-dark.is-outlined.is-hovered, +.button.is-dark.is-outlined:focus, +.button.is-dark.is-outlined.is-focused { + background-color: #363636; + border-color: #363636; + color: #fff; +} +.button.is-dark.is-outlined.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-dark.is-outlined.is-loading:hover::after, +.button.is-dark.is-outlined.is-loading.is-hovered::after, +.button.is-dark.is-outlined.is-loading:focus::after, +.button.is-dark.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-dark.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; +} +.button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-dark.is-inverted.is-outlined:hover, +.button.is-dark.is-inverted.is-outlined.is-hovered, +.button.is-dark.is-inverted.is-outlined:focus, +.button.is-dark.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #363636; +} +.button.is-dark.is-inverted.is-outlined.is-loading:hover::after, +.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-dark.is-inverted.is-outlined.is-loading:focus::after, +.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-dark.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-primary { + background-color: #fcee09; + border-color: transparent; + color: #121617; +} +.button.is-primary:hover, +.button.is-primary.is-hovered { + background-color: #f5e703; + border-color: transparent; + color: #121617; +} +.button.is-primary:focus, +.button.is-primary.is-focused { + border-color: transparent; + color: #121617; +} +.button.is-primary:focus:not(:active), +.button.is-primary.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(252,238,9,0.25); +} +.button.is-primary:active, +.button.is-primary.is-active { + background-color: #e9db03; + border-color: transparent; + color: #121617; +} +.button.is-primary[disabled], +fieldset[disabled] .button.is-primary { + background-color: #fcee09; + border-color: transparent; + box-shadow: none; +} +.button.is-primary.is-inverted { + background-color: #121617; + color: #fcee09; +} +.button.is-primary.is-inverted:hover, +.button.is-primary.is-inverted.is-hovered { + background-color: #070809; +} +.button.is-primary.is-inverted[disabled], +fieldset[disabled] .button.is-primary.is-inverted { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #fcee09; +} +.button.is-primary.is-loading::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-primary.is-outlined { + background-color: transparent; + border-color: #fcee09; + color: #fcee09; +} +.button.is-primary.is-outlined:hover, +.button.is-primary.is-outlined.is-hovered, +.button.is-primary.is-outlined:focus, +.button.is-primary.is-outlined.is-focused { + background-color: #fcee09; + border-color: #fcee09; + color: #121617; +} +.button.is-primary.is-outlined.is-loading::after { + border-color: transparent transparent #fcee09 #fcee09 !important; +} +.button.is-primary.is-outlined.is-loading:hover::after, +.button.is-primary.is-outlined.is-loading.is-hovered::after, +.button.is-primary.is-outlined.is-loading:focus::after, +.button.is-primary.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-primary.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-outlined { + background-color: transparent; + border-color: #fcee09; + box-shadow: none; + color: #fcee09; +} +.button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + color: #121617; +} +.button.is-primary.is-inverted.is-outlined:hover, +.button.is-primary.is-inverted.is-outlined.is-hovered, +.button.is-primary.is-inverted.is-outlined:focus, +.button.is-primary.is-inverted.is-outlined.is-focused { + background-color: #121617; + color: #fcee09; +} +.button.is-primary.is-inverted.is-outlined.is-loading:hover::after, +.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-primary.is-inverted.is-outlined.is-loading:focus::after, +.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fcee09 #fcee09 !important; +} +.button.is-primary.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + box-shadow: none; + color: #121617; +} +.button.is-primary.is-light { + background-color: #fffeeb; + color: #928a02; +} +.button.is-primary.is-light:hover, +.button.is-primary.is-light.is-hovered { + background-color: #fffdde; + border-color: transparent; + color: #928a02; +} +.button.is-primary.is-light:active, +.button.is-primary.is-light.is-active { + background-color: #fefcd2; + border-color: transparent; + color: #928a02; +} +.button.is-link { + background-color: #02d7f2; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-link:hover, +.button.is-link.is-hovered { + background-color: #02cce5; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-link:focus, +.button.is-link.is-focused { + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-link:focus:not(:active), +.button.is-link.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.button.is-link:active, +.button.is-link.is-active { + background-color: #02c1d9; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-link[disabled], +fieldset[disabled] .button.is-link { + background-color: #02d7f2; + border-color: transparent; + box-shadow: none; +} +.button.is-link.is-inverted { + background-color: rgba(0,0,0,0.7); + color: #02d7f2; +} +.button.is-link.is-inverted:hover, +.button.is-link.is-inverted.is-hovered { + background-color: rgba(0,0,0,0.7); +} +.button.is-link.is-inverted[disabled], +fieldset[disabled] .button.is-link.is-inverted { + background-color: rgba(0,0,0,0.7); + border-color: transparent; + box-shadow: none; + color: #02d7f2; +} +.button.is-link.is-loading::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-link.is-outlined { + background-color: transparent; + border-color: #02d7f2; + color: #02d7f2; +} +.button.is-link.is-outlined:hover, +.button.is-link.is-outlined.is-hovered, +.button.is-link.is-outlined:focus, +.button.is-link.is-outlined.is-focused { + background-color: #02d7f2; + border-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.button.is-link.is-outlined.is-loading::after { + border-color: transparent transparent #02d7f2 #02d7f2 !important; +} +.button.is-link.is-outlined.is-loading:hover::after, +.button.is-link.is-outlined.is-loading.is-hovered::after, +.button.is-link.is-outlined.is-loading:focus::after, +.button.is-link.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-link.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-outlined { + background-color: transparent; + border-color: #02d7f2; + box-shadow: none; + color: #02d7f2; +} +.button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + color: rgba(0,0,0,0.7); +} +.button.is-link.is-inverted.is-outlined:hover, +.button.is-link.is-inverted.is-outlined.is-hovered, +.button.is-link.is-inverted.is-outlined:focus, +.button.is-link.is-inverted.is-outlined.is-focused { + background-color: rgba(0,0,0,0.7); + color: #02d7f2; +} +.button.is-link.is-inverted.is-outlined.is-loading:hover::after, +.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-link.is-inverted.is-outlined.is-loading:focus::after, +.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #02d7f2 #02d7f2 !important; +} +.button.is-link.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + box-shadow: none; + color: rgba(0,0,0,0.7); +} +.button.is-link.is-light { + background-color: #ebfdff; + color: #018293; +} +.button.is-link.is-light:hover, +.button.is-link.is-light.is-hovered { + background-color: #defbff; + border-color: transparent; + color: #018293; +} +.button.is-link.is-light:active, +.button.is-link.is-light.is-active { + background-color: #d1faff; + border-color: transparent; + color: #018293; +} +.button.is-info { + background-color: #02d7f2; + border-color: transparent; + color: #121617; +} +.button.is-info:hover, +.button.is-info.is-hovered { + background-color: #02cce5; + border-color: transparent; + color: #121617; +} +.button.is-info:focus, +.button.is-info.is-focused { + border-color: transparent; + color: #121617; +} +.button.is-info:focus:not(:active), +.button.is-info.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.button.is-info:active, +.button.is-info.is-active { + background-color: #02c1d9; + border-color: transparent; + color: #121617; +} +.button.is-info[disabled], +fieldset[disabled] .button.is-info { + background-color: #02d7f2; + border-color: transparent; + box-shadow: none; +} +.button.is-info.is-inverted { + background-color: #121617; + color: #02d7f2; +} +.button.is-info.is-inverted:hover, +.button.is-info.is-inverted.is-hovered { + background-color: #070809; +} +.button.is-info.is-inverted[disabled], +fieldset[disabled] .button.is-info.is-inverted { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #02d7f2; +} +.button.is-info.is-loading::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-info.is-outlined { + background-color: transparent; + border-color: #02d7f2; + color: #02d7f2; +} +.button.is-info.is-outlined:hover, +.button.is-info.is-outlined.is-hovered, +.button.is-info.is-outlined:focus, +.button.is-info.is-outlined.is-focused { + background-color: #02d7f2; + border-color: #02d7f2; + color: #121617; +} +.button.is-info.is-outlined.is-loading::after { + border-color: transparent transparent #02d7f2 #02d7f2 !important; +} +.button.is-info.is-outlined.is-loading:hover::after, +.button.is-info.is-outlined.is-loading.is-hovered::after, +.button.is-info.is-outlined.is-loading:focus::after, +.button.is-info.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-info.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-outlined { + background-color: transparent; + border-color: #02d7f2; + box-shadow: none; + color: #02d7f2; +} +.button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + color: #121617; +} +.button.is-info.is-inverted.is-outlined:hover, +.button.is-info.is-inverted.is-outlined.is-hovered, +.button.is-info.is-inverted.is-outlined:focus, +.button.is-info.is-inverted.is-outlined.is-focused { + background-color: #121617; + color: #02d7f2; +} +.button.is-info.is-inverted.is-outlined.is-loading:hover::after, +.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-info.is-inverted.is-outlined.is-loading:focus::after, +.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #02d7f2 #02d7f2 !important; +} +.button.is-info.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + box-shadow: none; + color: #121617; +} +.button.is-info.is-light { + background-color: #ebfdff; + color: #018293; +} +.button.is-info.is-light:hover, +.button.is-info.is-light.is-hovered { + background-color: #defbff; + border-color: transparent; + color: #018293; +} +.button.is-info.is-light:active, +.button.is-info.is-light.is-active { + background-color: #d1faff; + border-color: transparent; + color: #018293; +} +.button.is-success { + background-color: #00ff41; + border-color: transparent; + color: #121617; +} +.button.is-success:hover, +.button.is-success.is-hovered { + background-color: #00f23e; + border-color: transparent; + color: #121617; +} +.button.is-success:focus, +.button.is-success.is-focused { + border-color: transparent; + color: #121617; +} +.button.is-success:focus:not(:active), +.button.is-success.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0,255,65,0.25); +} +.button.is-success:active, +.button.is-success.is-active { + background-color: #00e63a; + border-color: transparent; + color: #121617; +} +.button.is-success[disabled], +fieldset[disabled] .button.is-success { + background-color: #00ff41; + border-color: transparent; + box-shadow: none; +} +.button.is-success.is-inverted { + background-color: #121617; + color: #00ff41; +} +.button.is-success.is-inverted:hover, +.button.is-success.is-inverted.is-hovered { + background-color: #070809; +} +.button.is-success.is-inverted[disabled], +fieldset[disabled] .button.is-success.is-inverted { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #00ff41; +} +.button.is-success.is-loading::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-success.is-outlined { + background-color: transparent; + border-color: #00ff41; + color: #00ff41; +} +.button.is-success.is-outlined:hover, +.button.is-success.is-outlined.is-hovered, +.button.is-success.is-outlined:focus, +.button.is-success.is-outlined.is-focused { + background-color: #00ff41; + border-color: #00ff41; + color: #121617; +} +.button.is-success.is-outlined.is-loading::after { + border-color: transparent transparent #00ff41 #00ff41 !important; +} +.button.is-success.is-outlined.is-loading:hover::after, +.button.is-success.is-outlined.is-loading.is-hovered::after, +.button.is-success.is-outlined.is-loading:focus::after, +.button.is-success.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-success.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-outlined { + background-color: transparent; + border-color: #00ff41; + box-shadow: none; + color: #00ff41; +} +.button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + color: #121617; +} +.button.is-success.is-inverted.is-outlined:hover, +.button.is-success.is-inverted.is-outlined.is-hovered, +.button.is-success.is-inverted.is-outlined:focus, +.button.is-success.is-inverted.is-outlined.is-focused { + background-color: #121617; + color: #00ff41; +} +.button.is-success.is-inverted.is-outlined.is-loading:hover::after, +.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-success.is-inverted.is-outlined.is-loading:focus::after, +.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #00ff41 #00ff41 !important; +} +.button.is-success.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + box-shadow: none; + color: #121617; +} +.button.is-success.is-light { + background-color: #ebfff0; + color: #009426; +} +.button.is-success.is-light:hover, +.button.is-success.is-light.is-hovered { + background-color: #deffe6; + border-color: transparent; + color: #009426; +} +.button.is-success.is-light:active, +.button.is-success.is-light.is-active { + background-color: #d1ffdd; + border-color: transparent; + color: #009426; +} +.button.is-warning { + background-color: #ff8e3c; + border-color: transparent; + color: #121617; +} +.button.is-warning:hover, +.button.is-warning.is-hovered { + background-color: #ff872f; + border-color: transparent; + color: #121617; +} +.button.is-warning:focus, +.button.is-warning.is-focused { + border-color: transparent; + color: #121617; +} +.button.is-warning:focus:not(:active), +.button.is-warning.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,142,60,0.25); +} +.button.is-warning:active, +.button.is-warning.is-active { + background-color: #ff7f22; + border-color: transparent; + color: #121617; +} +.button.is-warning[disabled], +fieldset[disabled] .button.is-warning { + background-color: #ff8e3c; + border-color: transparent; + box-shadow: none; +} +.button.is-warning.is-inverted { + background-color: #121617; + color: #ff8e3c; +} +.button.is-warning.is-inverted:hover, +.button.is-warning.is-inverted.is-hovered { + background-color: #070809; +} +.button.is-warning.is-inverted[disabled], +fieldset[disabled] .button.is-warning.is-inverted { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #ff8e3c; +} +.button.is-warning.is-loading::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-warning.is-outlined { + background-color: transparent; + border-color: #ff8e3c; + color: #ff8e3c; +} +.button.is-warning.is-outlined:hover, +.button.is-warning.is-outlined.is-hovered, +.button.is-warning.is-outlined:focus, +.button.is-warning.is-outlined.is-focused { + background-color: #ff8e3c; + border-color: #ff8e3c; + color: #121617; +} +.button.is-warning.is-outlined.is-loading::after { + border-color: transparent transparent #ff8e3c #ff8e3c !important; +} +.button.is-warning.is-outlined.is-loading:hover::after, +.button.is-warning.is-outlined.is-loading.is-hovered::after, +.button.is-warning.is-outlined.is-loading:focus::after, +.button.is-warning.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-warning.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ff8e3c; + box-shadow: none; + color: #ff8e3c; +} +.button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + color: #121617; +} +.button.is-warning.is-inverted.is-outlined:hover, +.button.is-warning.is-inverted.is-outlined.is-hovered, +.button.is-warning.is-inverted.is-outlined:focus, +.button.is-warning.is-inverted.is-outlined.is-focused { + background-color: #121617; + color: #ff8e3c; +} +.button.is-warning.is-inverted.is-outlined.is-loading:hover::after, +.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-warning.is-inverted.is-outlined.is-loading:focus::after, +.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ff8e3c #ff8e3c !important; +} +.button.is-warning.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + box-shadow: none; + color: #121617; +} +.button.is-warning.is-light { + background-color: #fff3eb; + color: #a84700; +} +.button.is-warning.is-light:hover, +.button.is-warning.is-light.is-hovered { + background-color: #ffecde; + border-color: transparent; + color: #a84700; +} +.button.is-warning.is-light:active, +.button.is-warning.is-light.is-active { + background-color: #ffe4d1; + border-color: transparent; + color: #a84700; +} +.button.is-danger { + background-color: #ff003c; + border-color: transparent; + color: #121617; +} +.button.is-danger:hover, +.button.is-danger.is-hovered { + background-color: #f20039; + border-color: transparent; + color: #121617; +} +.button.is-danger:focus, +.button.is-danger.is-focused { + border-color: transparent; + color: #121617; +} +.button.is-danger:focus:not(:active), +.button.is-danger.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,0,60,0.25); +} +.button.is-danger:active, +.button.is-danger.is-active { + background-color: #e60036; + border-color: transparent; + color: #121617; +} +.button.is-danger[disabled], +fieldset[disabled] .button.is-danger { + background-color: #ff003c; + border-color: transparent; + box-shadow: none; +} +.button.is-danger.is-inverted { + background-color: #121617; + color: #ff003c; +} +.button.is-danger.is-inverted:hover, +.button.is-danger.is-inverted.is-hovered { + background-color: #070809; +} +.button.is-danger.is-inverted[disabled], +fieldset[disabled] .button.is-danger.is-inverted { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #ff003c; +} +.button.is-danger.is-loading::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-danger.is-outlined { + background-color: transparent; + border-color: #ff003c; + color: #ff003c; +} +.button.is-danger.is-outlined:hover, +.button.is-danger.is-outlined.is-hovered, +.button.is-danger.is-outlined:focus, +.button.is-danger.is-outlined.is-focused { + background-color: #ff003c; + border-color: #ff003c; + color: #121617; +} +.button.is-danger.is-outlined.is-loading::after { + border-color: transparent transparent #ff003c #ff003c !important; +} +.button.is-danger.is-outlined.is-loading:hover::after, +.button.is-danger.is-outlined.is-loading.is-hovered::after, +.button.is-danger.is-outlined.is-loading:focus::after, +.button.is-danger.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #121617 #121617 !important; +} +.button.is-danger.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-outlined { + background-color: transparent; + border-color: #ff003c; + box-shadow: none; + color: #ff003c; +} +.button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + color: #121617; +} +.button.is-danger.is-inverted.is-outlined:hover, +.button.is-danger.is-inverted.is-outlined.is-hovered, +.button.is-danger.is-inverted.is-outlined:focus, +.button.is-danger.is-inverted.is-outlined.is-focused { + background-color: #121617; + color: #ff003c; +} +.button.is-danger.is-inverted.is-outlined.is-loading:hover::after, +.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-danger.is-inverted.is-outlined.is-loading:focus::after, +.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ff003c #ff003c !important; +} +.button.is-danger.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #121617; + box-shadow: none; + color: #121617; +} +.button.is-danger.is-light { + background-color: #ffebef; + color: #eb0037; +} +.button.is-danger.is-light:hover, +.button.is-danger.is-light.is-hovered { + background-color: #ffdee6; + border-color: transparent; + color: #eb0037; +} +.button.is-danger.is-light:active, +.button.is-danger.is-light.is-active { + background-color: #ffd1dc; + border-color: transparent; + color: #eb0037; +} +.button.is-grey-lightest { + background-color: #ededed; + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest:hover, +.button.is-grey-lightest.is-hovered { + background-color: #e7e7e7; + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest:focus, +.button.is-grey-lightest.is-focused { + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest:focus:not(:active), +.button.is-grey-lightest.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(237,237,237,0.25); +} +.button.is-grey-lightest:active, +.button.is-grey-lightest.is-active { + background-color: #e0e0e0; + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest[disabled], +fieldset[disabled] .button.is-grey-lightest { + background-color: #ededed; + border-color: transparent; + box-shadow: none; +} +.button.is-grey-lightest.is-inverted { + background-color: #363636; + color: #ededed; +} +.button.is-grey-lightest.is-inverted:hover, +.button.is-grey-lightest.is-inverted.is-hovered { + background-color: #292929; +} +.button.is-grey-lightest.is-inverted[disabled], +fieldset[disabled] .button.is-grey-lightest.is-inverted { + background-color: #363636; + border-color: transparent; + box-shadow: none; + color: #ededed; +} +.button.is-grey-lightest.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-grey-lightest.is-outlined { + background-color: transparent; + border-color: #ededed; + color: #ededed; +} +.button.is-grey-lightest.is-outlined:hover, +.button.is-grey-lightest.is-outlined.is-hovered, +.button.is-grey-lightest.is-outlined:focus, +.button.is-grey-lightest.is-outlined.is-focused { + background-color: #ededed; + border-color: #ededed; + color: #363636; +} +.button.is-grey-lightest.is-outlined.is-loading::after { + border-color: transparent transparent #ededed #ededed !important; +} +.button.is-grey-lightest.is-outlined.is-loading:hover::after, +.button.is-grey-lightest.is-outlined.is-loading.is-hovered::after, +.button.is-grey-lightest.is-outlined.is-loading:focus::after, +.button.is-grey-lightest.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-grey-lightest.is-outlined[disabled], +fieldset[disabled] .button.is-grey-lightest.is-outlined { + background-color: transparent; + border-color: #ededed; + box-shadow: none; + color: #ededed; +} +.button.is-grey-lightest.is-inverted.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; +} +.button.is-grey-lightest.is-inverted.is-outlined:hover, +.button.is-grey-lightest.is-inverted.is-outlined.is-hovered, +.button.is-grey-lightest.is-inverted.is-outlined:focus, +.button.is-grey-lightest.is-inverted.is-outlined.is-focused { + background-color: #363636; + color: #ededed; +} +.button.is-grey-lightest.is-inverted.is-outlined.is-loading:hover::after, +.button.is-grey-lightest.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-grey-lightest.is-inverted.is-outlined.is-loading:focus::after, +.button.is-grey-lightest.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ededed #ededed !important; +} +.button.is-grey-lightest.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-grey-lightest.is-inverted.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; +} +.button.is-small { + border-radius: 0; + font-size: 0.75rem; +} +.button.is-normal { + font-size: 1rem; +} +.button.is-medium { + font-size: 1.25rem; +} +.button.is-large { + font-size: 1.5rem; +} +.button[disabled], +fieldset[disabled] .button { + background-color: #000; + border-color: #dbdbdb; + box-shadow: none; + opacity: 0.5; +} +.button.is-fullwidth { + display: flex; + width: 100%; +} +.button.is-loading { + color: transparent !important; + pointer-events: none; +} +.button.is-loading::after { + position: absolute; + left: calc(50% - (1em / 2)); + top: calc(50% - (1em / 2)); + position: absolute !important; +} +.button.is-static { + background-color: #f5f5f5; + border-color: #dbdbdb; + color: #848484; + box-shadow: none; + pointer-events: none; +} +.button.is-rounded { + border-radius: 290486px; + padding-left: calc(1em + 0.25em); + padding-right: calc(1em + 0.25em); +} +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.buttons .button { + margin-bottom: 0.5rem; +} +.buttons .button:not(:last-child):not(.is-fullwidth) { + margin-right: 0.5rem; +} +.buttons:last-child { + margin-bottom: -0.5rem; +} +.buttons:not(:last-child) { + margin-bottom: 1rem; +} +.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large) { + border-radius: 0; + font-size: 0.75rem; +} +.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large) { + font-size: 1.25rem; +} +.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium) { + font-size: 1.5rem; +} +.buttons.has-addons .button:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.buttons.has-addons .button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: -1px; +} +.buttons.has-addons .button:last-child { + margin-right: 0; +} +.buttons.has-addons .button:hover, +.buttons.has-addons .button.is-hovered { + z-index: 2; +} +.buttons.has-addons .button:focus, +.buttons.has-addons .button.is-focused, +.buttons.has-addons .button:active, +.buttons.has-addons .button.is-active, +.buttons.has-addons .button.is-selected { + z-index: 3; +} +.buttons.has-addons .button:focus:hover, +.buttons.has-addons .button.is-focused:hover, +.buttons.has-addons .button:active:hover, +.buttons.has-addons .button.is-active:hover, +.buttons.has-addons .button.is-selected:hover { + z-index: 4; +} +.buttons.has-addons .button.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.buttons.is-centered { + justify-content: center; +} +.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} +.buttons.is-right { + justify-content: flex-end; +} +.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} +.container { + flex-grow: 1; + margin: 0 auto; + position: relative; + width: auto; +} +.container.is-fluid { + max-width: none; + padding-left: 64px; + padding-right: 64px; + width: 100%; +} +@media screen and (min-width: 1088px) { + .container { + max-width: 960px; + } +} +@media screen and (max-width: 1279px) { + .container.is-widescreen { + max-width: 1152px; + } +} +@media screen and (max-width: 1471px) { + .container.is-fullhd { + max-width: 1344px; + } +} +@media screen and (min-width: 1280px) { + .container { + max-width: 1152px; + } +} +@media screen and (min-width: 1472px) { + .container { + max-width: 1344px; + } +} +.content li + li { + margin-top: 0.25em; +} +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: 1em; +} +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: #fcee09; + font-weight: 400; + line-height: 1.125; +} +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; +} +.content h1:not(:first-child) { + margin-top: 1em; +} +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; +} +.content h2:not(:first-child) { + margin-top: 1.1428em; +} +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; +} +.content h3:not(:first-child) { + margin-top: 1.3333em; +} +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; +} +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; +} +.content h6 { + font-size: 1em; + margin-bottom: 1em; +} +.content blockquote { + background-color: #f5f5f5; + border-left: 5px solid #dbdbdb; + padding: 1.25em 1.5em; +} +.content ol { + list-style-position: outside; + margin-left: 2em; + margin-top: 1em; +} +.content ol:not([type]) { + list-style-type: decimal; +} +.content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; +} +.content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; +} +.content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; +} +.content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; +} +.content ul { + list-style: disc outside; + margin-left: 2em; + margin-top: 1em; +} +.content ul ul { + list-style-type: circle; + margin-top: 0.5em; +} +.content ul ul ul { + list-style-type: square; +} +.content dd { + margin-left: 2em; +} +.content figure { + margin-left: 2em; + margin-right: 2em; + text-align: center; +} +.content figure:not(:first-child) { + margin-top: 2em; +} +.content figure:not(:last-child) { + margin-bottom: 2em; +} +.content figure img { + display: inline-block; +} +.content figure figcaption { + font-style: italic; +} +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1.25em 1.5em; + white-space: pre; + word-wrap: normal; +} +.content sup, +.content sub { + font-size: 75%; +} +.content table { + width: 100%; +} +.content table td, +.content table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} +.content table th { + color: #fcee09; +} +.content table th:not([align]) { + text-align: left; +} +.content table thead td, +.content table thead th { + border-width: 0 0 2px; + color: #fcee09; +} +.content table tfoot td, +.content table tfoot th { + border-width: 2px 0 0; + color: #fcee09; +} +.content table tbody tr:last-child td, +.content table tbody tr:last-child th { + border-bottom-width: 0; +} +.content .tabs li + li { + margin-top: 0; +} +.content.is-small { + font-size: 0.75rem; +} +.content.is-medium { + font-size: 1.25rem; +} +.content.is-large { + font-size: 1.5rem; +} +.icon { + align-items: center; + display: inline-flex; + justify-content: center; + height: 1.5rem; + width: 1.5rem; +} +.icon.is-small { + height: 1rem; + width: 1rem; +} +.icon.is-medium { + height: 2rem; + width: 2rem; +} +.icon.is-large { + height: 3rem; + width: 3rem; +} +.image { + display: block; + position: relative; +} +.image img { + display: block; + height: auto; + width: 100%; +} +.image img.is-rounded { + border-radius: 290486px; +} +.image.is-fullwidth { + width: 100%; +} +.image.is-square img, +.image.is-1by1 img, +.image.is-5by4 img, +.image.is-4by3 img, +.image.is-3by2 img, +.image.is-5by3 img, +.image.is-16by9 img, +.image.is-2by1 img, +.image.is-3by1 img, +.image.is-4by5 img, +.image.is-3by4 img, +.image.is-2by3 img, +.image.is-3by5 img, +.image.is-9by16 img, +.image.is-1by2 img, +.image.is-1by3 img, +.image.is-square .has-ratio, +.image.is-1by1 .has-ratio, +.image.is-5by4 .has-ratio, +.image.is-4by3 .has-ratio, +.image.is-3by2 .has-ratio, +.image.is-5by3 .has-ratio, +.image.is-16by9 .has-ratio, +.image.is-2by1 .has-ratio, +.image.is-3by1 .has-ratio, +.image.is-4by5 .has-ratio, +.image.is-3by4 .has-ratio, +.image.is-2by3 .has-ratio, +.image.is-3by5 .has-ratio, +.image.is-9by16 .has-ratio, +.image.is-1by2 .has-ratio, +.image.is-1by3 .has-ratio { + height: 100%; + width: 100%; +} +.image.is-square, +.image.is-1by1 { + padding-top: 100%; +} +.image.is-5by4 { + padding-top: 80%; +} +.image.is-4by3 { + padding-top: 75%; +} +.image.is-3by2 { + padding-top: 66.6666%; +} +.image.is-5by3 { + padding-top: 60%; +} +.image.is-16by9 { + padding-top: 56.25%; +} +.image.is-2by1 { + padding-top: 50%; +} +.image.is-3by1 { + padding-top: 33.3333%; +} +.image.is-4by5 { + padding-top: 125%; +} +.image.is-3by4 { + padding-top: 133.3333%; +} +.image.is-2by3 { + padding-top: 150%; +} +.image.is-3by5 { + padding-top: 166.6666%; +} +.image.is-9by16 { + padding-top: 177.7777%; +} +.image.is-1by2 { + padding-top: 200%; +} +.image.is-1by3 { + padding-top: 300%; +} +.image.is-16x16 { + height: 16px; + width: 16px; +} +.image.is-24x24 { + height: 24px; + width: 24px; +} +.image.is-32x32 { + height: 32px; + width: 32px; +} +.image.is-48x48 { + height: 48px; + width: 48px; +} +.image.is-64x64 { + height: 64px; + width: 64px; +} +.image.is-96x96 { + height: 96px; + width: 96px; +} +.image.is-128x128 { + height: 128px; + width: 128px; +} +.notification { + background-color: #f5f5f5; + border-radius: 0; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; + position: relative; +} +.notification a:not(.button):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} +.notification strong { + color: currentColor; +} +.notification code, +.notification pre { + background: #000; +} +.notification pre code { + background: transparent; +} +.notification > .delete { + position: absolute; + right: 0.5rem; + top: 0.5rem; +} +.notification .title, +.notification .subtitle, +.notification .content { + color: currentColor; +} +.notification.is-white { + background-color: #fff; + color: #000; +} +.notification.is-black { + background-color: #000; + color: #fff; +} +.notification.is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.notification.is-dark { + background-color: #363636; + color: #fff; +} +.notification.is-primary { + background-color: #fcee09; + color: #121617; +} +.notification.is-link { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.notification.is-info { + background-color: #02d7f2; + color: #121617; +} +.notification.is-success { + background-color: #00ff41; + color: #121617; +} +.notification.is-warning { + background-color: #ff8e3c; + color: #121617; +} +.notification.is-danger { + background-color: #ff003c; + color: #121617; +} +.notification.is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 290486px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; +} +.progress::-webkit-progress-bar { + background-color: #ededed; +} +.progress::-webkit-progress-value { + background-color: #cdcdcd; +} +.progress::-moz-progress-bar { + background-color: #cdcdcd; +} +.progress::-ms-fill { + background-color: #cdcdcd; + border: none; +} +.progress.is-white::-webkit-progress-value { + background-color: #fff; +} +.progress.is-white::-moz-progress-bar { + background-color: #fff; +} +.progress.is-white::-ms-fill { + background-color: #fff; +} +.progress.is-white:indeterminate { + background-image: linear-gradient(to right, #fff 30%, #ededed 30%); +} +.progress.is-black::-webkit-progress-value { + background-color: #000; +} +.progress.is-black::-moz-progress-bar { + background-color: #000; +} +.progress.is-black::-ms-fill { + background-color: #000; +} +.progress.is-black:indeterminate { + background-image: linear-gradient(to right, #000 30%, #ededed 30%); +} +.progress.is-light::-webkit-progress-value { + background-color: #f5f5f5; +} +.progress.is-light::-moz-progress-bar { + background-color: #f5f5f5; +} +.progress.is-light::-ms-fill { + background-color: #f5f5f5; +} +.progress.is-light:indeterminate { + background-image: linear-gradient(to right, #f5f5f5 30%, #ededed 30%); +} +.progress.is-dark::-webkit-progress-value { + background-color: #363636; +} +.progress.is-dark::-moz-progress-bar { + background-color: #363636; +} +.progress.is-dark::-ms-fill { + background-color: #363636; +} +.progress.is-dark:indeterminate { + background-image: linear-gradient(to right, #363636 30%, #ededed 30%); +} +.progress.is-primary::-webkit-progress-value { + background-color: #fcee09; +} +.progress.is-primary::-moz-progress-bar { + background-color: #fcee09; +} +.progress.is-primary::-ms-fill { + background-color: #fcee09; +} +.progress.is-primary:indeterminate { + background-image: linear-gradient(to right, #fcee09 30%, #ededed 30%); +} +.progress.is-link::-webkit-progress-value { + background-color: #02d7f2; +} +.progress.is-link::-moz-progress-bar { + background-color: #02d7f2; +} +.progress.is-link::-ms-fill { + background-color: #02d7f2; +} +.progress.is-link:indeterminate { + background-image: linear-gradient(to right, #02d7f2 30%, #ededed 30%); +} +.progress.is-info::-webkit-progress-value { + background-color: #02d7f2; +} +.progress.is-info::-moz-progress-bar { + background-color: #02d7f2; +} +.progress.is-info::-ms-fill { + background-color: #02d7f2; +} +.progress.is-info:indeterminate { + background-image: linear-gradient(to right, #02d7f2 30%, #ededed 30%); +} +.progress.is-success::-webkit-progress-value { + background-color: #00ff41; +} +.progress.is-success::-moz-progress-bar { + background-color: #00ff41; +} +.progress.is-success::-ms-fill { + background-color: #00ff41; +} +.progress.is-success:indeterminate { + background-image: linear-gradient(to right, #00ff41 30%, #ededed 30%); +} +.progress.is-warning::-webkit-progress-value { + background-color: #ff8e3c; +} +.progress.is-warning::-moz-progress-bar { + background-color: #ff8e3c; +} +.progress.is-warning::-ms-fill { + background-color: #ff8e3c; +} +.progress.is-warning:indeterminate { + background-image: linear-gradient(to right, #ff8e3c 30%, #ededed 30%); +} +.progress.is-danger::-webkit-progress-value { + background-color: #ff003c; +} +.progress.is-danger::-moz-progress-bar { + background-color: #ff003c; +} +.progress.is-danger::-ms-fill { + background-color: #ff003c; +} +.progress.is-danger:indeterminate { + background-image: linear-gradient(to right, #ff003c 30%, #ededed 30%); +} +.progress.is-grey-lightest::-webkit-progress-value { + background-color: #ededed; +} +.progress.is-grey-lightest::-moz-progress-bar { + background-color: #ededed; +} +.progress.is-grey-lightest::-ms-fill { + background-color: #ededed; +} +.progress.is-grey-lightest:indeterminate { + background-image: linear-gradient(to right, #ededed 30%, #ededed 30%); +} +.progress:indeterminate { + animation-duration: 1.5s; + animation-iteration-count: infinite; + animation-name: moveIndeterminate; + animation-timing-function: linear; + background-color: #ededed; + background-image: linear-gradient(to right, #cdcdcd 30%, #ededed 30%); + background-position: top left; + background-repeat: no-repeat; + background-size: 150% 150%; +} +.progress:indeterminate::-webkit-progress-bar { + background-color: transparent; +} +.progress:indeterminate::-moz-progress-bar { + background-color: transparent; +} +.progress.is-small { + height: 0.75rem; +} +.progress.is-medium { + height: 1.25rem; +} +.progress.is-large { + height: 1.5rem; +} +@-moz-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +@-webkit-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +@-o-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +@keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +.table { + background-color: #000; + color: #fcee09; +} +.table td, +.table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} +.table td.is-white, +.table th.is-white { + background-color: #fff; + border-color: #fff; + color: #000; +} +.table td.is-black, +.table th.is-black { + background-color: #000; + border-color: #000; + color: #fff; +} +.table td.is-light, +.table th.is-light { + background-color: #f5f5f5; + border-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.table td.is-dark, +.table th.is-dark { + background-color: #363636; + border-color: #363636; + color: #fff; +} +.table td.is-primary, +.table th.is-primary { + background-color: #fcee09; + border-color: #fcee09; + color: #121617; +} +.table td.is-link, +.table th.is-link { + background-color: #02d7f2; + border-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.table td.is-info, +.table th.is-info { + background-color: #02d7f2; + border-color: #02d7f2; + color: #121617; +} +.table td.is-success, +.table th.is-success { + background-color: #00ff41; + border-color: #00ff41; + color: #121617; +} +.table td.is-warning, +.table th.is-warning { + background-color: #ff8e3c; + border-color: #ff8e3c; + color: #121617; +} +.table td.is-danger, +.table th.is-danger { + background-color: #ff003c; + border-color: #ff003c; + color: #121617; +} +.table td.is-grey-lightest, +.table th.is-grey-lightest { + background-color: #ededed; + border-color: #ededed; + color: #363636; +} +.table td.is-narrow, +.table th.is-narrow { + white-space: nowrap; + width: 1%; +} +.table td.is-selected, +.table th.is-selected { + background-color: #fcee09; + color: #121617; +} +.table td.is-selected a, +.table th.is-selected a, +.table td.is-selected strong, +.table th.is-selected strong { + color: currentColor; +} +.table th { + color: #fcee09; +} +.table th:not([align]) { + text-align: left; +} +.table tr.is-selected { + background-color: #fcee09; + color: #121617; +} +.table tr.is-selected a, +.table tr.is-selected strong { + color: currentColor; +} +.table tr.is-selected td, +.table tr.is-selected th { + border-color: #121617; + color: currentColor; +} +.table thead { + background-color: transparent; +} +.table thead td, +.table thead th { + border-width: 0 0 2px; + color: #fcee09; +} +.table tfoot { + background-color: transparent; +} +.table tfoot td, +.table tfoot th { + border-width: 2px 0 0; + color: #fcee09; +} +.table tbody { + background-color: transparent; +} +.table tbody tr:last-child td, +.table tbody tr:last-child th { + border-bottom-width: 0; +} +.table.is-bordered td, +.table.is-bordered th { + border-width: 1px; +} +.table.is-bordered tr:last-child td, +.table.is-bordered tr:last-child th { + border-bottom-width: 1px; +} +.table.is-fullwidth { + width: 100%; +} +.table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #cdcdcd; +} +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: #cdcdcd; +} +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: #f5f5f5; +} +.table.is-narrow td, +.table.is-narrow th { + padding: 0.25em 0.5em; +} +.table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #cdcdcd; +} +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; +} +.tags { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.tags .tag { + margin-bottom: 0.5rem; +} +.tags .tag:not(:last-child) { + margin-right: 0.5rem; +} +.tags:last-child { + margin-bottom: -0.5rem; +} +.tags:not(:last-child) { + margin-bottom: 1rem; +} +.tags.are-medium .tag:not(.is-normal):not(.is-large) { + font-size: 1rem; +} +.tags.are-large .tag:not(.is-normal):not(.is-medium) { + font-size: 1.25rem; +} +.tags.is-centered { + justify-content: center; +} +.tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; +} +.tags.is-right { + justify-content: flex-end; +} +.tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; +} +.tags.is-right .tag:not(:last-child) { + margin-right: 0; +} +.tags.has-addons .tag { + margin-right: 0; +} +.tags.has-addons .tag:not(:first-child) { + margin-left: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.tags.has-addons .tag:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.tag:not(body) { + align-items: center; + background-color: #02d7f2; + border-radius: 0; + color: #000; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} +.tag:not(body) .delete { + margin-left: 0.25rem; + margin-right: -0.375rem; +} +.tag:not(body).is-white { + background-color: #fff; + color: #000; +} +.tag:not(body).is-black { + background-color: #000; + color: #fff; +} +.tag:not(body).is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.tag:not(body).is-dark { + background-color: #363636; + color: #fff; +} +.tag:not(body).is-primary { + background-color: #fcee09; + color: #121617; +} +.tag:not(body).is-primary.is-light { + background-color: #fffeeb; + color: #928a02; +} +.tag:not(body).is-link { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.tag:not(body).is-link.is-light { + background-color: #ebfdff; + color: #018293; +} +.tag:not(body).is-info { + background-color: #02d7f2; + color: #121617; +} +.tag:not(body).is-info.is-light { + background-color: #ebfdff; + color: #018293; +} +.tag:not(body).is-success { + background-color: #00ff41; + color: #121617; +} +.tag:not(body).is-success.is-light { + background-color: #ebfff0; + color: #009426; +} +.tag:not(body).is-warning { + background-color: #ff8e3c; + color: #121617; +} +.tag:not(body).is-warning.is-light { + background-color: #fff3eb; + color: #a84700; +} +.tag:not(body).is-danger { + background-color: #ff003c; + color: #121617; +} +.tag:not(body).is-danger.is-light { + background-color: #ffebef; + color: #eb0037; +} +.tag:not(body).is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.tag:not(body).is-normal { + font-size: 0.75rem; +} +.tag:not(body).is-medium { + font-size: 1rem; +} +.tag:not(body).is-large { + font-size: 1.25rem; +} +.tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; +} +.tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; +} +.tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; +} +.tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; +} +.tag:not(body).is-delete::before, +.tag:not(body).is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} +.tag:not(body).is-delete::before { + height: 1px; + width: 50%; +} +.tag:not(body).is-delete::after { + height: 50%; + width: 1px; +} +.tag:not(body).is-delete:hover, +.tag:not(body).is-delete:focus { + background-color: #02c1d9; +} +.tag:not(body).is-delete:active { + background-color: #02aabf; +} +.tag:not(body).is-rounded { + border-radius: 290486px; +} +a.tag:hover { + text-decoration: underline; +} +.title, +.subtitle { + word-break: break-word; +} +.title em, +.subtitle em, +.title span, +.subtitle span { + font-weight: inherit; +} +.title sub, +.subtitle sub { + font-size: 0.75em; +} +.title sup, +.subtitle sup { + font-size: 0.75em; +} +.title .tag, +.subtitle .tag { + vertical-align: middle; +} +.title { + color: #fcee09; + font-size: 2rem; + font-weight: 400; + line-height: 1.125; +} +.title strong { + color: inherit; + font-weight: inherit; +} +.title + .highlight { + margin-top: -0.75rem; +} +.title:not(.is-spaced) + .subtitle { + margin-top: -1.25rem; +} +.title.is-1 { + font-size: 3rem; +} +.title.is-2 { + font-size: 2.5rem; +} +.title.is-3 { + font-size: 2rem; +} +.title.is-4 { + font-size: 1.5rem; +} +.title.is-5 { + font-size: 1.25rem; +} +.title.is-6 { + font-size: 1rem; +} +.title.is-7 { + font-size: 0.85rem; +} +.subtitle { + color: #cdcdcd; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; +} +.subtitle strong { + color: #fcee09; + font-weight: 600; +} +.subtitle:not(.is-spaced) + .title { + margin-top: -1.25rem; +} +.subtitle.is-1 { + font-size: 3rem; +} +.subtitle.is-2 { + font-size: 2.5rem; +} +.subtitle.is-3 { + font-size: 2rem; +} +.subtitle.is-4 { + font-size: 1.5rem; +} +.subtitle.is-5 { + font-size: 1.25rem; +} +.subtitle.is-6 { + font-size: 1rem; +} +.subtitle.is-7 { + font-size: 0.85rem; +} +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; +} +.highlight { + font-weight: 400; + max-width: 100%; + overflow: hidden; + padding: 0; +} +.highlight pre { + overflow: auto; + max-width: 100%; +} +.number { + align-items: center; + background-color: #f5f5f5; + border-radius: 290486px; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; +} +.input, +.textarea, +.select select { + background-color: #000; + border-color: #dbdbdb; + border-radius: 0; + color: #cdcdcd; +} +.input::-moz-placeholder, +.textarea::-moz-placeholder, +.select select::-moz-placeholder { + color: rgba(205,205,205,0.8); +} +.input::-webkit-input-placeholder, +.textarea::-webkit-input-placeholder, +.select select::-webkit-input-placeholder { + color: rgba(205,205,205,0.8); +} +.input:-moz-placeholder, +.textarea:-moz-placeholder, +.select select:-moz-placeholder { + color: rgba(205,205,205,0.8); +} +.input:-ms-input-placeholder, +.textarea:-ms-input-placeholder, +.select select:-ms-input-placeholder { + color: rgba(205,205,205,0.8); +} +.input:hover, +.textarea:hover, +.select select:hover, +.input.is-hovered, +.textarea.is-hovered, +.select select.is-hovered { + border-color: #b5b5b5; +} +.input:focus, +.textarea:focus, +.select select:focus, +.input.is-focused, +.textarea.is-focused, +.select select.is-focused, +.input:active, +.textarea:active, +.select select:active, +.input.is-active, +.textarea.is-active, +.select select.is-active { + border-color: #02d7f2; + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.input[disabled], +.textarea[disabled], +.select select[disabled], +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select { + background-color: #f5f5f5; + border-color: #f5f5f5; + box-shadow: none; + color: #848484; +} +.input[disabled]::-moz-placeholder, +.textarea[disabled]::-moz-placeholder, +.select select[disabled]::-moz-placeholder, +fieldset[disabled] .input::-moz-placeholder, +fieldset[disabled] .textarea::-moz-placeholder, +fieldset[disabled] .select select::-moz-placeholder { + color: rgba(132,132,132,0.3); +} +.input[disabled]::-webkit-input-placeholder, +.textarea[disabled]::-webkit-input-placeholder, +.select select[disabled]::-webkit-input-placeholder, +fieldset[disabled] .input::-webkit-input-placeholder, +fieldset[disabled] .textarea::-webkit-input-placeholder, +fieldset[disabled] .select select::-webkit-input-placeholder { + color: rgba(132,132,132,0.3); +} +.input[disabled]:-moz-placeholder, +.textarea[disabled]:-moz-placeholder, +.select select[disabled]:-moz-placeholder, +fieldset[disabled] .input:-moz-placeholder, +fieldset[disabled] .textarea:-moz-placeholder, +fieldset[disabled] .select select:-moz-placeholder { + color: rgba(132,132,132,0.3); +} +.input[disabled]:-ms-input-placeholder, +.textarea[disabled]:-ms-input-placeholder, +.select select[disabled]:-ms-input-placeholder, +fieldset[disabled] .input:-ms-input-placeholder, +fieldset[disabled] .textarea:-ms-input-placeholder, +fieldset[disabled] .select select:-ms-input-placeholder { + color: rgba(132,132,132,0.3); +} +.input, +.textarea { + box-shadow: inset 0 0.0625em 0.125em rgba(0,0,0,0.05); + max-width: 100%; + width: 100%; +} +.input[readonly], +.textarea[readonly] { + box-shadow: none; +} +.input.is-white, +.textarea.is-white { + border-color: #fff; +} +.input.is-white:focus, +.textarea.is-white:focus, +.input.is-white.is-focused, +.textarea.is-white.is-focused, +.input.is-white:active, +.textarea.is-white:active, +.input.is-white.is-active, +.textarea.is-white.is-active { + box-shadow: 0 0 0 0.125em rgba(255,255,255,0.25); +} +.input.is-black, +.textarea.is-black { + border-color: #000; +} +.input.is-black:focus, +.textarea.is-black:focus, +.input.is-black.is-focused, +.textarea.is-black.is-focused, +.input.is-black:active, +.textarea.is-black:active, +.input.is-black.is-active, +.textarea.is-black.is-active { + box-shadow: 0 0 0 0.125em rgba(0,0,0,0.25); +} +.input.is-light, +.textarea.is-light { + border-color: #f5f5f5; +} +.input.is-light:focus, +.textarea.is-light:focus, +.input.is-light.is-focused, +.textarea.is-light.is-focused, +.input.is-light:active, +.textarea.is-light:active, +.input.is-light.is-active, +.textarea.is-light.is-active { + box-shadow: 0 0 0 0.125em rgba(245,245,245,0.25); +} +.input.is-dark, +.textarea.is-dark { + border-color: #363636; +} +.input.is-dark:focus, +.textarea.is-dark:focus, +.input.is-dark.is-focused, +.textarea.is-dark.is-focused, +.input.is-dark:active, +.textarea.is-dark:active, +.input.is-dark.is-active, +.textarea.is-dark.is-active { + box-shadow: 0 0 0 0.125em rgba(54,54,54,0.25); +} +.input.is-primary, +.textarea.is-primary { + border-color: #fcee09; +} +.input.is-primary:focus, +.textarea.is-primary:focus, +.input.is-primary.is-focused, +.textarea.is-primary.is-focused, +.input.is-primary:active, +.textarea.is-primary:active, +.input.is-primary.is-active, +.textarea.is-primary.is-active { + box-shadow: 0 0 0 0.125em rgba(252,238,9,0.25); +} +.input.is-link, +.textarea.is-link { + border-color: #02d7f2; +} +.input.is-link:focus, +.textarea.is-link:focus, +.input.is-link.is-focused, +.textarea.is-link.is-focused, +.input.is-link:active, +.textarea.is-link:active, +.input.is-link.is-active, +.textarea.is-link.is-active { + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.input.is-info, +.textarea.is-info { + border-color: #02d7f2; +} +.input.is-info:focus, +.textarea.is-info:focus, +.input.is-info.is-focused, +.textarea.is-info.is-focused, +.input.is-info:active, +.textarea.is-info:active, +.input.is-info.is-active, +.textarea.is-info.is-active { + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.input.is-success, +.textarea.is-success { + border-color: #00ff41; +} +.input.is-success:focus, +.textarea.is-success:focus, +.input.is-success.is-focused, +.textarea.is-success.is-focused, +.input.is-success:active, +.textarea.is-success:active, +.input.is-success.is-active, +.textarea.is-success.is-active { + box-shadow: 0 0 0 0.125em rgba(0,255,65,0.25); +} +.input.is-warning, +.textarea.is-warning { + border-color: #ff8e3c; +} +.input.is-warning:focus, +.textarea.is-warning:focus, +.input.is-warning.is-focused, +.textarea.is-warning.is-focused, +.input.is-warning:active, +.textarea.is-warning:active, +.input.is-warning.is-active, +.textarea.is-warning.is-active { + box-shadow: 0 0 0 0.125em rgba(255,142,60,0.25); +} +.input.is-danger, +.textarea.is-danger { + border-color: #ff003c; +} +.input.is-danger:focus, +.textarea.is-danger:focus, +.input.is-danger.is-focused, +.textarea.is-danger.is-focused, +.input.is-danger:active, +.textarea.is-danger:active, +.input.is-danger.is-active, +.textarea.is-danger.is-active { + box-shadow: 0 0 0 0.125em rgba(255,0,60,0.25); +} +.input.is-grey-lightest, +.textarea.is-grey-lightest { + border-color: #ededed; +} +.input.is-grey-lightest:focus, +.textarea.is-grey-lightest:focus, +.input.is-grey-lightest.is-focused, +.textarea.is-grey-lightest.is-focused, +.input.is-grey-lightest:active, +.textarea.is-grey-lightest:active, +.input.is-grey-lightest.is-active, +.textarea.is-grey-lightest.is-active { + box-shadow: 0 0 0 0.125em rgba(237,237,237,0.25); +} +.input.is-small, +.textarea.is-small { + border-radius: 0; + font-size: 0.75rem; +} +.input.is-medium, +.textarea.is-medium { + font-size: 1.25rem; +} +.input.is-large, +.textarea.is-large { + font-size: 1.5rem; +} +.input.is-fullwidth, +.textarea.is-fullwidth { + display: block; + width: 100%; +} +.input.is-inline, +.textarea.is-inline { + display: inline; + width: auto; +} +.input.is-rounded { + border-radius: 290486px; + padding-left: calc(calc(0.75em - 1px) + 0.375em); + padding-right: calc(calc(0.75em - 1px) + 0.375em); +} +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; +} +.textarea { + display: block; + max-width: 100%; + min-width: 100%; + padding: calc(0.75em - 1px); + resize: vertical; +} +.textarea:not([rows]) { + max-height: 40em; + min-height: 8em; +} +.textarea[rows] { + height: initial; +} +.textarea.has-fixed-size { + resize: none; +} +.checkbox, +.radio { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; +} +.checkbox input, +.radio input { + cursor: pointer; +} +.checkbox:hover, +.radio:hover { + color: #fcee09; +} +.checkbox[disabled], +.radio[disabled], +fieldset[disabled] .checkbox, +fieldset[disabled] .radio { + color: #848484; + cursor: not-allowed; +} +.radio + .radio { + margin-left: 0.5em; +} +.select { + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; +} +.select:not(.is-multiple) { + height: 2.25em; +} +.select:not(.is-multiple):not(.is-loading)::after { + border-color: #02d7f2; + right: 1.125em; + z-index: 4; +} +.select.is-rounded select { + border-radius: 290486px; + padding-left: 1em; +} +.select select { + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; +} +.select select::-ms-expand { + display: none; +} +.select select[disabled]:hover, +fieldset[disabled] .select select:hover { + border-color: #f5f5f5; +} +.select select:not([multiple]) { + padding-right: 2.5em; +} +.select select[multiple] { + height: auto; + padding: 0; +} +.select select[multiple] option { + padding: 0.5em 1em; +} +.select:not(.is-multiple):not(.is-loading):hover::after { + border-color: #fcee09; +} +.select.is-white:not(:hover)::after { + border-color: #fff; +} +.select.is-white select { + border-color: #fff; +} +.select.is-white select:hover, +.select.is-white select.is-hovered { + border-color: #f2f2f2; +} +.select.is-white select:focus, +.select.is-white select.is-focused, +.select.is-white select:active, +.select.is-white select.is-active { + box-shadow: 0 0 0 0.125em rgba(255,255,255,0.25); +} +.select.is-black:not(:hover)::after { + border-color: #000; +} +.select.is-black select { + border-color: #000; +} +.select.is-black select:hover, +.select.is-black select.is-hovered { + border-color: #000; +} +.select.is-black select:focus, +.select.is-black select.is-focused, +.select.is-black select:active, +.select.is-black select.is-active { + box-shadow: 0 0 0 0.125em rgba(0,0,0,0.25); +} +.select.is-light:not(:hover)::after { + border-color: #f5f5f5; +} +.select.is-light select { + border-color: #f5f5f5; +} +.select.is-light select:hover, +.select.is-light select.is-hovered { + border-color: #e8e8e8; +} +.select.is-light select:focus, +.select.is-light select.is-focused, +.select.is-light select:active, +.select.is-light select.is-active { + box-shadow: 0 0 0 0.125em rgba(245,245,245,0.25); +} +.select.is-dark:not(:hover)::after { + border-color: #363636; +} +.select.is-dark select { + border-color: #363636; +} +.select.is-dark select:hover, +.select.is-dark select.is-hovered { + border-color: #292929; +} +.select.is-dark select:focus, +.select.is-dark select.is-focused, +.select.is-dark select:active, +.select.is-dark select.is-active { + box-shadow: 0 0 0 0.125em rgba(54,54,54,0.25); +} +.select.is-primary:not(:hover)::after { + border-color: #fcee09; +} +.select.is-primary select { + border-color: #fcee09; +} +.select.is-primary select:hover, +.select.is-primary select.is-hovered { + border-color: #e9db03; +} +.select.is-primary select:focus, +.select.is-primary select.is-focused, +.select.is-primary select:active, +.select.is-primary select.is-active { + box-shadow: 0 0 0 0.125em rgba(252,238,9,0.25); +} +.select.is-link:not(:hover)::after { + border-color: #02d7f2; +} +.select.is-link select { + border-color: #02d7f2; +} +.select.is-link select:hover, +.select.is-link select.is-hovered { + border-color: #02c1d9; +} +.select.is-link select:focus, +.select.is-link select.is-focused, +.select.is-link select:active, +.select.is-link select.is-active { + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.select.is-info:not(:hover)::after { + border-color: #02d7f2; +} +.select.is-info select { + border-color: #02d7f2; +} +.select.is-info select:hover, +.select.is-info select.is-hovered { + border-color: #02c1d9; +} +.select.is-info select:focus, +.select.is-info select.is-focused, +.select.is-info select:active, +.select.is-info select.is-active { + box-shadow: 0 0 0 0.125em rgba(2,215,242,0.25); +} +.select.is-success:not(:hover)::after { + border-color: #00ff41; +} +.select.is-success select { + border-color: #00ff41; +} +.select.is-success select:hover, +.select.is-success select.is-hovered { + border-color: #00e63a; +} +.select.is-success select:focus, +.select.is-success select.is-focused, +.select.is-success select:active, +.select.is-success select.is-active { + box-shadow: 0 0 0 0.125em rgba(0,255,65,0.25); +} +.select.is-warning:not(:hover)::after { + border-color: #ff8e3c; +} +.select.is-warning select { + border-color: #ff8e3c; +} +.select.is-warning select:hover, +.select.is-warning select.is-hovered { + border-color: #ff7f22; +} +.select.is-warning select:focus, +.select.is-warning select.is-focused, +.select.is-warning select:active, +.select.is-warning select.is-active { + box-shadow: 0 0 0 0.125em rgba(255,142,60,0.25); +} +.select.is-danger:not(:hover)::after { + border-color: #ff003c; +} +.select.is-danger select { + border-color: #ff003c; +} +.select.is-danger select:hover, +.select.is-danger select.is-hovered { + border-color: #e60036; +} +.select.is-danger select:focus, +.select.is-danger select.is-focused, +.select.is-danger select:active, +.select.is-danger select.is-active { + box-shadow: 0 0 0 0.125em rgba(255,0,60,0.25); +} +.select.is-grey-lightest:not(:hover)::after { + border-color: #ededed; +} +.select.is-grey-lightest select { + border-color: #ededed; +} +.select.is-grey-lightest select:hover, +.select.is-grey-lightest select.is-hovered { + border-color: #e0e0e0; +} +.select.is-grey-lightest select:focus, +.select.is-grey-lightest select.is-focused, +.select.is-grey-lightest select:active, +.select.is-grey-lightest select.is-active { + box-shadow: 0 0 0 0.125em rgba(237,237,237,0.25); +} +.select.is-small { + border-radius: 0; + font-size: 0.75rem; +} +.select.is-medium { + font-size: 1.25rem; +} +.select.is-large { + font-size: 1.5rem; +} +.select.is-disabled::after { + border-color: #848484; +} +.select.is-fullwidth { + width: 100%; +} +.select.is-fullwidth select { + width: 100%; +} +.select.is-loading::after { + margin-top: 0; + position: absolute; + right: 0.625em; + top: 0.625em; + transform: none; +} +.select.is-loading.is-small:after { + font-size: 0.75rem; +} +.select.is-loading.is-medium:after { + font-size: 1.25rem; +} +.select.is-loading.is-large:after { + font-size: 1.5rem; +} +.file { + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; +} +.file.is-white .file-cta { + background-color: #fff; + border-color: transparent; + color: #000; +} +.file.is-white:hover .file-cta, +.file.is-white.is-hovered .file-cta { + background-color: #f9f9f9; + border-color: transparent; + color: #000; +} +.file.is-white:focus .file-cta, +.file.is-white.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255,255,255,0.25); + color: #000; +} +.file.is-white:active .file-cta, +.file.is-white.is-active .file-cta { + background-color: #f2f2f2; + border-color: transparent; + color: #000; +} +.file.is-black .file-cta { + background-color: #000; + border-color: transparent; + color: #fff; +} +.file.is-black:hover .file-cta, +.file.is-black.is-hovered .file-cta { + background-color: #000; + border-color: transparent; + color: #fff; +} +.file.is-black:focus .file-cta, +.file.is-black.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(0,0,0,0.25); + color: #fff; +} +.file.is-black:active .file-cta, +.file.is-black.is-active .file-cta { + background-color: #000; + border-color: transparent; + color: #fff; +} +.file.is-light .file-cta { + background-color: #f5f5f5; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-light:hover .file-cta, +.file.is-light.is-hovered .file-cta { + background-color: #eee; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-light:focus .file-cta, +.file.is-light.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(245,245,245,0.25); + color: rgba(0,0,0,0.7); +} +.file.is-light:active .file-cta, +.file.is-light.is-active .file-cta { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-dark .file-cta { + background-color: #363636; + border-color: transparent; + color: #fff; +} +.file.is-dark:hover .file-cta, +.file.is-dark.is-hovered .file-cta { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} +.file.is-dark:focus .file-cta, +.file.is-dark.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(54,54,54,0.25); + color: #fff; +} +.file.is-dark:active .file-cta, +.file.is-dark.is-active .file-cta { + background-color: #292929; + border-color: transparent; + color: #fff; +} +.file.is-primary .file-cta { + background-color: #fcee09; + border-color: transparent; + color: #121617; +} +.file.is-primary:hover .file-cta, +.file.is-primary.is-hovered .file-cta { + background-color: #f5e703; + border-color: transparent; + color: #121617; +} +.file.is-primary:focus .file-cta, +.file.is-primary.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(252,238,9,0.25); + color: #121617; +} +.file.is-primary:active .file-cta, +.file.is-primary.is-active .file-cta { + background-color: #e9db03; + border-color: transparent; + color: #121617; +} +.file.is-link .file-cta { + background-color: #02d7f2; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-link:hover .file-cta, +.file.is-link.is-hovered .file-cta { + background-color: #02cce5; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-link:focus .file-cta, +.file.is-link.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(2,215,242,0.25); + color: rgba(0,0,0,0.7); +} +.file.is-link:active .file-cta, +.file.is-link.is-active .file-cta { + background-color: #02c1d9; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-info .file-cta { + background-color: #02d7f2; + border-color: transparent; + color: #121617; +} +.file.is-info:hover .file-cta, +.file.is-info.is-hovered .file-cta { + background-color: #02cce5; + border-color: transparent; + color: #121617; +} +.file.is-info:focus .file-cta, +.file.is-info.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(2,215,242,0.25); + color: #121617; +} +.file.is-info:active .file-cta, +.file.is-info.is-active .file-cta { + background-color: #02c1d9; + border-color: transparent; + color: #121617; +} +.file.is-success .file-cta { + background-color: #00ff41; + border-color: transparent; + color: #121617; +} +.file.is-success:hover .file-cta, +.file.is-success.is-hovered .file-cta { + background-color: #00f23e; + border-color: transparent; + color: #121617; +} +.file.is-success:focus .file-cta, +.file.is-success.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(0,255,65,0.25); + color: #121617; +} +.file.is-success:active .file-cta, +.file.is-success.is-active .file-cta { + background-color: #00e63a; + border-color: transparent; + color: #121617; +} +.file.is-warning .file-cta { + background-color: #ff8e3c; + border-color: transparent; + color: #121617; +} +.file.is-warning:hover .file-cta, +.file.is-warning.is-hovered .file-cta { + background-color: #ff872f; + border-color: transparent; + color: #121617; +} +.file.is-warning:focus .file-cta, +.file.is-warning.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255,142,60,0.25); + color: #121617; +} +.file.is-warning:active .file-cta, +.file.is-warning.is-active .file-cta { + background-color: #ff7f22; + border-color: transparent; + color: #121617; +} +.file.is-danger .file-cta { + background-color: #ff003c; + border-color: transparent; + color: #121617; +} +.file.is-danger:hover .file-cta, +.file.is-danger.is-hovered .file-cta { + background-color: #f20039; + border-color: transparent; + color: #121617; +} +.file.is-danger:focus .file-cta, +.file.is-danger.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255,0,60,0.25); + color: #121617; +} +.file.is-danger:active .file-cta, +.file.is-danger.is-active .file-cta { + background-color: #e60036; + border-color: transparent; + color: #121617; +} +.file.is-grey-lightest .file-cta { + background-color: #ededed; + border-color: transparent; + color: #363636; +} +.file.is-grey-lightest:hover .file-cta, +.file.is-grey-lightest.is-hovered .file-cta { + background-color: #e7e7e7; + border-color: transparent; + color: #363636; +} +.file.is-grey-lightest:focus .file-cta, +.file.is-grey-lightest.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(237,237,237,0.25); + color: #363636; +} +.file.is-grey-lightest:active .file-cta, +.file.is-grey-lightest.is-active .file-cta { + background-color: #e0e0e0; + border-color: transparent; + color: #363636; +} +.file.is-small { + font-size: 0.75rem; +} +.file.is-medium { + font-size: 1.25rem; +} +.file.is-medium .file-icon .fa { + font-size: 21px; +} +.file.is-large { + font-size: 1.5rem; +} +.file.is-large .file-icon .fa { + font-size: 28px; +} +.file.has-name .file-cta { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.file.has-name .file-name { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.file.has-name.is-empty .file-cta { + border-radius: 0; +} +.file.has-name.is-empty .file-name { + display: none; +} +.file.is-boxed .file-label { + flex-direction: column; +} +.file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; +} +.file.is-boxed .file-name { + border-width: 0 1px 1px; +} +.file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; +} +.file.is-boxed .file-icon .fa { + font-size: 21px; +} +.file.is-boxed.is-small .file-icon .fa { + font-size: 14px; +} +.file.is-boxed.is-medium .file-icon .fa { + font-size: 28px; +} +.file.is-boxed.is-large .file-icon .fa { + font-size: 35px; +} +.file.is-boxed.has-name .file-cta { + border-radius: 0 0 0 0; +} +.file.is-boxed.has-name .file-name { + border-radius: 0 0 0 0; + border-width: 0 1px 1px; +} +.file.is-centered { + justify-content: center; +} +.file.is-fullwidth .file-label { + width: 100%; +} +.file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; +} +.file.is-right { + justify-content: flex-end; +} +.file.is-right .file-cta { + border-radius: 0 0 0 0; +} +.file.is-right .file-name { + border-radius: 0 0 0 0; + border-width: 1px 0 1px 1px; + order: -1; +} +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; +} +.file-label:hover .file-cta { + background-color: #eee; + color: #fcee09; +} +.file-label:hover .file-name { + border-color: #d5d5d5; +} +.file-label:active .file-cta { + background-color: #e8e8e8; + color: #fcee09; +} +.file-label:active .file-name { + border-color: #cfcfcf; +} +.file-input { + height: 100%; + left: 0; + opacity: 0; + outline: none; + position: absolute; + top: 0; + width: 100%; +} +.file-cta, +.file-name { + border-color: #dbdbdb; + border-radius: 0; + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; +} +.file-cta { + background-color: #f5f5f5; + color: #cdcdcd; +} +.file-name { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px 1px 1px 0; + display: block; + max-width: 16em; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; +} +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-right: 0.5em; + width: 1em; +} +.file-icon .fa { + font-size: 14px; +} +.label { + color: #fcee09; + display: block; + font-size: 1rem; + font-weight: 700; +} +.label:not(:last-child) { + margin-bottom: 0.5em; +} +.label.is-small { + font-size: 0.75rem; +} +.label.is-medium { + font-size: 1.25rem; +} +.label.is-large { + font-size: 1.5rem; +} +.help { + display: block; + font-size: 0.75rem; + margin-top: 0.25rem; +} +.help.is-white { + color: #fff; +} +.help.is-black { + color: #000; +} +.help.is-light { + color: #f5f5f5; +} +.help.is-dark { + color: #363636; +} +.help.is-primary { + color: #fcee09; +} +.help.is-link { + color: #02d7f2; +} +.help.is-info { + color: #02d7f2; +} +.help.is-success { + color: #00ff41; +} +.help.is-warning { + color: #ff8e3c; +} +.help.is-danger { + color: #ff003c; +} +.help.is-grey-lightest { + color: #ededed; +} +.field:not(:last-child) { + margin-bottom: 0.75rem; +} +.field.has-addons { + display: flex; + justify-content: flex-start; +} +.field.has-addons .control:not(:last-child) { + margin-right: -1px; +} +.field.has-addons .control:not(:first-child):not(:last-child) .button, +.field.has-addons .control:not(:first-child):not(:last-child) .input, +.field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; +} +.field.has-addons .control:first-child:not(:only-child) .button, +.field.has-addons .control:first-child:not(:only-child) .input, +.field.has-addons .control:first-child:not(:only-child) .select select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.field.has-addons .control:last-child:not(:only-child) .button, +.field.has-addons .control:last-child:not(:only-child) .input, +.field.has-addons .control:last-child:not(:only-child) .select select { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.field.has-addons .control .button:not([disabled]):hover, +.field.has-addons .control .input:not([disabled]):hover, +.field.has-addons .control .select select:not([disabled]):hover, +.field.has-addons .control .button:not([disabled]).is-hovered, +.field.has-addons .control .input:not([disabled]).is-hovered, +.field.has-addons .control .select select:not([disabled]).is-hovered { + z-index: 2; +} +.field.has-addons .control .button:not([disabled]):focus, +.field.has-addons .control .input:not([disabled]):focus, +.field.has-addons .control .select select:not([disabled]):focus, +.field.has-addons .control .button:not([disabled]).is-focused, +.field.has-addons .control .input:not([disabled]).is-focused, +.field.has-addons .control .select select:not([disabled]).is-focused, +.field.has-addons .control .button:not([disabled]):active, +.field.has-addons .control .input:not([disabled]):active, +.field.has-addons .control .select select:not([disabled]):active, +.field.has-addons .control .button:not([disabled]).is-active, +.field.has-addons .control .input:not([disabled]).is-active, +.field.has-addons .control .select select:not([disabled]).is-active { + z-index: 3; +} +.field.has-addons .control .button:not([disabled]):focus:hover, +.field.has-addons .control .input:not([disabled]):focus:hover, +.field.has-addons .control .select select:not([disabled]):focus:hover, +.field.has-addons .control .button:not([disabled]).is-focused:hover, +.field.has-addons .control .input:not([disabled]).is-focused:hover, +.field.has-addons .control .select select:not([disabled]).is-focused:hover, +.field.has-addons .control .button:not([disabled]):active:hover, +.field.has-addons .control .input:not([disabled]):active:hover, +.field.has-addons .control .select select:not([disabled]):active:hover, +.field.has-addons .control .button:not([disabled]).is-active:hover, +.field.has-addons .control .input:not([disabled]).is-active:hover, +.field.has-addons .control .select select:not([disabled]).is-active:hover { + z-index: 4; +} +.field.has-addons .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.field.has-addons.has-addons-centered { + justify-content: center; +} +.field.has-addons.has-addons-right { + justify-content: flex-end; +} +.field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; +} +.field.is-grouped { + display: flex; + justify-content: flex-start; +} +.field.is-grouped > .control { + flex-shrink: 0; +} +.field.is-grouped > .control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} +.field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.field.is-grouped.is-grouped-centered { + justify-content: center; +} +.field.is-grouped.is-grouped-right { + justify-content: flex-end; +} +.field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; +} +.field.is-grouped.is-grouped-multiline > .control:last-child, +.field.is-grouped.is-grouped-multiline > .control:not(:last-child) { + margin-bottom: 0.75rem; +} +.field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; +} +.field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; +} +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; + } +} +.field-label .label { + font-size: inherit; +} +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; + } +} +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; + } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; + } + .field-label.is-normal { + padding-top: 0.375em; + } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; + } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; + } +} +.field-body .field .field { + margin-bottom: 0; +} +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; + } + .field-body .field { + margin-bottom: 0; + } + .field-body > .field { + flex-shrink: 1; + } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; + } + .field-body > .field:not(:last-child) { + margin-right: 0.75rem; + } +} +.control { + box-sizing: border-box; + clear: both; + font-size: 1rem; + position: relative; + text-align: left; +} +.control.has-icons-left .input:focus ~ .icon, +.control.has-icons-right .input:focus ~ .icon, +.control.has-icons-left .select:focus ~ .icon, +.control.has-icons-right .select:focus ~ .icon { + color: #cdcdcd; +} +.control.has-icons-left .input.is-small ~ .icon, +.control.has-icons-right .input.is-small ~ .icon, +.control.has-icons-left .select.is-small ~ .icon, +.control.has-icons-right .select.is-small ~ .icon { + font-size: 0.75rem; +} +.control.has-icons-left .input.is-medium ~ .icon, +.control.has-icons-right .input.is-medium ~ .icon, +.control.has-icons-left .select.is-medium ~ .icon, +.control.has-icons-right .select.is-medium ~ .icon { + font-size: 1.25rem; +} +.control.has-icons-left .input.is-large ~ .icon, +.control.has-icons-right .input.is-large ~ .icon, +.control.has-icons-left .select.is-large ~ .icon, +.control.has-icons-right .select.is-large ~ .icon { + font-size: 1.5rem; +} +.control.has-icons-left .icon, +.control.has-icons-right .icon { + color: #dbdbdb; + height: 2.25em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.25em; + z-index: 4; +} +.control.has-icons-left .input, +.control.has-icons-left .select select { + padding-left: 2.25em; +} +.control.has-icons-left .icon.is-left { + left: 0; +} +.control.has-icons-right .input, +.control.has-icons-right .select select { + padding-right: 2.25em; +} +.control.has-icons-right .icon.is-right { + right: 0; +} +.control.is-loading::after { + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; +} +.control.is-loading.is-small:after { + font-size: 0.75rem; +} +.control.is-loading.is-medium:after { + font-size: 1.25rem; +} +.control.is-loading.is-large:after { + font-size: 1.5rem; +} +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; +} +.columns.is-mobile > .column.is-narrow { + flex: none; +} +.columns.is-mobile > .column.is-full { + flex: none; + width: 100%; +} +.columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; +} +.columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; +} +.columns.is-mobile > .column.is-half { + flex: none; + width: 50%; +} +.columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; +} +.columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; +} +.columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; +} +.columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; +} +.columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; +} +.columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; +} +.columns.is-mobile > .column.is-offset-three-quarters { + margin-left: 75%; +} +.columns.is-mobile > .column.is-offset-two-thirds { + margin-left: 66.6666%; +} +.columns.is-mobile > .column.is-offset-half { + margin-left: 50%; +} +.columns.is-mobile > .column.is-offset-one-third { + margin-left: 33.3333%; +} +.columns.is-mobile > .column.is-offset-one-quarter { + margin-left: 25%; +} +.columns.is-mobile > .column.is-offset-one-fifth { + margin-left: 20%; +} +.columns.is-mobile > .column.is-offset-two-fifths { + margin-left: 40%; +} +.columns.is-mobile > .column.is-offset-three-fifths { + margin-left: 60%; +} +.columns.is-mobile > .column.is-offset-four-fifths { + margin-left: 80%; +} +.columns.is-mobile > .column.is-0 { + flex: none; + width: 0%; +} +.columns.is-mobile > .column.is-offset-0 { + margin-left: 0%; +} +.columns.is-mobile > .column.is-1 { + flex: none; + width: 8.33333%; +} +.columns.is-mobile > .column.is-offset-1 { + margin-left: 8.33333%; +} +.columns.is-mobile > .column.is-2 { + flex: none; + width: 16.66667%; +} +.columns.is-mobile > .column.is-offset-2 { + margin-left: 16.66667%; +} +.columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; +} +.columns.is-mobile > .column.is-offset-3 { + margin-left: 25%; +} +.columns.is-mobile > .column.is-4 { + flex: none; + width: 33.33333%; +} +.columns.is-mobile > .column.is-offset-4 { + margin-left: 33.33333%; +} +.columns.is-mobile > .column.is-5 { + flex: none; + width: 41.66667%; +} +.columns.is-mobile > .column.is-offset-5 { + margin-left: 41.66667%; +} +.columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; +} +.columns.is-mobile > .column.is-offset-6 { + margin-left: 50%; +} +.columns.is-mobile > .column.is-7 { + flex: none; + width: 58.33333%; +} +.columns.is-mobile > .column.is-offset-7 { + margin-left: 58.33333%; +} +.columns.is-mobile > .column.is-8 { + flex: none; + width: 66.66667%; +} +.columns.is-mobile > .column.is-offset-8 { + margin-left: 66.66667%; +} +.columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; +} +.columns.is-mobile > .column.is-offset-9 { + margin-left: 75%; +} +.columns.is-mobile > .column.is-10 { + flex: none; + width: 83.33333%; +} +.columns.is-mobile > .column.is-offset-10 { + margin-left: 83.33333%; +} +.columns.is-mobile > .column.is-11 { + flex: none; + width: 91.66667%; +} +.columns.is-mobile > .column.is-offset-11 { + margin-left: 91.66667%; +} +.columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; +} +.columns.is-mobile > .column.is-offset-12 { + margin-left: 100%; +} +@media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; + } + .column.is-full-mobile { + flex: none; + width: 100%; + } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; + } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; + } + .column.is-half-mobile { + flex: none; + width: 50%; + } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; + } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; + } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; + } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; + } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; + } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; + } + .column.is-offset-half-mobile { + margin-left: 50%; + } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; + } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; + } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; + } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; + } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; + } + .column.is-0-mobile { + flex: none; + width: 0%; + } + .column.is-offset-0-mobile { + margin-left: 0%; + } + .column.is-1-mobile { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-mobile { + margin-left: 8.33333%; + } + .column.is-2-mobile { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-mobile { + margin-left: 16.66667%; + } + .column.is-3-mobile { + flex: none; + width: 25%; + } + .column.is-offset-3-mobile { + margin-left: 25%; + } + .column.is-4-mobile { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-mobile { + margin-left: 33.33333%; + } + .column.is-5-mobile { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-mobile { + margin-left: 41.66667%; + } + .column.is-6-mobile { + flex: none; + width: 50%; + } + .column.is-offset-6-mobile { + margin-left: 50%; + } + .column.is-7-mobile { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-mobile { + margin-left: 58.33333%; + } + .column.is-8-mobile { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-mobile { + margin-left: 66.66667%; + } + .column.is-9-mobile { + flex: none; + width: 75%; + } + .column.is-offset-9-mobile { + margin-left: 75%; + } + .column.is-10-mobile { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-mobile { + margin-left: 83.33333%; + } + .column.is-11-mobile { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-mobile { + margin-left: 91.66667%; + } + .column.is-12-mobile { + flex: none; + width: 100%; + } + .column.is-offset-12-mobile { + margin-left: 100%; + } +} +@media screen and (min-width: 769px), print { + .column.is-narrow, + .column.is-narrow-tablet { + flex: none; + } + .column.is-full, + .column.is-full-tablet { + flex: none; + width: 100%; + } + .column.is-three-quarters, + .column.is-three-quarters-tablet { + flex: none; + width: 75%; + } + .column.is-two-thirds, + .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; + } + .column.is-half, + .column.is-half-tablet { + flex: none; + width: 50%; + } + .column.is-one-third, + .column.is-one-third-tablet { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter, + .column.is-one-quarter-tablet { + flex: none; + width: 25%; + } + .column.is-one-fifth, + .column.is-one-fifth-tablet { + flex: none; + width: 20%; + } + .column.is-two-fifths, + .column.is-two-fifths-tablet { + flex: none; + width: 40%; + } + .column.is-three-fifths, + .column.is-three-fifths-tablet { + flex: none; + width: 60%; + } + .column.is-four-fifths, + .column.is-four-fifths-tablet { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters, + .column.is-offset-three-quarters-tablet { + margin-left: 75%; + } + .column.is-offset-two-thirds, + .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; + } + .column.is-offset-half, + .column.is-offset-half-tablet { + margin-left: 50%; + } + .column.is-offset-one-third, + .column.is-offset-one-third-tablet { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter, + .column.is-offset-one-quarter-tablet { + margin-left: 25%; + } + .column.is-offset-one-fifth, + .column.is-offset-one-fifth-tablet { + margin-left: 20%; + } + .column.is-offset-two-fifths, + .column.is-offset-two-fifths-tablet { + margin-left: 40%; + } + .column.is-offset-three-fifths, + .column.is-offset-three-fifths-tablet { + margin-left: 60%; + } + .column.is-offset-four-fifths, + .column.is-offset-four-fifths-tablet { + margin-left: 80%; + } + .column.is-0, + .column.is-0-tablet { + flex: none; + width: 0%; + } + .column.is-offset-0, + .column.is-offset-0-tablet { + margin-left: 0%; + } + .column.is-1, + .column.is-1-tablet { + flex: none; + width: 8.33333%; + } + .column.is-offset-1, + .column.is-offset-1-tablet { + margin-left: 8.33333%; + } + .column.is-2, + .column.is-2-tablet { + flex: none; + width: 16.66667%; + } + .column.is-offset-2, + .column.is-offset-2-tablet { + margin-left: 16.66667%; + } + .column.is-3, + .column.is-3-tablet { + flex: none; + width: 25%; + } + .column.is-offset-3, + .column.is-offset-3-tablet { + margin-left: 25%; + } + .column.is-4, + .column.is-4-tablet { + flex: none; + width: 33.33333%; + } + .column.is-offset-4, + .column.is-offset-4-tablet { + margin-left: 33.33333%; + } + .column.is-5, + .column.is-5-tablet { + flex: none; + width: 41.66667%; + } + .column.is-offset-5, + .column.is-offset-5-tablet { + margin-left: 41.66667%; + } + .column.is-6, + .column.is-6-tablet { + flex: none; + width: 50%; + } + .column.is-offset-6, + .column.is-offset-6-tablet { + margin-left: 50%; + } + .column.is-7, + .column.is-7-tablet { + flex: none; + width: 58.33333%; + } + .column.is-offset-7, + .column.is-offset-7-tablet { + margin-left: 58.33333%; + } + .column.is-8, + .column.is-8-tablet { + flex: none; + width: 66.66667%; + } + .column.is-offset-8, + .column.is-offset-8-tablet { + margin-left: 66.66667%; + } + .column.is-9, + .column.is-9-tablet { + flex: none; + width: 75%; + } + .column.is-offset-9, + .column.is-offset-9-tablet { + margin-left: 75%; + } + .column.is-10, + .column.is-10-tablet { + flex: none; + width: 83.33333%; + } + .column.is-offset-10, + .column.is-offset-10-tablet { + margin-left: 83.33333%; + } + .column.is-11, + .column.is-11-tablet { + flex: none; + width: 91.66667%; + } + .column.is-offset-11, + .column.is-offset-11-tablet { + margin-left: 91.66667%; + } + .column.is-12, + .column.is-12-tablet { + flex: none; + width: 100%; + } + .column.is-offset-12, + .column.is-offset-12-tablet { + margin-left: 100%; + } +} +@media screen and (max-width: 1087px) { + .column.is-narrow-touch { + flex: none; + } + .column.is-full-touch { + flex: none; + width: 100%; + } + .column.is-three-quarters-touch { + flex: none; + width: 75%; + } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; + } + .column.is-half-touch { + flex: none; + width: 50%; + } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-touch { + flex: none; + width: 25%; + } + .column.is-one-fifth-touch { + flex: none; + width: 20%; + } + .column.is-two-fifths-touch { + flex: none; + width: 40%; + } + .column.is-three-fifths-touch { + flex: none; + width: 60%; + } + .column.is-four-fifths-touch { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-touch { + margin-left: 75%; + } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; + } + .column.is-offset-half-touch { + margin-left: 50%; + } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-touch { + margin-left: 25%; + } + .column.is-offset-one-fifth-touch { + margin-left: 20%; + } + .column.is-offset-two-fifths-touch { + margin-left: 40%; + } + .column.is-offset-three-fifths-touch { + margin-left: 60%; + } + .column.is-offset-four-fifths-touch { + margin-left: 80%; + } + .column.is-0-touch { + flex: none; + width: 0%; + } + .column.is-offset-0-touch { + margin-left: 0%; + } + .column.is-1-touch { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-touch { + margin-left: 8.33333%; + } + .column.is-2-touch { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-touch { + margin-left: 16.66667%; + } + .column.is-3-touch { + flex: none; + width: 25%; + } + .column.is-offset-3-touch { + margin-left: 25%; + } + .column.is-4-touch { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-touch { + margin-left: 33.33333%; + } + .column.is-5-touch { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-touch { + margin-left: 41.66667%; + } + .column.is-6-touch { + flex: none; + width: 50%; + } + .column.is-offset-6-touch { + margin-left: 50%; + } + .column.is-7-touch { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-touch { + margin-left: 58.33333%; + } + .column.is-8-touch { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-touch { + margin-left: 66.66667%; + } + .column.is-9-touch { + flex: none; + width: 75%; + } + .column.is-offset-9-touch { + margin-left: 75%; + } + .column.is-10-touch { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-touch { + margin-left: 83.33333%; + } + .column.is-11-touch { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-touch { + margin-left: 91.66667%; + } + .column.is-12-touch { + flex: none; + width: 100%; + } + .column.is-offset-12-touch { + margin-left: 100%; + } +} +@media screen and (min-width: 1088px) { + .column.is-narrow-desktop { + flex: none; + } + .column.is-full-desktop { + flex: none; + width: 100%; + } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; + } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; + } + .column.is-half-desktop { + flex: none; + width: 50%; + } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; + } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; + } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; + } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; + } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; + } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; + } + .column.is-offset-half-desktop { + margin-left: 50%; + } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; + } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; + } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; + } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; + } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; + } + .column.is-0-desktop { + flex: none; + width: 0%; + } + .column.is-offset-0-desktop { + margin-left: 0%; + } + .column.is-1-desktop { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-desktop { + margin-left: 8.33333%; + } + .column.is-2-desktop { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-desktop { + margin-left: 16.66667%; + } + .column.is-3-desktop { + flex: none; + width: 25%; + } + .column.is-offset-3-desktop { + margin-left: 25%; + } + .column.is-4-desktop { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-desktop { + margin-left: 33.33333%; + } + .column.is-5-desktop { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-desktop { + margin-left: 41.66667%; + } + .column.is-6-desktop { + flex: none; + width: 50%; + } + .column.is-offset-6-desktop { + margin-left: 50%; + } + .column.is-7-desktop { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-desktop { + margin-left: 58.33333%; + } + .column.is-8-desktop { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-desktop { + margin-left: 66.66667%; + } + .column.is-9-desktop { + flex: none; + width: 75%; + } + .column.is-offset-9-desktop { + margin-left: 75%; + } + .column.is-10-desktop { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-desktop { + margin-left: 83.33333%; + } + .column.is-11-desktop { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-desktop { + margin-left: 91.66667%; + } + .column.is-12-desktop { + flex: none; + width: 100%; + } + .column.is-offset-12-desktop { + margin-left: 100%; + } +} +@media screen and (min-width: 1280px) { + .column.is-narrow-widescreen { + flex: none; + } + .column.is-full-widescreen { + flex: none; + width: 100%; + } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; + } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; + } + .column.is-half-widescreen { + flex: none; + width: 50%; + } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; + } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; + } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; + } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; + } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; + } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; + } + .column.is-offset-half-widescreen { + margin-left: 50%; + } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; + } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; + } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; + } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; + } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; + } + .column.is-0-widescreen { + flex: none; + width: 0%; + } + .column.is-offset-0-widescreen { + margin-left: 0%; + } + .column.is-1-widescreen { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-widescreen { + margin-left: 8.33333%; + } + .column.is-2-widescreen { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-widescreen { + margin-left: 16.66667%; + } + .column.is-3-widescreen { + flex: none; + width: 25%; + } + .column.is-offset-3-widescreen { + margin-left: 25%; + } + .column.is-4-widescreen { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-widescreen { + margin-left: 33.33333%; + } + .column.is-5-widescreen { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-widescreen { + margin-left: 41.66667%; + } + .column.is-6-widescreen { + flex: none; + width: 50%; + } + .column.is-offset-6-widescreen { + margin-left: 50%; + } + .column.is-7-widescreen { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-widescreen { + margin-left: 58.33333%; + } + .column.is-8-widescreen { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-widescreen { + margin-left: 66.66667%; + } + .column.is-9-widescreen { + flex: none; + width: 75%; + } + .column.is-offset-9-widescreen { + margin-left: 75%; + } + .column.is-10-widescreen { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-widescreen { + margin-left: 83.33333%; + } + .column.is-11-widescreen { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-widescreen { + margin-left: 91.66667%; + } + .column.is-12-widescreen { + flex: none; + width: 100%; + } + .column.is-offset-12-widescreen { + margin-left: 100%; + } +} +@media screen and (min-width: 1472px) { + .column.is-narrow-fullhd { + flex: none; + } + .column.is-full-fullhd { + flex: none; + width: 100%; + } + .column.is-three-quarters-fullhd { + flex: none; + width: 75%; + } + .column.is-two-thirds-fullhd { + flex: none; + width: 66.6666%; + } + .column.is-half-fullhd { + flex: none; + width: 50%; + } + .column.is-one-third-fullhd { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-fullhd { + flex: none; + width: 25%; + } + .column.is-one-fifth-fullhd { + flex: none; + width: 20%; + } + .column.is-two-fifths-fullhd { + flex: none; + width: 40%; + } + .column.is-three-fifths-fullhd { + flex: none; + width: 60%; + } + .column.is-four-fifths-fullhd { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-fullhd { + margin-left: 75%; + } + .column.is-offset-two-thirds-fullhd { + margin-left: 66.6666%; + } + .column.is-offset-half-fullhd { + margin-left: 50%; + } + .column.is-offset-one-third-fullhd { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-fullhd { + margin-left: 25%; + } + .column.is-offset-one-fifth-fullhd { + margin-left: 20%; + } + .column.is-offset-two-fifths-fullhd { + margin-left: 40%; + } + .column.is-offset-three-fifths-fullhd { + margin-left: 60%; + } + .column.is-offset-four-fifths-fullhd { + margin-left: 80%; + } + .column.is-0-fullhd { + flex: none; + width: 0%; + } + .column.is-offset-0-fullhd { + margin-left: 0%; + } + .column.is-1-fullhd { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-fullhd { + margin-left: 8.33333%; + } + .column.is-2-fullhd { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-fullhd { + margin-left: 16.66667%; + } + .column.is-3-fullhd { + flex: none; + width: 25%; + } + .column.is-offset-3-fullhd { + margin-left: 25%; + } + .column.is-4-fullhd { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-fullhd { + margin-left: 33.33333%; + } + .column.is-5-fullhd { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-fullhd { + margin-left: 41.66667%; + } + .column.is-6-fullhd { + flex: none; + width: 50%; + } + .column.is-offset-6-fullhd { + margin-left: 50%; + } + .column.is-7-fullhd { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-fullhd { + margin-left: 58.33333%; + } + .column.is-8-fullhd { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-fullhd { + margin-left: 66.66667%; + } + .column.is-9-fullhd { + flex: none; + width: 75%; + } + .column.is-offset-9-fullhd { + margin-left: 75%; + } + .column.is-10-fullhd { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-fullhd { + margin-left: 83.33333%; + } + .column.is-11-fullhd { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-fullhd { + margin-left: 91.66667%; + } + .column.is-12-fullhd { + flex: none; + width: 100%; + } + .column.is-offset-12-fullhd { + margin-left: 100%; + } +} +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} +.columns:last-child { + margin-bottom: -0.75rem; +} +.columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); +} +.columns.is-centered { + justify-content: center; +} +.columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; +} +.columns.is-gapless > .column { + margin: 0; + padding: 0 !important; +} +.columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; +} +.columns.is-gapless:last-child { + margin-bottom: 0; +} +.columns.is-mobile { + display: flex; +} +.columns.is-multiline { + flex-wrap: wrap; +} +.columns.is-vcentered { + align-items: center; +} +@media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; + } +} +@media screen and (min-width: 1088px) { + .columns.is-desktop { + display: flex; + } +} +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); +} +.columns.is-variable .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); +} +.columns.is-variable.is-0 { + --columnGap: 0rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-0-mobile { + --columnGap: 0rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-0-tablet { + --columnGap: 0rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-0-tablet-only { + --columnGap: 0rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-0-touch { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-0-desktop { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-0-desktop-only { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-0-widescreen { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-0-widescreen-only { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-0-fullhd { + --columnGap: 0rem; + } +} +.columns.is-variable.is-1 { + --columnGap: 0.25rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-1-mobile { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-1-tablet { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-1-tablet-only { + --columnGap: 0.25rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-1-touch { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-1-desktop { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-1-desktop-only { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-1-widescreen { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-1-widescreen-only { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-1-fullhd { + --columnGap: 0.25rem; + } +} +.columns.is-variable.is-2 { + --columnGap: 0.5rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-2-mobile { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-2-tablet { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-2-tablet-only { + --columnGap: 0.5rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-2-touch { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-2-desktop { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-2-desktop-only { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-2-widescreen { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-2-widescreen-only { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-2-fullhd { + --columnGap: 0.5rem; + } +} +.columns.is-variable.is-3 { + --columnGap: 0.75rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-3-mobile { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-3-tablet { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-3-tablet-only { + --columnGap: 0.75rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-3-touch { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-3-desktop { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-3-desktop-only { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-3-widescreen { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-3-widescreen-only { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-3-fullhd { + --columnGap: 0.75rem; + } +} +.columns.is-variable.is-4 { + --columnGap: 1rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-4-mobile { + --columnGap: 1rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-4-tablet { + --columnGap: 1rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-4-tablet-only { + --columnGap: 1rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-4-touch { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-4-desktop { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-4-desktop-only { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-4-widescreen { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-4-widescreen-only { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-4-fullhd { + --columnGap: 1rem; + } +} +.columns.is-variable.is-5 { + --columnGap: 1.25rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-5-mobile { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-5-tablet { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-5-tablet-only { + --columnGap: 1.25rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-5-touch { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-5-desktop { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-5-desktop-only { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-5-widescreen { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-5-widescreen-only { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-5-fullhd { + --columnGap: 1.25rem; + } +} +.columns.is-variable.is-6 { + --columnGap: 1.5rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-6-mobile { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-6-tablet { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-6-tablet-only { + --columnGap: 1.5rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-6-touch { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-6-desktop { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-6-desktop-only { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-6-widescreen { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-6-widescreen-only { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-6-fullhd { + --columnGap: 1.5rem; + } +} +.columns.is-variable.is-7 { + --columnGap: 1.75rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-7-mobile { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-7-tablet { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-7-tablet-only { + --columnGap: 1.75rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-7-touch { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-7-desktop { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-7-desktop-only { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-7-widescreen { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-7-widescreen-only { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-7-fullhd { + --columnGap: 1.75rem; + } +} +.columns.is-variable.is-8 { + --columnGap: 2rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-8-mobile { + --columnGap: 2rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-8-tablet { + --columnGap: 2rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-8-tablet-only { + --columnGap: 2rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-8-touch { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-8-desktop { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-8-desktop-only { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-8-widescreen { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-8-widescreen-only { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-8-fullhd { + --columnGap: 2rem; + } +} +.tile { + align-items: stretch; + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; +} +.tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} +.tile.is-ancestor:last-child { + margin-bottom: -0.75rem; +} +.tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; +} +.tile.is-child { + margin: 0 !important; +} +.tile.is-parent { + padding: 0.75rem; +} +.tile.is-vertical { + flex-direction: column; +} +.tile.is-vertical > .tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; +} +@media screen and (min-width: 769px), print { + .tile:not(.is-child) { + display: flex; + } + .tile.is-1 { + flex: none; + width: 8.33333%; + } + .tile.is-2 { + flex: none; + width: 16.66667%; + } + .tile.is-3 { + flex: none; + width: 25%; + } + .tile.is-4 { + flex: none; + width: 33.33333%; + } + .tile.is-5 { + flex: none; + width: 41.66667%; + } + .tile.is-6 { + flex: none; + width: 50%; + } + .tile.is-7 { + flex: none; + width: 58.33333%; + } + .tile.is-8 { + flex: none; + width: 66.66667%; + } + .tile.is-9 { + flex: none; + width: 75%; + } + .tile.is-10 { + flex: none; + width: 83.33333%; + } + .tile.is-11 { + flex: none; + width: 91.66667%; + } + .tile.is-12 { + flex: none; + width: 100%; + } +} +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.hero .navbar { + background: none; +} +.hero .tabs ul { + border-bottom: none; +} +.hero.is-white { + background-color: #fff; + color: #000; +} +.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-white strong { + color: inherit; +} +.hero.is-white .title { + color: #000; +} +.hero.is-white .subtitle { + color: rgba(0,0,0,0.9); +} +.hero.is-white .subtitle a:not(.button), +.hero.is-white .subtitle strong { + color: #000; +} +@media screen and (max-width: 1087px) { + .hero.is-white .navbar-menu { + background-color: #fff; + } +} +.hero.is-white .navbar-item, +.hero.is-white .navbar-link { + color: rgba(0,0,0,0.7); +} +.hero.is-white a.navbar-item:hover, +.hero.is-white .navbar-link:hover, +.hero.is-white a.navbar-item.is-active, +.hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #000; +} +.hero.is-white .tabs a { + color: #000; + opacity: 0.9; +} +.hero.is-white .tabs a:hover { + opacity: 1; +} +.hero.is-white .tabs li.is-active a { + opacity: 1; +} +.hero.is-white .tabs.is-boxed a, +.hero.is-white .tabs.is-toggle a { + color: #000; +} +.hero.is-white .tabs.is-boxed a:hover, +.hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-white .tabs.is-boxed li.is-active a, +.hero.is-white .tabs.is-toggle li.is-active a, +.hero.is-white .tabs.is-boxed li.is-active a:hover, +.hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #000; + border-color: #000; + color: #fff; +} +.hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e8e3e3 0%, #fff 71%, #fff 100%); +} +@media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e8e3e3 0%, #fff 71%, #fff 100%); + } +} +.hero.is-black { + background-color: #000; + color: #fff; +} +.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-black strong { + color: inherit; +} +.hero.is-black .title { + color: #fff; +} +.hero.is-black .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-black .subtitle a:not(.button), +.hero.is-black .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-black .navbar-menu { + background-color: #000; + } +} +.hero.is-black .navbar-item, +.hero.is-black .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-black a.navbar-item:hover, +.hero.is-black .navbar-link:hover, +.hero.is-black a.navbar-item.is-active, +.hero.is-black .navbar-link.is-active { + background-color: #000; + color: #fff; +} +.hero.is-black .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-black .tabs a:hover { + opacity: 1; +} +.hero.is-black .tabs li.is-active a { + opacity: 1; +} +.hero.is-black .tabs.is-boxed a, +.hero.is-black .tabs.is-toggle a { + color: #fff; +} +.hero.is-black .tabs.is-boxed a:hover, +.hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-black .tabs.is-boxed li.is-active a, +.hero.is-black .tabs.is-toggle li.is-active a, +.hero.is-black .tabs.is-boxed li.is-active a:hover, +.hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #000; +} +.hero.is-black.is-bold { + background-image: linear-gradient(141deg, #000 0%, #000 71%, #0d0c0c 100%); +} +@media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #000 0%, #000 71%, #0d0c0c 100%); + } +} +.hero.is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-light strong { + color: inherit; +} +.hero.is-light .title { + color: rgba(0,0,0,0.7); +} +.hero.is-light .subtitle { + color: rgba(0,0,0,0.9); +} +.hero.is-light .subtitle a:not(.button), +.hero.is-light .subtitle strong { + color: rgba(0,0,0,0.7); +} +@media screen and (max-width: 1087px) { + .hero.is-light .navbar-menu { + background-color: #f5f5f5; + } +} +.hero.is-light .navbar-item, +.hero.is-light .navbar-link { + color: rgba(0,0,0,0.7); +} +.hero.is-light a.navbar-item:hover, +.hero.is-light .navbar-link:hover, +.hero.is-light a.navbar-item.is-active, +.hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); +} +.hero.is-light .tabs a { + color: rgba(0,0,0,0.7); + opacity: 0.9; +} +.hero.is-light .tabs a:hover { + opacity: 1; +} +.hero.is-light .tabs li.is-active a { + opacity: 1; +} +.hero.is-light .tabs.is-boxed a, +.hero.is-light .tabs.is-toggle a { + color: rgba(0,0,0,0.7); +} +.hero.is-light .tabs.is-boxed a:hover, +.hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-light .tabs.is-boxed li.is-active a, +.hero.is-light .tabs.is-toggle li.is-active a, +.hero.is-light .tabs.is-boxed li.is-active a:hover, +.hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0,0,0,0.7); + border-color: rgba(0,0,0,0.7); + color: #f5f5f5; +} +.hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d8 0%, #f5f5f5 71%, #fff 100%); +} +@media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d8 0%, #f5f5f5 71%, #fff 100%); + } +} +.hero.is-dark { + background-color: #363636; + color: #fff; +} +.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-dark strong { + color: inherit; +} +.hero.is-dark .title { + color: #fff; +} +.hero.is-dark .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-dark .subtitle a:not(.button), +.hero.is-dark .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-dark .navbar-menu { + background-color: #363636; + } +} +.hero.is-dark .navbar-item, +.hero.is-dark .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-dark a.navbar-item:hover, +.hero.is-dark .navbar-link:hover, +.hero.is-dark a.navbar-item.is-active, +.hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: #fff; +} +.hero.is-dark .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-dark .tabs a:hover { + opacity: 1; +} +.hero.is-dark .tabs li.is-active a { + opacity: 1; +} +.hero.is-dark .tabs.is-boxed a, +.hero.is-dark .tabs.is-toggle a { + color: #fff; +} +.hero.is-dark .tabs.is-boxed a:hover, +.hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-dark .tabs.is-boxed li.is-active a, +.hero.is-dark .tabs.is-toggle li.is-active a, +.hero.is-dark .tabs.is-boxed li.is-active a:hover, +.hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #363636; +} +.hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f1a1a 0%, #363636 71%, #463f3f 100%); +} +@media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f1a1a 0%, #363636 71%, #463f3f 100%); + } +} +.hero.is-primary { + background-color: #fcee09; + color: #121617; +} +.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-primary strong { + color: inherit; +} +.hero.is-primary .title { + color: #121617; +} +.hero.is-primary .subtitle { + color: rgba(18,22,23,0.9); +} +.hero.is-primary .subtitle a:not(.button), +.hero.is-primary .subtitle strong { + color: #121617; +} +@media screen and (max-width: 1087px) { + .hero.is-primary .navbar-menu { + background-color: #fcee09; + } +} +.hero.is-primary .navbar-item, +.hero.is-primary .navbar-link { + color: rgba(18,22,23,0.7); +} +.hero.is-primary a.navbar-item:hover, +.hero.is-primary .navbar-link:hover, +.hero.is-primary a.navbar-item.is-active, +.hero.is-primary .navbar-link.is-active { + background-color: #e9db03; + color: #121617; +} +.hero.is-primary .tabs a { + color: #121617; + opacity: 0.9; +} +.hero.is-primary .tabs a:hover { + opacity: 1; +} +.hero.is-primary .tabs li.is-active a { + opacity: 1; +} +.hero.is-primary .tabs.is-boxed a, +.hero.is-primary .tabs.is-toggle a { + color: #121617; +} +.hero.is-primary .tabs.is-boxed a:hover, +.hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-primary .tabs.is-boxed li.is-active a, +.hero.is-primary .tabs.is-toggle li.is-active a, +.hero.is-primary .tabs.is-boxed li.is-active a:hover, +.hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #121617; + border-color: #121617; + color: #fcee09; +} +.hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #d2a300 0%, #fcee09 71%, #e7ff20 100%); +} +@media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #d2a300 0%, #fcee09 71%, #e7ff20 100%); + } +} +.hero.is-link { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-link strong { + color: inherit; +} +.hero.is-link .title { + color: rgba(0,0,0,0.7); +} +.hero.is-link .subtitle { + color: rgba(0,0,0,0.9); +} +.hero.is-link .subtitle a:not(.button), +.hero.is-link .subtitle strong { + color: rgba(0,0,0,0.7); +} +@media screen and (max-width: 1087px) { + .hero.is-link .navbar-menu { + background-color: #02d7f2; + } +} +.hero.is-link .navbar-item, +.hero.is-link .navbar-link { + color: rgba(0,0,0,0.7); +} +.hero.is-link a.navbar-item:hover, +.hero.is-link .navbar-link:hover, +.hero.is-link a.navbar-item.is-active, +.hero.is-link .navbar-link.is-active { + background-color: #02c1d9; + color: rgba(0,0,0,0.7); +} +.hero.is-link .tabs a { + color: rgba(0,0,0,0.7); + opacity: 0.9; +} +.hero.is-link .tabs a:hover { + opacity: 1; +} +.hero.is-link .tabs li.is-active a { + opacity: 1; +} +.hero.is-link .tabs.is-boxed a, +.hero.is-link .tabs.is-toggle a { + color: rgba(0,0,0,0.7); +} +.hero.is-link .tabs.is-boxed a:hover, +.hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-link .tabs.is-boxed li.is-active a, +.hero.is-link .tabs.is-toggle li.is-active a, +.hero.is-link .tabs.is-boxed li.is-active a:hover, +.hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0,0,0,0.7); + border-color: rgba(0,0,0,0.7); + color: #02d7f2; +} +.hero.is-link.is-bold { + background-image: linear-gradient(141deg, #00c1b7 0%, #02d7f2 71%, #0ebcff 100%); +} +@media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #00c1b7 0%, #02d7f2 71%, #0ebcff 100%); + } +} +.hero.is-info { + background-color: #02d7f2; + color: #121617; +} +.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-info strong { + color: inherit; +} +.hero.is-info .title { + color: #121617; +} +.hero.is-info .subtitle { + color: rgba(18,22,23,0.9); +} +.hero.is-info .subtitle a:not(.button), +.hero.is-info .subtitle strong { + color: #121617; +} +@media screen and (max-width: 1087px) { + .hero.is-info .navbar-menu { + background-color: #02d7f2; + } +} +.hero.is-info .navbar-item, +.hero.is-info .navbar-link { + color: rgba(18,22,23,0.7); +} +.hero.is-info a.navbar-item:hover, +.hero.is-info .navbar-link:hover, +.hero.is-info a.navbar-item.is-active, +.hero.is-info .navbar-link.is-active { + background-color: #02c1d9; + color: #121617; +} +.hero.is-info .tabs a { + color: #121617; + opacity: 0.9; +} +.hero.is-info .tabs a:hover { + opacity: 1; +} +.hero.is-info .tabs li.is-active a { + opacity: 1; +} +.hero.is-info .tabs.is-boxed a, +.hero.is-info .tabs.is-toggle a { + color: #121617; +} +.hero.is-info .tabs.is-boxed a:hover, +.hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-info .tabs.is-boxed li.is-active a, +.hero.is-info .tabs.is-toggle li.is-active a, +.hero.is-info .tabs.is-boxed li.is-active a:hover, +.hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #121617; + border-color: #121617; + color: #02d7f2; +} +.hero.is-info.is-bold { + background-image: linear-gradient(141deg, #00c1b7 0%, #02d7f2 71%, #0ebcff 100%); +} +@media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #00c1b7 0%, #02d7f2 71%, #0ebcff 100%); + } +} +.hero.is-success { + background-color: #00ff41; + color: #121617; +} +.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-success strong { + color: inherit; +} +.hero.is-success .title { + color: #121617; +} +.hero.is-success .subtitle { + color: rgba(18,22,23,0.9); +} +.hero.is-success .subtitle a:not(.button), +.hero.is-success .subtitle strong { + color: #121617; +} +@media screen and (max-width: 1087px) { + .hero.is-success .navbar-menu { + background-color: #00ff41; + } +} +.hero.is-success .navbar-item, +.hero.is-success .navbar-link { + color: rgba(18,22,23,0.7); +} +.hero.is-success a.navbar-item:hover, +.hero.is-success .navbar-link:hover, +.hero.is-success a.navbar-item.is-active, +.hero.is-success .navbar-link.is-active { + background-color: #00e63a; + color: #121617; +} +.hero.is-success .tabs a { + color: #121617; + opacity: 0.9; +} +.hero.is-success .tabs a:hover { + opacity: 1; +} +.hero.is-success .tabs li.is-active a { + opacity: 1; +} +.hero.is-success .tabs.is-boxed a, +.hero.is-success .tabs.is-toggle a { + color: #121617; +} +.hero.is-success .tabs.is-boxed a:hover, +.hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-success .tabs.is-boxed li.is-active a, +.hero.is-success .tabs.is-toggle li.is-active a, +.hero.is-success .tabs.is-boxed li.is-active a:hover, +.hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #121617; + border-color: #121617; + color: #00ff41; +} +.hero.is-success.is-bold { + background-image: linear-gradient(141deg, #00cc12 0%, #00ff41 71%, #1aff7a 100%); +} +@media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #00cc12 0%, #00ff41 71%, #1aff7a 100%); + } +} +.hero.is-warning { + background-color: #ff8e3c; + color: #121617; +} +.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-warning strong { + color: inherit; +} +.hero.is-warning .title { + color: #121617; +} +.hero.is-warning .subtitle { + color: rgba(18,22,23,0.9); +} +.hero.is-warning .subtitle a:not(.button), +.hero.is-warning .subtitle strong { + color: #121617; +} +@media screen and (max-width: 1087px) { + .hero.is-warning .navbar-menu { + background-color: #ff8e3c; + } +} +.hero.is-warning .navbar-item, +.hero.is-warning .navbar-link { + color: rgba(18,22,23,0.7); +} +.hero.is-warning a.navbar-item:hover, +.hero.is-warning .navbar-link:hover, +.hero.is-warning a.navbar-item.is-active, +.hero.is-warning .navbar-link.is-active { + background-color: #ff7f22; + color: #121617; +} +.hero.is-warning .tabs a { + color: #121617; + opacity: 0.9; +} +.hero.is-warning .tabs a:hover { + opacity: 1; +} +.hero.is-warning .tabs li.is-active a { + opacity: 1; +} +.hero.is-warning .tabs.is-boxed a, +.hero.is-warning .tabs.is-toggle a { + color: #121617; +} +.hero.is-warning .tabs.is-boxed a:hover, +.hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-warning .tabs.is-boxed li.is-active a, +.hero.is-warning .tabs.is-toggle li.is-active a, +.hero.is-warning .tabs.is-boxed li.is-active a:hover, +.hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: #121617; + border-color: #121617; + color: #ff8e3c; +} +.hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ff4809 0%, #ff8e3c 71%, #ffb956 100%); +} +@media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ff4809 0%, #ff8e3c 71%, #ffb956 100%); + } +} +.hero.is-danger { + background-color: #ff003c; + color: #121617; +} +.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-danger strong { + color: inherit; +} +.hero.is-danger .title { + color: #121617; +} +.hero.is-danger .subtitle { + color: rgba(18,22,23,0.9); +} +.hero.is-danger .subtitle a:not(.button), +.hero.is-danger .subtitle strong { + color: #121617; +} +@media screen and (max-width: 1087px) { + .hero.is-danger .navbar-menu { + background-color: #ff003c; + } +} +.hero.is-danger .navbar-item, +.hero.is-danger .navbar-link { + color: rgba(18,22,23,0.7); +} +.hero.is-danger a.navbar-item:hover, +.hero.is-danger .navbar-link:hover, +.hero.is-danger a.navbar-item.is-active, +.hero.is-danger .navbar-link.is-active { + background-color: #e60036; + color: #121617; +} +.hero.is-danger .tabs a { + color: #121617; + opacity: 0.9; +} +.hero.is-danger .tabs a:hover { + opacity: 1; +} +.hero.is-danger .tabs li.is-active a { + opacity: 1; +} +.hero.is-danger .tabs.is-boxed a, +.hero.is-danger .tabs.is-toggle a { + color: #121617; +} +.hero.is-danger .tabs.is-boxed a:hover, +.hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-danger .tabs.is-boxed li.is-active a, +.hero.is-danger .tabs.is-toggle li.is-active a, +.hero.is-danger .tabs.is-boxed li.is-active a:hover, +.hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #121617; + border-color: #121617; + color: #ff003c; +} +.hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #cc0052 0%, #ff003c 71%, #ff1a2a 100%); +} +@media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #cc0052 0%, #ff003c 71%, #ff1a2a 100%); + } +} +.hero.is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.hero.is-grey-lightest a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-grey-lightest strong { + color: inherit; +} +.hero.is-grey-lightest .title { + color: #363636; +} +.hero.is-grey-lightest .subtitle { + color: rgba(54,54,54,0.9); +} +.hero.is-grey-lightest .subtitle a:not(.button), +.hero.is-grey-lightest .subtitle strong { + color: #363636; +} +@media screen and (max-width: 1087px) { + .hero.is-grey-lightest .navbar-menu { + background-color: #ededed; + } +} +.hero.is-grey-lightest .navbar-item, +.hero.is-grey-lightest .navbar-link { + color: rgba(54,54,54,0.7); +} +.hero.is-grey-lightest a.navbar-item:hover, +.hero.is-grey-lightest .navbar-link:hover, +.hero.is-grey-lightest a.navbar-item.is-active, +.hero.is-grey-lightest .navbar-link.is-active { + background-color: #e0e0e0; + color: #363636; +} +.hero.is-grey-lightest .tabs a { + color: #363636; + opacity: 0.9; +} +.hero.is-grey-lightest .tabs a:hover { + opacity: 1; +} +.hero.is-grey-lightest .tabs li.is-active a { + opacity: 1; +} +.hero.is-grey-lightest .tabs.is-boxed a, +.hero.is-grey-lightest .tabs.is-toggle a { + color: #363636; +} +.hero.is-grey-lightest .tabs.is-boxed a:hover, +.hero.is-grey-lightest .tabs.is-toggle a:hover { + background-color: rgba(0,0,0,0.1); +} +.hero.is-grey-lightest .tabs.is-boxed li.is-active a, +.hero.is-grey-lightest .tabs.is-toggle li.is-active a, +.hero.is-grey-lightest .tabs.is-boxed li.is-active a:hover, +.hero.is-grey-lightest .tabs.is-toggle li.is-active a:hover { + background-color: #363636; + border-color: #363636; + color: #ededed; +} +.hero.is-grey-lightest.is-bold { + background-image: linear-gradient(141deg, #d8cfcf 0%, #ededed 71%, #faf9f9 100%); +} +@media screen and (max-width: 768px) { + .hero.is-grey-lightest.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #d8cfcf 0%, #ededed 71%, #faf9f9 100%); + } +} +.hero.is-small .hero-body { + padding-bottom: 1.5rem; + padding-top: 1.5rem; +} +@media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding-bottom: 9rem; + padding-top: 9rem; + } +} +@media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding-bottom: 18rem; + padding-top: 18rem; + } +} +.hero.is-halfheight .hero-body, +.hero.is-fullheight .hero-body, +.hero.is-fullheight-with-navbar .hero-body { + align-items: center; + display: flex; +} +.hero.is-halfheight .hero-body > .container, +.hero.is-fullheight .hero-body > .container, +.hero.is-fullheight-with-navbar .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; +} +.hero.is-halfheight { + min-height: 50vh; +} +.hero.is-fullheight { + min-height: 100vh; +} +.hero-video { + overflow: hidden; +} +.hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); +} +.hero-video.is-transparent { + opacity: 0.3; +} +@media screen and (max-width: 768px) { + .hero-video { + display: none; + } +} +.hero-buttons { + margin-top: 1.5rem; +} +@media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; + } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; + } +} +@media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; + } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; + } +} +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; +} +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: 3rem 1.5rem; +} +.section { + padding: 3rem 1.5rem; +} +@media screen and (min-width: 1088px) { + .section.is-medium { + padding: 9rem 1.5rem; + } + .section.is-large { + padding: 18rem 1.5rem; + } +} +.footer { + background-color: #fcee09; + padding: 3rem 1.5rem 6rem; + color: #000; +} +html { + height: 100%; + -webkit-text-size-adjust: 100%; + -moz-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + text-size-adjust: 100%; +} +body { + min-height: 100%; + display: flex; + flex-direction: column; +} +body > .section { + flex-grow: 1; +} +@media screen and (min-width: 1088px) { + ::-webkit-scrollbar { + width: 8px; + height: 8px; + } + ::-webkit-scrollbar-track { + border-radius: 3px; + background: rgba(0,0,0,0.06); + box-shadow: inset 0 0 5px rgba(0,0,0,0.1); + } + ::-webkit-scrollbar-thumb { + border-radius: 3px; + background: rgba(0,0,0,0.12); + box-shadow: inset 0 0 10px rgba(0,0,0,0.2); + } + ::-webkit-scrollbar-thumb:hover { + background: rgba(0,0,0,0.24); + } +} +.article-licensing .licensing-meta h6, +.article-licensing .licensing-title a, +.size-small { + font-size: 0.85rem !important; +} +.ml-0, +.mx-0 { + margin-left: 0 !important; +} +.mr-0, +.mx-0 { + margin-right: 0 !important; +} +.ml-n0, +.mx-n0 { + margin-left: 0 !important; +} +.mr-n0, +.mx-n0 { + margin-right: 0 !important; +} +.mt-0, +.my-0 { + margin-top: 0 !important; +} +.mb-0, +.my-0 { + margin-bottom: 0 !important; +} +.mt-n0, +.my-n0 { + margin-top: 0 !important; +} +.mb-n0, +.my-n0 { + margin-bottom: 0 !important; +} +.pl-0, +.px-0 { + padding-left: 0 !important; +} +.pr-0, +.px-0 { + padding-right: 0 !important; +} +.pl-n0, +.px-n0 { + padding-left: 0 !important; +} +.pr-n0, +.px-n0 { + padding-right: 0 !important; +} +.pt-0, +.py-0 { + padding-top: 0 !important; +} +.pb-0, +.py-0 { + padding-bottom: 0 !important; +} +.pt-n0, +.py-n0 { + padding-top: 0 !important; +} +.pb-n0, +.py-n0 { + padding-bottom: 0 !important; +} +.ml-1, +.mx-1 { + margin-left: 0.25rem !important; +} +.mr-1, +.mx-1, +.article-licensing .licensing-meta .icon { + margin-right: 0.25rem !important; +} +.ml-n1, +.mx-n1 { + margin-left: -0.25rem !important; +} +.mr-n1, +.mx-n1 { + margin-right: -0.25rem !important; +} +.mt-1, +.my-1 { + margin-top: 0.25rem !important; +} +.mb-1, +.my-1, +.article-licensing .licensing-title p:not(:last-child) { + margin-bottom: 0.25rem !important; +} +.mt-n1, +.my-n1 { + margin-top: -0.25rem !important; +} +.mb-n1, +.my-n1 { + margin-bottom: -0.25rem !important; +} +.pl-1, +.px-1 { + padding-left: 0.25rem !important; +} +.pr-1, +.px-1 { + padding-right: 0.25rem !important; +} +.pl-n1, +.px-n1 { + padding-left: -0.25rem !important; +} +.pr-n1, +.px-n1 { + padding-right: -0.25rem !important; +} +.pt-1, +.py-1 { + padding-top: 0.25rem !important; +} +.pb-1, +.py-1 { + padding-bottom: 0.25rem !important; +} +.pt-n1, +.py-n1 { + padding-top: -0.25rem !important; +} +.pb-n1, +.py-n1 { + padding-bottom: -0.25rem !important; +} +.ml-2, +.mx-2 { + margin-left: 0.5rem !important; +} +.mr-2, +.mx-2 { + margin-right: 0.5rem !important; +} +.ml-n2, +.mx-n2 { + margin-left: -0.5rem !important; +} +.mr-n2, +.mx-n2 { + margin-right: -0.5rem !important; +} +.mt-2, +.my-2 { + margin-top: 0.5rem !important; +} +.mb-2, +.my-2 { + margin-bottom: 0.5rem !important; +} +.mt-n2, +.my-n2 { + margin-top: -0.5rem !important; +} +.mb-n2, +.my-n2 { + margin-bottom: -0.5rem !important; +} +.pl-2, +.px-2 { + padding-left: 0.5rem !important; +} +.pr-2, +.px-2 { + padding-right: 0.5rem !important; +} +.pl-n2, +.px-n2 { + padding-left: -0.5rem !important; +} +.pr-n2, +.px-n2 { + padding-right: -0.5rem !important; +} +.pt-2, +.py-2 { + padding-top: 0.5rem !important; +} +.pb-2, +.py-2 { + padding-bottom: 0.5rem !important; +} +.pt-n2, +.py-n2 { + padding-top: -0.5rem !important; +} +.pb-n2, +.py-n2 { + padding-bottom: -0.5rem !important; +} +.ml-3, +.mx-3 { + margin-left: 1rem !important; +} +.mr-3, +.mx-3 { + margin-right: 1rem !important; +} +.ml-n3, +.mx-n3 { + margin-left: -1rem !important; +} +.mr-n3, +.mx-n3 { + margin-right: -1rem !important; +} +.mt-3, +.my-3 { + margin-top: 1rem !important; +} +.mb-3, +.my-3, +.article-licensing .licensing-title { + margin-bottom: 1rem !important; +} +.mt-n3, +.my-n3 { + margin-top: -1rem !important; +} +.mb-n3, +.my-n3 { + margin-bottom: -1rem !important; +} +.pl-3, +.px-3 { + padding-left: 1rem !important; +} +.pr-3, +.px-3 { + padding-right: 1rem !important; +} +.pl-n3, +.px-n3 { + padding-left: -1rem !important; +} +.pr-n3, +.px-n3 { + padding-right: -1rem !important; +} +.pt-3, +.py-3 { + padding-top: 1rem !important; +} +.pb-3, +.py-3 { + padding-bottom: 1rem !important; +} +.pt-n3, +.py-n3 { + padding-top: -1rem !important; +} +.pb-n3, +.py-n3 { + padding-bottom: -1rem !important; +} +.ml-4, +.mx-4 { + margin-left: 1.5rem !important; +} +.mr-4, +.mx-4, +.article-licensing .licensing-meta .level-item { + margin-right: 1.5rem !important; +} +.ml-n4, +.mx-n4 { + margin-left: -1.5rem !important; +} +.mr-n4, +.mx-n4 { + margin-right: -1.5rem !important; +} +.mt-4, +.my-4 { + margin-top: 1.5rem !important; +} +.mb-4, +.my-4 { + margin-bottom: 1.5rem !important; +} +.mt-n4, +.my-n4 { + margin-top: -1.5rem !important; +} +.mb-n4, +.my-n4 { + margin-bottom: -1.5rem !important; +} +.pl-4, +.px-4 { + padding-left: 1.5rem !important; +} +.pr-4, +.px-4 { + padding-right: 1.5rem !important; +} +.pl-n4, +.px-n4 { + padding-left: -1.5rem !important; +} +.pr-n4, +.px-n4 { + padding-right: -1.5rem !important; +} +.pt-4, +.py-4 { + padding-top: 1.5rem !important; +} +.pb-4, +.py-4 { + padding-bottom: 1.5rem !important; +} +.pt-n4, +.py-n4 { + padding-top: -1.5rem !important; +} +.pb-n4, +.py-n4 { + padding-bottom: -1.5rem !important; +} +.ml-5, +.mx-5 { + margin-left: 3rem !important; +} +.mr-5, +.mx-5 { + margin-right: 3rem !important; +} +.ml-n5, +.mx-n5 { + margin-left: -3rem !important; +} +.mr-n5, +.mx-n5 { + margin-right: -3rem !important; +} +.mt-5, +.my-5 { + margin-top: 3rem !important; +} +.mb-5, +.my-5 { + margin-bottom: 3rem !important; +} +.mt-n5, +.my-n5 { + margin-top: -3rem !important; +} +.mb-n5, +.my-n5 { + margin-bottom: -3rem !important; +} +.pl-5, +.px-5 { + padding-left: 3rem !important; +} +.pr-5, +.px-5 { + padding-right: 3rem !important; +} +.pl-n5, +.px-n5 { + padding-left: -3rem !important; +} +.pr-n5, +.px-n5 { + padding-right: -3rem !important; +} +.pt-5, +.py-5 { + padding-top: 3rem !important; +} +.pb-5, +.py-5 { + padding-bottom: 3rem !important; +} +.pt-n5, +.py-n5 { + padding-top: -3rem !important; +} +.pb-n5, +.py-n5 { + padding-bottom: -3rem !important; +} +.ml-auto, +.mx-auto { + margin-left: auto !important; +} +.mr-auto, +.mx-auto { + margin-right: auto !important; +} +.mt-auto, +.my-auto { + margin-top: auto !important; +} +.mb-auto, +.my-auto { + margin-bottom: auto !important; +} +.pl-auto, +.px-auto { + margin-left: auto !important; +} +.pr-auto, +.px-auto { + margin-right: auto !important; +} +.pt-auto, +.py-auto { + margin-top: auto !important; +} +.pb-auto, +.py-auto { + margin-bottom: auto !important; +} +.order-0 { + order: 0 !important; +} +.order-1 { + order: 1 !important; +} +.order-2 { + order: 2 !important; +} +.order-3 { + order: 3 !important; +} +.order-4 { + order: 4 !important; +} +.order-5 { + order: 5 !important; +} +.justify-content-start { + justify-content: start !important; +} +.justify-content-center { + justify-content: center !important; +} +.flex-shrink-1 { + flex-shrink: 1 !important; +} +.link-muted { + color: inherit; +} +.link-muted:hover { + color: #fcee09 !important; +} +.image.is-7by3 { + padding-top: 42.8%; +} +.image.is-7by3 img { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.image .avatar { + height: 100%; + object-fit: cover; +} +.image .fill { + object-fit: cover; + width: 100% !important; + height: 100% !important; +} +.button.is-transparent { + color: inherit; + background: transparent; + border-color: transparent; +} +.card { + overflow: visible; + border-radius: 0; +} +.card + .card, +.card + .column-right-shadow { + margin-top: 1.5rem; +} +.card .card-image { + overflow: hidden; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.card .media + .media { + border: none; + margin-top: 0; +} +article.media { + color: #848484; +} +article.media a { + color: inherit; +} +article.media a:hover { + color: #fcee09; +} +article.media .image { + width: 64px; + height: 64px; +} +article.media .image img { + object-fit: cover; + width: 100%; + height: 100%; +} +article.media .title { + margin-bottom: 0.25em; +} +article.media .media-content { + color: #848484; +} +article.media .media-content .title { + margin: 0; + line-height: inherit; +} +article.article .article-meta, +article.article .article-tags { + color: #848484; +} +article.article .article-meta { + overflow-x: auto; + margin-bottom: 0.5rem; +} +article.article .content { + word-wrap: break-word; + font-size: 1.1rem; +} +article.article .content h1 { + font-size: 1.75em; +} +article.article .content h2 { + font-size: 1.5em; +} +article.article .content h3 { + font-size: 1.25em; +} +article.article .content h4 { + font-size: 1.125em; +} +article.article .content h5 { + font-size: 1em; +} +article.article .content pre { + font-size: 0.85em; +} +article.article .content code { + padding: 0; + background: transparent; + overflow-wrap: break-word; +} +article.article .content blockquote.pullquote { + float: right; + max-width: 50%; + font-size: 1.15rem; + position: relative; +} +article.article .content blockquote footer strong + cite { + margin-left: 0.5em; +} +article.article .content .message.message-immersive { + border-radius: 0; + margin: 0 -1.5rem 1.5rem -1.5rem; +} +article.article .content .message.message-immersive .message-body { + border: none; +} +.rtl { + direction: rtl; +} +.rtl .level .level-item:not(:last-child), +.rtl .level.is-mobile .level-item:not(:last-child) { + margin-left: 0.75rem; + margin-right: 0; +} +.table-overflow { + overflow-x: auto; +} +.table-overflow table { + width: auto !important; +} +.table-overflow table th { + word-break: keep-all; +} +.video-container { + position: relative; + padding-bottom: 56.25%; + padding-top: 25px; + height: 0; +} +.video-container iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.article-licensing { + position: relative; + z-index: 1; + box-shadow: none; + background: #f5f5f5; + border-radius: 0; + overflow: hidden; +} +.article-licensing:after { + position: absolute; + z-index: -1; + right: -50px; + top: -87.87px; + content: '\f25e'; + font-size: 200px; + font-family: 'Font Awesome 5 Brands'; + opacity: 0.1; +} +.article-licensing .level-left { + flex-wrap: wrap; + max-width: 100%; +} +.article-licensing .licensing-title { + line-height: 1.2; +} +.article-licensing .licensing-meta .icon { + width: 1.2em; + height: 1.2em; + font-size: 1.2em; + vertical-align: bottom; +} +.article-licensing .licensing-meta a { + color: inherit; +} +a.article-nav-prev span { + text-align: left; + flex-shrink: 1; + word-wrap: break-word; + white-space: normal; +} +a.article-nav-next span { + text-align: right; + flex-shrink: 1; + word-wrap: break-word; + white-space: normal; +} +.navbar-main { + box-shadow: none; +} +.navbar-main .navbar-menu, +.navbar-main .navbar-start, +.navbar-main .navbar-end { + align-items: stretch; + display: flex; + padding: 0; + flex-shrink: 0; +} +.navbar-main .navbar-menu { + flex-grow: 1; + flex-shrink: 0; + overflow-x: auto; +} +.navbar-main .navbar-start { + justify-content: flex-start; + margin-right: auto; +} +.navbar-main .navbar-end { + justify-content: flex-end; + margin-left: auto; +} +.navbar-main .navbar-item { + display: flex; + align-items: center; + padding: 0 0.5rem; + margin: 1.25rem 0.25rem; +} +.navbar-main .navbar-item.is-active { + background-color: transparent; +} +@media screen and (max-width: 1087px) { + .navbar-main .navbar-menu { + justify-content: center; + box-shadow: none; + } + .navbar-main .navbar-start { + margin-right: 0; + } + .navbar-main .navbar-end { + margin-left: 0; + } +} +.navbar-logo img { + max-height: 1.75rem; +} +@media screen and (max-width: 768px) { + footer.footer .level-start { + text-align: center; + } +} +footer.footer .level-end .field { + flex-wrap: wrap; + align-items: center; +} +@media screen and (max-width: 768px) { + footer.footer .level-end .field { + justify-content: center; + margin-top: 1rem; + } +} +.footer-logo img { + max-height: 1.75rem; +} +.pagination { + margin-top: 1.5rem; +} +.pagination .pagination-link a, +.pagination .pagination-ellipsis a, +.pagination .pagination-previous a, +.pagination .pagination-next a { + color: #fcee09; +} +.pagination .pagination-link, +.pagination .pagination-previous, +.pagination .pagination-next { + border: none; + background: #000; + box-shadow: none, 0 0 1px rgba(0,0,0,0.1); +} +.pagination .pagination-link.is-current { + background: #02d7f2; +} +.post-navigation { + color: #cdcdcd; + flex-wrap: wrap; + justify-content: space-around; +} +.post-navigation .level-item { + margin-bottom: 0; +} +.timeline { + margin-left: 1rem; + padding: 1rem 0 0 1.5rem; + border-left: 1px solid #02d7f2; +} +.timeline .media { + position: relative; +} +.timeline .media:before, +.timeline .media:last-child:after { + content: ''; + display: block; + position: absolute; + left: calc(-0.375rem - 1.5rem - 0.25px); +} +.timeline .media:before { + width: 0.75rem; + height: 0.75rem; + top: calc(1rem + 1.5 * 0.85rem / 2 - 0.75rem / 2); + background: #02d7f2; + border-radius: 50%; +} +.timeline .media:first-child:before { + top: calc(1.5 * 0.85rem / 2 - 0.75rem / 2); +} +.timeline .media:last-child:after { + width: 0.75rem; + top: calc(1rem + 1.5 * 0.85rem / 2 + 0.75rem / 2); + bottom: 0; + background: #000; +} +.timeline .media:first-child:last-child:after { + top: calc(1.5 * 0.85rem / 2 + 0.75rem / 2); +} +.searchbox { + display: none; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 100; + font-size: 1rem; + line-height: 0; + background: rgba(0,0,0,0.86); +} +.searchbox.show { + display: flex; +} +.searchbox a, +.searchbox a:hover { + color: inherit; + text-decoration: none; +} +.searchbox input { + font-size: 1rem; + border: none; + outline: none; + box-shadow: none; + border-radius: 0; +} +.searchbox, +.searchbox .searchbox-container { + position: fixed; + align-items: center; + flex-direction: column; + line-height: 1.25em; +} +.searchbox .searchbox-container { + z-index: 101; + display: flex; + overflow: hidden; + box-shadow: none, 0 0 1px rgba(0,0,0,0.1); + border-radius: 0; + background-color: #050a0e; + width: 540px; + top: 100px; + bottom: 100px; +} +.searchbox .searchbox-header, +.searchbox .searchbox-body, +.searchbox .searchbox-footer { + width: 100%; +} +.searchbox .searchbox-header { + display: flex; + flex-direction: row; + line-height: 1.5em; + font-weight: normal; + background-color: #050a0e; + min-height: 3rem; +} +.searchbox .searchbox-input-container { + display: flex; + flex-grow: 1; +} +.searchbox .searchbox-input { + flex-grow: 1; + color: inherit; + box-sizing: border-box; + padding: 0.75em 0 0.75em 1.25em; + background: #050a0e; +} +.searchbox .searchbox-close { + display: inline-block; + font-size: 1.5em; + padding: 0.5em 0.75em; + cursor: pointer; +} +.searchbox .searchbox-close:hover { + background: #000; +} +.searchbox .searchbox-close:active { + background: #000; +} +.searchbox .searchbox-body { + flex-grow: 1; + overflow-y: auto; + border-top: 1px solid #02d7f2; +} +.searchbox .searchbox-result-section header, +.searchbox .searchbox-result-item { + padding: 0.75em 1em; +} +.searchbox .searchbox-result-section { + border-bottom: 1px solid #02d7f2; +} +.searchbox .searchbox-result-section header { + color: #b5b5b5; +} +.searchbox .searchbox-result-item { + display: flex; + flex-direction: row; +} +.searchbox .searchbox-result-item:not(.disabled):not(.active):not(:active):hover { + background-color: #000; +} +.searchbox .searchbox-result-item:active, +.searchbox .searchbox-result-item.active { + color: rgba(0,0,0,0.7); + background-color: #fcee09; +} +.searchbox .searchbox-result-item em { + font-style: normal; + background: #fcee09; +} +.searchbox .searchbox-result-icon { + margin-right: 1em; +} +.searchbox .searchbox-result-content { + overflow: hidden; +} +.searchbox .searchbox-result-title, +.searchbox .searchbox-result-preview { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.searchbox .searchbox-result-title-secondary { + color: #b5b5b5; +} +.searchbox .searchbox-result-preview { + margin-top: 0.25em; +} +.searchbox .searchbox-result-item:not(:active):not(.active) .searchbox-result-preview { + color: #b5b5b5; +} +.searchbox .searchbox-footer { + padding: 0.5em 1em; +} +.searchbox .searchbox-pagination { + margin: 0; + padding: 0; + list-style: none; + text-align: center; +} +.searchbox .searchbox-pagination .searchbox-pagination-item { + margin: 0 0.25rem; +} +.searchbox .searchbox-pagination .searchbox-pagination-item, +.searchbox .searchbox-pagination .searchbox-pagination-link { + display: inline-block; +} +.searchbox .searchbox-pagination .searchbox-pagination-link { + overflow: hidden; + padding: 0.5em 0.8em; + box-shadow: none, 0 0 1px rgba(0,0,0,0.1); + border-radius: 0; + background-color: #050a0e; +} +.searchbox .searchbox-pagination .searchbox-pagination-item.active .searchbox-pagination-link { + color: rgba(0,0,0,0.7); + background-color: #fcee09; +} +.searchbox .searchbox-pagination .searchbox-pagination-item.disabled .searchbox-pagination-link { + cursor: not-allowed; + background-color: #050a0e; +} +.searchbox .searchbox-pagination .searchbox-pagination-item:not(.active):not(.disabled) .searchbox-pagination-link:hover { + background-color: #050a0e; +} +@media screen and (max-width: 559px), screen and (max-height: 479px) { + .searchbox .searchbox-container { + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 0; + } +} +figure.highlight { + padding: 0; + width: 100%; + position: relative; + margin: 1em 0 1em !important; + border-radius: 0; +} +figure.highlight.folded .highlight-body { + height: 0; +} +figure.highlight .copy { + opacity: 0.7; +} +figure.highlight pre, +figure.highlight table tr:hover { + color: inherit; + background: transparent; +} +figure.highlight table { + width: auto; +} +figure.highlight table tr td { + border: none; +} +figure.highlight table tr:not(:first-child) td { + padding-top: 0; +} +figure.highlight table tr:not(:last-child) td { + padding-bottom: 0; +} +figure.highlight pre { + padding: 0; + overflow: visible; +} +figure.highlight pre .line, +figure.highlight pre code .hljs { + line-height: 1.5rem; +} +figure.highlight figcaption, +figure.highlight .gutter { + background: rgba(200,200,200,0.15); +} +figure.highlight figcaption { + margin: 0 !important; + padding: 0.3em 0em 0.3em 0.75em; + font-style: normal; + font-size: 0.8em; +} +figure.highlight figcaption * { + color: inherit; +} +figure.highlight figcaption span { + font-weight: 500; + font-family: 'Roboto Mono', monospace, 'Microsoft YaHei'; +} +figure.highlight figcaption .level-left *:not(:last-child) { + margin-right: 0.5em; +} +figure.highlight figcaption .level-right *:not(:first-child) { + margin-left: 0.5em; +} +figure.highlight figcaption .fold { + cursor: pointer; +} +figure.highlight figcaption.level { + overflow: auto; +} +figure.highlight figcaption.level .level-right a { + padding: 0em 0.75em; +} +figure.highlight .highlight-body { + overflow: auto; +} +figure.highlight .gutter { + text-align: right; +} +figure.highlight .tag, +figure.highlight .title, +figure.highlight .number, +figure.highlight .section { + display: inherit; + font: inherit; + margin: inherit; + padding: inherit; + background: inherit; + height: inherit; + text-align: inherit; + vertical-align: inherit; + min-width: inherit; + border-radius: inherit; +} +.gist table tr:hover { + background: transparent; +} +.gist table td { + border: none; +} +.gist .file { + all: initial; +} +.widget .menu-list li ul { + margin-right: 0; +} +.widget .menu-list .level { + margin-bottom: 0; +} +.widget .menu-list .level .level-left, +.widget .menu-list .level .level-right, +.widget .menu-list .level .level-item { + flex-shrink: 1; +} +.widget .menu-list .level .level-left, +.widget .menu-list .level .level-right { + align-items: flex-start; +} +.widget .menu-list .tag { + background: $light-grey; + color: $white-invert; +} +.widget .tags .tag:first-child { + background: #fcee09; + color: #121617; +} +.widget .tags .tag:last-child { + background: $light-grey; + color: $white-invert; +} +.donate { + position: relative; +} +.donate .qrcode { + display: none; + position: absolute; + z-index: 99; + bottom: 2.5em; + line-height: 0; + overflow: hidden; + box-shadow: none, 0 0 1px rgba(0,0,0,0.1); + border-radius: 0; +} +.donate .qrcode img { + max-width: 280px; +} +.donate:hover .qrcode { + display: block; +} +.donate:first-child:not(:last-child) .qrcode { + left: -0.75rem; +} +.donate:last-child:not(:first-child) .qrcode { + right: -0.75rem; +} +.donate[data-type="afdian"] { + color: #fff; + background-color: #885fd9; + border-color: transparent; +} +.donate[data-type="afdian"]:active { + background-color: #794ad4; +} +.donate[data-type="afdian"]:hover { + background-color: #8055d7; +} +.donate[data-type="afdian"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(136,95,217,0.25); +} +.donate[data-type="alipay"] { + color: #fff; + background-color: #00a0e8; + border-color: transparent; +} +.donate[data-type="alipay"]:active { + background-color: #008ecf; +} +.donate[data-type="alipay"]:hover { + background-color: #0097db; +} +.donate[data-type="alipay"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0,160,232,0.25); +} +.donate[data-type="buymeacoffee"] { + color: rgba(0,0,0,0.7); + background-color: #fd0; + border-color: transparent; +} +.donate[data-type="buymeacoffee"]:active { + background-color: #e6c700; +} +.donate[data-type="buymeacoffee"]:hover { + background-color: #f2d200; +} +.donate[data-type="buymeacoffee"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,221,0,0.25); +} +.donate[data-type="paypal"] { + color: rgba(0,0,0,0.7); + background-color: #feb700; + border-color: transparent; +} +.donate[data-type="paypal"]:active { + background-color: #e5a500; +} +.donate[data-type="paypal"]:hover { + background-color: #f1ae00; +} +.donate[data-type="paypal"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(254,183,0,0.25); +} +.donate[data-type="patreon"] { + color: #fff; + background-color: #ff424d; + border-color: transparent; +} +.donate[data-type="patreon"]:active { + background-color: #ff2835; +} +.donate[data-type="patreon"]:hover { + background-color: #ff3541; +} +.donate[data-type="patreon"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,66,77,0.25); +} +.donate[data-type="wechat"] { + color: #fff; + background-color: #1aad19; + border-color: transparent; +} +.donate[data-type="wechat"]:active { + background-color: #179716; +} +.donate[data-type="wechat"]:hover { + background-color: #18a217; +} +.donate[data-type="wechat"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(26,173,25,0.25); +} +#back-to-top { + position: fixed; + opacity: 0; + outline: none; + padding: 8px 0; + line-height: 24px; + border-radius: 0; + transform: translateY(120px); + transition: 0.4s ease opacity, 0.4s ease width, 0.4s ease transform, 0.4s ease border-radius; +} +#back-to-top.is-rounded { + border-radius: 50%; +} +#back-to-top.fade-in { + opacity: 1; +} +#back-to-top.rise-up { + transform: translateY(0); +} +.gallery-item .caption { + color: #848484; +} +@media screen and (max-width: 768px) { + #toc { + display: none; + position: fixed; + margin: 1rem; + left: 0; + right: 0; + bottom: 0; + z-index: 100; + max-height: calc(100vh - 2rem); + overflow-y: auto; + } + #toc-mask { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 99; + background: rgba(0,0,0,0.7); + } + #toc.is-active, + #toc-mask.is-active { + display: block; + } +} +.pace { + user-select: none; + pointer-events: none; +} +.pace .pace-progress { + top: 0; + right: 100%; + width: 100%; + height: 2px; + z-index: 2000; + position: fixed; + background: #fcee09; +} +.pace-inactive { + display: none; +} +.fa, +.fab, +.fal, +.far, +.fas { + line-height: inherit; +} +.MathJax, +.katex-display { + overflow-x: auto; + overflow-y: hidden; +} +.katex { + white-space: nowrap; +} +.katex-display { + margin-top: -1em !important; +} +.katex-html { + padding-top: 1em; +} +.katex-html .tag { + align-items: unset; + background-color: unset; + border-radius: unset; + color: unset; + display: unset; + font-size: unset; + height: unset; + justify-content: unset; + line-height: unset; + padding-left: unset; + padding-right: unset; + white-space: unset; +} +.cc-window, +.cc-revoke { + font-size: 1.1rem !important; + font-family: 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.cc-window { + color: #cdcdcd !important; + background-color: #000 !important; +} +.cc-window.cc-floating { + border-radius: 0; + box-shadow: none, 0 0 1px rgba(0,0,0,0.1); +} +.cc-window.cc-banner { + background-color: #000 !important; +} +.cc-window.cc-theme-block .cc-compliance > .cc-btn, +.cc-window.cc-theme-classic .cc-compliance > .cc-btn { + border-radius: 290486px; +} +.cc-window .cc-compliance > .cc-btn { + font-weight: 400; + border: none; + color: #121617; + background-color: #fcee09; +} +.cc-window .cc-compliance > .cc-btn:hover, +.cc-window .cc-compliance > .cc-btn:focus { + background-color: #f5e703; +} +.cc-window .cc-compliance > .cc-btn.cc-deny:hover { + color: #fcee09; + text-decoration: none; +} +.cc-revoke { + padding: 0.5rem 1rem !important; + color: #121617 !important; + background-color: #fcee09 !important; +} +.cc-revoke:hover { + text-decoration: none !important; + background-color: #f5e703; +} +@media screen and (min-width: 1280px) { + .is-1-column .container, + .is-2-column .container { + max-width: 960px; + width: 960px; + } +} +@media screen and (min-width: 1472px) { + .is-2-column .container { + max-width: 1152px; + width: 1152px; + } + .is-1-column .container { + max-width: 960px; + width: 960px; + } +} +@media screen and (min-width: 769px), print { + .is-sticky { + position: -webkit-sticky; + position: sticky; + top: 1.5rem; + z-index: 99; + } + .column-main.is-sticky, + .column-left.is-sticky, + .column-right.is-sticky, + .column-right-shadow.is-sticky { + top: 0.75rem; + align-self: flex-start; + } +} +@media screen and (max-width: 768px) { + .section { + padding: 1.5rem 1rem; + } +} +.display-none-class { + display: none; +} +.index-category-tag { + margin-bottom: 1rem; +} +.index-category-tag .level-item { + display: unset; +} +article.article .pin-icon { + color: #3273dc; + font-size: 1.6rem; + margin-right: 20px; + transform: rotate(30deg); + -ms-transform: rotate(30deg); + -moz-transform: rotate(30deg); + -webkit-transform: rotate(30deg); + -o-transform: rotate(30deg); +} +article.article .article-meta { + height: 41px; +} +.index-category-tag hr { + background-color: #f5f5f5; + margin-top: 0.3rem; + margin-bottom: 0.5rem; + box-shadow: unset; +} +.index-category-tag .button.is-small { + border-radius: 2px; + margin-bottom: 4px; + background-color: unset; +} +.index-categories, +.index-tags { + padding: 2px; +} +.recommend-post { + margin: 0 0 1.5rem 0; +} +.recommend-area { + background: #f5f5f5; + padding: 0.5rem 0.5rem; + margin: 0.5rem 0rem; +} +.function_ { + color: #ffdd57; +} +.class_ { + color: #ffdd57; +} +.navbar.is-fixed-top { + top: 0; +} +.navbar.is-fixed-bottom, +.navbar.is-fixed-top { + z-index: 100; +} +@media screen and (min-width: 1280px) { + .is-1-column .container, + .is-2-column .container, + .is-3-column .container { +/* 关闭评论图片 后调节 原94%*/ + max-width: 85%; /*screen-widescreen + 2 * extend-width - 2 * gap*/ + width: 85%; + } + .column.is-3-widescreen { + flex: none; + width: 24%; + } + .column.is-6-widescreen { + width: 52%; + } + .column.is-4-widescreen { + flex: none; + width: 24%; + } + .column.is-8-widescreen { + width: 76%; + } + .column.is-9-widescreen { + width: 76%; + } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: 0%; + } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: 0.5%; + } + .level-end { + margin-right: -1.5%; + } +} +@media screen and (min-width: 1472px) { + .is-2-column .container { + max-width: 1152px; + width: 1152px; + } + .is-1-column .container { + max-width: 960px; + width: 960px; + } +} +@media screen and (min-width: 769px), print { + .has-navbar-fixed-top .column-main.is-sticky, + .has-navbar-fixed-top .column-left.is-sticky, + .has-navbar-fixed-top .column-right.is-sticky, + .has-navbar-fixed-top .column-right-shadow.is-sticky, + .has-navbar-fixed-top .widget.is-sticky { + top: 5.5rem; + } +} +@media screen and (max-width: 768px) { + .section { + padding: 6.5rem 1.5rem; + } + .friend-card-item { + width: 100% !important; + } +} +.level-item .subtitle, +.level-item .title { + margin-bottom: 0; +} +#hitokoto { + text-align: center; + cursor: pointer; + padding: 1rem; +} +.level:not(:last-child) { + margin-bottom: 0.5rem; +} +hr { + margin: 0 0; +} +.donate .qrcode img { + max-width: 140px; +} +.body_hot_comment .comment-content { + font-size: 0.75em; + letter-spacing: 0.1em; +} +.body_hot_comment .comment-content .card-comment-item { + display: inline-block; + margin-top: 10px; + width: 100%; +} +.body_hot_comment .comment-content .card-comment-item .ava { + height: 3rem !important; + margin-right: 0.2em !important; + border-radius: 40px; +} +.body_hot_comment .comment-content .card-comment-item img { + float: left; + transition: all 0.5s ease-in; + -webkit-transition: all 0.5s ease-in; + -moz-transition: all 0.5s ease-in; + -o-transition: all 0.5s ease-in; +} +.body_hot_comment .comment-content .card-comment-item img:hover { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); +} +.body_hot_comment .comment-content :first-child { + margin-top: unset; +} +.body_hot_comment .comment-content .item-header-text { + padding-left: 0.75em; + font-size: 0.75rem; + line-height: 1.5; + -webkit-line-clamp: 1; + overflow: hidden; + -webkit-box-orient: vertical; + display: -webkit-box; +} +.body_hot_comment .comment-content .item-text { + padding-left: 0.75em; + font-size: 0.75rem; + line-height: 1.5; + -webkit-line-clamp: 2; + text-overflow: ellipsis; + overflow: hidden; + height: auto; + -webkit-box-orient: vertical; + word-break: break-all; + display: -webkit-box; + white-space: normal; +} +.level0 { + background-color: #d9e6fd; + color: #4a4a4a; +} +.level1 { + background-color: #8fb8fb; + color: #4a4a4a; +} +.level2 { + background-color: #5593f7; + color: #fff; +} +.level3 { + background-color: #3273dc; + color: #fff; +} +#index_hot_div { + margin-top: 10px; + display: flex; + flex-wrap: wrap; +} +#index_hot_div .item { + align-items: center; + border-radius: 4px; + display: inline-flex; + font-size: 0.75rem; + height: 2.1rem; + justify-content: center; + line-height: 1.5; + padding-left: 0.5rem; + padding-right: 0.5rem; + white-space: nowrap; + margin-bottom: 0.75rem; + box-shadow: 0px 0px 2px 1px #b5b5b5; +} +.post-calendar-pre { + overflow-x: auto; + justify-content: center; + max-width: 100%; +} +#post-calendar { + display: flex; + justify-context: center; + align-items: center; + left: 0px; + top: 0px; + width: 100%; + height: 200px; + -webkit-tap-highlight-color: rgba(0,0,0,0); + margin-bottom: 2rem; +} +.night { + color: #c0c0c0 !important; + background-color: #000; +} +.night .aplayer .aplayer-miniswitcher { + background: #c0c0c0 !important; +} +.night .navbar-highlight { + background-color: #151313 !important; +} +.night .content blockquote { + background-color: #151313; +} +.night .button.is-light { + background-color: #151313; +} +.night .tag:not(body) { + background-color: #151313; +} +.night strong { + color: #fff; +} +.night .time-axis-main .time-axis-achievement, +.night .time-axis-main .time-axis-title { + background-color: #151313; + color: #fff; +} +.night .pagination .pagination-link:not(.is-current), +.night .pagination .pagination-previous, +.night .pagination .pagination-next { + background-color: #151313; +} +.night .button.is-white { + color: #fff; +} +.night .button.is-light { + color: #c0c0c0; +} +.night a:hover { + color: #fff; +} +.night hr { + background-color: #151313; +} +.night .menu-list a:hover { + background-color: #7a7a7a; + color: #3273dc; +} +.night .menu-list a { + color: #c0c0c0; +} +.night .level a:hover { + color: #3273dc !important; +} +.night .level .is-rounded:hover { + color: #fff !important; +} +.night .level .level-item.is-marginless:hover { + background-color: #151313; + color: #3273dc; +} +.night .level .level-item.is-link:hover { + color: #fff; +} +.night .navbar-menu a:hover { + color: #3273dc; +} +.night .post-copyright { + background-color: #151313; +} +.night #back-to-top:hover { + color: #3273dc; +} +.night .tags.has-addons .tag:hover { + color: #3273dc; +} +.night input { + background-color: #000; + color: #fff; +} +.night .card { + color: #c0c0c0; +} +.night .has-text-grey { + color: #c0c0c0 !important; +} +.night .has-link-black-ter { + color: #3273dc !important; +} +.night .has-link-grey.-link { + color: #c0c0c0; +} +.night .has-link-grey, +.night .has-link-black-ter { + color: #c0c0c0 !important; +} +.night .menu-label { + color: #c0c0c0 !important; +} +.night .tag:not(body) { + color: #c0c0c0; +} +.night #body_hot_comment .comment-content .item { + color: #c0c0c0; +} +.night .has-text-black-ter { + color: #c0c0c0 !important; +} +.night .has-text-black-ter:hover { + color: #3273dc !important; +} +.night .navbar-item, +.night .navbar-link { + color: #c0c0c0; +} +.night .title { + color: #c0c0c0; +} +.night .level-item.tag.is-danger { + background-color: #3273dc !important; + color: #c0c0c0; +} +.night .friend-title-item { + color: #c0c0c0; +} +.night .music-container #musiclist { + background: #151313; +} +.night .meplayer-container { + background-color: #151313; +} +.night .navbar { + background-color: #151313; +} +.night .card { + background-color: #151313; +} +.night .footer { + background-color: #151313; +} +.night .button.is-white { + background-color: #151313; +} +.night .cardm { + background-color: #151313; +} +.night .waifu-tips { + background-color: #151313; + color: #c0c0c0; +} +.night .has-link-grey.-link:hover { + color: #3273dc !important; +} +.night .has-link-black-ter:hover { + color: #3273dc !important; +} +.night .timeline .media:last-child:after { + background-color: #151313; +} +.night .level-item.tag.is-danger, +.night .button:not(.is-white), +.night #index_hot_div, +.night #post-calendar canvas, +.night .waifu canvas, +.night .is-current, +.night .button.is-marginless .fab, +.night .fas, +.night .button.is-large, +.night .gt-btn, +.night .gt-comment-body pre, +.night .time-axis-main, +.night .meplayer-control-play, +.night .social-share, +.night .widget .tags .tag:first-child, +.night .g-emoji, +.night .fa-envelope, +.night input, +.night img { + filter: brightness(0.6) !important; +} +.night figure { + filter: brightness(0.7) !important; +} +.night strong { + filter: brightness(0.8) !important; +} +.night .content blockquote { + border-left: 3px solid #1e4584; +} +.night .timeline { + border-left: 1px solid rgba(219,219,219,0.439); +} +.night .timeline .media:before { + background: rgba(219,219,219,0.439); +} +.night .post-copyright { + border-left: 3px solid rgba(255,23,0,0.439); +} +.night .button.is-light { + filter: brightness(1) !important; +} +.night .breadcrumb li.is-active a { + color: #c0c0c0; +} +.night .menu-list li ul { + border-left: 1px solid rgba(219,219,219,0.439); +} +.night .markdown-body blockquote { + border-left: 0.25em solid rgba(223,226,229,0.565); +} +.night .gt-container .gt-comment-content { + background-color: #000 !important; + color: #c0c0c0 !important; +} +.night .gt-container .gt-comment-body { + color: #c0c0c0 !important; +} +.night .gt-container .gt-comment-content:hover { + -webkit-box-shadow: 0 0.625em 3.75em 0 #f4f4f4; + box-shadow: 0 0.625em 3.75em 0 #000; +} +.night textarea { + background-color: #151313; + color: #fff; +} +.night .gt-container .gt-header-textarea:hover { + background-color: #000; +} +.night .gt-container .gt-header-textarea { + background-color: #000; +} +.night .ins-section-container { + background-color: #151313; + color: #c0c0c0; +} +.night .searchbox .searchbox-input-wrapper .searchbox-input { + background-color: #151313; +} +.night .cardm { + color: unset; +} +.night .g-ads-x { + filter: brightness(0.6) !important; +} +.night .g-ads-y { + filter: brightness(0.6) !important; +} +.night .google-auto-placed { + filter: brightness(0.6) !important; +} +.night .pagination-previous, +.night .pagination-next, +.night .pagination-link { + color: #c0c0c0; +} +.night .pagination .pagination-link a, +.night .pagination .pagination-ellipsis a, +.night .pagination .pagination-previous a, +.night .pagination .pagination-next a { + color: #c0c0c0; +} +.night .content .gt-container .gt-comment-header { + background-color: #151313; +} +.night .content .gt-container .gt-comment-admin .gt-comment-content { + border: 2px solid #151313; +} +.night #post-calendar { + background-color: #626161; +} +.night .button.is-white, +.night .button.is-transparent { + color: #c0c0c0; +} +.night hr, +.night .index-category-tag hr { + background-color: #989898; +} +.night .navbar-menu { + background-color: unset; +} +.night #index_hot_div { + color: #c0c0c0; +} +.night #index_hot_div { + filter: unset !important; +} +.night #index_hot_div .item { + filter: brightness(0.6) !important; +} +.night .gt-container .gt-meta { + border-bottom: 2px solid #989898; +} +.night figure.highlight figcaption * { + color: unset; +} +.night figure.highlight figcaption.level .level-right a { + color: #c0c0c0; +} +.night .menu-list .is-current { + color: #3273dc; + background: #7a7a7a; + filter: unset !important; +} +.night .friend-card-item { + color: unset; +} +.night .g-ads-x, +.night .g-ads-y, +.night .google-auto-placed { + filter: brightness(0.6) !important; +} +.night .index-category-tag .button.is-small { + color: #c0c0c0; + filter: unset !important; +} +.night .index-category-tag .article-more:hover { + background-color: unset !important; +} +.night a.navbar-item:focus, +.night .navbar-link:focus, +.night a.navbar-item:focus-within, +.night .navbar-link:focus-within, +.night a.navbar-item:hover, +.night .navbar-link:hover, +.night a.navbar-item.is-active, +.night .navbar-link.is-active { + background-color: unset; + color: #3273dc; +} +.night .menu-list a.is-active { + background-color: #7a7a7a; + color: #3273dc; +} +.night .recommend-area, +.night .article-licensing { + background: #000; +} +.night .article-licensing .licensing-title a { + color: #3273dc !important; +} +.night .content h1, +.night .content h2, +.night .content h3, +.night .content h4, +.night .content h5, +.night .content h6 { + color: #c0c0c0; + font-weight: 800; +} +.night .navbar, +.night footer.footer, +.night .card { + background-color: rgba(21,19,19,0.678); +} +.aplayer-narrow { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} +.aplayer-narrow:hover { + -webkit-transform: translateX(0); + transform: translateX(0); +} +.aplayer { + transition: all 0.5s ease-out; +} +.aplayer .aplayer-miniswitcher { + background: #fff !important; +} +body, +button, +input, +select, +textarea { + font-family: AlimamaFangYuanTi, "PingFang SC", "Microsoft JhengHei", "Microsoft YaHei", sans-serif !important; +} +.img-x { + position: relative; + overflow-y: hidden; + height: 100%; + white-space: nowrap; +} +.img-x a { + box-sizing: border-box; + text-align: center; + position: relative; + display: inline-block; + padding: 10px 10px; + vertical-align: top; + height: 100%; + width: 40%; +} +.img-y { + position: relative; + overflow-y: hidden; + height: 100%; + white-space: nowrap; +} +.img-y a { + box-sizing: border-box; + text-align: center; + position: relative; + display: inline-block; + padding: 10px 10px; + vertical-align: top; + height: 100%; + width: 30%; +} +.article hr { + background-color: #6190e8; + margin-top: -0.8rem; + margin-bottom: 1rem; + box-shadow: 1px 2px 8px #000; +} +.index-category-tag hr { + background-color: #f5f5f5; + margin-top: 0.3rem; + margin-bottom: 0.5rem; + box-shadow: unset; +} +.friend-title-item { + font-weight: bold; + text-align: center; +} +.friend-card-item { + width: 32%; + border-radius: 2px; + color: #4a4a4a; + padding: 0.5rem; + display: inline-block; + margin: 5px; + margin-top: 15px; +} +.friend-card-item .text-desc { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.friend-card-item .ava { + width: 5rem !important; + height: 5rem !important; + margin: 0 !important; + margin-right: 0.2em !important; + border-radius: 40px; +} +.friend-card-item img { + float: left; + transition: all 0.5s ease-in; + -webkit-transition: all 0.5s ease-in; + -moz-transition: all 0.5s ease-in; + -o-transition: all 0.5s ease-in; +} +.friend-card-item img:hover { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); +} +.friend-card-item:hover { + transform: scale(0.995); + box-shadow: 0 2px 6px 0 rgba(0,0,0,0.12), 0 0 6px 0 rgba(0,0,0,0.04); +} +.content blockquote { + background-color: #f5f5f5; + border-left: 3px solid #6190e8; + padding: 1em 1em; + overflow: auto; +} +.time-axis-main { + width: 90%; + margin: 30px auto; +} +.time-axis-main .time-axis { + margin: 0; + padding: 0; + position: relative; +} +.time-axis-main .time-axis:before { + content: ''; + position: absolute; + left: 93px; + top: 15px; + width: 1px; + height: 100%; + background-color: #e4e4e4; +} +.time-axis-main .time-axis-item { + list-style: none; + padding-left: 150px; + position: relative; + line-height: 45px; + font-size: 14px; + color: #141414; +} +.time-axis-main .time-axis-date { + position: absolute; + left: -1.9%; + top: 0; + color: #3273dc; + font-style: italic; + font-weight: bold; +} +.time-axis-main .time-axis-title { + background-color: #f5f5f5; + border-left: 3px solid #6190e8; + padding: 0.8em 1em; + font-weight: bold; + line-height: 25px; +} +.time-axis-main .time-axis-achievement { + background-color: #f5f5f5; + border-left: 3px solid #e89b44; + padding: 0em 1em; + font-style: italic; + margin-bottom: 30px; +} +.time-axis-main .time-axis-date span { + position: absolute; + right: -25px; + top: 35%; + display: block; + width: 13px; + height: 13px; + border: 1px solid #ccc; + border-radius: 100%; + background-color: #fff; +} +.time-axis-main .time-axis-date span:after { + content: ''; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + width: 7px; + height: 7px; + margin: auto; + background-color: #ccc; + border: 1px solid #ccc; + border-radius: 100%; +} +.time-axis-main .time-axis-item:first-child .time-axis-date span { + border-color: #48beb2; +} +.time-axis-main .time-axis-item:first-child .time-axis-date span:after { + background-color: #48beb2; + border-color: #48beb2; +} +.music-container .video-player .fa-video-camera:before { + content: "\f03d"; +} +.music-container .video-player .fa-music:before { + content: "\f001"; +} +.music-container #musicarea { + margin: 20px auto; + width: 500px; +} +.music-container .music-player .d-title { + margin-bottom: 20px; + font-size: 2rem; + font-weight: 700; + text-align: center; +} +.video-player .d-title { + margin-bottom: 20px; + font-size: 2rem; + font-weight: 700; + text-align: center; +} +.video-player .fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.video-player .hits { + text-align: center; + font-size: 13px; + color: #cd0411; +} +.video-player #video-list { + overflow-y: auto; + height: 300px; +} +.video-player #video-list blockquote { + font-size: 13px; + text-align: center; + border-right: 3px solid #6190e8; +} +.text-center { + text-align: center; +} +.markdown-body { + font-family: 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.markdown-body img { + max-width: 30% !important; +} +#hitokoto { + text-align: center; + cursor: pointer; + padding: 1rem; +} +.text-tips { + text-align: center; + font-size: 0.875em; +} +.social-share { + text-align: center; +} +.level img { + border-radius: 100px; + transition: all 0.5s ease-in; + -webkit-transition: all 0.5s ease-in; + -moz-transition: all 0.5s ease-in; + -o-transition: all 0.5s ease-in; +} +.level figure img:hover { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); +} +.content .gt-container .gt-comment-edit { + margin-right: 2%; +} +.content a img { + margin: auto; + display: block; +} +.content .gt-container .gt-comment-admin .gt-comment-content { + border: 0.01em solid #deeafb; +} +.content .gt-container .gt-comment-header { + font-size: 0.875em; + position: relative; + display: inline-block; + left: -6%; + margin-bottom: 10px; + padding: 0 10% 0 32px; + height: 32px; + line-height: 32px; + border-radius: 0 3px 3px 0; + background-color: #deeafb; +} +.content .gt-container .gt-comment-content:hover { + -webkit-box-shadow: unset; + box-shadow: unset; +} +.content .gt-container .gt-comment-body { + padding-left: 2%; +} +.self-talking .gt-comment-reply .gt-ico-reply { + display: none; +} +.content .gt-container .gt-avatar { + display: none !important; +} +.article .content .markdown-body a img { + margin-right: 1%; + margin-top: 1%; + display: unset; +} +.gt-container .gt-comment-content:hover { + -webkit-box-shadow: unset !important; + box-shadow: unset !important; +} +.toc-scroll { + max-height: 500px; + overflow: auto; +} +.navbar-highlight { + background-color: #fff !important; +} +.gt-container .gt-comment-owner { + padding: 0.2em 0.2em !important; + margin: 0 0.5em 0 0.5em !important; +} +hr { + margin: 0rem 0; +} +.level:not(:last-child) { + margin-bottom: 0.5rem; +} +.post-navigation .level { + margin-bottom: 1rem; +} +.text-right { + text-align: right; +} +.text-left { + text-align: left; +} +.font1_1 { + font-size: 1.1rem; +} +.hljs-comment, +.hljs-quote { + color: #42bb35 !important; +} +body { + counter-reset: card; +} +::selection { + color: #000; + background: #02d7f2; +} +.card:not(#back-to-top) { + position: relative; + counter-increment: card; +} +.card:not(#back-to-top), +.card:not(#back-to-top) .card-content { + position: relative; +} +.card:not(#back-to-top):before, +.card:not(#back-to-top) .card-content:before { + content: ''; + position: absolute; + z-index: -1; + top: 0; + left: 0; + right: 0; + bottom: 0; +} +.card:not(#back-to-top):before { + top: -1.2px; + left: -1.2px; + right: -1.2px; + bottom: -1.2px; + background-color: #02d7f2; + clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 16px 100%, 0 calc(100% - 16px), 0 0); + -webkit-clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 16px 100%, 0 calc(100% - 16px), 0 0); +} +.card:not(#back-to-top):after { + content: 'R' counter(card); + position: absolute; + color: #02d7f2; + right: 2rem; + bottom: -0.6em; + font-size: 0.75rem; + padding: 0 0.25em; + background: #000; +} +.card:not(#back-to-top) .card-image { + clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 0 100%); + -webkit-clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 0 100%); +} +.card:not(#back-to-top) .card-content:before { + background-color: #000; + clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 16px 100%, 0 calc(100% - 16px), 0 0); + -webkit-clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 16px 100%, 0 calc(100% - 16px), 0 0); +} +.card:not(#back-to-top) .card-image + .card-content:before { + clip-path: polygon(0 0, 100% 0, 100% 100%, 16px 100%, 0 calc(100% - 16px)); + -webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 16px 100%, 0 calc(100% - 16px)); +} +.button:not(input) { + border: none; + outline: none; + background: transparent !important; + position: relative; +} +.button:not(input):before { + content: ''; + position: absolute; + z-index: -1; + top: 0; + left: 0; + right: 0; + bottom: 0; +} +.button:not(input):before { + clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); + -webkit-clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); +} +.button:not(input).is-white:before { + background-color: #fff; + color: #000; +} +.button:not(input).is-white:hover:before, +.button:not(input).is-white.is-hovered:before { + background-color: #f9f9f9; + color: #000; +} +.button:not(input).is-white:focus:before, +.button:not(input).is-white.is-focused:before { + color: #000; +} +.button:not(input).is-white:active:before, +.button:not(input).is-white.is-active:before { + background-color: #f2f2f2; + color: #000; +} +.button:not(input).is-white[disabled]:before, +fieldset[disabled] .button:not(input).is-white:before { + background-color: #fff; +} +.button:not(input).is-white.is-inverted:before { + background-color: #000; + color: #fff; +} +.button:not(input).is-white.is-inverted:before:hover:before, +.button:not(input).is-white.is-inverted:before.is-hovered:before { + background-color: #000; +} +.button:not(input).is-white.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-white.is-inverted:before:before { + background-color: #000; + border-color: transparent; + box-shadow: none; + color: #fff; +} +.button:not(input).is-black:before { + background-color: #000; + color: #fff; +} +.button:not(input).is-black:hover:before, +.button:not(input).is-black.is-hovered:before { + background-color: #000; + color: #fff; +} +.button:not(input).is-black:focus:before, +.button:not(input).is-black.is-focused:before { + color: #fff; +} +.button:not(input).is-black:active:before, +.button:not(input).is-black.is-active:before { + background-color: #000; + color: #fff; +} +.button:not(input).is-black[disabled]:before, +fieldset[disabled] .button:not(input).is-black:before { + background-color: #000; +} +.button:not(input).is-black.is-inverted:before { + background-color: #fff; + color: #000; +} +.button:not(input).is-black.is-inverted:before:hover:before, +.button:not(input).is-black.is-inverted:before.is-hovered:before { + background-color: #f2f2f2; +} +.button:not(input).is-black.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-black.is-inverted:before:before { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #000; +} +.button:not(input).is-light:before { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.button:not(input).is-light:hover:before, +.button:not(input).is-light.is-hovered:before { + background-color: #eee; + color: rgba(0,0,0,0.7); +} +.button:not(input).is-light:focus:before, +.button:not(input).is-light.is-focused:before { + color: rgba(0,0,0,0.7); +} +.button:not(input).is-light:active:before, +.button:not(input).is-light.is-active:before { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); +} +.button:not(input).is-light[disabled]:before, +fieldset[disabled] .button:not(input).is-light:before { + background-color: #f5f5f5; +} +.button:not(input).is-light.is-inverted:before { + background-color: rgba(0,0,0,0.7); + color: #f5f5f5; +} +.button:not(input).is-light.is-inverted:before:hover:before, +.button:not(input).is-light.is-inverted:before.is-hovered:before { + background-color: rgba(0,0,0,0.7); +} +.button:not(input).is-light.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-light.is-inverted:before:before { + background-color: rgba(0,0,0,0.7); + border-color: transparent; + box-shadow: none; + color: #f5f5f5; +} +.button:not(input).is-dark:before { + background-color: #363636; + color: #fff; +} +.button:not(input).is-dark:hover:before, +.button:not(input).is-dark.is-hovered:before { + background-color: #2f2f2f; + color: #fff; +} +.button:not(input).is-dark:focus:before, +.button:not(input).is-dark.is-focused:before { + color: #fff; +} +.button:not(input).is-dark:active:before, +.button:not(input).is-dark.is-active:before { + background-color: #292929; + color: #fff; +} +.button:not(input).is-dark[disabled]:before, +fieldset[disabled] .button:not(input).is-dark:before { + background-color: #363636; +} +.button:not(input).is-dark.is-inverted:before { + background-color: #fff; + color: #363636; +} +.button:not(input).is-dark.is-inverted:before:hover:before, +.button:not(input).is-dark.is-inverted:before.is-hovered:before { + background-color: #f2f2f2; +} +.button:not(input).is-dark.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-dark.is-inverted:before:before { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #363636; +} +.button:not(input).is-primary:before { + background-color: #fcee09; + color: #121617; +} +.button:not(input).is-primary:hover:before, +.button:not(input).is-primary.is-hovered:before { + background-color: #f5e703; + color: #121617; +} +.button:not(input).is-primary:focus:before, +.button:not(input).is-primary.is-focused:before { + color: #121617; +} +.button:not(input).is-primary:active:before, +.button:not(input).is-primary.is-active:before { + background-color: #e9db03; + color: #121617; +} +.button:not(input).is-primary[disabled]:before, +fieldset[disabled] .button:not(input).is-primary:before { + background-color: #fcee09; +} +.button:not(input).is-primary.is-inverted:before { + background-color: #121617; + color: #fcee09; +} +.button:not(input).is-primary.is-inverted:before:hover:before, +.button:not(input).is-primary.is-inverted:before.is-hovered:before { + background-color: #070809; +} +.button:not(input).is-primary.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-primary.is-inverted:before:before { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #fcee09; +} +.button:not(input).is-link:before { + background-color: #02d7f2; + color: rgba(0,0,0,0.7); +} +.button:not(input).is-link:hover:before, +.button:not(input).is-link.is-hovered:before { + background-color: #02cce5; + color: rgba(0,0,0,0.7); +} +.button:not(input).is-link:focus:before, +.button:not(input).is-link.is-focused:before { + color: rgba(0,0,0,0.7); +} +.button:not(input).is-link:active:before, +.button:not(input).is-link.is-active:before { + background-color: #02c1d9; + color: rgba(0,0,0,0.7); +} +.button:not(input).is-link[disabled]:before, +fieldset[disabled] .button:not(input).is-link:before { + background-color: #02d7f2; +} +.button:not(input).is-link.is-inverted:before { + background-color: rgba(0,0,0,0.7); + color: #02d7f2; +} +.button:not(input).is-link.is-inverted:before:hover:before, +.button:not(input).is-link.is-inverted:before.is-hovered:before { + background-color: rgba(0,0,0,0.7); +} +.button:not(input).is-link.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-link.is-inverted:before:before { + background-color: rgba(0,0,0,0.7); + border-color: transparent; + box-shadow: none; + color: #02d7f2; +} +.button:not(input).is-info:before { + background-color: #02d7f2; + color: #121617; +} +.button:not(input).is-info:hover:before, +.button:not(input).is-info.is-hovered:before { + background-color: #02cce5; + color: #121617; +} +.button:not(input).is-info:focus:before, +.button:not(input).is-info.is-focused:before { + color: #121617; +} +.button:not(input).is-info:active:before, +.button:not(input).is-info.is-active:before { + background-color: #02c1d9; + color: #121617; +} +.button:not(input).is-info[disabled]:before, +fieldset[disabled] .button:not(input).is-info:before { + background-color: #02d7f2; +} +.button:not(input).is-info.is-inverted:before { + background-color: #121617; + color: #02d7f2; +} +.button:not(input).is-info.is-inverted:before:hover:before, +.button:not(input).is-info.is-inverted:before.is-hovered:before { + background-color: #070809; +} +.button:not(input).is-info.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-info.is-inverted:before:before { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #02d7f2; +} +.button:not(input).is-success:before { + background-color: #00ff41; + color: #121617; +} +.button:not(input).is-success:hover:before, +.button:not(input).is-success.is-hovered:before { + background-color: #00f23e; + color: #121617; +} +.button:not(input).is-success:focus:before, +.button:not(input).is-success.is-focused:before { + color: #121617; +} +.button:not(input).is-success:active:before, +.button:not(input).is-success.is-active:before { + background-color: #00e63a; + color: #121617; +} +.button:not(input).is-success[disabled]:before, +fieldset[disabled] .button:not(input).is-success:before { + background-color: #00ff41; +} +.button:not(input).is-success.is-inverted:before { + background-color: #121617; + color: #00ff41; +} +.button:not(input).is-success.is-inverted:before:hover:before, +.button:not(input).is-success.is-inverted:before.is-hovered:before { + background-color: #070809; +} +.button:not(input).is-success.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-success.is-inverted:before:before { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #00ff41; +} +.button:not(input).is-warning:before { + background-color: #ff8e3c; + color: #121617; +} +.button:not(input).is-warning:hover:before, +.button:not(input).is-warning.is-hovered:before { + background-color: #ff872f; + color: #121617; +} +.button:not(input).is-warning:focus:before, +.button:not(input).is-warning.is-focused:before { + color: #121617; +} +.button:not(input).is-warning:active:before, +.button:not(input).is-warning.is-active:before { + background-color: #ff7f22; + color: #121617; +} +.button:not(input).is-warning[disabled]:before, +fieldset[disabled] .button:not(input).is-warning:before { + background-color: #ff8e3c; +} +.button:not(input).is-warning.is-inverted:before { + background-color: #121617; + color: #ff8e3c; +} +.button:not(input).is-warning.is-inverted:before:hover:before, +.button:not(input).is-warning.is-inverted:before.is-hovered:before { + background-color: #070809; +} +.button:not(input).is-warning.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-warning.is-inverted:before:before { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #ff8e3c; +} +.button:not(input).is-danger:before { + background-color: #ff003c; + color: #121617; +} +.button:not(input).is-danger:hover:before, +.button:not(input).is-danger.is-hovered:before { + background-color: #f20039; + color: #121617; +} +.button:not(input).is-danger:focus:before, +.button:not(input).is-danger.is-focused:before { + color: #121617; +} +.button:not(input).is-danger:active:before, +.button:not(input).is-danger.is-active:before { + background-color: #e60036; + color: #121617; +} +.button:not(input).is-danger[disabled]:before, +fieldset[disabled] .button:not(input).is-danger:before { + background-color: #ff003c; +} +.button:not(input).is-danger.is-inverted:before { + background-color: #121617; + color: #ff003c; +} +.button:not(input).is-danger.is-inverted:before:hover:before, +.button:not(input).is-danger.is-inverted:before.is-hovered:before { + background-color: #070809; +} +.button:not(input).is-danger.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-danger.is-inverted:before:before { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #ff003c; +} +.button:not(input).is-grey-lightest:before { + background-color: #ededed; + color: #363636; +} +.button:not(input).is-grey-lightest:hover:before, +.button:not(input).is-grey-lightest.is-hovered:before { + background-color: #e7e7e7; + color: #363636; +} +.button:not(input).is-grey-lightest:focus:before, +.button:not(input).is-grey-lightest.is-focused:before { + color: #363636; +} +.button:not(input).is-grey-lightest:active:before, +.button:not(input).is-grey-lightest.is-active:before { + background-color: #e0e0e0; + color: #363636; +} +.button:not(input).is-grey-lightest[disabled]:before, +fieldset[disabled] .button:not(input).is-grey-lightest:before { + background-color: #ededed; +} +.button:not(input).is-grey-lightest.is-inverted:before { + background-color: #363636; + color: #ededed; +} +.button:not(input).is-grey-lightest.is-inverted:before:hover:before, +.button:not(input).is-grey-lightest.is-inverted:before.is-hovered:before { + background-color: #292929; +} +.button:not(input).is-grey-lightest.is-inverted:before[disabled]:before, +fieldset[disabled] .button:not(input).is-grey-lightest.is-inverted:before:before { + background-color: #363636; + border-color: transparent; + box-shadow: none; + color: #ededed; +} +.field.has-addons .control:not(:first-child) .button { + clip-path: polygon(0 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%); + -webkit-clip-path: polygon(0 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%); +} +.menu-list a { + clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); + -webkit-clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); +} +.tags.has-addons .tag:first-child { + background: #fcee09 !important; +} +.tags.has-addons .tag:last-child { + background: #02d7f2 !important; +} +.pagination-previous, +.pagination-next, +.pagination-link { + clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); + -webkit-clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); +} +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover { + background-color: #02d7f2; +} +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover, +.pagination-previous:hover a, +.pagination-next:hover a, +.pagination-link:hover a { + color: #000; +} +.navbar-main { + padding-top: 10px; + padding-bottom: 30px; +} +.navbar-main:after { + content: ''; + position: absolute; + left: 0; + right: 0; + bottom: -2px; + background: url("../img/razor-top-black.svg") repeat-x top; + height: 40px; +} +.navbar-main .navbar-menu .navbar-item:hover, +.navbar-main .navbar-menu .navbar-item.is-active { + color: #fcee09; + background-color: #000 !important; +} +article.article .title a, +article.media .title a { + background-image: linear-gradient(transparent calc(100% - 2px), #fcee09 2px); + background-repeat: no-repeat; + background-size: 0 100%; + transition: background-size 0.25s ease-in-out; +} +article.article .title:hover a, +article.media .title:hover a { + background-size: 100% 100%; +} +article.article .article-more:before { + background-color: #02d7f2; + color: #121617; +} +article.article .article-more:hover:before, +article.article .article-more.is-hovered:before { + background-color: #02cce5; + color: #121617; +} +article.article .article-more:focus:before, +article.article .article-more.is-focused:before { + color: #121617; +} +article.article .article-more:active:before, +article.article .article-more.is-active:before { + background-color: #02c1d9; + color: #121617; +} +article.article .article-more[disabled]:before, +fieldset[disabled] article.article .article-more:before { + background-color: #02d7f2; +} +article.article .article-more.is-inverted:before { + background-color: #121617; + color: #02d7f2; +} +article.article .article-more.is-inverted:before:hover:before, +article.article .article-more.is-inverted:before.is-hovered:before { + background-color: #070809; +} +article.article .article-more.is-inverted:before[disabled]:before, +fieldset[disabled] article.article .article-more.is-inverted:before:before { + background-color: #121617; + border-color: transparent; + box-shadow: none; + color: #02d7f2; +} +.article-licensing { + background: #242424; +} +.content blockquote { + background: transparent; + border: 0.5px solid #02d7f2; + border-left: 5px solid #02d7f2; +} +.footer { + position: relative; +} +.footer:before { + content: ''; + position: absolute; + left: 0; + right: 0; + top: -1px; + height: 39px; + background: url("../img/razor-bottom-black.svg") repeat-x top; +} +.footer > .container { + padding-top: 40px; +} +.timeline .media:before { + clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); + -webkit-clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); +} +.searchbox .searchbox-container { + border: 1px solid #02d7f2; +} +.searchbox .searchbox-container .searchbox-body { + border-bottom: 1px solid #02d7f2; +} +.searchbox .searchbox-container .searchbox-body li:last-child .searchbox-result-section { + border-bottom: none; +} +.searchbox .searchbox-container .searchbox-result-item em { + color: #000; +} +#back-to-top { + color: #000; + background: #02d7f2; + margin-top: 45px; + clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); + -webkit-clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); +} +.cc-window, +.cc-revoke { + border-radius: 0 !important; +} +.cc-window:not(.cc-banner) { + border: 1px solid #02d7f2; +} +.cc-window.cc-theme-classic .cc-compliance > .cc-btn, +.cc-window.cc-theme-block .cc-compliance > .cc-btn { + border-radius: 0; +} +.cc-window.cc-banner .cc-compliance > .cc-btn { + background-color: #02d7f2; +} +.cc-window.cc-banner .cc-compliance > .cc-btn:hover, +.cc-window.cc-banner .cc-compliance > .cc-btn:focus { + background-color: #02cce5; +} diff --git a/css/default.css b/css/default.css new file mode 100644 index 0000000000..e37450d941 --- /dev/null +++ b/css/default.css @@ -0,0 +1,12605 @@ +@-moz-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +@-webkit-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +@-o-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +@keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +.is-unselectable, +.breadcrumb, +.modal-close, +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, +.tabs, +.button, +.delete, +.file { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.navbar-link:not(.is-arrowless)::after, +.select:not(.is-multiple):not(.is-loading)::after { + border: 3px solid transparent; + border-radius: 2px; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + width: 0.625em; +} +.breadcrumb:not(:last-child), +.level:not(:last-child), +.list:not(:last-child), +.message:not(:last-child), +.pagination:not(:last-child), +.tabs:not(:last-child), +.box:not(:last-child), +.content:not(:last-child), +.notification:not(:last-child), +.progress:not(:last-child), +.table:not(:last-child), +.table-container:not(:last-child), +.title:not(:last-child), +.subtitle:not(:last-child), +.block:not(:last-child), +.highlight:not(:last-child) { + margin-bottom: 1.5rem; +} +.modal-close, +.delete { + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10,10,10,0.2); + border: none; + border-radius: 290486px; + cursor: pointer; + pointer-events: auto; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; +} +.modal-close::before, +.delete::before, +.modal-close::after, +.delete::after { + background-color: #fff; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} +.modal-close::before, +.delete::before { + height: 2px; + width: 50%; +} +.modal-close::after, +.delete::after { + height: 50%; + width: 2px; +} +.modal-close:hover, +.delete:hover, +.modal-close:focus, +.delete:focus { + background-color: rgba(10,10,10,0.3); +} +.modal-close:active, +.delete:active { + background-color: rgba(10,10,10,0.4); +} +.modal-close.is-small, +.delete.is-small { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; +} +.modal-close.is-medium, +.delete.is-medium { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; +} +.modal-close.is-large, +.delete.is-large { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; +} +.button.is-loading::after, +.loader, +.select.is-loading::after, +.control.is-loading::after { + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 290486px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; +} +.is-overlay, +.modal, +.modal-background, +.image.is-square img, +.image.is-1by1 img, +.image.is-5by4 img, +.image.is-4by3 img, +.image.is-3by2 img, +.image.is-5by3 img, +.image.is-16by9 img, +.image.is-2by1 img, +.image.is-3by1 img, +.image.is-4by5 img, +.image.is-3by4 img, +.image.is-2by3 img, +.image.is-3by5 img, +.image.is-9by16 img, +.image.is-1by2 img, +.image.is-1by3 img, +.image.is-square .has-ratio, +.image.is-1by1 .has-ratio, +.image.is-5by4 .has-ratio, +.image.is-4by3 .has-ratio, +.image.is-3by2 .has-ratio, +.image.is-5by3 .has-ratio, +.image.is-16by9 .has-ratio, +.image.is-2by1 .has-ratio, +.image.is-3by1 .has-ratio, +.image.is-4by5 .has-ratio, +.image.is-3by4 .has-ratio, +.image.is-2by3 .has-ratio, +.image.is-3by5 .has-ratio, +.image.is-9by16 .has-ratio, +.image.is-1by2 .has-ratio, +.image.is-1by3 .has-ratio, +.hero-video { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, +.button, +.input, +.textarea, +.select select, +.file-cta, +.file-name { + -moz-appearance: none; + -webkit-appearance: none; + align-items: center; + border: 1px solid transparent; + border-radius: 4px; + box-shadow: none; + display: inline-flex; + font-size: 1rem; + height: 2.25em; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.5em - 1px); + padding-left: calc(0.75em - 1px); + padding-right: calc(0.75em - 1px); + padding-top: calc(0.5em - 1px); + position: relative; + vertical-align: top; +} +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus, +.pagination-ellipsis:focus, +.button:focus, +.input:focus, +.textarea:focus, +.select select:focus, +.file-cta:focus, +.file-name:focus, +.pagination-previous.is-focused, +.pagination-next.is-focused, +.pagination-link.is-focused, +.pagination-ellipsis.is-focused, +.button.is-focused, +.input.is-focused, +.textarea.is-focused, +.select select.is-focused, +.file-cta.is-focused, +.file-name.is-focused, +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active, +.pagination-ellipsis:active, +.button:active, +.input:active, +.textarea:active, +.select select:active, +.file-cta:active, +.file-name:active, +.pagination-previous.is-active, +.pagination-next.is-active, +.pagination-link.is-active, +.pagination-ellipsis.is-active, +.button.is-active, +.input.is-active, +.textarea.is-active, +.select select.is-active, +.file-cta.is-active, +.file-name.is-active { + outline: none; +} +.pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled], +.pagination-ellipsis[disabled], +.button[disabled], +.input[disabled], +.textarea[disabled], +.select select[disabled], +.file-cta[disabled], +.file-name[disabled], +fieldset[disabled] .pagination-previous, +fieldset[disabled] .pagination-next, +fieldset[disabled] .pagination-link, +fieldset[disabled] .pagination-ellipsis, +fieldset[disabled] .button, +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select, +fieldset[disabled] .file-cta, +fieldset[disabled] .file-name { + cursor: not-allowed; +} +/* minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} +ul { + list-style: none; +} +button, +input, +select, +textarea { + margin: 0; +} +html { + box-sizing: border-box; +} +*, +*::before, +*::after { + box-sizing: inherit; +} +img, +video { + height: auto; + max-width: 100%; +} +iframe { + border: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +td:not([align]), +th:not([align]) { + text-align: left; +} +html { + background-color: #f7f7f7; + font-size: 14px; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + text-size-adjust: 100%; +} +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; +} +body, +button, +input, +select, +textarea { + font-family: Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif; +} +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: 'Source Code Pro', monospace, 'Microsoft YaHei'; +} +body { + color: #4a4a4a; + font-size: 1em; + font-weight: 400; + line-height: 1.5; +} +a { + color: #3273dc; + cursor: pointer; + text-decoration: none; +} +a strong { + color: currentColor; +} +a:hover { + color: #363636; +} +code { + background-color: #f5f5f5; + color: #f14668; + font-size: 0.875em; + font-weight: normal; + padding: 0.25em 0.5em 0.25em; +} +hr { + background-color: #f5f5f5; + border: none; + display: block; + height: 2px; + margin: 1.5rem 0; +} +img { + height: auto; + max-width: 100%; +} +input[type="checkbox"], +input[type="radio"] { + vertical-align: baseline; +} +small { + font-size: 0.875em; +} +span { + font-style: inherit; + font-weight: inherit; +} +strong { + color: #363636; + font-weight: 700; +} +fieldset { + border: none; +} +pre { + -webkit-overflow-scrolling: touch; + background-color: #f5f5f5; + color: #4a4a4a; + font-size: 0.875em; + overflow-x: auto; + padding: 1.25rem 1.5rem; + white-space: pre; + word-wrap: normal; +} +pre code { + background-color: transparent; + color: currentColor; + font-size: 1em; + padding: 0; +} +table td, +table th { + vertical-align: top; +} +table td:not([align]), +table th:not([align]) { + text-align: left; +} +table th { + color: #363636; +} +.is-clearfix::after { + clear: both; + content: " "; + display: table; +} +.is-pulled-left { + float: left !important; +} +.is-pulled-right { + float: right !important; +} +.is-clipped { + overflow: hidden !important; +} +.is-size-1 { + font-size: 3rem !important; +} +.is-size-2 { + font-size: 2.5rem !important; +} +.is-size-3 { + font-size: 2rem !important; +} +.is-size-4 { + font-size: 1.5rem !important; +} +.is-size-5 { + font-size: 1.25rem !important; +} +.is-size-6, +article.media .title { + font-size: 1rem !important; +} +.is-size-7, +article.media .date, +article.media .categories, +.article-licensing .licensing-title a, +.article-licensing .licensing-meta h6 { + font-size: 0.85rem !important; +} +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; + } + .is-size-2-mobile { + font-size: 2.5rem !important; + } + .is-size-3-mobile { + font-size: 2rem !important; + } + .is-size-4-mobile { + font-size: 1.5rem !important; + } + .is-size-5-mobile { + font-size: 1.25rem !important; + } + .is-size-6-mobile { + font-size: 1rem !important; + } + .is-size-7-mobile { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; + } + .is-size-2-tablet { + font-size: 2.5rem !important; + } + .is-size-3-tablet { + font-size: 2rem !important; + } + .is-size-4-tablet { + font-size: 1.5rem !important; + } + .is-size-5-tablet { + font-size: 1.25rem !important; + } + .is-size-6-tablet { + font-size: 1rem !important; + } + .is-size-7-tablet { + font-size: 0.85rem !important; + } +} +@media screen and (max-width: 1087px) { + .is-size-1-touch { + font-size: 3rem !important; + } + .is-size-2-touch { + font-size: 2.5rem !important; + } + .is-size-3-touch { + font-size: 2rem !important; + } + .is-size-4-touch { + font-size: 1.5rem !important; + } + .is-size-5-touch { + font-size: 1.25rem !important; + } + .is-size-6-touch { + font-size: 1rem !important; + } + .is-size-7-touch { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 1088px) { + .is-size-1-desktop { + font-size: 3rem !important; + } + .is-size-2-desktop { + font-size: 2.5rem !important; + } + .is-size-3-desktop { + font-size: 2rem !important; + } + .is-size-4-desktop { + font-size: 1.5rem !important; + } + .is-size-5-desktop { + font-size: 1.25rem !important; + } + .is-size-6-desktop { + font-size: 1rem !important; + } + .is-size-7-desktop { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 1280px) { + .is-size-1-widescreen { + font-size: 3rem !important; + } + .is-size-2-widescreen { + font-size: 2.5rem !important; + } + .is-size-3-widescreen { + font-size: 2rem !important; + } + .is-size-4-widescreen { + font-size: 1.5rem !important; + } + .is-size-5-widescreen { + font-size: 1.25rem !important; + } + .is-size-6-widescreen { + font-size: 1rem !important; + } + .is-size-7-widescreen { + font-size: 0.85rem !important; + } +} +@media screen and (min-width: 1472px) { + .is-size-1-fullhd { + font-size: 3rem !important; + } + .is-size-2-fullhd { + font-size: 2.5rem !important; + } + .is-size-3-fullhd { + font-size: 2rem !important; + } + .is-size-4-fullhd { + font-size: 1.5rem !important; + } + .is-size-5-fullhd { + font-size: 1.25rem !important; + } + .is-size-6-fullhd { + font-size: 1rem !important; + } + .is-size-7-fullhd { + font-size: 0.85rem !important; + } +} +.has-text-centered { + text-align: center !important; +} +.has-text-justified { + text-align: justify !important; +} +.has-text-left { + text-align: left !important; +} +.has-text-right { + text-align: right !important; +} +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-centered-tablet-only { + text-align: center !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-centered-touch { + text-align: center !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-centered-desktop { + text-align: center !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-centered-desktop-only { + text-align: center !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-centered-widescreen { + text-align: center !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-centered-widescreen-only { + text-align: center !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-centered-fullhd { + text-align: center !important; + } +} +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-justified-tablet-only { + text-align: justify !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-justified-touch { + text-align: justify !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-justified-desktop { + text-align: justify !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-justified-desktop-only { + text-align: justify !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-justified-widescreen { + text-align: justify !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-justified-widescreen-only { + text-align: justify !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-justified-fullhd { + text-align: justify !important; + } +} +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-left-tablet-only { + text-align: left !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-left-touch { + text-align: left !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-left-desktop { + text-align: left !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-left-desktop-only { + text-align: left !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-left-widescreen { + text-align: left !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-left-widescreen-only { + text-align: left !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-left-fullhd { + text-align: left !important; + } +} +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-right-tablet-only { + text-align: right !important; + } +} +@media screen and (max-width: 1087px) { + .has-text-right-touch { + text-align: right !important; + } +} +@media screen and (min-width: 1088px) { + .has-text-right-desktop { + text-align: right !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-right-desktop-only { + text-align: right !important; + } +} +@media screen and (min-width: 1280px) { + .has-text-right-widescreen { + text-align: right !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .has-text-right-widescreen-only { + text-align: right !important; + } +} +@media screen and (min-width: 1472px) { + .has-text-right-fullhd { + text-align: right !important; + } +} +.is-capitalized { + text-transform: capitalize !important; +} +.is-lowercase { + text-transform: lowercase !important; +} +.is-uppercase, +article.media .categories { + text-transform: uppercase !important; +} +.is-italic { + font-style: italic !important; +} +.has-text-white { + color: #fff !important; +} +a.has-text-white:hover, +a.has-text-white:focus { + color: #e6e6e6 !important; +} +.has-background-white { + background-color: #fff !important; +} +.has-text-black { + color: #0a0a0a !important; +} +a.has-text-black:hover, +a.has-text-black:focus { + color: #000 !important; +} +.has-background-black { + background-color: #0a0a0a !important; +} +.has-text-light { + color: #f5f5f5 !important; +} +a.has-text-light:hover, +a.has-text-light:focus { + color: #dbdbdb !important; +} +.has-background-light { + background-color: #f5f5f5 !important; +} +.has-text-dark { + color: #363636 !important; +} +a.has-text-dark:hover, +a.has-text-dark:focus { + color: #1c1c1c !important; +} +.has-background-dark { + background-color: #363636 !important; +} +.has-text-primary { + color: #3273dc !important; +} +a.has-text-primary:hover, +a.has-text-primary:focus { + color: #205bbc !important; +} +.has-background-primary { + background-color: #3273dc !important; +} +.has-text-link { + color: #3273dc !important; +} +a.has-text-link:hover, +a.has-text-link:focus { + color: #205bbc !important; +} +.has-background-link { + background-color: #3273dc !important; +} +.has-text-info { + color: #3298dc !important; +} +a.has-text-info:hover, +a.has-text-info:focus { + color: #207dbc !important; +} +.has-background-info { + background-color: #3298dc !important; +} +.has-text-success { + color: #48c774 !important; +} +a.has-text-success:hover, +a.has-text-success:focus { + color: #34a85c !important; +} +.has-background-success { + background-color: #48c774 !important; +} +.has-text-warning { + color: #ffdd57 !important; +} +a.has-text-warning:hover, +a.has-text-warning:focus { + color: #ffd324 !important; +} +.has-background-warning { + background-color: #ffdd57 !important; +} +.has-text-danger { + color: #f14668 !important; +} +a.has-text-danger:hover, +a.has-text-danger:focus { + color: #ee1742 !important; +} +.has-background-danger { + background-color: #f14668 !important; +} +.has-text-grey-lightest { + color: #ededed !important; +} +a.has-text-grey-lightest:hover, +a.has-text-grey-lightest:focus { + color: #d4d4d4 !important; +} +.has-background-grey-lightest { + background-color: #ededed !important; +} +.has-text-black-bis { + color: #121212 !important; +} +.has-background-black-bis { + background-color: #121212 !important; +} +.has-text-black-ter { + color: #242424 !important; +} +.has-background-black-ter { + background-color: #242424 !important; +} +.has-text-grey-darker { + color: #363636 !important; +} +.has-background-grey-darker { + background-color: #363636 !important; +} +.has-text-grey-dark { + color: #4a4a4a !important; +} +.has-background-grey-dark { + background-color: #4a4a4a !important; +} +.has-text-grey, +.article-licensing .licensing-title a { + color: #7a7a7a !important; +} +.has-background-grey { + background-color: #7a7a7a !important; +} +.has-text-grey-light { + color: #b5b5b5 !important; +} +.has-background-grey-light { + background-color: #b5b5b5 !important; +} +.has-text-grey-lighter { + color: #dbdbdb !important; +} +.has-background-grey-lighter { + background-color: #dbdbdb !important; +} +.has-text-white-ter { + color: #f5f5f5 !important; +} +.has-background-white-ter { + background-color: #f5f5f5 !important; +} +.has-text-white-bis { + color: #fafafa !important; +} +.has-background-white-bis { + background-color: #fafafa !important; +} +.has-text-weight-light { + font-weight: 300 !important; +} +.has-text-weight-normal { + font-weight: 400 !important; +} +.has-text-weight-medium { + font-weight: 500 !important; +} +.has-text-weight-semibold { + font-weight: 600 !important; +} +.has-text-weight-bold { + font-weight: 700 !important; +} +.is-family-primary { + font-family: Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.is-family-secondary { + font-family: Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.is-family-sans-serif { + font-family: Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.is-family-monospace { + font-family: monospace !important; +} +.is-family-code { + font-family: 'Source Code Pro', monospace, 'Microsoft YaHei' !important; +} +.is-block { + display: block !important; +} +@media screen and (max-width: 768px) { + .is-block-mobile { + display: block !important; + } +} +@media screen and (min-width: 769px), print { + .is-block-tablet { + display: block !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-block-tablet-only { + display: block !important; + } +} +@media screen and (max-width: 1087px) { + .is-block-touch { + display: block !important; + } +} +@media screen and (min-width: 1088px) { + .is-block-desktop { + display: block !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-block-desktop-only { + display: block !important; + } +} +@media screen and (min-width: 1280px) { + .is-block-widescreen { + display: block !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-block-widescreen-only { + display: block !important; + } +} +@media screen and (min-width: 1472px) { + .is-block-fullhd { + display: block !important; + } +} +.is-flex { + display: flex !important; +} +@media screen and (max-width: 768px) { + .is-flex-mobile { + display: flex !important; + } +} +@media screen and (min-width: 769px), print { + .is-flex-tablet { + display: flex !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-flex-tablet-only { + display: flex !important; + } +} +@media screen and (max-width: 1087px) { + .is-flex-touch { + display: flex !important; + } +} +@media screen and (min-width: 1088px) { + .is-flex-desktop { + display: flex !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-flex-desktop-only { + display: flex !important; + } +} +@media screen and (min-width: 1280px) { + .is-flex-widescreen { + display: flex !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-flex-widescreen-only { + display: flex !important; + } +} +@media screen and (min-width: 1472px) { + .is-flex-fullhd { + display: flex !important; + } +} +.is-inline { + display: inline !important; +} +@media screen and (max-width: 768px) { + .is-inline-mobile { + display: inline !important; + } +} +@media screen and (min-width: 769px), print { + .is-inline-tablet { + display: inline !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-tablet-only { + display: inline !important; + } +} +@media screen and (max-width: 1087px) { + .is-inline-touch { + display: inline !important; + } +} +@media screen and (min-width: 1088px) { + .is-inline-desktop { + display: inline !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-desktop-only { + display: inline !important; + } +} +@media screen and (min-width: 1280px) { + .is-inline-widescreen { + display: inline !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-inline-widescreen-only { + display: inline !important; + } +} +@media screen and (min-width: 1472px) { + .is-inline-fullhd { + display: inline !important; + } +} +.is-inline-block { + display: inline-block !important; +} +@media screen and (max-width: 768px) { + .is-inline-block-mobile { + display: inline-block !important; + } +} +@media screen and (min-width: 769px), print { + .is-inline-block-tablet { + display: inline-block !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-block-tablet-only { + display: inline-block !important; + } +} +@media screen and (max-width: 1087px) { + .is-inline-block-touch { + display: inline-block !important; + } +} +@media screen and (min-width: 1088px) { + .is-inline-block-desktop { + display: inline-block !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-block-desktop-only { + display: inline-block !important; + } +} +@media screen and (min-width: 1280px) { + .is-inline-block-widescreen { + display: inline-block !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-inline-block-widescreen-only { + display: inline-block !important; + } +} +@media screen and (min-width: 1472px) { + .is-inline-block-fullhd { + display: inline-block !important; + } +} +.is-inline-flex { + display: inline-flex !important; +} +@media screen and (max-width: 768px) { + .is-inline-flex-mobile { + display: inline-flex !important; + } +} +@media screen and (min-width: 769px), print { + .is-inline-flex-tablet { + display: inline-flex !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-flex-tablet-only { + display: inline-flex !important; + } +} +@media screen and (max-width: 1087px) { + .is-inline-flex-touch { + display: inline-flex !important; + } +} +@media screen and (min-width: 1088px) { + .is-inline-flex-desktop { + display: inline-flex !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-flex-desktop-only { + display: inline-flex !important; + } +} +@media screen and (min-width: 1280px) { + .is-inline-flex-widescreen { + display: inline-flex !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-inline-flex-widescreen-only { + display: inline-flex !important; + } +} +@media screen and (min-width: 1472px) { + .is-inline-flex-fullhd { + display: inline-flex !important; + } +} +.is-hidden { + display: none !important; +} +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; +} +@media screen and (max-width: 768px) { + .is-hidden-mobile { + display: none !important; + } +} +@media screen and (min-width: 769px), print { + .is-hidden-tablet { + display: none !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-hidden-tablet-only { + display: none !important; + } +} +@media screen and (max-width: 1087px) { + .is-hidden-touch { + display: none !important; + } +} +@media screen and (min-width: 1088px) { + .is-hidden-desktop { + display: none !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-hidden-desktop-only { + display: none !important; + } +} +@media screen and (min-width: 1280px) { + .is-hidden-widescreen { + display: none !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-hidden-widescreen-only { + display: none !important; + } +} +@media screen and (min-width: 1472px) { + .is-hidden-fullhd { + display: none !important; + } +} +.is-invisible { + visibility: hidden !important; +} +@media screen and (max-width: 768px) { + .is-invisible-mobile { + visibility: hidden !important; + } +} +@media screen and (min-width: 769px), print { + .is-invisible-tablet { + visibility: hidden !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-invisible-tablet-only { + visibility: hidden !important; + } +} +@media screen and (max-width: 1087px) { + .is-invisible-touch { + visibility: hidden !important; + } +} +@media screen and (min-width: 1088px) { + .is-invisible-desktop { + visibility: hidden !important; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-invisible-desktop-only { + visibility: hidden !important; + } +} +@media screen and (min-width: 1280px) { + .is-invisible-widescreen { + visibility: hidden !important; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .is-invisible-widescreen-only { + visibility: hidden !important; + } +} +@media screen and (min-width: 1472px) { + .is-invisible-fullhd { + visibility: hidden !important; + } +} +.is-marginless { + margin: 0 !important; +} +.is-paddingless { + padding: 0 !important; +} +.is-radiusless { + border-radius: 0 !important; +} +.is-shadowless { + box-shadow: none !important; +} +.is-relative { + position: relative !important; +} +.breadcrumb { + font-size: 1rem; + white-space: nowrap; +} +.breadcrumb a { + align-items: center; + color: #3273dc; + display: flex; + justify-content: center; + padding: 0 0.75em; +} +.breadcrumb a:hover { + color: #363636; +} +.breadcrumb li { + align-items: center; + display: flex; +} +.breadcrumb li:first-child a { + padding-left: 0; +} +.breadcrumb li.is-active a { + color: #363636; + cursor: default; + pointer-events: none; +} +.breadcrumb li + li::before { + color: #b5b5b5; + content: "\0002f"; +} +.breadcrumb ul, +.breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.breadcrumb .icon:first-child { + margin-right: 0.5em; +} +.breadcrumb .icon:last-child { + margin-left: 0.5em; +} +.breadcrumb.is-centered ol, +.breadcrumb.is-centered ul { + justify-content: center; +} +.breadcrumb.is-right ol, +.breadcrumb.is-right ul { + justify-content: flex-end; +} +.breadcrumb.is-small { + font-size: 0.75rem; +} +.breadcrumb.is-medium { + font-size: 1.25rem; +} +.breadcrumb.is-large { + font-size: 1.5rem; +} +.breadcrumb.has-arrow-separator li + li::before { + content: "\02192"; +} +.breadcrumb.has-bullet-separator li + li::before { + content: "\02022"; +} +.breadcrumb.has-dot-separator li + li::before { + content: "\000b7"; +} +.breadcrumb.has-succeeds-separator li + li::before { + content: "\0227B"; +} +.card { + background-color: #fff; + box-shadow: 0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1); + color: #4a4a4a; + max-width: 100%; + position: relative; +} +.card-header { + background-color: transparent; + align-items: stretch; + box-shadow: 0 0.125em 0.25em rgba(10,10,10,0.1); + display: flex; +} +.card-header-title { + align-items: center; + color: #363636; + display: flex; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem 1rem; +} +.card-header-title.is-centered { + justify-content: center; +} +.card-header-icon { + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: 0.75rem 1rem; +} +.card-image { + display: block; + position: relative; +} +.card-content { + background-color: transparent; + padding: 1.5rem; +} +.card-footer { + background-color: transparent; + border-top: 1px solid #ededed; + align-items: stretch; + display: flex; +} +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: 0.75rem; +} +.card-footer-item:not(:last-child) { + border-right: 1px solid #ededed; +} +.card .media:not(:last-child) { + margin-bottom: 0.75rem; +} +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; +} +.dropdown.is-active .dropdown-menu, +.dropdown.is-hoverable:hover .dropdown-menu { + display: block; +} +.dropdown.is-right .dropdown-menu { + left: auto; + right: 0; +} +.dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: initial; + top: auto; +} +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; +} +.dropdown-content { + background-color: #fff; + border-radius: 4px; + box-shadow: 0 0.5em 1em -0.125em rgba(10,10,10,0.1), 0 0px 0 1px rgba(10,10,10,0.02); + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} +.dropdown-item { + color: #4a4a4a; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; +} +a.dropdown-item, +button.dropdown-item { + padding-right: 3rem; + text-align: left; + white-space: nowrap; + width: 100%; +} +a.dropdown-item:hover, +button.dropdown-item:hover { + background-color: #f5f5f5; + color: #0a0a0a; +} +a.dropdown-item.is-active, +button.dropdown-item.is-active { + background-color: #3273dc; + color: #fff; +} +.dropdown-divider { + background-color: #ededed; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; +} +.level { + align-items: center; + justify-content: space-between; +} +.level code { + border-radius: 4px; +} +.level img { + display: inline-block; + vertical-align: top; +} +.level.is-mobile { + display: flex; +} +.level.is-mobile .level-left, +.level.is-mobile .level-right { + display: flex; +} +.level.is-mobile .level-left + .level-right { + margin-top: 0; +} +.level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} +.level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; +} +@media screen and (min-width: 769px), print { + .level { + display: flex; + } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; + } +} +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; +} +.level-item .title, +.level-item .subtitle { + margin-bottom: 0; +} +@media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; + } +} +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} +.level-left .level-item.is-flexible, +.level-right .level-item.is-flexible { + flex-grow: 1; +} +@media screen and (min-width: 769px), print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; + } +} +.level-left { + align-items: center; + justify-content: flex-start; +} +@media screen and (max-width: 768px) { + .level-left + .level-right { + margin-top: 1.5rem; + } +} +@media screen and (min-width: 769px), print { + .level-left { + display: flex; + } +} +.level-right { + align-items: center; + justify-content: flex-end; +} +@media screen and (min-width: 769px), print { + .level-right { + display: flex; + } +} +.list { + background-color: #fff; + border-radius: 4px; + box-shadow: 0 2px 3px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1); +} +.list-item { + display: block; + padding: 0.5em 1em; +} +.list-item:not(a) { + color: #4a4a4a; +} +.list-item:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.list-item:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} +.list-item:not(:last-child) { + border-bottom: 1px solid #dbdbdb; +} +.list-item.is-active { + background-color: #3273dc; + color: #fff; +} +a.list-item { + background-color: #f5f5f5; + cursor: pointer; +} +.media { + align-items: flex-start; + display: flex; + text-align: left; +} +.media .content:not(:last-child) { + margin-bottom: 0.75rem; +} +.media .media { + border-top: 1px solid rgba(219,219,219,0.5); + display: flex; + padding-top: 0.75rem; +} +.media .media .content:not(:last-child), +.media .media .control:not(:last-child) { + margin-bottom: 0.5rem; +} +.media .media .media { + padding-top: 0.5rem; +} +.media .media .media + .media { + margin-top: 0.5rem; +} +.media + .media { + border-top: 1px solid rgba(219,219,219,0.5); + margin-top: 1rem; + padding-top: 1rem; +} +.media.is-large + .media { + margin-top: 1.5rem; + padding-top: 1.5rem; +} +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} +.media-left { + margin-right: 1rem; +} +.media-right { + margin-left: 1rem; +} +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: left; +} +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; + } +} +.menu { + font-size: 1rem; +} +.menu.is-small { + font-size: 0.75rem; +} +.menu.is-medium { + font-size: 1.25rem; +} +.menu.is-large { + font-size: 1.5rem; +} +.menu-list { + line-height: 1.25; +} +.menu-list a { + border-radius: 2px; + color: #4a4a4a; + display: block; + padding: 0.5em 0.75em; +} +.menu-list a:hover { + background-color: #f5f5f5; + color: #363636; +} +.menu-list a.is-active { + background-color: #eef3fc; + color: #3273dc; +} +.menu-list li ul { + border-left: 1px solid #dbdbdb; + margin: 0.75em; + padding-left: 0.75em; +} +.menu-label { + color: #7a7a7a; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; +} +.menu-label:not(:first-child) { + margin-top: 1em; +} +.menu-label:not(:last-child) { + margin-bottom: 1em; +} +.message { + background-color: #f5f5f5; + border-radius: 4px; + font-size: 1rem; +} +.message strong { + color: currentColor; +} +.message a:not(.button):not(.tag):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} +.message.is-small { + font-size: 0.75rem; +} +.message.is-medium { + font-size: 1.25rem; +} +.message.is-large { + font-size: 1.5rem; +} +.message.is-white { + background-color: #fff; +} +.message.is-white .message-header { + background-color: #fff; + color: #0a0a0a; +} +.message.is-white .message-body { + border-color: #fff; +} +.message.is-black { + background-color: #fafafa; +} +.message.is-black .message-header { + background-color: #0a0a0a; + color: #fff; +} +.message.is-black .message-body { + border-color: #0a0a0a; +} +.message.is-light { + background-color: #fafafa; +} +.message.is-light .message-header { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.message.is-light .message-body { + border-color: #f5f5f5; +} +.message.is-dark { + background-color: #fafafa; +} +.message.is-dark .message-header { + background-color: #363636; + color: #fff; +} +.message.is-dark .message-body { + border-color: #363636; +} +.message.is-primary { + background-color: #eef3fc; +} +.message.is-primary .message-header { + background-color: #3273dc; + color: #fff; +} +.message.is-primary .message-body { + border-color: #3273dc; + color: #2160c4; +} +.message.is-link { + background-color: #eef3fc; +} +.message.is-link .message-header { + background-color: #3273dc; + color: #fff; +} +.message.is-link .message-body { + border-color: #3273dc; + color: #2160c4; +} +.message.is-info { + background-color: #eef6fc; +} +.message.is-info .message-header { + background-color: #3298dc; + color: #fff; +} +.message.is-info .message-body { + border-color: #3298dc; + color: #1d72aa; +} +.message.is-success { + background-color: #effaf3; +} +.message.is-success .message-header { + background-color: #48c774; + color: #fff; +} +.message.is-success .message-body { + border-color: #48c774; + color: #257942; +} +.message.is-warning { + background-color: #fffbeb; +} +.message.is-warning .message-header { + background-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.message.is-warning .message-body { + border-color: #ffdd57; + color: #947600; +} +.message.is-danger { + background-color: #feecf0; +} +.message.is-danger .message-header { + background-color: #f14668; + color: #fff; +} +.message.is-danger .message-body { + border-color: #f14668; + color: #cc0f35; +} +.message.is-grey-lightest { + background-color: #fafafa; +} +.message.is-grey-lightest .message-header { + background-color: #ededed; + color: #363636; +} +.message.is-grey-lightest .message-body { + border-color: #ededed; +} +.message-header { + align-items: center; + background-color: #4a4a4a; + border-radius: 4px 4px 0 0; + color: #fff; + display: flex; + font-weight: 700; + justify-content: space-between; + line-height: 1.25; + padding: 0.75em 1em; + position: relative; +} +.message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-left: 0.75em; +} +.message-header + .message-body { + border-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.message-body { + border-color: #dbdbdb; + border-radius: 4px; + border-style: solid; + border-width: 0 0 0 4px; + color: #4a4a4a; + padding: 1.25em 1.5em; +} +.message-body code, +.message-body pre { + background-color: #fff; +} +.message-body pre code { + background-color: transparent; +} +.modal { + align-items: center; + display: none; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; +} +.modal.is-active { + display: flex; +} +.modal-background { + background-color: rgba(10,10,10,0.86); +} +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; +} +@media screen and (min-width: 769px), print { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; + } +} +.modal-close { + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; +} +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; + -ms-overflow-y: visible; +} +.modal-card-head, +.modal-card-foot { + align-items: center; + background-color: #f5f5f5; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: 20px; + position: relative; +} +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} +.modal-card-title { + color: #363636; + flex-grow: 1; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; +} +.modal-card-foot { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid #dbdbdb; +} +.modal-card-foot .button:not(:last-child) { + margin-right: 0.5em; +} +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: #fff; + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; +} +.navbar { + background-color: #fff; + min-height: 3.25rem; + position: relative; + z-index: 30; +} +.navbar.is-white { + background-color: #fff; + color: #0a0a0a; +} +.navbar.is-white .navbar-brand > .navbar-item, +.navbar.is-white .navbar-brand .navbar-link { + color: #0a0a0a; +} +.navbar.is-white .navbar-brand > a.navbar-item:focus, +.navbar.is-white .navbar-brand .navbar-link:focus, +.navbar.is-white .navbar-brand > a.navbar-item:hover, +.navbar.is-white .navbar-brand .navbar-link:hover, +.navbar.is-white .navbar-brand > a.navbar-item.is-active, +.navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} +.navbar.is-white .navbar-brand .navbar-link::after { + border-color: #0a0a0a; +} +.navbar.is-white .navbar-burger { + color: #0a0a0a; +} +@media screen and (min-width: 1088px) { + .navbar.is-white .navbar-start > .navbar-item, + .navbar.is-white .navbar-end > .navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end .navbar-link { + color: #0a0a0a; + } + .navbar.is-white .navbar-start > a.navbar-item:focus, + .navbar.is-white .navbar-end > a.navbar-item:focus, + .navbar.is-white .navbar-start .navbar-link:focus, + .navbar.is-white .navbar-end .navbar-link:focus, + .navbar.is-white .navbar-start > a.navbar-item:hover, + .navbar.is-white .navbar-end > a.navbar-item:hover, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-start > a.navbar-item.is-active, + .navbar.is-white .navbar-end > a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #0a0a0a; + } + .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: #fff; + color: #0a0a0a; + } +} +.navbar.is-black { + background-color: #0a0a0a; + color: #fff; +} +.navbar.is-black .navbar-brand > .navbar-item, +.navbar.is-black .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-black .navbar-brand > a.navbar-item:focus, +.navbar.is-black .navbar-brand .navbar-link:focus, +.navbar.is-black .navbar-brand > a.navbar-item:hover, +.navbar.is-black .navbar-brand .navbar-link:hover, +.navbar.is-black .navbar-brand > a.navbar-item.is-active, +.navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: #000; + color: #fff; +} +.navbar.is-black .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-black .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-black .navbar-start > .navbar-item, + .navbar.is-black .navbar-end > .navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-black .navbar-start > a.navbar-item:focus, + .navbar.is-black .navbar-end > a.navbar-item:focus, + .navbar.is-black .navbar-start .navbar-link:focus, + .navbar.is-black .navbar-end .navbar-link:focus, + .navbar.is-black .navbar-start > a.navbar-item:hover, + .navbar.is-black .navbar-end > a.navbar-item:hover, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-start > a.navbar-item.is-active, + .navbar.is-black .navbar-end > a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: #000; + color: #fff; + } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #000; + color: #fff; + } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #0a0a0a; + color: #fff; + } +} +.navbar.is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-brand > .navbar-item, +.navbar.is-light .navbar-brand .navbar-link { + color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-brand > a.navbar-item:focus, +.navbar.is-light .navbar-brand .navbar-link:focus, +.navbar.is-light .navbar-brand > a.navbar-item:hover, +.navbar.is-light .navbar-brand .navbar-link:hover, +.navbar.is-light .navbar-brand > a.navbar-item.is-active, +.navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-brand .navbar-link::after { + border-color: rgba(0,0,0,0.7); +} +.navbar.is-light .navbar-burger { + color: rgba(0,0,0,0.7); +} +@media screen and (min-width: 1088px) { + .navbar.is-light .navbar-start > .navbar-item, + .navbar.is-light .navbar-end > .navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end .navbar-link { + color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-start > a.navbar-item:focus, + .navbar.is-light .navbar-end > a.navbar-item:focus, + .navbar.is-light .navbar-start .navbar-link:focus, + .navbar.is-light .navbar-end .navbar-link:focus, + .navbar.is-light .navbar-start > a.navbar-item:hover, + .navbar.is-light .navbar-end > a.navbar-item:hover, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-start > a.navbar-item.is-active, + .navbar.is-light .navbar-end > a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); + } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); + } +} +.navbar.is-dark { + background-color: #363636; + color: #fff; +} +.navbar.is-dark .navbar-brand > .navbar-item, +.navbar.is-dark .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-dark .navbar-brand > a.navbar-item:focus, +.navbar.is-dark .navbar-brand .navbar-link:focus, +.navbar.is-dark .navbar-brand > a.navbar-item:hover, +.navbar.is-dark .navbar-brand .navbar-link:hover, +.navbar.is-dark .navbar-brand > a.navbar-item.is-active, +.navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: #fff; +} +.navbar.is-dark .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-dark .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-dark .navbar-start > .navbar-item, + .navbar.is-dark .navbar-end > .navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-dark .navbar-start > a.navbar-item:focus, + .navbar.is-dark .navbar-end > a.navbar-item:focus, + .navbar.is-dark .navbar-start .navbar-link:focus, + .navbar.is-dark .navbar-end .navbar-link:focus, + .navbar.is-dark .navbar-start > a.navbar-item:hover, + .navbar.is-dark .navbar-end > a.navbar-item:hover, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-start > a.navbar-item.is-active, + .navbar.is-dark .navbar-end > a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: #fff; + } +} +.navbar.is-primary { + background-color: #3273dc; + color: #fff; +} +.navbar.is-primary .navbar-brand > .navbar-item, +.navbar.is-primary .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-primary .navbar-brand > a.navbar-item:focus, +.navbar.is-primary .navbar-brand .navbar-link:focus, +.navbar.is-primary .navbar-brand > a.navbar-item:hover, +.navbar.is-primary .navbar-brand .navbar-link:hover, +.navbar.is-primary .navbar-brand > a.navbar-item.is-active, +.navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #2366d1; + color: #fff; +} +.navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-primary .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-primary .navbar-start > .navbar-item, + .navbar.is-primary .navbar-end > .navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-primary .navbar-start > a.navbar-item:focus, + .navbar.is-primary .navbar-end > a.navbar-item:focus, + .navbar.is-primary .navbar-start .navbar-link:focus, + .navbar.is-primary .navbar-end .navbar-link:focus, + .navbar.is-primary .navbar-start > a.navbar-item:hover, + .navbar.is-primary .navbar-end > a.navbar-item:hover, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-start > a.navbar-item.is-active, + .navbar.is-primary .navbar-end > a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #2366d1; + color: #fff; + } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #2366d1; + color: #fff; + } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #3273dc; + color: #fff; + } +} +.navbar.is-link { + background-color: #3273dc; + color: #fff; +} +.navbar.is-link .navbar-brand > .navbar-item, +.navbar.is-link .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-link .navbar-brand > a.navbar-item:focus, +.navbar.is-link .navbar-brand .navbar-link:focus, +.navbar.is-link .navbar-brand > a.navbar-item:hover, +.navbar.is-link .navbar-brand .navbar-link:hover, +.navbar.is-link .navbar-brand > a.navbar-item.is-active, +.navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #2366d1; + color: #fff; +} +.navbar.is-link .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-link .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-link .navbar-start > .navbar-item, + .navbar.is-link .navbar-end > .navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-link .navbar-start > a.navbar-item:focus, + .navbar.is-link .navbar-end > a.navbar-item:focus, + .navbar.is-link .navbar-start .navbar-link:focus, + .navbar.is-link .navbar-end .navbar-link:focus, + .navbar.is-link .navbar-start > a.navbar-item:hover, + .navbar.is-link .navbar-end > a.navbar-item:hover, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-start > a.navbar-item.is-active, + .navbar.is-link .navbar-end > a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #2366d1; + color: #fff; + } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #2366d1; + color: #fff; + } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #3273dc; + color: #fff; + } +} +.navbar.is-info { + background-color: #3298dc; + color: #fff; +} +.navbar.is-info .navbar-brand > .navbar-item, +.navbar.is-info .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-info .navbar-brand > a.navbar-item:focus, +.navbar.is-info .navbar-brand .navbar-link:focus, +.navbar.is-info .navbar-brand > a.navbar-item:hover, +.navbar.is-info .navbar-brand .navbar-link:hover, +.navbar.is-info .navbar-brand > a.navbar-item.is-active, +.navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #238cd1; + color: #fff; +} +.navbar.is-info .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-info .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-info .navbar-start > .navbar-item, + .navbar.is-info .navbar-end > .navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-info .navbar-start > a.navbar-item:focus, + .navbar.is-info .navbar-end > a.navbar-item:focus, + .navbar.is-info .navbar-start .navbar-link:focus, + .navbar.is-info .navbar-end .navbar-link:focus, + .navbar.is-info .navbar-start > a.navbar-item:hover, + .navbar.is-info .navbar-end > a.navbar-item:hover, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-start > a.navbar-item.is-active, + .navbar.is-info .navbar-end > a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #238cd1; + color: #fff; + } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #238cd1; + color: #fff; + } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #3298dc; + color: #fff; + } +} +.navbar.is-success { + background-color: #48c774; + color: #fff; +} +.navbar.is-success .navbar-brand > .navbar-item, +.navbar.is-success .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-success .navbar-brand > a.navbar-item:focus, +.navbar.is-success .navbar-brand .navbar-link:focus, +.navbar.is-success .navbar-brand > a.navbar-item:hover, +.navbar.is-success .navbar-brand .navbar-link:hover, +.navbar.is-success .navbar-brand > a.navbar-item.is-active, +.navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #3abb67; + color: #fff; +} +.navbar.is-success .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-success .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-success .navbar-start > .navbar-item, + .navbar.is-success .navbar-end > .navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-success .navbar-start > a.navbar-item:focus, + .navbar.is-success .navbar-end > a.navbar-item:focus, + .navbar.is-success .navbar-start .navbar-link:focus, + .navbar.is-success .navbar-end .navbar-link:focus, + .navbar.is-success .navbar-start > a.navbar-item:hover, + .navbar.is-success .navbar-end > a.navbar-item:hover, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-start > a.navbar-item.is-active, + .navbar.is-success .navbar-end > a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #3abb67; + color: #fff; + } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3abb67; + color: #fff; + } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #48c774; + color: #fff; + } +} +.navbar.is-warning { + background-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.navbar.is-warning .navbar-brand > .navbar-item, +.navbar.is-warning .navbar-brand .navbar-link { + color: rgba(0,0,0,0.7); +} +.navbar.is-warning .navbar-brand > a.navbar-item:focus, +.navbar.is-warning .navbar-brand .navbar-link:focus, +.navbar.is-warning .navbar-brand > a.navbar-item:hover, +.navbar.is-warning .navbar-brand .navbar-link:hover, +.navbar.is-warning .navbar-brand > a.navbar-item.is-active, +.navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0,0,0,0.7); +} +.navbar.is-warning .navbar-brand .navbar-link::after { + border-color: rgba(0,0,0,0.7); +} +.navbar.is-warning .navbar-burger { + color: rgba(0,0,0,0.7); +} +@media screen and (min-width: 1088px) { + .navbar.is-warning .navbar-start > .navbar-item, + .navbar.is-warning .navbar-end > .navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end .navbar-link { + color: rgba(0,0,0,0.7); + } + .navbar.is-warning .navbar-start > a.navbar-item:focus, + .navbar.is-warning .navbar-end > a.navbar-item:focus, + .navbar.is-warning .navbar-start .navbar-link:focus, + .navbar.is-warning .navbar-end .navbar-link:focus, + .navbar.is-warning .navbar-start > a.navbar-item:hover, + .navbar.is-warning .navbar-end > a.navbar-item:hover, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-start > a.navbar-item.is-active, + .navbar.is-warning .navbar-end > a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0,0,0,0.7); + } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: rgba(0,0,0,0.7); + } + .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ffd83d; + color: rgba(0,0,0,0.7); + } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ffdd57; + color: rgba(0,0,0,0.7); + } +} +.navbar.is-danger { + background-color: #f14668; + color: #fff; +} +.navbar.is-danger .navbar-brand > .navbar-item, +.navbar.is-danger .navbar-brand .navbar-link { + color: #fff; +} +.navbar.is-danger .navbar-brand > a.navbar-item:focus, +.navbar.is-danger .navbar-brand .navbar-link:focus, +.navbar.is-danger .navbar-brand > a.navbar-item:hover, +.navbar.is-danger .navbar-brand .navbar-link:hover, +.navbar.is-danger .navbar-brand > a.navbar-item.is-active, +.navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; +} +.navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #fff; +} +.navbar.is-danger .navbar-burger { + color: #fff; +} +@media screen and (min-width: 1088px) { + .navbar.is-danger .navbar-start > .navbar-item, + .navbar.is-danger .navbar-end > .navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-danger .navbar-start > a.navbar-item:focus, + .navbar.is-danger .navbar-end > a.navbar-item:focus, + .navbar.is-danger .navbar-start .navbar-link:focus, + .navbar.is-danger .navbar-end .navbar-link:focus, + .navbar.is-danger .navbar-start > a.navbar-item:hover, + .navbar.is-danger .navbar-end > a.navbar-item:hover, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-start > a.navbar-item.is-active, + .navbar.is-danger .navbar-end > a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; + } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ef2e55; + color: #fff; + } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #f14668; + color: #fff; + } +} +.navbar.is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.navbar.is-grey-lightest .navbar-brand > .navbar-item, +.navbar.is-grey-lightest .navbar-brand .navbar-link { + color: #363636; +} +.navbar.is-grey-lightest .navbar-brand > a.navbar-item:focus, +.navbar.is-grey-lightest .navbar-brand .navbar-link:focus, +.navbar.is-grey-lightest .navbar-brand > a.navbar-item:hover, +.navbar.is-grey-lightest .navbar-brand .navbar-link:hover, +.navbar.is-grey-lightest .navbar-brand > a.navbar-item.is-active, +.navbar.is-grey-lightest .navbar-brand .navbar-link.is-active { + background-color: #e0e0e0; + color: #363636; +} +.navbar.is-grey-lightest .navbar-brand .navbar-link::after { + border-color: #363636; +} +.navbar.is-grey-lightest .navbar-burger { + color: #363636; +} +@media screen and (min-width: 1088px) { + .navbar.is-grey-lightest .navbar-start > .navbar-item, + .navbar.is-grey-lightest .navbar-end > .navbar-item, + .navbar.is-grey-lightest .navbar-start .navbar-link, + .navbar.is-grey-lightest .navbar-end .navbar-link { + color: #363636; + } + .navbar.is-grey-lightest .navbar-start > a.navbar-item:focus, + .navbar.is-grey-lightest .navbar-end > a.navbar-item:focus, + .navbar.is-grey-lightest .navbar-start .navbar-link:focus, + .navbar.is-grey-lightest .navbar-end .navbar-link:focus, + .navbar.is-grey-lightest .navbar-start > a.navbar-item:hover, + .navbar.is-grey-lightest .navbar-end > a.navbar-item:hover, + .navbar.is-grey-lightest .navbar-start .navbar-link:hover, + .navbar.is-grey-lightest .navbar-end .navbar-link:hover, + .navbar.is-grey-lightest .navbar-start > a.navbar-item.is-active, + .navbar.is-grey-lightest .navbar-end > a.navbar-item.is-active, + .navbar.is-grey-lightest .navbar-start .navbar-link.is-active, + .navbar.is-grey-lightest .navbar-end .navbar-link.is-active { + background-color: #e0e0e0; + color: #363636; + } + .navbar.is-grey-lightest .navbar-start .navbar-link::after, + .navbar.is-grey-lightest .navbar-end .navbar-link::after { + border-color: #363636; + } + .navbar.is-grey-lightest .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-grey-lightest .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-grey-lightest .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e0e0e0; + color: #363636; + } + .navbar.is-grey-lightest .navbar-dropdown a.navbar-item.is-active { + background-color: #ededed; + color: #363636; + } +} +.navbar > .container { + align-items: stretch; + display: flex; + min-height: 3.25rem; + width: 100%; +} +.navbar.has-shadow { + box-shadow: 0 2px 0 0 #f5f5f5; +} +.navbar.is-fixed-bottom, +.navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; +} +.navbar.is-fixed-bottom { + bottom: 0; +} +.navbar.is-fixed-bottom.has-shadow { + box-shadow: 0 -2px 0 0 #f5f5f5; +} +.navbar.is-fixed-top { + top: 0; +} +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: 3.25rem; +} +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; +} +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: 3.25rem; +} +.navbar-brand a.navbar-item:focus, +.navbar-brand a.navbar-item:hover { + background-color: transparent; +} +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; +} +.navbar-burger { + color: #4a4a4a; + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; +} +.navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + transform-origin: center; + transition-duration: 86ms; + transition-property: background-color, opacity, transform; + transition-timing-function: ease-out; + width: 16px; +} +.navbar-burger span:nth-child(1) { + top: calc(50% - 6px); +} +.navbar-burger span:nth-child(2) { + top: calc(50% - 1px); +} +.navbar-burger span:nth-child(3) { + top: calc(50% + 4px); +} +.navbar-burger:hover { + background-color: rgba(0,0,0,0.05); +} +.navbar-burger.is-active span:nth-child(1) { + transform: translateY(5px) rotate(45deg); +} +.navbar-burger.is-active span:nth-child(2) { + opacity: 0; +} +.navbar-burger.is-active span:nth-child(3) { + transform: translateY(-5px) rotate(-45deg); +} +.navbar-menu { + display: none; +} +.navbar-item, +.navbar-link { + color: #4a4a4a; + display: block; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; +} +.navbar-item .icon:only-child, +.navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; +} +a.navbar-item, +.navbar-link { + cursor: pointer; +} +a.navbar-item:focus, +.navbar-link:focus, +a.navbar-item:focus-within, +.navbar-link:focus-within, +a.navbar-item:hover, +.navbar-link:hover, +a.navbar-item.is-active, +.navbar-link.is-active { + background-color: #fafafa; + color: #3273dc; +} +.navbar-item { + display: block; + flex-grow: 0; + flex-shrink: 0; +} +.navbar-item img { + max-height: 1.75rem; +} +.navbar-item.has-dropdown { + padding: 0; +} +.navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); +} +.navbar-item.is-tab:focus, +.navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #3273dc; +} +.navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #3273dc; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #3273dc; + padding-bottom: calc(0.5rem - 3px); +} +.navbar-content { + flex-grow: 1; + flex-shrink: 1; +} +.navbar-link:not(.is-arrowless) { + padding-right: 2.5em; +} +.navbar-link:not(.is-arrowless)::after { + border-color: #3273dc; + margin-top: -0.375em; + right: 1.125em; +} +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} +.navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.navbar-divider { + background-color: #f5f5f5; + border: none; + display: none; + height: 2px; + margin: 0.5rem 0; +} +@media screen and (max-width: 1087px) { + .navbar > .container { + display: block; + } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; + } + .navbar-link::after { + display: none; + } + .navbar-menu { + background-color: #fff; + box-shadow: 0 8px 16px rgba(10,10,10,0.1); + padding: 0.5rem 0; + } + .navbar-menu.is-active { + display: block; + } + .navbar.is-fixed-bottom-touch, + .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-touch { + bottom: 0; + } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -2px 3px rgba(10,10,10,0.1); + } + .navbar.is-fixed-top-touch { + top: 0; + } + .navbar.is-fixed-top .navbar-menu, + .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; + } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; + } +} +@media screen and (min-width: 1088px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; + } + .navbar { + min-height: 3.25rem; + } + .navbar.is-spaced { + padding: 1rem 2rem; + } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; + } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: 4px; + } + .navbar.is-transparent a.navbar-item:focus, + .navbar.is-transparent .navbar-link:focus, + .navbar.is-transparent a.navbar-item:hover, + .navbar.is-transparent .navbar-link:hover, + .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent .navbar-link.is-active { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, + .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link, + .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link, + .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item:focus, + .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: #f5f5f5; + color: #0a0a0a; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: #f5f5f5; + color: #3273dc; + } + .navbar-burger { + display: none; + } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; + } + .navbar-item { + display: flex; + } + .navbar-item.has-dropdown { + align-items: stretch; + } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); + } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 2px solid #dbdbdb; + border-radius: 6px 6px 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -8px 8px rgba(10,10,10,0.1); + top: auto; + } + .navbar-item.is-active .navbar-dropdown, + .navbar-item.is-hoverable:focus .navbar-dropdown, + .navbar-item.is-hoverable:focus-within .navbar-dropdown, + .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; + } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, + .navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown, + .navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown, + .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, + .navbar-item.is-active .navbar-dropdown.is-boxed, + .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed, + .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed, + .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; + } + .navbar-start { + justify-content: flex-start; + margin-right: auto; + } + .navbar-end { + justify-content: flex-end; + margin-left: auto; + } + .navbar-dropdown { + background-color: #fff; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 2px solid #dbdbdb; + box-shadow: 0 8px 8px rgba(10,10,10,0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; + } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; + } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; + } + .navbar-dropdown a.navbar-item:focus, + .navbar-dropdown a.navbar-item:hover { + background-color: #f5f5f5; + color: #0a0a0a; + } + .navbar-dropdown a.navbar-item.is-active { + background-color: #f5f5f5; + color: #3273dc; + } + .navbar.is-spaced .navbar-dropdown, + .navbar-dropdown.is-boxed { + border-radius: 6px; + border-top: none; + box-shadow: 0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + -4px); + transform: translateY(-5px); + transition-duration: 86ms; + transition-property: opacity, transform; + } + .navbar-dropdown.is-right { + left: auto; + right: 0; + } + .navbar-divider { + display: block; + } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: -0.75rem; + } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: -0.75rem; + } + .navbar.is-fixed-bottom-desktop, + .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-desktop { + bottom: 0; + } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -2px 3px rgba(10,10,10,0.1); + } + .navbar.is-fixed-top-desktop { + top: 0; + } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; + } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: 5.25rem; + } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: 5.25rem; + } + a.navbar-item.is-active, + .navbar-link.is-active { + color: #3273dc; + } + a.navbar-item.is-active:not(:focus):not(:hover), + .navbar-link.is-active:not(:focus):not(:hover) { + background-color: transparent; + } + .navbar-item.has-dropdown:focus .navbar-link, + .navbar-item.has-dropdown:hover .navbar-link, + .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #fafafa; + } +} +.hero.is-fullheight-with-navbar { + min-height: calc(100vh - 3.25rem); +} +.pagination { + font-size: 1rem; + margin: -0.25rem; +} +.pagination.is-small { + font-size: 0.75rem; +} +.pagination.is-medium { + font-size: 1.25rem; +} +.pagination.is-large { + font-size: 1.5rem; +} +.pagination.is-rounded .pagination-previous, +.pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 290486px; +} +.pagination.is-rounded .pagination-link { + border-radius: 290486px; +} +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; +} +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + font-size: 1em; + justify-content: center; + margin: 0.25rem; + padding-left: 0.5em; + padding-right: 0.5em; + text-align: center; +} +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #363636; + min-width: 2.25em; +} +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover { + border-color: #b5b5b5; + color: #363636; +} +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus { + border-color: #3273dc; +} +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active { + box-shadow: inset 0 1px 2px rgba(10,10,10,0.2); +} +.pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled] { + background-color: #dbdbdb; + border-color: #dbdbdb; + box-shadow: none; + color: #7a7a7a; + opacity: 0.5; +} +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} +.pagination-link.is-current { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; +} +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; +} +.pagination-list { + flex-wrap: wrap; +} +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; + } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; + } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; + } +} +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; + } + .pagination-previous { + order: 2; + } + .pagination-next { + order: 3; + } + .pagination { + justify-content: space-between; + } + .pagination.is-centered .pagination-previous, + .pagination .pagination-previous { + order: 1; + } + .pagination.is-centered .pagination-list, + .pagination .pagination-list { + justify-content: center; + order: 2; + } + .pagination.is-centered .pagination-next, + .pagination .pagination-next { + order: 3; + } + .pagination.is-right .pagination-previous { + order: 1; + } + .pagination.is-right .pagination-next { + order: 2; + } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; + } +} +.panel { + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10,10,10,0.1), 0 0px 0 1px rgba(10,10,10,0.02); + font-size: 1rem; +} +.panel:not(:last-child) { + margin-bottom: 1.5rem; +} +.panel.is-white .panel-heading { + background-color: #fff; + color: #0a0a0a; +} +.panel.is-white .panel-tabs a.is-active { + border-bottom-color: #fff; +} +.panel.is-white .panel-block.is-active .panel-icon { + color: #fff; +} +.panel.is-black .panel-heading { + background-color: #0a0a0a; + color: #fff; +} +.panel.is-black .panel-tabs a.is-active { + border-bottom-color: #0a0a0a; +} +.panel.is-black .panel-block.is-active .panel-icon { + color: #0a0a0a; +} +.panel.is-light .panel-heading { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.panel.is-light .panel-tabs a.is-active { + border-bottom-color: #f5f5f5; +} +.panel.is-light .panel-block.is-active .panel-icon { + color: #f5f5f5; +} +.panel.is-dark .panel-heading { + background-color: #363636; + color: #fff; +} +.panel.is-dark .panel-tabs a.is-active { + border-bottom-color: #363636; +} +.panel.is-dark .panel-block.is-active .panel-icon { + color: #363636; +} +.panel.is-primary .panel-heading { + background-color: #3273dc; + color: #fff; +} +.panel.is-primary .panel-tabs a.is-active { + border-bottom-color: #3273dc; +} +.panel.is-primary .panel-block.is-active .panel-icon { + color: #3273dc; +} +.panel.is-link .panel-heading { + background-color: #3273dc; + color: #fff; +} +.panel.is-link .panel-tabs a.is-active { + border-bottom-color: #3273dc; +} +.panel.is-link .panel-block.is-active .panel-icon { + color: #3273dc; +} +.panel.is-info .panel-heading { + background-color: #3298dc; + color: #fff; +} +.panel.is-info .panel-tabs a.is-active { + border-bottom-color: #3298dc; +} +.panel.is-info .panel-block.is-active .panel-icon { + color: #3298dc; +} +.panel.is-success .panel-heading { + background-color: #48c774; + color: #fff; +} +.panel.is-success .panel-tabs a.is-active { + border-bottom-color: #48c774; +} +.panel.is-success .panel-block.is-active .panel-icon { + color: #48c774; +} +.panel.is-warning .panel-heading { + background-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.panel.is-warning .panel-tabs a.is-active { + border-bottom-color: #ffdd57; +} +.panel.is-warning .panel-block.is-active .panel-icon { + color: #ffdd57; +} +.panel.is-danger .panel-heading { + background-color: #f14668; + color: #fff; +} +.panel.is-danger .panel-tabs a.is-active { + border-bottom-color: #f14668; +} +.panel.is-danger .panel-block.is-active .panel-icon { + color: #f14668; +} +.panel.is-grey-lightest .panel-heading { + background-color: #ededed; + color: #363636; +} +.panel.is-grey-lightest .panel-tabs a.is-active { + border-bottom-color: #ededed; +} +.panel.is-grey-lightest .panel-block.is-active .panel-icon { + color: #ededed; +} +.panel-tabs:not(:last-child), +.panel-block:not(:last-child) { + border-bottom: 1px solid #ededed; +} +.panel-heading { + background-color: #ededed; + border-radius: 6px 6px 0 0; + color: #363636; + font-size: 1.25em; + font-weight: 700; + line-height: 1.25; + padding: 0.75em 1em; +} +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: 0.875em; + justify-content: center; +} +.panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; +} +.panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; +} +.panel-list a { + color: #4a4a4a; +} +.panel-list a:hover { + color: #3273dc; +} +.panel-block { + align-items: center; + color: #363636; + display: flex; + justify-content: flex-start; + padding: 0.5em 0.75em; +} +.panel-block input[type="checkbox"] { + margin-right: 0.75em; +} +.panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; +} +.panel-block.is-wrapped { + flex-wrap: wrap; +} +.panel-block.is-active { + border-left-color: #3273dc; + color: #363636; +} +.panel-block.is-active .panel-icon { + color: #3273dc; +} +.panel-block:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; +} +a.panel-block, +label.panel-block { + cursor: pointer; +} +a.panel-block:hover, +label.panel-block:hover { + background-color: #f5f5f5; +} +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #7a7a7a; + margin-right: 0.75em; +} +.panel-icon .fa { + font-size: inherit; + line-height: inherit; +} +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: 1rem; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; +} +.tabs a { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #4a4a4a; + display: flex; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; +} +.tabs a:hover { + border-bottom-color: #363636; + color: #363636; +} +.tabs li { + display: block; +} +.tabs li.is-active a { + border-bottom-color: #3273dc; + color: #3273dc; +} +.tabs ul { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; +} +.tabs ul.is-left { + padding-right: 0.75em; +} +.tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; +} +.tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; +} +.tabs .icon:first-child { + margin-right: 0.5em; +} +.tabs .icon:last-child { + margin-left: 0.5em; +} +.tabs.is-centered ul { + justify-content: center; +} +.tabs.is-right ul { + justify-content: flex-end; +} +.tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.tabs.is-boxed a:hover { + background-color: #f5f5f5; + border-bottom-color: #dbdbdb; +} +.tabs.is-boxed li.is-active a { + background-color: #fff; + border-color: #dbdbdb; + border-bottom-color: transparent !important; +} +.tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; +} +.tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; +} +.tabs.is-toggle a:hover { + background-color: #f5f5f5; + border-color: #b5b5b5; + z-index: 2; +} +.tabs.is-toggle li + li { + margin-left: -1px; +} +.tabs.is-toggle li:first-child a { + border-radius: 4px 0 0 4px; +} +.tabs.is-toggle li:last-child a { + border-radius: 0 4px 4px 0; +} +.tabs.is-toggle li.is-active a { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; + z-index: 1; +} +.tabs.is-toggle ul { + border-bottom: none; +} +.tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 290486px; + border-top-left-radius: 290486px; + padding-left: 1.25em; +} +.tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 290486px; + border-top-right-radius: 290486px; + padding-right: 1.25em; +} +.tabs.is-small { + font-size: 0.75rem; +} +.tabs.is-medium { + font-size: 1.25rem; +} +.tabs.is-large { + font-size: 1.5rem; +} +.box { + background-color: #fff; + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10,10,10,0.1), 0 0px 0 1px rgba(10,10,10,0.02); + color: #4a4a4a; + display: block; + padding: 1.25rem; +} +a.box:hover, +a.box:focus { + box-shadow: 0 0.5em 1em -0.125em rgba(10,10,10,0.1), 0 0 0 1px #3273dc; +} +a.box:active { + box-shadow: inset 0 1px 2px rgba(10,10,10,0.2), 0 0 0 1px #3273dc; +} +.button { + background-color: #fff; + border-color: #dbdbdb; + border-width: 1px; + color: #363636; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.375em - 1px); + padding-left: 1em; + padding-right: 1em; + padding-top: calc(0.375em - 1px); + text-align: center; + white-space: nowrap; +} +.button strong { + color: inherit; +} +.button .icon, +.button .icon.is-small, +.button .icon.is-medium, +.button .icon.is-large { + height: 1.5em; + width: 1.5em; +} +.button .icon:first-child:not(:last-child) { + margin-left: calc(-0.5em - 1px); + margin-right: 0.25em; +} +.button .icon:last-child:not(:first-child) { + margin-left: 0.25em; + margin-right: calc(-0.5em - 1px); +} +.button .icon:first-child:last-child { + margin-left: calc(-0.5em - 1px); + margin-right: calc(-0.5em - 1px); +} +.button:hover, +.button.is-hovered { + border-color: #b5b5b5; + color: #363636; +} +.button:focus, +.button.is-focused { + border-color: #3273dc; + color: #363636; +} +.button:focus:not(:active), +.button.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.button:active, +.button.is-active { + border-color: #4a4a4a; + color: #363636; +} +.button.is-text { + background-color: transparent; + border-color: transparent; + color: #4a4a4a; + text-decoration: underline; +} +.button.is-text:hover, +.button.is-text.is-hovered, +.button.is-text:focus, +.button.is-text.is-focused { + background-color: #f5f5f5; + color: #363636; +} +.button.is-text:active, +.button.is-text.is-active { + background-color: #e8e8e8; + color: #363636; +} +.button.is-text[disabled], +fieldset[disabled] .button.is-text { + background-color: transparent; + border-color: transparent; + box-shadow: none; +} +.button.is-white { + background-color: #fff; + border-color: transparent; + color: #0a0a0a; +} +.button.is-white:hover, +.button.is-white.is-hovered { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; +} +.button.is-white:focus, +.button.is-white.is-focused { + border-color: transparent; + color: #0a0a0a; +} +.button.is-white:focus:not(:active), +.button.is-white.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,255,255,0.25); +} +.button.is-white:active, +.button.is-white.is-active { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; +} +.button.is-white[disabled], +fieldset[disabled] .button.is-white { + background-color: #fff; + border-color: transparent; + box-shadow: none; +} +.button.is-white.is-inverted { + background-color: #0a0a0a; + color: #fff; +} +.button.is-white.is-inverted:hover, +.button.is-white.is-inverted.is-hovered { + background-color: #000; +} +.button.is-white.is-inverted[disabled], +fieldset[disabled] .button.is-white.is-inverted { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; + color: #fff; +} +.button.is-white.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} +.button.is-white.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-white.is-outlined:hover, +.button.is-white.is-outlined.is-hovered, +.button.is-white.is-outlined:focus, +.button.is-white.is-outlined.is-focused { + background-color: #fff; + border-color: #fff; + color: #0a0a0a; +} +.button.is-white.is-outlined.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-white.is-outlined.is-loading:hover::after, +.button.is-white.is-outlined.is-loading.is-hovered::after, +.button.is-white.is-outlined.is-loading:focus::after, +.button.is-white.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} +.button.is-white.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; +} +.button.is-white.is-inverted.is-outlined:hover, +.button.is-white.is-inverted.is-outlined.is-hovered, +.button.is-white.is-inverted.is-outlined:focus, +.button.is-white.is-inverted.is-outlined.is-focused { + background-color: #0a0a0a; + color: #fff; +} +.button.is-white.is-inverted.is-outlined.is-loading:hover::after, +.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-white.is-inverted.is-outlined.is-loading:focus::after, +.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-white.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; +} +.button.is-black { + background-color: #0a0a0a; + border-color: transparent; + color: #fff; +} +.button.is-black:hover, +.button.is-black.is-hovered { + background-color: #040404; + border-color: transparent; + color: #fff; +} +.button.is-black:focus, +.button.is-black.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-black:focus:not(:active), +.button.is-black.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(10,10,10,0.25); +} +.button.is-black:active, +.button.is-black.is-active { + background-color: #000; + border-color: transparent; + color: #fff; +} +.button.is-black[disabled], +fieldset[disabled] .button.is-black { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; +} +.button.is-black.is-inverted { + background-color: #fff; + color: #0a0a0a; +} +.button.is-black.is-inverted:hover, +.button.is-black.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-black.is-inverted[disabled], +fieldset[disabled] .button.is-black.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #0a0a0a; +} +.button.is-black.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; +} +.button.is-black.is-outlined:hover, +.button.is-black.is-outlined.is-hovered, +.button.is-black.is-outlined:focus, +.button.is-black.is-outlined.is-focused { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: #fff; +} +.button.is-black.is-outlined.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} +.button.is-black.is-outlined.is-loading:hover::after, +.button.is-black.is-outlined.is-loading.is-hovered::after, +.button.is-black.is-outlined.is-loading:focus::after, +.button.is-black.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-black.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; +} +.button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-black.is-inverted.is-outlined:hover, +.button.is-black.is-inverted.is-outlined.is-hovered, +.button.is-black.is-inverted.is-outlined:focus, +.button.is-black.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #0a0a0a; +} +.button.is-black.is-inverted.is-outlined.is-loading:hover::after, +.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-black.is-inverted.is-outlined.is-loading:focus::after, +.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} +.button.is-black.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-light, +article.article .article-more { + background-color: #f5f5f5; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light:hover, +article.article .article-more:hover, +.button.is-light.is-hovered, +article.article .article-more.is-hovered { + background-color: #eee; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light:focus, +article.article .article-more:focus, +.button.is-light.is-focused, +article.article .article-more.is-focused { + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light:focus:not(:active), +article.article .article-more:focus:not(:active), +.button.is-light.is-focused:not(:active), +article.article .article-more.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(245,245,245,0.25); +} +.button.is-light:active, +article.article .article-more:active, +.button.is-light.is-active, +article.article .article-more.is-active { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-light[disabled], +article.article .article-more[disabled], +fieldset[disabled] .button.is-light, +fieldset[disabled] article.article .article-more { + background-color: #f5f5f5; + border-color: transparent; + box-shadow: none; +} +.button.is-light.is-inverted, +article.article .article-more.is-inverted { + background-color: rgba(0,0,0,0.7); + color: #f5f5f5; +} +.button.is-light.is-inverted:hover, +article.article .article-more.is-inverted:hover, +.button.is-light.is-inverted.is-hovered, +article.article .article-more.is-inverted.is-hovered { + background-color: rgba(0,0,0,0.7); +} +.button.is-light.is-inverted[disabled], +article.article .article-more.is-inverted[disabled], +fieldset[disabled] .button.is-light.is-inverted, +fieldset[disabled] article.article .article-more.is-inverted { + background-color: rgba(0,0,0,0.7); + border-color: transparent; + box-shadow: none; + color: #f5f5f5; +} +.button.is-light.is-loading::after, +article.article .article-more.is-loading::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-light.is-outlined, +article.article .article-more.is-outlined { + background-color: transparent; + border-color: #f5f5f5; + color: #f5f5f5; +} +.button.is-light.is-outlined:hover, +article.article .article-more.is-outlined:hover, +.button.is-light.is-outlined.is-hovered, +article.article .article-more.is-outlined.is-hovered, +.button.is-light.is-outlined:focus, +article.article .article-more.is-outlined:focus, +.button.is-light.is-outlined.is-focused, +article.article .article-more.is-outlined.is-focused { + background-color: #f5f5f5; + border-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.button.is-light.is-outlined.is-loading::after, +article.article .article-more.is-outlined.is-loading::after { + border-color: transparent transparent #f5f5f5 #f5f5f5 !important; +} +.button.is-light.is-outlined.is-loading:hover::after, +article.article .article-more.is-outlined.is-loading:hover::after, +.button.is-light.is-outlined.is-loading.is-hovered::after, +article.article .article-more.is-outlined.is-loading.is-hovered::after, +.button.is-light.is-outlined.is-loading:focus::after, +article.article .article-more.is-outlined.is-loading:focus::after, +.button.is-light.is-outlined.is-loading.is-focused::after, +article.article .article-more.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-light.is-outlined[disabled], +article.article .article-more.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-outlined, +fieldset[disabled] article.article .article-more.is-outlined { + background-color: transparent; + border-color: #f5f5f5; + box-shadow: none; + color: #f5f5f5; +} +.button.is-light.is-inverted.is-outlined, +article.article .article-more.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + color: rgba(0,0,0,0.7); +} +.button.is-light.is-inverted.is-outlined:hover, +article.article .article-more.is-inverted.is-outlined:hover, +.button.is-light.is-inverted.is-outlined.is-hovered, +article.article .article-more.is-inverted.is-outlined.is-hovered, +.button.is-light.is-inverted.is-outlined:focus, +article.article .article-more.is-inverted.is-outlined:focus, +.button.is-light.is-inverted.is-outlined.is-focused, +article.article .article-more.is-inverted.is-outlined.is-focused { + background-color: rgba(0,0,0,0.7); + color: #f5f5f5; +} +.button.is-light.is-inverted.is-outlined.is-loading:hover::after, +article.article .article-more.is-inverted.is-outlined.is-loading:hover::after, +.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after, +article.article .article-more.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-light.is-inverted.is-outlined.is-loading:focus::after, +article.article .article-more.is-inverted.is-outlined.is-loading:focus::after, +.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after, +article.article .article-more.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #f5f5f5 #f5f5f5 !important; +} +.button.is-light.is-inverted.is-outlined[disabled], +article.article .article-more.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-inverted.is-outlined, +fieldset[disabled] article.article .article-more.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + box-shadow: none; + color: rgba(0,0,0,0.7); +} +.button.is-dark { + background-color: #363636; + border-color: transparent; + color: #fff; +} +.button.is-dark:hover, +.button.is-dark.is-hovered { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} +.button.is-dark:focus, +.button.is-dark.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-dark:focus:not(:active), +.button.is-dark.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(54,54,54,0.25); +} +.button.is-dark:active, +.button.is-dark.is-active { + background-color: #292929; + border-color: transparent; + color: #fff; +} +.button.is-dark[disabled], +fieldset[disabled] .button.is-dark { + background-color: #363636; + border-color: transparent; + box-shadow: none; +} +.button.is-dark.is-inverted { + background-color: #fff; + color: #363636; +} +.button.is-dark.is-inverted:hover, +.button.is-dark.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-dark.is-inverted[disabled], +fieldset[disabled] .button.is-dark.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #363636; +} +.button.is-dark.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; +} +.button.is-dark.is-outlined:hover, +.button.is-dark.is-outlined.is-hovered, +.button.is-dark.is-outlined:focus, +.button.is-dark.is-outlined.is-focused { + background-color: #363636; + border-color: #363636; + color: #fff; +} +.button.is-dark.is-outlined.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-dark.is-outlined.is-loading:hover::after, +.button.is-dark.is-outlined.is-loading.is-hovered::after, +.button.is-dark.is-outlined.is-loading:focus::after, +.button.is-dark.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-dark.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; +} +.button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-dark.is-inverted.is-outlined:hover, +.button.is-dark.is-inverted.is-outlined.is-hovered, +.button.is-dark.is-inverted.is-outlined:focus, +.button.is-dark.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #363636; +} +.button.is-dark.is-inverted.is-outlined.is-loading:hover::after, +.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-dark.is-inverted.is-outlined.is-loading:focus::after, +.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-dark.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-primary { + background-color: #3273dc; + border-color: transparent; + color: #fff; +} +.button.is-primary:hover, +.button.is-primary.is-hovered { + background-color: #276cda; + border-color: transparent; + color: #fff; +} +.button.is-primary:focus, +.button.is-primary.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-primary:focus:not(:active), +.button.is-primary.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.button.is-primary:active, +.button.is-primary.is-active { + background-color: #2366d1; + border-color: transparent; + color: #fff; +} +.button.is-primary[disabled], +fieldset[disabled] .button.is-primary { + background-color: #3273dc; + border-color: transparent; + box-shadow: none; +} +.button.is-primary.is-inverted { + background-color: #fff; + color: #3273dc; +} +.button.is-primary.is-inverted:hover, +.button.is-primary.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-primary.is-inverted[disabled], +fieldset[disabled] .button.is-primary.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3273dc; +} +.button.is-primary.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-primary.is-outlined { + background-color: transparent; + border-color: #3273dc; + color: #3273dc; +} +.button.is-primary.is-outlined:hover, +.button.is-primary.is-outlined.is-hovered, +.button.is-primary.is-outlined:focus, +.button.is-primary.is-outlined.is-focused { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; +} +.button.is-primary.is-outlined.is-loading::after { + border-color: transparent transparent #3273dc #3273dc !important; +} +.button.is-primary.is-outlined.is-loading:hover::after, +.button.is-primary.is-outlined.is-loading.is-hovered::after, +.button.is-primary.is-outlined.is-loading:focus::after, +.button.is-primary.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-primary.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-outlined { + background-color: transparent; + border-color: #3273dc; + box-shadow: none; + color: #3273dc; +} +.button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-primary.is-inverted.is-outlined:hover, +.button.is-primary.is-inverted.is-outlined.is-hovered, +.button.is-primary.is-inverted.is-outlined:focus, +.button.is-primary.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3273dc; +} +.button.is-primary.is-inverted.is-outlined.is-loading:hover::after, +.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-primary.is-inverted.is-outlined.is-loading:focus::after, +.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3273dc #3273dc !important; +} +.button.is-primary.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-primary.is-light { + background-color: #eef3fc; + color: #2160c4; +} +.button.is-primary.is-light:hover, +.button.is-primary.is-light.is-hovered { + background-color: #e3ecfa; + border-color: transparent; + color: #2160c4; +} +.button.is-primary.is-light:active, +.button.is-primary.is-light.is-active { + background-color: #d8e4f8; + border-color: transparent; + color: #2160c4; +} +.button.is-link { + background-color: #3273dc; + border-color: transparent; + color: #fff; +} +.button.is-link:hover, +.button.is-link.is-hovered { + background-color: #276cda; + border-color: transparent; + color: #fff; +} +.button.is-link:focus, +.button.is-link.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-link:focus:not(:active), +.button.is-link.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.button.is-link:active, +.button.is-link.is-active { + background-color: #2366d1; + border-color: transparent; + color: #fff; +} +.button.is-link[disabled], +fieldset[disabled] .button.is-link { + background-color: #3273dc; + border-color: transparent; + box-shadow: none; +} +.button.is-link.is-inverted { + background-color: #fff; + color: #3273dc; +} +.button.is-link.is-inverted:hover, +.button.is-link.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-link.is-inverted[disabled], +fieldset[disabled] .button.is-link.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3273dc; +} +.button.is-link.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-link.is-outlined { + background-color: transparent; + border-color: #3273dc; + color: #3273dc; +} +.button.is-link.is-outlined:hover, +.button.is-link.is-outlined.is-hovered, +.button.is-link.is-outlined:focus, +.button.is-link.is-outlined.is-focused { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; +} +.button.is-link.is-outlined.is-loading::after { + border-color: transparent transparent #3273dc #3273dc !important; +} +.button.is-link.is-outlined.is-loading:hover::after, +.button.is-link.is-outlined.is-loading.is-hovered::after, +.button.is-link.is-outlined.is-loading:focus::after, +.button.is-link.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-link.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-outlined { + background-color: transparent; + border-color: #3273dc; + box-shadow: none; + color: #3273dc; +} +.button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-link.is-inverted.is-outlined:hover, +.button.is-link.is-inverted.is-outlined.is-hovered, +.button.is-link.is-inverted.is-outlined:focus, +.button.is-link.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3273dc; +} +.button.is-link.is-inverted.is-outlined.is-loading:hover::after, +.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-link.is-inverted.is-outlined.is-loading:focus::after, +.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3273dc #3273dc !important; +} +.button.is-link.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-link.is-light { + background-color: #eef3fc; + color: #2160c4; +} +.button.is-link.is-light:hover, +.button.is-link.is-light.is-hovered { + background-color: #e3ecfa; + border-color: transparent; + color: #2160c4; +} +.button.is-link.is-light:active, +.button.is-link.is-light.is-active { + background-color: #d8e4f8; + border-color: transparent; + color: #2160c4; +} +.button.is-info { + background-color: #3298dc; + border-color: transparent; + color: #fff; +} +.button.is-info:hover, +.button.is-info.is-hovered { + background-color: #2793da; + border-color: transparent; + color: #fff; +} +.button.is-info:focus, +.button.is-info.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-info:focus:not(:active), +.button.is-info.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50,152,220,0.25); +} +.button.is-info:active, +.button.is-info.is-active { + background-color: #238cd1; + border-color: transparent; + color: #fff; +} +.button.is-info[disabled], +fieldset[disabled] .button.is-info { + background-color: #3298dc; + border-color: transparent; + box-shadow: none; +} +.button.is-info.is-inverted { + background-color: #fff; + color: #3298dc; +} +.button.is-info.is-inverted:hover, +.button.is-info.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-info.is-inverted[disabled], +fieldset[disabled] .button.is-info.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3298dc; +} +.button.is-info.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-info.is-outlined { + background-color: transparent; + border-color: #3298dc; + color: #3298dc; +} +.button.is-info.is-outlined:hover, +.button.is-info.is-outlined.is-hovered, +.button.is-info.is-outlined:focus, +.button.is-info.is-outlined.is-focused { + background-color: #3298dc; + border-color: #3298dc; + color: #fff; +} +.button.is-info.is-outlined.is-loading::after { + border-color: transparent transparent #3298dc #3298dc !important; +} +.button.is-info.is-outlined.is-loading:hover::after, +.button.is-info.is-outlined.is-loading.is-hovered::after, +.button.is-info.is-outlined.is-loading:focus::after, +.button.is-info.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-info.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-outlined { + background-color: transparent; + border-color: #3298dc; + box-shadow: none; + color: #3298dc; +} +.button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-info.is-inverted.is-outlined:hover, +.button.is-info.is-inverted.is-outlined.is-hovered, +.button.is-info.is-inverted.is-outlined:focus, +.button.is-info.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3298dc; +} +.button.is-info.is-inverted.is-outlined.is-loading:hover::after, +.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-info.is-inverted.is-outlined.is-loading:focus::after, +.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3298dc #3298dc !important; +} +.button.is-info.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-info.is-light { + background-color: #eef6fc; + color: #1d72aa; +} +.button.is-info.is-light:hover, +.button.is-info.is-light.is-hovered { + background-color: #e3f1fa; + border-color: transparent; + color: #1d72aa; +} +.button.is-info.is-light:active, +.button.is-info.is-light.is-active { + background-color: #d8ebf8; + border-color: transparent; + color: #1d72aa; +} +.button.is-success { + background-color: #48c774; + border-color: transparent; + color: #fff; +} +.button.is-success:hover, +.button.is-success.is-hovered { + background-color: #3ec46d; + border-color: transparent; + color: #fff; +} +.button.is-success:focus, +.button.is-success.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-success:focus:not(:active), +.button.is-success.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72,199,116,0.25); +} +.button.is-success:active, +.button.is-success.is-active { + background-color: #3abb67; + border-color: transparent; + color: #fff; +} +.button.is-success[disabled], +fieldset[disabled] .button.is-success { + background-color: #48c774; + border-color: transparent; + box-shadow: none; +} +.button.is-success.is-inverted { + background-color: #fff; + color: #48c774; +} +.button.is-success.is-inverted:hover, +.button.is-success.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-success.is-inverted[disabled], +fieldset[disabled] .button.is-success.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #48c774; +} +.button.is-success.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-success.is-outlined { + background-color: transparent; + border-color: #48c774; + color: #48c774; +} +.button.is-success.is-outlined:hover, +.button.is-success.is-outlined.is-hovered, +.button.is-success.is-outlined:focus, +.button.is-success.is-outlined.is-focused { + background-color: #48c774; + border-color: #48c774; + color: #fff; +} +.button.is-success.is-outlined.is-loading::after { + border-color: transparent transparent #48c774 #48c774 !important; +} +.button.is-success.is-outlined.is-loading:hover::after, +.button.is-success.is-outlined.is-loading.is-hovered::after, +.button.is-success.is-outlined.is-loading:focus::after, +.button.is-success.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-success.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-outlined { + background-color: transparent; + border-color: #48c774; + box-shadow: none; + color: #48c774; +} +.button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-success.is-inverted.is-outlined:hover, +.button.is-success.is-inverted.is-outlined.is-hovered, +.button.is-success.is-inverted.is-outlined:focus, +.button.is-success.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #48c774; +} +.button.is-success.is-inverted.is-outlined.is-loading:hover::after, +.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-success.is-inverted.is-outlined.is-loading:focus::after, +.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #48c774 #48c774 !important; +} +.button.is-success.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-success.is-light { + background-color: #effaf3; + color: #257942; +} +.button.is-success.is-light:hover, +.button.is-success.is-light.is-hovered { + background-color: #e6f7ec; + border-color: transparent; + color: #257942; +} +.button.is-success.is-light:active, +.button.is-success.is-light.is-active { + background-color: #dcf4e4; + border-color: transparent; + color: #257942; +} +.button.is-warning { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-warning:hover, +.button.is-warning.is-hovered { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-warning:focus, +.button.is-warning.is-focused { + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-warning:focus:not(:active), +.button.is-warning.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,221,87,0.25); +} +.button.is-warning:active, +.button.is-warning.is-active { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.button.is-warning[disabled], +fieldset[disabled] .button.is-warning { + background-color: #ffdd57; + border-color: transparent; + box-shadow: none; +} +.button.is-warning.is-inverted { + background-color: rgba(0,0,0,0.7); + color: #ffdd57; +} +.button.is-warning.is-inverted:hover, +.button.is-warning.is-inverted.is-hovered { + background-color: rgba(0,0,0,0.7); +} +.button.is-warning.is-inverted[disabled], +fieldset[disabled] .button.is-warning.is-inverted { + background-color: rgba(0,0,0,0.7); + border-color: transparent; + box-shadow: none; + color: #ffdd57; +} +.button.is-warning.is-loading::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffdd57; + color: #ffdd57; +} +.button.is-warning.is-outlined:hover, +.button.is-warning.is-outlined.is-hovered, +.button.is-warning.is-outlined:focus, +.button.is-warning.is-outlined.is-focused { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.button.is-warning.is-outlined.is-loading::after { + border-color: transparent transparent #ffdd57 #ffdd57 !important; +} +.button.is-warning.is-outlined.is-loading:hover::after, +.button.is-warning.is-outlined.is-loading.is-hovered::after, +.button.is-warning.is-outlined.is-loading:focus::after, +.button.is-warning.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important; +} +.button.is-warning.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffdd57; + box-shadow: none; + color: #ffdd57; +} +.button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + color: rgba(0,0,0,0.7); +} +.button.is-warning.is-inverted.is-outlined:hover, +.button.is-warning.is-inverted.is-outlined.is-hovered, +.button.is-warning.is-inverted.is-outlined:focus, +.button.is-warning.is-inverted.is-outlined.is-focused { + background-color: rgba(0,0,0,0.7); + color: #ffdd57; +} +.button.is-warning.is-inverted.is-outlined.is-loading:hover::after, +.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-warning.is-inverted.is-outlined.is-loading:focus::after, +.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ffdd57 #ffdd57 !important; +} +.button.is-warning.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0,0,0,0.7); + box-shadow: none; + color: rgba(0,0,0,0.7); +} +.button.is-warning.is-light { + background-color: #fffbeb; + color: #947600; +} +.button.is-warning.is-light:hover, +.button.is-warning.is-light.is-hovered { + background-color: #fff8de; + border-color: transparent; + color: #947600; +} +.button.is-warning.is-light:active, +.button.is-warning.is-light.is-active { + background-color: #fff6d1; + border-color: transparent; + color: #947600; +} +.button.is-danger { + background-color: #f14668; + border-color: transparent; + color: #fff; +} +.button.is-danger:hover, +.button.is-danger.is-hovered { + background-color: #f03a5f; + border-color: transparent; + color: #fff; +} +.button.is-danger:focus, +.button.is-danger.is-focused { + border-color: transparent; + color: #fff; +} +.button.is-danger:focus:not(:active), +.button.is-danger.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(241,70,104,0.25); +} +.button.is-danger:active, +.button.is-danger.is-active { + background-color: #ef2e55; + border-color: transparent; + color: #fff; +} +.button.is-danger[disabled], +fieldset[disabled] .button.is-danger { + background-color: #f14668; + border-color: transparent; + box-shadow: none; +} +.button.is-danger.is-inverted { + background-color: #fff; + color: #f14668; +} +.button.is-danger.is-inverted:hover, +.button.is-danger.is-inverted.is-hovered { + background-color: #f2f2f2; +} +.button.is-danger.is-inverted[disabled], +fieldset[disabled] .button.is-danger.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #f14668; +} +.button.is-danger.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + color: #f14668; +} +.button.is-danger.is-outlined:hover, +.button.is-danger.is-outlined.is-hovered, +.button.is-danger.is-outlined:focus, +.button.is-danger.is-outlined.is-focused { + background-color: #f14668; + border-color: #f14668; + color: #fff; +} +.button.is-danger.is-outlined.is-loading::after { + border-color: transparent transparent #f14668 #f14668 !important; +} +.button.is-danger.is-outlined.is-loading:hover::after, +.button.is-danger.is-outlined.is-loading.is-hovered::after, +.button.is-danger.is-outlined.is-loading:focus::after, +.button.is-danger.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} +.button.is-danger.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + box-shadow: none; + color: #f14668; +} +.button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} +.button.is-danger.is-inverted.is-outlined:hover, +.button.is-danger.is-inverted.is-outlined.is-hovered, +.button.is-danger.is-inverted.is-outlined:focus, +.button.is-danger.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #f14668; +} +.button.is-danger.is-inverted.is-outlined.is-loading:hover::after, +.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-danger.is-inverted.is-outlined.is-loading:focus::after, +.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #f14668 #f14668 !important; +} +.button.is-danger.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} +.button.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} +.button.is-danger.is-light:hover, +.button.is-danger.is-light.is-hovered { + background-color: #fde0e6; + border-color: transparent; + color: #cc0f35; +} +.button.is-danger.is-light:active, +.button.is-danger.is-light.is-active { + background-color: #fcd4dc; + border-color: transparent; + color: #cc0f35; +} +.button.is-grey-lightest { + background-color: #ededed; + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest:hover, +.button.is-grey-lightest.is-hovered { + background-color: #e7e7e7; + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest:focus, +.button.is-grey-lightest.is-focused { + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest:focus:not(:active), +.button.is-grey-lightest.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(237,237,237,0.25); +} +.button.is-grey-lightest:active, +.button.is-grey-lightest.is-active { + background-color: #e0e0e0; + border-color: transparent; + color: #363636; +} +.button.is-grey-lightest[disabled], +fieldset[disabled] .button.is-grey-lightest { + background-color: #ededed; + border-color: transparent; + box-shadow: none; +} +.button.is-grey-lightest.is-inverted { + background-color: #363636; + color: #ededed; +} +.button.is-grey-lightest.is-inverted:hover, +.button.is-grey-lightest.is-inverted.is-hovered { + background-color: #292929; +} +.button.is-grey-lightest.is-inverted[disabled], +fieldset[disabled] .button.is-grey-lightest.is-inverted { + background-color: #363636; + border-color: transparent; + box-shadow: none; + color: #ededed; +} +.button.is-grey-lightest.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-grey-lightest.is-outlined { + background-color: transparent; + border-color: #ededed; + color: #ededed; +} +.button.is-grey-lightest.is-outlined:hover, +.button.is-grey-lightest.is-outlined.is-hovered, +.button.is-grey-lightest.is-outlined:focus, +.button.is-grey-lightest.is-outlined.is-focused { + background-color: #ededed; + border-color: #ededed; + color: #363636; +} +.button.is-grey-lightest.is-outlined.is-loading::after { + border-color: transparent transparent #ededed #ededed !important; +} +.button.is-grey-lightest.is-outlined.is-loading:hover::after, +.button.is-grey-lightest.is-outlined.is-loading.is-hovered::after, +.button.is-grey-lightest.is-outlined.is-loading:focus::after, +.button.is-grey-lightest.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; +} +.button.is-grey-lightest.is-outlined[disabled], +fieldset[disabled] .button.is-grey-lightest.is-outlined { + background-color: transparent; + border-color: #ededed; + box-shadow: none; + color: #ededed; +} +.button.is-grey-lightest.is-inverted.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; +} +.button.is-grey-lightest.is-inverted.is-outlined:hover, +.button.is-grey-lightest.is-inverted.is-outlined.is-hovered, +.button.is-grey-lightest.is-inverted.is-outlined:focus, +.button.is-grey-lightest.is-inverted.is-outlined.is-focused { + background-color: #363636; + color: #ededed; +} +.button.is-grey-lightest.is-inverted.is-outlined.is-loading:hover::after, +.button.is-grey-lightest.is-inverted.is-outlined.is-loading.is-hovered::after, +.button.is-grey-lightest.is-inverted.is-outlined.is-loading:focus::after, +.button.is-grey-lightest.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ededed #ededed !important; +} +.button.is-grey-lightest.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-grey-lightest.is-inverted.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; +} +.button.is-small { + border-radius: 2px; + font-size: 0.75rem; +} +.button.is-normal { + font-size: 1rem; +} +.button.is-medium { + font-size: 1.25rem; +} +.button.is-large { + font-size: 1.5rem; +} +.button[disabled], +fieldset[disabled] .button { + background-color: #fff; + border-color: #dbdbdb; + box-shadow: none; + opacity: 0.5; +} +.button.is-fullwidth { + display: flex; + width: 100%; +} +.button.is-loading { + color: transparent !important; + pointer-events: none; +} +.button.is-loading::after { + position: absolute; + left: calc(50% - (1em / 2)); + top: calc(50% - (1em / 2)); + position: absolute !important; +} +.button.is-static { + background-color: #f5f5f5; + border-color: #dbdbdb; + color: #7a7a7a; + box-shadow: none; + pointer-events: none; +} +.button.is-rounded { + border-radius: 290486px; + padding-left: calc(1em + 0.25em); + padding-right: calc(1em + 0.25em); +} +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.buttons .button { + margin-bottom: 0.5rem; +} +.buttons .button:not(:last-child):not(.is-fullwidth) { + margin-right: 0.5rem; +} +.buttons:last-child { + margin-bottom: -0.5rem; +} +.buttons:not(:last-child) { + margin-bottom: 1rem; +} +.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large) { + border-radius: 2px; + font-size: 0.75rem; +} +.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large) { + font-size: 1.25rem; +} +.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium) { + font-size: 1.5rem; +} +.buttons.has-addons .button:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.buttons.has-addons .button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: -1px; +} +.buttons.has-addons .button:last-child { + margin-right: 0; +} +.buttons.has-addons .button:hover, +.buttons.has-addons .button.is-hovered { + z-index: 2; +} +.buttons.has-addons .button:focus, +.buttons.has-addons .button.is-focused, +.buttons.has-addons .button:active, +.buttons.has-addons .button.is-active, +.buttons.has-addons .button.is-selected { + z-index: 3; +} +.buttons.has-addons .button:focus:hover, +.buttons.has-addons .button.is-focused:hover, +.buttons.has-addons .button:active:hover, +.buttons.has-addons .button.is-active:hover, +.buttons.has-addons .button.is-selected:hover { + z-index: 4; +} +.buttons.has-addons .button.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.buttons.is-centered { + justify-content: center; +} +.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} +.buttons.is-right { + justify-content: flex-end; +} +.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} +.container { + flex-grow: 1; + margin: 0 auto; + position: relative; + width: auto; +} +.container.is-fluid { + max-width: none; + padding-left: 64px; + padding-right: 64px; + width: 100%; +} +@media screen and (min-width: 1088px) { + .container { + max-width: 960px; + } +} +@media screen and (max-width: 1279px) { + .container.is-widescreen { + max-width: 1152px; + } +} +@media screen and (max-width: 1471px) { + .container.is-fullhd { + max-width: 1344px; + } +} +@media screen and (min-width: 1280px) { + .container { + max-width: 1152px; + } +} +@media screen and (min-width: 1472px) { + .container { + max-width: 1344px; + } +} +.content li + li { + margin-top: 0.25em; +} +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: 1em; +} +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: #363636; + font-weight: 400; + line-height: 1.125; +} +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; +} +.content h1:not(:first-child) { + margin-top: 1em; +} +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; +} +.content h2:not(:first-child) { + margin-top: 1.1428em; +} +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; +} +.content h3:not(:first-child) { + margin-top: 1.3333em; +} +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; +} +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; +} +.content h6 { + font-size: 1em; + margin-bottom: 1em; +} +.content blockquote { + background-color: #f5f5f5; + border-left: 5px solid #dbdbdb; + padding: 1.25em 1.5em; +} +.content ol { + list-style-position: outside; + margin-left: 2em; + margin-top: 1em; +} +.content ol:not([type]) { + list-style-type: decimal; +} +.content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; +} +.content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; +} +.content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; +} +.content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; +} +.content ul { + list-style: disc outside; + margin-left: 2em; + margin-top: 1em; +} +.content ul ul { + list-style-type: circle; + margin-top: 0.5em; +} +.content ul ul ul { + list-style-type: square; +} +.content dd { + margin-left: 2em; +} +.content figure { + margin-left: 2em; + margin-right: 2em; + text-align: center; +} +.content figure:not(:first-child) { + margin-top: 2em; +} +.content figure:not(:last-child) { + margin-bottom: 2em; +} +.content figure img { + display: inline-block; +} +.content figure figcaption { + font-style: italic; +} +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1.25em 1.5em; + white-space: pre; + word-wrap: normal; +} +.content sup, +.content sub { + font-size: 75%; +} +.content table { + width: 100%; +} +.content table td, +.content table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} +.content table th { + color: #363636; +} +.content table th:not([align]) { + text-align: left; +} +.content table thead td, +.content table thead th { + border-width: 0 0 2px; + color: #363636; +} +.content table tfoot td, +.content table tfoot th { + border-width: 2px 0 0; + color: #363636; +} +.content table tbody tr:last-child td, +.content table tbody tr:last-child th { + border-bottom-width: 0; +} +.content .tabs li + li { + margin-top: 0; +} +.content.is-small { + font-size: 0.75rem; +} +.content.is-medium { + font-size: 1.25rem; +} +.content.is-large { + font-size: 1.5rem; +} +.icon { + align-items: center; + display: inline-flex; + justify-content: center; + height: 1.5rem; + width: 1.5rem; +} +.icon.is-small { + height: 1rem; + width: 1rem; +} +.icon.is-medium { + height: 2rem; + width: 2rem; +} +.icon.is-large { + height: 3rem; + width: 3rem; +} +.image { + display: block; + position: relative; +} +.image img { + display: block; + height: auto; + width: 100%; +} +.image img.is-rounded { + border-radius: 290486px; +} +.image.is-fullwidth { + width: 100%; +} +.image.is-square img, +.image.is-1by1 img, +.image.is-5by4 img, +.image.is-4by3 img, +.image.is-3by2 img, +.image.is-5by3 img, +.image.is-16by9 img, +.image.is-2by1 img, +.image.is-3by1 img, +.image.is-4by5 img, +.image.is-3by4 img, +.image.is-2by3 img, +.image.is-3by5 img, +.image.is-9by16 img, +.image.is-1by2 img, +.image.is-1by3 img, +.image.is-square .has-ratio, +.image.is-1by1 .has-ratio, +.image.is-5by4 .has-ratio, +.image.is-4by3 .has-ratio, +.image.is-3by2 .has-ratio, +.image.is-5by3 .has-ratio, +.image.is-16by9 .has-ratio, +.image.is-2by1 .has-ratio, +.image.is-3by1 .has-ratio, +.image.is-4by5 .has-ratio, +.image.is-3by4 .has-ratio, +.image.is-2by3 .has-ratio, +.image.is-3by5 .has-ratio, +.image.is-9by16 .has-ratio, +.image.is-1by2 .has-ratio, +.image.is-1by3 .has-ratio { + height: 100%; + width: 100%; +} +.image.is-square, +.image.is-1by1 { + padding-top: 100%; +} +.image.is-5by4 { + padding-top: 80%; +} +.image.is-4by3 { + padding-top: 75%; +} +.image.is-3by2 { + padding-top: 66.6666%; +} +.image.is-5by3 { + padding-top: 60%; +} +.image.is-16by9 { + padding-top: 56.25%; +} +.image.is-2by1 { + padding-top: 50%; +} +.image.is-3by1 { + padding-top: 33.3333%; +} +.image.is-4by5 { + padding-top: 125%; +} +.image.is-3by4 { + padding-top: 133.3333%; +} +.image.is-2by3 { + padding-top: 150%; +} +.image.is-3by5 { + padding-top: 166.6666%; +} +.image.is-9by16 { + padding-top: 177.7777%; +} +.image.is-1by2 { + padding-top: 200%; +} +.image.is-1by3 { + padding-top: 300%; +} +.image.is-16x16 { + height: 16px; + width: 16px; +} +.image.is-24x24 { + height: 24px; + width: 24px; +} +.image.is-32x32 { + height: 32px; + width: 32px; +} +.image.is-48x48 { + height: 48px; + width: 48px; +} +.image.is-64x64 { + height: 64px; + width: 64px; +} +.image.is-96x96 { + height: 96px; + width: 96px; +} +.image.is-128x128 { + height: 128px; + width: 128px; +} +.notification { + background-color: #f5f5f5; + border-radius: 4px; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; + position: relative; +} +.notification a:not(.button):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} +.notification strong { + color: currentColor; +} +.notification code, +.notification pre { + background: #fff; +} +.notification pre code { + background: transparent; +} +.notification > .delete { + position: absolute; + right: 0.5rem; + top: 0.5rem; +} +.notification .title, +.notification .subtitle, +.notification .content { + color: currentColor; +} +.notification.is-white { + background-color: #fff; + color: #0a0a0a; +} +.notification.is-black { + background-color: #0a0a0a; + color: #fff; +} +.notification.is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.notification.is-dark { + background-color: #363636; + color: #fff; +} +.notification.is-primary { + background-color: #3273dc; + color: #fff; +} +.notification.is-link { + background-color: #3273dc; + color: #fff; +} +.notification.is-info { + background-color: #3298dc; + color: #fff; +} +.notification.is-success { + background-color: #48c774; + color: #fff; +} +.notification.is-warning { + background-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.notification.is-danger { + background-color: #f14668; + color: #fff; +} +.notification.is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 290486px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; +} +.progress::-webkit-progress-bar { + background-color: #ededed; +} +.progress::-webkit-progress-value { + background-color: #4a4a4a; +} +.progress::-moz-progress-bar { + background-color: #4a4a4a; +} +.progress::-ms-fill { + background-color: #4a4a4a; + border: none; +} +.progress.is-white::-webkit-progress-value { + background-color: #fff; +} +.progress.is-white::-moz-progress-bar { + background-color: #fff; +} +.progress.is-white::-ms-fill { + background-color: #fff; +} +.progress.is-white:indeterminate { + background-image: linear-gradient(to right, #fff 30%, #ededed 30%); +} +.progress.is-black::-webkit-progress-value { + background-color: #0a0a0a; +} +.progress.is-black::-moz-progress-bar { + background-color: #0a0a0a; +} +.progress.is-black::-ms-fill { + background-color: #0a0a0a; +} +.progress.is-black:indeterminate { + background-image: linear-gradient(to right, #0a0a0a 30%, #ededed 30%); +} +.progress.is-light::-webkit-progress-value { + background-color: #f5f5f5; +} +.progress.is-light::-moz-progress-bar { + background-color: #f5f5f5; +} +.progress.is-light::-ms-fill { + background-color: #f5f5f5; +} +.progress.is-light:indeterminate { + background-image: linear-gradient(to right, #f5f5f5 30%, #ededed 30%); +} +.progress.is-dark::-webkit-progress-value { + background-color: #363636; +} +.progress.is-dark::-moz-progress-bar { + background-color: #363636; +} +.progress.is-dark::-ms-fill { + background-color: #363636; +} +.progress.is-dark:indeterminate { + background-image: linear-gradient(to right, #363636 30%, #ededed 30%); +} +.progress.is-primary::-webkit-progress-value { + background-color: #3273dc; +} +.progress.is-primary::-moz-progress-bar { + background-color: #3273dc; +} +.progress.is-primary::-ms-fill { + background-color: #3273dc; +} +.progress.is-primary:indeterminate { + background-image: linear-gradient(to right, #3273dc 30%, #ededed 30%); +} +.progress.is-link::-webkit-progress-value { + background-color: #3273dc; +} +.progress.is-link::-moz-progress-bar { + background-color: #3273dc; +} +.progress.is-link::-ms-fill { + background-color: #3273dc; +} +.progress.is-link:indeterminate { + background-image: linear-gradient(to right, #3273dc 30%, #ededed 30%); +} +.progress.is-info::-webkit-progress-value { + background-color: #3298dc; +} +.progress.is-info::-moz-progress-bar { + background-color: #3298dc; +} +.progress.is-info::-ms-fill { + background-color: #3298dc; +} +.progress.is-info:indeterminate { + background-image: linear-gradient(to right, #3298dc 30%, #ededed 30%); +} +.progress.is-success::-webkit-progress-value { + background-color: #48c774; +} +.progress.is-success::-moz-progress-bar { + background-color: #48c774; +} +.progress.is-success::-ms-fill { + background-color: #48c774; +} +.progress.is-success:indeterminate { + background-image: linear-gradient(to right, #48c774 30%, #ededed 30%); +} +.progress.is-warning::-webkit-progress-value { + background-color: #ffdd57; +} +.progress.is-warning::-moz-progress-bar { + background-color: #ffdd57; +} +.progress.is-warning::-ms-fill { + background-color: #ffdd57; +} +.progress.is-warning:indeterminate { + background-image: linear-gradient(to right, #ffdd57 30%, #ededed 30%); +} +.progress.is-danger::-webkit-progress-value { + background-color: #f14668; +} +.progress.is-danger::-moz-progress-bar { + background-color: #f14668; +} +.progress.is-danger::-ms-fill { + background-color: #f14668; +} +.progress.is-danger:indeterminate { + background-image: linear-gradient(to right, #f14668 30%, #ededed 30%); +} +.progress.is-grey-lightest::-webkit-progress-value { + background-color: #ededed; +} +.progress.is-grey-lightest::-moz-progress-bar { + background-color: #ededed; +} +.progress.is-grey-lightest::-ms-fill { + background-color: #ededed; +} +.progress.is-grey-lightest:indeterminate { + background-image: linear-gradient(to right, #ededed 30%, #ededed 30%); +} +.progress:indeterminate { + animation-duration: 1.5s; + animation-iteration-count: infinite; + animation-name: moveIndeterminate; + animation-timing-function: linear; + background-color: #ededed; + background-image: linear-gradient(to right, #4a4a4a 30%, #ededed 30%); + background-position: top left; + background-repeat: no-repeat; + background-size: 150% 150%; +} +.progress:indeterminate::-webkit-progress-bar { + background-color: transparent; +} +.progress:indeterminate::-moz-progress-bar { + background-color: transparent; +} +.progress.is-small { + height: 0.75rem; +} +.progress.is-medium { + height: 1.25rem; +} +.progress.is-large { + height: 1.5rem; +} +@-moz-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +@-webkit-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +@-o-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +@keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +.table { + background-color: #fff; + color: #363636; +} +.table td, +.table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} +.table td.is-white, +.table th.is-white { + background-color: #fff; + border-color: #fff; + color: #0a0a0a; +} +.table td.is-black, +.table th.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: #fff; +} +.table td.is-light, +.table th.is-light { + background-color: #f5f5f5; + border-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.table td.is-dark, +.table th.is-dark { + background-color: #363636; + border-color: #363636; + color: #fff; +} +.table td.is-primary, +.table th.is-primary { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; +} +.table td.is-link, +.table th.is-link { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; +} +.table td.is-info, +.table th.is-info { + background-color: #3298dc; + border-color: #3298dc; + color: #fff; +} +.table td.is-success, +.table th.is-success { + background-color: #48c774; + border-color: #48c774; + color: #fff; +} +.table td.is-warning, +.table th.is-warning { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.table td.is-danger, +.table th.is-danger { + background-color: #f14668; + border-color: #f14668; + color: #fff; +} +.table td.is-grey-lightest, +.table th.is-grey-lightest { + background-color: #ededed; + border-color: #ededed; + color: #363636; +} +.table td.is-narrow, +.table th.is-narrow { + white-space: nowrap; + width: 1%; +} +.table td.is-selected, +.table th.is-selected { + background-color: #3273dc; + color: #fff; +} +.table td.is-selected a, +.table th.is-selected a, +.table td.is-selected strong, +.table th.is-selected strong { + color: currentColor; +} +.table th { + color: #363636; +} +.table th:not([align]) { + text-align: left; +} +.table tr.is-selected { + background-color: #3273dc; + color: #fff; +} +.table tr.is-selected a, +.table tr.is-selected strong { + color: currentColor; +} +.table tr.is-selected td, +.table tr.is-selected th { + border-color: #fff; + color: currentColor; +} +.table thead { + background-color: transparent; +} +.table thead td, +.table thead th { + border-width: 0 0 2px; + color: #363636; +} +.table tfoot { + background-color: transparent; +} +.table tfoot td, +.table tfoot th { + border-width: 2px 0 0; + color: #363636; +} +.table tbody { + background-color: transparent; +} +.table tbody tr:last-child td, +.table tbody tr:last-child th { + border-bottom-width: 0; +} +.table.is-bordered td, +.table.is-bordered th { + border-width: 1px; +} +.table.is-bordered tr:last-child td, +.table.is-bordered tr:last-child th { + border-bottom-width: 1px; +} +.table.is-fullwidth { + width: 100%; +} +.table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #fafafa; +} +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: #fafafa; +} +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: #f5f5f5; +} +.table.is-narrow td, +.table.is-narrow th { + padding: 0.25em 0.5em; +} +.table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #fafafa; +} +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; +} +.tags { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.tags .tag { + margin-bottom: 0.5rem; +} +.tags .tag:not(:last-child) { + margin-right: 0.5rem; +} +.tags:last-child { + margin-bottom: -0.5rem; +} +.tags:not(:last-child) { + margin-bottom: 1rem; +} +.tags.are-medium .tag:not(.is-normal):not(.is-large) { + font-size: 1rem; +} +.tags.are-large .tag:not(.is-normal):not(.is-medium) { + font-size: 1.25rem; +} +.tags.is-centered { + justify-content: center; +} +.tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; +} +.tags.is-right { + justify-content: flex-end; +} +.tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; +} +.tags.is-right .tag:not(:last-child) { + margin-right: 0; +} +.tags.has-addons .tag { + margin-right: 0; +} +.tags.has-addons .tag:not(:first-child) { + margin-left: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.tags.has-addons .tag:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.tag:not(body) { + align-items: center; + background-color: #f5f5f5; + border-radius: 4px; + color: #4a4a4a; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} +.tag:not(body) .delete { + margin-left: 0.25rem; + margin-right: -0.375rem; +} +.tag:not(body).is-white { + background-color: #fff; + color: #0a0a0a; +} +.tag:not(body).is-black { + background-color: #0a0a0a; + color: #fff; +} +.tag:not(body).is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.tag:not(body).is-dark { + background-color: #363636; + color: #fff; +} +.tag:not(body).is-primary { + background-color: #3273dc; + color: #fff; +} +.tag:not(body).is-primary.is-light { + background-color: #eef3fc; + color: #2160c4; +} +.tag:not(body).is-link { + background-color: #3273dc; + color: #fff; +} +.tag:not(body).is-link.is-light { + background-color: #eef3fc; + color: #2160c4; +} +.tag:not(body).is-info { + background-color: #3298dc; + color: #fff; +} +.tag:not(body).is-info.is-light { + background-color: #eef6fc; + color: #1d72aa; +} +.tag:not(body).is-success { + background-color: #48c774; + color: #fff; +} +.tag:not(body).is-success.is-light { + background-color: #effaf3; + color: #257942; +} +.tag:not(body).is-warning { + background-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.tag:not(body).is-warning.is-light { + background-color: #fffbeb; + color: #947600; +} +.tag:not(body).is-danger { + background-color: #f14668; + color: #fff; +} +.tag:not(body).is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} +.tag:not(body).is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.tag:not(body).is-normal { + font-size: 0.75rem; +} +.tag:not(body).is-medium { + font-size: 1rem; +} +.tag:not(body).is-large { + font-size: 1.25rem; +} +.tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; +} +.tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; +} +.tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; +} +.tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; +} +.tag:not(body).is-delete::before, +.tag:not(body).is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} +.tag:not(body).is-delete::before { + height: 1px; + width: 50%; +} +.tag:not(body).is-delete::after { + height: 50%; + width: 1px; +} +.tag:not(body).is-delete:hover, +.tag:not(body).is-delete:focus { + background-color: #e8e8e8; +} +.tag:not(body).is-delete:active { + background-color: #dbdbdb; +} +.tag:not(body).is-rounded { + border-radius: 290486px; +} +a.tag:hover { + text-decoration: underline; +} +.title, +.subtitle { + word-break: break-word; +} +.title em, +.subtitle em, +.title span, +.subtitle span { + font-weight: inherit; +} +.title sub, +.subtitle sub { + font-size: 0.75em; +} +.title sup, +.subtitle sup { + font-size: 0.75em; +} +.title .tag, +.subtitle .tag { + vertical-align: middle; +} +.title { + color: #363636; + font-size: 2rem; + font-weight: 400; + line-height: 1.125; +} +.title strong { + color: inherit; + font-weight: inherit; +} +.title + .highlight { + margin-top: -0.75rem; +} +.title:not(.is-spaced) + .subtitle { + margin-top: -1.25rem; +} +.title.is-1 { + font-size: 3rem; +} +.title.is-2 { + font-size: 2.5rem; +} +.title.is-3 { + font-size: 2rem; +} +.title.is-4 { + font-size: 1.5rem; +} +.title.is-5 { + font-size: 1.25rem; +} +.title.is-6 { + font-size: 1rem; +} +.title.is-7 { + font-size: 0.85rem; +} +.subtitle { + color: #4a4a4a; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; +} +.subtitle strong { + color: #363636; + font-weight: 600; +} +.subtitle:not(.is-spaced) + .title { + margin-top: -1.25rem; +} +.subtitle.is-1 { + font-size: 3rem; +} +.subtitle.is-2 { + font-size: 2.5rem; +} +.subtitle.is-3 { + font-size: 2rem; +} +.subtitle.is-4 { + font-size: 1.5rem; +} +.subtitle.is-5 { + font-size: 1.25rem; +} +.subtitle.is-6 { + font-size: 1rem; +} +.subtitle.is-7 { + font-size: 0.85rem; +} +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; +} +.highlight { + font-weight: 400; + max-width: 100%; + overflow: hidden; + padding: 0; +} +.highlight pre { + overflow: auto; + max-width: 100%; +} +.number { + align-items: center; + background-color: #f5f5f5; + border-radius: 290486px; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; +} +.input, +.textarea, +.select select { + background-color: #fff; + border-color: #dbdbdb; + border-radius: 4px; + color: #363636; +} +.input::-moz-placeholder, +.textarea::-moz-placeholder, +.select select::-moz-placeholder { + color: rgba(54,54,54,0.3); +} +.input::-webkit-input-placeholder, +.textarea::-webkit-input-placeholder, +.select select::-webkit-input-placeholder { + color: rgba(54,54,54,0.3); +} +.input:-moz-placeholder, +.textarea:-moz-placeholder, +.select select:-moz-placeholder { + color: rgba(54,54,54,0.3); +} +.input:-ms-input-placeholder, +.textarea:-ms-input-placeholder, +.select select:-ms-input-placeholder { + color: rgba(54,54,54,0.3); +} +.input:hover, +.textarea:hover, +.select select:hover, +.input.is-hovered, +.textarea.is-hovered, +.select select.is-hovered { + border-color: #b5b5b5; +} +.input:focus, +.textarea:focus, +.select select:focus, +.input.is-focused, +.textarea.is-focused, +.select select.is-focused, +.input:active, +.textarea:active, +.select select:active, +.input.is-active, +.textarea.is-active, +.select select.is-active { + border-color: #3273dc; + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.input[disabled], +.textarea[disabled], +.select select[disabled], +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select { + background-color: #f5f5f5; + border-color: #f5f5f5; + box-shadow: none; + color: #7a7a7a; +} +.input[disabled]::-moz-placeholder, +.textarea[disabled]::-moz-placeholder, +.select select[disabled]::-moz-placeholder, +fieldset[disabled] .input::-moz-placeholder, +fieldset[disabled] .textarea::-moz-placeholder, +fieldset[disabled] .select select::-moz-placeholder { + color: rgba(122,122,122,0.3); +} +.input[disabled]::-webkit-input-placeholder, +.textarea[disabled]::-webkit-input-placeholder, +.select select[disabled]::-webkit-input-placeholder, +fieldset[disabled] .input::-webkit-input-placeholder, +fieldset[disabled] .textarea::-webkit-input-placeholder, +fieldset[disabled] .select select::-webkit-input-placeholder { + color: rgba(122,122,122,0.3); +} +.input[disabled]:-moz-placeholder, +.textarea[disabled]:-moz-placeholder, +.select select[disabled]:-moz-placeholder, +fieldset[disabled] .input:-moz-placeholder, +fieldset[disabled] .textarea:-moz-placeholder, +fieldset[disabled] .select select:-moz-placeholder { + color: rgba(122,122,122,0.3); +} +.input[disabled]:-ms-input-placeholder, +.textarea[disabled]:-ms-input-placeholder, +.select select[disabled]:-ms-input-placeholder, +fieldset[disabled] .input:-ms-input-placeholder, +fieldset[disabled] .textarea:-ms-input-placeholder, +fieldset[disabled] .select select:-ms-input-placeholder { + color: rgba(122,122,122,0.3); +} +.input, +.textarea { + box-shadow: inset 0 0.0625em 0.125em rgba(10,10,10,0.05); + max-width: 100%; + width: 100%; +} +.input[readonly], +.textarea[readonly] { + box-shadow: none; +} +.input.is-white, +.textarea.is-white { + border-color: #fff; +} +.input.is-white:focus, +.textarea.is-white:focus, +.input.is-white.is-focused, +.textarea.is-white.is-focused, +.input.is-white:active, +.textarea.is-white:active, +.input.is-white.is-active, +.textarea.is-white.is-active { + box-shadow: 0 0 0 0.125em rgba(255,255,255,0.25); +} +.input.is-black, +.textarea.is-black { + border-color: #0a0a0a; +} +.input.is-black:focus, +.textarea.is-black:focus, +.input.is-black.is-focused, +.textarea.is-black.is-focused, +.input.is-black:active, +.textarea.is-black:active, +.input.is-black.is-active, +.textarea.is-black.is-active { + box-shadow: 0 0 0 0.125em rgba(10,10,10,0.25); +} +.input.is-light, +.textarea.is-light { + border-color: #f5f5f5; +} +.input.is-light:focus, +.textarea.is-light:focus, +.input.is-light.is-focused, +.textarea.is-light.is-focused, +.input.is-light:active, +.textarea.is-light:active, +.input.is-light.is-active, +.textarea.is-light.is-active { + box-shadow: 0 0 0 0.125em rgba(245,245,245,0.25); +} +.input.is-dark, +.textarea.is-dark { + border-color: #363636; +} +.input.is-dark:focus, +.textarea.is-dark:focus, +.input.is-dark.is-focused, +.textarea.is-dark.is-focused, +.input.is-dark:active, +.textarea.is-dark:active, +.input.is-dark.is-active, +.textarea.is-dark.is-active { + box-shadow: 0 0 0 0.125em rgba(54,54,54,0.25); +} +.input.is-primary, +.textarea.is-primary { + border-color: #3273dc; +} +.input.is-primary:focus, +.textarea.is-primary:focus, +.input.is-primary.is-focused, +.textarea.is-primary.is-focused, +.input.is-primary:active, +.textarea.is-primary:active, +.input.is-primary.is-active, +.textarea.is-primary.is-active { + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.input.is-link, +.textarea.is-link { + border-color: #3273dc; +} +.input.is-link:focus, +.textarea.is-link:focus, +.input.is-link.is-focused, +.textarea.is-link.is-focused, +.input.is-link:active, +.textarea.is-link:active, +.input.is-link.is-active, +.textarea.is-link.is-active { + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.input.is-info, +.textarea.is-info { + border-color: #3298dc; +} +.input.is-info:focus, +.textarea.is-info:focus, +.input.is-info.is-focused, +.textarea.is-info.is-focused, +.input.is-info:active, +.textarea.is-info:active, +.input.is-info.is-active, +.textarea.is-info.is-active { + box-shadow: 0 0 0 0.125em rgba(50,152,220,0.25); +} +.input.is-success, +.textarea.is-success { + border-color: #48c774; +} +.input.is-success:focus, +.textarea.is-success:focus, +.input.is-success.is-focused, +.textarea.is-success.is-focused, +.input.is-success:active, +.textarea.is-success:active, +.input.is-success.is-active, +.textarea.is-success.is-active { + box-shadow: 0 0 0 0.125em rgba(72,199,116,0.25); +} +.input.is-warning, +.textarea.is-warning { + border-color: #ffdd57; +} +.input.is-warning:focus, +.textarea.is-warning:focus, +.input.is-warning.is-focused, +.textarea.is-warning.is-focused, +.input.is-warning:active, +.textarea.is-warning:active, +.input.is-warning.is-active, +.textarea.is-warning.is-active { + box-shadow: 0 0 0 0.125em rgba(255,221,87,0.25); +} +.input.is-danger, +.textarea.is-danger { + border-color: #f14668; +} +.input.is-danger:focus, +.textarea.is-danger:focus, +.input.is-danger.is-focused, +.textarea.is-danger.is-focused, +.input.is-danger:active, +.textarea.is-danger:active, +.input.is-danger.is-active, +.textarea.is-danger.is-active { + box-shadow: 0 0 0 0.125em rgba(241,70,104,0.25); +} +.input.is-grey-lightest, +.textarea.is-grey-lightest { + border-color: #ededed; +} +.input.is-grey-lightest:focus, +.textarea.is-grey-lightest:focus, +.input.is-grey-lightest.is-focused, +.textarea.is-grey-lightest.is-focused, +.input.is-grey-lightest:active, +.textarea.is-grey-lightest:active, +.input.is-grey-lightest.is-active, +.textarea.is-grey-lightest.is-active { + box-shadow: 0 0 0 0.125em rgba(237,237,237,0.25); +} +.input.is-small, +.textarea.is-small { + border-radius: 2px; + font-size: 0.75rem; +} +.input.is-medium, +.textarea.is-medium { + font-size: 1.25rem; +} +.input.is-large, +.textarea.is-large { + font-size: 1.5rem; +} +.input.is-fullwidth, +.textarea.is-fullwidth { + display: block; + width: 100%; +} +.input.is-inline, +.textarea.is-inline { + display: inline; + width: auto; +} +.input.is-rounded { + border-radius: 290486px; + padding-left: calc(calc(0.75em - 1px) + 0.375em); + padding-right: calc(calc(0.75em - 1px) + 0.375em); +} +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; +} +.textarea { + display: block; + max-width: 100%; + min-width: 100%; + padding: calc(0.75em - 1px); + resize: vertical; +} +.textarea:not([rows]) { + max-height: 40em; + min-height: 8em; +} +.textarea[rows] { + height: initial; +} +.textarea.has-fixed-size { + resize: none; +} +.checkbox, +.radio { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; +} +.checkbox input, +.radio input { + cursor: pointer; +} +.checkbox:hover, +.radio:hover { + color: #363636; +} +.checkbox[disabled], +.radio[disabled], +fieldset[disabled] .checkbox, +fieldset[disabled] .radio { + color: #7a7a7a; + cursor: not-allowed; +} +.radio + .radio { + margin-left: 0.5em; +} +.select { + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; +} +.select:not(.is-multiple) { + height: 2.25em; +} +.select:not(.is-multiple):not(.is-loading)::after { + border-color: #3273dc; + right: 1.125em; + z-index: 4; +} +.select.is-rounded select { + border-radius: 290486px; + padding-left: 1em; +} +.select select { + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; +} +.select select::-ms-expand { + display: none; +} +.select select[disabled]:hover, +fieldset[disabled] .select select:hover { + border-color: #f5f5f5; +} +.select select:not([multiple]) { + padding-right: 2.5em; +} +.select select[multiple] { + height: auto; + padding: 0; +} +.select select[multiple] option { + padding: 0.5em 1em; +} +.select:not(.is-multiple):not(.is-loading):hover::after { + border-color: #363636; +} +.select.is-white:not(:hover)::after { + border-color: #fff; +} +.select.is-white select { + border-color: #fff; +} +.select.is-white select:hover, +.select.is-white select.is-hovered { + border-color: #f2f2f2; +} +.select.is-white select:focus, +.select.is-white select.is-focused, +.select.is-white select:active, +.select.is-white select.is-active { + box-shadow: 0 0 0 0.125em rgba(255,255,255,0.25); +} +.select.is-black:not(:hover)::after { + border-color: #0a0a0a; +} +.select.is-black select { + border-color: #0a0a0a; +} +.select.is-black select:hover, +.select.is-black select.is-hovered { + border-color: #000; +} +.select.is-black select:focus, +.select.is-black select.is-focused, +.select.is-black select:active, +.select.is-black select.is-active { + box-shadow: 0 0 0 0.125em rgba(10,10,10,0.25); +} +.select.is-light:not(:hover)::after { + border-color: #f5f5f5; +} +.select.is-light select { + border-color: #f5f5f5; +} +.select.is-light select:hover, +.select.is-light select.is-hovered { + border-color: #e8e8e8; +} +.select.is-light select:focus, +.select.is-light select.is-focused, +.select.is-light select:active, +.select.is-light select.is-active { + box-shadow: 0 0 0 0.125em rgba(245,245,245,0.25); +} +.select.is-dark:not(:hover)::after { + border-color: #363636; +} +.select.is-dark select { + border-color: #363636; +} +.select.is-dark select:hover, +.select.is-dark select.is-hovered { + border-color: #292929; +} +.select.is-dark select:focus, +.select.is-dark select.is-focused, +.select.is-dark select:active, +.select.is-dark select.is-active { + box-shadow: 0 0 0 0.125em rgba(54,54,54,0.25); +} +.select.is-primary:not(:hover)::after { + border-color: #3273dc; +} +.select.is-primary select { + border-color: #3273dc; +} +.select.is-primary select:hover, +.select.is-primary select.is-hovered { + border-color: #2366d1; +} +.select.is-primary select:focus, +.select.is-primary select.is-focused, +.select.is-primary select:active, +.select.is-primary select.is-active { + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.select.is-link:not(:hover)::after { + border-color: #3273dc; +} +.select.is-link select { + border-color: #3273dc; +} +.select.is-link select:hover, +.select.is-link select.is-hovered { + border-color: #2366d1; +} +.select.is-link select:focus, +.select.is-link select.is-focused, +.select.is-link select:active, +.select.is-link select.is-active { + box-shadow: 0 0 0 0.125em rgba(50,115,220,0.25); +} +.select.is-info:not(:hover)::after { + border-color: #3298dc; +} +.select.is-info select { + border-color: #3298dc; +} +.select.is-info select:hover, +.select.is-info select.is-hovered { + border-color: #238cd1; +} +.select.is-info select:focus, +.select.is-info select.is-focused, +.select.is-info select:active, +.select.is-info select.is-active { + box-shadow: 0 0 0 0.125em rgba(50,152,220,0.25); +} +.select.is-success:not(:hover)::after { + border-color: #48c774; +} +.select.is-success select { + border-color: #48c774; +} +.select.is-success select:hover, +.select.is-success select.is-hovered { + border-color: #3abb67; +} +.select.is-success select:focus, +.select.is-success select.is-focused, +.select.is-success select:active, +.select.is-success select.is-active { + box-shadow: 0 0 0 0.125em rgba(72,199,116,0.25); +} +.select.is-warning:not(:hover)::after { + border-color: #ffdd57; +} +.select.is-warning select { + border-color: #ffdd57; +} +.select.is-warning select:hover, +.select.is-warning select.is-hovered { + border-color: #ffd83d; +} +.select.is-warning select:focus, +.select.is-warning select.is-focused, +.select.is-warning select:active, +.select.is-warning select.is-active { + box-shadow: 0 0 0 0.125em rgba(255,221,87,0.25); +} +.select.is-danger:not(:hover)::after { + border-color: #f14668; +} +.select.is-danger select { + border-color: #f14668; +} +.select.is-danger select:hover, +.select.is-danger select.is-hovered { + border-color: #ef2e55; +} +.select.is-danger select:focus, +.select.is-danger select.is-focused, +.select.is-danger select:active, +.select.is-danger select.is-active { + box-shadow: 0 0 0 0.125em rgba(241,70,104,0.25); +} +.select.is-grey-lightest:not(:hover)::after { + border-color: #ededed; +} +.select.is-grey-lightest select { + border-color: #ededed; +} +.select.is-grey-lightest select:hover, +.select.is-grey-lightest select.is-hovered { + border-color: #e0e0e0; +} +.select.is-grey-lightest select:focus, +.select.is-grey-lightest select.is-focused, +.select.is-grey-lightest select:active, +.select.is-grey-lightest select.is-active { + box-shadow: 0 0 0 0.125em rgba(237,237,237,0.25); +} +.select.is-small { + border-radius: 2px; + font-size: 0.75rem; +} +.select.is-medium { + font-size: 1.25rem; +} +.select.is-large { + font-size: 1.5rem; +} +.select.is-disabled::after { + border-color: #7a7a7a; +} +.select.is-fullwidth { + width: 100%; +} +.select.is-fullwidth select { + width: 100%; +} +.select.is-loading::after { + margin-top: 0; + position: absolute; + right: 0.625em; + top: 0.625em; + transform: none; +} +.select.is-loading.is-small:after { + font-size: 0.75rem; +} +.select.is-loading.is-medium:after { + font-size: 1.25rem; +} +.select.is-loading.is-large:after { + font-size: 1.5rem; +} +.file { + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; +} +.file.is-white .file-cta { + background-color: #fff; + border-color: transparent; + color: #0a0a0a; +} +.file.is-white:hover .file-cta, +.file.is-white.is-hovered .file-cta { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; +} +.file.is-white:focus .file-cta, +.file.is-white.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255,255,255,0.25); + color: #0a0a0a; +} +.file.is-white:active .file-cta, +.file.is-white.is-active .file-cta { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; +} +.file.is-black .file-cta { + background-color: #0a0a0a; + border-color: transparent; + color: #fff; +} +.file.is-black:hover .file-cta, +.file.is-black.is-hovered .file-cta { + background-color: #040404; + border-color: transparent; + color: #fff; +} +.file.is-black:focus .file-cta, +.file.is-black.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(10,10,10,0.25); + color: #fff; +} +.file.is-black:active .file-cta, +.file.is-black.is-active .file-cta { + background-color: #000; + border-color: transparent; + color: #fff; +} +.file.is-light .file-cta { + background-color: #f5f5f5; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-light:hover .file-cta, +.file.is-light.is-hovered .file-cta { + background-color: #eee; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-light:focus .file-cta, +.file.is-light.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(245,245,245,0.25); + color: rgba(0,0,0,0.7); +} +.file.is-light:active .file-cta, +.file.is-light.is-active .file-cta { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-dark .file-cta { + background-color: #363636; + border-color: transparent; + color: #fff; +} +.file.is-dark:hover .file-cta, +.file.is-dark.is-hovered .file-cta { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} +.file.is-dark:focus .file-cta, +.file.is-dark.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(54,54,54,0.25); + color: #fff; +} +.file.is-dark:active .file-cta, +.file.is-dark.is-active .file-cta { + background-color: #292929; + border-color: transparent; + color: #fff; +} +.file.is-primary .file-cta { + background-color: #3273dc; + border-color: transparent; + color: #fff; +} +.file.is-primary:hover .file-cta, +.file.is-primary.is-hovered .file-cta { + background-color: #276cda; + border-color: transparent; + color: #fff; +} +.file.is-primary:focus .file-cta, +.file.is-primary.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50,115,220,0.25); + color: #fff; +} +.file.is-primary:active .file-cta, +.file.is-primary.is-active .file-cta { + background-color: #2366d1; + border-color: transparent; + color: #fff; +} +.file.is-link .file-cta { + background-color: #3273dc; + border-color: transparent; + color: #fff; +} +.file.is-link:hover .file-cta, +.file.is-link.is-hovered .file-cta { + background-color: #276cda; + border-color: transparent; + color: #fff; +} +.file.is-link:focus .file-cta, +.file.is-link.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50,115,220,0.25); + color: #fff; +} +.file.is-link:active .file-cta, +.file.is-link.is-active .file-cta { + background-color: #2366d1; + border-color: transparent; + color: #fff; +} +.file.is-info .file-cta { + background-color: #3298dc; + border-color: transparent; + color: #fff; +} +.file.is-info:hover .file-cta, +.file.is-info.is-hovered .file-cta { + background-color: #2793da; + border-color: transparent; + color: #fff; +} +.file.is-info:focus .file-cta, +.file.is-info.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50,152,220,0.25); + color: #fff; +} +.file.is-info:active .file-cta, +.file.is-info.is-active .file-cta { + background-color: #238cd1; + border-color: transparent; + color: #fff; +} +.file.is-success .file-cta { + background-color: #48c774; + border-color: transparent; + color: #fff; +} +.file.is-success:hover .file-cta, +.file.is-success.is-hovered .file-cta { + background-color: #3ec46d; + border-color: transparent; + color: #fff; +} +.file.is-success:focus .file-cta, +.file.is-success.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(72,199,116,0.25); + color: #fff; +} +.file.is-success:active .file-cta, +.file.is-success.is-active .file-cta { + background-color: #3abb67; + border-color: transparent; + color: #fff; +} +.file.is-warning .file-cta { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-warning:hover .file-cta, +.file.is-warning.is-hovered .file-cta { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-warning:focus .file-cta, +.file.is-warning.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255,221,87,0.25); + color: rgba(0,0,0,0.7); +} +.file.is-warning:active .file-cta, +.file.is-warning.is-active .file-cta { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0,0,0,0.7); +} +.file.is-danger .file-cta { + background-color: #f14668; + border-color: transparent; + color: #fff; +} +.file.is-danger:hover .file-cta, +.file.is-danger.is-hovered .file-cta { + background-color: #f03a5f; + border-color: transparent; + color: #fff; +} +.file.is-danger:focus .file-cta, +.file.is-danger.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(241,70,104,0.25); + color: #fff; +} +.file.is-danger:active .file-cta, +.file.is-danger.is-active .file-cta { + background-color: #ef2e55; + border-color: transparent; + color: #fff; +} +.file.is-grey-lightest .file-cta { + background-color: #ededed; + border-color: transparent; + color: #363636; +} +.file.is-grey-lightest:hover .file-cta, +.file.is-grey-lightest.is-hovered .file-cta { + background-color: #e7e7e7; + border-color: transparent; + color: #363636; +} +.file.is-grey-lightest:focus .file-cta, +.file.is-grey-lightest.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(237,237,237,0.25); + color: #363636; +} +.file.is-grey-lightest:active .file-cta, +.file.is-grey-lightest.is-active .file-cta { + background-color: #e0e0e0; + border-color: transparent; + color: #363636; +} +.file.is-small { + font-size: 0.75rem; +} +.file.is-medium { + font-size: 1.25rem; +} +.file.is-medium .file-icon .fa { + font-size: 21px; +} +.file.is-large { + font-size: 1.5rem; +} +.file.is-large .file-icon .fa { + font-size: 28px; +} +.file.has-name .file-cta { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.file.has-name .file-name { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.file.has-name.is-empty .file-cta { + border-radius: 4px; +} +.file.has-name.is-empty .file-name { + display: none; +} +.file.is-boxed .file-label { + flex-direction: column; +} +.file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; +} +.file.is-boxed .file-name { + border-width: 0 1px 1px; +} +.file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; +} +.file.is-boxed .file-icon .fa { + font-size: 21px; +} +.file.is-boxed.is-small .file-icon .fa { + font-size: 14px; +} +.file.is-boxed.is-medium .file-icon .fa { + font-size: 28px; +} +.file.is-boxed.is-large .file-icon .fa { + font-size: 35px; +} +.file.is-boxed.has-name .file-cta { + border-radius: 4px 4px 0 0; +} +.file.is-boxed.has-name .file-name { + border-radius: 0 0 4px 4px; + border-width: 0 1px 1px; +} +.file.is-centered { + justify-content: center; +} +.file.is-fullwidth .file-label { + width: 100%; +} +.file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; +} +.file.is-right { + justify-content: flex-end; +} +.file.is-right .file-cta { + border-radius: 0 4px 4px 0; +} +.file.is-right .file-name { + border-radius: 4px 0 0 4px; + border-width: 1px 0 1px 1px; + order: -1; +} +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; +} +.file-label:hover .file-cta { + background-color: #eee; + color: #363636; +} +.file-label:hover .file-name { + border-color: #d5d5d5; +} +.file-label:active .file-cta { + background-color: #e8e8e8; + color: #363636; +} +.file-label:active .file-name { + border-color: #cfcfcf; +} +.file-input { + height: 100%; + left: 0; + opacity: 0; + outline: none; + position: absolute; + top: 0; + width: 100%; +} +.file-cta, +.file-name { + border-color: #dbdbdb; + border-radius: 4px; + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; +} +.file-cta { + background-color: #f5f5f5; + color: #4a4a4a; +} +.file-name { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px 1px 1px 0; + display: block; + max-width: 16em; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; +} +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-right: 0.5em; + width: 1em; +} +.file-icon .fa { + font-size: 14px; +} +.label { + color: #363636; + display: block; + font-size: 1rem; + font-weight: 700; +} +.label:not(:last-child) { + margin-bottom: 0.5em; +} +.label.is-small { + font-size: 0.75rem; +} +.label.is-medium { + font-size: 1.25rem; +} +.label.is-large { + font-size: 1.5rem; +} +.help { + display: block; + font-size: 0.75rem; + margin-top: 0.25rem; +} +.help.is-white { + color: #fff; +} +.help.is-black { + color: #0a0a0a; +} +.help.is-light { + color: #f5f5f5; +} +.help.is-dark { + color: #363636; +} +.help.is-primary { + color: #3273dc; +} +.help.is-link { + color: #3273dc; +} +.help.is-info { + color: #3298dc; +} +.help.is-success { + color: #48c774; +} +.help.is-warning { + color: #ffdd57; +} +.help.is-danger { + color: #f14668; +} +.help.is-grey-lightest { + color: #ededed; +} +.field:not(:last-child) { + margin-bottom: 0.75rem; +} +.field.has-addons { + display: flex; + justify-content: flex-start; +} +.field.has-addons .control:not(:last-child) { + margin-right: -1px; +} +.field.has-addons .control:not(:first-child):not(:last-child) .button, +.field.has-addons .control:not(:first-child):not(:last-child) .input, +.field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; +} +.field.has-addons .control:first-child:not(:only-child) .button, +.field.has-addons .control:first-child:not(:only-child) .input, +.field.has-addons .control:first-child:not(:only-child) .select select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.field.has-addons .control:last-child:not(:only-child) .button, +.field.has-addons .control:last-child:not(:only-child) .input, +.field.has-addons .control:last-child:not(:only-child) .select select { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.field.has-addons .control .button:not([disabled]):hover, +.field.has-addons .control .input:not([disabled]):hover, +.field.has-addons .control .select select:not([disabled]):hover, +.field.has-addons .control .button:not([disabled]).is-hovered, +.field.has-addons .control .input:not([disabled]).is-hovered, +.field.has-addons .control .select select:not([disabled]).is-hovered { + z-index: 2; +} +.field.has-addons .control .button:not([disabled]):focus, +.field.has-addons .control .input:not([disabled]):focus, +.field.has-addons .control .select select:not([disabled]):focus, +.field.has-addons .control .button:not([disabled]).is-focused, +.field.has-addons .control .input:not([disabled]).is-focused, +.field.has-addons .control .select select:not([disabled]).is-focused, +.field.has-addons .control .button:not([disabled]):active, +.field.has-addons .control .input:not([disabled]):active, +.field.has-addons .control .select select:not([disabled]):active, +.field.has-addons .control .button:not([disabled]).is-active, +.field.has-addons .control .input:not([disabled]).is-active, +.field.has-addons .control .select select:not([disabled]).is-active { + z-index: 3; +} +.field.has-addons .control .button:not([disabled]):focus:hover, +.field.has-addons .control .input:not([disabled]):focus:hover, +.field.has-addons .control .select select:not([disabled]):focus:hover, +.field.has-addons .control .button:not([disabled]).is-focused:hover, +.field.has-addons .control .input:not([disabled]).is-focused:hover, +.field.has-addons .control .select select:not([disabled]).is-focused:hover, +.field.has-addons .control .button:not([disabled]):active:hover, +.field.has-addons .control .input:not([disabled]):active:hover, +.field.has-addons .control .select select:not([disabled]):active:hover, +.field.has-addons .control .button:not([disabled]).is-active:hover, +.field.has-addons .control .input:not([disabled]).is-active:hover, +.field.has-addons .control .select select:not([disabled]).is-active:hover { + z-index: 4; +} +.field.has-addons .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.field.has-addons.has-addons-centered { + justify-content: center; +} +.field.has-addons.has-addons-right { + justify-content: flex-end; +} +.field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; +} +.field.is-grouped { + display: flex; + justify-content: flex-start; +} +.field.is-grouped > .control { + flex-shrink: 0; +} +.field.is-grouped > .control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} +.field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.field.is-grouped.is-grouped-centered { + justify-content: center; +} +.field.is-grouped.is-grouped-right { + justify-content: flex-end; +} +.field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; +} +.field.is-grouped.is-grouped-multiline > .control:last-child, +.field.is-grouped.is-grouped-multiline > .control:not(:last-child) { + margin-bottom: 0.75rem; +} +.field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; +} +.field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; +} +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; + } +} +.field-label .label { + font-size: inherit; +} +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; + } +} +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; + } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; + } + .field-label.is-normal { + padding-top: 0.375em; + } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; + } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; + } +} +.field-body .field .field { + margin-bottom: 0; +} +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; + } + .field-body .field { + margin-bottom: 0; + } + .field-body > .field { + flex-shrink: 1; + } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; + } + .field-body > .field:not(:last-child) { + margin-right: 0.75rem; + } +} +.control { + box-sizing: border-box; + clear: both; + font-size: 1rem; + position: relative; + text-align: left; +} +.control.has-icons-left .input:focus ~ .icon, +.control.has-icons-right .input:focus ~ .icon, +.control.has-icons-left .select:focus ~ .icon, +.control.has-icons-right .select:focus ~ .icon { + color: #4a4a4a; +} +.control.has-icons-left .input.is-small ~ .icon, +.control.has-icons-right .input.is-small ~ .icon, +.control.has-icons-left .select.is-small ~ .icon, +.control.has-icons-right .select.is-small ~ .icon { + font-size: 0.75rem; +} +.control.has-icons-left .input.is-medium ~ .icon, +.control.has-icons-right .input.is-medium ~ .icon, +.control.has-icons-left .select.is-medium ~ .icon, +.control.has-icons-right .select.is-medium ~ .icon { + font-size: 1.25rem; +} +.control.has-icons-left .input.is-large ~ .icon, +.control.has-icons-right .input.is-large ~ .icon, +.control.has-icons-left .select.is-large ~ .icon, +.control.has-icons-right .select.is-large ~ .icon { + font-size: 1.5rem; +} +.control.has-icons-left .icon, +.control.has-icons-right .icon { + color: #dbdbdb; + height: 2.25em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.25em; + z-index: 4; +} +.control.has-icons-left .input, +.control.has-icons-left .select select { + padding-left: 2.25em; +} +.control.has-icons-left .icon.is-left { + left: 0; +} +.control.has-icons-right .input, +.control.has-icons-right .select select { + padding-right: 2.25em; +} +.control.has-icons-right .icon.is-right { + right: 0; +} +.control.is-loading::after { + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; +} +.control.is-loading.is-small:after { + font-size: 0.75rem; +} +.control.is-loading.is-medium:after { + font-size: 1.25rem; +} +.control.is-loading.is-large:after { + font-size: 1.5rem; +} +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; +} +.columns.is-mobile > .column.is-narrow { + flex: none; +} +.columns.is-mobile > .column.is-full { + flex: none; + width: 100%; +} +.columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; +} +.columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; +} +.columns.is-mobile > .column.is-half { + flex: none; + width: 50%; +} +.columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; +} +.columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; +} +.columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; +} +.columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; +} +.columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; +} +.columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; +} +.columns.is-mobile > .column.is-offset-three-quarters { + margin-left: 75%; +} +.columns.is-mobile > .column.is-offset-two-thirds { + margin-left: 66.6666%; +} +.columns.is-mobile > .column.is-offset-half { + margin-left: 50%; +} +.columns.is-mobile > .column.is-offset-one-third { + margin-left: 33.3333%; +} +.columns.is-mobile > .column.is-offset-one-quarter { + margin-left: 25%; +} +.columns.is-mobile > .column.is-offset-one-fifth { + margin-left: 20%; +} +.columns.is-mobile > .column.is-offset-two-fifths { + margin-left: 40%; +} +.columns.is-mobile > .column.is-offset-three-fifths { + margin-left: 60%; +} +.columns.is-mobile > .column.is-offset-four-fifths { + margin-left: 80%; +} +.columns.is-mobile > .column.is-0 { + flex: none; + width: 0%; +} +.columns.is-mobile > .column.is-offset-0 { + margin-left: 0%; +} +.columns.is-mobile > .column.is-1 { + flex: none; + width: 8.33333%; +} +.columns.is-mobile > .column.is-offset-1 { + margin-left: 8.33333%; +} +.columns.is-mobile > .column.is-2 { + flex: none; + width: 16.66667%; +} +.columns.is-mobile > .column.is-offset-2 { + margin-left: 16.66667%; +} +.columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; +} +.columns.is-mobile > .column.is-offset-3 { + margin-left: 25%; +} +.columns.is-mobile > .column.is-4 { + flex: none; + width: 33.33333%; +} +.columns.is-mobile > .column.is-offset-4 { + margin-left: 33.33333%; +} +.columns.is-mobile > .column.is-5 { + flex: none; + width: 41.66667%; +} +.columns.is-mobile > .column.is-offset-5 { + margin-left: 41.66667%; +} +.columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; +} +.columns.is-mobile > .column.is-offset-6 { + margin-left: 50%; +} +.columns.is-mobile > .column.is-7 { + flex: none; + width: 58.33333%; +} +.columns.is-mobile > .column.is-offset-7 { + margin-left: 58.33333%; +} +.columns.is-mobile > .column.is-8 { + flex: none; + width: 66.66667%; +} +.columns.is-mobile > .column.is-offset-8 { + margin-left: 66.66667%; +} +.columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; +} +.columns.is-mobile > .column.is-offset-9 { + margin-left: 75%; +} +.columns.is-mobile > .column.is-10 { + flex: none; + width: 83.33333%; +} +.columns.is-mobile > .column.is-offset-10 { + margin-left: 83.33333%; +} +.columns.is-mobile > .column.is-11 { + flex: none; + width: 91.66667%; +} +.columns.is-mobile > .column.is-offset-11 { + margin-left: 91.66667%; +} +.columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; +} +.columns.is-mobile > .column.is-offset-12 { + margin-left: 100%; +} +@media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; + } + .column.is-full-mobile { + flex: none; + width: 100%; + } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; + } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; + } + .column.is-half-mobile { + flex: none; + width: 50%; + } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; + } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; + } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; + } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; + } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; + } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; + } + .column.is-offset-half-mobile { + margin-left: 50%; + } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; + } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; + } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; + } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; + } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; + } + .column.is-0-mobile { + flex: none; + width: 0%; + } + .column.is-offset-0-mobile { + margin-left: 0%; + } + .column.is-1-mobile { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-mobile { + margin-left: 8.33333%; + } + .column.is-2-mobile { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-mobile { + margin-left: 16.66667%; + } + .column.is-3-mobile { + flex: none; + width: 25%; + } + .column.is-offset-3-mobile { + margin-left: 25%; + } + .column.is-4-mobile { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-mobile { + margin-left: 33.33333%; + } + .column.is-5-mobile { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-mobile { + margin-left: 41.66667%; + } + .column.is-6-mobile { + flex: none; + width: 50%; + } + .column.is-offset-6-mobile { + margin-left: 50%; + } + .column.is-7-mobile { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-mobile { + margin-left: 58.33333%; + } + .column.is-8-mobile { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-mobile { + margin-left: 66.66667%; + } + .column.is-9-mobile { + flex: none; + width: 75%; + } + .column.is-offset-9-mobile { + margin-left: 75%; + } + .column.is-10-mobile { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-mobile { + margin-left: 83.33333%; + } + .column.is-11-mobile { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-mobile { + margin-left: 91.66667%; + } + .column.is-12-mobile { + flex: none; + width: 100%; + } + .column.is-offset-12-mobile { + margin-left: 100%; + } +} +@media screen and (min-width: 769px), print { + .column.is-narrow, + .column.is-narrow-tablet { + flex: none; + } + .column.is-full, + .column.is-full-tablet { + flex: none; + width: 100%; + } + .column.is-three-quarters, + .column.is-three-quarters-tablet { + flex: none; + width: 75%; + } + .column.is-two-thirds, + .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; + } + .column.is-half, + .column.is-half-tablet { + flex: none; + width: 50%; + } + .column.is-one-third, + .column.is-one-third-tablet { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter, + .column.is-one-quarter-tablet { + flex: none; + width: 25%; + } + .column.is-one-fifth, + .column.is-one-fifth-tablet { + flex: none; + width: 20%; + } + .column.is-two-fifths, + .column.is-two-fifths-tablet { + flex: none; + width: 40%; + } + .column.is-three-fifths, + .column.is-three-fifths-tablet { + flex: none; + width: 60%; + } + .column.is-four-fifths, + .column.is-four-fifths-tablet { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters, + .column.is-offset-three-quarters-tablet { + margin-left: 75%; + } + .column.is-offset-two-thirds, + .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; + } + .column.is-offset-half, + .column.is-offset-half-tablet { + margin-left: 50%; + } + .column.is-offset-one-third, + .column.is-offset-one-third-tablet { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter, + .column.is-offset-one-quarter-tablet { + margin-left: 25%; + } + .column.is-offset-one-fifth, + .column.is-offset-one-fifth-tablet { + margin-left: 20%; + } + .column.is-offset-two-fifths, + .column.is-offset-two-fifths-tablet { + margin-left: 40%; + } + .column.is-offset-three-fifths, + .column.is-offset-three-fifths-tablet { + margin-left: 60%; + } + .column.is-offset-four-fifths, + .column.is-offset-four-fifths-tablet { + margin-left: 80%; + } + .column.is-0, + .column.is-0-tablet { + flex: none; + width: 0%; + } + .column.is-offset-0, + .column.is-offset-0-tablet { + margin-left: 0%; + } + .column.is-1, + .column.is-1-tablet { + flex: none; + width: 8.33333%; + } + .column.is-offset-1, + .column.is-offset-1-tablet { + margin-left: 8.33333%; + } + .column.is-2, + .column.is-2-tablet { + flex: none; + width: 16.66667%; + } + .column.is-offset-2, + .column.is-offset-2-tablet { + margin-left: 16.66667%; + } + .column.is-3, + .column.is-3-tablet { + flex: none; + width: 25%; + } + .column.is-offset-3, + .column.is-offset-3-tablet { + margin-left: 25%; + } + .column.is-4, + .column.is-4-tablet { + flex: none; + width: 33.33333%; + } + .column.is-offset-4, + .column.is-offset-4-tablet { + margin-left: 33.33333%; + } + .column.is-5, + .column.is-5-tablet { + flex: none; + width: 41.66667%; + } + .column.is-offset-5, + .column.is-offset-5-tablet { + margin-left: 41.66667%; + } + .column.is-6, + .column.is-6-tablet { + flex: none; + width: 50%; + } + .column.is-offset-6, + .column.is-offset-6-tablet { + margin-left: 50%; + } + .column.is-7, + .column.is-7-tablet { + flex: none; + width: 58.33333%; + } + .column.is-offset-7, + .column.is-offset-7-tablet { + margin-left: 58.33333%; + } + .column.is-8, + .column.is-8-tablet { + flex: none; + width: 66.66667%; + } + .column.is-offset-8, + .column.is-offset-8-tablet { + margin-left: 66.66667%; + } + .column.is-9, + .column.is-9-tablet { + flex: none; + width: 75%; + } + .column.is-offset-9, + .column.is-offset-9-tablet { + margin-left: 75%; + } + .column.is-10, + .column.is-10-tablet { + flex: none; + width: 83.33333%; + } + .column.is-offset-10, + .column.is-offset-10-tablet { + margin-left: 83.33333%; + } + .column.is-11, + .column.is-11-tablet { + flex: none; + width: 91.66667%; + } + .column.is-offset-11, + .column.is-offset-11-tablet { + margin-left: 91.66667%; + } + .column.is-12, + .column.is-12-tablet { + flex: none; + width: 100%; + } + .column.is-offset-12, + .column.is-offset-12-tablet { + margin-left: 100%; + } +} +@media screen and (max-width: 1087px) { + .column.is-narrow-touch { + flex: none; + } + .column.is-full-touch { + flex: none; + width: 100%; + } + .column.is-three-quarters-touch { + flex: none; + width: 75%; + } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; + } + .column.is-half-touch { + flex: none; + width: 50%; + } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-touch { + flex: none; + width: 25%; + } + .column.is-one-fifth-touch { + flex: none; + width: 20%; + } + .column.is-two-fifths-touch { + flex: none; + width: 40%; + } + .column.is-three-fifths-touch { + flex: none; + width: 60%; + } + .column.is-four-fifths-touch { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-touch { + margin-left: 75%; + } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; + } + .column.is-offset-half-touch { + margin-left: 50%; + } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-touch { + margin-left: 25%; + } + .column.is-offset-one-fifth-touch { + margin-left: 20%; + } + .column.is-offset-two-fifths-touch { + margin-left: 40%; + } + .column.is-offset-three-fifths-touch { + margin-left: 60%; + } + .column.is-offset-four-fifths-touch { + margin-left: 80%; + } + .column.is-0-touch { + flex: none; + width: 0%; + } + .column.is-offset-0-touch { + margin-left: 0%; + } + .column.is-1-touch { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-touch { + margin-left: 8.33333%; + } + .column.is-2-touch { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-touch { + margin-left: 16.66667%; + } + .column.is-3-touch { + flex: none; + width: 25%; + } + .column.is-offset-3-touch { + margin-left: 25%; + } + .column.is-4-touch { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-touch { + margin-left: 33.33333%; + } + .column.is-5-touch { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-touch { + margin-left: 41.66667%; + } + .column.is-6-touch { + flex: none; + width: 50%; + } + .column.is-offset-6-touch { + margin-left: 50%; + } + .column.is-7-touch { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-touch { + margin-left: 58.33333%; + } + .column.is-8-touch { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-touch { + margin-left: 66.66667%; + } + .column.is-9-touch { + flex: none; + width: 75%; + } + .column.is-offset-9-touch { + margin-left: 75%; + } + .column.is-10-touch { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-touch { + margin-left: 83.33333%; + } + .column.is-11-touch { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-touch { + margin-left: 91.66667%; + } + .column.is-12-touch { + flex: none; + width: 100%; + } + .column.is-offset-12-touch { + margin-left: 100%; + } +} +@media screen and (min-width: 1088px) { + .column.is-narrow-desktop { + flex: none; + } + .column.is-full-desktop { + flex: none; + width: 100%; + } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; + } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; + } + .column.is-half-desktop { + flex: none; + width: 50%; + } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; + } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; + } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; + } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; + } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; + } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; + } + .column.is-offset-half-desktop { + margin-left: 50%; + } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; + } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; + } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; + } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; + } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; + } + .column.is-0-desktop { + flex: none; + width: 0%; + } + .column.is-offset-0-desktop { + margin-left: 0%; + } + .column.is-1-desktop { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-desktop { + margin-left: 8.33333%; + } + .column.is-2-desktop { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-desktop { + margin-left: 16.66667%; + } + .column.is-3-desktop { + flex: none; + width: 25%; + } + .column.is-offset-3-desktop { + margin-left: 25%; + } + .column.is-4-desktop { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-desktop { + margin-left: 33.33333%; + } + .column.is-5-desktop { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-desktop { + margin-left: 41.66667%; + } + .column.is-6-desktop { + flex: none; + width: 50%; + } + .column.is-offset-6-desktop { + margin-left: 50%; + } + .column.is-7-desktop { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-desktop { + margin-left: 58.33333%; + } + .column.is-8-desktop { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-desktop { + margin-left: 66.66667%; + } + .column.is-9-desktop { + flex: none; + width: 75%; + } + .column.is-offset-9-desktop { + margin-left: 75%; + } + .column.is-10-desktop { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-desktop { + margin-left: 83.33333%; + } + .column.is-11-desktop { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-desktop { + margin-left: 91.66667%; + } + .column.is-12-desktop { + flex: none; + width: 100%; + } + .column.is-offset-12-desktop { + margin-left: 100%; + } +} +@media screen and (min-width: 1280px) { + .column.is-narrow-widescreen { + flex: none; + } + .column.is-full-widescreen { + flex: none; + width: 100%; + } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; + } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; + } + .column.is-half-widescreen { + flex: none; + width: 50%; + } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; + } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; + } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; + } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; + } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; + } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; + } + .column.is-offset-half-widescreen { + margin-left: 50%; + } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; + } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; + } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; + } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; + } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; + } + .column.is-0-widescreen { + flex: none; + width: 0%; + } + .column.is-offset-0-widescreen { + margin-left: 0%; + } + .column.is-1-widescreen { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-widescreen { + margin-left: 8.33333%; + } + .column.is-2-widescreen { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-widescreen { + margin-left: 16.66667%; + } + .column.is-3-widescreen { + flex: none; + width: 25%; + } + .column.is-offset-3-widescreen { + margin-left: 25%; + } + .column.is-4-widescreen { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-widescreen { + margin-left: 33.33333%; + } + .column.is-5-widescreen { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-widescreen { + margin-left: 41.66667%; + } + .column.is-6-widescreen { + flex: none; + width: 50%; + } + .column.is-offset-6-widescreen { + margin-left: 50%; + } + .column.is-7-widescreen { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-widescreen { + margin-left: 58.33333%; + } + .column.is-8-widescreen { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-widescreen { + margin-left: 66.66667%; + } + .column.is-9-widescreen { + flex: none; + width: 75%; + } + .column.is-offset-9-widescreen { + margin-left: 75%; + } + .column.is-10-widescreen { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-widescreen { + margin-left: 83.33333%; + } + .column.is-11-widescreen { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-widescreen { + margin-left: 91.66667%; + } + .column.is-12-widescreen { + flex: none; + width: 100%; + } + .column.is-offset-12-widescreen { + margin-left: 100%; + } +} +@media screen and (min-width: 1472px) { + .column.is-narrow-fullhd { + flex: none; + } + .column.is-full-fullhd { + flex: none; + width: 100%; + } + .column.is-three-quarters-fullhd { + flex: none; + width: 75%; + } + .column.is-two-thirds-fullhd { + flex: none; + width: 66.6666%; + } + .column.is-half-fullhd { + flex: none; + width: 50%; + } + .column.is-one-third-fullhd { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-fullhd { + flex: none; + width: 25%; + } + .column.is-one-fifth-fullhd { + flex: none; + width: 20%; + } + .column.is-two-fifths-fullhd { + flex: none; + width: 40%; + } + .column.is-three-fifths-fullhd { + flex: none; + width: 60%; + } + .column.is-four-fifths-fullhd { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-fullhd { + margin-left: 75%; + } + .column.is-offset-two-thirds-fullhd { + margin-left: 66.6666%; + } + .column.is-offset-half-fullhd { + margin-left: 50%; + } + .column.is-offset-one-third-fullhd { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-fullhd { + margin-left: 25%; + } + .column.is-offset-one-fifth-fullhd { + margin-left: 20%; + } + .column.is-offset-two-fifths-fullhd { + margin-left: 40%; + } + .column.is-offset-three-fifths-fullhd { + margin-left: 60%; + } + .column.is-offset-four-fifths-fullhd { + margin-left: 80%; + } + .column.is-0-fullhd { + flex: none; + width: 0%; + } + .column.is-offset-0-fullhd { + margin-left: 0%; + } + .column.is-1-fullhd { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-fullhd { + margin-left: 8.33333%; + } + .column.is-2-fullhd { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-fullhd { + margin-left: 16.66667%; + } + .column.is-3-fullhd { + flex: none; + width: 25%; + } + .column.is-offset-3-fullhd { + margin-left: 25%; + } + .column.is-4-fullhd { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-fullhd { + margin-left: 33.33333%; + } + .column.is-5-fullhd { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-fullhd { + margin-left: 41.66667%; + } + .column.is-6-fullhd { + flex: none; + width: 50%; + } + .column.is-offset-6-fullhd { + margin-left: 50%; + } + .column.is-7-fullhd { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-fullhd { + margin-left: 58.33333%; + } + .column.is-8-fullhd { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-fullhd { + margin-left: 66.66667%; + } + .column.is-9-fullhd { + flex: none; + width: 75%; + } + .column.is-offset-9-fullhd { + margin-left: 75%; + } + .column.is-10-fullhd { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-fullhd { + margin-left: 83.33333%; + } + .column.is-11-fullhd { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-fullhd { + margin-left: 91.66667%; + } + .column.is-12-fullhd { + flex: none; + width: 100%; + } + .column.is-offset-12-fullhd { + margin-left: 100%; + } +} +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} +.columns:last-child { + margin-bottom: -0.75rem; +} +.columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); +} +.columns.is-centered { + justify-content: center; +} +.columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; +} +.columns.is-gapless > .column { + margin: 0; + padding: 0 !important; +} +.columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; +} +.columns.is-gapless:last-child { + margin-bottom: 0; +} +.columns.is-mobile { + display: flex; +} +.columns.is-multiline { + flex-wrap: wrap; +} +.columns.is-vcentered { + align-items: center; +} +@media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; + } +} +@media screen and (min-width: 1088px) { + .columns.is-desktop { + display: flex; + } +} +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); +} +.columns.is-variable .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); +} +.columns.is-variable.is-0 { + --columnGap: 0rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-0-mobile { + --columnGap: 0rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-0-tablet { + --columnGap: 0rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-0-tablet-only { + --columnGap: 0rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-0-touch { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-0-desktop { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-0-desktop-only { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-0-widescreen { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-0-widescreen-only { + --columnGap: 0rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-0-fullhd { + --columnGap: 0rem; + } +} +.columns.is-variable.is-1 { + --columnGap: 0.25rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-1-mobile { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-1-tablet { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-1-tablet-only { + --columnGap: 0.25rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-1-touch { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-1-desktop { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-1-desktop-only { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-1-widescreen { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-1-widescreen-only { + --columnGap: 0.25rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-1-fullhd { + --columnGap: 0.25rem; + } +} +.columns.is-variable.is-2 { + --columnGap: 0.5rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-2-mobile { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-2-tablet { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-2-tablet-only { + --columnGap: 0.5rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-2-touch { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-2-desktop { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-2-desktop-only { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-2-widescreen { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-2-widescreen-only { + --columnGap: 0.5rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-2-fullhd { + --columnGap: 0.5rem; + } +} +.columns.is-variable.is-3 { + --columnGap: 0.75rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-3-mobile { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-3-tablet { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-3-tablet-only { + --columnGap: 0.75rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-3-touch { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-3-desktop { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-3-desktop-only { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-3-widescreen { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-3-widescreen-only { + --columnGap: 0.75rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-3-fullhd { + --columnGap: 0.75rem; + } +} +.columns.is-variable.is-4 { + --columnGap: 1rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-4-mobile { + --columnGap: 1rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-4-tablet { + --columnGap: 1rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-4-tablet-only { + --columnGap: 1rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-4-touch { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-4-desktop { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-4-desktop-only { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-4-widescreen { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-4-widescreen-only { + --columnGap: 1rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-4-fullhd { + --columnGap: 1rem; + } +} +.columns.is-variable.is-5 { + --columnGap: 1.25rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-5-mobile { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-5-tablet { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-5-tablet-only { + --columnGap: 1.25rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-5-touch { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-5-desktop { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-5-desktop-only { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-5-widescreen { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-5-widescreen-only { + --columnGap: 1.25rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-5-fullhd { + --columnGap: 1.25rem; + } +} +.columns.is-variable.is-6 { + --columnGap: 1.5rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-6-mobile { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-6-tablet { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-6-tablet-only { + --columnGap: 1.5rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-6-touch { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-6-desktop { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-6-desktop-only { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-6-widescreen { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-6-widescreen-only { + --columnGap: 1.5rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-6-fullhd { + --columnGap: 1.5rem; + } +} +.columns.is-variable.is-7 { + --columnGap: 1.75rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-7-mobile { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-7-tablet { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-7-tablet-only { + --columnGap: 1.75rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-7-touch { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-7-desktop { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-7-desktop-only { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-7-widescreen { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-7-widescreen-only { + --columnGap: 1.75rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-7-fullhd { + --columnGap: 1.75rem; + } +} +.columns.is-variable.is-8 { + --columnGap: 2rem; +} +@media screen and (max-width: 768px) { + .columns.is-variable.is-8-mobile { + --columnGap: 2rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-variable.is-8-tablet { + --columnGap: 2rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-8-tablet-only { + --columnGap: 2rem; + } +} +@media screen and (max-width: 1087px) { + .columns.is-variable.is-8-touch { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1088px) { + .columns.is-variable.is-8-desktop { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-8-desktop-only { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1280px) { + .columns.is-variable.is-8-widescreen { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-8-widescreen-only { + --columnGap: 2rem; + } +} +@media screen and (min-width: 1472px) { + .columns.is-variable.is-8-fullhd { + --columnGap: 2rem; + } +} +.tile { + align-items: stretch; + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; +} +.tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} +.tile.is-ancestor:last-child { + margin-bottom: -0.75rem; +} +.tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; +} +.tile.is-child { + margin: 0 !important; +} +.tile.is-parent { + padding: 0.75rem; +} +.tile.is-vertical { + flex-direction: column; +} +.tile.is-vertical > .tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; +} +@media screen and (min-width: 769px), print { + .tile:not(.is-child) { + display: flex; + } + .tile.is-1 { + flex: none; + width: 8.33333%; + } + .tile.is-2 { + flex: none; + width: 16.66667%; + } + .tile.is-3 { + flex: none; + width: 25%; + } + .tile.is-4 { + flex: none; + width: 33.33333%; + } + .tile.is-5 { + flex: none; + width: 41.66667%; + } + .tile.is-6 { + flex: none; + width: 50%; + } + .tile.is-7 { + flex: none; + width: 58.33333%; + } + .tile.is-8 { + flex: none; + width: 66.66667%; + } + .tile.is-9 { + flex: none; + width: 75%; + } + .tile.is-10 { + flex: none; + width: 83.33333%; + } + .tile.is-11 { + flex: none; + width: 91.66667%; + } + .tile.is-12 { + flex: none; + width: 100%; + } +} +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.hero .navbar { + background: none; +} +.hero .tabs ul { + border-bottom: none; +} +.hero.is-white { + background-color: #fff; + color: #0a0a0a; +} +.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-white strong { + color: inherit; +} +.hero.is-white .title { + color: #0a0a0a; +} +.hero.is-white .subtitle { + color: rgba(10,10,10,0.9); +} +.hero.is-white .subtitle a:not(.button), +.hero.is-white .subtitle strong { + color: #0a0a0a; +} +@media screen and (max-width: 1087px) { + .hero.is-white .navbar-menu { + background-color: #fff; + } +} +.hero.is-white .navbar-item, +.hero.is-white .navbar-link { + color: rgba(10,10,10,0.7); +} +.hero.is-white a.navbar-item:hover, +.hero.is-white .navbar-link:hover, +.hero.is-white a.navbar-item.is-active, +.hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} +.hero.is-white .tabs a { + color: #0a0a0a; + opacity: 0.9; +} +.hero.is-white .tabs a:hover { + opacity: 1; +} +.hero.is-white .tabs li.is-active a { + opacity: 1; +} +.hero.is-white .tabs.is-boxed a, +.hero.is-white .tabs.is-toggle a { + color: #0a0a0a; +} +.hero.is-white .tabs.is-boxed a:hover, +.hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-white .tabs.is-boxed li.is-active a, +.hero.is-white .tabs.is-toggle li.is-active a, +.hero.is-white .tabs.is-boxed li.is-active a:hover, +.hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: #fff; +} +.hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e8e3e3 0%, #fff 71%, #fff 100%); +} +@media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e8e3e3 0%, #fff 71%, #fff 100%); + } +} +.hero.is-black { + background-color: #0a0a0a; + color: #fff; +} +.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-black strong { + color: inherit; +} +.hero.is-black .title { + color: #fff; +} +.hero.is-black .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-black .subtitle a:not(.button), +.hero.is-black .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-black .navbar-menu { + background-color: #0a0a0a; + } +} +.hero.is-black .navbar-item, +.hero.is-black .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-black a.navbar-item:hover, +.hero.is-black .navbar-link:hover, +.hero.is-black a.navbar-item.is-active, +.hero.is-black .navbar-link.is-active { + background-color: #000; + color: #fff; +} +.hero.is-black .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-black .tabs a:hover { + opacity: 1; +} +.hero.is-black .tabs li.is-active a { + opacity: 1; +} +.hero.is-black .tabs.is-boxed a, +.hero.is-black .tabs.is-toggle a { + color: #fff; +} +.hero.is-black .tabs.is-boxed a:hover, +.hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-black .tabs.is-boxed li.is-active a, +.hero.is-black .tabs.is-toggle li.is-active a, +.hero.is-black .tabs.is-boxed li.is-active a:hover, +.hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #0a0a0a; +} +.hero.is-black.is-bold { + background-image: linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%); +} +@media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%); + } +} +.hero.is-light { + background-color: #f5f5f5; + color: rgba(0,0,0,0.7); +} +.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-light strong { + color: inherit; +} +.hero.is-light .title { + color: rgba(0,0,0,0.7); +} +.hero.is-light .subtitle { + color: rgba(0,0,0,0.9); +} +.hero.is-light .subtitle a:not(.button), +.hero.is-light .subtitle strong { + color: rgba(0,0,0,0.7); +} +@media screen and (max-width: 1087px) { + .hero.is-light .navbar-menu { + background-color: #f5f5f5; + } +} +.hero.is-light .navbar-item, +.hero.is-light .navbar-link { + color: rgba(0,0,0,0.7); +} +.hero.is-light a.navbar-item:hover, +.hero.is-light .navbar-link:hover, +.hero.is-light a.navbar-item.is-active, +.hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0,0,0,0.7); +} +.hero.is-light .tabs a { + color: rgba(0,0,0,0.7); + opacity: 0.9; +} +.hero.is-light .tabs a:hover { + opacity: 1; +} +.hero.is-light .tabs li.is-active a { + opacity: 1; +} +.hero.is-light .tabs.is-boxed a, +.hero.is-light .tabs.is-toggle a { + color: rgba(0,0,0,0.7); +} +.hero.is-light .tabs.is-boxed a:hover, +.hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-light .tabs.is-boxed li.is-active a, +.hero.is-light .tabs.is-toggle li.is-active a, +.hero.is-light .tabs.is-boxed li.is-active a:hover, +.hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0,0,0,0.7); + border-color: rgba(0,0,0,0.7); + color: #f5f5f5; +} +.hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d8 0%, #f5f5f5 71%, #fff 100%); +} +@media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d8 0%, #f5f5f5 71%, #fff 100%); + } +} +.hero.is-dark { + background-color: #363636; + color: #fff; +} +.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-dark strong { + color: inherit; +} +.hero.is-dark .title { + color: #fff; +} +.hero.is-dark .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-dark .subtitle a:not(.button), +.hero.is-dark .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-dark .navbar-menu { + background-color: #363636; + } +} +.hero.is-dark .navbar-item, +.hero.is-dark .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-dark a.navbar-item:hover, +.hero.is-dark .navbar-link:hover, +.hero.is-dark a.navbar-item.is-active, +.hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: #fff; +} +.hero.is-dark .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-dark .tabs a:hover { + opacity: 1; +} +.hero.is-dark .tabs li.is-active a { + opacity: 1; +} +.hero.is-dark .tabs.is-boxed a, +.hero.is-dark .tabs.is-toggle a { + color: #fff; +} +.hero.is-dark .tabs.is-boxed a:hover, +.hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-dark .tabs.is-boxed li.is-active a, +.hero.is-dark .tabs.is-toggle li.is-active a, +.hero.is-dark .tabs.is-boxed li.is-active a:hover, +.hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #363636; +} +.hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f1a1a 0%, #363636 71%, #463f3f 100%); +} +@media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f1a1a 0%, #363636 71%, #463f3f 100%); + } +} +.hero.is-primary { + background-color: #3273dc; + color: #fff; +} +.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-primary strong { + color: inherit; +} +.hero.is-primary .title { + color: #fff; +} +.hero.is-primary .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-primary .subtitle a:not(.button), +.hero.is-primary .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-primary .navbar-menu { + background-color: #3273dc; + } +} +.hero.is-primary .navbar-item, +.hero.is-primary .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-primary a.navbar-item:hover, +.hero.is-primary .navbar-link:hover, +.hero.is-primary a.navbar-item.is-active, +.hero.is-primary .navbar-link.is-active { + background-color: #2366d1; + color: #fff; +} +.hero.is-primary .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-primary .tabs a:hover { + opacity: 1; +} +.hero.is-primary .tabs li.is-active a { + opacity: 1; +} +.hero.is-primary .tabs.is-boxed a, +.hero.is-primary .tabs.is-toggle a { + color: #fff; +} +.hero.is-primary .tabs.is-boxed a:hover, +.hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-primary .tabs.is-boxed li.is-active a, +.hero.is-primary .tabs.is-toggle li.is-active a, +.hero.is-primary .tabs.is-boxed li.is-active a:hover, +.hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3273dc; +} +.hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #1576c6 0%, #3273dc 71%, #4266e5 100%); +} +@media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1576c6 0%, #3273dc 71%, #4266e5 100%); + } +} +.hero.is-link { + background-color: #3273dc; + color: #fff; +} +.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-link strong { + color: inherit; +} +.hero.is-link .title { + color: #fff; +} +.hero.is-link .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-link .subtitle a:not(.button), +.hero.is-link .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-link .navbar-menu { + background-color: #3273dc; + } +} +.hero.is-link .navbar-item, +.hero.is-link .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-link a.navbar-item:hover, +.hero.is-link .navbar-link:hover, +.hero.is-link a.navbar-item.is-active, +.hero.is-link .navbar-link.is-active { + background-color: #2366d1; + color: #fff; +} +.hero.is-link .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-link .tabs a:hover { + opacity: 1; +} +.hero.is-link .tabs li.is-active a { + opacity: 1; +} +.hero.is-link .tabs.is-boxed a, +.hero.is-link .tabs.is-toggle a { + color: #fff; +} +.hero.is-link .tabs.is-boxed a:hover, +.hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-link .tabs.is-boxed li.is-active a, +.hero.is-link .tabs.is-toggle li.is-active a, +.hero.is-link .tabs.is-boxed li.is-active a:hover, +.hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3273dc; +} +.hero.is-link.is-bold { + background-image: linear-gradient(141deg, #1576c6 0%, #3273dc 71%, #4266e5 100%); +} +@media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1576c6 0%, #3273dc 71%, #4266e5 100%); + } +} +.hero.is-info { + background-color: #3298dc; + color: #fff; +} +.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-info strong { + color: inherit; +} +.hero.is-info .title { + color: #fff; +} +.hero.is-info .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-info .subtitle a:not(.button), +.hero.is-info .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-info .navbar-menu { + background-color: #3298dc; + } +} +.hero.is-info .navbar-item, +.hero.is-info .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-info a.navbar-item:hover, +.hero.is-info .navbar-link:hover, +.hero.is-info a.navbar-item.is-active, +.hero.is-info .navbar-link.is-active { + background-color: #238cd1; + color: #fff; +} +.hero.is-info .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-info .tabs a:hover { + opacity: 1; +} +.hero.is-info .tabs li.is-active a { + opacity: 1; +} +.hero.is-info .tabs.is-boxed a, +.hero.is-info .tabs.is-toggle a { + color: #fff; +} +.hero.is-info .tabs.is-boxed a:hover, +.hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-info .tabs.is-boxed li.is-active a, +.hero.is-info .tabs.is-toggle li.is-active a, +.hero.is-info .tabs.is-boxed li.is-active a:hover, +.hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3298dc; +} +.hero.is-info.is-bold { + background-image: linear-gradient(141deg, #159cc6 0%, #3298dc 71%, #4289e5 100%); +} +@media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #159cc6 0%, #3298dc 71%, #4289e5 100%); + } +} +.hero.is-success { + background-color: #48c774; + color: #fff; +} +.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-success strong { + color: inherit; +} +.hero.is-success .title { + color: #fff; +} +.hero.is-success .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-success .subtitle a:not(.button), +.hero.is-success .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-success .navbar-menu { + background-color: #48c774; + } +} +.hero.is-success .navbar-item, +.hero.is-success .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-success a.navbar-item:hover, +.hero.is-success .navbar-link:hover, +.hero.is-success a.navbar-item.is-active, +.hero.is-success .navbar-link.is-active { + background-color: #3abb67; + color: #fff; +} +.hero.is-success .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-success .tabs a:hover { + opacity: 1; +} +.hero.is-success .tabs li.is-active a { + opacity: 1; +} +.hero.is-success .tabs.is-boxed a, +.hero.is-success .tabs.is-toggle a { + color: #fff; +} +.hero.is-success .tabs.is-boxed a:hover, +.hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-success .tabs.is-boxed li.is-active a, +.hero.is-success .tabs.is-toggle li.is-active a, +.hero.is-success .tabs.is-boxed li.is-active a:hover, +.hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #48c774; +} +.hero.is-success.is-bold { + background-image: linear-gradient(141deg, #29b342 0%, #48c774 71%, #56d296 100%); +} +@media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #29b342 0%, #48c774 71%, #56d296 100%); + } +} +.hero.is-warning { + background-color: #ffdd57; + color: rgba(0,0,0,0.7); +} +.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-warning strong { + color: inherit; +} +.hero.is-warning .title { + color: rgba(0,0,0,0.7); +} +.hero.is-warning .subtitle { + color: rgba(0,0,0,0.9); +} +.hero.is-warning .subtitle a:not(.button), +.hero.is-warning .subtitle strong { + color: rgba(0,0,0,0.7); +} +@media screen and (max-width: 1087px) { + .hero.is-warning .navbar-menu { + background-color: #ffdd57; + } +} +.hero.is-warning .navbar-item, +.hero.is-warning .navbar-link { + color: rgba(0,0,0,0.7); +} +.hero.is-warning a.navbar-item:hover, +.hero.is-warning .navbar-link:hover, +.hero.is-warning a.navbar-item.is-active, +.hero.is-warning .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0,0,0,0.7); +} +.hero.is-warning .tabs a { + color: rgba(0,0,0,0.7); + opacity: 0.9; +} +.hero.is-warning .tabs a:hover { + opacity: 1; +} +.hero.is-warning .tabs li.is-active a { + opacity: 1; +} +.hero.is-warning .tabs.is-boxed a, +.hero.is-warning .tabs.is-toggle a { + color: rgba(0,0,0,0.7); +} +.hero.is-warning .tabs.is-boxed a:hover, +.hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-warning .tabs.is-boxed li.is-active a, +.hero.is-warning .tabs.is-toggle li.is-active a, +.hero.is-warning .tabs.is-boxed li.is-active a:hover, +.hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0,0,0,0.7); + border-color: rgba(0,0,0,0.7); + color: #ffdd57; +} +.hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%); +} +@media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%); + } +} +.hero.is-danger { + background-color: #f14668; + color: #fff; +} +.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-danger strong { + color: inherit; +} +.hero.is-danger .title { + color: #fff; +} +.hero.is-danger .subtitle { + color: rgba(255,255,255,0.9); +} +.hero.is-danger .subtitle a:not(.button), +.hero.is-danger .subtitle strong { + color: #fff; +} +@media screen and (max-width: 1087px) { + .hero.is-danger .navbar-menu { + background-color: #f14668; + } +} +.hero.is-danger .navbar-item, +.hero.is-danger .navbar-link { + color: rgba(255,255,255,0.7); +} +.hero.is-danger a.navbar-item:hover, +.hero.is-danger .navbar-link:hover, +.hero.is-danger a.navbar-item.is-active, +.hero.is-danger .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; +} +.hero.is-danger .tabs a { + color: #fff; + opacity: 0.9; +} +.hero.is-danger .tabs a:hover { + opacity: 1; +} +.hero.is-danger .tabs li.is-active a { + opacity: 1; +} +.hero.is-danger .tabs.is-boxed a, +.hero.is-danger .tabs.is-toggle a { + color: #fff; +} +.hero.is-danger .tabs.is-boxed a:hover, +.hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-danger .tabs.is-boxed li.is-active a, +.hero.is-danger .tabs.is-toggle li.is-active a, +.hero.is-danger .tabs.is-boxed li.is-active a:hover, +.hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #f14668; +} +.hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #fa0a61 0%, #f14668 71%, #f7595f 100%); +} +@media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #fa0a61 0%, #f14668 71%, #f7595f 100%); + } +} +.hero.is-grey-lightest { + background-color: #ededed; + color: #363636; +} +.hero.is-grey-lightest a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-grey-lightest strong { + color: inherit; +} +.hero.is-grey-lightest .title { + color: #363636; +} +.hero.is-grey-lightest .subtitle { + color: rgba(54,54,54,0.9); +} +.hero.is-grey-lightest .subtitle a:not(.button), +.hero.is-grey-lightest .subtitle strong { + color: #363636; +} +@media screen and (max-width: 1087px) { + .hero.is-grey-lightest .navbar-menu { + background-color: #ededed; + } +} +.hero.is-grey-lightest .navbar-item, +.hero.is-grey-lightest .navbar-link { + color: rgba(54,54,54,0.7); +} +.hero.is-grey-lightest a.navbar-item:hover, +.hero.is-grey-lightest .navbar-link:hover, +.hero.is-grey-lightest a.navbar-item.is-active, +.hero.is-grey-lightest .navbar-link.is-active { + background-color: #e0e0e0; + color: #363636; +} +.hero.is-grey-lightest .tabs a { + color: #363636; + opacity: 0.9; +} +.hero.is-grey-lightest .tabs a:hover { + opacity: 1; +} +.hero.is-grey-lightest .tabs li.is-active a { + opacity: 1; +} +.hero.is-grey-lightest .tabs.is-boxed a, +.hero.is-grey-lightest .tabs.is-toggle a { + color: #363636; +} +.hero.is-grey-lightest .tabs.is-boxed a:hover, +.hero.is-grey-lightest .tabs.is-toggle a:hover { + background-color: rgba(10,10,10,0.1); +} +.hero.is-grey-lightest .tabs.is-boxed li.is-active a, +.hero.is-grey-lightest .tabs.is-toggle li.is-active a, +.hero.is-grey-lightest .tabs.is-boxed li.is-active a:hover, +.hero.is-grey-lightest .tabs.is-toggle li.is-active a:hover { + background-color: #363636; + border-color: #363636; + color: #ededed; +} +.hero.is-grey-lightest.is-bold { + background-image: linear-gradient(141deg, #d8cfcf 0%, #ededed 71%, #faf9f9 100%); +} +@media screen and (max-width: 768px) { + .hero.is-grey-lightest.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #d8cfcf 0%, #ededed 71%, #faf9f9 100%); + } +} +.hero.is-small .hero-body { + padding-bottom: 1.5rem; + padding-top: 1.5rem; +} +@media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding-bottom: 9rem; + padding-top: 9rem; + } +} +@media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding-bottom: 18rem; + padding-top: 18rem; + } +} +.hero.is-halfheight .hero-body, +.hero.is-fullheight .hero-body, +.hero.is-fullheight-with-navbar .hero-body { + align-items: center; + display: flex; +} +.hero.is-halfheight .hero-body > .container, +.hero.is-fullheight .hero-body > .container, +.hero.is-fullheight-with-navbar .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; +} +.hero.is-halfheight { + min-height: 50vh; +} +.hero.is-fullheight { + min-height: 100vh; +} +.hero-video { + overflow: hidden; +} +.hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); +} +.hero-video.is-transparent { + opacity: 0.3; +} +@media screen and (max-width: 768px) { + .hero-video { + display: none; + } +} +.hero-buttons { + margin-top: 1.5rem; +} +@media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; + } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; + } +} +@media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; + } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; + } +} +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; +} +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: 3rem 1.5rem; +} +.section { + padding: 3rem 1.5rem; +} +@media screen and (min-width: 1088px) { + .section.is-medium { + padding: 9rem 1.5rem; + } + .section.is-large { + padding: 18rem 1.5rem; + } +} +.footer { + background-color: #fff; + padding: 3rem 1.5rem 6rem; +} +html { + height: 100%; + -webkit-text-size-adjust: 100%; + -moz-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + text-size-adjust: 100%; +} +body { + min-height: 100%; + display: flex; + flex-direction: column; +} +body > .section { + flex-grow: 1; +} +@media screen and (min-width: 1088px) { + ::-webkit-scrollbar { + width: 8px; + height: 8px; + } + ::-webkit-scrollbar-track { + border-radius: 3px; + background: rgba(0,0,0,0.06); + box-shadow: inset 0 0 5px rgba(0,0,0,0.1); + } + ::-webkit-scrollbar-thumb { + border-radius: 3px; + background: rgba(0,0,0,0.12); + box-shadow: inset 0 0 10px rgba(0,0,0,0.2); + } + ::-webkit-scrollbar-thumb:hover { + background: rgba(0,0,0,0.24); + } +} +.article-licensing .licensing-meta h6, +.article-licensing .licensing-title a, +.size-small { + font-size: 0.85rem !important; +} +.ml-0, +.mx-0 { + margin-left: 0 !important; +} +.mr-0, +.mx-0 { + margin-right: 0 !important; +} +.ml-n0, +.mx-n0 { + margin-left: 0 !important; +} +.mr-n0, +.mx-n0 { + margin-right: 0 !important; +} +.mt-0, +.my-0 { + margin-top: 0 !important; +} +.mb-0, +.my-0 { + margin-bottom: 0 !important; +} +.mt-n0, +.my-n0 { + margin-top: 0 !important; +} +.mb-n0, +.my-n0 { + margin-bottom: 0 !important; +} +.pl-0, +.px-0 { + padding-left: 0 !important; +} +.pr-0, +.px-0 { + padding-right: 0 !important; +} +.pl-n0, +.px-n0 { + padding-left: 0 !important; +} +.pr-n0, +.px-n0 { + padding-right: 0 !important; +} +.pt-0, +.py-0 { + padding-top: 0 !important; +} +.pb-0, +.py-0 { + padding-bottom: 0 !important; +} +.pt-n0, +.py-n0 { + padding-top: 0 !important; +} +.pb-n0, +.py-n0 { + padding-bottom: 0 !important; +} +.ml-1, +.mx-1 { + margin-left: 0.25rem !important; +} +.mr-1, +.mx-1, +.article-licensing .licensing-meta .icon { + margin-right: 0.25rem !important; +} +.ml-n1, +.mx-n1 { + margin-left: -0.25rem !important; +} +.mr-n1, +.mx-n1 { + margin-right: -0.25rem !important; +} +.mt-1, +.my-1 { + margin-top: 0.25rem !important; +} +.mb-1, +.my-1, +.article-licensing .licensing-title p:not(:last-child) { + margin-bottom: 0.25rem !important; +} +.mt-n1, +.my-n1 { + margin-top: -0.25rem !important; +} +.mb-n1, +.my-n1 { + margin-bottom: -0.25rem !important; +} +.pl-1, +.px-1 { + padding-left: 0.25rem !important; +} +.pr-1, +.px-1 { + padding-right: 0.25rem !important; +} +.pl-n1, +.px-n1 { + padding-left: -0.25rem !important; +} +.pr-n1, +.px-n1 { + padding-right: -0.25rem !important; +} +.pt-1, +.py-1 { + padding-top: 0.25rem !important; +} +.pb-1, +.py-1 { + padding-bottom: 0.25rem !important; +} +.pt-n1, +.py-n1 { + padding-top: -0.25rem !important; +} +.pb-n1, +.py-n1 { + padding-bottom: -0.25rem !important; +} +.ml-2, +.mx-2 { + margin-left: 0.5rem !important; +} +.mr-2, +.mx-2 { + margin-right: 0.5rem !important; +} +.ml-n2, +.mx-n2 { + margin-left: -0.5rem !important; +} +.mr-n2, +.mx-n2 { + margin-right: -0.5rem !important; +} +.mt-2, +.my-2 { + margin-top: 0.5rem !important; +} +.mb-2, +.my-2 { + margin-bottom: 0.5rem !important; +} +.mt-n2, +.my-n2 { + margin-top: -0.5rem !important; +} +.mb-n2, +.my-n2 { + margin-bottom: -0.5rem !important; +} +.pl-2, +.px-2 { + padding-left: 0.5rem !important; +} +.pr-2, +.px-2 { + padding-right: 0.5rem !important; +} +.pl-n2, +.px-n2 { + padding-left: -0.5rem !important; +} +.pr-n2, +.px-n2 { + padding-right: -0.5rem !important; +} +.pt-2, +.py-2 { + padding-top: 0.5rem !important; +} +.pb-2, +.py-2 { + padding-bottom: 0.5rem !important; +} +.pt-n2, +.py-n2 { + padding-top: -0.5rem !important; +} +.pb-n2, +.py-n2 { + padding-bottom: -0.5rem !important; +} +.ml-3, +.mx-3 { + margin-left: 1rem !important; +} +.mr-3, +.mx-3 { + margin-right: 1rem !important; +} +.ml-n3, +.mx-n3 { + margin-left: -1rem !important; +} +.mr-n3, +.mx-n3 { + margin-right: -1rem !important; +} +.mt-3, +.my-3 { + margin-top: 1rem !important; +} +.mb-3, +.my-3, +.article-licensing .licensing-title { + margin-bottom: 1rem !important; +} +.mt-n3, +.my-n3 { + margin-top: -1rem !important; +} +.mb-n3, +.my-n3 { + margin-bottom: -1rem !important; +} +.pl-3, +.px-3 { + padding-left: 1rem !important; +} +.pr-3, +.px-3 { + padding-right: 1rem !important; +} +.pl-n3, +.px-n3 { + padding-left: -1rem !important; +} +.pr-n3, +.px-n3 { + padding-right: -1rem !important; +} +.pt-3, +.py-3 { + padding-top: 1rem !important; +} +.pb-3, +.py-3 { + padding-bottom: 1rem !important; +} +.pt-n3, +.py-n3 { + padding-top: -1rem !important; +} +.pb-n3, +.py-n3 { + padding-bottom: -1rem !important; +} +.ml-4, +.mx-4 { + margin-left: 1.5rem !important; +} +.mr-4, +.mx-4, +.article-licensing .licensing-meta .level-item { + margin-right: 1.5rem !important; +} +.ml-n4, +.mx-n4 { + margin-left: -1.5rem !important; +} +.mr-n4, +.mx-n4 { + margin-right: -1.5rem !important; +} +.mt-4, +.my-4 { + margin-top: 1.5rem !important; +} +.mb-4, +.my-4 { + margin-bottom: 1.5rem !important; +} +.mt-n4, +.my-n4 { + margin-top: -1.5rem !important; +} +.mb-n4, +.my-n4 { + margin-bottom: -1.5rem !important; +} +.pl-4, +.px-4 { + padding-left: 1.5rem !important; +} +.pr-4, +.px-4 { + padding-right: 1.5rem !important; +} +.pl-n4, +.px-n4 { + padding-left: -1.5rem !important; +} +.pr-n4, +.px-n4 { + padding-right: -1.5rem !important; +} +.pt-4, +.py-4 { + padding-top: 1.5rem !important; +} +.pb-4, +.py-4 { + padding-bottom: 1.5rem !important; +} +.pt-n4, +.py-n4 { + padding-top: -1.5rem !important; +} +.pb-n4, +.py-n4 { + padding-bottom: -1.5rem !important; +} +.ml-5, +.mx-5 { + margin-left: 3rem !important; +} +.mr-5, +.mx-5 { + margin-right: 3rem !important; +} +.ml-n5, +.mx-n5 { + margin-left: -3rem !important; +} +.mr-n5, +.mx-n5 { + margin-right: -3rem !important; +} +.mt-5, +.my-5 { + margin-top: 3rem !important; +} +.mb-5, +.my-5 { + margin-bottom: 3rem !important; +} +.mt-n5, +.my-n5 { + margin-top: -3rem !important; +} +.mb-n5, +.my-n5 { + margin-bottom: -3rem !important; +} +.pl-5, +.px-5 { + padding-left: 3rem !important; +} +.pr-5, +.px-5 { + padding-right: 3rem !important; +} +.pl-n5, +.px-n5 { + padding-left: -3rem !important; +} +.pr-n5, +.px-n5 { + padding-right: -3rem !important; +} +.pt-5, +.py-5 { + padding-top: 3rem !important; +} +.pb-5, +.py-5 { + padding-bottom: 3rem !important; +} +.pt-n5, +.py-n5 { + padding-top: -3rem !important; +} +.pb-n5, +.py-n5 { + padding-bottom: -3rem !important; +} +.ml-auto, +.mx-auto { + margin-left: auto !important; +} +.mr-auto, +.mx-auto { + margin-right: auto !important; +} +.mt-auto, +.my-auto { + margin-top: auto !important; +} +.mb-auto, +.my-auto { + margin-bottom: auto !important; +} +.pl-auto, +.px-auto { + margin-left: auto !important; +} +.pr-auto, +.px-auto { + margin-right: auto !important; +} +.pt-auto, +.py-auto { + margin-top: auto !important; +} +.pb-auto, +.py-auto { + margin-bottom: auto !important; +} +.order-0 { + order: 0 !important; +} +.order-1 { + order: 1 !important; +} +.order-2 { + order: 2 !important; +} +.order-3 { + order: 3 !important; +} +.order-4 { + order: 4 !important; +} +.order-5 { + order: 5 !important; +} +.justify-content-start { + justify-content: start !important; +} +.justify-content-center { + justify-content: center !important; +} +.flex-shrink-1 { + flex-shrink: 1 !important; +} +.link-muted { + color: inherit; +} +.link-muted:hover { + color: #3273dc !important; +} +.image.is-7by3 { + padding-top: 42.8%; +} +.image.is-7by3 img { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.image .avatar { + height: 100%; + object-fit: cover; +} +.image .fill { + object-fit: cover; + width: 100% !important; + height: 100% !important; +} +.button.is-transparent { + color: inherit; + background: transparent; + border-color: transparent; +} +.card { + overflow: visible; + border-radius: 4px; +} +.card + .card, +.card + .column-right-shadow { + margin-top: 1.5rem; +} +.card .card-image { + overflow: hidden; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.card .media + .media { + border: none; + margin-top: 0; +} +article.media { + color: #7a7a7a; +} +article.media a { + color: inherit; +} +article.media a:hover { + color: #3273dc; +} +article.media .image { + width: 64px; + height: 64px; +} +article.media .image img { + object-fit: cover; + width: 100%; + height: 100%; +} +article.media .title { + margin-bottom: 0.25em; +} +article.media .media-content { + color: #7a7a7a; +} +article.media .media-content .title { + margin: 0; + line-height: inherit; +} +article.article .article-meta, +article.article .article-tags { + color: #7a7a7a; +} +article.article .article-meta { + overflow-x: auto; + margin-bottom: 0.5rem; +} +article.article .content { + word-wrap: break-word; + font-size: 1.1rem; +} +article.article .content h1 { + font-size: 1.75em; +} +article.article .content h2 { + font-size: 1.5em; +} +article.article .content h3 { + font-size: 1.25em; +} +article.article .content h4 { + font-size: 1.125em; +} +article.article .content h5 { + font-size: 1em; +} +article.article .content pre { + font-size: 0.85em; +} +article.article .content code { + padding: 0; + background: transparent; + overflow-wrap: break-word; +} +article.article .content blockquote.pullquote { + float: right; + max-width: 50%; + font-size: 1.15rem; + position: relative; +} +article.article .content blockquote footer strong + cite { + margin-left: 0.5em; +} +article.article .content .message.message-immersive { + border-radius: 0; + margin: 0 -1.5rem 1.5rem -1.5rem; +} +article.article .content .message.message-immersive .message-body { + border: none; +} +.rtl { + direction: rtl; +} +.rtl .level .level-item:not(:last-child), +.rtl .level.is-mobile .level-item:not(:last-child) { + margin-left: 0.75rem; + margin-right: 0; +} +.table-overflow { + overflow-x: auto; +} +.table-overflow table { + width: auto !important; +} +.table-overflow table th { + word-break: keep-all; +} +.video-container { + position: relative; + padding-bottom: 56.25%; + padding-top: 25px; + height: 0; +} +.video-container iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.article-licensing { + position: relative; + z-index: 1; + box-shadow: none; + background: #f5f5f5; + border-radius: 4px; + overflow: hidden; +} +.article-licensing:after { + position: absolute; + z-index: -1; + right: -50px; + top: -87.87px; + content: '\f25e'; + font-size: 200px; + font-family: 'Font Awesome 5 Brands'; + opacity: 0.1; +} +.article-licensing .level-left { + flex-wrap: wrap; + max-width: 100%; +} +.article-licensing .licensing-title { + line-height: 1.2; +} +.article-licensing .licensing-meta .icon { + width: 1.2em; + height: 1.2em; + font-size: 1.2em; + vertical-align: bottom; +} +.article-licensing .licensing-meta a { + color: inherit; +} +a.article-nav-prev span { + text-align: left; + flex-shrink: 1; + word-wrap: break-word; + white-space: normal; +} +a.article-nav-next span { + text-align: right; + flex-shrink: 1; + word-wrap: break-word; + white-space: normal; +} +.navbar-main { + box-shadow: 0 4px 10px rgba(0,0,0,0.05); +} +.navbar-main .navbar-menu, +.navbar-main .navbar-start, +.navbar-main .navbar-end { + align-items: stretch; + display: flex; + padding: 0; + flex-shrink: 0; +} +.navbar-main .navbar-menu { + flex-grow: 1; + flex-shrink: 0; + overflow-x: auto; +} +.navbar-main .navbar-start { + justify-content: flex-start; + margin-right: auto; +} +.navbar-main .navbar-end { + justify-content: flex-end; + margin-left: auto; +} +.navbar-main .navbar-item { + display: flex; + align-items: center; + padding: 1.25rem 0.75rem; + margin: 0 0; +} +.navbar-main .navbar-item.is-active { + background-color: transparent; +} +@media screen and (max-width: 1087px) { + .navbar-main .navbar-menu { + justify-content: center; + box-shadow: none; + } + .navbar-main .navbar-start { + margin-right: 0; + } + .navbar-main .navbar-end { + margin-left: 0; + } +} +.navbar-logo img { + max-height: 1.75rem; +} +@media screen and (max-width: 768px) { + footer.footer .level-start { + text-align: center; + } +} +footer.footer .level-end .field { + flex-wrap: wrap; + align-items: center; +} +@media screen and (max-width: 768px) { + footer.footer .level-end .field { + justify-content: center; + margin-top: 1rem; + } +} +.footer-logo img { + max-height: 1.75rem; +} +.pagination { + margin-top: 1.5rem; +} +.pagination .pagination-link a, +.pagination .pagination-ellipsis a, +.pagination .pagination-previous a, +.pagination .pagination-next a { + color: #363636; +} +.pagination .pagination-link, +.pagination .pagination-previous, +.pagination .pagination-next { + border: none; + background: #fff; + box-shadow: 0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1); +} +.pagination .pagination-link.is-current { + background: #3273dc; +} +.post-navigation { + color: #7a7a7a; + flex-wrap: wrap; + justify-content: space-around; +} +.post-navigation .level-item { + margin-bottom: 0; +} +.timeline { + margin-left: 1rem; + padding: 1rem 0 0 1.5rem; + border-left: 1px solid #dbdbdb; +} +.timeline .media { + position: relative; +} +.timeline .media:before, +.timeline .media:last-child:after { + content: ''; + display: block; + position: absolute; + left: calc(-0.375rem - 1.5rem - 0.25px); +} +.timeline .media:before { + width: 0.75rem; + height: 0.75rem; + top: calc(1rem + 1.5 * 0.85rem / 2 - 0.75rem / 2); + background: #dbdbdb; + border-radius: 50%; +} +.timeline .media:first-child:before { + top: calc(1.5 * 0.85rem / 2 - 0.75rem / 2); +} +.timeline .media:last-child:after { + width: 0.75rem; + top: calc(1rem + 1.5 * 0.85rem / 2 + 0.75rem / 2); + bottom: 0; + background: #fff; +} +.timeline .media:first-child:last-child:after { + top: calc(1.5 * 0.85rem / 2 + 0.75rem / 2); +} +.searchbox { + display: none; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 100; + font-size: 1rem; + line-height: 0; + background: rgba(10,10,10,0.86); +} +.searchbox.show { + display: flex; +} +.searchbox a, +.searchbox a:hover { + color: inherit; + text-decoration: none; +} +.searchbox input { + font-size: 1rem; + border: none; + outline: none; + box-shadow: none; + border-radius: 0; +} +.searchbox, +.searchbox .searchbox-container { + position: fixed; + align-items: center; + flex-direction: column; + line-height: 1.25em; +} +.searchbox .searchbox-container { + z-index: 101; + display: flex; + overflow: hidden; + box-shadow: 0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1); + border-radius: 4px; + background-color: #f5f5f5; + width: 540px; + top: 100px; + bottom: 100px; +} +.searchbox .searchbox-header, +.searchbox .searchbox-body, +.searchbox .searchbox-footer { + width: 100%; +} +.searchbox .searchbox-header { + display: flex; + flex-direction: row; + line-height: 1.5em; + font-weight: normal; + background-color: #fff; + min-height: 3rem; +} +.searchbox .searchbox-input-container { + display: flex; + flex-grow: 1; +} +.searchbox .searchbox-input { + flex-grow: 1; + color: inherit; + box-sizing: border-box; + padding: 0.75em 0 0.75em 1.25em; + background: #fff; +} +.searchbox .searchbox-close { + display: inline-block; + font-size: 1.5em; + padding: 0.5em 0.75em; + cursor: pointer; +} +.searchbox .searchbox-close:hover { + background: #f5f5f5; +} +.searchbox .searchbox-close:active { + background: #dbdbdb; +} +.searchbox .searchbox-body { + flex-grow: 1; + overflow-y: auto; + border-top: 1px solid #dbdbdb; +} +.searchbox .searchbox-result-section header, +.searchbox .searchbox-result-item { + padding: 0.75em 1em; +} +.searchbox .searchbox-result-section { + border-bottom: 1px solid #dbdbdb; +} +.searchbox .searchbox-result-section header { + color: #b5b5b5; +} +.searchbox .searchbox-result-item { + display: flex; + flex-direction: row; +} +.searchbox .searchbox-result-item:not(.disabled):not(.active):not(:active):hover { + background-color: #fff; +} +.searchbox .searchbox-result-item:active, +.searchbox .searchbox-result-item.active { + color: #fff; + background-color: #3273dc; +} +.searchbox .searchbox-result-item em { + font-style: normal; + background: #ffdd57; +} +.searchbox .searchbox-result-icon { + margin-right: 1em; +} +.searchbox .searchbox-result-content { + overflow: hidden; +} +.searchbox .searchbox-result-title, +.searchbox .searchbox-result-preview { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.searchbox .searchbox-result-title-secondary { + color: #b5b5b5; +} +.searchbox .searchbox-result-preview { + margin-top: 0.25em; +} +.searchbox .searchbox-result-item:not(:active):not(.active) .searchbox-result-preview { + color: #b5b5b5; +} +.searchbox .searchbox-footer { + padding: 0.5em 1em; +} +.searchbox .searchbox-pagination { + margin: 0; + padding: 0; + list-style: none; + text-align: center; +} +.searchbox .searchbox-pagination .searchbox-pagination-item { + margin: 0 0.25rem; +} +.searchbox .searchbox-pagination .searchbox-pagination-item, +.searchbox .searchbox-pagination .searchbox-pagination-link { + display: inline-block; +} +.searchbox .searchbox-pagination .searchbox-pagination-link { + overflow: hidden; + padding: 0.5em 0.8em; + box-shadow: 0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1); + border-radius: 4px; + background-color: #fff; +} +.searchbox .searchbox-pagination .searchbox-pagination-item.active .searchbox-pagination-link { + color: #fff; + background-color: #3273dc; +} +.searchbox .searchbox-pagination .searchbox-pagination-item.disabled .searchbox-pagination-link { + cursor: not-allowed; + background-color: #f5f5f5; +} +.searchbox .searchbox-pagination .searchbox-pagination-item:not(.active):not(.disabled) .searchbox-pagination-link:hover { + background-color: #f5f5f5; +} +@media screen and (max-width: 559px), screen and (max-height: 479px) { + .searchbox .searchbox-container { + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 0; + } +} +figure.highlight { + padding: 0; + width: 100%; + position: relative; + margin: 1em 0 1em !important; + border-radius: 4px; +} +figure.highlight.folded .highlight-body { + height: 0; +} +figure.highlight .copy { + opacity: 0.7; +} +figure.highlight pre, +figure.highlight table tr:hover { + color: inherit; + background: transparent; +} +figure.highlight table { + width: auto; +} +figure.highlight table tr td { + border: none; +} +figure.highlight table tr:not(:first-child) td { + padding-top: 0; +} +figure.highlight table tr:not(:last-child) td { + padding-bottom: 0; +} +figure.highlight pre { + padding: 0; + overflow: visible; +} +figure.highlight pre .line, +figure.highlight pre code .hljs { + line-height: 1.5rem; +} +figure.highlight figcaption, +figure.highlight .gutter { + background: rgba(200,200,200,0.15); +} +figure.highlight figcaption { + margin: 0 !important; + padding: 0.3em 0em 0.3em 0.75em; + font-style: normal; + font-size: 0.8em; +} +figure.highlight figcaption * { + color: inherit; +} +figure.highlight figcaption span { + font-weight: 500; + font-family: 'Source Code Pro', monospace, 'Microsoft YaHei'; +} +figure.highlight figcaption .level-left *:not(:last-child) { + margin-right: 0.5em; +} +figure.highlight figcaption .level-right *:not(:first-child) { + margin-left: 0.5em; +} +figure.highlight figcaption .fold { + cursor: pointer; +} +figure.highlight figcaption.level { + overflow: auto; +} +figure.highlight figcaption.level .level-right a { + padding: 0em 0.75em; +} +figure.highlight .highlight-body { + overflow: auto; +} +figure.highlight .gutter { + text-align: right; +} +figure.highlight .tag, +figure.highlight .title, +figure.highlight .number, +figure.highlight .section { + display: inherit; + font: inherit; + margin: inherit; + padding: inherit; + background: inherit; + height: inherit; + text-align: inherit; + vertical-align: inherit; + min-width: inherit; + border-radius: inherit; +} +.gist table tr:hover { + background: transparent; +} +.gist table td { + border: none; +} +.gist .file { + all: initial; +} +.widget .menu-list li ul { + margin-right: 0; +} +.widget .menu-list .level { + margin-bottom: 0; +} +.widget .menu-list .level .level-left, +.widget .menu-list .level .level-right, +.widget .menu-list .level .level-item { + flex-shrink: 1; +} +.widget .menu-list .level .level-left, +.widget .menu-list .level .level-right { + align-items: flex-start; +} +.widget .menu-list .tag { + background: $light-grey; + color: $white-invert; +} +.widget .tags .tag:first-child { + background: #3273dc; + color: #fff; +} +.widget .tags .tag:last-child { + background: $light-grey; + color: $white-invert; +} +.donate { + position: relative; +} +.donate .qrcode { + display: none; + position: absolute; + z-index: 99; + bottom: 2.5em; + line-height: 0; + overflow: hidden; + box-shadow: 0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1); + border-radius: 4px; +} +.donate .qrcode img { + max-width: 280px; +} +.donate:hover .qrcode { + display: block; +} +.donate:first-child:not(:last-child) .qrcode { + left: -0.75rem; +} +.donate:last-child:not(:first-child) .qrcode { + right: -0.75rem; +} +.donate[data-type="afdian"] { + color: #fff; + background-color: #885fd9; + border-color: transparent; +} +.donate[data-type="afdian"]:active { + background-color: #794ad4; +} +.donate[data-type="afdian"]:hover { + background-color: #8055d7; +} +.donate[data-type="afdian"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(136,95,217,0.25); +} +.donate[data-type="alipay"] { + color: #fff; + background-color: #00a0e8; + border-color: transparent; +} +.donate[data-type="alipay"]:active { + background-color: #008ecf; +} +.donate[data-type="alipay"]:hover { + background-color: #0097db; +} +.donate[data-type="alipay"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0,160,232,0.25); +} +.donate[data-type="buymeacoffee"] { + color: rgba(0,0,0,0.7); + background-color: #fd0; + border-color: transparent; +} +.donate[data-type="buymeacoffee"]:active { + background-color: #e6c700; +} +.donate[data-type="buymeacoffee"]:hover { + background-color: #f2d200; +} +.donate[data-type="buymeacoffee"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,221,0,0.25); +} +.donate[data-type="paypal"] { + color: rgba(0,0,0,0.7); + background-color: #feb700; + border-color: transparent; +} +.donate[data-type="paypal"]:active { + background-color: #e5a500; +} +.donate[data-type="paypal"]:hover { + background-color: #f1ae00; +} +.donate[data-type="paypal"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(254,183,0,0.25); +} +.donate[data-type="patreon"] { + color: #fff; + background-color: #ff424d; + border-color: transparent; +} +.donate[data-type="patreon"]:active { + background-color: #ff2835; +} +.donate[data-type="patreon"]:hover { + background-color: #ff3541; +} +.donate[data-type="patreon"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255,66,77,0.25); +} +.donate[data-type="wechat"] { + color: #fff; + background-color: #1aad19; + border-color: transparent; +} +.donate[data-type="wechat"]:active { + background-color: #179716; +} +.donate[data-type="wechat"]:hover { + background-color: #18a217; +} +.donate[data-type="wechat"]:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(26,173,25,0.25); +} +#back-to-top { + position: fixed; + opacity: 0; + outline: none; + padding: 8px 0; + line-height: 24px; + border-radius: 4px; + transform: translateY(120px); + transition: 0.4s ease opacity, 0.4s ease width, 0.4s ease transform, 0.4s ease border-radius; +} +#back-to-top.is-rounded { + border-radius: 50%; +} +#back-to-top.fade-in { + opacity: 1; +} +#back-to-top.rise-up { + transform: translateY(0); +} +.gallery-item .caption { + color: #7a7a7a; +} +@media screen and (max-width: 768px) { + #toc { + display: none; + position: fixed; + margin: 1rem; + left: 0; + right: 0; + bottom: 0; + z-index: 100; + max-height: calc(100vh - 2rem); + overflow-y: auto; + } + #toc-mask { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 99; + background: rgba(0,0,0,0.7); + } + #toc.is-active, + #toc-mask.is-active { + display: block; + } +} +.pace { + user-select: none; + pointer-events: none; +} +.pace .pace-progress { + top: 0; + right: 100%; + width: 100%; + height: 2px; + z-index: 2000; + position: fixed; + background: #3273dc; +} +.pace-inactive { + display: none; +} +.fa, +.fab, +.fal, +.far, +.fas { + line-height: inherit; +} +.MathJax, +.katex-display { + overflow-x: auto; + overflow-y: hidden; +} +.katex { + white-space: nowrap; +} +.katex-display { + margin-top: -1em !important; +} +.katex-html { + padding-top: 1em; +} +.katex-html .tag { + align-items: unset; + background-color: unset; + border-radius: unset; + color: unset; + display: unset; + font-size: unset; + height: unset; + justify-content: unset; + line-height: unset; + padding-left: unset; + padding-right: unset; + white-space: unset; +} +.cc-window, +.cc-revoke { + font-size: 1.1rem !important; + font-family: Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.cc-window { + color: #4a4a4a !important; + background-color: #fff !important; +} +.cc-window.cc-floating { + border-radius: 4px; + box-shadow: 0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1); +} +.cc-window.cc-banner { + background-color: #f9f9f9 !important; +} +.cc-window.cc-theme-block .cc-compliance > .cc-btn, +.cc-window.cc-theme-classic .cc-compliance > .cc-btn { + border-radius: 290486px; +} +.cc-window .cc-compliance > .cc-btn { + font-weight: 400; + border: none; + color: #fff; + background-color: #3273dc; +} +.cc-window .cc-compliance > .cc-btn:hover, +.cc-window .cc-compliance > .cc-btn:focus { + background-color: #276cda; +} +.cc-window .cc-compliance > .cc-btn.cc-deny:hover { + color: #3273dc; + text-decoration: none; +} +.cc-revoke { + padding: 0.5rem 1rem !important; + color: #fff !important; + background-color: #3273dc !important; +} +.cc-revoke:hover { + text-decoration: none !important; + background-color: #276cda; +} +@media screen and (min-width: 1280px) { + .is-1-column .container, + .is-2-column .container { + max-width: 960px; + width: 960px; + } +} +@media screen and (min-width: 1472px) { + .is-2-column .container { + max-width: 1152px; + width: 1152px; + } + .is-1-column .container { + max-width: 960px; + width: 960px; + } +} +@media screen and (min-width: 769px), print { + .is-sticky { + position: -webkit-sticky; + position: sticky; + top: 1.5rem; + z-index: 99; + } + .column-main.is-sticky, + .column-left.is-sticky, + .column-right.is-sticky, + .column-right-shadow.is-sticky { + top: 0.75rem; + align-self: flex-start; + } +} +@media screen and (max-width: 768px) { + .section { + padding: 1.5rem 1rem; + } +} +.display-none-class { + display: none; +} +.index-category-tag { + margin-bottom: 1rem; +} +.index-category-tag .level-item { + display: unset; +} +article.article .pin-icon { + color: #3273dc; + font-size: 1.6rem; + margin-right: 20px; + transform: rotate(30deg); + -ms-transform: rotate(30deg); + -moz-transform: rotate(30deg); + -webkit-transform: rotate(30deg); + -o-transform: rotate(30deg); +} +article.article .article-meta { + height: 41px; +} +.index-category-tag hr { + background-color: #f5f5f5; + margin-top: 0.3rem; + margin-bottom: 0.5rem; + box-shadow: unset; +} +.index-category-tag .button.is-small { + border-radius: 2px; + margin-bottom: 4px; + background-color: unset; +} +.index-categories, +.index-tags { + padding: 2px; +} +.recommend-post { + margin: 0 0 1.5rem 0; +} +.recommend-area { + background: #f5f5f5; + padding: 0.5rem 0.5rem; + margin: 0.5rem 0rem; +} +.function_ { + color: #ffdd57; +} +.class_ { + color: #ffdd57; +} +.navbar.is-fixed-top { + top: 0; +} +.navbar.is-fixed-bottom, +.navbar.is-fixed-top { + z-index: 100; +} +@media screen and (min-width: 1280px) { + .is-1-column .container, + .is-2-column .container, + .is-3-column .container { +/* 关闭评论图片 后调节 原94%*/ + max-width: 85%; /*screen-widescreen + 2 * extend-width - 2 * gap*/ + width: 85%; + } + .column.is-3-widescreen { + flex: none; + width: 24%; + } + .column.is-6-widescreen { + width: 52%; + } + .column.is-4-widescreen { + flex: none; + width: 24%; + } + .column.is-8-widescreen { + width: 76%; + } + .column.is-9-widescreen { + width: 76%; + } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: 0%; + } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: 0.5%; + } + .level-end { + margin-right: -1.5%; + } +} +@media screen and (min-width: 1472px) { + .is-2-column .container { + max-width: 1152px; + width: 1152px; + } + .is-1-column .container { + max-width: 960px; + width: 960px; + } +} +@media screen and (min-width: 769px), print { + .has-navbar-fixed-top .column-main.is-sticky, + .has-navbar-fixed-top .column-left.is-sticky, + .has-navbar-fixed-top .column-right.is-sticky, + .has-navbar-fixed-top .column-right-shadow.is-sticky, + .has-navbar-fixed-top .widget.is-sticky { + top: 5.5rem; + } +} +@media screen and (max-width: 768px) { + .section { + padding: 6.5rem 1.5rem; + } + .friend-card-item { + width: 100% !important; + } +} +.level-item .subtitle, +.level-item .title { + margin-bottom: 0; +} +#hitokoto { + text-align: center; + cursor: pointer; + padding: 1rem; +} +.level:not(:last-child) { + margin-bottom: 0.5rem; +} +hr { + margin: 0 0; +} +.donate .qrcode img { + max-width: 140px; +} +.body_hot_comment .comment-content { + font-size: 0.75em; + letter-spacing: 0.1em; +} +.body_hot_comment .comment-content .card-comment-item { + display: inline-block; + margin-top: 10px; + width: 100%; +} +.body_hot_comment .comment-content .card-comment-item .ava { + height: 3rem !important; + margin-right: 0.2em !important; + border-radius: 40px; +} +.body_hot_comment .comment-content .card-comment-item img { + float: left; + transition: all 0.5s ease-in; + -webkit-transition: all 0.5s ease-in; + -moz-transition: all 0.5s ease-in; + -o-transition: all 0.5s ease-in; +} +.body_hot_comment .comment-content .card-comment-item img:hover { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); +} +.body_hot_comment .comment-content :first-child { + margin-top: unset; +} +.body_hot_comment .comment-content .item-header-text { + padding-left: 0.75em; + font-size: 0.75rem; + line-height: 1.5; + -webkit-line-clamp: 1; + overflow: hidden; + -webkit-box-orient: vertical; + display: -webkit-box; +} +.body_hot_comment .comment-content .item-text { + padding-left: 0.75em; + font-size: 0.75rem; + line-height: 1.5; + -webkit-line-clamp: 2; + text-overflow: ellipsis; + overflow: hidden; + height: auto; + -webkit-box-orient: vertical; + word-break: break-all; + display: -webkit-box; + white-space: normal; +} +.level0 { + background-color: #d9e6fd; + color: #4a4a4a; +} +.level1 { + background-color: #8fb8fb; + color: #4a4a4a; +} +.level2 { + background-color: #5593f7; + color: #fff; +} +.level3 { + background-color: #3273dc; + color: #fff; +} +#index_hot_div { + margin-top: 10px; + display: flex; + flex-wrap: wrap; +} +#index_hot_div .item { + align-items: center; + border-radius: 4px; + display: inline-flex; + font-size: 0.75rem; + height: 2.1rem; + justify-content: center; + line-height: 1.5; + padding-left: 0.5rem; + padding-right: 0.5rem; + white-space: nowrap; + margin-bottom: 0.75rem; + box-shadow: 0px 0px 2px 1px #b5b5b5; +} +.post-calendar-pre { + overflow-x: auto; + justify-content: center; + max-width: 100%; +} +#post-calendar { + display: flex; + justify-context: center; + align-items: center; + left: 0px; + top: 0px; + width: 100%; + height: 200px; + -webkit-tap-highlight-color: rgba(0,0,0,0); + margin-bottom: 2rem; +} +.night { + color: #c0c0c0 !important; + background-color: #000; +} +.night .aplayer .aplayer-miniswitcher { + background: #c0c0c0 !important; +} +.night .navbar-highlight { + background-color: #151313 !important; +} +.night .content blockquote { + background-color: #151313; +} +.night .button.is-light { + background-color: #151313; +} +.night .tag:not(body) { + background-color: #151313; +} +.night strong { + color: #fff; +} +.night .time-axis-main .time-axis-achievement, +.night .time-axis-main .time-axis-title { + background-color: #151313; + color: #fff; +} +.night .pagination .pagination-link:not(.is-current), +.night .pagination .pagination-previous, +.night .pagination .pagination-next { + background-color: #151313; +} +.night .button.is-white { + color: #fff; +} +.night .button.is-light { + color: #c0c0c0; +} +.night a:hover { + color: #fff; +} +.night hr { + background-color: #151313; +} +.night .menu-list a:hover { + background-color: #7a7a7a; + color: #3273dc; +} +.night .menu-list a { + color: #c0c0c0; +} +.night .level a:hover { + color: #3273dc !important; +} +.night .level .is-rounded:hover { + color: #fff !important; +} +.night .level .level-item.is-marginless:hover { + background-color: #151313; + color: #3273dc; +} +.night .level .level-item.is-link:hover { + color: #fff; +} +.night .navbar-menu a:hover { + color: #3273dc; +} +.night .post-copyright { + background-color: #151313; +} +.night #back-to-top:hover { + color: #3273dc; +} +.night .tags.has-addons .tag:hover { + color: #3273dc; +} +.night input { + background-color: #000; + color: #fff; +} +.night .card { + color: #c0c0c0; +} +.night .has-text-grey { + color: #c0c0c0 !important; +} +.night .has-link-black-ter { + color: #3273dc !important; +} +.night .has-link-grey.-link { + color: #c0c0c0; +} +.night .has-link-grey, +.night .has-link-black-ter { + color: #c0c0c0 !important; +} +.night .menu-label { + color: #c0c0c0 !important; +} +.night .tag:not(body) { + color: #c0c0c0; +} +.night #body_hot_comment .comment-content .item { + color: #c0c0c0; +} +.night .has-text-black-ter { + color: #c0c0c0 !important; +} +.night .has-text-black-ter:hover { + color: #3273dc !important; +} +.night .navbar-item, +.night .navbar-link { + color: #c0c0c0; +} +.night .title { + color: #c0c0c0; +} +.night .level-item.tag.is-danger { + background-color: #3273dc !important; + color: #c0c0c0; +} +.night .friend-title-item { + color: #c0c0c0; +} +.night .music-container #musiclist { + background: #151313; +} +.night .meplayer-container { + background-color: #151313; +} +.night .navbar { + background-color: #151313; +} +.night .card { + background-color: #151313; +} +.night .footer { + background-color: #151313; +} +.night .button.is-white { + background-color: #151313; +} +.night .cardm { + background-color: #151313; +} +.night .waifu-tips { + background-color: #151313; + color: #c0c0c0; +} +.night .has-link-grey.-link:hover { + color: #3273dc !important; +} +.night .has-link-black-ter:hover { + color: #3273dc !important; +} +.night .timeline .media:last-child:after { + background-color: #151313; +} +.night .level-item.tag.is-danger, +.night .button:not(.is-white), +.night #index_hot_div, +.night #post-calendar canvas, +.night .waifu canvas, +.night .is-current, +.night .button.is-marginless .fab, +.night .fas, +.night .button.is-large, +.night .gt-btn, +.night .gt-comment-body pre, +.night .time-axis-main, +.night .meplayer-control-play, +.night .social-share, +.night .widget .tags .tag:first-child, +.night .g-emoji, +.night .fa-envelope, +.night input, +.night img { + filter: brightness(0.6) !important; +} +.night figure { + filter: brightness(0.7) !important; +} +.night strong { + filter: brightness(0.8) !important; +} +.night .content blockquote { + border-left: 3px solid #1e4584; +} +.night .timeline { + border-left: 1px solid rgba(219,219,219,0.439); +} +.night .timeline .media:before { + background: rgba(219,219,219,0.439); +} +.night .post-copyright { + border-left: 3px solid rgba(255,23,0,0.439); +} +.night .button.is-light { + filter: brightness(1) !important; +} +.night .breadcrumb li.is-active a { + color: #c0c0c0; +} +.night .menu-list li ul { + border-left: 1px solid rgba(219,219,219,0.439); +} +.night .markdown-body blockquote { + border-left: 0.25em solid rgba(223,226,229,0.565); +} +.night .gt-container .gt-comment-content { + background-color: #000 !important; + color: #c0c0c0 !important; +} +.night .gt-container .gt-comment-body { + color: #c0c0c0 !important; +} +.night .gt-container .gt-comment-content:hover { + -webkit-box-shadow: 0 0.625em 3.75em 0 #f4f4f4; + box-shadow: 0 0.625em 3.75em 0 #000; +} +.night textarea { + background-color: #151313; + color: #fff; +} +.night .gt-container .gt-header-textarea:hover { + background-color: #000; +} +.night .gt-container .gt-header-textarea { + background-color: #000; +} +.night .ins-section-container { + background-color: #151313; + color: #c0c0c0; +} +.night .searchbox .searchbox-input-wrapper .searchbox-input { + background-color: #151313; +} +.night .cardm { + color: unset; +} +.night .g-ads-x { + filter: brightness(0.6) !important; +} +.night .g-ads-y { + filter: brightness(0.6) !important; +} +.night .google-auto-placed { + filter: brightness(0.6) !important; +} +.night .pagination-previous, +.night .pagination-next, +.night .pagination-link { + color: #c0c0c0; +} +.night .pagination .pagination-link a, +.night .pagination .pagination-ellipsis a, +.night .pagination .pagination-previous a, +.night .pagination .pagination-next a { + color: #c0c0c0; +} +.night .content .gt-container .gt-comment-header { + background-color: #151313; +} +.night .content .gt-container .gt-comment-admin .gt-comment-content { + border: 2px solid #151313; +} +.night #post-calendar { + background-color: #626161; +} +.night .button.is-white, +.night .button.is-transparent { + color: #c0c0c0; +} +.night hr, +.night .index-category-tag hr { + background-color: #989898; +} +.night .navbar-menu { + background-color: unset; +} +.night #index_hot_div { + color: #c0c0c0; +} +.night #index_hot_div { + filter: unset !important; +} +.night #index_hot_div .item { + filter: brightness(0.6) !important; +} +.night .gt-container .gt-meta { + border-bottom: 2px solid #989898; +} +.night figure.highlight figcaption * { + color: unset; +} +.night figure.highlight figcaption.level .level-right a { + color: #c0c0c0; +} +.night .menu-list .is-current { + color: #3273dc; + background: #7a7a7a; + filter: unset !important; +} +.night .friend-card-item { + color: unset; +} +.night .g-ads-x, +.night .g-ads-y, +.night .google-auto-placed { + filter: brightness(0.6) !important; +} +.night .index-category-tag .button.is-small { + color: #c0c0c0; + filter: unset !important; +} +.night .index-category-tag .article-more:hover { + background-color: unset !important; +} +.night a.navbar-item:focus, +.night .navbar-link:focus, +.night a.navbar-item:focus-within, +.night .navbar-link:focus-within, +.night a.navbar-item:hover, +.night .navbar-link:hover, +.night a.navbar-item.is-active, +.night .navbar-link.is-active { + background-color: unset; + color: #3273dc; +} +.night .menu-list a.is-active { + background-color: #7a7a7a; + color: #3273dc; +} +.night .recommend-area, +.night .article-licensing { + background: #000; +} +.night .article-licensing .licensing-title a { + color: #3273dc !important; +} +.night .content h1, +.night .content h2, +.night .content h3, +.night .content h4, +.night .content h5, +.night .content h6 { + color: #c0c0c0; + font-weight: 800; +} +.night .navbar, +.night footer.footer, +.night .card { + background-color: rgba(21,19,19,0.678); +} +.aplayer-narrow { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} +.aplayer-narrow:hover { + -webkit-transform: translateX(0); + transform: translateX(0); +} +.aplayer { + transition: all 0.5s ease-out; +} +.aplayer .aplayer-miniswitcher { + background: #fff !important; +} +body, +button, +input, +select, +textarea { + font-family: AlimamaFangYuanTi, "PingFang SC", "Microsoft JhengHei", "Microsoft YaHei", sans-serif !important; +} +.img-x { + position: relative; + overflow-y: hidden; + height: 100%; + white-space: nowrap; +} +.img-x a { + box-sizing: border-box; + text-align: center; + position: relative; + display: inline-block; + padding: 10px 10px; + vertical-align: top; + height: 100%; + width: 40%; +} +.img-y { + position: relative; + overflow-y: hidden; + height: 100%; + white-space: nowrap; +} +.img-y a { + box-sizing: border-box; + text-align: center; + position: relative; + display: inline-block; + padding: 10px 10px; + vertical-align: top; + height: 100%; + width: 30%; +} +.article hr { + background-color: #6190e8; + margin-top: -0.8rem; + margin-bottom: 1rem; + box-shadow: 1px 2px 8px #000; +} +.index-category-tag hr { + background-color: #f5f5f5; + margin-top: 0.3rem; + margin-bottom: 0.5rem; + box-shadow: unset; +} +.friend-title-item { + font-weight: bold; + text-align: center; +} +.friend-card-item { + width: 32%; + border-radius: 2px; + color: #4a4a4a; + padding: 0.5rem; + display: inline-block; + margin: 5px; + margin-top: 15px; +} +.friend-card-item .text-desc { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.friend-card-item .ava { + width: 5rem !important; + height: 5rem !important; + margin: 0 !important; + margin-right: 0.2em !important; + border-radius: 40px; +} +.friend-card-item img { + float: left; + transition: all 0.5s ease-in; + -webkit-transition: all 0.5s ease-in; + -moz-transition: all 0.5s ease-in; + -o-transition: all 0.5s ease-in; +} +.friend-card-item img:hover { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); +} +.friend-card-item:hover { + transform: scale(0.995); + box-shadow: 0 2px 6px 0 rgba(0,0,0,0.12), 0 0 6px 0 rgba(0,0,0,0.04); +} +.content blockquote { + background-color: #f5f5f5; + border-left: 3px solid #6190e8; + padding: 1em 1em; + overflow: auto; +} +.time-axis-main { + width: 90%; + margin: 30px auto; +} +.time-axis-main .time-axis { + margin: 0; + padding: 0; + position: relative; +} +.time-axis-main .time-axis:before { + content: ''; + position: absolute; + left: 93px; + top: 15px; + width: 1px; + height: 100%; + background-color: #e4e4e4; +} +.time-axis-main .time-axis-item { + list-style: none; + padding-left: 150px; + position: relative; + line-height: 45px; + font-size: 14px; + color: #141414; +} +.time-axis-main .time-axis-date { + position: absolute; + left: -1.9%; + top: 0; + color: #3273dc; + font-style: italic; + font-weight: bold; +} +.time-axis-main .time-axis-title { + background-color: #f5f5f5; + border-left: 3px solid #6190e8; + padding: 0.8em 1em; + font-weight: bold; + line-height: 25px; +} +.time-axis-main .time-axis-achievement { + background-color: #f5f5f5; + border-left: 3px solid #e89b44; + padding: 0em 1em; + font-style: italic; + margin-bottom: 30px; +} +.time-axis-main .time-axis-date span { + position: absolute; + right: -25px; + top: 35%; + display: block; + width: 13px; + height: 13px; + border: 1px solid #ccc; + border-radius: 100%; + background-color: #fff; +} +.time-axis-main .time-axis-date span:after { + content: ''; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + width: 7px; + height: 7px; + margin: auto; + background-color: #ccc; + border: 1px solid #ccc; + border-radius: 100%; +} +.time-axis-main .time-axis-item:first-child .time-axis-date span { + border-color: #48beb2; +} +.time-axis-main .time-axis-item:first-child .time-axis-date span:after { + background-color: #48beb2; + border-color: #48beb2; +} +.music-container .video-player .fa-video-camera:before { + content: "\f03d"; +} +.music-container .video-player .fa-music:before { + content: "\f001"; +} +.music-container #musicarea { + margin: 20px auto; + width: 500px; +} +.music-container .music-player .d-title { + margin-bottom: 20px; + font-size: 2rem; + font-weight: 700; + text-align: center; +} +.video-player .d-title { + margin-bottom: 20px; + font-size: 2rem; + font-weight: 700; + text-align: center; +} +.video-player .fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.video-player .hits { + text-align: center; + font-size: 13px; + color: #cd0411; +} +.video-player #video-list { + overflow-y: auto; + height: 300px; +} +.video-player #video-list blockquote { + font-size: 13px; + text-align: center; + border-right: 3px solid #6190e8; +} +.text-center { + text-align: center; +} +.markdown-body { + font-family: Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif !important; +} +.markdown-body img { + max-width: 30% !important; +} +#hitokoto { + text-align: center; + cursor: pointer; + padding: 1rem; +} +.text-tips { + text-align: center; + font-size: 0.875em; +} +.social-share { + text-align: center; +} +.level img { + border-radius: 100px; + transition: all 0.5s ease-in; + -webkit-transition: all 0.5s ease-in; + -moz-transition: all 0.5s ease-in; + -o-transition: all 0.5s ease-in; +} +.level figure img:hover { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); +} +.content .gt-container .gt-comment-edit { + margin-right: 2%; +} +.content a img { + margin: auto; + display: block; +} +.content .gt-container .gt-comment-admin .gt-comment-content { + border: 0.01em solid #deeafb; +} +.content .gt-container .gt-comment-header { + font-size: 0.875em; + position: relative; + display: inline-block; + left: -6%; + margin-bottom: 10px; + padding: 0 10% 0 32px; + height: 32px; + line-height: 32px; + border-radius: 0 3px 3px 0; + background-color: #deeafb; +} +.content .gt-container .gt-comment-content:hover { + -webkit-box-shadow: unset; + box-shadow: unset; +} +.content .gt-container .gt-comment-body { + padding-left: 2%; +} +.self-talking .gt-comment-reply .gt-ico-reply { + display: none; +} +.content .gt-container .gt-avatar { + display: none !important; +} +.article .content .markdown-body a img { + margin-right: 1%; + margin-top: 1%; + display: unset; +} +.gt-container .gt-comment-content:hover { + -webkit-box-shadow: unset !important; + box-shadow: unset !important; +} +.toc-scroll { + max-height: 500px; + overflow: auto; +} +.navbar-highlight { + background-color: #fff !important; +} +.gt-container .gt-comment-owner { + padding: 0.2em 0.2em !important; + margin: 0 0.5em 0 0.5em !important; +} +hr { + margin: 0rem 0; +} +.level:not(:last-child) { + margin-bottom: 0.5rem; +} +.post-navigation .level { + margin-bottom: 1rem; +} +.text-right { + text-align: right; +} +.text-left { + text-align: left; +} +.font1_1 { + font-size: 1.1rem; +} +.hljs-comment, +.hljs-quote { + color: #42bb35 !important; +} diff --git a/css/fonts/fontello.eot b/css/fonts/fontello.eot new file mode 100644 index 0000000000000000000000000000000000000000..2d1c6f0672b0fe052e25578e3a6f2c5c82250faa GIT binary patch literal 5456 zcmd^Cdu&@*89(P+l$$rVoMaJ;~;zb!G?S8m*XbzNFQ zm284#*gRWeX*P?$3GbvN4;G^IZ;JtI^`7Has=Uwnq;KjT-mwx{T_1nQ;#`?d@W)_!zm~{UX zTa*5g>_R&Gr!(sFjMeDiFEOrO=U14Wxs;0vEM_khDF2YPbA)L~XV@tvK#%^jSFf=!Oboy|&5Kkw=G)otfahtr|d`5GbE+1%*t>bBMS6sJRd z^3|1@m%ruxx~s}vKk$Ih<#o8H9g`P%?`%BO7G3%1wOf4nNayZjm1Qq_U-%yX#x?g= zN0qZ~TVMSa_qml1W}kWJ+~_~fy>hXG@5}wyF%^uZgByj_>ohqdG(a)VHIo#bG_xS_NYoI z$g64`TA-nMC)U^#=+^Zlt@OSNTN$|e zP4$Ml2Q|2Z^)UA>z45`Ca+?|oR(19(+f}bEtn}1u=NS~;I-IV~9&X4)n$~FG_fdj+S%9++n zmkwXO`VxPg2R_}-1KPp&4(D%kE!&EHvEHG-`ZslTy;^A=9tW*t{i;CG3DqALcx!Y&TJ|;e z3EvHlx`BiBTAjkm48&*=vU(5oOnSDm57yT20#7sO?P6U;tS~2gq=;3>2aDJSe7K11 z$kXFR?121q5xZFs7e!%B536S1p$=s$!wxg-M@7t8C9f!Ag?agoB32;}6|oKYks`J; zAAh`v9gwGr*v(Gz#Ul2wX8xOKCVOFFdU9$>?27Id9c}I1V(fy*Kr}sX&I%Ig(6hNsJC0OJK-PhbrzIl6GA>qrqi_&T@?dtQOJW zVl84yWo$z76!w?)mXLJnf{gS;Q*YbY7*t^9fRQ8>W6(0vr7t@@EET zUr`a2+>FSIASEeMHJj@=S>xPsj=_B4W~mq;w;0Mno9c{;kSN zj{7?j$r<^rj-Xr!`WxV;8l0^<7?QPmo)h)K&qV9=yh?PNp0^QwK+oHWKB(s%ME!c+ zNwi+iyNEud=gWw0*O@F2egQ*vz>w`&K)?{90T@EG0frFOUEpa9&%3{kzaYe8_(Mvs7eRG?>nXH6i+PSgU(|ScD5}NE_CKmXHP&^T5%>O+~1} ze^Y5zA52E5!MV^Xu^)EShEQ6F;>J2bQS)G-lPghUT$5_l97m5)qNX3%NTM(|&oN;V zx~?{4_WCvKFobh~Si4}o`)mS3s1w>y-SE8~iG;qr$r7w+VsevZ1m3ttsD-WXg)HeI z9|-JjZ!Y>k>w{~0EwOZ=dW9I$hG{d3*29*|=m15Jvg3)c=)=WF78iwBY~AIKCU6HZ zw05-?0(Eb48Co$iurVa}7A=UDLSxX~yZMNvQ0~(;5hkwW4U0ai%kE$fIYh~lLpk2FF~Sm-LF_+Zxr-98GfGa4()k1Ac`~th zjfjy;>1;sI;;-McGP0*Gvq_)wY;WUc0gxXmz^N{$!jtARSetGPWyT%@I0V269M+e)C3zgck{ltO2!@^@9RhLEA#jv*2#k|N8IB*xO7vJh!cTZmL=boua_>KS4z)maOX>YRm0 zbzYZy*HkmaSgKhIk?J!RBGm=`W|>VXeHlf9(v_BKWBfc_H6ezN?Dt0S0m5HGQ!ac~ zXY + + +Copyright (C) 2016 by original authors @ fontello.com + + + + + + + + + + + + \ No newline at end of file diff --git a/css/fonts/fontello.ttf b/css/fonts/fontello.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b85b74ee78519960a2d8b8d7f18c182f9d5db4c5 GIT binary patch literal 5288 zcmd^CYiwLc6`r|wU*3(^c5JWHuA9vI+D_uVyLKGEnmDez>$MXnO&#aay(x9>^?Ln^ zA6t79@<7m5R79(`1SqYDL|P&tK_tqoLzT8dP$7O4Q6$7qB&tdj5u^%!Ar(|?zH@ii ziIbE{{mXUsp6{IbX6DS9GiPoXXN>vTGfZXX<40TD`-XPNe3o%knO1!B&Aytd3OrYxm`k3mmD_s?7BGVFW4 zcc4#07Yo*W`u*?MZ-ssd`c&5iEPE=OHJal6zfUR|Ai`J4V{JyqWN{s#gczso!0n!3Py z=0+lI@zsxByUB+RckDb`S@xp;h41pOU-fQwRk`c7^ww|ko?ZQ5?&*ilj{W28D;L`N z-rP^Vw)*L8fHniWxOQEwQmdH{{;`@lu&FfubxzWtb%Q0o;QQlK2?c?c~y-|3pF%v#~8aq?E&Xqx@y!^uKu~A zh6nuop^Ct&Z-c7*_0zxm0|CFfncjC`I|J9gpKng!<12@h{m)$g z)%E8Fm&dOC^4i$gwNv|_8|&ds4ef%zRMoJn>NW0iaLyIZ$4=crcO1U3@{~y((5q+c zxuFlYG$_r1_g<_*$EvG}i@P08r=9RPHEZ+gE%kAnOFs+1=RmdJ>rmlyXVq?A#hbc1 zws!~WYTR{Ql>n9QkNNoORsQ;c14A>)>DG%E4_&$P5`UeCKHbVg+VJ~_hG$>?R=V}e z+`Kq^W%baN!XDB-zWVOZr{%)*;V!l-wBPXfs6InRl?2;?9no8^**YZ^lWAy ztdHLboqEvQ!#aytVQ#jsh*j7Jir4{ssED1&(_=;Kg8ftxds&!G6|s+1vu{&{a+G0) zS@y#s=B$!e6tTkmd|MH#ut$p60lcq>oh-l~D`FSysUr5W6MVUdeXN=PCccr8ffacNofi^;`>YTe-hSCe^B`cerpwXAlPPJ#VlVWmdab64-#}%2S#o2T!8=cN(GkaQF zOFd~m7H5kr!_KoMHiJ-2vn&%R-f^}QvYoZDU91ae91HCgcv7ikgsZ)ZRwScSn)}PUI{hy(38z7C~)ZLS2Nq%%Eu)Mo{vwVQ7+#B-4fw zk*Y2dLOPl(IOL3vB&Ab}NtYIb`-bFZL^^a0eu;^^b37)fr7$_YB{LH#skVe*kBgkh zVeEXHvkA*Ok~Bwx)~J!x47BziO`<7Ciz?0>kxpH@f0=ArXi`3T{h(+!Q%e zNI!xWk(K(vW68W@V!&vW(WVNuii)`8R!mle zDM^vKvHT`_mE$FO06U>JjU@Awxd>J)hwY_lTS6MTm2j}oPF;}u)M{WQL-2pd#3pXo zs?XTKJY&@wLX2$cTfyyaXG68l@=Qq_OUeo@CKA$zr1WCn%$P7S{hO7Q9QSuDmNWC4 zU17Nt4mKc6HCS79I3jEHJSQ1IoJrQ{d6ncAJ?|j-fSz}fd{EE3NCx%1n`FJ7_mF%@ z&zF(hsxw(0{sN9{gCkopfPf<;LvVy-0~{f#!4Z;;aD-$N93j~ZM@VjmBP4gg5t2J~ z(QD^ z15$61ytd7ba`euqY;0=PMW^j&8#p|1?{P&HxUXAeXMvyD^>(07>&dtBTC8Lj)(uDR z+r>oIT0Ifju1D*7BXalWQITOO&^xddEYKvPVu(&ALU69LDOp-7KPoF{A@yf+eI$hq?bq@`fT*5xk)^s}CA6 zDsUc@O3a5DwLu&$?Bd3AfCDfsv( ziUkVvdZw1v`}wIjbic&-BH2fAqq@?o^#ntA?03j0`WT~Nl!6+k^@k|(q{QM zl4}cx6IVITVRcmQ!dXmwhJ6sVme*9vc5sGt*#WViqLx5h#USpiQk)Lxl#X&g!aA(4 zF!m_GK>$wRkiNog%VPkxI0VLs^9aBx;t(*2L%<>qfpJ}SuZKBBirfqH zgpGQE(sn+G5Q>57JX&VuH#zsV))#bzM)YGKc)Hxdwb>2oqUC`y8b?PE1 zHZ@}-qCRaSqAuw-${b4R%P1C>p0rdON6yhz6Jhwses2^XAp9j1<-%umCeNHPd@!^W zq-TSC8@ET9Z7Cv^4dfg7r6c%Qyp+tV69f5X(%$hrga3>6UrOPN2^4%28+o>=j&1F4f-yCFn(wStMc~2gR$_V9H1Wv`rrcYuPhU94v7*Le8O7Jwz_xbOPqjpW1f>X^ ztZ6o@Fg>sp3;%fZ4J_6v9Lo*Wfg-(WHo4k@IibwxerORlcQzN7UG?4};_^lWjh2Co z#wdhFh_@q-9&k~C)`C_1&j`$~v~=}l*F_eL;(8S>Mj+S}h*n)bcl|B1dl`^jU-da> zQJWcGHIi)&{MQpr_MrQ@cBCsLue}$q`A$w?MJ=wJ*55DQUNhWYy>EAKFpXk&Ev0BW zSgg2S!PW7L-lg*d>*P7j$w|1Fx#59yT!c&A2zgCWSdfiab}L#WVq%;6PIz83Mb^4r zq}lDV=dxbFBoAVx^7q#8pjq+eawQcv4U*|cTXNNEaE9iun&tUrB`=nEcY z5{Xz6PV36UF{ONVp1*6!UD@T2(k2;Y@@gk&$*IN(rqo*77uuXv$Lv1fzHGNE|0p<$ zpTrTAJ`B70#y@vvTSRU79se@FVD5{X^Gckf~I#RUZ2hY1^gA)*wa zyn8E!U(M`>U1t5Yi$(hxGJCG3UfX5FZz0~eeG2Z$Qso&E}TCr^AND#%o23L+Ma6ePwpl#c`T+{vqM2 z`kGuy&tq4DoP#jQ^g*<*t9Tq*;XQAo`=lVD54K;<{i3vOPU2}|9oFt{tk>06UA48czKsyfdSZSS#_Y}Ws{^kkWvqYT|h0kI>D;e`C&s=T~QyOWLEy99)Z3@{D_?Bxs<{K^VbIXdZR@`>< z;kYd{cyC^7{1ivZv*pdkGTrgR!~_<1VkqPZ60U8P$xO~k-7qT|Hf6S1K+5sTA;y0- z;rjRt_2Q3|u+0P33HV5ZjN`Wur|)6O?->eyyBI<;2rcZgfA&Q%>C+DDmRA_a>rv!XJYla>E`tcVw7mh$T-GAz^Jp~ zX}E#VLX6u6&ZcroN7nd3Rp|tCZ*2mCUw1k{KN*kSy~J9stE*PotWhx1xZiWyb4F#K zAwu2N{$PuoGxs1ppe_w>=>ai+$&+C|p4-t`&hnxE@p@4Aq^QrB{0Bdi>7V3ci@=buWsMmQN3CQdpv)sxuBH) z@qj(kCPFbx_ZQvLm$QbAG3j4|ve*kfr#mKPZ98o%3g>28E9w@VmU+B2hncfuE38j8 z^)LsQK$S1Nn@;|T+^AWHeFw1Yt@a!7>(*UA#KOM^ccJ)aeHUe1WMkVneYps7&dk_Y zB_{uz4s41N6B+wfxizZ~hm?&~r=XxF+3bKSo+Yv>yJOaUQD!GbX`6-&@@yq0wndqV zaXaxAs}War$jRvfv)UE4ArjSKTaJ`aC{} zBhAA`{hTlDC!L7-{Yu?%zXM%-arjJ^Pfptn9kM|*q(@qz@W(dg4}CiirXGAxX$}to zL}0#c>VP}D8M1rk^~>9Np1DSLwdBfrqyAHq=(F*s@{BNy5!m<0^4T{2+4?xaq+e)_ zD6Ku#W9kI$QkYVaNOw3L$FfnIIpTm>uyjfNXBqN5dAiJ(i!9d{u-Jj-I^e6Pp7DW- zAVbbUQjJAiR9)xnxf2w|h0x|X_66PALatp45mL*j-t_#?#j$a|rvc4|Im)$pK^A3_ zL%l|)r3wxC6<0#-W+HlC*L}O1q9z?7QOvh%4S$jp+KV%goS;mUyf z6r%o?l^^zi`*X+z?k(1QW13+XNw;jh8X^Avn*(9zl*;Kon9wjcz=mnoe;X_WiwoM;EBtI`IxQiHcMl6rSDDBu}>mo`<%zwlcLxU{H({ z34vfh&It1HU!!mda02cFJ2YY-rvU*46amQJGg@#)0>0pkf`fg|QJ!0=y~gdB<1vS% zL|8nJ(X_Gz zY)s#Jjx3O>W`a_J=b!D_Jyx=0B|WHiT{`WCWR_`X-h%A@s|6Sz^4haGD1QYy;mcjl zofnecBGOWYvl`P!R%_|BpiF}Xj;hSwpZ6DFrv&S4I-7TRN=Geq)m`={a8SF}{p@4xpWAb*@|WWYO8w0|yYW@F^8@~) z!$yM&PSRhjr4|OAs2P^<898H@zOpHoy$cA)>5A%T9ZES2hcFfD8o>RFw|$mjr}EJ>Jygd?!t2Xjwl2I5tU8M zX~RE;Ip|_3(Aea-q&_ie-cihJTNE?XT}hUcZv