From 97798845b554cc6f17b344e5dcde2b8c96f33fe6 Mon Sep 17 00:00:00 2001 From: smartliby Date: Wed, 24 Apr 2019 23:32:15 +0800 Subject: [PATCH 01/23] init --- .gitignore | 8 + _config.yml | 87 + package-lock.json | 4429 +++++++++++++++++ package.json | 22 + scaffolds/draft.md | 4 + scaffolds/page.md | 4 + scaffolds/post.md | 5 + ...33\345\273\272\346\250\241\345\274\217.md" | 223 + ...33\345\273\272\346\250\241\345\274\217.md" | 249 + ...33\345\273\272\346\250\241\345\274\217.md" | 226 + ...33\345\273\272\346\250\241\345\274\217.md" | 104 + ...33\345\273\272\346\250\241\345\274\217.md" | 71 + ...33\345\273\272\346\250\241\345\274\217.md" | 297 ++ ...33\345\273\272\346\250\241\345\274\217.md" | 117 + ...23\346\236\204\346\250\241\345\274\217.md" | 117 + ...23\346\236\204\346\250\241\345\274\217.md" | 383 ++ ...23\346\236\204\346\250\241\345\274\217.md" | 231 + ...23\346\236\204\346\250\241\345\274\217.md" | 143 + ...23\346\236\204\346\250\241\345\274\217.md" | 376 ++ ...23\346\236\204\346\250\241\345\274\217.md" | 303 ++ ...23\346\236\204\346\250\241\345\274\217.md" | 245 + ...14\344\270\272\346\250\241\345\274\217.md" | 252 + ...14\344\270\272\346\250\241\345\274\217.md" | 169 + ...14\344\270\272\346\250\241\345\274\217.md" | 193 + ...14\344\270\272\346\250\241\345\274\217.md" | 190 + ...14\344\270\272\346\250\241\345\274\217.md" | 266 + ...20\347\240\201\350\260\203\350\257\225.md" | 87 + ...57\345\242\203\350\256\276\347\275\256.md" | 353 ++ ...26\347\240\201\346\265\205\346\236\220.md" | 78 + source/about/index.md | 14 + source/categories/index.md | 5 + source/tags/index.md | 5 + 32 files changed, 9256 insertions(+) create mode 100644 .gitignore create mode 100644 _config.yml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scaffolds/draft.md create mode 100644 scaffolds/page.md create mode 100644 scaffolds/post.md create mode 100644 "source/_posts/2014-05-14-\350\256\276\350\256\241\346\250\241\345\274\21701\344\271\213-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-15-\350\256\276\350\256\241\346\250\241\345\274\21702\344\271\213-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-16-\350\256\276\350\256\241\346\250\241\345\274\21703\344\271\213-\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-17-\350\256\276\350\256\241\346\250\241\345\274\21704\344\271\213-\345\215\225\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-18-\350\256\276\350\256\241\346\250\241\345\274\21705\344\271\213-\345\244\232\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-19-\350\256\276\350\256\241\346\250\241\345\274\21706\344\271\213-\345\273\272\351\200\240\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-20-\350\256\276\350\256\241\346\250\241\345\274\21707\344\271\213-\345\216\237\345\236\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-21-\350\256\276\350\256\241\346\250\241\345\274\21708\344\271\213-\351\200\202\351\205\215\345\231\250-Adapter-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-22-\350\256\276\350\256\241\346\250\241\345\274\21709\344\271\213-\345\220\210\346\210\220-Composite-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-23-\350\256\276\350\256\241\346\250\241\345\274\21710\344\271\213-\350\243\205\351\245\260-Decorator-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-24-\350\256\276\350\256\241\346\250\241\345\274\21711\344\271\213-\344\273\243\347\220\206-Proxy-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-25-\350\256\276\350\256\241\346\250\241\345\274\21712\344\271\213-\344\272\253\345\205\203-Flyweight-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-26-\350\256\276\350\256\241\346\250\241\345\274\21713\344\271\213-\351\227\250\351\235\242-Facade-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-27-\350\256\276\350\256\241\346\250\241\345\274\21714\344\271\213-\346\241\245\346\242\201-Bridge-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-28-\350\256\276\350\256\241\346\250\241\345\274\21715\344\271\213-\344\270\215\345\217\230-Immutable-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-05-29-\350\256\276\350\256\241\346\250\241\345\274\21716\344\271\213-\347\255\226\347\225\245-Strategy-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-06-01-\350\256\276\350\256\241\346\250\241\345\274\21717\344\271\213-\346\250\241\346\235\277\346\226\271\346\263\225-Template-Method-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-06-02-\350\256\276\350\256\241\346\250\241\345\274\21718\344\271\213-\350\247\202\345\257\237\350\200\205-Observer-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2014-06-03-\350\256\276\350\256\241\346\250\241\345\274\21719\344\271\213-\350\277\255\344\273\243\345\231\250-Iterator-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" create mode 100644 "source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" create mode 100644 "source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" create mode 100644 "source/_posts/2017-05-14-java\345\255\227\347\254\246\347\274\226\347\240\201\346\265\205\346\236\220.md" create mode 100644 source/about/index.md create mode 100644 source/categories/index.md create mode 100644 source/tags/index.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b60666 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +Thumbs.db +db.json +*.log +node_modules/ +public/ +.deploy*/ +themes/ diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..d9c6910 --- /dev/null +++ b/_config.yml @@ -0,0 +1,87 @@ +# Hexo Configuration +## Docs: https://hexo.io/docs/configuration.html +## Source: https://github.com/hexojs/hexo/ + +# Site +title: 以梦为马 +subtitle: +description: +author: James Lee +language: zh-Hans +timezone: Asia/Shanghai + +# URL +## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/' +url: https://smartliby.github.io +root: / +permalink: :year/:month/:day/:title/ +permalink_defaults: + +# Directory +source_dir: source +public_dir: public +tag_dir: tags +archive_dir: archives +category_dir: categories +code_dir: downloads/code +i18n_dir: :lang +skip_render: + +# Writing +new_post_name: :year-:month-:day-:title.md # File name of new posts +default_layout: post +titlecase: false # Transform title into titlecase +external_link: true # Open external links in new tab +filename_case: 0 +render_drafts: false +post_asset_folder: false +relative_link: false +future: true +highlight: + enable: true + line_number: true + auto_detect: false + tab_replace: + +# Category & Tag +default_category: uncategorized +category_map: +tag_map: + +# Date / Time format +## Hexo uses Moment.js to parse and display date +## You can customize the date format as defined in +## http://momentjs.com/docs/#/displaying/format/ +date_format: YYYY-MM-DD +time_format: HH:mm:ss + +# Pagination +## Set per_page to 0 to disable pagination +per_page: 10 +pagination_dir: page + +search: + path: search.xml + field: post + format: html + limit: 10000 + +#algolia: +# applicationID: 'KDAZDTO6SY' +# apiKey: '5753ff70853ef31dc50924d0ab849484' +# adminApiKey: 'c1ffc3f2eabc40a4cf07ac0575e32dea' +# indexName: 'smartliby' +# chunkSize: 5000 + + +# Extensions +## Plugins: https://hexo.io/plugins/ +## Themes: https://hexo.io/themes/ +theme: next + +# Deployment +## Docs: https://hexo.io/docs/deployment.html +deploy: + type: git + repository: git@github.com:smartliby/smartliby.github.io.git + branch: master diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..069cd8a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4429 @@ +{ + "name": "hexo-site", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.0.0.tgz", + "integrity": "sha1-BuKrGb21NThVWaq7W6WXKUgoAPg=", + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/generator": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.4.0.tgz", + "integrity": "sha1-wjDnlYmuenKf1GMbne1NwiBBgZY=", + "requires": { + "@babel/types": "^7.4.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.1.0.tgz", + "integrity": "sha1-oM6wFoX3M1XUNgwSR/WCv6/I/1M=", + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha1-g1ctQyDipGVyY3NBE8QoaLZOScM=", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.4.0.tgz", + "integrity": "sha1-Vxv9UnAfSSkg1jt/c1Aw6aPhC1U=", + "requires": { + "@babel/types": "^7.4.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.0.0.tgz", + "integrity": "sha1-9xDDjI1Fjm3ZogGvtjf8t4HOmeQ=", + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.4.3", + "resolved": "http://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.4.3.tgz", + "integrity": "sha1-6zrID2SqEByQfUzlQGNg/nW3iVs=" + }, + "@babel/template": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/template/download/@babel/template-7.4.0.tgz", + "integrity": "sha1-EkdOnAd7rlhcXYNalcCwt5DCXIs=", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0" + } + }, + "@babel/traverse": { + "version": "7.4.3", + "resolved": "http://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.4.3.tgz", + "integrity": "sha1-GgHwePxXXVif8wwPcb88PZzLrYQ=", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/types": "^7.4.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", + "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz", + "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" + } + } + }, + "@babel/types": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/types/download/@babel/types-7.4.0.tgz", + "integrity": "sha1-Zwck930kzObMfYz2RZnVEdFkiUw=", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha1-MgjB8I06TZkmGrZPkjArwV4RHKA=", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "a-sync-waterfall": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", + "integrity": "sha1-dba2qnJZi0l6El56J3DxT0yKH6c=" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=" + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=", + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=" + }, + "babel-eslint": { + "version": "10.0.1", + "resolved": "http://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.0.1.tgz", + "integrity": "sha1-kZaB3AmWFM19MdRciQhpUJKh+u0=", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=" + } + } + }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha1-uZgnm/R844NEtPPPkW1Gebv1Hjo=", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=" + }, + "bluebird": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", + "integrity": "sha1-1sxmFZXeMNWzr1/O3TwLPvbsVxQ=" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "browser-fingerprint": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/browser-fingerprint/-/browser-fingerprint-0.0.1.tgz", + "integrity": "sha1-jfPNyiW/fVs1QtYVRdcwBT/OYEo=" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "command-exists": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz", + "integrity": "sha1-cVrO/dEiO5ybNxEKFJxjksKFIpE=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=" + }, + "compressible": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz", + "integrity": "sha1-pJv5hY84IbZM4b4Clq/HOARmp38=", + "requires": { + "mime-db": ">= 1.38.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48=", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "css-parse": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", + "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=" + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha1-ptdgRXM2X+dGhsPzEcVlE9iChfI=" + }, + "cuid": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/cuid/-/cuid-1.3.8.tgz", + "integrity": "sha1-S4deCWm612T37AcGz0T1+wgx9rc=", + "requires": { + "browser-fingerprint": "0.0.1", + "core-js": "^1.1.1", + "node-fingerprint": "0.0.2" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=" + } + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha1-HsQFnihLq+027sKUHUqXChic58A=", + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=" + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", + "integrity": "sha1-SY7A1JVlWrxvI81hho2SZGQHGqA=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=" + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "http://registry.npm.taobao.org/esrecurse/download/esrecurse-4.2.1.tgz", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "http://registry.npm.taobao.org/estraverse/download/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "http://registry.npm.taobao.org/esutils/download/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "^2.1.0" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "^1.0.1" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.8", + "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.8.tgz", + "integrity": "sha1-V+pTIPdizUaW5ejocSDszIsRys8=", + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "optional": true + } + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "^2.0.0" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "http://registry.npm.taobao.org/globals/download/globals-11.11.0.tgz", + "integrity": "sha1-3Pk3V/ot5Uhvvu1xGFOK33ienC4=" + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha1-/7cD4QZuig7qpMi4C6klPu77+wA=" + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hexo": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/hexo/-/hexo-3.8.0.tgz", + "integrity": "sha1-TQXM5Vje1cFN+hUWu645cXR/l0c=", + "requires": { + "abbrev": "^1.0.7", + "archy": "^1.0.0", + "bluebird": "^3.4.0", + "chalk": "^2.3.1", + "cheerio": "0.22.0", + "hexo-cli": "^1.1.0", + "hexo-front-matter": "^0.2.2", + "hexo-fs": "^0.2.0", + "hexo-i18n": "^0.2.1", + "hexo-log": "^0.2.0", + "hexo-util": "^0.6.3", + "js-yaml": "^3.6.1", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", + "moment": "^2.19.4", + "moment-timezone": "^0.5.14", + "nunjucks": "^3.1.2", + "pretty-hrtime": "^1.0.2", + "resolve": "^1.5.0", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0", + "swig-extras": "0.0.1", + "swig-templates": "^2.0.2", + "text-table": "^0.2.0", + "tildify": "^1.2.0", + "titlecase": "^1.1.2", + "warehouse": "^2.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "hexo-cli": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-1.1.0.tgz", + "integrity": "sha1-SW0jjUZG2/0c8Ee23FJxv7XLeY8=", + "requires": { + "abbrev": "^1.0.7", + "bluebird": "^3.4.0", + "chalk": "^1.1.3", + "command-exists": "^1.2.0", + "hexo-fs": "^0.2.0", + "hexo-log": "^0.2.0", + "hexo-util": "^0.6.0", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "resolve": "^1.5.0", + "tildify": "^1.2.0" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "hexo-bunyan": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexo-bunyan/-/hexo-bunyan-1.0.0.tgz", + "integrity": "sha1-shBrJlR7Iy8BlduGPLXV/4Un/TY=", + "requires": { + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "hexo-deployer-git": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/hexo-deployer-git/download/hexo-deployer-git-1.0.0.tgz", + "integrity": "sha1-Bs3gzuKx1a9eBLWaqlFhMLvQPRY=", + "requires": { + "babel-eslint": "^10.0.1", + "bluebird": "^3.5.0", + "chalk": "^2.4.1", + "hexo-fs": "^1.0.0", + "hexo-util": "^0.6.0", + "moment": "^2.18.0", + "swig-templates": "^2.0.2" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", + "integrity": "sha1-CuhDTZYigaX1bHKGnnnLbZ2GrU0=", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=" + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "hexo-fs": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/hexo-fs/download/hexo-fs-1.0.2.tgz", + "integrity": "sha1-XqvjRKeato4vppN8xdRoEpMIZZ8=", + "requires": { + "bluebird": "^3.5.1", + "chokidar": "^2.0.4", + "escape-string-regexp": "^1.0.5", + "graceful-fs": "^4.1.11" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=" + } + } + }, + "hexo-front-matter": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hexo-front-matter/-/hexo-front-matter-0.2.3.tgz", + "integrity": "sha1-x8qO9CDqNr2F6ECKLoyb9J76YF4=", + "requires": { + "js-yaml": "^3.6.1" + } + }, + "hexo-fs": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-0.2.3.tgz", + "integrity": "sha1-w6gbRuRX36/FbYfHjvEUEE9KPkE=", + "requires": { + "bluebird": "^3.4.0", + "chokidar": "^1.5.2", + "escape-string-regexp": "^1.0.5", + "graceful-fs": "^4.1.4" + } + }, + "hexo-generator-archive": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/hexo-generator-archive/-/hexo-generator-archive-0.1.5.tgz", + "integrity": "sha1-qXkhTN3e4mk+BVGAnClL7a27abM=", + "requires": { + "hexo-pagination": "0.0.2", + "object-assign": "^2.0.0" + }, + "dependencies": { + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=" + } + } + }, + "hexo-generator-category": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/hexo-generator-category/-/hexo-generator-category-0.1.3.tgz", + "integrity": "sha1-uealhiUwqDvdfaTIGcG58+TMtLI=", + "requires": { + "hexo-pagination": "0.0.2", + "object-assign": "^2.0.0" + }, + "dependencies": { + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=" + } + } + }, + "hexo-generator-index": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/hexo-generator-index/-/hexo-generator-index-0.2.1.tgz", + "integrity": "sha1-kEIin8rHmq9wBXXaGTMr8/fuXF0=", + "requires": { + "hexo-pagination": "0.0.2", + "object-assign": "^4.0.1" + } + }, + "hexo-generator-search": { + "version": "2.4.0", + "resolved": "https://registry.npm.taobao.org/hexo-generator-search/download/hexo-generator-search-2.4.0.tgz", + "integrity": "sha1-9au7u+NSmfUsJVS7iYRdCk+rbJs=", + "requires": { + "nunjucks": "^3.0.1", + "utils-merge": "^1.0.0" + } + }, + "hexo-generator-searchdb": { + "version": "1.0.8", + "resolved": "https://registry.npm.taobao.org/hexo-generator-searchdb/download/hexo-generator-searchdb-1.0.8.tgz", + "integrity": "sha1-BCRSVuFBOmYxOTLb8cCn5WhVkwE=", + "requires": { + "ejs": "^1.0.0", + "striptags": "^3.1.1", + "utils-merge": "^1.0.0" + }, + "dependencies": { + "ejs": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/ejs/download/ejs-1.0.0.tgz", + "integrity": "sha1-ycYKSKRu5FL7MqccMXuV5aofyz0=" + }, + "striptags": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/striptags/download/striptags-3.1.1.tgz", + "integrity": "sha1-yMPn/db7S7OjKjt1LltePjgJPr0=" + } + } + }, + "hexo-generator-tag": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/hexo-generator-tag/-/hexo-generator-tag-0.2.0.tgz", + "integrity": "sha1-xXFYRrtB5X2cIMHWbX2yGhq/emI=", + "requires": { + "hexo-pagination": "0.0.2", + "object-assign": "^4.0.1" + } + }, + "hexo-i18n": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/hexo-i18n/-/hexo-i18n-0.2.1.tgz", + "integrity": "sha1-hPFBQyvwnYtVjth4xygWS20c1t4=", + "requires": { + "sprintf-js": "^1.0.2" + } + }, + "hexo-log": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/hexo-log/-/hexo-log-0.2.0.tgz", + "integrity": "sha1-0w/UXhoSqDyIAzWGZASF78XfWm8=", + "requires": { + "chalk": "^1.1.1", + "hexo-bunyan": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "hexo-pagination": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/hexo-pagination/-/hexo-pagination-0.0.2.tgz", + "integrity": "sha1-jPRwx9sN5bGKOSanbesZQBXffys=", + "requires": { + "utils-merge": "^1.0.0" + } + }, + "hexo-renderer-ejs": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/hexo-renderer-ejs/-/hexo-renderer-ejs-0.3.1.tgz", + "integrity": "sha1-wMGjdXUy1H5bfZ3JCLXf2YyUviw=", + "requires": { + "ejs": "^2.3.4", + "object-assign": "^4.0.1" + } + }, + "hexo-renderer-marked": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/hexo-renderer-marked/-/hexo-renderer-marked-0.3.2.tgz", + "integrity": "sha1-1qN6+f8ZXjD5727eGgbqH+QyKWY=", + "requires": { + "hexo-util": "^0.6.2", + "marked": "^0.3.9", + "object-assign": "^4.1.1", + "strip-indent": "^2.0.0" + } + }, + "hexo-renderer-stylus": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/hexo-renderer-stylus/-/hexo-renderer-stylus-0.3.3.tgz", + "integrity": "sha1-xU6ifh/Y48ipp6hM+6itNUEiyn8=", + "requires": { + "nib": "^1.1.2", + "stylus": "^0.54.5" + } + }, + "hexo-server": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/hexo-server/-/hexo-server-0.3.3.tgz", + "integrity": "sha1-uGcSl0kgv8wwV9672zXdG+bDAIA=", + "requires": { + "bluebird": "^3.5.1", + "chalk": "^1.1.3", + "compression": "^1.7.3", + "connect": "^3.6.6", + "mime": "^1.6.0", + "morgan": "^1.9.0", + "object-assign": "^4.1.1", + "opn": "^5.3.0", + "serve-static": "^1.13.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "hexo-util": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-0.6.3.tgz", + "integrity": "sha1-FqKt5Fe++VWvDf0io/5vCkmpE3w=", + "requires": { + "bluebird": "^3.4.0", + "camel-case": "^3.0.0", + "cross-spawn": "^4.0.0", + "highlight.js": "^9.4.0", + "html-entities": "^1.2.0", + "striptags": "^2.1.1" + } + }, + "highlight.js": { + "version": "9.15.6", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", + "integrity": "sha1-ctTY13nsBmr5oXyxQ2DD3vCqV8Q=" + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=" + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha1-vWedw/WYl7ajS7EHSchVu1OpOS8=", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "dependencies": { + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=" + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=" + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc=", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "http://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz", + "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=" + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha1-s56mIp72B+zYniyN8SU2iRysm40=" + }, + "lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" + }, + "lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" + }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" + }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha1-rcJdnLmbk5HFliTzefu6YNcRHVQ=" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, + "lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" + }, + "lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/markdown/-/markdown-0.5.0.tgz", + "integrity": "sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=", + "requires": { + "nopt": "~2.1.1" + } + }, + "marked": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "integrity": "sha1-XUf3CcTJ/Dwha21GEnKA9As515A=" + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha1-XdaUPJOFSCZwFtTjTwV1gwgMUUw=" + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha1-plBX6ZjbCQ9zKmj2wnbTh9QSbDI=" + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha1-tvjQs+lR77d97eyhlM/20W9nb4E=", + "requires": { + "mime-db": "1.40.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s=" + }, + "moment-timezone": { + "version": "0.5.25", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.25.tgz", + "integrity": "sha1-oRv6L3TgiDJ/LNTAiz5731WVeBA=", + "requires": { + "moment": ">= 2.9.0" + } + }, + "morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha1-Co0Wc0odmvvIJLmd+H5zjlji2lk=", + "requires": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + } + }, + "nan": { + "version": "2.13.2", + "resolved": "https://registry.npm.taobao.org/nan/download/nan-2.13.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnan%2Fdownload%2Fnan-2.13.2.tgz", + "integrity": "sha1-9R3Hrma6fV1V4ebU2AkugCya7+c=", + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=" + } + } + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "nib": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/nib/-/nib-1.1.2.tgz", + "integrity": "sha1-amnt5AgblcDe+L4CSkyK4MLLtsc=", + "requires": { + "stylus": "0.54.5" + } + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fingerprint": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/node-fingerprint/-/node-fingerprint-0.0.2.tgz", + "integrity": "sha1-Mcur63GmeufdWn3AQuUcPHWGhQE=" + }, + "nopt": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz", + "integrity": "sha1-bMzZd7gBMqB3MdbozljCyDA8+a8=", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", + "requires": { + "boolbase": "~1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "nunjucks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.0.tgz", + "integrity": "sha1-U+lfQ8lVXoIuiVAAiiAbEALUmTM=", + "requires": { + "a-sync-waterfall": "^1.0.0", + "asap": "^2.0.3", + "chokidar": "^2.0.0", + "yargs": "^3.32.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", + "integrity": "sha1-CuhDTZYigaX1bHKGnnnLbZ2GrU0=", + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "optional": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "optional": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "optional": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "optional": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", + "optional": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "optional": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "optional": true + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w=", + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + } + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha1-t3bvxZN1mE42xTey9RofCv8Noe0=", + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=" + } + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "readable-stream": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "integrity": "sha1-y4ARqtAC63F78EApH+uoVpyYb7k=", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=" + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha1-O9qur0XMB/N1ZW39LlTtCBCxAbo=", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=" + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "^6.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha1-NW5EvJjx+TzkXfFLzXwBzahuCv0=", + "optional": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha1-bsyh4PjBVtFBWXVZhI32RzCmu8E=", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=" + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=" + } + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha1-CV6Ecv1bRiN9tQzkhqQ/S4bGzsE=", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=" + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "requires": { + "kind-of": "^3.2.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha1-cuLMNAlVQ+Q7LGKyxMENSpBU8lk=", + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha1-/obnOLGVRK/nBGkkOyoe6SQOro0=", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + } + } + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=" + }, + "striptags": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/striptags/-/striptags-2.2.1.tgz", + "integrity": "sha1-TEULcI1BuL85zyTEn/I0/Gqr/TI=" + }, + "stylus": { + "version": "0.54.5", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", + "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", + "requires": { + "css-parse": "1.7.x", + "debug": "*", + "glob": "7.0.x", + "mkdirp": "0.5.x", + "sax": "0.5.x", + "source-map": "0.1.x" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "requires": { + "has-flag": "^3.0.0" + } + }, + "swig-extras": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/swig-extras/-/swig-extras-0.0.1.tgz", + "integrity": "sha1-tQP+3jcqucJMasaMr2VrzvGHIyg=", + "requires": { + "markdown": "~0.5.0" + } + }, + "swig-templates": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/swig-templates/-/swig-templates-2.0.3.tgz", + "integrity": "sha1-a0xDtGIXXfKo2oV6IEM3nsbqb9A=", + "requires": { + "optimist": "~0.6", + "uglify-js": "2.6.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "requires": { + "os-homedir": "^1.0.0" + } + }, + "titlecase": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/titlecase/-/titlecase-1.1.3.tgz", + "integrity": "sha1-/G1l/1grBgJBB2jvGgm3BQYxPcM=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + } + } + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/trim-right/download/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "uglify-js": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.0.tgz", + "integrity": "sha1-JeqhzDVQ45QQzu+v0c+7a20V8AE=", + "requires": { + "async": "~0.2.6", + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=" + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha1-PbZYYA7a7sy+bbXmhNZ+6MKs0Gg=" + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "warehouse": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/warehouse/-/warehouse-2.2.0.tgz", + "integrity": "sha1-XQnWSUKZK+Zn2PfIagnCuK6gQGI=", + "requires": { + "JSONStream": "^1.0.7", + "bluebird": "^3.2.2", + "cuid": "~1.3.8", + "graceful-fs": "^4.1.3", + "is-plain-object": "^2.0.1", + "lodash": "^4.2.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "requires": { + "isexe": "^2.0.0" + } + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0af2dd8 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "hexo-site", + "version": "0.0.0", + "private": true, + "hexo": { + "version": "3.8.0" + }, + "dependencies": { + "hexo": "^3.8.0", + "hexo-deployer-git": "^1.0.0", + "hexo-generator-archive": "^0.1.5", + "hexo-generator-category": "^0.1.3", + "hexo-generator-index": "^0.2.1", + "hexo-generator-search": "^2.4.0", + "hexo-generator-searchdb": "^1.0.8", + "hexo-generator-tag": "^0.2.0", + "hexo-renderer-ejs": "^0.3.1", + "hexo-renderer-marked": "^0.3.2", + "hexo-renderer-stylus": "^0.3.3", + "hexo-server": "^0.3.3" + } +} diff --git a/scaffolds/draft.md b/scaffolds/draft.md new file mode 100644 index 0000000..498e95b --- /dev/null +++ b/scaffolds/draft.md @@ -0,0 +1,4 @@ +--- +title: {{ title }} +tags: +--- diff --git a/scaffolds/page.md b/scaffolds/page.md new file mode 100644 index 0000000..f01ba3c --- /dev/null +++ b/scaffolds/page.md @@ -0,0 +1,4 @@ +--- +title: {{ title }} +date: {{ date }} +--- diff --git a/scaffolds/post.md b/scaffolds/post.md new file mode 100644 index 0000000..1f9b9a4 --- /dev/null +++ b/scaffolds/post.md @@ -0,0 +1,5 @@ +--- +title: {{ title }} +date: {{ date }} +tags: +--- diff --git "a/source/_posts/2014-05-14-\350\256\276\350\256\241\346\250\241\345\274\21701\344\271\213-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-14-\350\256\276\350\256\241\346\250\241\345\274\21701\344\271\213-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..fcdc71c --- /dev/null +++ "b/source/_posts/2014-05-14-\350\256\276\350\256\241\346\250\241\345\274\21701\344\271\213-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" @@ -0,0 +1,223 @@ +--- +title: 设计模式01之 简单工厂模式(创建模式) +date: 2014-05-14 10:48:52 +categories: +- 设计模式 +tags: +- java +- 工厂模式 +--- + +# 简单工厂模式简介 + +简单工厂模式(Simple Factory),又被称为"静态工厂方法模式"。它属于"创建模式"(创建对象的模式),并且是"工厂方法"模式的一种特殊实现。 + +通常,我们利用简单工厂模式来进行类的创建。例如,获取线程池对象,就是通过简单工厂模式来实现的。它的结构图如下所示: + + + +![pattern01_01](/images/media/pattern01_01.jpg) +简单工厂模式的结构共包括3个组成部分:**工厂(Factory),抽象产品(Product),具体产品(ConcreteProduct)**。 + + +| 组成部分 | 说明 | +| -------------- | --------------- | +| 工厂 | 工厂是简单工厂模式的核心,提供了对外接口。客户端或其它程序要获取Product对象,都是通过Factory的接口来获取的。 | +| 抽象产品 | 抽象产品是(许多)不同产品抽象出来的。Product可以是接口或者抽象类。 | +| 具体产品 | 工厂中返回的产品对象,实际上是通过ConcreteProduct来创建的。 | + + + +# 简单工厂模式代码模型 + + public class Factory { + public static Product newInstance() { + return new ConcreteProduct(); + } + } + public abstract Product { + } + public class ConcreteProduct extends Product { + public ConcreteProduct() {} + } + +模型的类图 +![pattern01_02](/images/media/pattern01_02.jpg) + +# 简单工厂模式示例 + +假设现在有一个水果工厂,能够生成各种各样的水果。目前能生产的水果包括苹果,葡萄和草莓。 + +我们通过"简单工厂模式"描述该问题,它的UML类图如下: +![pattern01_03](/images/media/pattern01_03.jpg) + +## 工厂类 + +工厂类是"FruitFactory"。FruitFactory是水果工厂,水果工厂会生成水果。 + +FruitFactory的源码 + + public class FruitFactory { + + public static Fruit newInstance(String name) + throws BadFruitException { + // 如果name等于"apple"(忽略大小写),则返回苹果。 + if ("apple".equalsIgnoreCase(name)) { + return new Apple(); + // 如果name等于"grape"(忽略大小写),则返回葡萄。 + } else if ("grape".equalsIgnoreCase(name)) { + return new Grape(); + // 如果name等于"strawberry"(忽略大小写),则返回草莓。 + } else if ("strawberry".equalsIgnoreCase(name)) { + return new Strawberry(); + // 其它情况,则抛出异常。 + } else { + throw new BadFruitException("Bad fruit request!"); + } + } + } + + + +## 抽象产品类 + +Product类是"Fruit"。Fruit代表水果,它是抽象类,包含水果的基本特征:生长,种植,收获。 + +Fruit的源码 + + public abstract class Fruit { + abstract void grow(); // 生长 + abstract void harvest(); // 收获 + abstract void plant(); // 种植 + } + + + +## 具体产品类 + +具体产品类是"Apple", "Grape"和"Strawberry"。它们是3种具体的水果,分别代表苹果,葡萄和草莓。 + +Apple的源码 + + // Apple实现Fruit的函数接口,并且Apple中有私有成员age和私有方法log。 + public class Apple extends Fruit { + private int age; + + public void grow() { + log("Apple grow()"); + } + public void harvest() { + log("Apple harvest()"); + } + public void plant() { + log("Apple plant()"); + } + public void setAge(int age) { + this.age = age; + } + public int getAge() { + return age; + } + private void log(String msg) { + System.out.println(msg); + } + } + +Grape的源码 + + // Grape仅仅只实现Fruit的函数接口。 + public class Grape extends Fruit { + public void grow() { + System.out.println("Grape grow()"); + } + public void harvest() { + System.out.println("Grape harvest()"); + } + public void plant() { + System.out.println("Grape plant()"); + } + } + +Strawberry的源码 + + // Strawberry实现Fruit的函数接口,并且Strawberry中有私有方法log + public class Strawberry extends Fruit { + + public void grow() { + log("Strawberry grow()"); + } + public void harvest() { + log("Strawberry harvest()"); + } + public void plant() { + log("Strawberry plant()"); + } + private void log(String msg) { + System.out.println(msg); + } + } + + + +## 客户端测试程序 + +客户端是"Client"。 + +Client的源码 + + public class Client { + + public static void main(String[] args) { + try { + Fruit apple = FruitFactory.newInstance("Apple"); + apple.plant(); + apple.grow(); + apple.harvest(); + + Fruit grape = FruitFactory.newInstance("Grape"); + grape.plant(); + grape.grow(); + grape.harvest(); + + Fruit strawberry = FruitFactory.newInstance("strawberry"); + strawberry.plant(); + strawberry.grow(); + strawberry.harvest(); + + Fruit error = FruitFactory.newInstance("error"); + error.plant(); + error.grow(); + error.harvest(); + } catch (BadFruitException e) { + e.printStackTrace(); + } + } + } + +运行结果: + + Apple plant() + Apple grow() + Apple harvest() + Grape plant() + Grape grow() + Grape harvest() + Strawberry plant() + Strawberry grow() + Strawberry harvest() + BadFruitException: Bad fruit request! + at FruitFactory.newInstance(FruitFactory.java:17) + at Client.main(Client.java:21) + +结果说明: + +Client成功创建了Apple, Grape, Strawberry这3个水果对象,并调用了它们的方法;然后创建error时,由于不存在error对应的水果,因此抛出异常。 + +(01) Fruit,是抽象产品。Fruit中声明了grow(), harvest(), plant()这3个函数接口,它们是水果共用拥有的行为。 + +(02) Apple, Grape和Strawberry这三个类是具体产品。 +Apple -- 实现Fruit的函数接口,并且Apple中有私有成员age和私有方法log。 +Grape -- 仅仅只实现Fruit的函数接口。 +Strawberry -- 实现Fruit的函数接口,并且Strawberry中有私有方法log + +(03) FruitFactory,是工厂类。通过它的newInstance()方法,我们可以获取相应的Fruit对象。若要获取的水果不存在,则抛出BadFruitException异常。BadFruitException是Exception的子类。 diff --git "a/source/_posts/2014-05-15-\350\256\276\350\256\241\346\250\241\345\274\21702\344\271\213-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-15-\350\256\276\350\256\241\346\250\241\345\274\21702\344\271\213-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..422b6ca --- /dev/null +++ "b/source/_posts/2014-05-15-\350\256\276\350\256\241\346\250\241\345\274\21702\344\271\213-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" @@ -0,0 +1,249 @@ +--- +title: 设计模式02之 工厂方法模式(创建模式) +date: 2014-05-15 11:03:36 +categories: +- 设计模式 +tags: +- java +- 工厂方法 +--- + +# 工厂方法模式简介 + +工厂方法模式(Factory Method),又被称为"虚构造子模式"或"多态性工厂模式"。它属于"创建模式"(创建对象的模式)。 + + + +它的用意是提供一个"创建产品对象"的接口,而将这些接口的实现推迟到它的子类中去。因此它具有两个明显的优点: +(1) 定义创建对象的接口,封装了对象的创建。 +(2) 使得具体化类的工作延迟到了子类中。 + +下面看看它的结构图: +![pattern02_01](/images/media/pattern02_01.jpg) + +工厂方法模式的结构共包括4个组成部分:**抽象工厂(Factory),具体工厂(ConcreteFactory), 抽象产品(Product),具体产品(ConcreteProduct)。** + +| 组成部分 | 说明 | +| -------------- | --------------- | +| Factory | 它提供了"创建产品"的函数接口,该函数接口由具体工厂ConcreteFactory来实现。Factory可以是接口或者抽象类。 | +| ConcreteFactory | 它实现了Factory的函数接口。在上面的结构图中,给出了ConcreteFactory1和ConcreteFactory2两个具体工厂类。 | +| Product | 它是抽象产品。 | +| ConcreteProduct | 它是具体产品,实现了Product中的函数接口。ConcreteFactory中"创建产品"的函数实现中,实际上是返回的ConcreteProduct实例。在上面的结构图中,给出了ConcreteProduct1和ConcreteProduct2两个具体产品类。 | + + +# 工厂方法模式代码模型 + +代码 + + public interface Factory { + public Product newInstance() ; + } + public class ConcreteFactory1 implements Factory { + public Product newInstance() { + return new ConcreteProduct1(); + } + } + public class ConcreteFactory2 implements Factory { + public Product newInstance() { + return new ConcreteProduct2(); + } + } + public interface Product { + } + public class ConcreteProduct1 implements Product { + public ConcreteProduct1() { + // do something + } + } + public class ConcreteProduct2 implements Product { + public ConcreteProduct2() { + // do something + } + } + +模型的类图 +![pattern02_02](/images/media/pattern02_02.jpg) + +以上模型中,对于"抽象工厂"和"抽象产品"都只给出了两个实现类;在实际中,情况可能比这复杂许多。 + + +# 工厂方法模式示例 + +将"简单工厂模式"中的示例,改为由"工厂方法模式"实现。它的UML类图如下: +![pattern02_03](/images/media/pattern02_03.jpg) + +## 抽象工厂类 + +抽象工厂类类是"FruitFactory"。FruitFactory是水果工厂,水果工厂会生成苹果,葡萄和草莓这3种水果。 + +FruitFactory的源码 + + abstract public class FruitFactory { + public abstract Fruit newInstance(); + } + + + +## 具体工厂类 + +具体工厂类是"AppleFactory", "GrapeFactory"和"StrawberryFactory";它们都继承于FruitFactory。AppleFactory生产苹果,GrapeFactory生成葡萄,Strawberry生成草莓。 + +AppleFactory的源码 + + public class AppleFactory extends FruitFactory { + public Fruit newInstance() { + return new Apple(); + } + } + +GrapeFactory的源码 + + public class GrapeFactory extends FruitFactory { + public Fruit newInstance() { + return new Grape(); + } + } + +Strawberry的源码 + + public class StrawberryFactory extends FruitFactory { + public Fruit newInstance() { + return new Strawberry(); + } + } + + +## 抽象产品类 + +抽象产品类是"Fruit"。Fruit代表水果,它是抽象类,包含水果的基本特征:生长,种植,收获。 + +Fruit的源码 + + public abstract class Fruit { + abstract void grow(); // 生长 + abstract void harvest(); // 收获 + abstract void plant(); // 种植 + } + + +## 具体产品类 + +具体产品类是"Apple", "Grape"和"Strawberry"。它们是3种具体的水果,分别代表苹果,葡萄和草莓。 + +Apple的源码 + + // Apple实现Fruit的函数接口,并且Apple中有私有成员age和私有方法log。 + public class Apple extends Fruit { + private int age; + + public void grow() { + log("Apple grow()"); + } + public void harvest() { + log("Apple harvest()"); + } + public void plant() { + log("Apple plant()"); + } + public void setAge(int age) { + this.age = age; + } + public int getAge() { + return age; + } + private void log(String msg) { + System.out.println(msg); + } + } + +Grape的源码 + + // Grape仅仅只实现Fruit的函数接口。 + public class Grape extends Fruit { + public void grow() { + System.out.println("Grape grow()"); + } + public void harvest() { + System.out.println("Grape harvest()"); + } + public void plant() { + System.out.println("Grape plant()"); + } + } + +Strawberry的源码 + + // Strawberry实现Fruit的函数接口,并且Strawberry中有私有方法log + public class Strawberry extends Fruit { + + public void grow() { + log("Strawberry grow()"); + } + public void harvest() { + log("Strawberry harvest()"); + } + public void plant() { + log("Strawberry plant()"); + } + private void log(String msg) { + System.out.println(msg); + } + } + + + +## 客户端测试程序 + +客户端是"Client"。 + +Client的源码 + + public class Client { + + public static void main(String[] args) { + // 创建"抽象工厂FruitFactory"对象,该对象是"具体工厂AppleFactory"的实例 + FruitFactory appleFac = new AppleFactory(); + // 根据工厂实例,创建对应的产品 + Fruit apple = appleFac.newInstance(); + apple.plant(); + apple.grow(); + apple.harvest(); + + // 创建"抽象工厂FruitFactory"对象,该对象是"具体工厂GrapeFactory"的实例 + FruitFactory grapeFac = new GrapeFactory(); + // 根据工厂实例,创建对应的产品 + Fruit grape = grapeFac.newInstance(); + grape.plant(); + grape.grow(); + grape.harvest(); + + // 创建"抽象工厂FruitFactory"对象,该对象是"具体工厂StrawberryFactory"的实例 + FruitFactory strawberryFac = new StrawberryFactory(); + // 根据工厂实例,创建对应的产品 + Fruit strawberry = strawberryFac.newInstance(); + strawberry.plant(); + strawberry.grow(); + strawberry.harvest(); + } + } + +运行结果: + + Apple plant() + Apple grow() + Apple harvest() + Grape plant() + Grape grow() + Grape harvest() + Strawberry plant() + Strawberry grow() + Strawberry harvest() + +# 工厂方法模式和简单工厂模式的比较 + +在简单共存模式中,"工厂类"处于实例化产品的中心位置;它知道每一个产品,决定了哪一个产品类应该被实例化。如果有新的产品添加到系统中,就需要对应的修改"工厂类"。 +而工厂方法模式的出现,既保持了简单工厂模式的优点,又客服了它的缺点。在工厂方法模式中,"工厂类"不再负责产品的实例化,而是将实例化工作交给它的子类(具体工厂)去完成。这样,当有新的产品添加到系统中时,就不需要修改"工厂类",而只要添加对应的"具体工厂"类即可! + +简单工厂模式相当于工厂方法模式的特殊形式。即,当工厂方法模式中,只有一个"具体工厂"存在时,将"抽象工厂"和"具体工厂"合并成一个类;接着,将实例化产品的方法改为静态方法。此时,就得到了简单工厂模式。 + +反之,工厂方法模式也相当于"多态"的简单工厂模式。 diff --git "a/source/_posts/2014-05-16-\350\256\276\350\256\241\346\250\241\345\274\21703\344\271\213-\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-16-\350\256\276\350\256\241\346\250\241\345\274\21703\344\271\213-\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..1ef853a --- /dev/null +++ "b/source/_posts/2014-05-16-\350\256\276\350\256\241\346\250\241\345\274\21703\344\271\213-\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" @@ -0,0 +1,226 @@ +--- +title: 设计模式03之 抽象工厂模式(创建模式) +date: 2014-05-16 11:03:59 +categories: +- 设计模式 +tags: +- java +- 抽象工厂 +--- +# 抽象工厂模式简介 + +抽象工厂模式(Abstract Factory),它是所有形态的工厂模式中最为抽象,也是最具有一般性的形态。它属于"创建模式"(创建对象的模式)。它的结构图如下所示: +![pattern03_01](/images/media/pattern03_01.jpg) + + + +抽象工厂模式的结构共包括4个组成部分:**抽象工厂(Factory),具体工厂(ConcreteFactory), 抽象产品(Product),具体产品(ConcreteProduct)**。 + +| 组成部分 | 说明 | +| -------------- | --------------- | +| Factory | 它提供了"创建产品"的函数接口,该函数接口由具体工厂ConcreteFactory来实现。Factory可以是接口或者抽象类。 | +| ConcreteFactory | 它实现了Factory的函数接口。 | +| Product | 它是抽象产品,是(许多)不同产品抽象出来的。在抽象工厂模式中,抽象产品不止一个。 | +| ConcreteProduct | 它是具体产品。ConcreteFactory中"创建产品"的函数实现中,实际上是返回的ConcreteProduct实例。 | + +**抽象工厂模式与工厂方法模式的区别**: 在工厂方法模式中,"抽象产品"只有一个,而在抽象工厂模式中,"抽象产品"有很多个!在工厂方法模式中,是由"具体工厂"决定返回哪一类产品;然后,抽象工厂中,是由"客户端"决定返回哪一类产品。 + +# 抽象工厂模式代码模型 + +代码 + + public interface Factory { + public ProductA newProductA(); + public ProductB newProductB(); + } + public class ConcreteFactory1 implements Factory { + public ProductA newProductA() { + return new ConcreteProductA1(); + } + public ProductB newProductB(); + return new ConcreteProductB1(); + } + } + public class ConcreteFactory2 implements Factory { + public ProductA newProductA2() { + return new ConcreteProduct1(); + } + public ProductB newProductB2(); + return new ConcreteProduct1(); + } + } + public interface ProductA { + } + public class ProductA1 implements ProductA { + } + public class ProductA2 implements ProductA { + } + public interface ProductB { + } + public class ProductB1 implements ProductB { + } + public class ProductB2 implements ProductB { + } + +模型的类图 + ![pattern03_02](/images/media/pattern03_02.jpg) + +# 抽象工厂模式示例 + +假设,我们要实现一个工厂管理系统,记录三星和苹果这两家工厂(Factory)生产的手机(Phone)和电脑(Computer)信息。 + +已知,三星和苹果都由自己的工厂,分别是"三星工厂(SumFactory)"和"苹果工厂(AppleFactory)"。三星工厂生产"三星手机(SumPhone)"和"三星电脑(SumComputer)",苹果工厂生产"苹果手机(ApplePhone)"和"苹果电脑(AppleComputer)"。 + +我们用抽象工厂模式实现该系统,它的设计图如下: +![pattern03_03](/images/media/pattern03_03.jpg) + +在该系统中,"抽象工厂","具体工厂", 抽象产品"和"具体产品"这4个角色分别如下: + +## 抽象工厂 + +"抽象工厂"是Factory,Factory中定义了"生产手机"以及"生产电脑"的方法。 + +Factory的源码 + + public interface Factory { + // 生产手机 + public Phone createPhone() ; + // 生产电脑 + public Computer createComputer() ; + } + + + +## 具体工厂 + +"具体工厂"是SumFactory和AppleFactory。SumFactory能返回的"三星手机(SumPhone)"和“三星电脑SumComputer”对象。AppleFactory能返回的"苹果手机(ApplePhone)"和“苹果电脑AppleComputer”对象。 + +SumFactory的源码 + + public class SumFactory implements Factory{ + // 生产三星手机 + public Phone createPhone() { + return new SumPhone(); + } + // 生产三星电脑 + public Computer createComputer() { + return new SumComputer(); + } + } + +AppleFactory的源码 + + public class AppleFactory implements Factory{ + // 生产苹果手机 + public Phone createPhone() { + return new ApplePhone(); + } + // 生产苹果电脑 + public Computer createComputer() { + return new AppleComputer(); + } + } + + + +## 抽象产品 + +"抽象产品"是"手机(Phone)"和"电脑(Computer)"。手机包括"activate()方法",而电脑则包括"getOSName()方法"。 + +Phone的源码 + + abstract public class Phone { + // 激活手机 + abstract public void activate(); + } + +Computer的源码 + + abstract public class Computer { + // 获取操作系统名词 + abstract public String getOSName(); + } + + + +## 具体产品 + +"具体产品"是"三星手机(SumPhone)","三星电脑(SumComputer)";以及 "苹果手机(ApplePhone)"和"苹果电脑(AppleComputer)"。 + +SumPhone源码 + + public class SumPhone extends Phone{ + // 激活手机 + public void activate() { + System.out.println("activate SumPhone"); + } + } + +SumComputer源码 + + public class SumComputer extends Computer{ + // 获取操作系统名词 + public String getOSName() { + return "Windows"; + } + } + +ApplePhone源码 + + public class ApplePhone extends Phone{ + // 激活手机 + public void activate() { + System.out.println("activate ApplePhone"); + } + } + +AppleComputer源码 + + public class AppleComputer extends Computer{ + // 获取操作系统名词 + public String getOSName() { + return "Mac"; + } + } + + + +## 客户端测试程序 + +客户端是"Client"。 + +Client的源码 + + public class Client { + + public static void main(String[] args) { + // 创建"Factory"对象,该对象是"AppleFactory"的实例 + Factory appleFac = new AppleFactory(); + // 根据工厂实例,创建对应的手机和电脑 + Phone applePhone = appleFac.createPhone(); + Computer appleComputer = appleFac.createComputer(); + // 激活"手机" + applePhone.activate(); + // 获取"电脑操作系统名词" + String appleOS =appleComputer.getOSName(); + System.out.println("appleOS is: "+appleOS); + + // 创建"Factory"对象,该对象是"SumFactory"的实例 + Factory sumFac = new SumFactory(); + // 根据工厂实例,创建对应的手机和电脑 + Phone sumPhone = sumFac.createPhone(); + Computer sumComputer = sumFac.createComputer(); + // 激活"手机" + sumPhone.activate(); + // 获取"电脑操作系统名词" + String sumOS = sumComputer.getOSName(); + System.out.println("sumOS is: "+sumOS); + } + } + +运行结果: + + activate ApplePhone + appleOS is: Mac + activate SumPhone + sumOS is: Windows diff --git "a/source/_posts/2014-05-17-\350\256\276\350\256\241\346\250\241\345\274\21704\344\271\213-\345\215\225\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-17-\350\256\276\350\256\241\346\250\241\345\274\21704\344\271\213-\345\215\225\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..830e1e2 --- /dev/null +++ "b/source/_posts/2014-05-17-\350\256\276\350\256\241\346\250\241\345\274\21704\344\271\213-\345\215\225\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" @@ -0,0 +1,104 @@ +--- +title: 设计模式04之 单例模式(创建模式) +date: 2014-05-17 11:03:28 +categories: +- 设计模式 +tags: +- java +- 单例模式 +--- + +# 单例模式简介 + +单例模式(Simple Factory),确保类只有一个实例,而且类自己实例化该实例并向客户端提供该实例。它属于"创建模式"(创建对象的模式)。 + +单例模式具有以下特点:(01), 类只能有一个实例。(02), 类自行创建实例。(03), 向整个系统提供这个实例。 + + + +它的结构图如下所示: +![pattern04_01](/images/media/pattern04_01.jpg) + +# 单例模式代码模型 + +单例模式包括:**饿汉式单例模式** 和 **懒汉式单例模式** + +**它们的相同点**:它们的单例类中,构造函数都是私有的!这样,就避免了外界利用构造函数创建对象,而只能通过指定的函数来获取对象。此外,由于构造函数是私有的,此类不能被继承! + +**它们的不同点**:饿汉式单例模式,是在类被加载时,就创建了类的对象。而在懒汉式单例模式中,在类被第一次引用时,才将自己实例化。 + + + +## 饿汉式单例模式的代码模型 + + public class EagerSingleton { + private static final EagerSingleton mInstance = new EagerSingleton(); + + private EagerSingleton() {} + + public static EagerSingleton getInstance() { + return mInstance; + } + } + +在饿汉式单例模式中,在类被加载时,静态变量mInstance就会被初始化。这时候,单例类的唯一实例就被创建出来了。 + + +## 懒汉式单例模式的代码模型 + + public class LazySingleton { + private static LazySingleton mInstance = null; + + private LazySingleton() {} + + synchronized public static LazySingleton getInstance() { + if (mInstance==null) { + mInstance = new LazySingleton(); + } + return mInstance; + } + } + +在懒汉式单例模式中,在类被加载时,静态变量mInstance并不会被初始化;而只有当getInstance()第1次被调用的时候,mInstance才被初始化。 + +# 单例模式示例 + +示例代码: + + class EagerSingleton { + private static final EagerSingleton mInstance = new EagerSingleton(); + + private EagerSingleton() {} + + public static EagerSingleton getInstance() { + return mInstance; + } + + public void doSomething() { + System.out.println(Thread.currentThread().getName()+" do something"); + } + } + + public class SingletonTest { + + public static void main(String[] args) { + // 启动5个线程。它们会分别获取EagerSingleton实例,并调用它的doSomething()方法。 + for (int i=0; i<5; i++) { + new Thread( new Runnable() { + @Override + public void run() { + EagerSingleton es = EagerSingleton.getInstance(); + es.doSomething(); + } + }).start(); + } + } + } + +运行结果: + + Thread-3 do something + Thread-4 do something + Thread-2 do something + Thread-1 do something + Thread-0 do something diff --git "a/source/_posts/2014-05-18-\350\256\276\350\256\241\346\250\241\345\274\21705\344\271\213-\345\244\232\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-18-\350\256\276\350\256\241\346\250\241\345\274\21705\344\271\213-\345\244\232\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..1c071a7 --- /dev/null +++ "b/source/_posts/2014-05-18-\350\256\276\350\256\241\346\250\241\345\274\21705\344\271\213-\345\244\232\344\276\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" @@ -0,0 +1,71 @@ +--- +title: 设计模式05之 多例模式(创建模式) +date: 2014-05-18 11:04:40 +categories: +- 设计模式 +tags: +- java +- 多例模式 +--- + +# 多例模式简介 + +多例模式(Multiton),顾名思义,是指存在一个类由多个相同实例,而且该实例都是该类本身。这个类叫做多例类。 + +多例模式的特点是: (01), 多例类可以由多个实例。 (02), 多例类必须自己创建、管理自己的实例,并向外界提供自己的实例。 + + + +多例模式的结构图如下: +![pattern05_01](/images/media/pattern05_01.jpg) + +# 多例模式代码模型 + + public class /images/mediaMultiton { + public static final Multiton INSTANCE_01 = new Multiton("instance_01"); + public static final Multiton INSTANCE_02 = new Multiton("instance_02"); + + private Multiton(String name) {} + } + + + +# 多例模式示例 + +示例代码: + + // 多例类。 + // 包括CHINA, ENGLAND 和 FRANCE 这3个实例。 + class Country { + public static final Country CHINA = new Country("chinae"); + public static final Country ENGLAND = new Country("england"); + public static final Country FRANCE = new Country("france"); + + private String name; + private Country(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + public class MultitonTest { + + public static void main(String[] args) { + Country c1 = Country.CHINA; + Country c2 = Country.ENGLAND; + Country c3 = Country.FRANCE; + + System.out.println("c1 is: "+c1.getName()); + System.out.println("c2 is: "+c2.getName()); + System.out.println("c3 is: "+c3.getName()); + } + } + +运行结果: + + c1 is: chinae + c2 is: england + c3 is: france diff --git "a/source/_posts/2014-05-19-\350\256\276\350\256\241\346\250\241\345\274\21706\344\271\213-\345\273\272\351\200\240\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-19-\350\256\276\350\256\241\346\250\241\345\274\21706\344\271\213-\345\273\272\351\200\240\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..5a497ff --- /dev/null +++ "b/source/_posts/2014-05-19-\350\256\276\350\256\241\346\250\241\345\274\21706\344\271\213-\345\273\272\351\200\240\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" @@ -0,0 +1,297 @@ +--- +title: 设计模式06之 建造模式(创建模式) +date: 2014-05-19 11:04:57 +categories: +- 设计模式 +tags: +- java +- 建造模式 +--- +# 建造模式简介 + +建造模式是"创建模式"(创建对象的模式)。当我们要创建的对象比较复杂的时候,可以将对象的"创建"和"表示"分割开来;从而可以使一个构造过程创建具有不同表示的产品。这种参见对象的方式就是建造模式。 + + + +**建造模式的使用场景** + +(01), 对象包含复杂的内部结构。每个内部成分本身可以是对象,也可以仅仅是一个对象的一个组成成分。 +     例如,一个电子邮件由发件人地址、收件人地址、主题、内容、附件等内容。我们可以根据这些组成部分组合成一份邮件,然后发送出去。 + +(02), 对象的各个属性相互依赖。 +     例如,某对象包含许多性质,而这些性质必须按照某个顺序赋值才有意义。 + +(03), 对象创建过程会使用到系统中的其他对象,而这些对象在产品对象的创建过程中不易得到。 + + + +下面看看它的结构图: +![pattern06_01](/images/media/pattern06_01.jpg) + +建造模式包括4个组成部分:**导演者(Director), 抽象建造者(Builder), 具体建造者(ConcreteBuilder) 和 产品(Product)**。 + +| 组成部分 | 说明 | +| -------------- | --------------- | +| Director | 它会调用具体创建者来创造一个产品对象。 | +| Builder | 它会给出"创建一个产品对象的各个组成成分"的抽象接口。 | +| ConcreteBuilder | 实现"抽象建造者"给出的抽象接口。 | +| Product | 要被创建的产品对象。 | + +# 建造模式代码模型 + + public class Director { + private Builder builder; + + // 构造产品 + public void construct() { + builder = new ConcreteBuilder(); + builder.buildPart1(); + builder.buildPart2(); + } + } + + abstract public class Builder { + // 构造"产品的Part1"的接口 + public abstract void buildPart1(); + // 构造"产品的Part2"的接口 + public abstract void buildPart2(); + // 返回产品 + public abstract Product retrieveResult(); + } + + public class ConcreteBuilder { + private Product product = new Product(); + public void buildPart1() { + // 参见产品的Part1 + } + public void buildPart2() { + // 参见产品的Part2 + } + public Product retrieveResult() { + return product; + } + } + + public class Product { + // 产品组成部分... + } + +# 建造模式示例 + +假设由一个电子杂志系统,定期的向用户的发送电子邮箱。发送的电子邮件模板由两种:欢迎和欢送。邮件包括"发送者地址","接收者地址",“主题”,“内容”,“发送日期”等内容;其中,“发送者地址”和“接收者地址”是必填的。 + +下面通过建造模式实现该系统,对应的UML图如下: +![pattern06_02](/images/media/pattern06_02.jpg) + +建造模式包括4个组成部分:"导演者", "抽象建造者", "具体建造者"和"产品"这4个角色分别如下: + +## "导演者" + +导演者是Director。Director会根据Builder对象,构造出邮件。 + +Director的源码 + + public class Director { + + private Builder builder; + + public Director(Builder builder) { + this.builder = builder; + } + + public void construct(String from, String to) { + builder.buildFrom(from); + builder.buildTo(to); + builder.buildSubject(); + builder.buildBody(); + builder.buildSendDate(); + + builder.send(); + } + } + + + +## "抽象建造者" + +抽象建造者是Builder。Builder是抽象类,它包含具体的邮件对象msg,msg是在Builder的子类中根据所要创建的消息来初始化的。此外,Builder提供了构造邮件的函数接口。 + +Builder的源码 + + import java.util.Date; + + abstract public class Builder { + + protected AutoMessage msg; + + public Builder() { + } + + public abstract void buildBody() ; + public abstract void buildSubject() ; + + public void buildFrom(String from) { + msg.setFrom(from); + } + public void buildTo(String to) { + msg.setTo(to); + } + public void buildSendDate() { + msg.setSendDate(new Date()); + } + public void send() { + msg.send(); + } + } + + + +## "具体建造者" + +具体建造者是WelcomeBuilder和GoodbyeBuilder。WelcomeBuilder是欢迎消息,GoodbyeBuilder是欢送消息。 + +WelcomeBuilder的源码 + + public class WelcomeBuilder extends Builder { + + public WelcomeBuilder() { + System.out.println("create WelcomeBuilder"); + this.msg = new WelcomeMessage(); + } + + public void buildBody() { + msg.setBody("Welcome body!"); + } + public void buildSubject() { + msg.setSubject("Welcome subject!"); + } + } + +GoodbyeBuilder的源码 + + public class GoodbyeBuilder extends Builder { + + public GoodbyeBuilder() { + System.out.println("create GoodbyeBuilder"); + msg = new GoodbyeMessage(); + } + + public void buildBody() { + msg.setBody("Goodbye body!"); + } + public void buildSubject() { + msg.setSubject("Goodbye subject!"); + } + } + + + +## "产品" + +产品是AutoMessage。AutoMessage是抽象出来的产品类,它包含两个子类WelcomeBuilder和GoodbyeMessage。 + +AutoMessage的源码 + + import java.util.Date; + + abstract public class AutoMessage { + + protected String from; + protected String to; + protected String subject; + protected String body; + protected Date sendDate; + + public void setFrom(String from) { + this.from = from; + } + public String getFrom() { + return from; + } + public void setTo(String to) { + this.to = to; + } + public String getTo() { + return to; + } + public void setSubject(String subject) { + this.subject = subject; + } + public String getSubject() { + return subject; + } + public void setBody(String body) { + this.body = body; + } + public String getBody() { + return body; + } + public void setSendDate(Date sendDate) { + this.sendDate = sendDate; + } + public Date getSendDate() { + return sendDate; + } + public void send() { + System.out.println("send MSG[Subject: \""+subject+"\", Body: \""+body+"\"] from \""+from+"\" to \""+to+"\" @date:\""+sendDate+"\""); + } + } + +WelcomeMessage的源码 + + public class WelcomeMessage extends AutoMessage { + + public WelcomeMessage() { + System.out.println("Create WelcomeMessage"); + } + + public void sayWelcome() { + System.out.println("Welcome."); + } + } + +GoodbyeMessage的源码 + + public class GoodbyeMessage extends AutoMessage { + + public GoodbyeMessage() { + System.out.println("Create GoodbyeMessage"); + } + + public void sayGoodbye() { + System.out.println("Goodbye."); + } + } + + + +## 客户端测试程序 + +客户端是"Client"。 + +Client的源码 + + public class Client { + + private static Director dw, dg; + private static Builder bw, bg; + + public static void main(String[] args) { + bw = new WelcomeBuilder(); + dw = new Director(bw); + dw.construct("skywang12345@gmail.com", "java_patterns@gmail.com"); + + bg = new GoodbyeBuilder(); + dg = new Director(bg); + dg.construct("skywang54321@gmail.com", "java_patterns@gmail.com"); + } + } + +运行结果: + + create WelcomeBuilder + Create WelcomeMessage + send MSG[Subject: "Welcome subject!", Body: "Welcome body!"] from "skywang12345@gmail.com" to "java_patterns@gmail.com" @date:"Sun Jan 19 10:48:02 CST 2014" + create GoodbyeBuilder + Create GoodbyeMessage + send MSG[Subject: "Goodbye subject!", Body: "Goodbye body!"] from "skywang54321@gmail.com" to "java_patterns@gmail.com" @date:"Sun Jan 19 10:48:02 CST 2014" diff --git "a/source/_posts/2014-05-20-\350\256\276\350\256\241\346\250\241\345\274\21707\344\271\213-\345\216\237\345\236\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-20-\350\256\276\350\256\241\346\250\241\345\274\21707\344\271\213-\345\216\237\345\236\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..77945a8 --- /dev/null +++ "b/source/_posts/2014-05-20-\350\256\276\350\256\241\346\250\241\345\274\21707\344\271\213-\345\216\237\345\236\213\346\250\241\345\274\217-\345\210\233\345\273\272\346\250\241\345\274\217.md" @@ -0,0 +1,117 @@ +--- +title: 设计模式07之 原型模式(创建模式) +date: 2014-05-20 11:05:17 +categories: +- 设计模式 +tags: +- java +- 原型模式 +--- + +# 原型模式简介 + +原型模式是"创建模式"(创建对象的模式)。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。 + + + +Java语言的支持支持创建模式。在Java中Object是所有类的父类,而Object中提供了clone()方法。clone()会通过调用本地方法实现对象的复制。它的源码如下: + + protected native Object clone() throws CloneNotSupportedException; + +clone()定义了Object中,就相当于Java中的任何类都继承了clone()方法。但是,如果要类支持克隆的话,必须要声明该类实现了Cloneable接口。否则,调用该类的clone()方法时,会抛出CloneNotSupportedException异常。 + +使用场景: 系统的产品是动态加载的,而产品类具有一定的等级结构。 例如,数据库中存储了很多数据,有时我们需要将其中的一些数据取出来存放到新的表格中。或者,有时候我们需要对比一个对象在处理前/后的姿态;在处理之前,可以克隆该对象,然后和处理之后的对象比较。 + +原型模式有两种表现形式:**简单形式** 和 **登记形式**。 +如果需要创建的原型对象数目少而且比较固定的华,就采用"简单形式";如果要创建的原型对象数目不确定的华,就采用"登记形式"。 + +# 简单形式的原型模式 + +类图 +![pattern07_01](/images/media/pattern07_01.jpg) + +它涉及到3个角色:**客户(Client), 抽象原型(Prototype) 和 具体原型(ConcretePrototype)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| Client | 客户类提出创建对象的请求。 | +| Prototype | 抽象原型给出所有的具体原型所需要实现的函数接口。 | +| ConcreteType | 被复制的对象,实现了Prototype中的函数接口。 | + + +代码模型 + + public interface Prototype extends Cloneable { + Prototype clone(); + } + public class ConcretePrototype implements Prototype { + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + } + public class Client { + private Prototype prototype; + public void operation(Prototype example) { + Prototype p = (Prototype) example.clone(); + } + } +# 登记形式的原型模式 + +UML类图 +![pattern07_02](/images/media/pattern07_02.jpg) + +它涉及到4个角色:**客户(Client), 抽象原型(Prototype), 具体原型(ConcretePrototype) 和 PrototypeManager(原型管理器)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| Client | 客户类提出创建对象的请求。 | +| Prototype | 抽象原型给出所有的具体原型所需要实现的函数接口。 | +| ConcreteType | 被复制的对象,实现了Prototype中的函数接口。 | +| PrototypeManager | 创建具体原型类的对象,并记录每一个被创建的对象。 | + + + +代码模型 + + public interface Prototype extends Cloneable { + Prototype clone(); + } + public class ConcretePrototype implements Prototype { + public synchronized Object clone() { + Prototype temp = null; + try { + temp = (Prototype)super.clone(); + return temp; + } catch (CloneNotSupportedException e) { + return null; + } finally { + return temp; + } + } + } + public class PrototypeManager { + private Vector objects = new Vector(); + + public void add(Prototype object) { + objects.add(object); + } + public Prototype get(int i) { + return (Prototype) objects.get(i); + } + public int getSize() { + return objects.size(); + } + } + public class Client { + private PrototypeManager mgr; + private Prototype prototype; + public void registerPrototype() { + prototype = new ConcretePrototype(); + Prototype copytype = (Prototype)prototype.clone(); + mgr.add(copytype); + } + } diff --git "a/source/_posts/2014-05-21-\350\256\276\350\256\241\346\250\241\345\274\21708\344\271\213-\351\200\202\351\205\215\345\231\250-Adapter-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" "b/source/_posts/2014-05-21-\350\256\276\350\256\241\346\250\241\345\274\21708\344\271\213-\351\200\202\351\205\215\345\231\250-Adapter-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" new file mode 100644 index 0000000..e270638 --- /dev/null +++ "b/source/_posts/2014-05-21-\350\256\276\350\256\241\346\250\241\345\274\21708\344\271\213-\351\200\202\351\205\215\345\231\250-Adapter-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" @@ -0,0 +1,117 @@ +--- +title: 设计模式08之 适配器(Adapter)模式(结构模式) +date: 2014-05-21 11:05:37 +categories: +- 设计模式 +tags: +- 原型模式 +- java +--- + +# 原型模式简介 + +原型模式是"创建模式"(创建对象的模式)。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。 + + + +Java语言的支持支持创建模式。在Java中Object是所有类的父类,而Object中提供了clone()方法。clone()会通过调用本地方法实现对象的复制。它的源码如下: + + protected native Object clone() throws CloneNotSupportedException; + +clone()定义了Object中,就相当于Java中的任何类都继承了clone()方法。但是,如果要类支持克隆的话,必须要声明该类实现了Cloneable接口。否则,调用该类的clone()方法时,会抛出CloneNotSupportedException异常。 + +使用场景: 系统的产品是动态加载的,而产品类具有一定的等级结构。 例如,数据库中存储了很多数据,有时我们需要将其中的一些数据取出来存放到新的表格中。或者,有时候我们需要对比一个对象在处理前/后的姿态;在处理之前,可以克隆该对象,然后和处理之后的对象比较。 + +原型模式有两种表现形式:**简单形式** 和 **登记形式**。 +如果需要创建的原型对象数目少而且比较固定的华,就采用"简单形式";如果要创建的原型对象数目不确定的华,就采用"登记形式"。 + +# 简单形式的原型模式 + +类图 +![pattern07_01](/images/media/pattern07_01.jpg) + +它涉及到3个角色:**客户(Client), 抽象原型(Prototype) 和 具体原型(ConcretePrototype)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| Client | 客户类提出创建对象的请求。 | +| Prototype | 抽象原型给出所有的具体原型所需要实现的函数接口。 | +| ConcreteType | 被复制的对象,实现了Prototype中的函数接口。 | + + +代码模型 + + public interface Prototype extends Cloneable { + Prototype clone(); + } + public class ConcretePrototype implements Prototype { + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + } + public class Client { + private Prototype prototype; + public void operation(Prototype example) { + Prototype p = (Prototype) example.clone(); + } + } +# 登记形式的原型模式 + +UML类图 +![pattern07_02](/images/media/pattern07_02.jpg) + +它涉及到4个角色:**客户(Client), 抽象原型(Prototype), 具体原型(ConcretePrototype) 和 PrototypeManager(原型管理器)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| Client | 客户类提出创建对象的请求。 | +| Prototype | 抽象原型给出所有的具体原型所需要实现的函数接口。 | +| ConcreteType | 被复制的对象,实现了Prototype中的函数接口。 | +| PrototypeManager | 创建具体原型类的对象,并记录每一个被创建的对象。 | + + + +代码模型 + + public interface Prototype extends Cloneable { + Prototype clone(); + } + public class ConcretePrototype implements Prototype { + public synchronized Object clone() { + Prototype temp = null; + try { + temp = (Prototype)super.clone(); + return temp; + } catch (CloneNotSupportedException e) { + return null; + } finally { + return temp; + } + } + } + public class PrototypeManager { + private Vector objects = new Vector(); + + public void add(Prototype object) { + objects.add(object); + } + public Prototype get(int i) { + return (Prototype) objects.get(i); + } + public int getSize() { + return objects.size(); + } + } + public class Client { + private PrototypeManager mgr; + private Prototype prototype; + public void registerPrototype() { + prototype = new ConcretePrototype(); + Prototype copytype = (Prototype)prototype.clone(); + mgr.add(copytype); + } + } diff --git "a/source/_posts/2014-05-22-\350\256\276\350\256\241\346\250\241\345\274\21709\344\271\213-\345\220\210\346\210\220-Composite-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" "b/source/_posts/2014-05-22-\350\256\276\350\256\241\346\250\241\345\274\21709\344\271\213-\345\220\210\346\210\220-Composite-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" new file mode 100644 index 0000000..4679d62 --- /dev/null +++ "b/source/_posts/2014-05-22-\350\256\276\350\256\241\346\250\241\345\274\21709\344\271\213-\345\220\210\346\210\220-Composite-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" @@ -0,0 +1,383 @@ +--- +title: 设计模式09之 合成(Composite)模式(结构模式) +date: 2014-05-22 11:06:02 +categories: +- 设计模式 +tags: +- java +- 合成模式 +--- + +# 合成模式简介 + +合成模式属于对象的结构型模式,有时又被称为"部分-整体模式"。合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。 + + + +例如,文件系统就是一个典型的合成模式系统。合成模式的树形图如下所示: +![pattern09_01](/images/media/pattern09_01.jpg) + +它的UML类图如下所示: +![pattern09_02](/images/media/pattern09_02.jpg) + +它共包括3个角色:**抽象构件(Component)**,**树叶构件(Leaf)** 和 **树枝构件(Composite)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象构件 | 这是一个抽象角色,它给参加组合的对象规定一个接口。这个角色给出共有的接口及其默认行为。 | +| 树叶构件 | 代表参加组合的树叶对象。树叶对象没有下级子对象,它定义出参加组合的原始对象的行为。 | +| 树枝构件 | 代表参加组合的有下级子对象的对象,并给出树枝构件对象的行为。 | + +根据"参加组合的对象的管理方式",可以将合成模式分为两种不同的形式:**安全合成模式** 和 **透明合成模式**。 +• 安全合成模式:此方式只允许"树枝构件"有对象的管理方法。 +• 透明合成模式:此方式只允许"树枝构件'和"树叶构件"都有对象的管理方法,但"树叶构件"中的管理方法无实际意义。 + +# 安全合成模式 + +安全合成模式要求管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件类中。 + +安全合成模式的UML图如下: +![pattern09_03](/images/media/pattern09_03.jpg) + +它共包括3个角色:**抽象构件(Component),树叶构件(Leaf) 和 树枝构件(Composite)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象构件 | 这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝构件对象给出。 | +| 树叶构件 | 树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。 | +| 树枝构件 | 代表参加组合的有下级子对象的对象。树枝构件类给出所有的管理子对象的方法,如add()、remove()以及getChild()。 | + + +示例代码 + + public interface Component { + // 返还自己的示例 + Composite getComposite(); + // 某个商业方法 + void sampleOperation(); + } + + public class Composite implements Component { + private Vector componentVector = new Vector(); + public Composite getComposite() { + return this; + } + public void sampleOperation() { + Enumeration enum = composites(); + while (enum.hasMoreElements()) { + ((Composite)enum.nextElement()).sampleOperation(); + } + } + // 添加一个子构件对象 + public void add(Component component) { + componentVector.addElement(component); + } + // 删除一个子构件对象 + public void remove(Component component) { + componentVector.removeElement(component); + } + // 聚集管理办法,返还聚集的Enumeration对象 + public Enumeration components() { + return componentVector.elements(); + } + } + + public class Leaf implements Component { + public void sampleOperation() { + } + public Composite getComposite() { + return null; + } + } + +从中可以看出,树叶构建(Leaf)中没有对节点的管理方法,而只有树枝构建(Composite)中有节点的管理方法。 + +# 透明合成模式 + +与安全式的合成模式不同的是,透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口。 + +透明合成模式的UML图如下: +![pattern09_04](/images/media/pattern09_04.jpg) + +它共包括3个角色:**抽象构件(Component),树叶构件(Leaf) 和 树枝构件(Composite)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象构件 | 这是一个抽象角色,它给参加组合的对象规定一个接口,规范共有的接口及默认行为。这个接口可以用来管理所有的子对象,要提供一个接口以规范取得和管理下层组件的接口,包括add(), remove()以及getChild()之类的方法。 | +| 树叶构件 | 代表参加组合的树叶对象,定义出参加组合的原始对象的行为。树叶类会给出add(), remove()以及getChild()之类的用来管理子类对象的方法的平庸实现。 | +| 树枝构件 | 代表参加组合的有子对象的对象,定义出这样的对象的行为。 | + +示例代码 + + public interface Component { + // 某个商业方法 + void sampleOperation(); + // 返还自己的示例 + Composite getComposite(); + // 聚集管理方法,增加子构件对象 + void add(Component component); + // 聚集管理方法,删除子构件对象 + void remove(Component component); + // 聚集管理办法,返还聚集的Enumeration对象 + Enumeration components(); + } + + public class Composite implements Component { + private Vector componentVector = new Vector(); + public Composite getComposite() { + return this; + } + public void sampleOperation() { + Enumeration enum = composites(); + while (enum.hasMoreElements()) { + ((Composite)enum.nextElement()).sampleOperation(); + } + } + // 添加一个子构件对象 + public void add(Component component) { + componentVector.addElement(component); + } + // 删除一个子构件对象 + public void remove(Component component) { + componentVector.removeElement(component); + } + // 聚集管理办法,返还聚集的Enumeration对象 + public Enumeration components() { + return componentVector.elements(); + } + } + + public class Leaf implements Component { + public void sampleOperation() { + } + public Composite getComposite() { + return null; + } + // 添加一个子构件对象 + public void add(Component component) { + } + // 删除一个子构件对象 + public void remove(Component component) { + } + // 聚集管理办法,返还聚集的Enumeration对象 + public Enumeration components() { + return null; + } + + }  + + + +# 合成模式示例 + +下面以一个逻辑树为例子,演示合成模式。 + +## 抽象构件(IFile.java) + + public interface IFile { + //返回自己的实例 + IFile getComposite(); + + //某个商业方法 + void sampleOperation(); + + //获取深度 + int getDeep(); + + //设置深度 + void setDeep(int x); + } + +## 树枝构件(Folder.java) + + import java.util.Vector; + + public class Folder implements IFile { + private String name; //文件名字 + private int deep; //层级深度,根深度为0 + private Vector componentVector = new Vector(); + + public Folder(String name) { + this.name = name; + } + + //返回自己的实例 + public IFile getComposite() { + return this; + } + + //某个商业方法 + public void sampleOperation() { + System.out.println("执行了某个商业方法!"); + } + + //增加一个文件或文件夹 + public void add(IFile IFile) { + componentVector.addElement(IFile); + IFile.setDeep(this.deep + 1); + } + + //删除一个文件或文件夹 + public void remove(IFile IFile) { + componentVector.removeElement(IFile); + } + + //返回直接子文件(夹)集合 + public Vector getAllComponent() { + return componentVector; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getDeep() { + return deep; + } + + public void setDeep(int deep) { + this.deep = deep; + } + } + +## 树枝构件(File.java) + + public class File implements IFile { + private String name; //文件名字 + private int deep; //层级深度 + + public File(String name) { + this.name = name; + } + + //返回自己的实例 + public IFile getComposite() { + return this; + } + + //某个商业方法 + public void sampleOperation() { + System.out.println("执行了某个商业方法!"); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getDeep() { + return deep; + } + + public void setDeep(int deep) { + this.deep = deep; + } + } + +## 客户端测试程序(Client.java) + + import java.util.Iterator; + import java.util.Vector; + import java.util.Collections; + + public class Client { + private static final String INDENT_CHAR = "\t"; //文件层次缩进字符 + + public static void main(String args[]) { + new Client().test(); + } + + /** + * 客户端测试方法 + */ + public void test() { + //根下文件及文件夹 + Folder root = new Folder("树根"); + + Folder b1_1 = new Folder("1_枝1"); + Folder b1_2 = new Folder("1_枝2"); + Folder b1_3 = new Folder("1_枝3"); + File l1_1 = new File("1_叶1"); + File l1_2 = new File("1_叶2"); + File l1_3 = new File("1_叶3"); + + //b1_2下的文件及文件夹 + Folder b2_1 = new Folder("2_枝1"); + Folder b2_2 = new Folder("2_枝2"); + File l2_1 = new File("2_叶1"); + + //缔造树的层次关系(简单测试,没有重复添加的控制) + root.add(b1_1); + root.add(b1_2); + root.add(l1_1); + root.add(l1_2); + + b1_2.add(b2_1); + b1_2.add(b2_2); + b1_2.add(l2_1); + root.add(l1_3); + root.add(b1_3); + //控制台打印树的层次 + outTree(root); + } + + public void outTree(Folder folder) { + System.out.println(folder.getName()); + iterateTree(folder); + } + + /** + * 遍历文件夹,输入文件树 + * + * @param folder + */ + public void iterateTree(Folder folder) { + Vector clist = folder.getAllComponent(); + for (Iterator it = clist.iterator(); it.hasNext();) { + IFile em = it.next(); + if (em instanceof Folder) { + Folder cm = (Folder) em; + System.out.println(getIndents(em.getDeep()) + cm.getName()); + iterateTree(cm); + } else { + System.out.println(getIndents(em.getDeep()) + ((File) em).getName()); + } + } + } + + /** + * 文件层次缩进字符串 + * + * @param x 缩进字符个数 + * @return 缩进字符串 + */ + public static String getIndents(int x) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < x; i++) { + sb.append(INDENT_CHAR); + } + return sb.toString(); + } + } + + + +运行结果: + + 树根 + 1_枝1 + 1_枝2 + 2_枝1 + 2_枝2 + 2_叶1 + 1_叶1 + 1_叶2 + 1_叶3 + 1_枝3 diff --git "a/source/_posts/2014-05-23-\350\256\276\350\256\241\346\250\241\345\274\21710\344\271\213-\350\243\205\351\245\260-Decorator-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" "b/source/_posts/2014-05-23-\350\256\276\350\256\241\346\250\241\345\274\21710\344\271\213-\350\243\205\351\245\260-Decorator-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" new file mode 100644 index 0000000..45a1681 --- /dev/null +++ "b/source/_posts/2014-05-23-\350\256\276\350\256\241\346\250\241\345\274\21710\344\271\213-\350\243\205\351\245\260-Decorator-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" @@ -0,0 +1,231 @@ +--- +title: 设计模式10之 装饰(Decorator)模式(结构模式) +date: 2014-05-23 11:07:00 +categories: +- 设计模式 +tags: +- java +- 装饰模式 +--- + +# 装饰模式简介 + +装饰(Decorator)模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。 + +它以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。 + + + +装饰模式的类图如下: +![pattern10_01](/images/media/pattern10_01.jpg) + +装饰模式包含了三个角色: **抽象构件(Component),具体构件(ConcreteComponent) ,装饰(Decorator) 和 具体装饰(ConcreteDecorator)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象构件(Component) | 给出一个抽象接口,以规范准备接收附加责任的对象。 | +| 具体构件(ConcreteComponent) | 定义一个将要接收附加责任的类。 | +| 装饰(Decorator) | 持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。 | +| 具体装饰(ConcreteDecorator) | 负责给构件对象“贴上”附加的责任。 | + + + +示意代码 + + public interface Component { + // 商业方法 + public void sampleOperation(); + } + + public class ConcreteComponent implements Component { + // 构造函数 + public ConcreteComponent() { + // write your code here + } + + @Override + public void sampleOperation() { + // 写相关的业务代码 + } + } + + public class Decorator implements Component{ + private Component component; + + // 构造函数 + public Decorator(Component component){ + // write your code here + } + + // 构造函数 + public Decorator(Component component){ + this.component = component; + } + + @Override + public void sampleOperation() { + // 商业方法,委派给构件 + component.sampleOperation(); + } + } + + public class ConcreteDecorator extends Decorator { + + @Override + public void sampleOperation() { + super.sampleOperation(); + // write your code here + } + } + +需要指出的是: +(01) 在装饰类Decorator中,有一个私有树形component,其数据结构是构件(Component)。 +(02) 装饰类Decorator实现了构件(Component)接口。 +(03) Decorator类中,接口的每一个实现方法都委派给父类,但并不单纯地委派,而是有功能的增强。 + +# 装饰模式示例 + +下面,通过"齐天大圣"的例子来对装饰模式进行说明。 + +孙悟空有七十二般变化,他的每一种变化都给他带来一种附加的本领。他变成鱼儿时,就可以到水里游泳;他变成鸟儿时,就可以在天上飞行。 + +在装饰模式中,Component的角色便由鼎鼎大名的齐天大圣扮演;ConcreteComponent的角色属于大圣的本尊,就是猢狲本人;Decorator的角色由大圣的七十二变扮演。而ConcreteDecorator的角色便是花、鸟、鱼、虫等七十二般变化。它的类图如下: +![pattern10_02](/images/media/pattern10_02.jpg) + +示例代码 + +## 抽象构件(Component) + +抽象构件是"齐天大圣",它包行了move()接口。 + + abstract public class GreatSage { + public abstract void move(); + } + + + +## 具体构件(ConcreteComponent) +具体构件属于大圣的本尊,就是孙悟空。 + + public class Monkey extends GreatSage { + @Override + public void move() { + System.out.println("Monkey Move"); + } + } + + + +## 装饰(Decorator) + +装饰由大圣的七十二变扮演。 + + public class Change extends GreatSage { + private GreatSage sage; + + public Change(GreatSage sage){ + this.sage = sage; + } + + @Override + public void move() { + sage.move(); + } + } + + + +## 具体装饰(ConcreteDecorator)。 + +花 + + public class Flower extends Change { + + public Flower(GreatSage sage) { + super(sage); + } + + @Override + public void move() { + System.out.println("Flower Move"); + } + } + +鸟 + + public class Bird extends Change { + + public Bird(GreatSage sage) { + super(sage); + } + + @Override + public void move() { + System.out.println("Bird Move"); + } + } + + + +鱼 + + public class Fish extends Change { + + public Fish(GreatSage sage) { + super(sage); + } + + @Override + public void move() { + System.out.println("Fish Move"); + } + } + + + +虫 + + public class Insect extends Change { + + public Insect(GreatSage sage) { + super(sage); + } + + @Override + public void move() { + System.out.println("Insect Move"); + } + } + + + +## 客户端测试程序 + + public class Client { + + public static void main(String[] args) { + GreatSage sage = new Monkey(); + + // 1. "齐天大圣" + sage.move(); + + // 2. "齐天大圣"变成"鸟"之后,再变成"鱼" + GreatSage bird = new Bird(sage); + GreatSage fish = new Fish(bird); + fish.move(); + + // 3. "齐天大圣"变成"昆虫"之后,再变成"花" + GreatSage flower = new Flower(new Insect(sage)); + flower.move(); + } + } + +运行结果: + + Monkey Move + Fish Move + Flower Move + +结果说明:上面的例子的2中,系统把大圣从一只猢狲装饰成了一只鸟儿(把鸟儿的功能加到了猢狲身上),然后又把鸟儿装饰成了一条鱼儿(把鱼儿的功能加到了猢狲+鸟儿身上,得到了猢狲+鸟儿+鱼儿)。如下图所示: +![pattern10_03](/images/media/pattern10_03.jpg) +![pattern10_04](/images/media/pattern10_04.jpg) diff --git "a/source/_posts/2014-05-24-\350\256\276\350\256\241\346\250\241\345\274\21711\344\271\213-\344\273\243\347\220\206-Proxy-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" "b/source/_posts/2014-05-24-\350\256\276\350\256\241\346\250\241\345\274\21711\344\271\213-\344\273\243\347\220\206-Proxy-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" new file mode 100644 index 0000000..28e35dd --- /dev/null +++ "b/source/_posts/2014-05-24-\350\256\276\350\256\241\346\250\241\345\274\21711\344\271\213-\344\273\243\347\220\206-Proxy-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" @@ -0,0 +1,143 @@ +--- +title: 设计模式11之 代理(Proxy)模式(结构模式) +date: 2014-05-24 11:08:47 +categories: +- 设计模式 +tags: +- java +- 代理模式 +--- +# 代理模式简介 + +代理(Proxy)模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。 + +一个比较典型的例子就是"Windows的快捷方式"。Windows快捷方式,可以使任何对象同时出现在多个地方而不必修改原对象。对快捷方式的调用完全与对原对象的调用一样,换言之,快捷方式对客户端是完全透明的。 + + + +代理模式的类图如下: +![pattern11_01](/images/media/pattern11_01.jpg) + +代理模式中共包含了三个角色: **抽象主体(Subject),代理主题(ProxySubject),真实主题(RealSubject)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象主题角色 | 声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以使用代理主题。 | +| 代理主题角色 | 代理主题内部含有真实主题的引用,从而可以在任何时候操作真实主题;代理主题提供一个与真实主题相同的接口,以便可以在任何时候替代真实主题。代理主题通常在客户端调用传递给真实主题之前或之后,执行某个操作,而不是单纯地将调用传递给真实主题。 | +| 真实主题角色 | 定义了代理主题所代表的真实主题。 | + + + +示意代码 + + abstract public class Subject { + // 声明一个抽象的请求方法 + public abstract void request(); + } + + public class RealSubject extends Subject { + @Override + public void request() { + System.out.println("From real subject"); + } + } + + public class ProxySubject extends Subject{ + RealSubject realSubject = new RealSubject(); + + @Override + public void request() { + preRequest(); + realSubject.request(); + postRequest(); + } + + // 请求前的操作 + private void preRequest() { + // something you want to do before requesting + } + + // 请求后的操作 + private void postRequest() { + // something you want to do after requesting + } + } + + + +若要使用代理主题,则可以通过以下代码: + + Subject subject = new ProxySubject(); + subject.request(); + +从中可以看出代理模式是怎样工作的。首先,代理模式并不改变主题的接口,因为代理模式的用意是不让客户端感觉到代理的存在;其次,代理使用委派将客户端的调用委派给真实的主题对象;换言之,代理主题起到的是一个传递请求的作用。最后,代理主题在传递请求之前和之后都可以执行特定的操作,而不是单纯的传递请求。 + +它的时序图如下: +![pattern11_02](/images/media/pattern11_02.jpg) + +# 代理模式示例 + +下面,通过"高老庄悟空降八戒"的例子来对代理模式进行说明。 + +悟空假扮成高小姐去见猪八戒。通过代理模式去分析,"高小姐的神貌"是抽象主题,高小姐本人是真实主题,而悟空是代理主题,他巧妙的实现了"高小姐的神貌";猪八戒就是客户端,猪八戒根本分不清"悟空假扮的高小姐"和"高小姐本人"。 + +对应的类图如下: +![pattern11_03](/images/media/pattern11_03.jpg) + +下面是各个角色对应的类。 + +## 抽象主体 + +抽象主题是"高小姐的神貌",它对应的类是AbstractAppearance。 + + abstract public class AbstractAppearance { + public abstract void smile(); + } + + +## 真实主题 + +真实主题是"高小姐本人",它对应的类是MissGao。 + + public class MissGao extends AbstractAppearance { + @Override + public void smile() { + System.out.println("Miss Gao smiles."); + } + } + + +## 代理主题 + +代理主题是"悟空",它对应的类是WuKong。 + + public class WuKong extends AbstractAppearance { + AbstractAppearance missGao = new MissGao(); + + @Override + public void smile() { + missGao.smile(); + System.out.println("Actual, it's wukong smiles."); + } + } + + + +## 客户端测试程序 + +客户端是"八戒",它对应的类是BaJie。 + + public class BaJie { + public static void main(String[] args) { + // 八戒只认识"高小姐的样貌",而该"高小姐的样貌"实际上是悟空假扮的。 + AbstractAppearance appearance = new WuKong(); + appearance.smile(); + } + } + + + +运行结果: + + Miss Gao smiles. + Actual, it's wukong smiles. diff --git "a/source/_posts/2014-05-25-\350\256\276\350\256\241\346\250\241\345\274\21712\344\271\213-\344\272\253\345\205\203-Flyweight-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" "b/source/_posts/2014-05-25-\350\256\276\350\256\241\346\250\241\345\274\21712\344\271\213-\344\272\253\345\205\203-Flyweight-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" new file mode 100644 index 0000000..bb9c4b2 --- /dev/null +++ "b/source/_posts/2014-05-25-\350\256\276\350\256\241\346\250\241\345\274\21712\344\271\213-\344\272\253\345\205\203-Flyweight-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" @@ -0,0 +1,376 @@ +--- +title: 设计模式12之 享元(Flyweight)模式(结构模式) +date: 2014-05-25 11:09:05 +categories: +- 设计模式 +tags: +- java +- 享元模式 +--- +# 享元模式简介 + +享元模式(Flyweight)是对象的结构模式,它以共享的方式高效地支持大量的细粒度对象。 + +它的好处是,通过共享来避免大量拥有相同内容对象的开销。 + +享元模式中的对象称为享元对象,享元对象分为内蕴状态和外蕴状态。 +内蕴对象和外蕴对象是相互独立的:内蕴状态是存储在享元对象内部,并且不会随环境改变而有所不同的;内蕴状态是可以共享。外蕴状态是随环境改变而改变,不可以共享的状态;享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。 + + + +一个比较典型的享元模式示例就是:"Java中的String对象"。 + +例如,定义一个String常量a和b,它们的值为"hello",定义如下: + + String a="hello"; + String b="hello"; + +实际上,a和b都是存在常量池中。由于a和b的值都是"hello",它们实际上是常量池的同一个对象! + +常量池(constant pool)指的是在编译期就被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。 + + + +## String示例1 + + public class String1 { + public static void main(String[] args) { + String a = "hello"; + String b = "hello"; + String c = "he"+"llo"; + System.out.println(a==b); + System.out.println(a==c); + } + } + +运行结果: + + true + true + +结果说明: +(01) a和b中的"hello"都是字符串常量,它们存储在常量池中,在编译期就被确定了,所以a==b为true。 +(02) "he"和"llo"也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以c也同样在编译期就被解析为一个字符串常量,所以c也是常量池中"hello"的一个引用。 + + + +## String示例2 + + public class String2 { + public static void main(String[] args) { + String a = "hello"; + String b = new String("hello"); + String c = "he"+new String("llo"); + System.out.println(a==b); + System.out.println(a==c); + System.out.println(b==c); + } + } + +运行结果: + + false + false + false + +结果说明:a还是常量池中"hello"字符串常量;而b则无法在编译期确定,它是运行时创建"hello"对象的引用;而c因为有后半部分new String("llo"),所以c也无法在编译期确定,因此,c也是一个新创建的"hello"对象的应用。 + + +继续回到享元模式。它分为"**单纯享元模式**" 和 "**复合享元模式**"。 + + + +# 单纯享元模式 + +在单纯的享元模式中,所有的享元对象都是可以共享的。它的UML类图如下: +![pattern12_01](/images/media/pattern12_01.jpg) + +单纯享元模式涉及到的角色:**抽象享元(Flyweight),具体享元(ConcreteFlyweight),享元工厂(FlyweightFactory)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象享元 | 该角色是所有的具体享元类的超类,它给出了具体享元类需要实现的公共接口。 | +| 具体享元 | 实现抽象享元角色所规定出的接口。 | +| 享元工厂 | 本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。 | + + +## 抽象享元 + + abstract public class Flyweight { + // 示意性方法,参数state是外蕴状态。 + public abstract void operation(String state); + } + + + +## 具体享元 + + public class ConcreteFlyweight extends Flyweight { + private Character intrinsicState = null; + + // 内蕴状态作为参数传入 + public ConcreteFlyweight(Character state) { + this.intrinsicState = state; + } + // 外蕴状态作为参量传入方法中,改变方法的行为。 + public void operation(String state) { + System.out.println("\tIntrisic State=" + + intrinsicState + + ", Extriinsic State="+state); + } + } + + + +## 享元工厂 + + import java.util.Map; + import java.util.HashMap; + import java.util.Iterator; + + public class FlyweightFactory { + private HashMap flies = new HashMap(); + + public Flyweight factory(Character state) { + if (flies.containsKey(state)) { + System.out.println(state+" exists."); + return (Flyweight)flies.get(state); + } else { + System.out.println(state+" not exists!"); + Flyweight fly = new ConcreteFlyweight(state); + flies.put(state, fly); + return fly; + } + } + } + + + +## 客户端测试程序 + + public class Client { + + public static void main(String[] args) { + FlyweightFactory factory = new FlyweightFactory(); + Flyweight fly = factory.factory(new Character('a')); + fly.operation("First Call"); + + fly = factory.factory(new Character('b')); + fly.operation("Second Call"); + + fly = factory.factory(new Character('a')); + fly.operation("Third Call"); + } + } + + + +运行结果: + + a not exists! + Intrisic State=a, Extriinsic State=First Call + b not exists! + Intrisic State=b, Extriinsic State=Second Call + a exists. + Intrisic State=a, Extriinsic State=Third Call + +结果说明: + +抽象享元类Flyweight提供了operation()公共接口。 +具体享元类ConcreteFlyweight实现了抽象享元所给定的接口。 +享元工厂类FlyweightFactory负责创建和管理享元角色。 +客户端不能直接将具体享元类实例化,而必须通过调用工厂对象的factory()来获取享元对象。 +在示例中,虽然客户端申请了三个享元对象,但是实际创建的享元对象只有两个,这就是共享的含义。 + +# 复合享元模式 + +在单纯享元模式中,所有的享元对象都是单纯享元对象,也就是说都是可以直接共享的。而还有一种较为复杂的情况,将一些单纯享元使用合成模式加以复合,形成复合享元对象。这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。 + +复合享元模式的UML类图如下: +![pattern12_02](/images/media/pattern12_02.jpg) + +复合享元角色所涉及到的角色如下:**抽象享元(Flyweight),具体享元(ConcreteFlyweight),复合享元(ConcreteCompositeFlyweight),享元工厂(FlyweightFactory)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象享元 | 该角色是所有的具体享元类的超类,它给出了具体享元类需要实现的公共接口。 | +| 具体享元 | 实现抽象享元角色所规定出的接口。 | +| 复合享元 | 复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称作不可共享的享元对象。 | +| 享元工厂 | 本角色负责创建和管理享元角色。 | + + + +## 抽象享元 + +抽象享元类是Flyweight,它定义了operation()公共接口,operation()方法接收一个外蕴状态作为参量。 + + abstract public class Flyweight { + // 示意性方法,参数state是外蕴状态 + public abstract void operation(String state); + } + + + +## 具体享元 + +具体享元类是ConcreteFlyweight。它主要责任有两个: +(01) 实现抽象享元所定义的接口operation()。 +(02) 为内涵状态提供存储空间,也就是ConcreteFlyweight中的intrinsicState树形。 + + public class ConcreteFlyweight extends Flyweight { + private Character intrinsicState = null; + + // 构造函数,内蕴状态作为参数传入 + public ConcreteFlyweight(Character state){ + this.intrinsicState = state; + } + + // 外蕴状态作为参数传入方法中,改变方法的行为, + @Override + public void operation(String state) { + System.out.println("\tIntrisic State=" + + intrinsicState + + ", Extriinsic State="+state); + } + } + + + +## 复合享元 + +复合享元类是ConcreteCompositeFlyweight。 + +复合享元是由"单纯享元"对象通过复合而成,因此,它提供了add()这样的聚集管理方法。由于一个复合享元对象具有不同的聚集元素,这些聚集元素在复合享元对象被创建之后加入,这本身就意味着复合享元对象的状态是会改变的,因此复合享元对象是不能共享的。 + +此外,复合享元角色实现了抽象享元角色所规定的接口,也就是operation()方法,这个方法有一个参数,代表复合享元对象的外蕴状态。一个复合享元对象的所有单纯享元对象元素的外蕴状态都是与复合享元对象的外蕴状态相等的;而一个复合享元对象所含有的单纯享元对象的内蕴状态一般是不相等的,不然就没有使用价值了。 + + import java.util.Map; + import java.util.HashMap; + import java.util.Iterator; + + // 复合享元:它由若干个"单纯享元对象"组成。 + public class ConcreteCompositeFlyweight extends Flyweight { + + private HashMap flies = new HashMap(); + private Flyweight flyweight; + + // 增加一个新的单纯享元对象到复合享元中 + public void add(Character key , Flyweight fly) { + flies.put(key,fly); + } + + // 外蕴状态作为参数传入到方法中 + @Override + public void operation(String state) { + Flyweight fly = null; + for (Iterator it = flies.entrySet().iterator(); + it.hasNext(); ) { + Map.Entry e = (Map.Entry) it.next(); + fly = (Flyweight) e.getValue(); + fly.operation(state); + } + } + } + + + +## 享元工厂 + +享元工厂是FlyweightFactory类。 + +享元工厂提供两种不同的"返回抽象享元"的方法,一种用于提供单纯享元对象,另一种用于提供复合享元对象。 + +当需要单纯享元的时候,就调用factory(),并传入Character类型的参数。 +当需要复合享元的时候,就调用factory(),并传入String类型的参数。 + + import java.util.Map; + import java.util.HashMap; + import java.util.Iterator; + + public class FlyweightFactory { + private HashMap flies = new HashMap(); + + // 创建"复合享元"的工厂方法 + public Flyweight factory(String compositeState){ + ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight(); + int length = compositeState.length(); + Character state = null; + for (int i=0; i + +![pattern13_01](/images/media/pattern13_01.jpg) + +而如果引"进门面模式",在医院中增加一个接待员。由接待员负责代为挂号、划价、缴费、取药等,病人只接触接待员,由接待员与各个部门打交道。这样,对病人来说,就会简单很多。如下图所示: +![pattern13_02](/images/media/pattern13_02.jpg) + +下面看看门面模式的UML类图: +![pattern13_03](/images/media/pattern13_03.jpg) + +门面模式包括2个角色:**门面(Facade),子系统(SubSystem)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 门 面 | 客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。 | +| 子系统 | 可以同时有一个或者多个子系统。每个子系统都不是一个单独的类,而是一个类的集合。每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。 | + + +# 门面模式示例 + +一个保安系统由两个录像机、三个电灯、一个遥控器和一个警报器组成。保安系统的操作人员在早上上班的时候,将这些仪器打开;晚上下班之后,会将这些仪器关闭。 + +我们先演示在不使用"门面模式"的情况下,实现该系统。然后,通过"门面模式"实现该系统。 + + + +## 未使用"门面模式" + +UML类图如下: +![pattern13_04](/images/media/pattern13_04.jpg) + +从图中可以看出,客户端Client对象需要引用到录像机(Camera)、电灯(Light)、感应器(Sensor)和报警器(Alarm)所有的对象。 + +客户端(Client)源码 + + public class Client { + + private static Camera camera1, camera2; + private static Light light1, light2, light3; + private static Sensor sensor; + private static Alarm alarm; + + public static void main(String[] args) { + camera1 = new Camera(); + camera2 = new Camera(); + light1 = new Light(); + light2 = new Light(); + light3 = new Light(); + sensor = new Sensor(); + alarm = new Alarm(); + + camera1.turnOn(); + camera2.turnOn(); + light1.turnOn(); + light2.turnOn(); + light3.turnOn(); + sensor.activate(); + alarm.activate(); + } + } + +录像机(Camera)源码 + + public class Camera { + // 打开录像机 + public void turnOn() { + System.out.println("Turning on the camera."); + } + // 关闭录像机 + public void turnOff() { + System.out.println("Turning off the camera."); + } + // 转动录像机 + public void rotate(int degrees) { + System.out.println("Rotating the camera by "+degrees+" degrees."); + } + } + +电灯(Light)源码 + + public class Light { + // 打开灯 + public void turnOn() { + System.out.println("Turning on the light."); + } + // 关闭灯 + public void turnOff() { + System.out.println("Turning off the light."); + } + // 换灯泡 + public void changeBulb() { + System.out.println("Cotating the light-bulb."); + } + } + +感应器(Sensor)源码 + + public class Sensor { + // 启动感应器 + public void activate() { + System.out.println("Activating on the sensor."); + } + // 关闭感应器 + public void deactivate() { + System.out.println("Deactivating the sensor."); + } + // 触发感应器 + public void trigger() { + System.out.println("The sensor has been triggered."); + } + } + +报警器(Alarm)源码 + + public class Alarm { + // 启动警报器 + public void activate() { + System.out.println("Activating on the alarm."); + } + // 关闭警报器 + public void deactivate() { + System.out.println("Deactivating the alarm."); + } + // 拉响警报器 + public void ring() { + System.out.println("Ringing the alarm"); + } + // 停掉警报器 + public void stopRing() { + System.out.println("Stop the alarm"); + } + } + +运行结果: + + Turning on the camera. + Turning on the camera. + Turning on the light. + Turning on the light. + Turning on the light. + Activating on the sensor. + Activating on the alarm. + + + +## 使用"门面模式" + +UML类图如下: +![pattern13_05](/images/media/pattern13_05.jpg) + +可以看出:门面SecurityFade承担了与保安系统内部各个对象打交道的任务,而客户对象只需要与门面对象打交道即可。SecurityFade是客户端与保安系统之间的一个门户,它使得客户端与子系统之间的关系变得简单和易于管理。 + +客户端(Client)源码 + + public class Client { + + private static SecurityFacade security; + + public static void main(String[] args) { + security = new SecurityFacade(); + security.activate(); + } + } + +门面(SecurityFade)源码 + + public class SecurityFacade { + + private Camera camera1, camera2; + private Light light1, light2, light3; + private Sensor sensor; + private Alarm alarm; + + public SecurityFacade() { + camera1 = new Camera(); + camera2 = new Camera(); + light1 = new Light(); + light2 = new Light(); + light3 = new Light(); + sensor = new Sensor(); + alarm = new Alarm(); + } + + public void activate() { + camera1.turnOn(); + camera2.turnOn(); + light1.turnOn(); + light2.turnOn(); + light3.turnOn(); + sensor.activate(); + alarm.activate(); + } + + public void deactivate() { + camera1.turnOff(); + camera2.turnOff(); + light1.turnOff(); + light2.turnOff(); + light3.turnOff(); + sensor.deactivate(); + alarm.deactivate(); + } + + } + +录像机(Camera)源码 + + public class Camera { + // 打开录像机 + public void turnOn() { + System.out.println("Turning on the camera."); + } + // 关闭录像机 + public void turnOff() { + System.out.println("Turning off the camera."); + } + // 转动录像机 + public void rotate(int degrees) { + System.out.println("Rotating the camera by "+degrees+" degrees."); + } + } + +电灯(Light)源码 + + public class Light { + // 打开灯 + public void turnOn() { + System.out.println("Turning on the light."); + } + // 关闭灯 + public void turnOff() { + System.out.println("Turning off the light."); + } + // 换灯泡 + public void changeBulb() { + System.out.println("Cotating the light-bulb."); + } + } + +感应器(Sensor)源码 + + public class Sensor { + // 启动感应器 + public void activate() { + System.out.println("Activating on the sensor."); + } + // 关闭感应器 + public void deactivate() { + System.out.println("Deactivating the sensor."); + } + // 触发感应器 + public void trigger() { + System.out.println("The sensor has been triggered."); + } + } + +报警器(Alarm)源码 + + public class Alarm { + // 启动警报器 + public void activate() { + System.out.println("Activating on the alarm."); + } + // 关闭警报器 + public void deactivate() { + System.out.println("Deactivating the alarm."); + } + // 拉响警报器 + public void ring() { + System.out.println("Ringing the alarm"); + } + // 停掉警报器 + public void stopRing() { + System.out.println("Stop the alarm"); + } + } + +运行结果: + + Turning on the camera. + Turning on the camera. + Turning on the light. + Turning on the light. + Turning on the light. + Activating on the sensor. + Activating on the alarm. diff --git "a/source/_posts/2014-05-27-\350\256\276\350\256\241\346\250\241\345\274\21714\344\271\213-\346\241\245\346\242\201-Bridge-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" "b/source/_posts/2014-05-27-\350\256\276\350\256\241\346\250\241\345\274\21714\344\271\213-\346\241\245\346\242\201-Bridge-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" new file mode 100644 index 0000000..d01b61d --- /dev/null +++ "b/source/_posts/2014-05-27-\350\256\276\350\256\241\346\250\241\345\274\21714\344\271\213-\346\241\245\346\242\201-Bridge-\346\250\241\345\274\217-\347\273\223\346\236\204\346\250\241\345\274\217.md" @@ -0,0 +1,245 @@ +--- +title: 设计模式14之 桥梁(Bridge)模式(结构模式) +date: 2014-05-27 11:09:42 +categories: +- 设计模式 +tags: +- java +- 桥梁模式 +--- + +# 桥梁模式简介 + +  桥梁模式(Bridge),又称为柄体(Handle and Body)模式或接口(Interface)模式。它属于对象的结构模式,其用意是“将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化”。 + +  这句话有三个关键词:**"抽象化"、"实现化"和"脱耦"**。 + + + +  • **抽象化** + +  存在于多个实体中的共同的概念联系,就是抽象话。例如,苹果、葡萄、草莓,它们的共同特征就是水果,因此,水果是它们的抽象化存在;圆形、正方形、三角形,它们的共同特征就是形状,因此,形状就是它们的抽象话。 + +  通常情况下,一组对象如果具有相同的特征,那么它们就可以通过一个共同的类来描述。如果一些类具有相同的特征,往往可以通过一个共同的抽象类来描述。 + +  • **实现化** + +  抽象化给出的具体实现,就是实现化。 + +  一个类的实例就是这个类的实例化,一个具体子类是它的抽象超类的实例化。 + +  • **脱耦** + +  所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。 + +  所谓强关联,就是在编译时期已经确定的,无法在运行时期动态改变的关联;所谓弱关联,就是可以动态地确定并且可以在运行时期动态地改变的关联。显然,在Java语言中,继承关系是强关联,而聚合关系是弱关联。 + +  将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换成为弱关联。因此,桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用聚合关系而不是继承关系,从而使两者可以相对独立地变化。这就是桥梁模式的用意。 + +桥梁模式的UML类图 +![pattern14_01](/images/media/pattern14_01.jpg) + +从中可以看出,桥接模式含有两个等级结构: +(01) 由抽象化角色和修正抽象化角色组成的抽象化等级结构。 +(02) 由实现化角色和两个具体实现化角色所组成的实现化等级结构。 + +桥梁模式包含四种角色: **抽象化(Abstraction),修正抽象化(RefinedAbstraction),实现化(Implementor),具体实现化(ConcreteImplementor)**。 +• 抽象化: 抽象化给出的定义,并保存一个对实现化对象的引用。 +• 修正抽象化: 扩展抽象化角色,改变和修正父类对抽象化的定义。 +• 实现化: 这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。 +• 具体实现化: 这个角色给出实现化角色接口的具体实现。 + +  对象是对行为的封装,而行为是由方法实现的。在这个示意性系统里,抽象化等级结构中的类封装了operation()方法;而实现化等级结构中的类封装的是operationImpl()方法。当然,在实际的系统中往往会有多于一个的方法。 + +  抽象化等级结构中的方法通过向对应的实现化对象的委派实现自己的功能,这意味着抽象化角色可以通过向不同的实现化对象委派,来达到动态地转换自己的功能的目的。 + +## 示意代码 + +抽象化 + + public abstract class Abstraction { + + protected Implementor impl; + + public Abstraction(Implementor impl){ + this.impl = impl; + } + // 商业方法 + public void operation(){ + + impl.operationImpl(); + } + } + +修正抽象化角色 + + public class RefinedAbstraction extends Abstraction { + + public RefinedAbstraction(Implementor impl) { + super(impl); + } + } + +实现化角色 + + public abstract class Implementor { + // 方法的实现化声明 + public abstract void operationImpl(); + } + +具体实现化角色 + + public class ConcreteImplementorA extends Implementor { + + // 方法的实现化实现 + @Override + public void operationImpl() { + // something you want to do + } + + } + public class ConcreteImplementorB extends Implementor { + + // 方法的实现化实现 + @Override + public void operationImpl() { + // something you want to do + } + } + +# 桥梁模式示例 + +  **问题** + +  空中巴士(Airbus)、波音(Boeing)和麦道(MD)都是飞机制造商,它们都生成载客飞机(PassengerPlane)和载货飞机(CargoPlane)。现在需要设计一个系统,描述这些飞机制造商以及它们所制造的飞机种类。 + + + +  **设计方案一(不使用桥梁模式)** + +  系统是关于飞机的,因此可以设计一个总的飞机接口,叫做Airplane。其它所有的飞机都是这个总接口的字接口或者具体实现。 + +  下面是这个方案的设计图,可以看出,这是一个不太高明的设计,导致了理不清的关系。 +![pattern14_02](/images/media/pattern14_02.jpg) + +  在这个设计方案里面,出现了两个子接口,分别代表客户和货机。所有的具体飞机又要继承自Airbus,Boeing和MD等超类。这样一类,每个具体飞机都带有两个超类:飞机制造商类型,客、货机类型。 + + + +  **设计方案二(使用桥梁模式)** + +  使用桥梁模式的关键在于准确的找出这个系统的抽象化角色和具体化角色。从系统所面对的问题不难看出,代表飞机的抽象化是它的类型,也就是"客户"或者"货机";而代表飞机的实现化的则是飞机的制造商。 + +使用桥梁模式,对应的UML类图如下: +![pattern14_03](/images/media/pattern14_03.jpg) + +## 抽象化类 + + abstract public class Airplane { + // 飞机制造商 + protected AirplaneMaker maker; + + // 指定飞机制造商 + public Airplane(AirplaneMaker maker) { + this.maker = maker; + } + + public void fly() { + // 调用AirplaneMaker的produce()方法 + maker.produce(); + } + } + +## 修正抽象化 + +PassengerPlane代码 + + public class PassengerPlane extends Airplane { + public PassengerPlane(AirplaneMaker maker) { + super(maker); + } + + public void fly() { + super.fly(); + System.out.println("PassengerPlane fly."); + } + } + +CargoPlane代码 + + public class CargoPlane extends Airplane { + + public CargoPlane(AirplaneMaker maker) { + super(maker); + } + + public void fly() { + super.fly(); + System.out.println("CargoPlane fly."); + } + } + +## 实现化 + +AirplaneMaker代码 + + abstract public class AirplaneMaker { + // 生产飞机 + public abstract void produce() ; + } + +## 具体实现化 + +Airbus代码 + + public class Airbus extends AirplaneMaker { + public void produce() { + System.out.println("Airbus produced."); + } + } + +Boeing代码 + + public class Boeing extends AirplaneMaker { + public void produce() { + System.out.println("Boeing produced."); + } + } + +MD代码 + + public class MD extends AirplaneMaker { + public void produce() { + System.out.println("MD produced."); + } + } + +## 客户端测试程序 + + public class Client { + + public static void main(String[] args) { + // "飞机制造商"为Airbus + AirplaneMaker maker = new Airbus(); + // "飞机类型"为PassengerPlane + Airplane plane = new PassengerPlane(maker); + // 飞机飞行 + plane.fly(); + + // "飞机制造商"为MD + maker = new MD(); + // "飞机类型"为CargoPlane + plane = new CargoPlane(maker); + // 飞机飞行 + plane.fly(); + } + } + + + +运行结果: + + Airbus produced. + PassengerPlane fly. + MD produced. + CargoPlane fly. diff --git "a/source/_posts/2014-05-28-\350\256\276\350\256\241\346\250\241\345\274\21715\344\271\213-\344\270\215\345\217\230-Immutable-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-28-\350\256\276\350\256\241\346\250\241\345\274\21715\344\271\213-\344\270\215\345\217\230-Immutable-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..d46f9b8 --- /dev/null +++ "b/source/_posts/2014-05-28-\350\256\276\350\256\241\346\250\241\345\274\21715\344\271\213-\344\270\215\345\217\230-Immutable-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" @@ -0,0 +1,252 @@ +--- +title: 设计模式15之 不变(Immutable)模式(行为模式) +date: 2014-05-28 11:10:00 +categories: +- 设计模式 +tags: +- java +- 不变模式 +--- + +# 不变模式简介 + +一个对象的状态在对象被创建之后就不再变化,这就是所谓的不变(Immutable)模式。 + + + +## 不变模式的结构 + +  不变模式可增强对象的强壮型(robustness)。不变模式允许多个对象共享某一个对象,降低了对该对象进行并发访问时的同步化开销。如果需要修改一个不变对象的状态,那么就需要建立一个新的同类型对象,并在创建时将这个新的状态存储在新对象里。 + +  不变模式只涉及到一个类。一个类的内部状态创建后,在整个生命周期都不会发生变化时,这样的类称作不变类。这种使用不变类的做法叫做不变模式。不变模式有两种形式:一种是弱不变模式,另一种是强不变模式。 + +## 弱不变模式 + +  一个类的实例的状态是不可改变的;但是这个类的子类的实例具有可能会变化的状态。这样的类符合弱不变模式的定义。要实现弱不变模式,一个类必须满足下面条件: + +(01) 所考虑的对象没有任何方法会修改对象的状态;这样一来,当对象的构造函数将对象的状态初始化之后,对象的状态便不再改变。 +(02) 所有属性都应当是私有的。不要声明任何的公开的属性,以防客户端对象直接修改任何的内部状态。 +(03) 这个对象所引用到的其他对象如何是可变对象的话,必须设法限制外界对这些可变对象的访问,以防止外界修改这些对象。如何可能,应当尽量在不变对象内部初始化这些被引用的对象,而不要在客户端初始化,然后再传入到不变对象内部来。如果某个可变对象必须在客户端初始化,然后再传入到不变对象里的话,就应当考虑在不变对象初始化的时候,将这个可变对象复制一份,而不要使用原来的拷贝。 + +弱不变模式的缺点是: +第一, 一个弱不变对象的子对象可以是可变对象;换言之,一个弱不变对象的子对象可能是可变的。 +第二, 这个可变的子对象可能可以修改父对象的状态,从而可能会允许外界修改父对象的状态。 + + + +## 强不变模式 + +  一个类的实例不会改变,同时它的子类的实例也具有不可变化的状态。这样的类符合强不变模式。要实现强不变模式,一个类必须首先满足弱不变模式所要求的所有条件,并且还有满足下面条件之一: +(01) 所考虑的类所有的方法都应当是final,这样这个类的子类不能够置换掉此类的方法。 +(02) 这个类本身就是final的,那么这个类就不可能会有子类,从而也就不可能有被子类修改的问题。 + + + +# 不变模式示例 + +通过以下几个示例来看看"弱不变模式"和"强不变模式"。 + +## 可变模式 + + class Person { + private String name; + private int age; + public Person(String name, int age) { + this.name = name; + this.age = age; + } + public void setName(String name) { this.name = name; } + public String getName() { return name; } + public void setAge(int age) { this.age = age; } + public int getAge() { return age; } + + public String toString() { + return "name:"+name+", age:"+age; + } + } + + // Complex不是"弱不变类"。 + // 因为它包含了可变类对象person,并且person是在外部初始化的。 + class Complex { + private Person person; + private int id; + + public Complex (Person person, int id) { + this.person = person; + this.id = id; + } + + public int getId() { return id; } + public Person getPerson() { return person; } + + public String toString() { + return "id:"+id+", person("+person+")"; + } + } + + public class MutableDemo { + public static void main(String[] args) { + // 新建Complex对象,在"外部(即,非Complex内部)"初始化person。 + Person person = new Person("张三", 18); + Complex com = new Complex(person, 1); + System.out.println(com); + + // 修改person的名字为"李四",年龄为20 + person.setName("李四"); + person.setAge(20); + System.out.println(com); + } + } + +运行结果: + + id:1, person(name:张三, age:18) + id:1, person(name:李四, age:20) + +结果说明: +MutableDemo中的Complex类满足"弱不变模式"的前2个条件: +(01) Complex中没有方法可以修改对象的状态。Complex包含了person和id两个属性值,但是没有方法修改这两个树形。 +(02) Complex中的person和id属性都是私有的。 +  但是,Complex不满足"若不变模式"的第3个条件。Complex引用了"可变类对象person",person是Person类的对象,而Person是一个可变类! +  所以,在MutableDemo中,我们初始化了Complex的person值为("张三",18)之后;在后面修改了person的名字为"李四",年龄为18。Complex中的person的值也会相应的改变!所以,Complex是"可变类"。 + +  若想将Complex修改为"不变类",需要将Complex修改的满足"若不变模式"的第3个条件。方法是,在Complex中初始化person的时候,创建一个person的拷贝即可。详细代码请看"2. 弱不变模式"。 + + + +## 弱不变模式 + + class Person { + private String name; + private int age; + public Person(String name, int age) { + this.name = name; + this.age = age; + } + public void setName(String name) { this.name = name; } + public String getName() { return name; } + public void setAge(int age) { this.age = age; } + public int getAge() { return age; } + + public String toString() { + return "name:"+name+", age:"+age; + } + } + + // Complex是"弱不变类"。 + // 它虽然包含了可变的外部对象person,但是Complex内部的person是不会改变的。因为它保存的是person的拷贝。 + class Complex { + private Person person; + private int id; + + public Complex (Person person, int id) { + // 新建一个person的拷贝。 + this.person = new Person(person.getName(), person.getAge()); + this.id = id; + } + + public int getId() { return id; } + public Person getPerson() { return person; } + + public String toString() { + return "id:"+id+", person("+person+")"; + } + } + + public class WeakImmutable { + public static void main(String[] args) { + // 新建Complex对象。 + // id是1, person的名字是"张三",年龄是18 + Person person = new Person("张三", 18); + Complex com = new Complex(person, 1); + System.out.println(com); + + // 修改person的名字为"李四",年龄为20 + person.setName("李四"); + person.setAge(20); + System.out.println(com); + } + } + +运行结果: + + id:1, person(name:张三, age:18) + id:1, person(name:张三, age:18) + +结果说明:WeakImmutable相比MutableDemo,只对Complex的构造函数进行了修改。Complex同时满足"弱不变模式"的3个条件,因此,它就是个不变模式。 + + + +## 强不变模式 + + class Person { + private String name; + private int age; + public Person(String name, int age) { + this.name = name; + this.age = age; + } + public void setName(String name) { this.name = name; } + public String getName() { return name; } + public void setAge(int age) { this.age = age; } + public int getAge() { return age; } + + public String toString() { + return "name:"+name+", age:"+age; + } + } + + // Complex是"强不变类"。 + final class Complex { + private final Person person; + private final int id; + + public Complex (Person person, int id) { + // 新建一个person的拷贝。 + this.person = new Person(person.getName(), person.getAge()); + this.id = id; + } + + public final int getId() { return id; } + public final Person getPerson() { return person; } + + public String toString() { + return "id:"+id+", person("+person+")"; + } + } + + public class StrongImmutable { + public static void main(String[] args) { + // 新建Complex对象。 + // id是1, person的名字是"张三",年龄是18 + Person person = new Person("张三", 18); + Complex com = new Complex(person, 1); + System.out.println(com); + + // 修改person的名字为"李四",年龄为20 + person.setName("李四"); + person.setAge(20); + System.out.println(com); + } + } + +运行结果: + + id:1, person(name:张三, age:18) + id:1, person(name:张三, age:18) + +结果说明: +StrongImmutable中的Complex满足"强不变模式"的要求。StrongImmutable相比WeakImmutable,进行了两个修改: +第一,将Complex中的属性和方法都修改为final类型。 +第二,将Complex类本身修改为final类型。 + +# 不变模式的优缺点 + +不变模式有很明显的优点: +(1) 因为不能修改一个不变对象的状态,所以可以避免由此引起的不必要的程序错误;换言之,一个不变的对象要比可变的对象更加容易维护。 +(2) 因为没有任何一个线程能够修改不变对象的内部状态,一个不变对象自动就是线程安全的,这样就可以省掉处理同步化的开销。一个不变对象可以自由地被不同的客户端共享。 + +不变模式的缺点: +不变模式唯一的缺点是:一旦需要修改一个不变对象的状态,就只好创建一个新的同类对象。在需要频繁修改不变对象的环境里,会有大量的不变对象作为中间结果被创建出来,再被JAVA垃圾收集器收集走。这是一种资源上的浪费。 + +在设计任何一个类的时候,应当慎重考虑其状态是否有需要变化的可能性。除非其状态有变化的必要,不然应当将它设计成不变类。 diff --git "a/source/_posts/2014-05-29-\350\256\276\350\256\241\346\250\241\345\274\21716\344\271\213-\347\255\226\347\225\245-Strategy-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" "b/source/_posts/2014-05-29-\350\256\276\350\256\241\346\250\241\345\274\21716\344\271\213-\347\255\226\347\225\245-Strategy-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..207af31 --- /dev/null +++ "b/source/_posts/2014-05-29-\350\256\276\350\256\241\346\250\241\345\274\21716\344\271\213-\347\255\226\347\225\245-Strategy-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" @@ -0,0 +1,169 @@ +--- +title: 设计模式16之 策略(Strategy)模式(行为模式) +date: 2014-05-29 11:10:17 +categories: +- 设计模式 +tags: +- java +- 策略模式 +--- +# 策略模式简介 + +策略(Strategy)模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。 + + + +UML类图 +![pattern16_01](/images/media/pattern16_01.jpg) + +这个模式涉及到三个角色:**环境(Context),抽象策略(Strategy),具体策略(ConcreteStrategy)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 环境 | 持有一个Strategy的引用。 | +| 抽象策略 | 这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。 | +| 具体策略 | 包装了相关的算法或行为。 | + +示意代码 + + public class Context { + // 策略对象 + private Strategy strategy; + + // 构造函数 + public Context(Strategy strategy){ + this.strategy = strategy; + } + + // 策略方法 + public void contextInterface(){ + strategy.strategyInterface(); + } + } + + abstract public class Strategy { + // 策略方法 + public abstract void strategyInterface(); + } + + public class ConcreteStrategy extends Strategy { + + @Override + public void strategyInterface() { + // write your algorithm code here + } + } + + +# 策略模式示例 + +假设现在要设计一个贩卖各类书籍的电子商务的购物车系统。下面是图书的三种折扣算法。 + +算法一:对图书没有折扣。 +算法二:对图书提供一个固定值为5元的折扣。 +算法三:对图书提供一个八折的折扣。 + +使用策略模式描述的话,这些不同的算法都是不同的具体策略角色:用一个NoDiscountStrategy对象描述"算法一";用一个FlatRateStrategy对象描述"算法二";用一个PercentageStrage对象描述"算法三"。 + +## 抽象策略 + + abstract public class DiscountStrategy { + + // 价格 + protected int price = 0; + // 策略 + protected int copies = 0; + + public abstract int calculateDiscount(); + + public DiscountStrategy(int price, int copies) { + this.price = price; + this.copies = copies; + } + } + +## 具体策略 + +算法一(无折扣) + + public class NoDiscountStrategy extends DiscountStrategy { + + public NoDiscountStrategy(int price, int copies) { + super(price, copies); + } + + public int calculateDiscount() { + return copies*price; + } + } + +算法二(优惠5元) + + public class FlatRateStrategy extends DiscountStrategy { + + private int discard = 5; + + public FlatRateStrategy(int price, int copies) { + super(price, copies); + } + + public void setDiscard() { + this.discard = discard; + } + + public int getDiscard() { + return discard; + } + + public int calculateDiscount() { + return copies*(price - discard); + } + } + +算法三(打8折) + + public class PercentageStrategy extends DiscountStrategy { + + // 折扣比例 + private float percent = 0.8f; + + public PercentageStrategy(int price, int copies) { + super(price, copies); + } + + public void setPercent() { + this.percent = percent; + } + + public float getPercent() { + return percent; + } + + public int calculateDiscount() { + return (int)(copies*price*percent); + } + } + +## 客户端 + + public class Client { + + public static void main(String[] args) { + // 第一种策略 + DiscountStrategy strategy = new NoDiscountStrategy(60, 5); + System.out.println("total(60,5)="+strategy.calculateDiscount()); + + strategy = new FlatRateStrategy(80, 5); + System.out.println("total(80,5)="+strategy.calculateDiscount()); + + strategy = new PercentageStrategy(100, 3); + System.out.println("total(100,4)="+strategy.calculateDiscount()); + + } + } + +运行结果: + + total(60,5)=300 + total(80,5)=375 + total(100,4)=240 diff --git "a/source/_posts/2014-06-01-\350\256\276\350\256\241\346\250\241\345\274\21717\344\271\213-\346\250\241\346\235\277\346\226\271\346\263\225-Template-Method-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" "b/source/_posts/2014-06-01-\350\256\276\350\256\241\346\250\241\345\274\21717\344\271\213-\346\250\241\346\235\277\346\226\271\346\263\225-Template-Method-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..b62bb8b --- /dev/null +++ "b/source/_posts/2014-06-01-\350\256\276\350\256\241\346\250\241\345\274\21717\344\271\213-\346\250\241\346\235\277\346\226\271\346\263\225-Template-Method-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" @@ -0,0 +1,193 @@ +--- +title: 设计模式17之 模板方法(Template Method)模式(行为模式) +date: 2014-06-01 11:10:33 +categories: +- 设计模式 +tags: +- java +- 模板方法模式 +--- + +# 模板模式简介 + +  模板方法(Template Method)模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。 +  模板方法模式是所有模式中最为常见的几个模式之一,而且很可能我们自己使用过模板方法模式而没有意识到自己已经使用了这个模式。模板方法模式是基于继承的代码复用的基本技术。 +  Java的集合就是一个典型的,利用了模板方法模式的例子。Java集合中的Collection集合包括List和Set两大组成部分。List是队列,而Set是没有重复元素的集合。它们共同的接口都在Collection接口声明;例如,都包含了size(),isEmpty()方法。而AbstractCollection这个抽象类则实现了它们共同的方法,其余未实现的方法定义为抽象方法。List和Set的实例类,就是通过继承AbstractCollection(或它的子类),省去了许多重复性编码的工作! + + + +模板方法模式的UML类图: +![pattern17_01](/images/media/pattern17_01.jpg) + +这里涉及到两个角色:**抽象模板(Abstract Template),具体模板(Concrete Template)**。 + + 抽象模板有如下责任: +• 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。 +• 定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。 + + 具体模板有如下责任: +• 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。 +• 每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。 + + + +示意代码 + + + abstract public class AbstractClass { + // 模板方法 + public void templateMethod(){ + hookMethod(); //调用基本方法(由子类实现) + abstractMethod(); //调用基本方法(由子类实现) + concreteMethod(); //调用基本方法(已经实现) + } + + // 基本方法的声明(由子类实现,但抽象模板给出了默认实现) + public void hookMethod() {} + + // 基本方法的声明(由子类实现) + public abstract void abstractMethod(); + + // 基本方法(已经实现) + public final void concreteMethod(){ + // do something + } + } + + public class ConcreteClass extends AbstractClass { + // 基本方法的实现 + @Override + public void hookMethod() { + // do something + } + + // 基本方法的实现 + @Override + public void abstractMethod() { + // do something + } + } + + + +  抽象模板角色AbstractTemplate提供了两个具体方法templateMethod()和concreteMethod();声明了2个抽象方法hookMethod()和abstractMethod()。 + +  具体模板角色ConcreteTemplate实现了父类声明的基本方法hookMethod()和abstractMethod()。 + + + +
+模板方法模式中的方法 + +模板方法中的方法可以分为两大类:**模板方法** 和 **基本方法**。 + +**模板方法** + +一个模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。 +一个抽象类可以有任意多个模板方法,而不限于一个。每一个模板方法都可以调用任意多个具体方法。 + +**基本方法** + +基本方法又可以分为三种:**抽象方法(Abstract Method)、具体方法(Concrete Method)和钩子方法(Hook Method)**。 +• 抽象方法: 一个抽象方法由抽象类声明,由具体子类实现。在Java语言里抽象方法以abstract关键字标示。 +• 具体方法: 一个具体方法由抽象类声明并实现,而子类并不实现或置换。 +• 钩子方法: 一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空实现,作为方法的默认实现。 + +  在前面的UML示例中,AbstractClass是一个抽象类,它带有三个方法。其中abstractMethod()是一个抽象方法,它由抽象类声明为抽象方法,并由子类实现;hookMethod()是一个钩子方法,它由抽象类声明并提供默认实现,并且由子类置换掉。concreteMethod()是一个具体方法,它由抽象类声明并实现。 + +提示:钩子方法的名字应当以do开始。 + +# 模板方法模式示例 + +  考虑一个计算存款利息的例子。假设系统需要支持两种存款账号,即货币市场(Money Market)账号和定期存款(Certificate of Deposite)账号。这两种账号的存款利息是不同的,因此,在计算一个存户的存款利息额时,必须区分两种不同的账号类型。 + +  这个系统的总行为应当是计算出利息,这也就决定了作为一个模板方法模式的顶级逻辑应当是利息计算。由于利息计算涉及到两个步骤:一个基本方法给出账号种类,另一个基本方法给出利息百分比。这两个基本方法构成具体逻辑,因为账号的类型不同,所以具体逻辑会有所不同。 + +  显然,系统需要一个抽象角色给出顶级行为的实现,而将两个作为细节步骤的基本方法留给具体子类实现。由于需要考虑的账号有两种:一是货币市场账号,二是定期存款账号。系统的UML类图如下图所示。 + +## 抽象模板类 + + abstract public class Account { + + protected String accountNumber; + + public Account() { + accountNumber = null; + } + + public Account(String accountNumber) { + this.accountNumber = accountNumber; + } + + // 模板方法,计算利息数额 + public final double calculateInterest(){ + double interestRate = doCalculateInterestRate(); + String accountType = doCalculateAccountType(); + double amount = calculateAmount(accountType, accountNumber); + return amount * interestRate; + } + + // 基本方法留给子类实现 + protected abstract String doCalculateAccountType(); + + // 基本方法留给子类实现 + protected abstract double doCalculateInterestRate(); + + // 基本方法,已经实现 + private double calculateAmount(String accountType, String accountNumber){ + // retrive amount from database + return 7243.00D; + } + } + +## 具体模板类 + +MoneyMarketAccount + + public class MoneyMarketAccount extends Account { + + @Override + protected String doCalculateAccountType() { + return "Money Market"; + } + + @Override + protected double doCalculateInterestRate() { + return 0.045D; + } + } + +CDAccount + + public class CDAccount extends Account { + + @Override + protected String doCalculateAccountType() { + return "Certificate of Deposite"; + } + + @Override + protected double doCalculateInterestRate() { + return 0.065D; + } + } + +## 客户端测试程序 + + public class Client { + + private static Account acct = null; + public static void main(String[] args) { + acct = new MoneyMarketAccount(); + System.out.println("Interest from Money Market account: " + acct.calculateInterest()); + acct = new CDAccount(); + System.out.println("Interest from CD account: " + acct.calculateInterest()); + } + } + +运行结果: + + Interest from Money Market account: 325.935 + Interest from CD account: 470.795 + +结果说明:Account是抽象模板类,calculateInterest()是模板方法。不管是"货币市场帐号"或者"定期存款",它们的利息计算方式都是通过抽象模板类的calculateInterest()来计算的;只不过涉及到的本金和利率不同而已。 diff --git "a/source/_posts/2014-06-02-\350\256\276\350\256\241\346\250\241\345\274\21718\344\271\213-\350\247\202\345\257\237\350\200\205-Observer-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" "b/source/_posts/2014-06-02-\350\256\276\350\256\241\346\250\241\345\274\21718\344\271\213-\350\247\202\345\257\237\350\200\205-Observer-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..8384c84 --- /dev/null +++ "b/source/_posts/2014-06-02-\350\256\276\350\256\241\346\250\241\345\274\21718\344\271\213-\350\247\202\345\257\237\350\200\205-Observer-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" @@ -0,0 +1,190 @@ +--- +title: 设计模式18之 观察者(Observer)模式(行为模式) +date: 2014-06-02 11:10:51 +categories: +- 设计模式 +tags: +- java +- 观察者模式 +--- + +# 观察者模式简介 + + 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。 +  + 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 + + + + 例如,马路上的交通指示灯为红灯亮的话,汽车会停止,行人可以通行。在这个场景中,交通指示等就是被观察者,而行人和汽车则是观察者,他们会根据观察到的交通指示灯的状况作出相应的行为。 + + 观察者的UML类图如下: +![pattern18_01](/images/media/pattern18_01.jpg) + +  观察者模式所涉及的角色有:**抽象主题(Subject),具体主题(ConcreteSubject),抽象观察者(Observer),具体观察者(ConcreteObserver)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象主题 | 抽象主题角色把所有对观察者对象的引用保存在一个集合(比如Vector对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。 | +| 具体主题 | 将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。具体主题通常用一个具体子类实现。 | +| 抽象观察者 | 为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。 | +| 具体观察者 | 存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。它通常用一个具体子类实现。 | + + +## 示意代码 + +抽象主题类 + + import java.util.Vector; + import java.util.Enumeration; + + abstract public class Subject { + + private Vector observersVector = new Vector(); + + // 注册观察者对象 + public void attach(Observer observer) { + observersVector.addElement(observer); + } + + // 注销观察者对象 + public void detach(Observer observer) { + observersVector.removeElement(observer); + } + + // 通知所有注册的观察者对象 + public void notifyObservers() { + Enumeration enu = observers(); + while (enu.hasMoreElements()) { + ((Observer)enu.nextElement()).update(); + } + } + + public Enumeration observers(){ + return ((Vector)observersVector.clone()).elements(); + } + } + +具体主题类 + + public class ConcreteSubject extends Subject{ + private String state; + + // 改变主题的方法。 + public void change(String newState){ + state = newState; + this.notifyObservers(); + } + } + +抽象观察者类 + + public interface Observer { + // 通知接口 + public void update(); + } + +具体观察者类 + + public class ConcreteObserver implements Observer { + + @Override + public void update() { + System.out.println("I am notified."); + } + } + +客户端类 + + public class Client { + + private static ConcreteSubject subject; + private static Observer observer; + public static void main(String[] args) { + // 创建主题 + subject = new ConcreteSubject(); + // 创建观察者 + observer = new ConcreteObserver(); + // 将观察者注册到"主题"上 + subject.attach(observer); + // 改变主题对象的状态 + subject.change("new state"); + } + } + +运行结果: + + I am notified. + +# Java中的观察者模式 + +  Java语言本身支持"观察者模式",它提供了相应的"抽象主题类(Observable)"和"抽象观察者类(Observer)"。 + +  Observable是个实例类。它提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。 + +  Observer是一个接口。它只定义了一个方法,即update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法。 + +  下面演示Java中Observer和Observable的用法。 + +  以公鸡打鸣来建模:太阳是被观察者,公鸡是观察者;当公鸡观察到太阳升起的时候,就打鸣。 + +## 太阳 + +太阳是被观察者,它继承了Observable。 + + import java.util.Observable; + + public class Sun extends Observable { + + public void rise() { + System.out.println("Sun rise."); + // 设置"被观察者"的状态标记,表示它发生了变化。 + this.setChanged(); + // 通知"观察者"该变化。 + this.notifyObservers(); + } + } + +## 公鸡 + +公鸡是观察者,它实现了Observer对象。 + + import java.util.Observer; + import java.util.Observable; + + public class Cock implements Observer { + private Sun sun; + + public Cock(Sun sun) { + this.sun = sun; + // 将观察者Cock注册到"被观察者sun"上。 + sun.addObserver(this); + } + + // "被观察者"发生变化时,"观察者"对应的响应方法。 + @Override + public void update(Observable o, Object arg) { + System.out.println("Cock gogoda,gogoda,gogoda..."); + } + } + +## 客户端测试程序 + + public class Client { + + private static Cock cock; + private static Sun sun; + public static void main(String[] args) { + // 新建"太阳"(被观察者) + sun = new Sun(); + // 新建"公鸡"(观察者) + cock = new Cock(sun); + // 太阳升起。公鸡观察到太阳升级后,会打鸣! + sun.rise(); + } + } + +运行结果: + + Sun rise. + Cock gogoda,gogoda,gogoda... diff --git "a/source/_posts/2014-06-03-\350\256\276\350\256\241\346\250\241\345\274\21719\344\271\213-\350\277\255\344\273\243\345\231\250-Iterator-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" "b/source/_posts/2014-06-03-\350\256\276\350\256\241\346\250\241\345\274\21719\344\271\213-\350\277\255\344\273\243\345\231\250-Iterator-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" new file mode 100644 index 0000000..c8f2e41 --- /dev/null +++ "b/source/_posts/2014-06-03-\350\256\276\350\256\241\346\250\241\345\274\21719\344\271\213-\350\277\255\344\273\243\345\231\250-Iterator-\346\250\241\345\274\217-\350\241\214\344\270\272\346\250\241\345\274\217.md" @@ -0,0 +1,266 @@ +--- +title: 设计模式19之 迭代器(Iterator)模式(行为模式) +date: 2014-06-03 11:11:08 +categories: +- 设计模式 +tags: +- java +- 迭代器模式 +--- + +# 迭代器模式简介 + +  迭代器模式又叫游标(Cursor)模式,是对象的行为模式。迭代器模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(internal representation)。 + +  迭代器模式是设计模式中最常见的几个模式之一。在Java的集合(Collection)框架中,广泛的使用迭代器(Iterator和Enumeration)来遍历集合的元素。 + + + +迭代器模式涉及到以下几个角色:**抽象迭代器(Iterator),具体迭代器(ConcreteIterator),聚集(Aggregate),具体聚集(ConcreteAggregate),客户端(Client)**。 + +| 角色 | 说明 | +| ---------- | --------------- | +| 抽象迭代器 | 此抽象角色定义出遍历元素所需的接口。 | +| 具体迭代器 | 此角色实现了抽象迭代器的接口,并保持迭代过程中的游标位置。 | +| 聚集 | 此抽象角色给出创建迭代器(Iterator)对象的接口。 | +| 具体聚集 | 实现了创建迭代器(Iterator)对象的接口,返回一个合适的具体迭代器实例。 | +| 客户端 | 持有对聚集及其迭代器对象的引用,调用迭代器对象的迭代接口,也有可能通过迭代器操作聚集元素的增加和删除。 | + +  迭代器模式有两种:**外禀迭代器**和**内禀迭代器**。 +外禀迭代器 -- "具体迭代器"是在"具体聚集"之外实现的。 +内禀迭代器 -- "具体迭代器"是在"具体聚集"里面实现的,"具体迭代器"是"具体聚集"的私有内部类。 + +  在外禀迭代器中,"具体聚集"向外提供了访问聚集中各个元素的接口;而在内禀迭代器中,"具体聚集"包含了内部类"具体迭代器",这就意味着"具体迭代器"可以直接访问"具体聚集"的成员对象,而不需要通过函数接口去访问。 + +# 外禀迭代器 + +  如果迭代器是在聚集结构之外实现的,这样的迭代器被称为外禀迭代器(Extrinsic Iterator)。 + +下面看看"外禀迭代器"中各个角色的代码。 + +## 抽象迭代器类 + + public interface Iterator { + // 迭代方法:移动到第一个元素 + public void first(); + + // 迭代方法:移动到下一个元素 + public void next(); + + // 迭代方法:是否为最后一个元素 + public boolean isDone(); + + // 迭代方法:返还当前元素 + public Object currentItem(); + } + +## 具体迭代器类 + + public class ConcreteIterator implements Iterator { + private ConcreteAggregate agg; + // 索引位置 + private int index = 0; + // 集合大小 + private int size = 0; + + public ConcreteIterator(ConcreteAggregate agg){ + this.agg = agg; + this.size = agg.size(); + index = 0; + } + + // 迭代方法:移动到第一个元素 + @Override + public void first() { + index = 0; + } + + // 迭代方法:是否为最后一个元素 + @Override + public boolean isDone() { + return (index >= size); + } + + // 迭代方法:移动到下一个元素 + @Override + public void next() { + if(index < size) { + index ++; + } + } + + // 迭代方法:返还当前元素 + @Override + public Object currentItem() { + return agg.getElement(index); + } + } + +## 聚集类 + + abstract public class Aggregate { + // 工厂方法:返回迭代器对象 + public abstract Iterator createIterator(); + } + +## 具体聚集类 + + public class ConcreteAggregate extends Aggregate { + + private Object[] objs = {"Monk Tang", + "Monkey", "Pigsy", + "Sandy", "Horse"}; + + @Override + public Iterator createIterator() { + return new ConcreteIterator(this); + } + + // 取值方法:向外界提供聚集元素 + public Object getElement(int index){ + + if(index < objs.length){ + return objs[index]; + }else{ + return null; + } + } + + // 取值方法:向外界提供聚集的大小 + public int size(){ + return objs.length; + } + } + +## 客户端类 + + public class Client { + + private Iterator it; + private Aggregate agg = new ConcreteAggregate(); + public void operation() { + it = agg.createIterator(); + while(!it.isDone()) { + System.out.println(it.currentItem()); + it.next(); + } + }3.4 + + public static void main(String[] args) { + Client client = new Client(); + client.operation(); + } + + } + +运行结果: + + Monk Tang + Monkey + Pigsy + Sandy + Horse + +# 内禀迭代器 + +  如果将"外禀迭代器"中的"具体迭代器"改写成"具体聚集类"的一个私有类,即迭代器是在聚集结构之内实现;这样的迭代器,就被称为内禀迭代器(Intrinsic Iterator)。 + +下面看看"内禀迭代器"中各个角色的代码。 + +## 抽象迭代器类 + + public interface Iterator { + // 迭代方法:移动到第一个元素 + public void first(); + + // 迭代方法:移动到下一个元素 + public void next(); + + // 迭代方法:是否为最后一个元素 + public boolean isDone(); + + // 迭代方法:返还当前元素 + public Object currentItem(); + } + +## 聚集类 + + abstract public class Aggregate { + // 工厂方法:返回迭代器对象 + public abstract Iterator createIterator(); + } + +## 具体聚集类 + + public class ConcreteAggregate extends Aggregate { + + private Object[] objs = {"Monk Tang", + "Monkey", "Pigsy", + "Sandy", "Horse"}; + + @Override + public Iterator createIterator() { + return new ConcreteIterator(); + } + + private class ConcreteIterator + implements Iterator { + // 索引位置 + private int index = 0; + + // 迭代方法:移动到第一个元素 + @Override + public void first() { + index = 0; + } + + // 迭代方法:是否为最后一个元素 + @Override + public boolean isDone() { + return (index == objs.length); + } + + // 迭代方法:移动到下一个元素 + @Override + public void next() { + if(index < objs.length) { + index ++; + } + } + + // 迭代方法:返还当前元素 + @Override + public Object currentItem() { + return objs[index]; + } + } + } + +## 客户端类 + + public class Client { + + private Iterator it; + private Aggregate agg = new ConcreteAggregate(); + public void operation() { + it = agg.createIterator(); + while(!it.isDone()) { + System.out.println(it.currentItem()); + it.next(); + } + } + + public static void main(String[] args) { + Client client = new Client(); + client.operation(); + } + + } + +运行结果: + + Monk Tang + Monkey + Pigsy + Sandy + Horse diff --git "a/source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" "b/source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" new file mode 100644 index 0000000..7983742 --- /dev/null +++ "b/source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" @@ -0,0 +1,87 @@ +--- +title: Flume1.7源码调试 +date: 2017-02-14 19:02:40 +categories: +- Flume +tags: +- Flume +--- + +# 下载源码 +git clone https://github.com/apache/flume.git + + + +# 将源码导入Idea +![选区_021](/images/media/选区_021.png) +# 编译时会有以下jar仓库中无法找到并下载,需要手动下载到本地仓库 +``` +linq4j-0.4.jar pentaho-aggdesigner-algorithm-5.1.3-jhyde.jar quidem-0.1.1.jar +``` + +以上jar文件可以在下面的网站中找到 + +``` +http://conjars.org/repo/ +http://repository.pentaho.org/artifactory/repo/ +``` + +执行下面的命令将jar下载到本地仓库 + +``` +mvn install:install-file -Dfile=pentaho-aggdesigner-algorithm-5.1.3-jhyde.jar -DgroupId=org.pentaho -DartifactId=pentaho-aggdesigner-algorithm -Dversion=5.1.3-jhyde -Dpackaging=jar +mvn install:install-file -Dfile=linq4j-0.4.jar -DgroupId=net.hydromatic -DartifactId=linq4j -Dversion=0.4 -Dpackaging=jar +mvn install:install-file -Dfile=quidem-0.1.1.jar -DgroupId=net.hydromatic -DartifactId=quidem -Dversion=0.1.1 -Dpackaging=jar +``` + +# 执行编译命令 + +``` +mvn clean install -DskipTests +``` + +![选区_022](/images/media/选区_022.png) + +# 本地调试 + +``` +主类:org.apache.flume.node.Application +参数:-n agent -f /home/liby/local/apache-flume-1.7.0-bin/conf/flume-conf.properties +``` + +flume-conf.properties + +```sh + # Name the components on this agent + agent.sources = r1 + agent.sinks = k1 + agent.channels = c1 + # Describe/configure the source + agent.sources.r1.type = netcat + agent.sources.r1.bind = localhost + agent.sources.r1.port = 44445 + # Describe the sink + # 将数据输出至日志中 + agent.sinks.k1.type = logger + # Use a channel which buffers events in memory + agent.channels.c1.type = memory + agent.channels.c1.capacity = 1000 + agent.channels.c1.transactionCapacity = 100 + # Bind the source and sink to the channel + agent.sources.r1.channels = c1 + agent.sinks.k1.channel = c1 +``` + +![选区_023](/images/media/选区_023.png) + +运行效果 +![选区_024](/images/media/选区_024.png) + +# 远程调试 +在conf/flume-env.properties增加以下配置,然后启动flume + +``` +-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 +``` +在idea中启动远程调试 +![选区_025](/images/media/选区_025.png) diff --git "a/source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" "b/source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" new file mode 100644 index 0000000..fc5676d --- /dev/null +++ "b/source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" @@ -0,0 +1,353 @@ +--- +title: Ubuntu16.04系统工作环境设置 +date: 2017-03-11 22:06:39 +categories: +- Ubuntu +tags: +- Linux +- 系统设置 +--- + +# 主题美化 + +1.执行以下命令安装Flatabulous主题 + +```sh +sudo apt-get install unity-tweak-tool +sudo add-apt-repository ppa:noobslab/themes +sudo apt-get update +sudo apt-get install flatabulous-theme +``` + + + +2.该主题有配套的图标,安装方式如下 + +```sh +sudo add-apt-repository ppa:noobslab/icons +sudo apt-get update +sudo apt-get install ultra-flat-icons +``` +3.安装完成后,打开unity-tweak-tool软件,修改主题和图标 +![选区_026](/images/media/选区_026.png) + +4.进入Theme,修改为Flatabulous +![Unity Tweak Tool_027](/images/media/Unity Tweak Tool_027.png) + +5.在此界面下进入Icons栏,修改为Ultra-flat +![Unity Tweak Tool_028](/images/media/Unity Tweak Tool_028.png) + +6.安装字体YaHei Consolas Hybrid + +```sh +要想安装这款字体,首先需要安装 Font Manager (字体管理)软件。 +sudo apt-get install font-manager +google搜索 YaHei.Consolas 下载这款字体。 +在 Font Manager 中点击 Manager Fonts - Install Fonts ,就可以安装 ttf 字体了。 +``` +# 系统更新 + +```sh +sudo apt-get update +sudo apt-get upgrade +``` +# 安装vim +```sh +sudo apt-get install vim +``` + +# 安装 maximum-awesome-linux +``` +git clone https://github.com/smartliby/maximum-awesome-linux.git +cd maximum-awesome-linux && rake +``` +![工作区 1_040](/images/media/工作区 1_040.png) + +# 安装zsh、oh-my-zsh + +安装zsh + +```sh +sudo apt install zsh +``` + +via curl download Oh My Zsh + +```sh +sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" +``` + +切换到zsh + +```sh +chsh -s /usr/bin/zsh +``` +![liby@kingsoft: ~_031](/images/media/liby@kingsoft:%20~_031.png) +# 安装terminator +Ubuntu自带的终端是gnome-terminal,虽然也还不错,但是不能支持屏幕分割、选择复制等功能让我很不爽,于是我换用terminator作为终端,terminator可以支持屏幕分割,并且默认快捷键和gnome-terminal无异,熟悉gnome-terminal的话可以快速上手。 + +Ubuntu下可以这样安装terminator + +```sh +sudo apt-get install terminator +``` +terminator常用快捷键 + +* Ctrl-Shift-c 拷贝 +* Ctrl-Shift-v 粘贴 +* Ctrl-Shift-t 开新Tab窗口 +* Ctrl-Shift-o 上下拆分屏幕 +* Ctrl-Shift-e 左右拆分屏幕 +* Ctrl-Shift-w 关闭当前窗口 +* Ctrl-Shift-q 关闭整个终端 + +配置terminator使用solarized配色 + +```sh +mkdir -p ~/.config/terminator/ +curl https://raw.github.com/ghuntley/terminator-solarized/master/config > ~/.config/terminator/config +``` + +然后重新打开terminator就已经是solarized配色了。 + +对terminator更多的配置 + +接下来,可以在terminator-solarized配置文件的基础上进行更多的配置,例如背景透明、启用选择复制等。 + +关于terminator的详细配置选项可以参考[terminator manpage](http://manpages.ubuntu.com/manpages/zesty/en/man5/terminator_config.5.html),下面贴出我的~/.config/terminator/config供参考: + +```sh +[global_config] + title_transmit_bg_color = "#d30102" + focus = system + suppress_multiple_term_dialog = True +[keybindings] +[profiles] + [[default]] + palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3" + copy_on_selection = True + background_image = None + background_darkness = 0.95 + background_type = transparent + use_system_font = False + cursor_color = "#eee8d5" + foreground_color = "#839496" + show_titlebar = False + font = Monospace 11 + background_color = "#002b36" + [[solarized-dark]] + palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3" + background_color = "#002b36" + background_image = None + cursor_color = "#eee8d5" + foreground_color = "#839496" + [[solarized-light]] + palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3" + background_color = "#fdf6e3" + background_image = None + cursor_color = "#002b36" + foreground_color = "#657b83" +[layouts] + [[default]] + [[[child1]]] + type = Terminal + parent = window0 + profile = default + [[[window0]]] + type = Window + parent = "" +[plugins] +``` + +配置dircolors + +完成上述配置后,你会发现用ls命令查看目录和文件时是一片灰色。这是因为默认情况下solarized各种bright方案基本都是灰色,而系统默认显示目录和文件时多用bright色,此时需要配置dircolors才能显示出彩色的文件和目录。 + +[dircolors-solarized](https://github.com/seebi/dircolors-solarized)项目提供了适合于solarized的dircolors配色方案,只要选择合适的方案使用就可以了。例如我是用的solarized dark配色,所以可以选择适合这个配色的dircolors.ansi-dark + +```sh +curl https://raw.github.com/seebi/dircolors-solarized/master/dircolors.ansi-dark > ~/.dircolors +``` + +然后在~/.zshrc中加入如下配置: + +```sh +# enable color support of ls and also add handy aliases +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + #alias dir='dir --color=auto' + #alias vdir='vdir --color=auto' + + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi + +# some more ls aliases +alias ll='ls -alF' +alias la='ls -A' +alias l='ls -CF' +``` + +执行 + +```sh +source ~/.zshrc +``` + +后,再执行ls或ll就可以看到彩色的目录或文件了。 + +配置完的terminator效果如下: +![工作区 1_045](/images/media/工作区 1_045.png) + +# 安装jdk1.8 + +```sh +1.下载jdk,因为oracle现在要同意协议才能下载,直接使用wget加链接下载不到,所以要加上前面的那些代码 + wget --no-check-certificate --no-cookie --header "Cookie: oraclelicense=accept-securebackup-cookie;" http://download.oracle.com/otn-pub/java/jdk/8u121-b13/jdk-8u121-linux-x64.tar.gz +2.安装jdk + tar -zxvf jdk-8u121-linux-x64.tar.gz +3.设置环境变量 vim /home/liby/.zshrc,添加如下内容 + export JAVA_HOME=/home/liby/local/jdk1.8.0_121/ + export JRE_HOME=${JAVA_HOME}/jre + export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib + export MAVEN_HOME=/home/liby/local/apache-maven-3.3.9 + export PATH=${JAVA_HOME}/bin:${MAVEN_HOME}/bin:$PATH +4.刷新配置文件 + source /home/liby/.zshrc +``` + +# 安装maven + +```sh +1.下载maven + wget http://mirror.cc.columbia.edu/pub/software/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz +2.安装maven + tar -zxvf apache-maven-3.3.9-bin.tar.gz +3.设置环境变量 vim /home/liby/.zshrc,添加如下内容 + export JAVA_HOME=/home/liby/local/jdk1.8.0_121/ + export JRE_HOME=${JAVA_HOME}/jre + export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib + export MAVEN_HOME=/home/liby/local/apache-maven-3.3.9 + export PATH=${JAVA_HOME}/bin:${MAVEN_HOME}/bin:$PATH +4.刷新配置文件 + source /home/liby/.zshrc +``` +# 下载chrome + +```sh +wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb +sudo dpkg -i google-chrome-stable_current_amd64.deb +登录账号并同步数据 +``` +# 安装搜狗输入法 +```sh +wget http://cdn2.ime.sogou.com/dl/index/1475147394/sogoupinyin_2.1.0.0082_amd64.deb?st=_vb5fHHeRyUHCwduavC5Qw&e=1489585347&fn=sogoupinyin_2.1.0.0082_amd64.deb +sudo dpkg -i sogoupinyin_2.1.0.0082_amd64.deb +``` + +# 安装virtualbox +```sh +wget http://download.virtualbox.org/virtualbox/5.1.16/virtualbox-5.1_5.1.16-113841~Ubuntu~xenial_amd64.deb +sudo dpkg -i virtualbox-5.1_5.1.16-113841~Ubuntu~xenial_amd64.deb +``` +# 安装idea +```sh +wget https://download.jetbrains.8686c.com/idea/ideaIU-2016.3.5.tar.gz +tar -zxvf ideaIU-2016.3.5.tar.gz +安装插件:scala,.ignore,python,Markdown Navigator2.3.2破解版,VisualVM Launcher +``` +# 安装pycharm +```sh +wget https://download.jetbrains.8686c.com/python/pycharm-professional-2016.3.2.tar.gz +tar -zxvf pycharm-professional-2016.3.2.tar.gz +安装插件:.ignore,Markdown Navigator2.3.2破解版 +``` +# 修复idea和pycharm字体模糊锯齿和乱码等现象 +设置字体为YaHei Consolas Hybrid,同时支持中英文 +![Settings_033](/images/media/Settings_033.png) +![Settings_034](/images/media/Settings_034.png) + +# idea与系统冲突的快捷键设置 +```sh +1.Change or disable the Lock Screen action, assigned to Ctrl + Alt + L (Reformat code) +2.Change or disable the Launch terminal action, assigned to Ctrl + Alt + T (Surround with) +3.Change or disable the Switch to workspace action, assigned to Ctrl + Alt + Arrow Keys(Navigation) +4.Disable the Move window action, assigned to Alt + F7 (Find usages) +5.Change or disable the Resize window action, assigned to Alt + F8 (Evaluate expression) +6.Fcitx输入法激活快捷键,assigned to Ctrl + 空格 (code completion basic) +``` + +解决办法是打开系统设置中的键盘,修改冲突的快捷键,将系统的快捷键禁用或者修改idea快捷键。 + +``` +1.修改idea快捷键为Ctrl + L +2.用的地方不多,先不修改了 +3.窗口中的移动窗口禁用 +4.导航中的切换至左侧工作区/切换至右侧工作区/切换至侧上工作区/切换至下侧工作区禁用 +5.窗口中的调整窗口大小禁用 +6.禁用Fcitx输入法激活快捷键 +``` + +# 安装atom + +```sh +wget https://atom-installer.github.com/v1.15.0/atom-amd64.deb?s=1489019656&ext=.deb +sudo dpkg -i atom-amd64.deb +``` +安装插件:markdown-writer、autocomplete-python、ile-icons、git-control、language-hql、markdown-pdf、pdf-view、activate-power-mode + +# 安装markdown神器 + +```sh +# optional, but recommended +sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE +# add Typora's repository +sudo add-apt-repository 'deb https://typora.io ./linux/' +sudo apt-get update +# install typora +sudo apt-get install typora +``` + +# 截图工具 + +```sh +sudo apt-get install shutter +``` +# 网易云音乐 + +```sh +wget http://s1.music.126.net/download/pc/netease-cloud-music_1.0.0_amd64_ubuntu16.04.deb +sudo dpkg -i netease-cloud-music_1.0.0_amd64_ubuntu16.04.deb +登录账号并同步数据 +``` + +# 开启ssh服务,允许远程连接 +```sh +sudo apt-get install openssh-server +这样其他的电脑就可以ssh登录公司的这台电脑了 +``` +# 开启远程桌面服务 + 1.Dash中打开桌面共享 + ![桌面共享首选项_029](/images/media/桌面共享首选项_029.png) + + 2.安装并运行dconf-editor,把加密选项去掉 + + ```sh + sudo apt-get install dconf-editor + dconf-editor + ``` +依次展开org->gnome->desktop->remote-access +这里也可以直接设置远程控制选项,但重要的是将“requre-encryption”去掉。 +![dconf 系统配置编辑器_030](/images/media/dconf 系统配置编辑器_030.png) + +之后就可以在其他的电脑上使用远程桌面登录了 + +# 16.04默认没有打开工作区切换功能需要手动打开,使用起来方便多了。 +![Unity Tweak Tool_039](/images/media/Unity Tweak Tool_039.png) +![工作区_041](/images/media/工作区_041.png) + +# 最终的效果图 +![工作区 1_043](/images/media/工作区 1_076.png) +![工作区 1_044](/images/media/工作区 1_077.png) diff --git "a/source/_posts/2017-05-14-java\345\255\227\347\254\246\347\274\226\347\240\201\346\265\205\346\236\220.md" "b/source/_posts/2017-05-14-java\345\255\227\347\254\246\347\274\226\347\240\201\346\265\205\346\236\220.md" new file mode 100644 index 0000000..fd34d3f --- /dev/null +++ "b/source/_posts/2017-05-14-java\345\255\227\347\254\246\347\274\226\347\240\201\346\265\205\346\236\220.md" @@ -0,0 +1,78 @@ +--- +title: java字符编码浅析 +date: 2016-07-14 19:24:13 +categories: +- java +tags: +- 字符编码 +--- +# java字符编码浅析 +> 关于这篇文章其实是从一个问题开始的:java中char类型能存储汉字吗? + +## UTF-8编码 +UTF-8就是在互联网上使用最广的一种Unicode的实现方式。其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。 +UTF-8的编码规则很简单,只有二条: + + + +1.对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。 +2.对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。 +下表总结了编码规则,字母x表示可用编码的位。 + +Unicode符号范围(十六进制) | UTF-8编码方式(二进制) +--------------- | ------------ +0000 0000-0000 007F | 0xxxxxxx +0000 0080-0000 07FF | 110xxxxx 10xxxxxx +0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx +0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +跟据上表,解读UTF-8编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。 +下面,还是以汉字"严"为例,演示如何实现UTF-8编码。 +已知"严"的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此"严"的UTF-8编码需要三个字节,即格式是"1110xxxx 10xxxxxx 10xxxxxx"。然后,从"严"的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,"严"的UTF-8编码是"11100100 10111000 10100101",转换成十六进制就是E4B8A5。 + +## UTF-16编码 +UTF-16是Unicode的其中一个使用方式。 UTF是 Unicode TransferFormat,即把Unicode转做某种格式的意思。UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存,但UTF-16却无法兼容于ASCII编码。UTF-16的大端和小端储存形式都在用。为了弄清楚UTF-16文件的大小端,在UTF-16文件的开首,都会放置一个U+FEFF字符作为Byte Order Mark(UTF-16LE以FF FE代表,UTF-16BE以FE FF代表),以显示这个文字档案是以UTF-16编码,其中U+FEFF字符在UNICODE中代表的意义是ZERO WIDTH NO-BREAK SPACE,顾名思义,它是个没有宽度也没有断字的空白。 + +## 实例讲解 +### 例1 +``` +String s = "I'm 李博玉"; +byte[] charArr = s.getBytes(Charset.forName("UTF-16")); + for (byte b : charArr) { + System.out.printf("%X ", b); + } +System.out.println(s.getBytes(Charset.forName("UTF-16")).length); + +charArr = s.getBytes(Charset.forName("UTF-8")); + for (byte b : charArr) { + System.out.printf("%X ", b); + } +System.out.println(s.getBytes(Charset.forName("UTF-8")).length); +``` +输出的结果是什么呢? +FE FF 0 49 0 27 0 6D 0 20 67 4E 53 5A 73 89 +16 +49 27 6D 20 E6 9D 8E E5 8D 9A E7 8E 89 +13 + +1.UTF-16的编码为什么是16? +对于大部分字符来讲,UTF-16都使用两个字节来存储。但是UTF-16是支持大小端的,所以需要在字符的开头使用两个字节的额外空间指定好它的字节序,FE FF 表示使用大端存储。 +7 x 2 + 2 = 16 +2.UTF-8的编码为什么是13? +UTF-8是完全兼容ASCII编码的,所以英文是占一个字节,中文大部分占3个字节,不常用的占4个字节 +4 + 3 x 3 = 13 + +### 例2 + + +String s1 = "李"; +String s2 = "![](/images/media/14707129240405.jpg)" +System.out.println(s1.length()); +System.out.println(s2.length()); + +输出的结果是什么呢? +1 +2 +看到这个结果是不是崩溃了,到底怎么回事? + +1.首先要明白.length指的是什么,String内部是以char数组的形式存储的,.length是指char数组的长度,char是以UTF-16编码的,李是常用字,UTF-16编码后占两个字节,一个char就能够存储,所以是长度是1,而![](/images/media/14707129334632.jpg)UTF-16编码后占四个字节,两个char来存储,所以长度是2 diff --git a/source/about/index.md b/source/about/index.md new file mode 100644 index 0000000..85f8436 --- /dev/null +++ b/source/about/index.md @@ -0,0 +1,14 @@ +--- +date: 2017-05-08 01:02:07 +--- + +## 关于我 + +> 大家好,他叫James Lee,这是一名程序员的博客。 +> 他是个不错的家伙,喜欢接触新事物,并愿意将他所学的东西与人分享。 +> 他始终保持着一颗积极乐观的心态,并相信:生活不只是眼前的苟且,还有诗和远方。 + +## 联系方式 + +> 个人邮箱: +> GitHub: diff --git a/source/categories/index.md b/source/categories/index.md new file mode 100644 index 0000000..d19ca0f --- /dev/null +++ b/source/categories/index.md @@ -0,0 +1,5 @@ +--- +title: categories +date: 2017-05-04 23:16:17 +type: "categories" +--- diff --git a/source/tags/index.md b/source/tags/index.md new file mode 100644 index 0000000..2c74028 --- /dev/null +++ b/source/tags/index.md @@ -0,0 +1,5 @@ +--- +title: tags +date: 2017-05-04 23:22:00 +type: "tags" +--- From dd70d364a359c4c52366e155e512a742b1ddb85b Mon Sep 17 00:00:00 2001 From: smartliby Date: Sat, 27 Apr 2019 20:16:40 +0800 Subject: [PATCH 02/23] next update --- _config.yml | 10 +++++++-- package-lock.json | 46 ++++++++++++++++++++++++++++++++++++++ package.json | 6 ++++- source/404.md | 7 ++++++ source/about/index.md | 1 + source/categories/index.md | 1 + source/tags/index.md | 1 + 7 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 source/404.md diff --git a/_config.yml b/_config.yml index d9c6910..87c29db 100644 --- a/_config.yml +++ b/_config.yml @@ -7,9 +7,15 @@ title: 以梦为马 subtitle: description: author: James Lee -language: zh-Hans +language: zh-CN timezone: Asia/Shanghai +symbols_count_time: + symbols: true + time: true + total_symbols: true + total_time: true + # URL ## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/' url: https://smartliby.github.io @@ -77,7 +83,7 @@ search: # Extensions ## Plugins: https://hexo.io/plugins/ ## Themes: https://hexo.io/themes/ -theme: next +theme: next-reloaded # Deployment ## Docs: https://hexo.io/docs/deployment.html diff --git a/package-lock.json b/package-lock.json index 069cd8a..c22f80b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2000,6 +2000,16 @@ } } }, + "hexo-generator-baidu-sitemap": { + "version": "0.1.6", + "resolved": "https://registry.npm.taobao.org/hexo-generator-baidu-sitemap/download/hexo-generator-baidu-sitemap-0.1.6.tgz", + "integrity": "sha1-CsL4mmKijZtblxD90p0ulCXVTwQ=", + "requires": { + "ejs": "^2.5.5", + "hexo": "^3.0.0", + "utils-merge": "^1.0.0" + } + }, "hexo-generator-category": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/hexo-generator-category/-/hexo-generator-category-0.1.3.tgz", @@ -2016,6 +2026,15 @@ } } }, + "hexo-generator-feed": { + "version": "1.2.2", + "resolved": "https://registry.npm.taobao.org/hexo-generator-feed/download/hexo-generator-feed-1.2.2.tgz", + "integrity": "sha1-lRbRWWUJsVf00ET7SbK645i4K6c=", + "requires": { + "nunjucks": "^3.0.0", + "object-assign": "^4.1.1" + } + }, "hexo-generator-index": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/hexo-generator-index/-/hexo-generator-index-0.2.1.tgz", @@ -2056,6 +2075,28 @@ } } }, + "hexo-generator-sitemap": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/hexo-generator-sitemap/download/hexo-generator-sitemap-1.2.0.tgz", + "integrity": "sha1-MBj419Hi5Cs/caZacxb/z1g7w/M=", + "requires": { + "minimatch": "^3.0.0", + "nunjucks": "^2.3.0", + "object-assign": "^4.0.1" + }, + "dependencies": { + "nunjucks": { + "version": "2.5.2", + "resolved": "https://registry.npm.taobao.org/nunjucks/download/nunjucks-2.5.2.tgz", + "integrity": "sha1-6n00bnhbikh0Zmw8yp4YxXf7oiw=", + "requires": { + "asap": "^2.0.3", + "chokidar": "^1.6.0", + "yargs": "^3.32.0" + } + } + } + }, "hexo-generator-tag": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/hexo-generator-tag/-/hexo-generator-tag-0.2.0.tgz", @@ -2199,6 +2240,11 @@ } } }, + "hexo-symbols-count-time": { + "version": "0.4.4", + "resolved": "https://registry.npm.taobao.org/hexo-symbols-count-time/download/hexo-symbols-count-time-0.4.4.tgz", + "integrity": "sha1-xbrXbURdfgoe6KRsetIzSbwWLB0=" + }, "hexo-util": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-0.6.3.tgz", diff --git a/package.json b/package.json index 0af2dd8..a1d0d81 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,18 @@ "hexo": "^3.8.0", "hexo-deployer-git": "^1.0.0", "hexo-generator-archive": "^0.1.5", + "hexo-generator-baidu-sitemap": "^0.1.6", "hexo-generator-category": "^0.1.3", + "hexo-generator-feed": "^1.2.2", "hexo-generator-index": "^0.2.1", "hexo-generator-search": "^2.4.0", "hexo-generator-searchdb": "^1.0.8", + "hexo-generator-sitemap": "^1.2.0", "hexo-generator-tag": "^0.2.0", "hexo-renderer-ejs": "^0.3.1", "hexo-renderer-marked": "^0.3.2", "hexo-renderer-stylus": "^0.3.3", - "hexo-server": "^0.3.3" + "hexo-server": "^0.3.3", + "hexo-symbols-count-time": "^0.4.4" } } diff --git a/source/404.md b/source/404.md new file mode 100644 index 0000000..e2cc123 --- /dev/null +++ b/source/404.md @@ -0,0 +1,7 @@ +--- +title: 404.md +date: 2019-04-27 20:04:29 +comments: false +--- + + diff --git a/source/about/index.md b/source/about/index.md index 85f8436..9ecc762 100644 --- a/source/about/index.md +++ b/source/about/index.md @@ -1,4 +1,5 @@ --- +comments: false date: 2017-05-08 01:02:07 --- diff --git a/source/categories/index.md b/source/categories/index.md index d19ca0f..2686737 100644 --- a/source/categories/index.md +++ b/source/categories/index.md @@ -2,4 +2,5 @@ title: categories date: 2017-05-04 23:16:17 type: "categories" +comments: false --- diff --git a/source/tags/index.md b/source/tags/index.md index 2c74028..da93f12 100644 --- a/source/tags/index.md +++ b/source/tags/index.md @@ -2,4 +2,5 @@ title: tags date: 2017-05-04 23:22:00 type: "tags" +comments: false --- From 25f47a3538a68fe9405957c336f3062e22dd7909 Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 12 May 2019 18:48:38 +0800 Subject: [PATCH 03/23] ubuntu add aria2 --- ...0\275\275\347\245\236\345\231\250aria2.md" | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 "source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" diff --git "a/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" "b/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" new file mode 100644 index 0000000..b3ff46b --- /dev/null +++ "b/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" @@ -0,0 +1,136 @@ +--- +title: Mac、Ubuntu系统的下载神器aria2 +date: 2019-05-12 18:21:11 +categories: +- Ubuntu +tags: +- aria2 +- 系统设置 +--- + +# Mac、Ubuntu系统的下载神器aria2 + +Mac 用户肯定都受够了百度网盘在自己电脑上的糟糕体验,至少我是如此:安装官方的 App,经常下载时中断,有时甚至 Bug 般连续中断,无奈使用浏览器下载,速度却是令人挠头。花点时间来配置 aria2,结合 Chrome,一定让你舒心 + + + +> aria2 是什么? + +aria2 是一款支持多种协议的轻量级命令行下载工具。有以下特性: + +* 多线程连线:aria2 会自动从多个线程下载文件,并充分利用你的带宽; +* 轻量:运行时不会占用过多资源,根据官方介绍,内存占用通常在 4MB~9MB,使用 BitTorrent 协议,下行速度 2.8MB/s 时 CPU 占用率约 6%; +* 全功能 BitTorrent 客户端; +* 支持 RPC 界面远程控制(下文重点介绍)。 + +> 开始吧 + +## 1.安装 aria2 + +``` +brew install aria2 +``` + +## 2.设置配置文件 + +aria2 提供两种方式使用,一种是直接命令行模式下载,不推荐使用这种方法,推荐使用另外一种 RPC 模式,这种方式 aria 启动之后只会安静的等待下载请求,下载完成后也只会安静的驻留后台不会自动退出。而使用RPC模式推荐做一个配置文件方便使用。我们把配置文件放在 ~/.aria2 下,依次输入命令: + +``` +cd ~ +mkdir .aria2 +cd .aria2 +vim aria2.conf +``` + +复制以下内容到aria2.conf + +``` +#用户名 +#rpc-user=user +#密码 +#rpc-passwd=passwd +#上面的认证方式不建议使用,建议使用下面的token方式 +#设置加密的密钥 +#rpc-secret=token +#允许rpc +enable-rpc=true +#允许所有来源, web界面跨域权限需要 +rpc-allow-origin-all=true +#允许外部访问,false的话只监听本地端口 +rpc-listen-all=true +#RPC端口, 仅当默认端口被占用时修改 +#rpc-listen-port=6800 +#最大同时下载数(任务数), 路由建议值: 3 +max-concurrent-downloads=5 +#断点续传 +continue=true +#同服务器连接数 +max-connection-per-server=5 +#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要 +min-split-size=10M +#单文件最大线程数, 路由建议值: 5 +split=10 +#下载速度限制 +max-overall-download-limit=0 +#单文件速度限制 +max-download-limit=0 +#上传速度限制 +max-overall-upload-limit=0 +#单文件速度限制 +max-upload-limit=0 +#断开速度过慢的连接 +#lowest-speed-limit=0 +#验证用,需要1.16.1之后的release版本 +#referer=* +#文件保存路径, 默认为当前启动位置 +dir=/Users/xxx/Downloads +#文件缓存, 使用内置的文件缓存, 如果你不相信Linux内核文件缓存和磁盘内置缓存时使用, 需要1.16及以上版本 +#disk-cache=0 +#另一种Linux文件缓存方式, 使用前确保您使用的内核支持此选项, 需要1.15及以上版本(?) +#enable-mmap=true +#文件预分配, 能有效降低文件碎片, 提高磁盘性能. 缺点是预分配时间较长 +#所需时间 none < falloc ? trunc « prealloc, falloc和trunc需要文件系统和内核支持 +file-allocation=prealloc +``` + +默认下载路径的「/Users/xxx/Downloads」可以改为任何你想要的绝对路径。此处写为 Downloads 目录,xxx 请自行替换成你的 Mac 用户名,然后保存,退出编辑器。 + +## 3.启动 RPC 模式 +在终端输入aria2c --conf-path="/Users/xxxxxx/.aria2/aria2.conf" -D,然后 aria2 就启动了,但是如何搞定百度网盘?还需要在Chrome网上应用商店下载百度网盘助手插件。 +## 4.访问webUI +首先从github中克隆webui-aria2项目 + +``` +git clone https://github.com/ziahamza/webui-aria2 +``` + +* 方法一:不需创建任何 web 服务器,只需直接双击运行 index.html +* 方法二:在终端执行下面的命令 + + ``` + python -m SimpleHTTPServer 6801 + ``` + + 在浏览器中访问http://localhost:6801 即可 + +## 5.如何进行下载操作 +随便打开一个百度网盘的链接,会发现网页上多出一个「导出下载」按钮,点击它弹出的「ARIA2 RPC」就自动添加到你的下载队列里了,然后利用 这里 提供的网页界面管理你的下载任务,如下图所示,你可以利用图形界面进行许多操作: +![aria2](http://ws3.sinaimg.cn/large/77520195ly1g2yq28mh2uj21400mujvx.jpg) + +## 6.关闭 aria2 +如果你想关掉后台的 aria2,可以到活动监视器中找到 aria2c 杀掉 +## 7.设置aria2开机自动启动 +在家目录 `/Users/liby/` 执行 `vim aria2-starter`,然后添加如下内容 + +``` +#!/bin/bash +aria2c --conf-path="/Users/liby/.aria2/aria2.conf" -D +nohup python -m SimpleHTTPServer 6801 & +exit +``` +设置该脚本为可执行文件 +最后在 `系统偏好设置`->`用户与组群`->`登录项` 添加该执行脚本 + +## 8.总结 +通过 Aria2 下载后,速度一般可达300KB以上,如果不用,同一个文件可能才只有几十或者100K左右的速度,这个差别真是非常大啊! + From b646a0d4b258f8f4772d32b583818e8ccc823f26 Mon Sep 17 00:00:00 2001 From: smartliby Date: Thu, 16 May 2019 21:49:33 +0800 Subject: [PATCH 04/23] aria2 path update --- package-lock.json | 490 ------------------ ...0\275\275\347\245\236\345\231\250aria2.md" | 20 +- 2 files changed, 10 insertions(+), 500 deletions(-) diff --git a/package-lock.json b/package-lock.json index c22f80b..1ee1dad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -458,7 +458,6 @@ "requires": { "anymatch": "^1.3.0", "async-each": "^1.0.0", - "fsevents": "^1.0.0", "glob-parent": "^2.0.0", "inherits": "^2.0.1", "is-binary-path": "^1.0.0", @@ -926,487 +925,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "1.2.8", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.8.tgz", - "integrity": "sha1-V+pTIPdizUaW5ejocSDszIsRys8=", - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "optional": true - } - } - }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -1693,7 +1211,6 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", - "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", @@ -2750,12 +2267,6 @@ "rimraf": "~2.4.0" } }, - "nan": { - "version": "2.13.2", - "resolved": "https://registry.npm.taobao.org/nan/download/nan-2.13.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnan%2Fdownload%2Fnan-2.13.2.tgz", - "integrity": "sha1-9R3Hrma6fV1V4ebU2AkugCya7+c=", - "optional": true - }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -2934,7 +2445,6 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", - "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", diff --git "a/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" "b/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" index b3ff46b..5aa3709 100644 --- "a/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" +++ "b/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" @@ -8,7 +8,7 @@ tags: - 系统设置 --- -# Mac、Ubuntu系统的下载神器aria2 +# 背景 Mac 用户肯定都受够了百度网盘在自己电脑上的糟糕体验,至少我是如此:安装官方的 App,经常下载时中断,有时甚至 Bug 般连续中断,无奈使用浏览器下载,速度却是令人挠头。花点时间来配置 aria2,结合 Chrome,一定让你舒心 @@ -25,13 +25,13 @@ aria2 是一款支持多种协议的轻量级命令行下载工具。有以下 > 开始吧 -## 1.安装 aria2 +# 1.安装 aria2 ``` brew install aria2 ``` -## 2.设置配置文件 +# 2.设置配置文件 aria2 提供两种方式使用,一种是直接命令行模式下载,不推荐使用这种方法,推荐使用另外一种 RPC 模式,这种方式 aria 启动之后只会安静的等待下载请求,下载完成后也只会安静的驻留后台不会自动退出。而使用RPC模式推荐做一个配置文件方便使用。我们把配置文件放在 ~/.aria2 下,依次输入命令: @@ -95,9 +95,9 @@ file-allocation=prealloc 默认下载路径的「/Users/xxx/Downloads」可以改为任何你想要的绝对路径。此处写为 Downloads 目录,xxx 请自行替换成你的 Mac 用户名,然后保存,退出编辑器。 -## 3.启动 RPC 模式 +# 3.启动 RPC 模式 在终端输入aria2c --conf-path="/Users/xxxxxx/.aria2/aria2.conf" -D,然后 aria2 就启动了,但是如何搞定百度网盘?还需要在Chrome网上应用商店下载百度网盘助手插件。 -## 4.访问webUI +# 4.访问webUI 首先从github中克隆webui-aria2项目 ``` @@ -113,13 +113,13 @@ git clone https://github.com/ziahamza/webui-aria2 在浏览器中访问http://localhost:6801 即可 -## 5.如何进行下载操作 +# 5.如何进行下载操作 随便打开一个百度网盘的链接,会发现网页上多出一个「导出下载」按钮,点击它弹出的「ARIA2 RPC」就自动添加到你的下载队列里了,然后利用 这里 提供的网页界面管理你的下载任务,如下图所示,你可以利用图形界面进行许多操作: -![aria2](http://ws3.sinaimg.cn/large/77520195ly1g2yq28mh2uj21400mujvx.jpg) +![aria2](/images/media/aria2.png) -## 6.关闭 aria2 +# 6.关闭 aria2 如果你想关掉后台的 aria2,可以到活动监视器中找到 aria2c 杀掉 -## 7.设置aria2开机自动启动 +# 7.设置aria2开机自动启动 在家目录 `/Users/liby/` 执行 `vim aria2-starter`,然后添加如下内容 ``` @@ -131,6 +131,6 @@ exit 设置该脚本为可执行文件 最后在 `系统偏好设置`->`用户与组群`->`登录项` 添加该执行脚本 -## 8.总结 +# 8.总结 通过 Aria2 下载后,速度一般可达300KB以上,如果不用,同一个文件可能才只有几十或者100K左右的速度,这个差别真是非常大啊! From 35cb3101bfb6d1e5433fef419540cf97361f0217 Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 5 Apr 2020 00:11:38 +0800 Subject: [PATCH 05/23] =?UTF-8?q?microk8s=E5=92=8Ckubeflow=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E7=BC=96=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...11\350\243\205\346\225\231\347\250\213.md" | 266 ++++++++++++++ ...11\350\243\205\346\225\231\347\250\213.md" | 332 ++++++++++++++++++ 2 files changed, 598 insertions(+) create mode 100644 "source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" create mode 100644 "source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" new file mode 100644 index 0000000..935f7e8 --- /dev/null +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -0,0 +1,266 @@ +--- +title: kubeflow1.0 安装教程 +date: 2020-04-14 18:21:11 +categories: +- k8s +tags: +- k8s +- kubeflow +- microk8s +--- + +[Kubeflow](https://www.kubeflow.org/docs)是Google推出的基于kubernetes环境下的机器学习组件,通过Kubeflow可以实现对TFJob等资源类型定义,可以像部署应用一样完成在TFJob分布式训练模型的过程。最初的设计是将Kubernetes和Tensorflow结合实现对Tensorflow分布式训练的支持。但是仅仅实现对Tensorflow的支持还是远远不够的,`Kubeflow`社区又陆续对各种深度学习框架进行支持,例如:`MXNet`, `Caffee`, `PyTorch`等。使得机器学习算法同学只需关心算法实现,而后续的模型训练和服务上线都交给平台来做,解放算法同学使其专做自己擅长的事儿。 + + + +目前Kubeflow仅支持在v1.15.11及以下版本的k8s上部署,v1.16及以上存在兼容性问题,具体情况可参考[这篇文章](https://www.kubeflow.org/docs/started/k8s/overview/),接下来我们基于[Microk8s](https://microk8s.io/)(版本1.15/stable)部署kubeflow v1.0 + +#### 安装 knative v0.7.1 + +kubeflow安装时依赖knative和istio组件,所以需要先安装knative,istio(microk8s安装时已安装`microk8s.enable istio`,不需要再安装),knative 的镜像是用 sha256 方式来 pull的。在本地我们不能通过 docker tag 的方式重新打包,只能修改 yaml 里的所有配置 + +默认knative的安装配置文件在`/snap/microk8s/current/actions/knative/`目录下,没有操作权限无法修改,需要先拷贝出来或者去github下载到本地,并将里面的镜像下载域名由gcr.io改成gcr.azk8s.cn + +```shell +# 安装 Knative CRD +kubectl apply --selector knative.dev/crd-install=true -f serving.yaml + +# 再运行一遍 kubectl apply +kubectl apply -f serving.yaml +``` + +#### 验证 knative 安装 + +运行`kubectl get pods --namespace knative-serving`验证 Knative 所有 pod 是否可以正常启动 + +```shell +NAME READY STATUS RESTARTS AGE +activator-55f6c8d9b-2hs77 2/2 Running 24 2d13h +autoscaler-78d575f875-l7zfj 2/2 Running 18 2d13h +controller-776478fb94-hmmxc 1/1 Running 3 2d13h +networking-certmanager-779cd6f448-xtvrb 1/1 Running 3 2d13h +networking-istio-674bd78b75-688gc 1/1 Running 3 2d13h +webhook-59b575dc79-cs7f4 1/1 Running 0 13h +``` + +#### 安装kubeflow + +下载 kfctl binary from the [Kubeflow releases page](https://github.com/kubeflow/kfctl/releases/) + +解压安装包并添加到执行目录 + +``` +tar -xvf kfctl_v1.0.1-0-gf3edb9b_linux.tar.gz +sudo cp kfctl /usr/bin +``` + +设置环境 + +``` +export BASE_DIR=/data/ +export KF_NAME=my-kubeflow +export KF_DIR=${BASE_DIR}/${KF_NAME} +export CONFIG_URI="https://raw.githubusercontent.com/kubeflow/manifests/v1.0-branch/kfdef/kfctl_k8s_istio.v1.0.1.yaml" +``` + +部署kubeflow + +``` +mkdir -p ${KF_DIR} +cd ${KF_DIR} +kfctl apply -V -f ${CONFIG_URI} +kubectl -n kubeflow get all +``` + +输出如下日志即安装成功 + +``` +INFO[0259] Applied the configuration Successfully! filename="cmd/apply.go:72" +``` + +查看当前 Kubernetes pods 状态 + +``` +kubectl get pods --namespace kubeflow +``` + +发现kubeflow的pod大部分没有启动成功,原因还是网络问题,需要访问gcr.io下载镜像 + +执行以下脚本将镜像下载到本地并导入到microk8s + +```shell +#!/usr/bin/env bash + +echo "" +echo "==========================================================" +echo "pull kubeflow v1.0 images from gcr.azk8s.cn ..." +echo "==========================================================" +echo "" + +ORIGINAL_REGISTRY=gcr.io +MY_REGISTRY=gcr.azk8s.cn + +gcr_imgs=( + "kfserving/kfserving-controller:0.2.2" + "ml-pipeline/api-server:0.2.0" + "kubeflow-images-public/kfam:v1.0.0-gf3e09203" + "kubeflow-images-public/ingress-setup:latest" + "kubeflow-images-public/kubernetes-sigs/application:1.0-beta" + "kubeflow-images-public/centraldashboard:v1.0.0-g3ec0de71" + "kubeflow-images-public/jupyter-web-app:v1.0.0-g2bd63238" + "kubeflow-images-public/katib/v1alpha3/katib-controller:v0.8.0" + "kubeflow-images-public/katib/v1alpha3/katib-db-manager:v0.8.0" + "kubeflow-images-public/katib/v1alpha3/katib-ui:v0.8.0" + "kubebuilder/kube-rbac-proxy:v0.4.0" + "metacontroller/metacontroller:v0.3.0" + "kubeflow-images-public/metadata:v0.1.11" + "ml-pipeline/envoy:metadata-grpc" + "tfx-oss-public/ml_metadata_store_server:v0.21.1" + "kubeflow-images-public/metadata-frontend:v0.1.8" + "ml-pipeline/visualization-server:0.2.0" + "ml-pipeline/persistenceagent:0.2.0" + "ml-pipeline/scheduledworkflow:0.2.0" + "ml-pipeline/frontend:0.2.0" + "ml-pipeline/viewer-crd-controller:0.2.0" + "kubeflow-images-public/notebook-controller:v1.0.0-gcd65ce25" + "kubeflow-images-public/profile-controller:v1.0.0-ge50a8531" + "kubeflow-images-public/pytorch-operator:v1.0.0-g047cf0f" + "spark-operator/spark-operator:v1beta2-1.0.0-2.4.4" + "spark-operator/spark-operator:v1beta2-1.0.0-2.4.4" + "google_containers/spartakus-amd64:v1.1.0" + "kubeflow-images-public/tf_operator:v1.0.0-g92389064" + "kubeflow-images-public/admission-webhook:v1.0.0-gaf96e4e3" +) + +for img in ${gcr_imgs[@]} +do + # 拉取镜像 + docker pull ${MY_REGISTRY}/${img} + # 添加Tag + docker tag ${MY_REGISTRY}/${img} ${ORIGINAL_REGISTRY}/${img} + # 输出 + docker save ${ORIGINAL_REGISTRY}/${img} > ${img##*/}.tar + # 输入 + microk8s.ctr -n k8s.io image import ${img##*/}.tar + # 删除Tag + docker rmi ${MY_REGISTRY}/${img} ${ORIGINAL_REGISTRY}/${img} +done + +echo "" +echo "==========================================================" +echo "pull kubeflow v1.0 images from gcr.azk8s.cn finished." +echo "==========================================================" +echo "" +``` + +如果还是有pod无法启动,可通过`kubectl describe pod 未启动pod的名称 -n kubeflow`查看原因 + +如果是因为镜像无法下载,可以将依赖的镜像加到上面的脚本里下载镜像 + +如果是因为镜像拉取策略导致每次都重新下载问题,可通过下面命令或者kubernetes-dashboard修改,将`Always` 改为 `IfNotPresent` + +``` +kubectl edit pod 未启动pod的名称 -n kubeflow +``` + +执行 `kubectl get pods --namespace kubeflow`查看kubeflow的pod都已运行起来 + +``` +NAME READY STATUS RESTARTS AGE +admission-webhook-bootstrap-stateful-set-0 1/1 Running 6 2d4h +admission-webhook-deployment-569558c8b6-n8b7k 1/1 Running 0 13h +application-controller-stateful-set-0 1/1 Running 3 2d4h +argo-ui-7ffb9b6577-w8pb7 1/1 Running 7 3d7h +centraldashboard-659bd78c-fxgqd 1/1 Running 3 3d7h +jupyter-web-app-deployment-878f9c988-xgh82 1/1 Running 3 2d5h +katib-controller-7f58569f7d-8bw7z 1/1 Running 4 3d7h +katib-db-manager-54b66f9f9d-ngqw9 1/1 Running 3 3d7h +katib-mysql-dcf7dcbd5-7wbck 1/1 Running 12 4d1h +katib-ui-6f97756598-4mtjs 1/1 Running 3 3d7h +kfserving-controller-manager-0 2/2 Running 7 2d5h +metacontroller-0 1/1 Running 5 3d7h +metadata-db-65fb5b695d-wq8vh 1/1 Running 12 4d1h +metadata-deployment-65ccddfd4c-vwfd2 1/1 Running 3 3d7h +metadata-envoy-deployment-7754f56bff-svtz2 1/1 Running 3 3d7h +metadata-grpc-deployment-75f9888cbf-zj4sn 1/1 Running 5 3d7h +metadata-ui-7c85545947-v68l7 1/1 Running 3 3d7h +minio-69b4676bb7-w96xk 1/1 Running 12 4d1h +ml-pipeline-5cddb75848-bsc48 1/1 Running 3 2d6h +ml-pipeline-ml-pipeline-visualizationserver-7f6fcb68c8-vxjj7 1/1 Running 3 2d7h +ml-pipeline-persistenceagent-6ff9fb86dc-dvxx4 1/1 Running 5 2d6h +ml-pipeline-scheduledworkflow-7f84b54646-ndxcb 1/1 Running 3 2d7h +ml-pipeline-ui-6758f58868-gqvlp 1/1 Running 3 2d6h +ml-pipeline-viewer-controller-deployment-685874bc58-jljw8 1/1 Running 3 2d5h +mysql-6bcbfbb6b8-xmphz 1/1 Running 12 4d1h +notebook-controller-deployment-7db7c8589d-mlgb4 1/1 Running 3 2d5h +profiles-deployment-56b7c6788f-kk8kh 2/2 Running 6 2d7h +pytorch-operator-cf8c5c497-nmfnv 1/1 Running 7 3d7h +seldon-controller-manager-6b4b969447-qp7l4 1/1 Running 20 4d1h +spark-operatorcrd-cleanup-rrpxd 0/2 Completed 0 3d7h +spark-operatorsparkoperator-76dd5f5688-kn28n 1/1 Running 3 3d7h +spartakus-volunteer-5dc96f4447-xjclm 1/1 Running 3 3d7h +tensorboard-5f685f9d79-9x549 1/1 Running 12 4d1h +tf-job-operator-5fb85c5fb7-lqvrg 1/1 Running 6 3d7h +workflow-controller-689d6c8846-znvt9 1/1 Running 12 4d1h +``` + +执行如下命令进行端口映射访问Kubeflow UI + +``` +nohup kubectl port-forward -n istio-system svc/istio-ingressgateway 8088:80 & +``` + +访问http://127.0.0.1:8088/ + +![](/images/media/选区_053.png) + +#### 创建Jupyter notebook server + +![](/images/media/选区_054.png) + +![](/images/media/选区_055.png) + +![](/images/media/选区_056.png) + +点击连接之后就可以跑模型训练了 + +#### 测试Jupyter + +创建Python 3 notebook,执行如下代码 + +``` +from tensorflow.examples.tutorials.mnist import input_data +mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) + +import tensorflow as tf + +x = tf.placeholder(tf.float32, [None, 784]) + +W = tf.Variable(tf.zeros([784, 10])) +b = tf.Variable(tf.zeros([10])) + +y = tf.nn.softmax(tf.matmul(x, W) + b) + +y_ = tf.placeholder(tf.float32, [None, 10]) +cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])) + +train_step = tf.train.GradientDescentOptimizer(0.05).minimize(cross_entropy) + +sess = tf.InteractiveSession() +tf.global_variables_initializer().run() + +for _ in range(1000): + batch_xs, batch_ys = mnist.train.next_batch(100) + sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) + +correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) +accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) +print("Accuracy: ", sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})) +``` + +运行结果如下 + +``` +Accuracy: 0.9012 +``` + diff --git "a/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" new file mode 100644 index 0000000..3ef6854 --- /dev/null +++ "b/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -0,0 +1,332 @@ +--- +title: ubuntu 18.04安装microk8s教程 +date: 2020-04-14 18:21:11 +categories: +- k8s +tags: +- k8s +- microk8s +--- + +[Microk8s](https://microk8s.io/)是一个集成化的容器管理平台,与Kubernetes完全兼容,主要面向工作站、边缘计算和IoT等领域建立容器计算平台。 + + + +#### 安装 microk8s + +```shell +snap install microk8s --classic --channel=1.15/stable +``` + +#### 设置别名 + +```shell +sudo snap alias microk8s.kubectl kubectl +``` + +#### config配置 + +``` +sudo microk8s.kubectl config view --raw > $HOME/.kube/config +``` + +#### 启用k8s组件 + +```shell +microk8s.enable dashboard dns ingress istio registry storage +``` + +#### 如果有GPU + +```shell +microk8s.enable gpu +``` + +#### 执行 `microk8s.enable` 顺利的话,你将看到类似下面的日志 + +```shell +logentry.config.istio.io/accesslog created +logentry.config.istio.io/tcpaccesslog created +rule.config.istio.io/stdio created +rule.config.istio.io/stdiotcp created +... +... +Istio is starting +Enabling the private registry +Enabling default storage class +deployment.extensions/hostpath-provisioner created +storageclass.storage.k8s.io/microk8s-hostpath created +Storage will be available soon +Applying registry manifest +namespace/container-registry created +persistentvolumeclaim/registry-claim created +deployment.extensions/registry created +service/registry created +The registry is enabled +Enabling default storage class +deployment.extensions/hostpath-provisioner unchanged +storageclass.storage.k8s.io/microk8s-hostpath unchanged +Storage will be available soon +``` + +#### 使用 `microk8s.status` 检查各个组件的状态 + +```sh +microk8s is running +addons: +knative: disabled +jaeger: disabled +fluentd: disabled +gpu: enabled +cilium: disabled +storage: enabled +registry: enabled +rbac: disabled +ingress: enabled +dns: enabled +metrics-server: disabled +linkerd: disabled +prometheus: disabled +istio: enabled +dashboard: enabled +``` + +#### 使用 `microk8s.inspect` 排查下安装部署结果 + +``` +Inspecting services + Service snap.microk8s.daemon-containerd is running + Service snap.microk8s.daemon-docker is running + Service snap.microk8s.daemon-apiserver is running + Service snap.microk8s.daemon-proxy is running + Service snap.microk8s.daemon-kubelet is running + Service snap.microk8s.daemon-scheduler is running + Service snap.microk8s.daemon-controller-manager is running + Service snap.microk8s.daemon-etcd is running + Copy service arguments to the final report tarball +Inspecting AppArmor configuration +Gathering system info + Copy network configuration to the final report tarball + Copy processes list to the final report tarball + Copy snap list to the final report tarball + Inspect kubernetes cluster + + WARNING: IPtables FORWARD policy is DROP. Consider enabling traffic forwarding with: sudo iptables -P FORWARD ACCEPT +``` + +执行如下命令 + +``` +sudo ufw default allow routed +sudo iptables -P FORWARD ACCEPT +``` + +再次使用 `microk8s.inspect` 命令检查,会发现 WARNING消失了 + +#### 使用 `microk8s.kubectl get pods --all-namespaces` 查看当前 Kubernetes pods 状态 + +``` +NAMESPACE NAME READY STATUS RESTARTS AGE +container-registry registry-7fc4594d64-rrgs9 0/1 Pending 0 15m +default default-http-backend-855bc7bc45-t4st8 0/1 ContainerCreating 0 16m +default nginx-ingress-microk8s-controller-kgjtl 0/1 ContainerCreating 0 16m +... +... +``` + +大部分pod都没有启动起来,什么原因呢? + +#### 使用 describe 命令查看 pod + +``` +kubectl describe pod default-http-backend -n container-registry +``` + +日志如下 + +``` +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Warning FailedCreatePodSandBox 22m (x33 over 69m) kubelet, izwz9h8m2chowowqckbcy0z Failed create pod sandbox: rpc error: code = Unknown desc = failed to get sandbox image "k8s.gcr.io/pause:3.1": failed to pull image "k8s.gcr.io/pause:3.1": failed to resolve image "k8s.gcr.io/pause:3.1": no available registry endpoint: failed to do request: Head https://k8s.gcr.io/v2/pause/manifests/3.1: dial tcp 108.177.97.82:443: i/o timeout +``` + +这是 pod 的 sandbox 镜像拉取失败。 + +网上查资料,k8s.gcr.io/pause:3.1 是存放在 google cloud 上的镜像,由于众所周知的原因,访问失败了。 + +解决的方法有: + +1. 科学上网 +2. 手动下载镜像 + +#### 方法1操作流程 + +编辑 MicroK8s 使用的 docker 环境变量配置文件,`vim /var/snap/microk8s/current/args/containerd-env`在其中添加代理配置 + +``` +HTTPS_PROXY=https://127.0.0.1:8123 +``` + +重启 docker + +``` +sudo systemctl restart snap.microk8s.daemon-docker.service +``` + +重置 MicroK8s 并再次尝试安装各种组件 + +``` +microk8s.reset +microk8s.enable dashboard dns ingress istio registry storage +``` + +#### 方法2操作流程 + +安装 docker + +``` +sudo apt install docker-ce +``` + +感谢微软 azure 提供 gcr 镜像下载:[地址](http://mirror.azure.cn/help/gcr-proxy-cache.html) + +``` +docker pull gcr.azk8s.cn/google_containers/pause:3.1 +docker tag gcr.azk8s.cn/google_containers/pause:3.1 k8s.gcr.io/pause:3.1 +``` + +**v1.14 之后 microk8s 使用 containerd 代替 dockerd**,具体可见这个[issue](https://github.com/ubuntu/microk8s/issues/382) + +> Indeed in the 1.14 release contanerd replaced dockerd. + +要么使用私有仓库 registry,要么手动把 docker 镜像导入到 containerd。microk8s 官网提供了例子:[Working with locally built images without a registry](https://microk8s.io/docs/working)。 这里先使用手动操作,以后再建立私有仓库 + +``` +docker save k8s.gcr.io/pause:3.1 > pause.tar +microk8s.ctr -n k8s.io image import pause.tar +``` + +`-n` 是指定 namespace。`microk8s.ctr -n k8s.io image ls`,看到导入的镜像了: + +``` +k8s.gcr.io/pause:3.1 application/vnd.oci.image.manifest.v1+json sha256:3efe4ff64c93123e1217b0ad6d23b4c87a1fc2109afeff55d2f27d70c55d8f73 728.9 KiB linux/amd64 io.cri-containerd.image=managed +``` + +其他组件如果遇到gcr.io无法访问的情况也可使用如上的方法,这里特别写了个脚本来自动下载并导入这些镜像 + +```shell +#!/usr/bin/env bash + +echo "" +echo "==========================================================" +echo "pull microk8s v1.15.11 images from gcr.azk8s.cn ..." +echo "==========================================================" +echo "" + + +gcr_imgs=( + "gcr.azk8s.cn/google_containers/pause:3.1,k8s.gcr.io/pause:3.1" + "gcr.azk8s.cn/google_containers/heapster-influxdb-amd64:v1.3.3,k8s.gcr.io/heapster-influxdb-amd64:v1.3.3" + "gcr.azk8s.cn/google_containers/heapster-grafana-amd64:v4.4.3,k8s.gcr.io/heapster-grafana-amd64:v4.4.3" + "gcr.azk8s.cn/google_containers/kubernetes-dashboard-amd64:v1.10.1,k8s.gcr.io/google_containers/kubernetes-dashboard-amd64:v1.10.1" + "gcr.azk8s.cn/google_containers/heapster-amd64:v1.5.2,k8s.gcr.io/heapster-amd64:v1.5.2" + "gcr.azk8s.cn/google_containers/defaultbackend-amd64:1.4,gcr.io/google_containers/defaultbackend-amd64:1.4" +) + +for img in ${gcr_imgs[@]} +do + img_array=(${img//,/ }) + # 拉取镜像 + docker pull ${img_array[0]} + # 添加Tag + docker tag ${img_array[0]} ${img_array[1]} + # 输出 + docker save ${img_array[1]} > ${img_array[1]##*/}.tar + # 输入 + microk8s.ctr -n k8s.io image import ${img_array[1]##*/}.tar + # 删除Tag + docker rmi ${img_array[0]} ${img_array[1]} +done + +echo "" +echo "==========================================================" +echo "pull microk8s v1.15.11 images from gcr.azk8s.cn finished." +echo "==========================================================" +echo "" +``` + +使用 `microk8s.kubectl get pods --all-namespaces` 继续进行验证 + +``` +NAMESPACE NAME READY STATUS RESTARTS AGE +cert-manager cert-manager-5d849b9888-8nh9j 1/1 Running 12 3d18h +cert-manager cert-manager-cainjector-dccb4d7f-7rrkf 1/1 Running 15 3d +cert-manager cert-manager-webhook-695df7dbb-gpsqs 1/1 Running 12 3d18h +container-registry registry-6c99589dc-gttcq 1/1 Running 15 4d4h +default default-http-backend-5d5ff5d4f5-g9h8h 1/1 Running 15 4d4h +default nginx-ingress-microk8s-controller-td2mz 1/1 Running 59 3h26m +istio-system cluster-local-gateway-7bf56777fb-rbjjn 1/1 Running 12 3d18h +istio-system grafana-6575997f54-j77rc 1/1 Running 6 3d +istio-system istio-citadel-894d98c85-xr8qm 1/1 Running 12 3d19h +istio-system istio-cleanup-secrets-1.2.2-l4djr 0/1 Completed 0 3d19h +istio-system istio-egressgateway-9b7866bf5-h8ltc 1/1 Running 10 3d +istio-system istio-galley-5b984f89b-w26n9 1/1 Running 0 6h43m +istio-system istio-grafana-post-install-1.2.2-v5sfg 0/1 Completed 0 3d19h +istio-system istio-ingressgateway-75ddf64567-glfkm 1/1 Running 12 3d19h +istio-system istio-pilot-5d77c559d4-nhc7d 2/2 Running 14 3d +istio-system istio-policy-86478df5d4-w2lgb 2/2 Running 46 3d +istio-system istio-security-post-install-1.2.2-sczrc 0/1 Completed 0 3d19h +istio-system istio-sidecar-injector-7b98dd6bcc-g597g 1/1 Running 8 3d +istio-system istio-telemetry-786747687f-t8k6k 2/2 Running 35 3d +istio-system istio-tracing-555cf644d-4d9f4 1/1 Running 13 3d19h +istio-system kfserving-ingressgateway-64c7bd9b76-2rcxt 1/1 Running 12 3d18h +istio-system kiali-6cd6f9dfb5-tlwzq 1/1 Running 13 3d19h +istio-system prometheus-7d7b9f7844-swqf8 1/1 Running 19 3d19h +kube-system coredns-f7867546d-wkv76 1/1 Running 15 4d4h +kube-system heapster-v1.5.2-844b564688-kr9t8 4/4 Running 60 4d4h +kube-system hostpath-provisioner-65cfd8595b-rjlhz 1/1 Running 5 3d +kube-system kubernetes-dashboard-7d75c474bb-s7n2t 1/1 Running 15 4d4h +kube-system monitoring-influxdb-grafana-v4-6b6954958c-spcqb 2/2 Running 32 4d4h +kube-system nvidia-device-plugin-daemonset-jv96f 1/1 Running 14 3d23h +``` + +如果你看到的结果类似上面这样,说明 Kubernetes 是真的就绪了。 + +#### 查看 Dashboard + +`microk8s.kubectl describe service kubernetes-dashboard -n kube-system`获取访问ip和端口 + +``` +Name: kubernetes-dashboard +Namespace: kube-system +Labels: k8s-app=kubernetes-dashboard +Annotations: kubectl.kubernetes.io/last-applied-configuration: + {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"k8s-app":"kubernetes-dashboard"},"name":"kubernetes-dashboard"... +Selector: k8s-app=kubernetes-dashboard +Type: ClusterIP +IP: 10.152.183.151 +Port: 443/TCP +``` + +接着访问下面的地址,就能看到我们熟悉的 Dashboard + +``` +https://10.152.183.151/ +``` + +![](/images/media/选区_051.png) + +#### 使用令牌登录 + +获取token + +```shell +token=$(microk8s kubectl -n kube-system get secret | grep default-token | cut -d " " -f1) + echo $token +microk8s kubectl -n kube-system describe secret $token +``` + +输入token后就进入管理页面了 + +![](/images/media/选区_052.png) \ No newline at end of file From b630814c353514b9c547aab263d57d4578942a4f Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 5 Apr 2020 00:21:02 +0800 Subject: [PATCH 06/23] =?UTF-8?q?=E6=97=A5=E6=9C=9F=E5=86=99=E9=94=99?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...beflow\345\256\211\350\243\205\346\225\231\347\250\213.md" | 4 ++-- ...crok8s\345\256\211\350\243\205\346\225\231\347\250\213.md" | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index 935f7e8..75c72cf 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -1,8 +1,8 @@ --- title: kubeflow1.0 安装教程 -date: 2020-04-14 18:21:11 +date: 2020-04-04 18:21:11 categories: -- k8s +- kubeflow tags: - k8s - kubeflow diff --git "a/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" index 3ef6854..af7c90b 100644 --- "a/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -1,6 +1,6 @@ --- title: ubuntu 18.04安装microk8s教程 -date: 2020-04-14 18:21:11 +date: 2020-04-04 18:21:11 categories: - k8s tags: From d5efbdbf634d6c6b7f306ea10110c70a0c91702c Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 5 Apr 2020 00:25:20 +0800 Subject: [PATCH 07/23] =?UTF-8?q?=E6=97=A5=E6=9C=9F=E5=86=99=E9=94=99?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" | 2 +- ...kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename "source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" => "source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" (99%) diff --git "a/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" similarity index 99% rename from "source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" rename to "source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" index af7c90b..1a7c514 100644 --- "a/source/_posts/2020-04-04-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -1,6 +1,6 @@ --- title: ubuntu 18.04安装microk8s教程 -date: 2020-04-04 18:21:11 +date: 2020-04-03 20:21:11 categories: - k8s tags: diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index 75c72cf..9a4d257 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -1,6 +1,6 @@ --- title: kubeflow1.0 安装教程 -date: 2020-04-04 18:21:11 +date: 2020-04-04 20:21:11 categories: - kubeflow tags: From c69b0427efabec646d53fc316e5b6538b763717e Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 5 Apr 2020 14:40:59 +0800 Subject: [PATCH 08/23] add CNAME --- source/CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 source/CNAME diff --git a/source/CNAME b/source/CNAME new file mode 100644 index 0000000..16774d0 --- /dev/null +++ b/source/CNAME @@ -0,0 +1 @@ +blog.flyfox.top \ No newline at end of file From 101a7543ad7ad85e3276f4e864e77b5e752f34b9 Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 5 Apr 2020 16:50:02 +0800 Subject: [PATCH 09/23] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E7=AB=A0,?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E9=98=BF=E9=87=8C=E4=BA=91=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E9=95=9C=E5=83=8F=E6=9C=8D=E5=8A=A1=E4=B8=8B=E8=BD=BDgcr-io?= =?UTF-8?q?=E9=95=9C=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...11\350\243\205\346\225\231\347\250\213.md" | 4 +- ...\275\275gcr-io\351\225\234\345\203\217.md" | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 "source/_posts/2020-04-05-\351\200\232\350\277\207\351\230\277\351\207\214\344\272\221\345\256\271\345\231\250\351\225\234\345\203\217\346\234\215\345\212\241\344\270\213\350\275\275gcr-io\351\225\234\345\203\217.md" diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index 9a4d257..eac1a88 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -74,9 +74,7 @@ kubectl -n kubeflow get all 输出如下日志即安装成功 -``` -INFO[0259] Applied the configuration Successfully! filename="cmd/apply.go:72" -``` +![](/images/media/选区_047.png) 查看当前 Kubernetes pods 状态 diff --git "a/source/_posts/2020-04-05-\351\200\232\350\277\207\351\230\277\351\207\214\344\272\221\345\256\271\345\231\250\351\225\234\345\203\217\346\234\215\345\212\241\344\270\213\350\275\275gcr-io\351\225\234\345\203\217.md" "b/source/_posts/2020-04-05-\351\200\232\350\277\207\351\230\277\351\207\214\344\272\221\345\256\271\345\231\250\351\225\234\345\203\217\346\234\215\345\212\241\344\270\213\350\275\275gcr-io\351\225\234\345\203\217.md" new file mode 100644 index 0000000..c764d39 --- /dev/null +++ "b/source/_posts/2020-04-05-\351\200\232\350\277\207\351\230\277\351\207\214\344\272\221\345\256\271\345\231\250\351\225\234\345\203\217\346\234\215\345\212\241\344\270\213\350\275\275gcr-io\351\225\234\345\203\217.md" @@ -0,0 +1,59 @@ +--- +title: 通过阿里云容器镜像服务下载gcr.io镜像 +date: 2020-04-05 15:49:25 +categories: +- k8s +tags: +- k8s +- github +- docker +--- + +安装k8s时发现好多镜像都是gcr.io上的,在国内由于被墙而不能正常下载,也就导致了集群不能正常安装。那么问题来了,要怎样才能下载这些镜像呢?我们要寻找免费下载gcr.io镜像的途径,阿里云就提供了这一服务。本文通过github设置代码源下载所需的gcr.io镜像。 + + + +#### github创建仓库 + +首先在github创建一个repository,创建好后然后git clone到本地,并在本地创建所需下载的镜像dockerfile,这里本地的目录层级为 镜像名称->版本号->dockerfile。创建之后再把所有的文件push到github仓库。这里是我的github上的[dockderfile仓库](https://github.com/smartliby/docker-library),大家可以follow我的项目 + +![](/images/media/选区_057.png) + +选取其中一个组件的dockerfile,查看其中的内容 + +``` +FROM gcr.io/kubeflow-images-public/tensorflow-1.15.2-notebook-cpu:1.0.0 +MAINTAINER smartliby +``` + +里面的内容非常少,就两行,其中第一行是基于某个镜像制作的新镜像,第二行为作者信息。通过这个dockerfile我们就可以看出端倪来了,其实我们什么都没做,就是利用阿里云这个介质帮我们翻墙去下载镜像。 + +#### 登录[阿里云镜像](https://cr.console.aliyun.com/) + +创建镜像仓库 + +![](/images/media/选区_059.png) + +选择镜像构建所依赖的在github仓库 + +![](/images/media/选区_060.png) + +进入刚创建的仓库然后选择构建菜单点击添加构建规则 + +![](/images/media/选区_061.png) + +点击立即构建 + +![](/images/media/选区_063.png) + +构建成功 + +![](/images/media/选区_062.png) + +#### 使用镜像 + +``` +docker pull registry.cn-beijing.aliyuncs.com/smartliby/tensorflow-1.15.2-notebook-gpu:1.0.0 +docker tag registry.cn-beijing.aliyuncs.com/smartliby/tensorflow-1.15.2-notebook-gpu:1.0.0 gcr.io/kubeflow-images-public/tensorflow-1.15.2-notebook-gpu:1.0.0 +``` + From d2711c8494871c4e35d5576ed4e5203703046ad3 Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 5 Apr 2020 23:28:14 +0800 Subject: [PATCH 10/23] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=9F=9F=E5=90=8D?= =?UTF-8?q?=E7=AD=89=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index 87c29db..96f7405 100644 --- a/_config.yml +++ b/_config.yml @@ -18,7 +18,7 @@ symbols_count_time: # URL ## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/' -url: https://smartliby.github.io +url: https://blog.flyfox.top root: / permalink: :year/:month/:day/:title/ permalink_defaults: From 572b2ab4a5b3e16a229dfdae965b5fc30fe99e17 Mon Sep 17 00:00:00 2001 From: smartliby Date: Mon, 6 Apr 2020 19:40:21 +0800 Subject: [PATCH 11/23] =?UTF-8?q?=E6=B7=BB=E5=8A=A0hexo=E6=90=AD=E5=BB=BA?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...11\350\243\205\346\225\231\347\250\213.md" | 2 +- ...52\344\272\272\345\215\232\345\256\242.md" | 262 ++++++++++++++++++ 2 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 "source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index eac1a88..0e57c66 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -1,5 +1,5 @@ --- -title: kubeflow1.0 安装教程 +title: kubeflow 1.0 安装教程 date: 2020-04-04 20:21:11 categories: - kubeflow diff --git "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" new file mode 100644 index 0000000..54ef642 --- /dev/null +++ "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" @@ -0,0 +1,262 @@ +--- +title: Ubuntu+Hexo+Github Pages搭建个人博客 +date: 2020-04-06 14:24:21 +categories: +- hexo +tags: +- hexo +- ubuntu +- gitHub pages +- zeit.co +--- + +我的个人博客其实若干年前就搭建完成并投入使用了,但是比较懒一直没有写笔记,最近发现百度爬虫没有收录我的个人博客文章,研究了一下发现是github把百度爬虫给禁掉了,解决一下顺便补一下笔记吧 + + + +## 安装Nodejs + +Node.js是基于Chrome V8引擎的JavaScript运行环境,npm是随Node.js一起安装的包管理工具,新版的Node.js集成了npm。 + +``` +sudo apt install nodejs +sudo apt install npm +``` + +检查node版本:`node -v` + +``` +v8.10.0 +``` + +检查npm版本:`npm -v` + +``` +6.9.0 +``` + +## 安装Hexo + +Hexo是一个基于nodw.js的快速、简介且高效的博客框架,支持Markdown解析文章。简言之,hexo将Markdown编写的文章生成为静态html页面,然后部署到github。 +安装hexo:`sudo npm install -g hexo`。 +在指定文件夹新建所需的文件: + +``` +hexo init +cd +npm install +``` + +该位置就是hexo的工作空间,该工作空间的目录如下: + +```shell +. +├── _config.yml +├── package.json +├── scaffolds +├── source +| ├── _drafts +| └── _posts +└── themes +``` + +其中,`_config.yml`是博客网站的配置文件,`source`文件夹是存放用户资源的地方,`_posts` 文件夹存放Markdown文件(.md),`scaffolds`是模板文件夹,当用hexo新建文章时,hexo会根据`scaffolds`文件夹下的文件来建立文件,`themes`文件夹是存放主题的文件夹,hexo根据主题生成静态页面。 +关于_config.yml的补充说明:其中工作空间根目录下有一个_config.yml,是博客网站的配置文件,themes文件夹中对应不同主题的目录下也有一个_config.yml文件夹,是主题的配置文件。 + +## 配置Hexo + +### hexo常用命令 + +| 命令 | 作用 | 简写 | +| :---------------------- | :------------------------------------------------: | :----: | +| hexo init "folder-name" | 新建一个网站 | | +| hexo new "title-name" | 新建一篇文章 | | +| hexo generate | 生成静态文件 | hexo g | +| hexo server | 启动服务器,默认服务器网址:http://localhost:4000/ | hexo s | +| hexo deploy | 部署网站 | hexo d | +| hexo clean | 清楚缓存文件 | | + +### 更换主题 + +默认主题为landscape,更换为next或其它主题。 +下载主题命令: + +``` +git clone https://github.com/theme-next/hexo-theme-next +git pull +``` + +我一般会在自己的github保存hexo-theme-next主题,这样方便个性化修改保存,我的主题地址大家可以参考下 + +``` +git@github.com:smartliby/hexo-theme-next.git +``` + +采用`git`命令克隆主题文件,以后更新可以通过`git pull`命令来快速更新,而不用再次下载安装包进行替换。 +打开_config.yml文件,修改`theme`为`next`。然后运行: + +``` +hexo clean +hexo g +hexo s +``` + +打开`http://localhost:4000/`可以发现主题更改了。 + +## 安装配置github + +首先查看是否已经安装git,`git --version`,一般ubuntu自带git。若没有安装采用`sudo apt install git`进行安装。 + +### 配置github + +命令行输入: + +``` +git config --global user.name "your user name" +git config --global user.email "your email address" +``` + +### 创建公钥 + +命令行输入: + +``` +ssh-keygen -C 'your email address' -t rsa +``` + +一直按回车直至结束,结束后会在`~/.ssh/`下建立密钥文件,即`~/.ssh/id_rsa_pub`,打开该文件,复制全部内容。 + +### github添加公钥 + +点击个人头像—>settings—>SSH and GPG keys—>New SSH key,粘贴刚才复制的文本。 + +### 创建项目仓库 + +在github页面,选择New repository,Respository name输入`username.github.io`,点击确定。 + +## hexo将静态页面部署到github + +打开hexo目录下的`_config.yml`,在最后添加: + +``` +deploy: + type: git + repository: git@github.com:username/username.github.io.git + branch: master +``` + +master分支托管public目录下的静态网页代码,source分支托管markdown源码,这样就不用担心源码丢失了,就算电脑丢了也不怕,同时也方便管理,**平时在source分支开发即可**。 + +我平时写文章的流程: + +1. hexo new "title-name" +2. `hexo g` 生成静态网页代码 +3. `hexo d` push到远程master分支 +4. 在source分支执行 `git add -A` `git commit -m "提交内容"` `git push` + +然后安装hexo插件: + +``` +npm install hexo-deployer-git --save +``` + +最终进行部署,命令行输入: + +``` +hexo clean +hexo g +hexo d +``` + +现在就可以通过`username.github.io`访问你的博客了! + +## 丰富博客功能安装一些插件或者配置 + +* [gitalk](https://gitalk.github.io/) 评论功能 +* [busuanzi](https://busuanzi.ibruce.info/) 极简网页计数器 +* local_search 搜索功能 +* google_analytics 网站运行情况分析 +* baidu_analytics 网站运行情况分析 +* [google_site_verification](https://search.google.com/search-console) 验证网站所有权,SEO优化 +* [baidu_site_verification](https://ziyuan.baidu.com/linksubmit/index) 验证网站所有权,SEO优化 +* needmoreshare2 分享功能 + +以上是本人使用的一些插件和配置,大家参考一下,可根据自己情况选择安装和配置,具体安装和配置方法可自行google + +## 绑定域名 + +首先申请域名,我是在[阿里云](https://homenew.console.aliyun.com/)申请的,需要备案 + +域名解析配置,添加一条CNAME记录 + +![](/images/media/选区_068.png) + +github pages 上 `CNAME` 文件配置 + +方法1:静态源码中添加CNAME文件,内容为申请的域名并执行`hexo g` `hexo d`部署到github上 + +![](/images/media/选区_071.png) + +方法2:直接在github.io仓库的Settings的`GitHub Pages`项直接设置`Custom domain`,github会自动添加CNAME文件 + +![](/images/media/选区_070.png) + +现在使用申请的域名访问一下试试吧 + +## 解决百度爬虫无法爬取 Github Pages 个人博客问题 + +网上有很多方法可以使百度爬虫爬取博客页面,总结起来主要有: + +1. CDN,利用云服务提供商将 blog 多做几个镜像。 +2. 换托管平台,比如说国内的代码托管平台。 +3. 自行使用 VPS 托管。 + +CDN 比较贵还不完美,不适合小流量网站,又不想换托管平台,VPS 大陆访问速度不快。 + +有没有简单、可靠还免费的方法? + +有,真的有,[zeit.co](https://zeit.co/)就是目前比较好的一个选择,一个静态网页和无状态函数托管的云平台。试用了之后,感觉非常强大,它能够以 Github App 的形式与 GitHub 集成,接管 repo 的 CI,进行深度定制,并且能够快速部署、自动伸缩。 + +关键是,现在基本功能是免费的,这对于我们托管博客来说,已经很够用了。更惊喜的是,它还提供智能 CDN 和智能 DNS + +![](/images/media/选区_066.png) + + + +本质上他们提供了 Storage + CDN + DNS 这一套完整服务。根据他们的文档,整个过程我只需要: + +- 用我的 Github 账户登陆 +- Import Project—>Import Git Repository—>给zeit 我的静态网页 repo 的 read 权限 +- 导入过程中,选择 other 模板即可,默认 ci 命令不用改,Root Directory 也不用改,导入完成后就会自动帮你 deploy。 +- 等几秒,importing +- 部署成功! + +不用写任何 code,点两下鼠标就完事了。部署完成后,会生成一个类似于 xxxxxxx.now.sh 的链接,点击即可访问,静态资源已经部署到了他们的边缘 CDN 节点上。 + +![](/images/media/选区_067.png) + +接着在[zeit.co](https://zeit.co/)设置域名 + +Selecting Your Project—>Navigating to Domain Settings—>Entering Your Chosen Domain—>Configuring the Domain + +![](/images/media/选区_069.png) + +到了这一步,接下来需要做的就是切换域名,修改 DNS 指向。 + +我这里使用的是cloudflare的DNS功能,用其他的也可以,因为我申请的域名之前是为梯子用的,cloudflare的CDN免费并且支持websocket,所以我这里就继续这么用了,在cloudflare上添加CNAME 记录就行了。 + +![](/images/media/选区_068.png) + +## 百度爬取 + +最后在[百度站长工具](https://ziyuan.baidu.com/)页面,在 *数据监控* > *抓取诊断*,进行测试,测试通过后选择链接提交以sitemap方式提交链接即可,之后百度就会开始爬取我们的博客了 + +## 参考 + +[1] 解决百度爬虫无法爬取 Github Pages 个人博客的问题:https://zpjiang.me/2020/01/15/let-baidu-index-github-page/ + +[2] zeit.co 帮助文档:https://zeit.co/docs + +[3] 使用 zeit.co 托管 Hexo 静态博客:https://www.qtmuniao.com/2020/03/15/hexo-to-zeit-co/ + +[4] 域名绑定:https://segmentfault.com/a/1190000011203711 \ No newline at end of file From 37a982d41538741b61afb051029f09d4931eac2a Mon Sep 17 00:00:00 2001 From: smartliby Date: Mon, 6 Apr 2020 19:48:18 +0800 Subject: [PATCH 12/23] =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" | 3 --- 1 file changed, 3 deletions(-) diff --git "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" index 54ef642..68b65bd 100644 --- "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" +++ "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" @@ -254,9 +254,6 @@ Selecting Your Project—>Navigating to Domain Settings—>Entering Your Chosen ## 参考 [1] 解决百度爬虫无法爬取 Github Pages 个人博客的问题:https://zpjiang.me/2020/01/15/let-baidu-index-github-page/ - [2] zeit.co 帮助文档:https://zeit.co/docs - [3] 使用 zeit.co 托管 Hexo 静态博客:https://www.qtmuniao.com/2020/03/15/hexo-to-zeit-co/ - [4] 域名绑定:https://segmentfault.com/a/1190000011203711 \ No newline at end of file From 9571552030306c1a5cb8c55cda1dbe3cfd27e73b Mon Sep 17 00:00:00 2001 From: smartliby Date: Mon, 6 Apr 2020 22:46:15 +0800 Subject: [PATCH 13/23] =?UTF-8?q?=E6=9B=B4=E6=96=B0Hexo=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\270\252\344\272\272\345\215\232\345\256\242.md" | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" index 68b65bd..0704c87 100644 --- "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" +++ "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" @@ -237,15 +237,17 @@ CDN 比较贵还不完美,不适合小流量网站,又不想换托管平台 接着在[zeit.co](https://zeit.co/)设置域名 -Selecting Your Project—>Navigating to Domain Settings—>Entering Your Chosen Domain—>Configuring the Domain +Selecting Your Project—>Settings—>Domains—>Entering Your Chosen Domain—>Add the Domain -![](/images/media/选区_069.png) +![](/images/media/选区_074.png) -到了这一步,接下来需要做的就是切换域名,修改 DNS 指向。 +这时候它会报错,因为你的域名还没有添加解析。这里,他们推荐的方式是让你的域名使用他们的Nameserver,或者说让他们提供DNS解析服务。但是我这里选择CNAME的方式。因为我一直使用的是cloudflare的DNS解析,我申请的域名之前是为梯子用的,cloudflare的CDN免费并且支持websocket,所以我这里就继续这么用了,在cloudflare上添加 CNAME 记录就行了,内容为上图的value值:`alias.zeit.co`。 -我这里使用的是cloudflare的DNS功能,用其他的也可以,因为我申请的域名之前是为梯子用的,cloudflare的CDN免费并且支持websocket,所以我这里就继续这么用了,在cloudflare上添加CNAME 记录就行了。 +![](/images/media/选区_072.png) -![](/images/media/选区_068.png) +如果还是报错的话,你可以试着删除(先点击“Edit”按钮,然后点击“Remove”)后重新添加,如下图即表示设置成功了 + +![](/images/media/选区_069.png) ## 百度爬取 From 11f9340f411240618507a7650ff8e2744b97c4a8 Mon Sep 17 00:00:00 2001 From: smartliby Date: Mon, 6 Apr 2020 22:50:24 +0800 Subject: [PATCH 14/23] =?UTF-8?q?=E6=9B=B4=E6=96=B0Hexo=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E5=8F=82=E8=80=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" index 0704c87..921181f 100644 --- "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" +++ "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" @@ -258,4 +258,5 @@ Selecting Your Project—>Settings—>Domains—>Entering Your Chosen Domain—> [1] 解决百度爬虫无法爬取 Github Pages 个人博客的问题:https://zpjiang.me/2020/01/15/let-baidu-index-github-page/ [2] zeit.co 帮助文档:https://zeit.co/docs [3] 使用 zeit.co 托管 Hexo 静态博客:https://www.qtmuniao.com/2020/03/15/hexo-to-zeit-co/ -[4] 域名绑定:https://segmentfault.com/a/1190000011203711 \ No newline at end of file +[4] 域名绑定:https://segmentfault.com/a/1190000011203711 +[5] zeit域名解析:https://blog.solariar.tech/2020/how-this-site-work-v2/ \ No newline at end of file From a3e663044fd850a7303f31166eb1ae349b4cfcc4 Mon Sep 17 00:00:00 2001 From: smartliby Date: Tue, 7 Apr 2020 11:26:11 +0800 Subject: [PATCH 15/23] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E6=A0=BC?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" index 921181f..fd87a69 100644 --- "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" +++ "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" @@ -71,10 +71,10 @@ npm install | :---------------------- | :------------------------------------------------: | :----: | | hexo init "folder-name" | 新建一个网站 | | | hexo new "title-name" | 新建一篇文章 | | +| hexo clean | 清除缓存文件 | | | hexo generate | 生成静态文件 | hexo g | | hexo server | 启动服务器,默认服务器网址:http://localhost:4000/ | hexo s | | hexo deploy | 部署网站 | hexo d | -| hexo clean | 清楚缓存文件 | | ### 更换主题 From b945e439fd7e7f78cc4514fde3ed92ed0f9457b3 Mon Sep 17 00:00:00 2001 From: smartliby Date: Tue, 7 Apr 2020 23:33:13 +0800 Subject: [PATCH 16/23] =?UTF-8?q?=E6=96=87=E7=AB=A0=E6=9C=AB=E5=B0=BE?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=AC=E4=BC=97=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" index fd87a69..ab6e812 100644 --- "a/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" +++ "b/source/_posts/2020-04-06-Ubuntu-Hexo-Github-Pages\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" @@ -37,7 +37,7 @@ v8.10.0 ## 安装Hexo -Hexo是一个基于nodw.js的快速、简介且高效的博客框架,支持Markdown解析文章。简言之,hexo将Markdown编写的文章生成为静态html页面,然后部署到github。 +Hexo是一个基于node.js的快速、简洁且高效的博客框架,支持Markdown解析文章。简言之,hexo将Markdown编写的文章生成为静态html页面,然后部署到github。 安装hexo:`sudo npm install -g hexo`。 在指定文件夹新建所需的文件: From a1ae6eeef26aca1eb53a6c40c5f49dff9d00125c Mon Sep 17 00:00:00 2001 From: smartliby Date: Tue, 7 Apr 2020 23:44:05 +0800 Subject: [PATCH 17/23] alt update --- ...20\347\240\201\350\260\203\350\257\225.md" | 10 +++---- ...57\345\242\203\350\256\276\347\275\256.md" | 28 +++++++++---------- ...0\275\275\347\245\236\345\231\250aria2.md" | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git "a/source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" "b/source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" index 7983742..e2ef3f0 100644 --- "a/source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" +++ "b/source/_posts/2017-02-14-Flume1-7\346\272\220\347\240\201\350\260\203\350\257\225.md" @@ -13,7 +13,7 @@ git clone https://github.com/apache/flume.git # 将源码导入Idea -![选区_021](/images/media/选区_021.png) +![](/images/media/选区_021.png) # 编译时会有以下jar仓库中无法找到并下载,需要手动下载到本地仓库 ``` linq4j-0.4.jar pentaho-aggdesigner-algorithm-5.1.3-jhyde.jar quidem-0.1.1.jar @@ -40,7 +40,7 @@ mvn install:install-file -Dfile=quidem-0.1.1.jar -DgroupId=net.hydromatic -Darti mvn clean install -DskipTests ``` -![选区_022](/images/media/选区_022.png) +![](/images/media/选区_022.png) # 本地调试 @@ -72,10 +72,10 @@ flume-conf.properties agent.sinks.k1.channel = c1 ``` -![选区_023](/images/media/选区_023.png) +![](/images/media/选区_023.png) 运行效果 -![选区_024](/images/media/选区_024.png) +![](/images/media/选区_024.png) # 远程调试 在conf/flume-env.properties增加以下配置,然后启动flume @@ -84,4 +84,4 @@ flume-conf.properties -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 ``` 在idea中启动远程调试 -![选区_025](/images/media/选区_025.png) +![](/images/media/选区_025.png) \ No newline at end of file diff --git "a/source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" "b/source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" index fc5676d..248565a 100644 --- "a/source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" +++ "b/source/_posts/2017-03-11-Ubuntu16-04\347\263\273\347\273\237\345\267\245\344\275\234\347\216\257\345\242\203\350\256\276\347\275\256.md" @@ -29,13 +29,13 @@ sudo apt-get update sudo apt-get install ultra-flat-icons ``` 3.安装完成后,打开unity-tweak-tool软件,修改主题和图标 -![选区_026](/images/media/选区_026.png) +![](/images/media/选区_026.png) 4.进入Theme,修改为Flatabulous -![Unity Tweak Tool_027](/images/media/Unity Tweak Tool_027.png) +![](/images/media/Unity Tweak Tool_027.png) 5.在此界面下进入Icons栏,修改为Ultra-flat -![Unity Tweak Tool_028](/images/media/Unity Tweak Tool_028.png) +![](/images/media/Unity Tweak Tool_028.png) 6.安装字体YaHei Consolas Hybrid @@ -61,7 +61,7 @@ sudo apt-get install vim git clone https://github.com/smartliby/maximum-awesome-linux.git cd maximum-awesome-linux && rake ``` -![工作区 1_040](/images/media/工作区 1_040.png) +![](/images/media/工作区 1_040.png) # 安装zsh、oh-my-zsh @@ -82,7 +82,7 @@ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/mas ```sh chsh -s /usr/bin/zsh ``` -![liby@kingsoft: ~_031](/images/media/liby@kingsoft:%20~_031.png) +![](/images/media/liby@kingsoft:%20~_031.png) # 安装terminator Ubuntu自带的终端是gnome-terminal,虽然也还不错,但是不能支持屏幕分割、选择复制等功能让我很不爽,于是我换用terminator作为终端,terminator可以支持屏幕分割,并且默认快捷键和gnome-terminal无异,熟悉gnome-terminal的话可以快速上手。 @@ -199,7 +199,7 @@ source ~/.zshrc 后,再执行ls或ll就可以看到彩色的目录或文件了。 配置完的terminator效果如下: -![工作区 1_045](/images/media/工作区 1_045.png) +![](/images/media/工作区 1_045.png) # 安装jdk1.8 @@ -266,8 +266,8 @@ tar -zxvf pycharm-professional-2016.3.2.tar.gz ``` # 修复idea和pycharm字体模糊锯齿和乱码等现象 设置字体为YaHei Consolas Hybrid,同时支持中英文 -![Settings_033](/images/media/Settings_033.png) -![Settings_034](/images/media/Settings_034.png) +![](/images/media/Settings_033.png) +![](/images/media/Settings_034.png) # idea与系统冲突的快捷键设置 ```sh @@ -330,7 +330,7 @@ sudo apt-get install openssh-server ``` # 开启远程桌面服务 1.Dash中打开桌面共享 - ![桌面共享首选项_029](/images/media/桌面共享首选项_029.png) + ![](/images/media/桌面共享首选项_029.png) 2.安装并运行dconf-editor,把加密选项去掉 @@ -340,14 +340,14 @@ sudo apt-get install openssh-server ``` 依次展开org->gnome->desktop->remote-access 这里也可以直接设置远程控制选项,但重要的是将“requre-encryption”去掉。 -![dconf 系统配置编辑器_030](/images/media/dconf 系统配置编辑器_030.png) +![](/images/media/dconf 系统配置编辑器_030.png) 之后就可以在其他的电脑上使用远程桌面登录了 # 16.04默认没有打开工作区切换功能需要手动打开,使用起来方便多了。 -![Unity Tweak Tool_039](/images/media/Unity Tweak Tool_039.png) -![工作区_041](/images/media/工作区_041.png) +![](/images/media/Unity Tweak Tool_039.png) +![](/images/media/工作区_041.png) # 最终的效果图 -![工作区 1_043](/images/media/工作区 1_076.png) -![工作区 1_044](/images/media/工作区 1_077.png) +![](/images/media/工作区 1_076.png) +![](/images/media/工作区 1_077.png) diff --git "a/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" "b/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" index 5aa3709..1688432 100644 --- "a/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" +++ "b/source/_posts/2019-05-12-Mac\343\200\201Ubuntu\347\263\273\347\273\237\347\232\204\344\270\213\350\275\275\347\245\236\345\231\250aria2.md" @@ -115,7 +115,7 @@ git clone https://github.com/ziahamza/webui-aria2 # 5.如何进行下载操作 随便打开一个百度网盘的链接,会发现网页上多出一个「导出下载」按钮,点击它弹出的「ARIA2 RPC」就自动添加到你的下载队列里了,然后利用 这里 提供的网页界面管理你的下载任务,如下图所示,你可以利用图形界面进行许多操作: -![aria2](/images/media/aria2.png) +![](/images/media/aria2.png) # 6.关闭 aria2 如果你想关掉后台的 aria2,可以到活动监视器中找到 aria2c 杀掉 From 2e29b7336d39624e70ac1ea9a0335e866c322706 Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 19 Apr 2020 15:45:11 +0800 Subject: [PATCH 18/23] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...11\350\243\205\346\225\231\347\250\213.md" | 51 +++-- ...11\350\243\205\346\225\231\347\250\213.md" | 144 +++++++------ ...11\350\243\205\346\225\231\347\250\213.md" | 199 ++++++++++++++++++ ...11\350\243\205\346\225\231\347\250\213.md" | 76 +++++++ ...03\217\345\272\223\345\222\214dockehub.md" | 85 ++++++++ 5 files changed, 476 insertions(+), 79 deletions(-) create mode 100644 "source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" create mode 100644 "source/_posts/2020-04-19-miniKF\345\256\211\350\243\205\346\225\231\347\250\213.md" create mode 100644 "source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" diff --git "a/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" index 1a7c514..f2c2bc3 100644 --- "a/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -220,18 +220,42 @@ k8s.gcr.io/pause:3.1 echo "" echo "==========================================================" -echo "pull microk8s v1.15.11 images from gcr.azk8s.cn ..." +echo "pull microk8s v1.15.11 images from aliyuncs ..." echo "==========================================================" echo "" +# registry.cn-hangzhou.aliyuncs.com/smartliby gcr_imgs=( - "gcr.azk8s.cn/google_containers/pause:3.1,k8s.gcr.io/pause:3.1" - "gcr.azk8s.cn/google_containers/heapster-influxdb-amd64:v1.3.3,k8s.gcr.io/heapster-influxdb-amd64:v1.3.3" - "gcr.azk8s.cn/google_containers/heapster-grafana-amd64:v4.4.3,k8s.gcr.io/heapster-grafana-amd64:v4.4.3" - "gcr.azk8s.cn/google_containers/kubernetes-dashboard-amd64:v1.10.1,k8s.gcr.io/google_containers/kubernetes-dashboard-amd64:v1.10.1" - "gcr.azk8s.cn/google_containers/heapster-amd64:v1.5.2,k8s.gcr.io/heapster-amd64:v1.5.2" - "gcr.azk8s.cn/google_containers/defaultbackend-amd64:1.4,gcr.io/google_containers/defaultbackend-amd64:1.4" + "registry.cn-hangzhou.aliyuncs.com/smartliby/pause:3.1,k8s.gcr.io/pause:3.1" + "registry.cn-hangzhou.aliyuncs.com/smartliby/heapster-influxdb-amd64:v1.3.3,k8s.gcr.io/heapster-influxdb-amd64:v1.3.3" + "registry.cn-hangzhou.aliyuncs.com/smartliby/heapster-grafana-amd64:v4.4.3,k8s.gcr.io/heapster-grafana-amd64:v4.4.3" + "registry.cn-hangzhou.aliyuncs.com/smartliby/kubernetes-dashboard-amd64:v1.10.1,k8s.gcr.io/google_containers/kubernetes-dashboard-amd64:v1.10.1" + "registry.cn-hangzhou.aliyuncs.com/smartliby/heapster-amd64:v1.5.2,k8s.gcr.io/heapster-amd64:v1.5.2" + "registry.cn-hangzhou.aliyuncs.com/smartliby/defaultbackend-amd64:1.4,gcr.io/google_containers/defaultbackend-amd64:1.4" + "registry.cn-hangzhou.aliyuncs.com/smartliby/nginx-ingress-controller-amd64:0.24.1,quay.io/kubernetes-ingress-controller/nginx-ingress-controller-amd64:0.24.1" + "registry.cn-hangzhou.aliyuncs.com/smartliby/grafana:6.1.6,grafana/grafana:6.1.6" + "registry.cn-hangzhou.aliyuncs.com/smartliby/addon-resizer-amd64:1.8.1,cdkbot/addon-resizer-amd64:1.8.1" + "registry.cn-hangzhou.aliyuncs.com/smartliby/hostpath-provisioner-amd64:1.0.0,cdkbot/hostpath-provisioner-amd64:1.0.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/dashboard:v2.0.0-rc5,kubernetesui/dashboard:v2.0.0-rc5" + "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-device-plugin:1.11,nvidia/k8s-device-plugin:1.11" + "registry.cn-hangzhou.aliyuncs.com/smartliby/controller:v0.8.2,metallb/controller:v0.8.2" + "registry.cn-hangzhou.aliyuncs.com/smartliby/speaker:v0.8.2,metallb/speaker:v0.8.2" + "registry.cn-hangzhou.aliyuncs.com/smartliby/citadel:1.3.4,docker.io/istio/citadel:1.3.4" + "registry.cn-hangzhou.aliyuncs.com/smartliby/jujud-operator:2.7.3,jujusolutions/jujud-operator:2.7.3" + "registry.cn-hangzhou.aliyuncs.com/smartliby/kicbase:v0.0.8,gcr.io/k8s-minikube/kicbase:v0.0.8" + "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-dns-dnsmasq-nanny-amd64:1.14.7,gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.7" + "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-dns-kube-dns-amd64:1.14.7,gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.7" + "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-dns-sidecar-amd64:1.14.7,gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.7" + "registry.cn-hangzhou.aliyuncs.com/smartliby/kubernetes-dashboard-amd64:v1.8.3,k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3" + "registry.cn-hangzhou.aliyuncs.com/smartliby/cert-manager-controller:v0.11.0,quay.io/jetstack/cert-manager-controller:v0.11.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/sidecar_injector:1.1.6,docker.io/istio/sidecar_injector:1.1.6" + "registry.cn-hangzhou.aliyuncs.com/smartliby/prometheus:v2.3.1,docker.io/prom/prometheus:v2.3.1" + "registry.cn-hangzhou.aliyuncs.com/smartliby/galley:1.1.6,docker.io/istio/galley:1.1.6" + "registry.cn-hangzhou.aliyuncs.com/smartliby/cert-manager-cainjector:v0.11.0,quay.io/jetstack/cert-manager-cainjector:v0.11.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/cert-manager-webhook:v0.11.0,quay.io/jetstack/cert-manager-webhook:v0.11.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/application:1.0-beta,gcr.io/kubeflow-images-public/kubernetes-sigs/application:1.0-beta" + "registry.cn-hangzhou.aliyuncs.com/smartliby/kiali:v0.16,docker.io/kiali/kiali:v0.16" ) for img in ${gcr_imgs[@]} @@ -240,18 +264,21 @@ do # 拉取镜像 docker pull ${img_array[0]} # 添加Tag - docker tag ${img_array[0]} ${img_array[1]} + image_name=${img_array[1]} + image_name=${image_name##*/} + image_name=${image_name%@*} + docker tag ${img_array[0]} ${image_name} # 输出 - docker save ${img_array[1]} > ${img_array[1]##*/}.tar + docker save ${image_name} > /data/k8s_img/kubeflow/${image_name}.tar # 输入 - microk8s.ctr -n k8s.io image import ${img_array[1]##*/}.tar + microk8s.ctr --namespace k8s.io image import /data/k8s_img/kubeflow/${image_name}.tar # 删除Tag - docker rmi ${img_array[0]} ${img_array[1]} + docker rmi ${img_array[0]} ${image_name} done echo "" echo "==========================================================" -echo "pull microk8s v1.15.11 images from gcr.azk8s.cn finished." +echo "pull microk8s v1.15.11 images from aliyuncs finished." echo "==========================================================" echo "" ``` diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index 0e57c66..bcb8200 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -15,34 +15,6 @@ tags: 目前Kubeflow仅支持在v1.15.11及以下版本的k8s上部署,v1.16及以上存在兼容性问题,具体情况可参考[这篇文章](https://www.kubeflow.org/docs/started/k8s/overview/),接下来我们基于[Microk8s](https://microk8s.io/)(版本1.15/stable)部署kubeflow v1.0 -#### 安装 knative v0.7.1 - -kubeflow安装时依赖knative和istio组件,所以需要先安装knative,istio(microk8s安装时已安装`microk8s.enable istio`,不需要再安装),knative 的镜像是用 sha256 方式来 pull的。在本地我们不能通过 docker tag 的方式重新打包,只能修改 yaml 里的所有配置 - -默认knative的安装配置文件在`/snap/microk8s/current/actions/knative/`目录下,没有操作权限无法修改,需要先拷贝出来或者去github下载到本地,并将里面的镜像下载域名由gcr.io改成gcr.azk8s.cn - -```shell -# 安装 Knative CRD -kubectl apply --selector knative.dev/crd-install=true -f serving.yaml - -# 再运行一遍 kubectl apply -kubectl apply -f serving.yaml -``` - -#### 验证 knative 安装 - -运行`kubectl get pods --namespace knative-serving`验证 Knative 所有 pod 是否可以正常启动 - -```shell -NAME READY STATUS RESTARTS AGE -activator-55f6c8d9b-2hs77 2/2 Running 24 2d13h -autoscaler-78d575f875-l7zfj 2/2 Running 18 2d13h -controller-776478fb94-hmmxc 1/1 Running 3 2d13h -networking-certmanager-779cd6f448-xtvrb 1/1 Running 3 2d13h -networking-istio-674bd78b75-688gc 1/1 Running 3 2d13h -webhook-59b575dc79-cs7f4 1/1 Running 0 13h -``` - #### 安装kubeflow 下载 kfctl binary from the [Kubeflow releases page](https://github.com/kubeflow/kfctl/releases/) @@ -82,7 +54,7 @@ kubectl -n kubeflow get all kubectl get pods --namespace kubeflow ``` -发现kubeflow的pod大部分没有启动成功,原因还是网络问题,需要访问gcr.io下载镜像 +发现kubeflow的pod大部分没有启动成功,原因还是网络问题,需要访问gcr.io下载镜像,之前我都是通过gcr.azk8s.cn镜像地址下载的,但是最近发现gcr.azk8s.cn这个地址无法使用了,所以只能通过自己构建然后保存到阿里云镜像库里,大家可以直接使用我已经构建好的镜像,执行下面脚本即可,也可自己构建,具体构建流程可以参考[这篇文章](https://blog.flyfox.top/2020/04/19/通过Travis-CI自动构建镜像到阿里云镜像库和dockehub) 执行以下脚本将镜像下载到本地并导入到microk8s @@ -91,66 +63,100 @@ kubectl get pods --namespace kubeflow echo "" echo "==========================================================" -echo "pull kubeflow v1.0 images from gcr.azk8s.cn ..." +echo "pull kubeflow v1.0 images from aliyuncs ..." echo "==========================================================" echo "" -ORIGINAL_REGISTRY=gcr.io -MY_REGISTRY=gcr.azk8s.cn +# registry.cn-hangzhou.aliyuncs.com/smartliby gcr_imgs=( - "kfserving/kfserving-controller:0.2.2" - "ml-pipeline/api-server:0.2.0" - "kubeflow-images-public/kfam:v1.0.0-gf3e09203" - "kubeflow-images-public/ingress-setup:latest" - "kubeflow-images-public/kubernetes-sigs/application:1.0-beta" - "kubeflow-images-public/centraldashboard:v1.0.0-g3ec0de71" - "kubeflow-images-public/jupyter-web-app:v1.0.0-g2bd63238" - "kubeflow-images-public/katib/v1alpha3/katib-controller:v0.8.0" - "kubeflow-images-public/katib/v1alpha3/katib-db-manager:v0.8.0" - "kubeflow-images-public/katib/v1alpha3/katib-ui:v0.8.0" - "kubebuilder/kube-rbac-proxy:v0.4.0" - "metacontroller/metacontroller:v0.3.0" - "kubeflow-images-public/metadata:v0.1.11" - "ml-pipeline/envoy:metadata-grpc" - "tfx-oss-public/ml_metadata_store_server:v0.21.1" - "kubeflow-images-public/metadata-frontend:v0.1.8" - "ml-pipeline/visualization-server:0.2.0" - "ml-pipeline/persistenceagent:0.2.0" - "ml-pipeline/scheduledworkflow:0.2.0" - "ml-pipeline/frontend:0.2.0" - "ml-pipeline/viewer-crd-controller:0.2.0" - "kubeflow-images-public/notebook-controller:v1.0.0-gcd65ce25" - "kubeflow-images-public/profile-controller:v1.0.0-ge50a8531" - "kubeflow-images-public/pytorch-operator:v1.0.0-g047cf0f" - "spark-operator/spark-operator:v1beta2-1.0.0-2.4.4" - "spark-operator/spark-operator:v1beta2-1.0.0-2.4.4" - "google_containers/spartakus-amd64:v1.1.0" - "kubeflow-images-public/tf_operator:v1.0.0-g92389064" - "kubeflow-images-public/admission-webhook:v1.0.0-gaf96e4e3" + "registry.cn-hangzhou.aliyuncs.com/smartliby/kfserving-controller:0.2.2,gcr.io/kfserving/kfserving-controller:0.2.2" + "registry.cn-hangzhou.aliyuncs.com/smartliby/api-server:0.2.0,gcr.io/ml-pipeline/api-server:0.2.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/kfam:v1.0.0-gf3e09203,gcr.io/kubeflow-images-public/kfam:v1.0.0-gf3e09203" + "registry.cn-hangzhou.aliyuncs.com/smartliby/ingress-setup:latest,gcr.io/kubeflow-images-public/ingress-setup:latest" + "registry.cn-hangzhou.aliyuncs.com/smartliby/application:1.0-beta,gcr.io/kubeflow-images-public/kubernetes-sigs/application:1.0-beta" + "registry.cn-hangzhou.aliyuncs.com/smartliby/centraldashboard:v1.0.0-g3ec0de71,gcr.io/kubeflow-images-public/centraldashboard:v1.0.0-g3ec0de71" + "registry.cn-hangzhou.aliyuncs.com/smartliby/jupyter-web-app:v1.0.0-g2bd63238,gcr.io/kubeflow-images-public/jupyter-web-app:v1.0.0-g2bd63238" + "registry.cn-hangzhou.aliyuncs.com/smartliby/katib-controller:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-controller:v0.8.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/katib-db-manager:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-db-manager:v0.8.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/katib-ui:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-ui:v0.8.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/kube-rbac-proxy:v0.4.0,gcr.io/kubebuilder/kube-rbac-proxy:v0.4.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/metacontroller:v0.3.0,gcr.io/metacontroller/metacontroller:v0.3.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/metadata:v0.1.11,gcr.io/kubeflow-images-public/metadata:v0.1.11" + "registry.cn-hangzhou.aliyuncs.com/smartliby/envoy:metadata-grpc,gcr.io/ml-pipeline/envoy:metadata-grpc" + "registry.cn-hangzhou.aliyuncs.com/smartliby/ml_metadata_store_server:v0.21.1,gcr.io/tfx-oss-public/ml_metadata_store_server:v0.21.1" + "registry.cn-hangzhou.aliyuncs.com/smartliby/metadata-frontend:v0.1.8,gcr.io/kubeflow-images-public/metadata-frontend:v0.1.8" + "registry.cn-hangzhou.aliyuncs.com/smartliby/visualization-server:0.2.0,gcr.io/ml-pipeline/visualization-server:0.2.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/persistenceagent:0.2.0,gcr.io/ml-pipeline/persistenceagent:0.2.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/scheduledworkflow:0.2.0,gcr.io/ml-pipeline/scheduledworkflow:0.2.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/frontend:0.2.0,gcr.io/ml-pipeline/frontend:0.2.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby,gcr.io/ml-pipeline/viewer-crd-controller:0.2.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/notebook-controller:v1.0.0-gcd65ce25,gcr.io/kubeflow-images-public/notebook-controller:v1.0.0-gcd65ce25" + "registry.cn-hangzhou.aliyuncs.com/smartliby/profile-controller:v1.0.0-ge50a8531,gcr.io/kubeflow-images-public/profile-controller:v1.0.0-ge50a8531" + "registry.cn-hangzhou.aliyuncs.com/smartliby/pytorch-operator:v1.0.0-g047cf0f,gcr.io/kubeflow-images-public/pytorch-operator:v1.0.0-g047cf0f" + "registry.cn-hangzhou.aliyuncs.com/smartliby/spark-operator:v1beta2-1.0.0-2.4.4,gcr.io/spark-operator/spark-operator:v1beta2-1.0.0-2.4.4" + "registry.cn-hangzhou.aliyuncs.com/smartliby/spartakus-amd64:v1.1.0,gcr.io/google_containers/spartakus-amd64:v1.1.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/tf_operator:v1.0.0-g92389064,gcr.io/kubeflow-images-public/tf_operator:v1.0.0-g92389064" + "registry.cn-hangzhou.aliyuncs.com/smartliby/admission-webhook:v1.0.0-gaf96e4e3,gcr.io/kubeflow-images-public/admission-webhook:v1.0.0-gaf96e4e3" + "smartliby/kfam:v1.0.0-gf3e09203,gcr.io/kubeflow-images-public/kfam:v1.0.0-gf3e09203" + "smartliby/api-server:0.2.0,gcr.io/ml-pipeline/api-server:0.2.0" ) for img in ${gcr_imgs[@]} do + img_array=(${img//,/ }) # 拉取镜像 - docker pull ${MY_REGISTRY}/${img} + docker pull ${img_array[0]} # 添加Tag - docker tag ${MY_REGISTRY}/${img} ${ORIGINAL_REGISTRY}/${img} + image_name=${img_array[1]} + image_name=${image_name##*/} + image_name=${image_name%@*} + docker tag ${img_array[0]} ${image_name} # 输出 - docker save ${ORIGINAL_REGISTRY}/${img} > ${img##*/}.tar + docker save ${image_name} > /data/k8s_img/kubeflow/${image_name}.tar # 输入 - microk8s.ctr -n k8s.io image import ${img##*/}.tar + microk8s.ctr --namespace k8s.io image import /data/k8s_img/kubeflow/${image_name}.tar # 删除Tag - docker rmi ${MY_REGISTRY}/${img} ${ORIGINAL_REGISTRY}/${img} + docker rmi ${img_array[0]} ${image_name} done echo "" echo "==========================================================" -echo "pull kubeflow v1.0 images from gcr.azk8s.cn finished." +echo "pull kubeflow v1.0 images from aliyuncs finished." echo "==========================================================" echo "" ``` +执行完以上脚本后发现knative-serving还是没有启动,原因是因为knative镜像使用的是sha256,没有使用具体版本号,而镜像下载到阿里云之后sha256就变更了,所以无法下载,只能通过修改配置文件更改下载地址了 + +``` +vim /data/my-kubeflow/kustomize/knative-install/base/deployment.yaml +``` + +镜像地址如下格式 + +``` +gcr.io/knative-releases/knative.dev/serving/cmd/activator@sha256:8e606671215cc029683e8cd633ec5de9eabeaa6e9a4392ff289883304be1f418 +gcr.io/knative-releases/knative.dev/serving/cmd/autoscaler-hpa@sha256:5e0fadf574e66fb1c893806b5c5e5f19139cc476ebf1dff9860789fe4ac5f545 +gcr.io/knative-releases/knative.dev/serving/cmd/autoscaler@sha256:ef1f01b5fb3886d4c488a219687aac72d28e72f808691132f658259e4e02bb27 +gcr.io/knative-releases/knative.dev/serving/cmd/networking/istio@sha256:727a623ccb17676fae8058cb1691207a9658a8d71bc7603d701e23b1a6037e6c +gcr.io/knative-releases/knative.dev/serving/cmd/webhook@sha256:1ef3328282f31704b5802c1136bd117e8598fd9f437df8209ca87366c5ce9fcb +gcr.io/knative-releases/knative.dev/serving/cmd/controller@sha256:5ca13e5b3ce5e2819c4567b75c0984650a57272ece44bc1dabf930f9fe1e19a1 +``` + +改成 + +``` +smartliby/activator:latest +smartliby/autoscaler-hpa:latest +smartliby/autoscaler:latest +smartliby/istio:latest +smartliby/webhook:latest +smartliby/controller:latest +``` + +最后执行`kfctl apply -V -f ${CONFIG_URI}`重新安装即可 + 如果还是有pod无法启动,可通过`kubectl describe pod 未启动pod的名称 -n kubeflow`查看原因 如果是因为镜像无法下载,可以将依赖的镜像加到上面的脚本里下载镜像 @@ -262,3 +268,7 @@ print("Accuracy: ", sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnis Accuracy: 0.9012 ``` +#### 测试pipelines + +![](/images/media/选区_079.png) + diff --git "a/source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" new file mode 100644 index 0000000..423f0f2 --- /dev/null +++ "b/source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -0,0 +1,199 @@ +--- +title: minikube安装教程 +date: 2020-04-18 22:20:02 +categories: +- minikube +tags: +- minikube +- ubuntu +- k8s +--- + +minikube 是 K8S 官方为了开发者能在个人电脑上运行 K8S 而提供的一套工具。实现上是通过 Go 语言编写,通过调用虚拟化管理程序,创建出一个运行在虚拟机内的单节点集群。 + + + +本次安装的minikube版本为1.2.0(k8s 1.15.0),并没有安装最新版1.9.2,原因是我要基于k8s安装kubeflow,kubeflow对k8s 1.16及以上版本存在兼容性问题,所以为避免不必要的麻烦就安装了老版本的minikube。 + +#### 安装docker + +``` +apt-get update + apt-get install -y apt-transport-https ca-certificates curl software-properties-common + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - + add-apt-repository \ + "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) \ + Stable" + apt-get update + apt-get install -y docker-ce +``` + +测试是否安装成功 + +``` +docker run hello-world +``` + +#### 安装kubectl + +``` +curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/linux/amd64/kubectl +``` + +如果由于墙的问题无法下载可以访问下面的github地址,点击选择对应版本md进入,找到client binaries(也就是kubectl),选择对应操作系统的客户端然后复制连接地址下载 + +``` +https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG +``` + +赋予执行权限 + +``` +chmod +x ./kubectl +sudo mv ./kubectl /usr/bin/kubectl +``` + +查看版本 + +``` +sudo kubectl version --client +``` + +结果如下 + +``` +Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.0", GitCommit:"e8462b5b5dc2584fdcd18e6bcfe9f1e4d970a529", GitTreeState:"clean", BuildDate:"2019-06-19T16:40:16Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"linux/amd64"} +``` + +#### 安装minikube + +下载minikube + +``` +https://github.com/kubernetes/minikube/releases/download/v1.2.0/minikube_1.2.0.deb +``` + +安装minikube + +``` +sudo dpkg -i minikube_1.2.0.deb +``` + +#### 启动minikube + +``` +sudo minikube start --vm-driver=none --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers --cpus 6 --memory 12288 --disk-size=120g --extra-config=apiserver.authorization-mode=RBAC --extra-config=kubelet.resolv-conf=/run/systemd/resolve/resolv.conf --extra-config kubeadm.ignore-preflight-errors=SystemVerification +``` + +执行结果如下表示部署启动成功 + +``` +😄 minikube v1.2.0 on linux (amd64) +✅ using image repository registry.cn-hangzhou.aliyuncs.com/google_containers +🔥 Creating none VM (CPUs=6, Memory=12288MB, Disk=120000MB) ... +🐳 Configuring environment for Kubernetes v1.15.0 on Docker 19.03.8 + ▪ apiserver.authorization-mode=RBAC + ▪ kubelet.resolv-conf=/run/systemd/resolve/resolv.conf + ▪ kubeadm.ignore-preflight-errors=SystemVerification + ▪ kubelet.resolv-conf=/run/systemd/resolve/resolv.conf +🚜 Pulling images ... +🚀 Launching Kubernetes ... +🤹 Configuring local host environment ... + +⚠️ The 'none' driver provides limited isolation and may reduce system security and reliability. +⚠️ For more information, see: +👉 https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md + +⚠️ kubectl and minikube configuration will be stored in /home/liby +⚠️ To use kubectl or minikube commands as your own user, you may +⚠️ need to relocate them. For example, to overwrite your own settings: + + ▪ sudo mv /home/liby/.kube /home/liby/.minikube $HOME + ▪ sudo chown -R $USER $HOME/.kube $HOME/.minikube + +💡 This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true +⌛ Verifying: apiserver proxy etcd scheduler controller dns +🏄 Done! kubectl is now configured to use "minikube" +``` + +执行`sudo minikube status`查看minikube运行情况 + +``` +host: Running +kubelet: Running +apiserver: Running +kubectl: Correctly Configured: pointing to minikube-vm at 192.168.0.110 +``` + +查看pod运行情况 + +``` +sudo kubectl get pods --all-namespaces +``` + +如下pod运行正常 + +``` +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system coredns-6967fb4995-svq2c 1/1 Running 79 3d19h +kube-system coredns-6967fb4995-wlk48 1/1 Running 79 3d19h +kube-system etcd-minikube 1/1 Running 0 13h +kube-system kube-addon-manager-minikube 1/1 Running 5 3d19h +kube-system kube-apiserver-minikube 1/1 Running 0 13h +kube-system kube-controller-manager-minikube 1/1 Running 45 3d19h +kube-system kube-proxy-fxp74 1/1 Running 5 3d19h +kube-system kube-scheduler-minikube 1/1 Running 37 3d19h +kube-system kubernetes-dashboard-95564f4f-ql2zr 1/1 Running 8 3d19h +kube-system storage-provisioner 1/1 Running 0 12h +``` + +执行`sudo minikube dashboard`打开Kubernetes控制台 + +``` +🤔 Verifying dashboard health ... +🚀 Launching proxy ... +🤔 Verifying proxy health ... +🎉 Opening http://127.0.0.1:41123/api/v1/namespaces/kube-system/services/http:kubernetes-dashboard:/proxy/ in your default browser... +``` + +![](/images/media/选区_084.png) + +#### minikube基本操作 + +检测集群状态 + +``` +sudo kubectl cluster-info +``` + +minikube的配置文件在如下路径 + +``` +~/.minikube/machines/minikube/config.json +``` + +检验node状态 + +``` +sudo kubectl get nodes +``` + +停止运行中的kubernetes集群 + +``` +sudo minikube stop +``` + +删除本地的kubernetes集群 + +``` +sudo minikube delete +``` + +如果安装了kubeflow,通过以下命令获取Kubeflow Dashboard的访问ip和端口 + +``` +export INGRESS_HOST=$(sudo minikube ip) +export INGRESS_PORT=$(sudo kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}’) +``` \ No newline at end of file diff --git "a/source/_posts/2020-04-19-miniKF\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-19-miniKF\345\256\211\350\243\205\346\225\231\347\250\213.md" new file mode 100644 index 0000000..e9fa094 --- /dev/null +++ "b/source/_posts/2020-04-19-miniKF\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -0,0 +1,76 @@ +--- +title: miniKF安装教程 +date: 2020-04-19 14:09:31 +categories: +- miniKF +tags: +- miniKF +- ubuntu +- k8s +--- + +MiniKF is a fast and easy way to get started with Kubeflow. With just a few clicks, you are up for experimentation, and for running complete Kubeflow Pipelines. + + + +#### 下载vagrant + +``` +wget https://releases.hashicorp.com/vagrant/2.2.7/vagrant_2.2.7_x86_64.deb +sudo dpkg -i vagrant_2.2.7_x86_64.deb +``` + +#### 安装 Virtual Box + +``` +wget https://download.virtualbox.org/virtualbox/6.1.6/virtualbox-6.1_6.1.6-137129~Ubuntu~bionic_amd64.deb +sudo dpkg -i virtualbox-6.1_6.1.6-137129~Ubuntu~bionic_amd64.deb +``` + +#### 安装MiniKF + +Open a terminal on your laptop, create a new directory, switch into it, and run the following commands to install MiniKF + +``` +mkdir -p /data/miniKF/ +cd /data/miniKF/ +vagrant init arrikto/minikf +vagrant up +``` + +整个安装过程需要下载30G左右的文件,并且需要访问google,所以需要代理,出现如下内容表示安装成功 + +``` +==> default: Machine booted and ready! +==> default: Checking for guest additions in VM... + default: The guest additions on this VM do not match the installed version of + default: VirtualBox! In most cases this is fine, but in rare cases it can + default: prevent things such as shared folders from working properly. If you see + default: shared folder errors, please make sure the guest additions within the + default: virtual machine match the version of VirtualBox you have installed on + default: your host and reload your VM. + default: + default: Guest Additions Version: 6.0.14_Ubuntu r132055 + default: VirtualBox Version: 5.2 +==> default: Using /data/miniKF/minikf-user-data.vdi for persistent storage. +==> default: ** Managing persistent storage ** +==> default: Setting hostname... +==> default: Configuring and enabling network interfaces... +==> default: Mounting shared folders... + default: /vagrant => /data/miniKF + +==> default: Machine 'default' has a post `vagrant up` message. This is a message +==> default: from the creator of the Vagrantfile, and not from Vagrant itself: +==> default: +==> default: Welcome to MiniKF! +==> default: Visit http://10.10.10.10/ to get started. +==> default: +``` + +访问`http://10.10.10.10/`,点击页面的OK按钮,等待一段时间后整个服务就启动了,点击`connect to Kubeflow`就进入了kubeflow的操作界面 + +![](/images/media/选区_077.png) + +#### 参考 + +[1] https://www.kubeflow.org/docs/started/workstation/getting-started-minikf/ \ No newline at end of file diff --git "a/source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" "b/source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" new file mode 100644 index 0000000..c8e1a59 --- /dev/null +++ "b/source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" @@ -0,0 +1,85 @@ +--- +title: 通过Travis CI自动构建镜像到阿里云镜像库和dockehub +date: 2020-04-19 14:57:23 +categories: +- k8s +tags: +- k8s +- github +- docker +--- + +其实之前我已经写过一篇关于通过阿里云镜像库下载gcr.io镜像的文章,但是该方法有一个问题,每次需要新的镜像都需要在阿里云镜像库手动创建,太麻烦了,这篇文章通过**Travis CI**可以自动构建镜像到阿里云,方便好用 + + + +#### 创建github仓库 + +首先登录github创建一个仓库,名称自定义,仓库包含如下2个文件: + +img-list.txt 外网镜像列表文件 +.travis.yaml travisCI自动构建文件 +示例仓库:https://github.com/smartliby/pull-docker-images + +.travis.yaml 内容如下,主要从国外镜像仓库pull镜像,打tag,并push到阿里云或dockerhub + +``` +language: bash + +services: + - docker + +env: + global: + # change the registry name and username/password to yourself's. + - DOCKER_HUB=smartliby + - ALI_REGISTRY=registry.cn-hangzhou.aliyuncs.com/smartliby + +before_script: + - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + - echo "$ALI_PASSWORD" | docker login "$ALI_REGISTRY" -u "$ALI_USERNAME" --password-stdin + +script: + - echo "start pull and retag and push" + - | + for image in $(cat img-list.txt) + do + image_name=${image##*/} + image_name=${image_name%@*} + docker pull $image + docker tag $image $DOCKER_HUB/$image_name + echo $ALI_REGISTRY + docker tag $image $ALI_REGISTRY/$image_name + + # push到dockerhub + docker push $DOCKER_HUB/$image_name + # push到阿里云仓库 + docker push $ALI_REGISTRY/$image_name + done + +``` + +.travis.yaml文件监测github仓库的代码变动,当有代码变动时比如img-list.txt写入新的镜像列表时将触发tarvis的自动构建 +这里需要登录阿里云或dockerhub才能执行docker push操作,其中$ALI_USERNAME这类变量在TravisCI管理界面定义好即可。 + +#### Travis CI配置 + +访问travis官网: https://www.travis-ci.com, 使用github账号登录。 + +开启需要进行自动化构建的仓库并设置$ALI_USERNAME这类变量即可 + +![](/images/media/选区_085.png) + +当对github仓库执行git commit、git push操作时将自动触发构建,执行仓库中的脚本 + +![](/images/media/选区_086.png) + +登录阿里云或dockerhub查看,imagepath.txt 列表中的镜像已经成功被push上来 + +![](/images/media/选区_087.png) + +![](/images/media/选区_088.png) + +#### 参考 + +[1] https://blog.csdn.net/networken/article/details/84571373 \ No newline at end of file From 0ff52be61789d2b260871a1f46d8702430b6f65c Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 19 Apr 2020 15:50:52 +0800 Subject: [PATCH 19/23] =?UTF-8?q?=E6=96=87=E5=AD=97=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" "b/source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" index c8e1a59..dcea6f8 100644 --- "a/source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" +++ "b/source/_posts/2020-04-19-\351\200\232\350\277\207Travis-CI\350\207\252\345\212\250\346\236\204\345\273\272\351\225\234\345\203\217\345\210\260\351\230\277\351\207\214\344\272\221\351\225\234\345\203\217\345\272\223\345\222\214dockehub.md" @@ -74,7 +74,7 @@ script: ![](/images/media/选区_086.png) -登录阿里云或dockerhub查看,imagepath.txt 列表中的镜像已经成功被push上来 +登录阿里云或dockerhub查看,img-list.txt 列表中的镜像已经成功被push上来 ![](/images/media/选区_087.png) From 9ea3af9c755aee4ca162cdf4b4d26175e2df258e Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 26 Apr 2020 16:53:07 +0800 Subject: [PATCH 20/23] =?UTF-8?q?=E6=96=87=E7=AB=A0=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...beflow\345\256\211\350\243\205\346\225\231\347\250\213.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index bcb8200..f390125 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -54,7 +54,7 @@ kubectl -n kubeflow get all kubectl get pods --namespace kubeflow ``` -发现kubeflow的pod大部分没有启动成功,原因还是网络问题,需要访问gcr.io下载镜像,之前我都是通过gcr.azk8s.cn镜像地址下载的,但是最近发现gcr.azk8s.cn这个地址无法使用了,所以只能通过自己构建然后保存到阿里云镜像库里,大家可以直接使用我已经构建好的镜像,执行下面脚本即可,也可自己构建,具体构建流程可以参考[这篇文章](https://blog.flyfox.top/2020/04/19/通过Travis-CI自动构建镜像到阿里云镜像库和dockehub) +发现kubeflow的pod大部分没有启动成功,原因还是网络问题,需要访问gcr.io下载镜像,之前我都是通过gcr.azk8s.cn镜像地址下载的,但是最近发现gcr.azk8s.cn这个地址无法使用了,所以只能通过自己构建然后保存到阿里云或者dockerhub镜像库里,大家可以直接使用我已经构建好的镜像,执行下面脚本即可,也可自己构建,具体构建流程可以参考[这篇文章](https://blog.flyfox.top/2020/04/19/通过Travis-CI自动构建镜像到阿里云镜像库和dockehub) 执行以下脚本将镜像下载到本地并导入到microk8s @@ -90,7 +90,7 @@ gcr_imgs=( "registry.cn-hangzhou.aliyuncs.com/smartliby/persistenceagent:0.2.0,gcr.io/ml-pipeline/persistenceagent:0.2.0" "registry.cn-hangzhou.aliyuncs.com/smartliby/scheduledworkflow:0.2.0,gcr.io/ml-pipeline/scheduledworkflow:0.2.0" "registry.cn-hangzhou.aliyuncs.com/smartliby/frontend:0.2.0,gcr.io/ml-pipeline/frontend:0.2.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby,gcr.io/ml-pipeline/viewer-crd-controller:0.2.0" + "registry.cn-hangzhou.aliyuncs.com/smartliby/viewer-crd-controller:0.2.0,gcr.io/ml-pipeline/viewer-crd-controller:0.2.0" "registry.cn-hangzhou.aliyuncs.com/smartliby/notebook-controller:v1.0.0-gcd65ce25,gcr.io/kubeflow-images-public/notebook-controller:v1.0.0-gcd65ce25" "registry.cn-hangzhou.aliyuncs.com/smartliby/profile-controller:v1.0.0-ge50a8531,gcr.io/kubeflow-images-public/profile-controller:v1.0.0-ge50a8531" "registry.cn-hangzhou.aliyuncs.com/smartliby/pytorch-operator:v1.0.0-g047cf0f,gcr.io/kubeflow-images-public/pytorch-operator:v1.0.0-g047cf0f" From 64f4739784869f046c36139a61a1da6117ca5423 Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 26 Apr 2020 17:44:13 +0800 Subject: [PATCH 21/23] =?UTF-8?q?=E6=96=87=E7=AB=A0=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...rok8s\345\256\211\350\243\205\346\225\231\347\250\213.md" | 5 ++--- ...eflow\345\256\211\350\243\205\346\225\231\347\250\213.md" | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git "a/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" index f2c2bc3..c9845dc 100644 --- "a/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -265,13 +265,12 @@ do docker pull ${img_array[0]} # 添加Tag image_name=${img_array[1]} - image_name=${image_name##*/} image_name=${image_name%@*} docker tag ${img_array[0]} ${image_name} # 输出 - docker save ${image_name} > /data/k8s_img/kubeflow/${image_name}.tar + docker save ${image_name} > /data/k8s_img/k8s/${image_name##*/}.tar # 输入 - microk8s.ctr --namespace k8s.io image import /data/k8s_img/kubeflow/${image_name}.tar + microk8s.ctr --namespace k8s.io image import /data/k8s_img/k8s/${image_name##*/}.tar # 删除Tag docker rmi ${img_array[0]} ${image_name} done diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index f390125..968b1ff 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -109,13 +109,12 @@ do docker pull ${img_array[0]} # 添加Tag image_name=${img_array[1]} - image_name=${image_name##*/} image_name=${image_name%@*} docker tag ${img_array[0]} ${image_name} # 输出 - docker save ${image_name} > /data/k8s_img/kubeflow/${image_name}.tar + docker save ${image_name} > /data/k8s_img/kubeflow/${image_name##*/}.tar # 输入 - microk8s.ctr --namespace k8s.io image import /data/k8s_img/kubeflow/${image_name}.tar + microk8s.ctr --namespace k8s.io image import /data/k8s_img/kubeflow/${image_name##*/}.tar # 删除Tag docker rmi ${img_array[0]} ${image_name} done From 6655f6035286d75f42978dc21460a5be6ae25295 Mon Sep 17 00:00:00 2001 From: smartliby Date: Sun, 26 Apr 2020 18:09:16 +0800 Subject: [PATCH 22/23] =?UTF-8?q?=E6=96=87=E7=AB=A0=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...11\350\243\205\346\225\231\347\250\213.md" | 62 +++++++++---------- ...11\350\243\205\346\225\231\347\250\213.md" | 60 +++++++++--------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git "a/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" index c9845dc..6ca8849 100644 --- "a/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-03-microk8s\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -220,42 +220,42 @@ k8s.gcr.io/pause:3.1 echo "" echo "==========================================================" -echo "pull microk8s v1.15.11 images from aliyuncs ..." +echo "pull microk8s v1.15.11 images from dockerhub ..." echo "==========================================================" echo "" # registry.cn-hangzhou.aliyuncs.com/smartliby gcr_imgs=( - "registry.cn-hangzhou.aliyuncs.com/smartliby/pause:3.1,k8s.gcr.io/pause:3.1" - "registry.cn-hangzhou.aliyuncs.com/smartliby/heapster-influxdb-amd64:v1.3.3,k8s.gcr.io/heapster-influxdb-amd64:v1.3.3" - "registry.cn-hangzhou.aliyuncs.com/smartliby/heapster-grafana-amd64:v4.4.3,k8s.gcr.io/heapster-grafana-amd64:v4.4.3" - "registry.cn-hangzhou.aliyuncs.com/smartliby/kubernetes-dashboard-amd64:v1.10.1,k8s.gcr.io/google_containers/kubernetes-dashboard-amd64:v1.10.1" - "registry.cn-hangzhou.aliyuncs.com/smartliby/heapster-amd64:v1.5.2,k8s.gcr.io/heapster-amd64:v1.5.2" - "registry.cn-hangzhou.aliyuncs.com/smartliby/defaultbackend-amd64:1.4,gcr.io/google_containers/defaultbackend-amd64:1.4" - "registry.cn-hangzhou.aliyuncs.com/smartliby/nginx-ingress-controller-amd64:0.24.1,quay.io/kubernetes-ingress-controller/nginx-ingress-controller-amd64:0.24.1" - "registry.cn-hangzhou.aliyuncs.com/smartliby/grafana:6.1.6,grafana/grafana:6.1.6" - "registry.cn-hangzhou.aliyuncs.com/smartliby/addon-resizer-amd64:1.8.1,cdkbot/addon-resizer-amd64:1.8.1" - "registry.cn-hangzhou.aliyuncs.com/smartliby/hostpath-provisioner-amd64:1.0.0,cdkbot/hostpath-provisioner-amd64:1.0.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/dashboard:v2.0.0-rc5,kubernetesui/dashboard:v2.0.0-rc5" - "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-device-plugin:1.11,nvidia/k8s-device-plugin:1.11" - "registry.cn-hangzhou.aliyuncs.com/smartliby/controller:v0.8.2,metallb/controller:v0.8.2" - "registry.cn-hangzhou.aliyuncs.com/smartliby/speaker:v0.8.2,metallb/speaker:v0.8.2" - "registry.cn-hangzhou.aliyuncs.com/smartliby/citadel:1.3.4,docker.io/istio/citadel:1.3.4" - "registry.cn-hangzhou.aliyuncs.com/smartliby/jujud-operator:2.7.3,jujusolutions/jujud-operator:2.7.3" - "registry.cn-hangzhou.aliyuncs.com/smartliby/kicbase:v0.0.8,gcr.io/k8s-minikube/kicbase:v0.0.8" - "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-dns-dnsmasq-nanny-amd64:1.14.7,gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.7" - "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-dns-kube-dns-amd64:1.14.7,gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.7" - "registry.cn-hangzhou.aliyuncs.com/smartliby/k8s-dns-sidecar-amd64:1.14.7,gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.7" - "registry.cn-hangzhou.aliyuncs.com/smartliby/kubernetes-dashboard-amd64:v1.8.3,k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3" - "registry.cn-hangzhou.aliyuncs.com/smartliby/cert-manager-controller:v0.11.0,quay.io/jetstack/cert-manager-controller:v0.11.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/sidecar_injector:1.1.6,docker.io/istio/sidecar_injector:1.1.6" - "registry.cn-hangzhou.aliyuncs.com/smartliby/prometheus:v2.3.1,docker.io/prom/prometheus:v2.3.1" - "registry.cn-hangzhou.aliyuncs.com/smartliby/galley:1.1.6,docker.io/istio/galley:1.1.6" - "registry.cn-hangzhou.aliyuncs.com/smartliby/cert-manager-cainjector:v0.11.0,quay.io/jetstack/cert-manager-cainjector:v0.11.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/cert-manager-webhook:v0.11.0,quay.io/jetstack/cert-manager-webhook:v0.11.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/application:1.0-beta,gcr.io/kubeflow-images-public/kubernetes-sigs/application:1.0-beta" - "registry.cn-hangzhou.aliyuncs.com/smartliby/kiali:v0.16,docker.io/kiali/kiali:v0.16" + "smartliby/pause:3.1,k8s.gcr.io/pause:3.1" + "smartliby/heapster-influxdb-amd64:v1.3.3,k8s.gcr.io/heapster-influxdb-amd64:v1.3.3" + "smartliby/heapster-grafana-amd64:v4.4.3,k8s.gcr.io/heapster-grafana-amd64:v4.4.3" + "smartliby/kubernetes-dashboard-amd64:v1.10.1,k8s.gcr.io/google_containers/kubernetes-dashboard-amd64:v1.10.1" + "smartliby/heapster-amd64:v1.5.2,k8s.gcr.io/heapster-amd64:v1.5.2" + "smartliby/defaultbackend-amd64:1.4,gcr.io/google_containers/defaultbackend-amd64:1.4" + "smartliby/nginx-ingress-controller-amd64:0.24.1,quay.io/kubernetes-ingress-controller/nginx-ingress-controller-amd64:0.24.1" + "smartliby/grafana:6.1.6,grafana/grafana:6.1.6" + "smartliby/addon-resizer-amd64:1.8.1,cdkbot/addon-resizer-amd64:1.8.1" + "smartliby/hostpath-provisioner-amd64:1.0.0,cdkbot/hostpath-provisioner-amd64:1.0.0" + "smartliby/dashboard:v2.0.0-rc5,kubernetesui/dashboard:v2.0.0-rc5" + "smartliby/k8s-device-plugin:1.11,nvidia/k8s-device-plugin:1.11" + "smartliby/controller:v0.8.2,metallb/controller:v0.8.2" + "smartliby/speaker:v0.8.2,metallb/speaker:v0.8.2" + "smartliby/citadel:1.3.4,docker.io/istio/citadel:1.3.4" + "smartliby/jujud-operator:2.7.3,jujusolutions/jujud-operator:2.7.3" + "smartliby/kicbase:v0.0.8,gcr.io/k8s-minikube/kicbase:v0.0.8" + "smartliby/k8s-dns-dnsmasq-nanny-amd64:1.14.7,gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.7" + "smartliby/k8s-dns-kube-dns-amd64:1.14.7,gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.7" + "smartliby/k8s-dns-sidecar-amd64:1.14.7,gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.7" + "smartliby/kubernetes-dashboard-amd64:v1.8.3,k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3" + "smartliby/cert-manager-controller:v0.11.0,quay.io/jetstack/cert-manager-controller:v0.11.0" + "smartliby/sidecar_injector:1.1.6,docker.io/istio/sidecar_injector:1.1.6" + "smartliby/prometheus:v2.3.1,docker.io/prom/prometheus:v2.3.1" + "smartliby/galley:1.1.6,docker.io/istio/galley:1.1.6" + "smartliby/cert-manager-cainjector:v0.11.0,quay.io/jetstack/cert-manager-cainjector:v0.11.0" + "smartliby/cert-manager-webhook:v0.11.0,quay.io/jetstack/cert-manager-webhook:v0.11.0" + "smartliby/application:1.0-beta,gcr.io/kubeflow-images-public/kubernetes-sigs/application:1.0-beta" + "smartliby/kiali:v0.16,docker.io/kiali/kiali:v0.16" ) for img in ${gcr_imgs[@]} @@ -277,7 +277,7 @@ done echo "" echo "==========================================================" -echo "pull microk8s v1.15.11 images from aliyuncs finished." +echo "pull microk8s v1.15.11 images from dockerhub finished." echo "==========================================================" echo "" ``` diff --git "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" index 968b1ff..e9d2977 100644 --- "a/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-04-kubeflow\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -63,41 +63,41 @@ kubectl get pods --namespace kubeflow echo "" echo "==========================================================" -echo "pull kubeflow v1.0 images from aliyuncs ..." +echo "pull kubeflow v1.0 images from dockerhub ..." echo "==========================================================" echo "" # registry.cn-hangzhou.aliyuncs.com/smartliby gcr_imgs=( - "registry.cn-hangzhou.aliyuncs.com/smartliby/kfserving-controller:0.2.2,gcr.io/kfserving/kfserving-controller:0.2.2" - "registry.cn-hangzhou.aliyuncs.com/smartliby/api-server:0.2.0,gcr.io/ml-pipeline/api-server:0.2.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/kfam:v1.0.0-gf3e09203,gcr.io/kubeflow-images-public/kfam:v1.0.0-gf3e09203" - "registry.cn-hangzhou.aliyuncs.com/smartliby/ingress-setup:latest,gcr.io/kubeflow-images-public/ingress-setup:latest" - "registry.cn-hangzhou.aliyuncs.com/smartliby/application:1.0-beta,gcr.io/kubeflow-images-public/kubernetes-sigs/application:1.0-beta" - "registry.cn-hangzhou.aliyuncs.com/smartliby/centraldashboard:v1.0.0-g3ec0de71,gcr.io/kubeflow-images-public/centraldashboard:v1.0.0-g3ec0de71" - "registry.cn-hangzhou.aliyuncs.com/smartliby/jupyter-web-app:v1.0.0-g2bd63238,gcr.io/kubeflow-images-public/jupyter-web-app:v1.0.0-g2bd63238" - "registry.cn-hangzhou.aliyuncs.com/smartliby/katib-controller:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-controller:v0.8.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/katib-db-manager:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-db-manager:v0.8.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/katib-ui:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-ui:v0.8.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/kube-rbac-proxy:v0.4.0,gcr.io/kubebuilder/kube-rbac-proxy:v0.4.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/metacontroller:v0.3.0,gcr.io/metacontroller/metacontroller:v0.3.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/metadata:v0.1.11,gcr.io/kubeflow-images-public/metadata:v0.1.11" - "registry.cn-hangzhou.aliyuncs.com/smartliby/envoy:metadata-grpc,gcr.io/ml-pipeline/envoy:metadata-grpc" - "registry.cn-hangzhou.aliyuncs.com/smartliby/ml_metadata_store_server:v0.21.1,gcr.io/tfx-oss-public/ml_metadata_store_server:v0.21.1" - "registry.cn-hangzhou.aliyuncs.com/smartliby/metadata-frontend:v0.1.8,gcr.io/kubeflow-images-public/metadata-frontend:v0.1.8" - "registry.cn-hangzhou.aliyuncs.com/smartliby/visualization-server:0.2.0,gcr.io/ml-pipeline/visualization-server:0.2.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/persistenceagent:0.2.0,gcr.io/ml-pipeline/persistenceagent:0.2.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/scheduledworkflow:0.2.0,gcr.io/ml-pipeline/scheduledworkflow:0.2.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/frontend:0.2.0,gcr.io/ml-pipeline/frontend:0.2.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/viewer-crd-controller:0.2.0,gcr.io/ml-pipeline/viewer-crd-controller:0.2.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/notebook-controller:v1.0.0-gcd65ce25,gcr.io/kubeflow-images-public/notebook-controller:v1.0.0-gcd65ce25" - "registry.cn-hangzhou.aliyuncs.com/smartliby/profile-controller:v1.0.0-ge50a8531,gcr.io/kubeflow-images-public/profile-controller:v1.0.0-ge50a8531" - "registry.cn-hangzhou.aliyuncs.com/smartliby/pytorch-operator:v1.0.0-g047cf0f,gcr.io/kubeflow-images-public/pytorch-operator:v1.0.0-g047cf0f" - "registry.cn-hangzhou.aliyuncs.com/smartliby/spark-operator:v1beta2-1.0.0-2.4.4,gcr.io/spark-operator/spark-operator:v1beta2-1.0.0-2.4.4" - "registry.cn-hangzhou.aliyuncs.com/smartliby/spartakus-amd64:v1.1.0,gcr.io/google_containers/spartakus-amd64:v1.1.0" - "registry.cn-hangzhou.aliyuncs.com/smartliby/tf_operator:v1.0.0-g92389064,gcr.io/kubeflow-images-public/tf_operator:v1.0.0-g92389064" - "registry.cn-hangzhou.aliyuncs.com/smartliby/admission-webhook:v1.0.0-gaf96e4e3,gcr.io/kubeflow-images-public/admission-webhook:v1.0.0-gaf96e4e3" + "smartliby/kfserving-controller:0.2.2,gcr.io/kfserving/kfserving-controller:0.2.2" + "smartliby/api-server:0.2.0,gcr.io/ml-pipeline/api-server:0.2.0" + "smartliby/kfam:v1.0.0-gf3e09203,gcr.io/kubeflow-images-public/kfam:v1.0.0-gf3e09203" + "smartliby/ingress-setup:latest,gcr.io/kubeflow-images-public/ingress-setup:latest" + "smartliby/application:1.0-beta,gcr.io/kubeflow-images-public/kubernetes-sigs/application:1.0-beta" + "smartliby/centraldashboard:v1.0.0-g3ec0de71,gcr.io/kubeflow-images-public/centraldashboard:v1.0.0-g3ec0de71" + "smartliby/jupyter-web-app:v1.0.0-g2bd63238,gcr.io/kubeflow-images-public/jupyter-web-app:v1.0.0-g2bd63238" + "smartliby/katib-controller:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-controller:v0.8.0" + "smartliby/katib-db-manager:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-db-manager:v0.8.0" + "smartliby/katib-ui:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-ui:v0.8.0" + "smartliby/kube-rbac-proxy:v0.4.0,gcr.io/kubebuilder/kube-rbac-proxy:v0.4.0" + "smartliby/metacontroller:v0.3.0,gcr.io/metacontroller/metacontroller:v0.3.0" + "smartliby/metadata:v0.1.11,gcr.io/kubeflow-images-public/metadata:v0.1.11" + "smartliby/envoy:metadata-grpc,gcr.io/ml-pipeline/envoy:metadata-grpc" + "smartliby/ml_metadata_store_server:v0.21.1,gcr.io/tfx-oss-public/ml_metadata_store_server:v0.21.1" + "smartliby/metadata-frontend:v0.1.8,gcr.io/kubeflow-images-public/metadata-frontend:v0.1.8" + "smartliby/visualization-server:0.2.0,gcr.io/ml-pipeline/visualization-server:0.2.0" + "smartliby/persistenceagent:0.2.0,gcr.io/ml-pipeline/persistenceagent:0.2.0" + "smartliby/scheduledworkflow:0.2.0,gcr.io/ml-pipeline/scheduledworkflow:0.2.0" + "smartliby/frontend:0.2.0,gcr.io/ml-pipeline/frontend:0.2.0" + "smartliby/viewer-crd-controller:0.2.0,gcr.io/ml-pipeline/viewer-crd-controller:0.2.0" + "smartliby/notebook-controller:v1.0.0-gcd65ce25,gcr.io/kubeflow-images-public/notebook-controller:v1.0.0-gcd65ce25" + "smartliby/profile-controller:v1.0.0-ge50a8531,gcr.io/kubeflow-images-public/profile-controller:v1.0.0-ge50a8531" + "smartliby/pytorch-operator:v1.0.0-g047cf0f,gcr.io/kubeflow-images-public/pytorch-operator:v1.0.0-g047cf0f" + "smartliby/spark-operator:v1beta2-1.0.0-2.4.4,gcr.io/spark-operator/spark-operator:v1beta2-1.0.0-2.4.4" + "smartliby/spartakus-amd64:v1.1.0,gcr.io/google_containers/spartakus-amd64:v1.1.0" + "smartliby/tf_operator:v1.0.0-g92389064,gcr.io/kubeflow-images-public/tf_operator:v1.0.0-g92389064" + "smartliby/admission-webhook:v1.0.0-gaf96e4e3,gcr.io/kubeflow-images-public/admission-webhook:v1.0.0-gaf96e4e3" "smartliby/kfam:v1.0.0-gf3e09203,gcr.io/kubeflow-images-public/kfam:v1.0.0-gf3e09203" "smartliby/api-server:0.2.0,gcr.io/ml-pipeline/api-server:0.2.0" ) @@ -121,7 +121,7 @@ done echo "" echo "==========================================================" -echo "pull kubeflow v1.0 images from aliyuncs finished." +echo "pull kubeflow v1.0 images from dockerhub finished." echo "==========================================================" echo "" ``` From 18a539a0a525c5dbd2a16592425744c97e4379e3 Mon Sep 17 00:00:00 2001 From: smartliby Date: Mon, 27 Apr 2020 11:31:50 +0800 Subject: [PATCH 23/23] =?UTF-8?q?=E6=96=87=E7=AB=A0=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...kube\345\256\211\350\243\205\346\225\231\347\250\213.md" | 6 ++++++ 1 file changed, 6 insertions(+) diff --git "a/source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" "b/source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" index 423f0f2..29ed028 100644 --- "a/source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" +++ "b/source/_posts/2020-04-18-minikube\345\256\211\350\243\205\346\225\231\347\250\213.md" @@ -159,6 +159,12 @@ kube-system storage-provisioner ![](/images/media/选区_084.png) +为了安全起见,默认情况下dashboard已经不向外提供服务,在我们学习过程中,总有些不方便,这时我们可以利用 kubectl proxy 命令来实现外网提供服务 + +``` +nohup kubectl proxy --address='0.0.0.0' --port=8888 --accept-hosts='^*$' > dashboard.log & +``` + #### minikube基本操作 检测集群状态