├── .gitignore ├── 404.html ├── Gemfile ├── Gemfile.lock ├── README.md ├── _config.yml ├── _includes ├── comments.html ├── disqus.html ├── duosuo.html ├── footer.html ├── header.html ├── page.html ├── post.html ├── posts.html └── statistics.html ├── _layouts ├── index.html ├── page.html └── post.html ├── _posts ├── 2013-04-10-start-blog.md ├── 2013-04-11-base64.md ├── 2013-04-22-linux-file-permission.md ├── 2013-04-25-mklink.md ├── 2013-05-11-sh-execute-diff.md ├── 2013-05-12-buy-a-vps.md ├── 2013-05-13-a-xshell-style.md ├── 2013-05-23-thinking-from-shaver.md ├── 2013-05-26-difference-between-resume-and-cv.md ├── 2013-06-16-ifttt.md ├── 2013-08-01-ubuntu-static-ip-and-dns.md ├── 2013-09-25-simple-factory-pattern.md ├── 2013-09-27-polymorphic-factory-pattern.md ├── 2013-09-29-abstract-factory-pattern.md ├── 2013-09-30-singleton-pattern.md ├── 2013-12-25-mongoose.md ├── 2013-12-28-argparse.md ├── 2013-12-31-the-2013.md ├── 2014-01-09-samba.md ├── 2014-01-11-ubuntuone-command-line.md ├── 2014-10-16-centos-die-on-boot.md ├── 2014-10-21-python-import-test.md ├── 2014-12-29-python-reference.md ├── 2015-02-26-the-2014.md ├── 2015-09-27-uwsgi-fork-trap.md ├── 2015-11-08-raspberry-pi-first-time.md ├── 2016-06-10-texture-unpacker.md └── 2016-07-02-animations-and-spritesheets-in-cocos2d-x.md ├── about.md ├── archives.html ├── atom.xml ├── avater.html ├── categories.html ├── favicon.ico ├── feed.xml ├── images └── 2016 │ ├── animationphases.png │ ├── black-bars.png │ ├── device-stats.png │ ├── extended-scene.png │ ├── gamescene-animated.png │ ├── gamescene-capguy.png │ ├── gamescene-just-background.png │ ├── texturepacker-add-sprites.png │ ├── texturepacker-polygon-sprites.png │ ├── texturepacker-scaling-variants.png │ ├── texturepacker-select-cocos2d-x.png │ └── trim-and-polygon-trim.png ├── index.html ├── media ├── css │ ├── highlight.css │ └── style.css ├── img │ ├── favicon.png │ └── rss.png └── js │ └── base.js ├── photo.html ├── read.html ├── resume.html ├── tags.html └── wish.html /.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 Not Found 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 | 404 18 |
19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 6 | 7 | # gem "rails" 8 | gem 'github-pages', group: :jekyll_plugins 9 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (6.0.4.4) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 0.7, < 2) 7 | minitest (~> 5.1) 8 | tzinfo (~> 1.1) 9 | zeitwerk (~> 2.2, >= 2.2.2) 10 | addressable (2.8.0) 11 | public_suffix (>= 2.0.2, < 5.0) 12 | coffee-script (2.4.1) 13 | coffee-script-source 14 | execjs 15 | coffee-script-source (1.11.1) 16 | colorator (1.1.0) 17 | commonmarker (0.17.13) 18 | ruby-enum (~> 0.5) 19 | concurrent-ruby (1.1.9) 20 | dnsruby (1.61.7) 21 | simpleidn (~> 0.1) 22 | em-websocket (0.5.3) 23 | eventmachine (>= 0.12.9) 24 | http_parser.rb (~> 0) 25 | ethon (0.15.0) 26 | ffi (>= 1.15.0) 27 | eventmachine (1.2.7) 28 | execjs (2.8.1) 29 | faraday (1.8.0) 30 | faraday-em_http (~> 1.0) 31 | faraday-em_synchrony (~> 1.0) 32 | faraday-excon (~> 1.1) 33 | faraday-httpclient (~> 1.0.1) 34 | faraday-net_http (~> 1.0) 35 | faraday-net_http_persistent (~> 1.1) 36 | faraday-patron (~> 1.0) 37 | faraday-rack (~> 1.0) 38 | multipart-post (>= 1.2, < 3) 39 | ruby2_keywords (>= 0.0.4) 40 | faraday-em_http (1.0.0) 41 | faraday-em_synchrony (1.0.0) 42 | faraday-excon (1.1.0) 43 | faraday-httpclient (1.0.1) 44 | faraday-net_http (1.0.1) 45 | faraday-net_http_persistent (1.2.0) 46 | faraday-patron (1.0.0) 47 | faraday-rack (1.0.0) 48 | ffi (1.15.4) 49 | forwardable-extended (2.6.0) 50 | gemoji (3.0.1) 51 | github-pages (222) 52 | github-pages-health-check (= 1.17.9) 53 | jekyll (= 3.9.0) 54 | jekyll-avatar (= 0.7.0) 55 | jekyll-coffeescript (= 1.1.1) 56 | jekyll-commonmark-ghpages (= 0.1.6) 57 | jekyll-default-layout (= 0.1.4) 58 | jekyll-feed (= 0.15.1) 59 | jekyll-gist (= 1.5.0) 60 | jekyll-github-metadata (= 2.13.0) 61 | jekyll-mentions (= 1.6.0) 62 | jekyll-optional-front-matter (= 0.3.2) 63 | jekyll-paginate (= 1.1.0) 64 | jekyll-readme-index (= 0.3.0) 65 | jekyll-redirect-from (= 0.16.0) 66 | jekyll-relative-links (= 0.6.1) 67 | jekyll-remote-theme (= 0.4.3) 68 | jekyll-sass-converter (= 1.5.2) 69 | jekyll-seo-tag (= 2.7.1) 70 | jekyll-sitemap (= 1.4.0) 71 | jekyll-swiss (= 1.0.0) 72 | jekyll-theme-architect (= 0.2.0) 73 | jekyll-theme-cayman (= 0.2.0) 74 | jekyll-theme-dinky (= 0.2.0) 75 | jekyll-theme-hacker (= 0.2.0) 76 | jekyll-theme-leap-day (= 0.2.0) 77 | jekyll-theme-merlot (= 0.2.0) 78 | jekyll-theme-midnight (= 0.2.0) 79 | jekyll-theme-minimal (= 0.2.0) 80 | jekyll-theme-modernist (= 0.2.0) 81 | jekyll-theme-primer (= 0.6.0) 82 | jekyll-theme-slate (= 0.2.0) 83 | jekyll-theme-tactile (= 0.2.0) 84 | jekyll-theme-time-machine (= 0.2.0) 85 | jekyll-titles-from-headings (= 0.5.3) 86 | jemoji (= 0.12.0) 87 | kramdown (= 2.3.1) 88 | kramdown-parser-gfm (= 1.1.0) 89 | liquid (= 4.0.3) 90 | mercenary (~> 0.3) 91 | minima (= 2.5.1) 92 | nokogiri (>= 1.12.5, < 2.0) 93 | rouge (= 3.26.0) 94 | terminal-table (~> 1.4) 95 | github-pages-health-check (1.17.9) 96 | addressable (~> 2.3) 97 | dnsruby (~> 1.60) 98 | octokit (~> 4.0) 99 | public_suffix (>= 3.0, < 5.0) 100 | typhoeus (~> 1.3) 101 | html-pipeline (2.14.0) 102 | activesupport (>= 2) 103 | nokogiri (>= 1.4) 104 | http_parser.rb (0.8.0) 105 | i18n (0.9.5) 106 | concurrent-ruby (~> 1.0) 107 | jekyll (3.9.0) 108 | addressable (~> 2.4) 109 | colorator (~> 1.0) 110 | em-websocket (~> 0.5) 111 | i18n (~> 0.7) 112 | jekyll-sass-converter (~> 1.0) 113 | jekyll-watch (~> 2.0) 114 | kramdown (>= 1.17, < 3) 115 | liquid (~> 4.0) 116 | mercenary (~> 0.3.3) 117 | pathutil (~> 0.9) 118 | rouge (>= 1.7, < 4) 119 | safe_yaml (~> 1.0) 120 | jekyll-avatar (0.7.0) 121 | jekyll (>= 3.0, < 5.0) 122 | jekyll-coffeescript (1.1.1) 123 | coffee-script (~> 2.2) 124 | coffee-script-source (~> 1.11.1) 125 | jekyll-commonmark (1.3.1) 126 | commonmarker (~> 0.14) 127 | jekyll (>= 3.7, < 5.0) 128 | jekyll-commonmark-ghpages (0.1.6) 129 | commonmarker (~> 0.17.6) 130 | jekyll-commonmark (~> 1.2) 131 | rouge (>= 2.0, < 4.0) 132 | jekyll-default-layout (0.1.4) 133 | jekyll (~> 3.0) 134 | jekyll-feed (0.15.1) 135 | jekyll (>= 3.7, < 5.0) 136 | jekyll-gist (1.5.0) 137 | octokit (~> 4.2) 138 | jekyll-github-metadata (2.13.0) 139 | jekyll (>= 3.4, < 5.0) 140 | octokit (~> 4.0, != 4.4.0) 141 | jekyll-mentions (1.6.0) 142 | html-pipeline (~> 2.3) 143 | jekyll (>= 3.7, < 5.0) 144 | jekyll-optional-front-matter (0.3.2) 145 | jekyll (>= 3.0, < 5.0) 146 | jekyll-paginate (1.1.0) 147 | jekyll-readme-index (0.3.0) 148 | jekyll (>= 3.0, < 5.0) 149 | jekyll-redirect-from (0.16.0) 150 | jekyll (>= 3.3, < 5.0) 151 | jekyll-relative-links (0.6.1) 152 | jekyll (>= 3.3, < 5.0) 153 | jekyll-remote-theme (0.4.3) 154 | addressable (~> 2.0) 155 | jekyll (>= 3.5, < 5.0) 156 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) 157 | rubyzip (>= 1.3.0, < 3.0) 158 | jekyll-sass-converter (1.5.2) 159 | sass (~> 3.4) 160 | jekyll-seo-tag (2.7.1) 161 | jekyll (>= 3.8, < 5.0) 162 | jekyll-sitemap (1.4.0) 163 | jekyll (>= 3.7, < 5.0) 164 | jekyll-swiss (1.0.0) 165 | jekyll-theme-architect (0.2.0) 166 | jekyll (> 3.5, < 5.0) 167 | jekyll-seo-tag (~> 2.0) 168 | jekyll-theme-cayman (0.2.0) 169 | jekyll (> 3.5, < 5.0) 170 | jekyll-seo-tag (~> 2.0) 171 | jekyll-theme-dinky (0.2.0) 172 | jekyll (> 3.5, < 5.0) 173 | jekyll-seo-tag (~> 2.0) 174 | jekyll-theme-hacker (0.2.0) 175 | jekyll (> 3.5, < 5.0) 176 | jekyll-seo-tag (~> 2.0) 177 | jekyll-theme-leap-day (0.2.0) 178 | jekyll (> 3.5, < 5.0) 179 | jekyll-seo-tag (~> 2.0) 180 | jekyll-theme-merlot (0.2.0) 181 | jekyll (> 3.5, < 5.0) 182 | jekyll-seo-tag (~> 2.0) 183 | jekyll-theme-midnight (0.2.0) 184 | jekyll (> 3.5, < 5.0) 185 | jekyll-seo-tag (~> 2.0) 186 | jekyll-theme-minimal (0.2.0) 187 | jekyll (> 3.5, < 5.0) 188 | jekyll-seo-tag (~> 2.0) 189 | jekyll-theme-modernist (0.2.0) 190 | jekyll (> 3.5, < 5.0) 191 | jekyll-seo-tag (~> 2.0) 192 | jekyll-theme-primer (0.6.0) 193 | jekyll (> 3.5, < 5.0) 194 | jekyll-github-metadata (~> 2.9) 195 | jekyll-seo-tag (~> 2.0) 196 | jekyll-theme-slate (0.2.0) 197 | jekyll (> 3.5, < 5.0) 198 | jekyll-seo-tag (~> 2.0) 199 | jekyll-theme-tactile (0.2.0) 200 | jekyll (> 3.5, < 5.0) 201 | jekyll-seo-tag (~> 2.0) 202 | jekyll-theme-time-machine (0.2.0) 203 | jekyll (> 3.5, < 5.0) 204 | jekyll-seo-tag (~> 2.0) 205 | jekyll-titles-from-headings (0.5.3) 206 | jekyll (>= 3.3, < 5.0) 207 | jekyll-watch (2.2.1) 208 | listen (~> 3.0) 209 | jemoji (0.12.0) 210 | gemoji (~> 3.0) 211 | html-pipeline (~> 2.2) 212 | jekyll (>= 3.0, < 5.0) 213 | kramdown (2.3.1) 214 | rexml 215 | kramdown-parser-gfm (1.1.0) 216 | kramdown (~> 2.0) 217 | liquid (4.0.3) 218 | listen (3.7.0) 219 | rb-fsevent (~> 0.10, >= 0.10.3) 220 | rb-inotify (~> 0.9, >= 0.9.10) 221 | mercenary (0.3.6) 222 | mini_portile2 (2.8.0) 223 | minima (2.5.1) 224 | jekyll (>= 3.5, < 5.0) 225 | jekyll-feed (~> 0.9) 226 | jekyll-seo-tag (~> 2.1) 227 | minitest (5.15.0) 228 | multipart-post (2.1.1) 229 | nokogiri (1.13.3) 230 | mini_portile2 (~> 2.8.0) 231 | racc (~> 1.4) 232 | octokit (4.21.0) 233 | faraday (>= 0.9) 234 | sawyer (~> 0.8.0, >= 0.5.3) 235 | pathutil (0.16.2) 236 | forwardable-extended (~> 2.6) 237 | public_suffix (4.0.6) 238 | racc (1.6.0) 239 | rb-fsevent (0.11.0) 240 | rb-inotify (0.10.1) 241 | ffi (~> 1.0) 242 | rexml (3.2.5) 243 | rouge (3.26.0) 244 | ruby-enum (0.9.0) 245 | i18n 246 | ruby2_keywords (0.0.5) 247 | rubyzip (2.3.2) 248 | safe_yaml (1.0.5) 249 | sass (3.7.4) 250 | sass-listen (~> 4.0.0) 251 | sass-listen (4.0.0) 252 | rb-fsevent (~> 0.9, >= 0.9.4) 253 | rb-inotify (~> 0.9, >= 0.9.7) 254 | sawyer (0.8.2) 255 | addressable (>= 2.3.5) 256 | faraday (> 0.8, < 2.0) 257 | simpleidn (0.2.1) 258 | unf (~> 0.1.4) 259 | terminal-table (1.8.0) 260 | unicode-display_width (~> 1.1, >= 1.1.1) 261 | thread_safe (0.3.6) 262 | typhoeus (1.4.0) 263 | ethon (>= 0.9.0) 264 | tzinfo (1.2.9) 265 | thread_safe (~> 0.1) 266 | unf (0.1.4) 267 | unf_ext 268 | unf_ext (0.0.8) 269 | unicode-display_width (1.8.0) 270 | zeitwerk (2.5.1) 271 | 272 | PLATFORMS 273 | ruby 274 | 275 | DEPENDENCIES 276 | github-pages 277 | 278 | BUNDLED WITH 279 | 2.1.4 280 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | It's my blog 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | markdown: kramdown 2 | permalink: /:title.html 3 | url: https://blog.9527.eu.org 4 | lsi: true 5 | rouge: true 6 | safe: true 7 | 8 | # presonal config 9 | title: likebeta's Blog 10 | feed: /atom.xml 11 | comments: disqus 12 | 13 | author: 14 | name: likebeta 15 | email: 9527.eu.org@gmail.com 16 | qqmail: https://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=GnZzcX94f257WmtrNHl1dw 17 | site: https://9527.eu.org 18 | 19 | seo: 20 | keyword: 21 | description: 22 | -------------------------------------------------------------------------------- /_includes/comments.html: -------------------------------------------------------------------------------- 1 | {% if site.comments == 'duoshuo' %} 2 | {% include duoshuo.html %} 3 | {% else %} 4 | {% include disqus.html %} 5 | {% endif %} 6 | -------------------------------------------------------------------------------- /_includes/disqus.html: -------------------------------------------------------------------------------- 1 |
2 | 13 | 14 | comments powered by Disqus 15 | -------------------------------------------------------------------------------- /_includes/duosuo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 14 | 15 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /_includes/header.html: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /_includes/page.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{ content }}
4 |
5 |
6 |
7 |
-------------------------------------------------------------------------------- /_includes/post.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{ page.date | date:"%d" }} 5 | {{ page.date | date:"%b" }} 6 | {{ page.date | date:"%Y" }} 7 |
8 |
9 |

{{ page.title }}

10 |
11 |
{{ content }}
12 |
13 | {% if page.previous %} 14 |
上一篇: {{ page.previous.title }}
15 | {% else %} 16 |
下一篇: 这个真没有!!!
17 | {% endif %} 18 | {% if page.next %} 19 |
上一篇: {{ page.next.title }}
20 | {% else %} 21 |
下一篇: 这个真没有!!!
22 | {% endif %} 23 |
24 |
{% include comments.html %}
25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /_includes/posts.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{ content }} 4 |
5 |
6 |
-------------------------------------------------------------------------------- /_includes/statistics.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_layouts/index.html: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | {{site.title}} 29 | 30 | 31 |
假装异步加载中...
32 |
33 | {% include header.html %} 34 | {% include posts.html %} 35 | {% include footer.html %} 36 |
37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | {% if page.read %}{% endif %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | {{page.title}} 30 | 31 | 32 |
假装异步加载中...
33 |
34 | {% include header.html %} 35 | {% include page.html %} 36 | {% include footer.html %} 37 |
38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | {{page.title}} 29 | 30 | 31 |
假装异步加载中...
32 |
33 | {% include header.html %} 34 | {% include post.html %} 35 | {% include footer.html %} 36 |
37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /_posts/2013-04-10-start-blog.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 推倒重来,开始写blog 4 | tags: [blog] 5 | --- 6 | 7 | 最近喜欢上了Git,然后对Github一发不可收拾, 原来也听过使用Github Pages搭建博客, 当时因为在使用WordPress, 没怎么注意这个, 偶然的机会看到了阮一峰博客上介绍[Github Pages和Jekyll入门][1], 刹那间有种相逢恨晚的感觉... 8 | 9 | #### 大学 10 | 11 | 那一年我18岁,她也18岁, 我们...sorry,意淫了... 12 | 13 | 2008年离家去洛阳上学, 这算是我真正意义上的离开家乡去外地上学。 记得那一年是爸爸送我去的学校, 大学的一起都让我感到新奇。开学没几天开始体育选课, 由于我没接触过电脑, 我特么还得让同学帮忙选课, 起跑线都输人一大截啊 14 | 15 | 16 | 17 | 大一的时候没有电脑, 于是就开始了和宿舍的几个哥们的网吧生活,一如霓虹深似海,从此节操为路人,有那么一夜小鱼网吧骗取了我的初包... 18 | 看见互联网上海量的知识, 一颗幼小的心灵瞬间禁止,从此一个悲催的程序员命运就此定格。注册邮箱,聊QQ,收藏网址,下软件,看电影,逛论坛...一切都那么有吸引力, 然后就是想自己做网站放在网上让别人浏览, 自己不会web编程, 只能用dreamweaver瞎折腾, 记得我们很多次去网吧包夜,他们玩游戏看片,我一个人在整网页,整夜的都不觉得累。当时网络资源还是很匮乏的,hao123也没有那么出名,没有什么免费空间,免费域名,开发者平台......最终还是没发布成网站 19 | 20 | 1. 开始接触各大博客:和讯博客,新浪博客,网易博客,百度空间... 21 | 2. 接触技术性博客:csdn,c++博客,博客园... 22 | 3. 买了域名空间,开始各种折腾:WordPress,Typecho,织梦,Discuz(x)... 23 | 4. 各种原因都没有更新了,偶尔会更新博客园... 24 | 5. ... 25 | 26 | 大学4年,转眼就完了, 第一次让我感觉到了时间过得这么快,虽然大学中我也经常逃课,成绩也不怎么好,但是说实在的,大学生活还算充实,我从一个菜鸟迅速的蜕变,虽然现在也不是高手,也没有什么传奇,但是四年里,我真的看了不少书,折腾了好多东西。 27 | 28 | 我主要学习c++,跟着导师主要是MFC,在实验室过了几年。期间为了架博客搞论坛学习了PHP,Javascript,CSS,HTML等一系列的web方面的知识,仿照了一个[WordPress主题][2],[网盘搜索引擎][3]等各种拿不出手的小玩意。c++方面也折腾了一些上不了台面的小玩意。 29 | 30 | #### 遗憾 31 | 32 | 1. 大学没有尽最大的努力,学更多的东西,看更多的书,或者专一一样东西,毕业了发现自己没什么特长 33 | 2. 没有学习Linux,以及开源社区的东西,目光太局限了 34 | 3. 没有早点接触Github,stackoverflow等一系列的网站服务 35 | 4. 没有认识几个痴迷编程的网友,真心想找几个人创业 36 | 5. 没有坚持一样东西四年 37 | 6. API,开放平台和开发者平台没有兴起,没能利用上他们 38 | 7. 没有谈过恋爱 39 | 40 | #### 工作 41 | 42 | 现实世界中我是个不喜欢折腾的人,喜欢安静点,但是也喜欢剧烈的运动。原本打算毕业后去杭州和父母在一起,或者就近在郑州的,当时工作已经找好了,然而偶然的选择来到了帝都,成了名符其实的三无人员纯北漂,还进入了陌生页游行业。 43 | 44 | 工作还行,老大人很好,同事都很好相处,工作压力也不是太大,有时还很闲。按理说应该挺不错的,但是我就是折腾的命,只要是闲下来了就心里恐慌,害怕落后,拼命的看书,但是还是觉得不够用功,觉得自己不太行。书看过了也记不住,想做的东西也坚持不了... 45 | 46 | #### 计划 47 | 48 | 晚上琢磨了一下,我这种状态其实是一种浮躁。这个是很可怕的, 不仅弄的我很疲惫,而且我学的东西都记不住,做了很多的无用功。所以我打算放慢动作,准备开始重新开始写博客,太多太快的知识只会让我更加疲惫,更加浮躁。 49 | 50 | 这次写博客采用Github Pages+Jekyll+Markdown的组合,不再使用WordPress,不可否认WordPress是个非常优秀的blog系统,几乎无所不能,但是我只是想写博客而已,而WordPress更像一个CMS,况且MarkDown写博客太爽了,Git也让我欲罢不能,我能跟专注于文字,而不是折腾各种主题和插件... 51 | 52 | 希望这一次我能坚持下去... 53 | 54 | 55 | [1]: http://www.ruanyifeng.com/blog/2012/08/blogging_with_jekyll.html 56 | [2]: https://github.com/likebeta/ipc 57 | [3]: https://github.com/likebeta/cse 58 | -------------------------------------------------------------------------------- /_posts/2013-04-11-base64.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Base64加密解密算法的C/C++代码实现 4 | tags: [cpp] 5 | --- 6 | 7 | 今天再次用到了base64编解码,以前看过,现在又有点陌生了,上网查了下,然后用c++实现了下,在此记录下,以备将来查用。 8 | 9 | #### 介绍 10 | 11 | [百度百科][1]和[维基百科][2]说的很清楚,我就不罗嗦了 12 | 13 | #### 用途 14 | 15 | Base64算法不是为了防止内容被人破解而使用的算法, 因为破解Base64太容易了, 就是简单的字符替换。 16 | Base64还有个不好的地方,就是加密后, 长度会变成。 17 | 那我们为何还要使用Base64 呢?因为Base64可以把乱七八糟的二进制转化为字符串,这个特性在很多地方很有用。 18 | 19 | 20 | 21 | #### 实现(c++) 22 | 23 | ```cpp 24 | // Base64.h 25 | #ifndef __BASE64_H__ 26 | #define __BASE64_H__ 27 | 28 | #include 29 | using std::string; 30 | 31 | class CBase64 32 | { 33 | public: 34 | static bool Encode(const string& strIn,string& strOut); 35 | static bool Decode(const string& strIn,string& strOut,bool fCheckInputValid = false); 36 | }; 37 | 38 | #endif 39 | ``` 40 | 41 | 42 | ```cpp 43 | // Base64.cpp 44 | #include "base64.h" 45 | 46 | static const char encode_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 47 | static char decode_map[256]; 48 | static void initBase64DecodeMap() 49 | { 50 | memset(decode_map,-1,sizeof(decode_map)); 51 | for (int i = 'A'; i <= 'Z'; ++i) decode_map[i] = 0 + (i - 'A'); 52 | for (int i = 'a'; i <= 'z'; ++i) decode_map[i] = 26 + (i - 'a'); 53 | for (int i = '0'; i <= '9'; ++i) decode_map[i] = 52 + (i - '0'); 54 | decode_map[(unsigned char)'+'] = 62; 55 | decode_map[(unsigned char)'/'] = 63; 56 | decode_map[(unsigned char)'='] = 0; 57 | } 58 | 59 | bool CBase64::Encode(const string& strIn,string& strOut) 60 | { 61 | size_t nInLen = strIn.length(); 62 | size_t numOrig24BitValues = nInLen/3; 63 | bool havePadding = (nInLen != numOrig24BitValues*3); 64 | bool havePadding2 = (nInLen == numOrig24BitValues*3 + 1); 65 | size_t numResultBytes = 4*(numOrig24BitValues + havePadding); 66 | strOut.clear(); 67 | for (size_t i = 0; i < numOrig24BitValues; ++i) 68 | { 69 | strOut.append(1,encode_map[(strIn[3*i] >> 2) & 0x3F]); 70 | strOut.append(1,encode_map[((strIn[3*i] << 4) & 0x30) | ((strIn[3*i+1] >> 4) & 0x0F)]); 71 | strOut.append(1,encode_map[((strIn[3*i+1] << 2) & 0x3C) | ((strIn[3*i+2] >> 6) & 0x03)]); 72 | strOut.append(1,encode_map[strIn[3*i+2] & 0x3F]); 73 | 74 | } 75 | 76 | if (havePadding) 77 | { 78 | size_t i = numOrig24BitValues; 79 | strOut.append(1,encode_map[(strIn[3*i] >> 2) & 0x3F]); 80 | if (havePadding2) 81 | { 82 | strOut.append(1,encode_map[((strIn[3*i] << 4) & 0x30) | ((strIn[3*i+1] >> 4) & 0x0F)]); 83 | strOut.append(1,'='); 84 | } 85 | else 86 | { 87 | strOut.append(1,encode_map[((strIn[3*i] << 4) & 0x30) | ((strIn[3*i+1] >> 4) & 0x0F)]); 88 | strOut.append(1,encode_map[((strIn[3*i+1] << 2) & 0x3C) | ((strIn[3*i+2] >> 6) & 0x03)]); 89 | } 90 | strOut.append(1,'='); 91 | } 92 | 93 | return true; 94 | } 95 | 96 | bool CBase64::Decode(const string& strIn,string& strOut,bool fCheckInputValid/* = false*/) 97 | { 98 | size_t nInlen = strIn.length(); 99 | if (nInlen < 4 || (nInlen % 4) != 0) 100 | { 101 | return false; 102 | } 103 | 104 | static bool bInit = false; 105 | if (!bInit) 106 | { 107 | initBase64DecodeMap(); 108 | bInit = true; 109 | } 110 | 111 | if (fCheckInputValid) 112 | { 113 | for (size_t i = 0; i < nInlen; ++i) 114 | { 115 | if (decode_map[(unsigned char)strIn[i]] == -1) 116 | { 117 | return false; 118 | } 119 | } 120 | } 121 | size_t nOutLen = (nInlen * 3) / 4; 122 | string strTmpOut; 123 | strTmpOut.resize(nOutLen); 124 | size_t nLoopLen = nOutLen / 3; 125 | for (size_t i = 0; i < nLoopLen;++i) 126 | { 127 | strTmpOut[i*3] = ((decode_map[strIn[i*4]] << 2) & 0xFC) | ((decode_map[strIn[i*4+1]] >> 4) & 0x03); 128 | strTmpOut[i*3+1] = ((decode_map[strIn[i*4+1]] << 4) & 0xF0) | ((decode_map[strIn[i*4+2]] >> 2) & 0x0F); 129 | strTmpOut[i*3+2] = ((decode_map[strIn[i*4+2]] << 6) & 0xC0) | (decode_map[strIn[i*4+3]] & 0x3F); 130 | } 131 | 132 | if (strIn[nInlen - 1] == '=') 133 | { 134 | nOutLen--; 135 | if (strIn[nInlen - 2] == '=') 136 | { 137 | nOutLen--; 138 | } 139 | } 140 | const char* pData = strTmpOut.data(); 141 | strOut.clear(); 142 | strOut.append(pData,pData + nOutLen); 143 | return true; 144 | } 145 | ``` 146 | 147 | #### 获取 148 | 149 | 获取文件及更新:[Github][3] 150 | 151 | PS: 在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。这个是MIME中的规定,base64只是一种编码格式,并不是所有的应用都需要遵守这个原则。 152 | 153 | [1]:http://baike.baidu.com/view/469071.htm 154 | [2]:http://zh.wikipedia.org/wiki/Base64 155 | [3]:https://github.com/likebeta/classlib/tree/master/cpp/base64 156 | -------------------------------------------------------------------------------- /_posts/2013-04-22-linux-file-permission.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Linux 文件权限 4 | tags: [linux] 5 | --- 6 | 7 | 大学生涯没有接触linux和开源社区是一大遗憾,年前买本`鸟哥的Linux私房菜 第三版`一直没看,最近扒出来开始学习,大概看了6,7章,发现有些东西当时记下来了,过后又忘记了,所以准备在这里记录下学习笔记,记录一下我认为比较重要的东西,方便自己查阅。 8 | 9 | #### 文件拥有者概念 10 | 11 | 1. 拥有者:文件的所有者,表示谁拥有此文件 12 | 2. 群组:文件属于哪个群组,群组中的成员对此文件有相同的某种权限,方便团队合作 13 | 3. 其他人:不是拥有者,不是root,也不属于该文件所属群组的人 14 | 15 | 16 | 17 | 鸟哥使用了家的概念来解释这些关系非常的浅显易懂,私人空间,公共客厅,以及朋友来比喻非常贴切。 18 | 19 | #### Linux 文件权限概念 20 | 21 | ```sh 22 | [root@king tmp]# ls -l 23 | total 4 24 | drwxr-xr-x 2 root root 4096 Apr 22 10:53 dir 25 | -rw-r--r-- 1 root root 0 Apr 22 10:53 file 26 | [ 1 ][2][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ] 27 | ``` 28 | 29 | [1]表示文件权限,[3]表示拥有者,[4]表示所属群组,[7]表示名称 30 | 31 | [1]文件权限是由10位组成: 32 | 33 | 1. 000:文件的类型(目录,文件,链接文件...) 34 | 2. 123:拥有者的读写执行权限 35 | 3. 456:群组的读写执行权限 36 | 4. 789:其他人的读写执行权限 37 | 38 | #### 改变文件属性与权限 39 | 40 | - chgrp :改变文件所属群组 41 | - chown :改变文件拥有者 42 | - chmod :改变文件的权限, SUID, SGID, SBIT等等的特性 43 | 44 | #### 权限对文件的意义 45 | 46 | - r (read):可读取此一文件的实际内容,如读取文本文件的文字内容等; 47 | - w (write):可以编辑、新增或者是修改该文件的内容(但不含删除该文件); 48 | - x (execute):该文件具有可以被系统执行的权限。 49 | 50 | 在Linux底下,文件是否能被执行,则是藉由是否具有x这个权限来决定的!跟文件名(扩展名)是没有绝对的关系的!文件具有w权限时,你可以修改文件的内容, 但并不具备有删除该文件本身的权限!对于文件的rwx来说, 主要都是针对`文件的内容`而言。 51 | 52 | #### 权限对目录的意义 53 | 54 | - r (read contents in directory): 55 | 表示具有读取目录结构列表的权限,所以当你具有读取(r)一个目录的权限时,表示你可以查询该目录下的文件名数据。 所以你就可以利用 ls 这个指令将该目录的内容列表显示出来! 56 | - w (modify contents of directory): 57 | 这个可写入的权限对目录来说,是很了不起的! 因为他表示你具有异动该目录结构列表的权限,也就是底下这些权限: 58 | 59 | + 建立新的文件与目录 60 | + 删除已经存在的文件与目录(不论该文件的权限为何!) 61 | + 将已存在的文件或目录进行更名 62 | + 搬移该目录内的文件、目录位置 63 | 64 | - x (access directory): 65 | 目录的x代表的是用户能否进入该目录成为工作目录! 所谓的工作目录(work directory)就是你目前所在的目录!举例来说,当你登入Linux时, 你所在的家目录就是你当下的工作目录。而变换目录的指令是`cd`。 66 | 67 | 能不能进入某一个目录,只与该目录的x权限有关!工作目录对于指令的执行是非常重要的,如果你在某目录下不具有x的权限, 那么你就无法切换到该目录下,也就无法执行该目录下的任何指令,即使你具有该目录的r的权限。 68 | 69 | 很多朋友在架设网站的时候都会卡在一些权限的设定上,他们开放目录给因特网的任何人来浏览, 却只开放r的权限,如上面的范例所示那样,那样的结果就是导致网站服务器软件无法到该目录下读取文件(最多只能看到文件名), 最终用户总是无法正确的查阅到文件的内容(显示权限不足)。要注意:要开放目录给任何人浏览时,应该至少也要给予r及x的权限,但w权限不可随便给! 70 | 71 | #### 扩展阅读 72 | 73 | [Linux 的文件权限与目录配置](http://vbird.dic.ksu.edu.tw/linux_basic/0210filepermission.php) 74 | -------------------------------------------------------------------------------- /_posts/2013-04-25-mklink.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: mklink让网盘同步不同文件夹 4 | tags: [网盘, mklink] 5 | --- 6 | 7 | 现在云存储越演越烈,各大公司都推出了自己的网盘,竞争进入白热化,有的以大容量吸引人,有的以速度著称,有的以网赚扎根,有的以托微博圈地,有的定位企业,还有的主打安全...... 8 | 9 | 我接触网盘是08年大一的时候,到现在基本上所有的网盘都不同程度的试用过,目前还在使用的也还有几种。大大小小的N种网盘中只有[坚果云][1]和[skydrive][2]支持不同目录的同步,而其他的[金山快盘][3],[酷盘][4],[百度网盘][5],[云诺][6],[新浪微盘][7],[115][8],[华为网盘][9],[够快][10],[Dropbox][11],[Google Driver][12],[Box][13]等等都只能同步选定的一个目录。 10 | 11 | 12 | 13 | #### mklink简介 14 | 15 | Linux 下有一个叫符号链接的东东,是 ln 这个链接命令,mklink 和 ln 的功能几乎一样。在xp系统下,junction命令要用微软开发的小程序 junction.exe实现,从http://live.sysinternals.com/可以下载。现在Windows Vista之后的系统自带了mklink的功能。创建符号链接不仅可以当作快捷方式使用,最重要的是重定向链接符可以被程序读取然后重定向真正的位置,这是快捷方式无法做到的。 16 | 17 | win+r -> cmd -> mklink: 18 | 19 | ```sh 20 | MKLINK [[/D] | [/H] | [/J]] Link Target 21 | /D 创建目录符号链接。默认为文件符号链接。 22 | /H 创建硬链接,而不是符号链接。 23 | /J 创建目录联接。 24 | Link 指定新的符号链接名称。 25 | Target 指定新链接引用的路径(相对或绝对)。 26 | ``` 27 | 28 | 默认情况: 29 | 30 | - 文件的符号链接,如没有参数指定,则创建文件的符号链接,删除文件链接不会影响目 标文件,且创建链接时允许目标文件不存在; 31 | - 目录的符号链接(SYMLINKD) /D该参数可以创建目录的符号链接,删除目录链接不 会影响目标目录,且创建链接时允许目标目录不存在; 32 | - 目录的软链接(JUNCTION) /J 该参数可以创建目录的软链接(联接),作用基本和符号链接类似,NT6系统的用户目录就是以这种形式存在的; 33 | - 文件的硬链接 /H 该参数可以创建文件的硬链接,即一个文件的多个别名,NT6系统WinSXS目录下的大部分文件是以这个形式存在的; 34 | 35 | 更多阅读: 36 | 37 | [mklink使用简介][20] 38 | [mklink的参数j和参数d在实际应用中的区别是什么?][21] 39 | 40 | #### mklink的应用 41 | 42 | 根据上面的介绍大家肯定知道我想干什么了,对!就是利用mklink为网盘加上多目录同步的功能。下面以Dropbox备份某软件的配置为例,其他的网盘都类似: 43 | 网盘的同步文件夹是`E:/u/Dropbox`,需要同步的文件夹是`D:/soft1/config`我们使用下面的命令: 44 | 45 | ```sh 46 | mklink /D "E:/u/Dropbox/mydata" "D:/soft1/config" 47 | ``` 48 | 49 | 这样E:/u/Dropbox/mydata就指向D:/mydata,相当于两个访问接口,删除`E:/u/Dropbox/mydata`不会影响到`D:/soft1/config`,反之则不行。按照这种方法就可以让Dropbox等网盘部分不同的文件夹了。 50 | 51 | 但是现在也有个问题,你会发现只有Dropbox第一次启动或者重启时会同步,你的修改不能马上被Dropbox捕获到,Dropbox可以使用系统托盘菜单中的暂停和恢复同步来手动让Dropbox对修改进行捕获,有些网盘如酷盘就没有这个功能,只能利用重启软件来同步,很不方便。 52 | 53 | 其实这里还有个方法就是:我们反着来,将真实文件夹(如`config`)放在Dropbox中,在`D:/soft1/`中创建软连接, 如命令: 54 | 55 | ```sh 56 | mklink /D "D:/soft1/config" "E:/u/Dropbox/mydata" 57 | ``` 58 | 59 | 这样的缺点就是其实根本没有改进网盘不支持多目录备份的问题,而是和系统开玩笑而已,但是这样确实很方便,我目前基本使用这种方法。 60 | 61 | #### 实例 62 | 63 | 举几个我使用mklink的例子: 64 | 65 | 1. 备份hosts 66 | 2. 备份一些软件的配置,如Notepad++,vim配置... 67 | 3. 备份分散的代码(不推荐,推荐git来备份) 68 | 3. wamp中www下的目录分散到不同地方 69 | 5. ... 70 | 71 | 72 | 73 | [1]: https://jianguoyun.com/d/ref/WITP6i8eN9eYaXQ5QWJo5A 74 | [2]: https://skydrive.live.com 75 | [3]: http://www.kuaipan.cn/?channel=ptmv42 76 | [4]: http://kb.vc/bp2V 77 | [5]: http://pan.baidu.com 78 | [6]: https://www.yunio.com/index/url/code/RndYTVl3WkxtU09XUkNQM1ZvdjhXWmp6cnkzOFEwTW05ZnllZ3JqNW1JVVQ1N0ZtbHY3STRJMA== 79 | [7]: http://vdisk.weibo.com 80 | [8]: http://115.com/invite/64a385 81 | [9]: http://dbank.vmall.com/inviter/306001 82 | [10]: http://www.gokuai.com 83 | [11]: http://db.tt/jacpdIw 84 | [12]: https://drive.google.com/ 85 | [13]: https://www.box.com 86 | [20]: http://wenku.baidu.com/view/56453dcfda38376baf1fae2c.html 87 | [21]: http://bbs.csdn.net/topics/330135418 88 | -------------------------------------------------------------------------------- /_posts/2013-05-11-sh-execute-diff.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: shell脚本不同运行方式的区别 4 | tags: [shell, script] 5 | --- 6 | 7 | shell脚本的运行大体分为下面几种方式: 8 | 9 | > 1. `sh filename` 10 | > 2. `./filename` 或 `/$(parent_path)/filename` 11 | > 3. `source filename` 或者 `. filename` 12 | 13 | 不同的 script 运行方式会造成不一样的结果,比如对 bash 的环境的影响。 14 | 15 | 16 | 17 | #### 直接的方式运行 script 18 | 19 | 上面的第1,2中都是属于直接的方式来运行,不管定位shell脚本的时候是使用相对路径,绝对路径还是包含在$PATH,脚本运行的是否都会使用一个新的bash环境。这就是说,使用这种方式时,其实脚本是在子进程中运行的,这样带来的结果就是: 20 | 21 | > 当srcipt完成后,在子进程内的各项变量或动作将会结束而不会传回到父进程中 22 | 23 | #### 利用 source 来运行 script 24 | 25 | 利用source(或者.)来运行脚本的时候,脚本是在当前bash进程中运行,这就是说: 26 | 27 | > 当srcipt完成后,它的各项变量或动作会影响当前的bash进程 28 | 29 | 比如我们修改了~/.bashrc这,不注销系统而要让其生效的时候,需要使用 source ~/.bashrc 而不能使用 sh ~/.bashrc 30 | -------------------------------------------------------------------------------- /_posts/2013-05-12-buy-a-vps.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 买了个super屌丝级vps 4 | tags: [vps,xshell,屌丝,openshift] 5 | --- 6 | 7 | 最近在折腾openshift云空间,真是个好东西,相比国内的云空间直接甩开几条街,还可以绑定域名,免费的配置已经足够我们折腾了,看了教程后,搞了几个app,感觉速度还行,况且我会再加上一层cdn。直接把自己的几个站移了过来,等待dns和cdn都生效后,速度不错,各方面都比较满意(git来提交代码爽爆了)。 8 | 9 | 10 | 11 | 第二天,想修改点东西,大清早跑到公司,发现ssh速度慢的要死,而且经常连不上,网站还正常访问(可爱的cdn),测试下知道是方院士的杰作,妈的,这个只能等待连得上的时候再试呗,怄火啊,时间浪费了...... 12 | 13 | 下午,查资料的时候偶尔进入了一个网站,发现博主竟然是一个初中的小盆友,我太阳,感慨自己真的老了。翻看博文的时候发现了他说自己买了个微型的vps,内存128M,当前网站使用的就是这个,才100多块钱。我靠,原以为vps都是高帅富用的,感情还有屌丝级别的啊。于是自己也想买个,搜索找到了个[host700][1], 有个128M内存,10G空间,400G流量,虽然不知道会不会跑路,但是还是买了一个。反正这vps不用来做站,我只想通过它来操作openshift,省这点钱其实很不划算,时间就是钱,现在总是感觉时间不够用,况且最近在学习linux,每次开个虚拟机挺卡的。 14 | 15 | 在公司用xshell通过ssh连上vps,安装了git和rhc,然后在上面修改openshift上的东西,速度很不错(直接连接openshift,敲个命令可能就卡死了),真他妈有种高潮的感觉,咳咳,我是男的...... 16 | 17 | 晚上下班了,回到狗窝,迫不及待的想在修改点代码,我操,竟然连接不上,ping了下vps,不通。你妹的,宿舍的铁通竟然vps的ip被墙了,这下通过vps曲线救国的方式也完蛋了,真他妈怄火。最后想了想,很久以前有个ssh账号,代理用的,最后因为速度慢,改用GoAgent了。翻箱倒柜找了出来,发现竟然还可以使用! 18 | 19 | 通过MyEntunnel配置了代理,然后xshell又通过sock5代理(本地的MyEntunnel将ssh转成sock5)连接到vps,然后vps操作openshift,虽然有点慢,但是感觉还行,这样等于说饶了两道弯才能修改openshift。 20 | 21 | PS: 不直接通过本地sock5连接到openshift是因为这个sock5的速度不怎么样,用来传输shell命令还行,如果直接操作openshift上的代码就伤不起了,而vps链接openshift的速度很快。 22 | 23 | PPS: 在天朝做个程序员真的不容易啊 24 | 25 | **老妈,母亲节快乐,愿你永远健康长寿** 26 | 27 | [1]: https://manager.host700.com/aff.php?aff=274 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /_posts/2013-05-13-a-xshell-style.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 一个好看的Xshell配色方案(转) 4 | tags: [xshell] 5 | --- 6 | 7 | xshell的默认配色风格真的不敢恭维,用久了,眼睛疼,网上搜了一圈,找到了个不错的配色方案,我把放在这里,省的以后再找,还可以凑篇文章,hia hia 8 | 9 | 10 | 11 | ``` 12 | [Solarized Dark] 13 | text(bold)=839496 14 | magenta(bold)=6c71c4 15 | text=839496 16 | white(bold)=fdf6e3 17 | green=859900 18 | red(bold)=cb4b16 19 | green(bold)=586e75 20 | black(bold)=073642 21 | red=dc322f 22 | blue=268bd2 23 | black=002b36 24 | blue(bold)=839496 25 | yellow(bold)=657b83 26 | cyan(bold)=93a1a1 27 | yellow=b58900 28 | magenta=dd3682 29 | background=042028 30 | white=eee8d5 31 | cyan=2aa198 32 | [Names] 33 | count=1 34 | name0=Solarized Dark 35 | ``` 36 | 37 | 新建solarized-dark.xcs,copy上面内容,然后 右键 > Color Schemes > Import 38 | 39 | -------------------------------------------------------------------------------- /_posts/2013-05-23-thinking-from-shaver.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 从Philips剃须刀想到的产品设计 4 | tags: [Philips,产品设计] 5 | --- 6 | 7 | 5.1的时候,狠心刮了胡子,第一次啊,尼玛,怎么看都像太监,无奈长得又慢。然后在当当买了个剃须刀,到货了发现是装电池的(提前没看清楚),不过完美的流线体,还是挺不错的。当时因为胡子没有长出来,宿舍又没有电池,就扔在那里没在意。 8 | 9 | 10 | 11 | 过了大概5天,久违的胡子终于长出来了,所以买了电池(尼玛型号买错了一次)准备使用,我靠,不转,电池反过来倒过去都不转。宿舍的几个哥们捣鼓个遍,都不行,我想应该是装上次货了。宿舍的小胖说可能是南孚电池的劲太猛,他原来也遇到过,让我换种垃圾点的电池试试。第二天,中午想起了这事,和客服交流了下,客服说不可能,他们发货前都检查过,让我回去电池倒着装试试。说实在话我都试了,好吧回去再试试看,苟且认为是我2了。回去的时候,买了垃圾点的电池,回去都不行。这下他妈火大,真心不想换货这种麻烦的流程... 12 | 13 | 在我毫不抱希望把玩的时候,突然看到装电池的插槽的地步印的有+和—,并且两个竟然是相反的。调换了次序,果然,我被习惯性常识忽悠了… 14 | 15 | 我不知道Philips的设计师是基于什么设计的,当然有人可能说是我太2,但是我想说的是:我宿舍的人也没发现。这就说明了一个问题,设计本身有问题。你可能认为是很显而易见的东西,但是对于用户可能就很难理解,大费周章,产生强烈的挫败感,甚至是恼怒。 16 | 17 | > Don't Make Me Think 18 | 19 | 产品设计不应该让用户过多的思考,用户只是想用你的东西,他们只是希望拿来就用,任何其他的东西都是多余的。另外,产品的设计不应该违背用户的习惯,比如windows中 ctrl+c(复制)和 ctrl+v(粘贴),几乎任何地方都是一样的功能。试想某个软件将ctrl+c和ctrl+v的含义修改了,用户是啥感觉; 我们习惯按钮灰色代表不可用,如果你的产品是相反的意思,你就给用户带来了负担,疑惑和巨大的学习成本。 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /_posts/2013-05-26-difference-between-resume-and-cv.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: resume和cv的区别 4 | tags: [扫盲,简历] 5 | --- 6 | 7 | 英语一直都不好,四级不知道咋过的(居然还485),六级考过一次,也没有报什么希望,耳机都没带,结果得了个245(会不会2和4写错位子了)。最近本屌丝想写下个人简历,在命名网址的时候纠结了,有道词典的翻译如下: 8 | 9 | #### cv 10 | 11 | > n. curriculum vitae :简历(书), 个人履历 12 | 13 | #### resume 14 | 15 | > n. 摘要;履历,简历(该释义发音[rezju:'mei]) 16 | > vt. 重新开始,继续;恢复,重新占用 17 | > vi. 重新开始,继续 18 | 19 | 20 | 21 | 你妹的,完全看不出啥区别,本屌丝有强迫症,选择太多对我来说是种折磨,不搞清楚区别我是没法干其他事的。Google了一下区别,伟大的前辈们已经给我写好了区别,这里直接拿来用(原谅我的无耻): 22 | 23 | #### 区别 24 | 25 | > 我们现在常常有人把CV和Resume混起来称为“简历”,其实精确而言,CV应该是“履历”,Resume才是简历。要记住,Resume概述了与求职有关的教育准备和经历,是对经验技能的摘要,其主要目的在说服用人单位老板雇佣自己;Curriculum Vitae则集中说明学术工作,不重视与文化程度和学习成绩无直接关系的资料。 26 | 27 | 大部分国家是不区分这两个词的,建议大家可以这样使用 28 | 29 | > 如果你申请的是公司里的一个职位,那么你的个人简历就写成:resume。比如:Dr. Jinsong Guo’s resume. 30 | > 如果你申请的是学校里的一个教学职位,那么你的个人简历就写成:curriculum vitae。比如:Dr. Jinsong Guo’s curriculum vitae或Dr. Jinsong Guo’s CV。 31 | 32 | 看来我需要使用resume了,`学术` 听起来很牛逼的样子,咱也不懂,不适合吊儿郎当的本屌。 33 | 34 | ps: 我一直感觉吃辣椒就像高潮,痛并快乐着... 35 | 36 | #### 扩展阅读 37 | 38 | CV与Resume的区别() 39 | Resume 和 CV 的区别() 40 | -------------------------------------------------------------------------------- /_posts/2013-06-16-ifttt.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: ifttt的使用体验 4 | tags: [ifttt] 5 | --- 6 | 7 | 这玩意在内测的时候就注册了号,但是没用过。最近Google Reader关闭,说实话目前真找不到替代品。订阅的feed太多,很多都来不及查看,但是email却是经常查看的,比如很多博客使用QQ邮件列表,feedburner来进行邮件更新推送,订阅用户可以不用主动去查看。但是很多博客还是不能使用邮件来订阅的,当然我们可以使用QQ邮件列表,feedburner创建个item来进行转换,但是我也可以使用ifttt做到类似的功能,并且功能更强大。 8 | 9 | 10 | 11 | #### 原理 12 | 13 | > ifttt是一个新生的网络服务平台,通过不同其他平台的条件来决定是否执行下一条命令。即对网络服务通过其他网络服务作出反应作出反映。ifttt得名为其口号"if this then that"。 14 | 15 | > ifttt基于任务的条件触发,类似编程语言,即:“若XXX进行YYY行为,执行ZZZ。”。每一个可以触发或者作为任务的网站叫做一个Channel,触发的条件叫做Triggers,之后执行的任务叫做Actions,综合上面的一套流程叫做Task。 16 | 17 | #### 用途 18 | 19 | 用ifttt创建条目很简单,甚至有很多别人已经分享的Task,我们可以直接拿来用。我使用ifttt创建了几个Task: 20 | 21 | 1. ifttt有更新,发email给我 22 | 2. 皮皮书屋有更新,发email给我 23 | 3. dropbox产生event,发email给我 24 | 4. v2ex有回复,发email给我 25 | 5. facebook添加了图片,将图片添加到dropbox(这个又会触发3) 26 | 6. xjp博客有更新,将博文email给我 27 | 28 | 还有好多好玩的Task,大家可以自己去挖掘...... 29 | 30 | #### 吐槽 31 | 32 | 拿 `feed更新email我` 这个Task来说:同QQ邮件列表和feedburner一样只能输入一个feed地址,这样就需要创建大量的Task。 33 | 另外,貌似我没看到api,我想自己搞个解决上面这个吐槽的方法,但是我真心找不到api。如果能创建一个类似杂志的Task,里面可以随意订阅自己喜欢的feed挺爽的,貌似盛大出过一个`微杂志`,现在已经关了(btw,盛大的东西以后咋也不会用了,IT行业的败类)。 34 | 35 | #### 扩展 36 | 37 | [ifttt/likebeta](https://ifttt.com/people/likebeta) 38 | [wikipedia/ifttt](http://zh.wikipedia.org/wiki/Ifttt) 39 | -------------------------------------------------------------------------------- /_posts/2013-08-01-ubuntu-static-ip-and-dns.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: ubuntu配置静态ip和dns 4 | tags: [ubuntu,dns,ip] 5 | --- 6 | 7 | 前段时间同事离职,他的机子配置比较好,我和老大申请,无耻的换用他的主机,收编了他的显示器。这下内存和硬盘都上去了,总得折腾点事情做啊,安装虚拟机,折腾个 ubuntu 用用,刚好同事的 ip 我也霸占了(我们局域网的 ip 是静态绑定的)。我想把原来在 windows 下搭建的 php 环境放在 linux 上,这样的话就需要配置个 ip , vmware 的网络设置需要是 bridge 模式,不能是原来的 nat 模式。 debian 下配置静态 ip 和 dns 挺简单的, ubuntu 下有点不同,在此记录下。 8 | 9 | 10 | 11 | #### 修改网络配置文件 12 | 13 | 网络配置文件存储在 /etc/network/interfaces 中 14 | 15 | ```sh 16 | sudo vi /etc/network/interfaces 17 | ``` 18 | 19 | 填写信息如下: 20 | 21 | ```sh 22 | auto eth0 #指明网卡eth0在系统启动时自动加载 23 | #指明eth0采用ipv4地址,inet表示ipv4地址,inet6表示ipv6地址; static表示静态,dhcp表示动态 24 | iface eth0 inet static 25 | 26 | address 192.168.1.155 #静态ip 27 | netmask 255.255.255.0 #子网掩码 28 | gateway 192.168.1.1 #网关地址 29 | ``` 30 | 31 | ip 地址设置完毕了 32 | 33 | #### 设置 dns 服务器 34 | 35 | 这个你可以设置自己的 dns 服务器,我还是比较习惯用谷歌的。 dns 信息存储在 /etc/resolv.conf 中 36 | 37 | ```sh 38 | sudo vi /etc/resolv.conf 39 | ``` 40 | 41 | 添加以下内容 42 | 43 | ```sh 44 | nameserver 8.8.8.8 #首选dns服务器 45 | #nameserver x.x.x.x #备选dns服务器 46 | ``` 47 | 48 | dns 服务器也设置完毕。 49 | 50 | #### 重启网络 51 | 52 | 需要重启下网络才能生效,命令如下 53 | 54 | ```sh 55 | sudo /etc/init.d/networking restart 56 | ``` 57 | 58 | #### 问题 59 | 60 | debian 或者 centos 按照上面设置后就彻底没有问题了,但是 ubuntu 在重启电脑后, dns 的设置都丢失了。原因是 /etc/resolv.conf 是动态创建的,重启后会被覆盖。晚上找到解决方法两个: 61 | 62 | **/etc/network/interfaces 最后添加 dns 服务器** 63 | 64 | ```sh 65 | dns-nameservers 8.8.8.8 66 | ``` 67 | 68 | 重启网络就行了,此时 /etc/resolv.conf 中也会添加上面的 dns 69 | 70 | **/etc/resolvconf/resolv.conf.d/base 中添加 dns 服务器** 71 | 72 | ```sh 73 | nameserver 8.8.8.8 #首选dns服务器 74 | #nameserver x.x.x.x #备选dns服务器 75 | ``` 76 | 77 | 保存后,执行 resolvconf -u 就行了,此时 /etc/resolv.conf 中也会添加上面的 dns 78 | 79 | 至此,全部配置完毕。 80 | -------------------------------------------------------------------------------- /_posts/2013-09-25-simple-factory-pattern.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 设计模式 - 简单工厂模式 4 | tags: [factory,pattern] 5 | --- 6 | 7 | #### 工厂模式 8 | 9 | 1. 简单工厂(Simple Factory)模式:又称静态工厂方法(Static Factory Method)模式 10 | 2. 工厂方法(Factory Method)模式:又称多态性工厂(Polymorphic Factory)模式 11 | 3. 抽象工厂(Abstract Factory)模式:又称工具箱(Kit 或 Toolkit)模式 12 | 13 | 从设计模式的类型上来说,简单工厂模式是属于创建型模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。 14 | 15 | 16 | 17 | 其包括三个角色: 18 | 19 | 1. 工厂(Creator)角色 :简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。 20 | 2. 抽象产品(Product)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。 21 | 3. 具体产品(Concrete Product)角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。 22 | 23 | #### 优点 24 | 25 | 工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。 26 | 27 | #### 缺点 28 | 29 |   由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。 30 |   当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利; 31 |   这些缺点在工厂方法模式中得到了一定的克服。 32 | 33 | #### 使用场景 34 | 35 | - 工厂类负责创建的对象比较少; 36 | - 客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心; 37 | - 由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。 38 | 39 | 说明:以上文字概念部分,均来自百度百科。自己没有那么好的归纳能力。 40 | 41 | c++实现: 42 | 43 | ```cpp 44 | // IPhone.h 45 | #ifndef __IPHONE_H__ 46 | #define __IPHONE_H__ 47 | 48 | class IPhone 49 | { 50 | public: 51 | IPhone(){}; 52 | virtual ~IPhone(){}; 53 | virtual void showName() = 0; 54 | }; 55 | 56 | #endif 57 | ``` 58 | 59 | ```cpp 60 | // Phone.h 61 | #ifndef __PHONE_H__ 62 | #define __PHONE_H__ 63 | #include "IPhone.h" 64 | 65 | class CMX1Phone:public IPhone 66 | { 67 | public: 68 | CMX1Phone(); 69 | virtual ~CMX1Phone(); 70 | virtual void showName(); 71 | }; 72 | 73 | class CMX2Phone:public IPhone 74 | { 75 | public: 76 | CMX2Phone(); 77 | virtual ~CMX2Phone(); 78 | virtual void showName(); 79 | }; 80 | 81 | class CMI1Phone:public IPhone 82 | { 83 | public: 84 | CMI1Phone(); 85 | virtual ~CMI1Phone(); 86 | virtual void showName(); 87 | }; 88 | 89 | #endif 90 | ``` 91 | 92 | ```cpp 93 | // Phone.cpp 94 | #include "Phone.h" 95 | #include 96 | 97 | CMX1Phone::CMX1Phone() 98 | { 99 | } 100 | 101 | CMX1Phone::~CMX1Phone() 102 | { 103 | } 104 | 105 | void CMX1Phone::showName() 106 | { 107 | std::cout << "I am mx1 of meizu!\n"; 108 | } 109 | 110 | CMX2Phone::CMX2Phone() 111 | { 112 | } 113 | 114 | CMX2Phone::~CMX2Phone() 115 | { 116 | } 117 | 118 | void CMX2Phone::showName() 119 | { 120 | std::cout << "I am mx2 of meizu!\n"; 121 | } 122 | 123 | CMI1Phone::CMI1Phone() 124 | { 125 | } 126 | 127 | CMI1Phone::~CMI1Phone() 128 | { 129 | } 130 | 131 | void CMI1Phone::showName() 132 | { 133 | std::cout << "I am mi1 of xiaomi!\n"; 134 | } 135 | ``` 136 | 137 | ```cpp 138 | // PhoneFactory.h 139 | #ifndef __PHONE_FACTORY_H__ 140 | #define __PHONE_FACTORY_H__ 141 | #include "IPhone.h" 142 | #include "Phone.h" 143 | #include 144 | 145 | class CPhoneFactory 146 | { 147 | public: 148 | static IPhone* createPhone(std::string strName); 149 | }; 150 | 151 | IPhone* CPhoneFactory::createPhone(std::string strName) 152 | { 153 | IPhone* pPhone = NULL; 154 | if (strName == "mx1") 155 | { 156 | pPhone = new CMX1Phone(); 157 | } 158 | else if (strName == "mx2") 159 | { 160 | pPhone = new CMX2Phone(); 161 | } 162 | else if (strName == "mi1") 163 | { 164 | pPhone = new CMI1Phone(); 165 | } 166 | 167 | if (pPhone != NULL) 168 | { 169 | pPhone->showName(); 170 | } 171 | 172 | return pPhone; 173 | } 174 | 175 | #endif 176 | ``` 177 | 178 | ```cpp 179 | // main.cpp 180 | #include 181 | #include 182 | using namespace std; 183 | #include "PhoneFactory.h" 184 | 185 | int main() 186 | { 187 | std::string strName[5] = {"mx1","mx2","mx3","mi1","mi2"}; 188 | for (int i = 0; i < 5; ++i) 189 | { 190 | IPhone* pPhone = CPhoneFactory::createPhone(strName[i]); 191 | if (pPhone == NULL) 192 | { 193 | std::cout << "not exist " << strName[i] << "!\n"; 194 | } 195 | delete pPhone; 196 | } 197 | return 0; 198 | } 199 | ``` 200 | 201 | #### 总结 202 | 203 | PhoneFactory的createPhone只是一个根据某种标识索引并创建出目标对象,我们可以用id,字符串都可以,我们目前服务器的代码是根据消息id来索引具体的消息体,它这里面作为类的静态方法开启来听别扭的, 我更倾向于直接是一个全局静态方法或者放在某个namespace中。 204 | -------------------------------------------------------------------------------- /_posts/2013-09-27-polymorphic-factory-pattern.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 设计模式 - 工厂模式 4 | tags: [factory,pattern] 5 | --- 6 | 7 | Simple Factory模式经常在系统开发中用到,但是这并不是 Factory 模式的最大威力所在(因为这可以通过其他方式解决这个问题)。Factory模式不单是提供了创建对象的接口,其最重要的是延迟了子类的实例化。 8 | 9 | Factory模式的应用并不是只是为了封装对象的创建,而是要把对象的创建放到子类中实现:Factory 中只是提供了对象创建的接口,其实现将放在 Factory 的子类ConcreteFactory中进行。 10 | 11 | 12 | 13 | #### 优点 14 | 15 | Factory 模式在实际开发中应用非常广泛,面向对象的系统经常面临着对象创建问题: 16 | 要创建的类实在是太多了。而 Factory 提供的创建对象的接口封装(第一个功能),以及其将类的实例化推迟到子类(第二个功能)都部分地解决了实际问题。 17 | 18 | #### 缺点 19 | 20 | Factory模式也带来至少以下两个问题: 21 | 22 | 1. 如果为每一个具体的 ConcreteProduct 类的实例化提供一个函数体,那么我们可能不得不在系统中添加了一个方法来处理这个新建的 ConcreteProduct,这样 Factory 的接口永远就不可能封闭(Close)。当然我们可以通过创建一个 Factory的子类来通过多态实现这一点,但是这也是以新建一个类作为代价的。 23 | 2. 在实现中我们可以通过参数化工厂方法,即给 FactoryMethod()传递一个参数用以决定是创建具体哪一个具体的 Product。当然也可以通过模板化避免子类创建子类,其方法就是将具体 Product 类作为模板参数,实现起来也很简单。 24 | 25 | #### 实现 26 | 27 | ```cpp 28 | // IPhone.h 29 | #ifndef __IPHONE_H__ 30 | #define __IPHONE_H__ 31 | 32 | class IPhone 33 | { 34 | public: 35 | IPhone(){}; 36 | virtual ~IPhone(){}; 37 | virtual void showName() = 0; 38 | }; 39 | 40 | #endif 41 | ``` 42 | 43 | ```cpp 44 | // Phone.h 45 | #ifndef __PHONE_H__ 46 | #define __PHONE_H__ 47 | #include "IPhone.h" 48 | 49 | class CMX1Phone:public IPhone 50 | { 51 | public: 52 | CMX1Phone(); 53 | virtual ~CMX1Phone(); 54 | virtual void showName(); 55 | }; 56 | 57 | class CMX2Phone:public IPhone 58 | { 59 | public: 60 | CMX2Phone(); 61 | virtual ~CMX2Phone(); 62 | virtual void showName(); 63 | }; 64 | 65 | class CMX3Phone:public IPhone 66 | { 67 | public: 68 | CMX3Phone(); 69 | virtual ~CMX3Phone(); 70 | virtual void showName(); 71 | }; 72 | 73 | class CMI1Phone:public IPhone 74 | { 75 | public: 76 | CMI1Phone(); 77 | virtual ~CMI1Phone(); 78 | virtual void showName(); 79 | }; 80 | 81 | class CMI2Phone:public IPhone 82 | { 83 | public: 84 | CMI2Phone(); 85 | virtual ~CMI2Phone(); 86 | virtual void showName(); 87 | }; 88 | 89 | #endif 90 | ``` 91 | 92 | ```cpp 93 | // Phone.cpp 94 | #include "Phone.h" 95 | #include 96 | 97 | CMX1Phone::CMX1Phone() 98 | { 99 | } 100 | 101 | CMX1Phone::~CMX1Phone() 102 | { 103 | } 104 | 105 | void CMX1Phone::showName() 106 | { 107 | std::cout << "I am mx1 of meizu!\n"; 108 | } 109 | 110 | CMX2Phone::CMX2Phone() 111 | { 112 | } 113 | 114 | CMX2Phone::~CMX2Phone() 115 | { 116 | } 117 | 118 | void CMX2Phone::showName() 119 | { 120 | std::cout << "I am mx2 of meizu!\n"; 121 | } 122 | 123 | CMX3Phone::CMX3Phone() 124 | { 125 | } 126 | 127 | CMX3Phone::~CMX3Phone() 128 | { 129 | } 130 | 131 | void CMX3Phone::showName() 132 | { 133 | std::cout << "I am mx3 of meizu!\n"; 134 | } 135 | 136 | CMI1Phone::CMI1Phone() 137 | { 138 | } 139 | 140 | CMI1Phone::~CMI1Phone() 141 | { 142 | } 143 | 144 | void CMI1Phone::showName() 145 | { 146 | std::cout << "I am mi1 of xiaomi!\n"; 147 | } 148 | 149 | CMI2Phone::CMI2Phone() 150 | { 151 | } 152 | 153 | CMI2Phone::~CMI2Phone() 154 | { 155 | } 156 | 157 | void CMI2Phone::showName() 158 | { 159 | std::cout << "I am mi2 of xiaomi!\n"; 160 | } 161 | ``` 162 | 163 | ```cpp 164 | // IFactory.h 165 | #ifndef __IFACTORY_H__ 166 | #define __IFACTORY_H__ 167 | #include "Phone.h" 168 | #include 169 | 170 | class IFactory 171 | { 172 | public: 173 | IFactory(){}; 174 | virtual ~IFactory(){}; 175 | virtual IPhone* createPhone(std::string strName) = 0; 176 | }; 177 | 178 | #endif 179 | ``` 180 | 181 | ```cpp 182 | // PhoneFactory.h 183 | #ifndef __PHONE_FACTORY_H__ 184 | #define __PHONE_FACTORY_H__ 185 | #include "IFactory.h" 186 | #include "IPhone.h" 187 | #include "Phone.h" 188 | 189 | class CMXFactory:public IFactory 190 | { 191 | public: 192 | CMXFactory(); 193 | virtual ~CMXFactory(); 194 | virtual IPhone* createPhone(std::string strName); 195 | }; 196 | 197 | class CMIFactory:public IFactory 198 | { 199 | public: 200 | CMIFactory(); 201 | virtual ~CMIFactory(); 202 | virtual IPhone* createPhone(std::string strName); 203 | }; 204 | 205 | #endif 206 | ``` 207 | 208 | ```cpp 209 | // PhoneFactory.cpp 210 | #include "PhoneFactory.h" 211 | #include "Phone.h" 212 | 213 | CMXFactory::CMXFactory() 214 | { 215 | } 216 | 217 | CMXFactory::~CMXFactory() 218 | { 219 | } 220 | 221 | IPhone* CMXFactory::createPhone(std::string strName) 222 | { 223 | IPhone* pPhone = NULL; 224 | if (strName == "mx1") 225 | { 226 | pPhone = new CMX1Phone(); 227 | } 228 | else if (strName == "mx2") 229 | { 230 | pPhone = new CMX2Phone(); 231 | } 232 | else if (strName == "mx3") 233 | { 234 | pPhone = new CMX3Phone(); 235 | } 236 | 237 | if (pPhone != NULL) 238 | { 239 | pPhone->showName(); 240 | } 241 | 242 | return pPhone; 243 | } 244 | 245 | CMIFactory::CMIFactory() 246 | { 247 | } 248 | 249 | CMIFactory::~CMIFactory() 250 | { 251 | } 252 | 253 | IPhone* CMIFactory::createPhone(std::string strName) 254 | { 255 | IPhone* pPhone = NULL; 256 | if (strName == "mi1") 257 | { 258 | pPhone = new CMI1Phone(); 259 | } 260 | else if (strName == "mi2") 261 | { 262 | pPhone = new CMI2Phone(); 263 | } 264 | 265 | if (pPhone != NULL) 266 | { 267 | pPhone->showName(); 268 | } 269 | 270 | return pPhone; 271 | } 272 | ``` 273 | 274 | ```cpp 275 | // main.cpp 276 | #include 277 | #include 278 | using namespace std; 279 | #include "PhoneFactory.h" 280 | 281 | int main() 282 | { 283 | std::string strName[2][4] = {"mx1","mx2","mx3","mx4","mi1","mi2","mi3","mi4"}; 284 | IFactory* pFactory[2] = {new CMXFactory(),new CMIFactory()}; 285 | for (int n = 0; n < 2; ++n) 286 | { 287 | for (int i = 0; i < 4; ++i) 288 | { 289 | IPhone* pPhone = pFactory[n]->createPhone(strName[n][i]); 290 | if (pPhone == NULL) 291 | { 292 | std::cout << "not exist " << strName[n][i] << "!\n"; 293 | } 294 | delete pPhone; 295 | } 296 | delete pFactory[n]; 297 | pFactory[n] = NULL; 298 | } 299 | return 0; 300 | } 301 | ``` 302 | 303 | #### 讨论 304 | 305 | 可以看出,Factory 模式对于对象的创建给予开发人员提供了很好的实现策略,但是Factory 模式仅仅局限于一类类(就是说 Product 是一类,有一个共同的基类),如果我们要为不同类的类提供一个对象创建的接口,那就要用 Abstract Factory了。 306 | 307 | #### ps 308 | 309 | 工厂模式我还未能真正理解他的好处,例子也太小,不能体现工厂模式的威力,我水平不够,这个需要慢慢积累理解 310 | -------------------------------------------------------------------------------- /_posts/2013-09-29-abstract-factory-pattern.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 设计模式 - 抽象工厂模式 4 | tags: [factory,pattern] 5 | --- 6 | 7 | #### 问题 8 | 9 | 假设我们要开发一款游戏,当然为了吸引更多的人玩,游戏难度不能太大(让大家都没有信心了,估计游戏也就没有前途了),但是也不能太简单(没有挑战性也不符合玩家的心理)。于是我们就可以采用这样一种处理策略:为游戏设立等级,初级、中级、高级甚至有BT 级。假设也是过关的游戏,每个关卡都有一些怪物(monster)守着,玩家要把这些怪物干掉才可以过关。 10 | 11 | 12 | 13 | 作为开发者,我们就不得不创建怪物的类,然后初级怪物、中级怪物等都继承自怪物类(当然不同种类的则需要另创建类,但是模式相同)。在每个关卡,我们都要创建怪物的实例,例如初级就创建初级怪物(有很多种类)、中级创建中级怪物等。可以想象在这个系统中,将会有成千上万的怪物实例要创建,问题是还要保证创建的时候不会出错:初级不能创建 BT 级的怪物(玩家就郁闷了,玩家一郁闷,游戏也就挂挂了),反之也不可以。 14 | 15 | #### 模式选择 16 | 17 | AbstractFactory模式就是用来解决这类问题的:要创建一组相关或者相互依赖的对象。 18 | Abstract Factory 模式关键就是将这一组对象的创建封装到一个用于创建对象的类(ConcreteFactory)中,维护这样一个创建类总比维护 n 多相关对象的创建过程要简单的多。 19 | 20 | #### 实现 21 | 22 | ```cpp 23 | // IPhone.h 24 | #ifndef __IPHONE_H__ 25 | #define __IPHONE_H__ 26 | 27 | class IPhone 28 | { 29 | public: 30 | IPhone(){}; 31 | virtual ~IPhone(){}; 32 | virtual void showName() = 0; 33 | }; 34 | 35 | #endif 36 | ``` 37 | 38 | ```cpp 39 | // Phone.h 40 | #ifndef __PHONE_H__ 41 | #define __PHONE_H__ 42 | #include "IPhone.h" 43 | 44 | class CMX1Phone:public IPhone 45 | { 46 | public: 47 | CMX1Phone(); 48 | virtual ~CMX1Phone(); 49 | virtual void showName(); 50 | }; 51 | 52 | class CMX2Phone:public IPhone 53 | { 54 | public: 55 | CMX2Phone(); 56 | virtual ~CMX2Phone(); 57 | virtual void showName(); 58 | }; 59 | 60 | class CMX3Phone:public IPhone 61 | { 62 | public: 63 | CMX3Phone(); 64 | virtual ~CMX3Phone(); 65 | virtual void showName(); 66 | }; 67 | 68 | class CMI1Phone:public IPhone 69 | { 70 | public: 71 | CMI1Phone(); 72 | virtual ~CMI1Phone(); 73 | virtual void showName(); 74 | }; 75 | 76 | class CMI2Phone:public IPhone 77 | { 78 | public: 79 | CMI2Phone(); 80 | virtual ~CMI2Phone(); 81 | virtual void showName(); 82 | }; 83 | 84 | #endif 85 | ``` 86 | 87 | ```cpp 88 | // Phone.cpp 89 | #include "Phone.h" 90 | #include 91 | 92 | CMX1Phone::CMX1Phone() 93 | { 94 | } 95 | 96 | CMX1Phone::~CMX1Phone() 97 | { 98 | } 99 | 100 | void CMX1Phone::showName() 101 | { 102 | std::cout << "I am mx1 of meizu!\n"; 103 | } 104 | 105 | CMX2Phone::CMX2Phone() 106 | { 107 | } 108 | 109 | CMX2Phone::~CMX2Phone() 110 | { 111 | } 112 | 113 | void CMX2Phone::showName() 114 | { 115 | std::cout << "I am mx2 of meizu!\n"; 116 | } 117 | 118 | CMX3Phone::CMX3Phone() 119 | { 120 | } 121 | 122 | CMX3Phone::~CMX3Phone() 123 | { 124 | } 125 | 126 | void CMX3Phone::showName() 127 | { 128 | std::cout << "I am mx3 of meizu!\n"; 129 | } 130 | 131 | CMI1Phone::CMI1Phone() 132 | { 133 | } 134 | 135 | CMI1Phone::~CMI1Phone() 136 | { 137 | } 138 | 139 | void CMI1Phone::showName() 140 | { 141 | std::cout << "I am mi1 of xiaomi!\n"; 142 | } 143 | 144 | CMI2Phone::CMI2Phone() 145 | { 146 | } 147 | 148 | CMI2Phone::~CMI2Phone() 149 | { 150 | } 151 | 152 | void CMI2Phone::showName() 153 | { 154 | std::cout << "I am mi2 of xiaomi!\n"; 155 | } 156 | ``` 157 | 158 | ```cpp 159 | // IBattery.h 160 | #ifndef __IBATTERY_H__ 161 | #define __IBATTERY_H__ 162 | 163 | class IBattery 164 | { 165 | public: 166 | IBattery(){}; 167 | virtual ~IBattery(){}; 168 | virtual void showName() = 0; 169 | }; 170 | 171 | #endif 172 | ``` 173 | 174 | ```cpp 175 | // Battery.h 176 | #ifndef __BATTERY_H__ 177 | #define __BATTERY_H__ 178 | #include "IBattery.h" 179 | 180 | class CMX1Battery:public IBattery 181 | { 182 | public: 183 | CMX1Battery(); 184 | virtual ~CMX1Battery(); 185 | virtual void showName(); 186 | }; 187 | 188 | class CMX2Battery:public IBattery 189 | { 190 | public: 191 | CMX2Battery(); 192 | virtual ~CMX2Battery(); 193 | virtual void showName(); 194 | }; 195 | 196 | class CMX3Battery:public IBattery 197 | { 198 | public: 199 | CMX3Battery(); 200 | virtual ~CMX3Battery(); 201 | virtual void showName(); 202 | }; 203 | 204 | class CMI1Battery:public IBattery 205 | { 206 | public: 207 | CMI1Battery(); 208 | virtual ~CMI1Battery(); 209 | virtual void showName(); 210 | }; 211 | 212 | class CMI2Battery:public IBattery 213 | { 214 | public: 215 | CMI2Battery(); 216 | virtual ~CMI2Battery(); 217 | virtual void showName(); 218 | }; 219 | 220 | #endif 221 | ``` 222 | 223 | ```cpp 224 | // Battery.cpp 225 | #include "Battery.h" 226 | #include 227 | 228 | CMX1Battery::CMX1Battery() 229 | { 230 | } 231 | 232 | CMX1Battery::~CMX1Battery() 233 | { 234 | } 235 | 236 | void CMX1Battery::showName() 237 | { 238 | std::cout << "I am mx1's battery of meizu!\n"; 239 | } 240 | 241 | CMX2Battery::CMX2Battery() 242 | { 243 | } 244 | 245 | CMX2Battery::~CMX2Battery() 246 | { 247 | } 248 | 249 | void CMX2Battery::showName() 250 | { 251 | std::cout << "I am mx2's battery of meizu!\n"; 252 | } 253 | 254 | CMX3Battery::CMX3Battery() 255 | { 256 | } 257 | 258 | CMX3Battery::~CMX3Battery() 259 | { 260 | } 261 | 262 | void CMX3Battery::showName() 263 | { 264 | std::cout << "I am mx3's battery of meizu!\n"; 265 | } 266 | 267 | CMI1Battery::CMI1Battery() 268 | { 269 | } 270 | 271 | CMI1Battery::~CMI1Battery() 272 | { 273 | } 274 | 275 | void CMI1Battery::showName() 276 | { 277 | std::cout << "I am mi1's battery of xiaomi!\n"; 278 | } 279 | 280 | CMI2Battery::CMI2Battery() 281 | { 282 | } 283 | 284 | CMI2Battery::~CMI2Battery() 285 | { 286 | } 287 | 288 | void CMI2Battery::showName() 289 | { 290 | std::cout << "I am mi2's battery of xiaomi!\n"; 291 | } 292 | ``` 293 | 294 | ```cpp 295 | // IFactory.h 296 | #ifndef __IFACTORY_H__ 297 | #define __IFACTORY_H__ 298 | #include "IPhone.h" 299 | #include "IBattery.h" 300 | #include 301 | 302 | class IFactory 303 | { 304 | public: 305 | IFactory(){}; 306 | virtual ~IFactory(){}; 307 | virtual IPhone* createPhone(std::string strName) = 0; 308 | virtual IBattery* createBattery(std::string strName) = 0; 309 | }; 310 | 311 | #endif 312 | ``` 313 | 314 | ```cpp 315 | // BatteryFactory.h 316 | #ifndef __BATTERY_FACTORY_H__ 317 | #define __BATTERY_FACTORY_H__ 318 | #include "IFactory.h" 319 | #include "IPhone.h" 320 | #include "IBattery.h" 321 | 322 | class CMXFactory:public IFactory 323 | { 324 | public: 325 | CMXFactory(); 326 | virtual ~CMXFactory(); 327 | virtual IPhone* createPhone(std::string strName); 328 | virtual IBattery* createBattery(std::string strName); 329 | }; 330 | 331 | class CMIFactory:public IFactory 332 | { 333 | public: 334 | CMIFactory(); 335 | virtual ~CMIFactory(); 336 | virtual IPhone* createPhone(std::string strName); 337 | virtual IBattery* createBattery(std::string strName); 338 | }; 339 | 340 | #endif 341 | ``` 342 | 343 | ```cpp 344 | // BatteryFactory.cpp 345 | #include "Factory.h" 346 | #include "Phone.h" 347 | #include "Battery.h" 348 | 349 | CMXFactory::CMXFactory() 350 | { 351 | } 352 | 353 | CMXFactory::~CMXFactory() 354 | { 355 | } 356 | 357 | IPhone* CMXFactory::createPhone(std::string strName) 358 | { 359 | IPhone* pPhone = NULL; 360 | if (strName == "mx1") 361 | { 362 | pPhone = new CMX1Phone(); 363 | } 364 | else if (strName == "mx2") 365 | { 366 | pPhone = new CMX2Phone(); 367 | } 368 | else if (strName == "mx3") 369 | { 370 | pPhone = new CMX3Phone(); 371 | } 372 | 373 | if (pPhone != NULL) 374 | { 375 | pPhone->showName(); 376 | } 377 | 378 | return pPhone; 379 | } 380 | 381 | IBattery* CMXFactory::createBattery(std::string strName) 382 | { 383 | IBattery* pBattery = NULL; 384 | if (strName == "mx1") 385 | { 386 | pBattery = new CMX1Battery(); 387 | } 388 | else if (strName == "mx2") 389 | { 390 | pBattery = new CMX2Battery(); 391 | } 392 | else if (strName == "mx3") 393 | { 394 | pBattery = new CMX3Battery(); 395 | } 396 | 397 | if (pBattery != NULL) 398 | { 399 | pBattery->showName(); 400 | } 401 | 402 | return pBattery; 403 | } 404 | 405 | CMIFactory::CMIFactory() 406 | { 407 | } 408 | 409 | CMIFactory::~CMIFactory() 410 | { 411 | } 412 | 413 | IPhone* CMIFactory::createPhone(std::string strName) 414 | { 415 | IPhone* pPhone = NULL; 416 | if (strName == "mi1") 417 | { 418 | pPhone = new CMI1Phone(); 419 | } 420 | else if (strName == "mi2") 421 | { 422 | pPhone = new CMI2Phone(); 423 | } 424 | 425 | if (pPhone != NULL) 426 | { 427 | pPhone->showName(); 428 | } 429 | 430 | return pPhone; 431 | } 432 | 433 | IBattery* CMIFactory::createBattery(std::string strName) 434 | { 435 | IBattery* pBattery = NULL; 436 | if (strName == "mi1") 437 | { 438 | pBattery = new CMI1Battery(); 439 | } 440 | else if (strName == "mi2") 441 | { 442 | pBattery = new CMI2Battery(); 443 | } 444 | 445 | if (pBattery != NULL) 446 | { 447 | pBattery->showName(); 448 | } 449 | 450 | return pBattery; 451 | } 452 | ``` 453 | 454 | ```cpp 455 | // main.cpp 456 | #include 457 | #include 458 | using namespace std; 459 | #include "Factory.h" 460 | 461 | int main() 462 | { 463 | std::string strName[2][4] = {"mx1","mx2","mx3","mx4","mi1","mi2","mi3","mi4"}; 464 | IFactory* pFactory[2] = {new CMXFactory(),new CMIFactory()}; 465 | for (int n = 0; n < 2; ++n) 466 | { 467 | for (int i = 0; i < 4; ++i) 468 | { 469 | IPhone* pPhone = pFactory[n]->createPhone(strName[n][i]); 470 | if (pPhone == NULL) 471 | { 472 | std::cout << "not exist phone of " << strName[n][i] << "!\n"; 473 | } 474 | delete pPhone; 475 | 476 | IBattery* pBattery = pFactory[n]->createBattery(strName[n][i]); 477 | if (pBattery == NULL) 478 | { 479 | std::cout << "not exist battery of " << strName[n][i] << "!\n"; 480 | } 481 | delete pBattery; 482 | } 483 | delete pFactory[n]; 484 | pFactory[n] = NULL; 485 | } 486 | return 0; 487 | } 488 | ``` 489 | -------------------------------------------------------------------------------- /_posts/2013-09-30-singleton-pattern.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 设计模式 - 单例模式 4 | tags: [singleton,pattern] 5 | --- 6 | 7 | #### 问题 8 | 9 | 个人认为 Singleton 模式是设计模式中最为简单、最为常见、最容易实现,也是最应该熟悉和掌握的模式。且不说公司企业在招聘的时候为了考察员工对设计的了解和把握,考的最多的就是 Singleton 模式。 10 | 11 | Singleton 模式解决问题十分常见,我们怎样去创建一个唯一的变量(对象?在基于对象的设计中我们可以通过创建一个全局变量(对象)来实现,在面向对象和面向过程结合的设计范式(如 C++中)中,我们也还是可以通过一个全局变量实现这一点。 12 | 13 | 14 | 15 | 但是当我们遇到了纯粹的面向对象范式中,这一点可能就只能是通过 Singleton 模式来实现了,可能这也正是很多公司在招聘 Java 开发人员时候经常考 Singleton 模式的缘故吧。 Singleton 模式在开发中非常有用,我们开发过程中一些变量必须是唯一的,比如说打印机的实例等等。 16 | 17 | #### 模式选择 18 | 19 | 我们通过维护一个 static 的成员变量来记录这个唯一的对象实例。通过提供一个 staitc 的接口instance 来获得这个唯一的实例。Singleton模式经常和Factory(Abstract Factory)模式在一起使用,因为系统中工厂对象一般来说只要一个。 20 | 21 | #### 实现 22 | 23 | ```cpp 24 | //Singleton.h 25 | #ifndef __SINGLETON_H__ 26 | #define __SINGLETON_H__ 27 | 28 | class CSingleton 29 | { 30 | public: 31 | static CSingleton* Instance(); 32 | protected: 33 | CSingleton(); 34 | private: 35 | static CSingleton* _instance; 36 | }; 37 | 38 | #endif 39 | ``` 40 | 41 | ```cpp 42 | //Singleton.cpp 43 | #include "Singleton.h" 44 | #include 45 | 46 | CSingleton* CSingleton::_instance = NULL; 47 | CSingleton::CSingleton() 48 | { 49 | std::cout << "Singleton....\n"; 50 | } 51 | CSingleton* CSingleton::Instance() 52 | { 53 | if (_instance == NULL) 54 | { 55 | _instance = new CSingleton(); 56 | } 57 | return _instance; 58 | } 59 | ``` 60 | 61 | ```cpp 62 | //main.cpp 63 | #include "Singleton.h" 64 | 65 | int main() 66 | { 67 | CSingleton* pSingleton = CSingleton::Instance(); 68 | return 0; 69 | } 70 | ``` 71 | 72 | #### 总结 73 | 74 | Singleton模式看起来简单,其实上面的单例也是有问题的,比如非线程安全,这里有一篇文章讨论了Singleton模式的几种写法,有兴趣可以看看。 75 | 76 | [单例模式(Singleton)的6种实现][1] 77 | [.NET设计模式(2):单件模式(Singleton Pattern)][2] 78 | 79 | [1]: http://www.cnblogs.com/rush/archive/2011/10/30/2229565.html 80 | [2]: http://terrylee.cnblogs.com/archive/2005/12/09/293509.html 81 | -------------------------------------------------------------------------------- /_posts/2013-12-25-mongoose.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 小型web服务器Mongoose试用 4 | tags: [Mongoose,c++] 5 | --- 6 | 7 | #### 缘由 8 | 9 | 早先PC端有几个服务器由于需求牵扯到了一些HTTP请求,当时使用了Mongoose,当时没怎么接触,前段时间客户端做加速器又准备使用个小型web server,选定的也是这个,处于兴趣,前N个星期六抽了半天看了下相关文档,记录下(我承认我TM懒)。 10 | 11 | 12 | 13 | #### 简介 14 | 15 | Mongoose是一个非常小巧的web服务器,支持C/C++、C#、Python、Ruby、Lua语言。它实现了对Socket的封装,提供了简洁的开发接口,性能也很好,主要用在嵌入式开发平台,主页是 16 | 17 | Mongoose可以编译成so,或者直接上源文件(就两个文件,适合携带),主要有以下特性: 18 | 19 | 1. 可以运行在Windows,Mac,Unix/Linux,iPhone, Android和其他平台 20 | 2. 脚本支持Lua,数据库支持SQLite,扩展性不错(PHP也能用) 21 | 3. 支持CGI,SSL,SSI,Digest(MD5)认证,Websocket,WebDAV 22 | 4. 支持断点续传,URL rewrite,文件黑名单,基于IP的ACL 23 | 5. 干净简单的API,只有mongoose.h和mongoose.c 24 | 6. 大量的实例 25 | 26 | #### 实例 27 | 28 | 在监听1125端口,如果请求的是`hello.html`就返回这个网页,其他情况返回请求的目录,代码如下: 29 | 30 | ```cpp 31 | #include 32 | #include 33 | using namespace std; 34 | #include "mongoose.h" 35 | 36 | static int event_handle(struct mg_event* event) 37 | { 38 | if (event->type == MG_REQUEST_BEGIN) 39 | { 40 | if (strcmp(event->request_info->uri,"/hello.html") != 0) 41 | { 42 | char content[100]; 43 | 44 | // Prepare the message we're going to send 45 | int content_length = snprintf(content, sizeof(content), 46 | "Hello from mongoose! Requested: [%s] [%s]", 47 | event->request_info->request_method, event->request_info->uri); 48 | 49 | // Send HTTP reply to the client 50 | mg_printf(event->conn, 51 | "HTTP/1.1 200 OK\r\n" 52 | "Content-Type: text/plain\r\n" 53 | "Content-Length: %d\r\n" // Always set Content-Length 54 | "\r\n" 55 | "%s", 56 | content_length, content); 57 | 58 | // Returning non-zero tells mongoose that our function has replied to 59 | return 1; 60 | } 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | int main() 67 | { 68 | const char* options[] = { 69 | "listening_ports", "1125", 70 | "document_root", "wwwroot", 71 | NULL}; 72 | struct mg_context* ctx = mg_start(options,&event_handle,NULL); 73 | if (ctx == NULL) 74 | { 75 | cout << "start failed\n"; 76 | } 77 | else 78 | { 79 | cout << "start success\n"; 80 | } 81 | 82 | getchar(); 83 | 84 | mg_stop(ctx); 85 | return 0; 86 | } 87 | ``` 88 | 89 | #### 总结 90 | 91 | 总体来说Mongoose很让人惊喜,小巧强大,使用简便,还支持URL rewrite和正则表达式,并且可以通过Lua来扩展。下载的源码中有大部分的使用示例,官方文档也很齐全。 92 | 93 | 下载: 94 | 文档: 95 | -------------------------------------------------------------------------------- /_posts/2013-12-28-argparse.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Argparse简易教程 4 | tags: [python,argparse] 5 | --- 6 | 7 | 原文:[Argparse Tutorial][1] 8 | 9 | 本教程是对于Python标准库中推荐使用的命令行解析模块[argparse][1]的简单介绍。 10 | 11 | > PS:还有其他两个模块实现这一功能,[getopt][2](等同于C语言中的getopt())和弃用的[optparse][3]。因为argparse是基于optparse,所以用法很类似。 12 | 13 | 14 | 15 | #### 概念 16 | 17 | 让我们先用`ls`来展示这篇教程将要介绍的相关特性: 18 | 19 | ```sh 20 | $ ls 21 | cpython devguide prog.py pypy rm-unused-function.patch 22 | $ ls pypy 23 | ctypes_configure demo dotviewer include lib_pypy lib-python ... 24 | $ ls -l 25 | total 20 26 | drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython 27 | drwxr-xr-x 4 wena wena 4096 Feb 8 12:04 devguide 28 | -rwxr-xr-x 1 wena wena 535 Feb 19 00:05 prog.py 29 | drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy 30 | -rw-r--r-- 1 wena wena 741 Feb 18 01:01 rm-unused-function.patch 31 | $ ls --help 32 | Usage: ls [OPTION]... [FILE]... 33 | List information about the FILEs (the current directory by default). 34 | Sort entries alphabetically if none of -cftuvSUX nor --sort is specified. 35 | ... 36 | ``` 37 | 38 | 从上面的四个命令,我们可以了解一些概念: 39 | 40 | - `ls`命令在没有参数的情况下也是可以使用的。默认显示当前目录的内容。 41 | - 如果想让它展示不同,需要给它更多的参数。这个例子中,我们想让它显示目录`pypy`,需要指定必要的参数。因为程序需要基于这些参数确定做些什么。这个概念类似`cp`, 比如最常见的`cp SRC DST`。第一个参数表示你要复制什么,第二个参数表示复制到哪里去。 42 | - 现在,我想要改变程序的行为。在示例中,我们让它显示更多的信息,不仅仅是文件名,这里的`-l`就是一个可选参数。 43 | - 最后是一个帮助文档的片段。这些帮助对于没有使用过这个程序的人很有帮助,他们可以通过简单的阅读,就可以了解程序的用法。 44 | 45 | #### 基础 46 | 47 | 让我们从一个简单的例子开始,它(几乎)什么都不做: 48 | 49 | ```python 50 | import argparse 51 | parser = argparse.ArgumentParser() 52 | parser.parse_args() 53 | ``` 54 | 55 | 运行: 56 | 57 | ```sh 58 | $ python prog.py 59 | $ python prog.py --help 60 | usage: prog.py [-h] 61 | 62 | optional arguments: 63 | -h, --help show this help message and exit 64 | $ python prog.py --verbose 65 | usage: prog.py [-h] 66 | prog.py: error: unrecognized arguments: --verbose 67 | $ python prog.py foo 68 | usage: prog.py [-h] 69 | prog.py: error: unrecognized arguments: foo 70 | ``` 71 | 72 | 结果分析: 73 | 74 | - 不加任何参数运行,什么也不显示,没有什么用。 75 | - 第二条展示了`argparse`模块的好处,几乎什么都不做,却得到了一个很有用的帮助信息。 76 | - `--help`参数可简写成`-h`,是唯一预设的(不需要指定)。 77 | 78 | #### 定位参数 79 | 80 | 例子: 81 | 82 | ```python 83 | import argparse 84 | parser = argparse.ArgumentParser() 85 | parser.add_argument("echo") 86 | args = parser.parse_args() 87 | print args.echo 88 | ``` 89 | 90 | 运行: 91 | 92 | ```sh 93 | $ python prog.py 94 | usage: prog.py [-h] echo 95 | prog.py: error: the following arguments are required: echo 96 | $ python prog.py --help 97 | usage: prog.py [-h] echo 98 | 99 | positional arguments: 100 | echo 101 | 102 | optional arguments: 103 | -h, --help show this help message and exit 104 | $ python prog.py foo 105 | foo 106 | ``` 107 | 108 | 结果分析: 109 | 110 | - 我们用到了方法`add_argument()`,用来指定程序需要接受的命令参数,本例中的`echo`。 111 | - 现在运行程序必须指定一个参数。 112 | - 方法`parse_args()`通过分析指定的参数返回一些数据,如本例中的`echo`。 113 | - 像魔法一样,`argparse`自动生成这些变量,你可能已经注意到变量`echo`和我们指定的参数相同。 114 | 115 | 虽然现在帮助信息已经很美观了,但是还不够好。例如我们知道`echo`是个定位参数,但是却不知道该参数的意思,只能通过猜或者读源码。下面,我们可以让它更有帮助: 116 | 117 | ```python 118 | import argparse 119 | parser = argparse.ArgumentParser() 120 | parser.add_argument("echo", help="echo the string you use here") 121 | args = parser.parse_args() 122 | print args.echo 123 | ``` 124 | 125 | 运行: 126 | 127 | ```sh 128 | $ python prog.py -h 129 | usage: prog.py [-h] echo 130 | 131 | positional arguments: 132 | echo echo the string you use here 133 | 134 | optional arguments: 135 | -h, --help show this help message and exit 136 | ``` 137 | 138 | 再修改下: 139 | 140 | ```python 141 | import argparse 142 | parser = argparse.ArgumentParser() 143 | parser.add_argument("square", help="display a square of a given number") 144 | args = parser.parse_args() 145 | print args.square**2 146 | ``` 147 | 148 | 运行如下: 149 | 150 | ```sh 151 | $ python prog.py 4 152 | Traceback (most recent call last): 153 | File "prog.py", line 5, in 154 | print args.square**2 155 | TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int' 156 | ``` 157 | 158 | 运行有点问题,因为如果不指定参数类型,`argparse`默认它是字符串。因此我们需要告诉`argparse`该参数是整型。 159 | 160 | ```python 161 | import argparse 162 | parser = argparse.ArgumentParser() 163 | parser.add_argument("square", help="display a square of a given number", 164 | type=int) 165 | args = parser.parse_args() 166 | print args.square**2 167 | ``` 168 | 169 | 运行: 170 | 171 | ```sh 172 | $ python prog.py 4 173 | 16 174 | $ python prog.py four 175 | usage: prog.py [-h] square 176 | prog.py: error: argument square: invalid int value: 'four' 177 | ``` 178 | 179 | 可以运行了,程序能够在执行前过滤一些错误的参数输入。 180 | 181 | #### 可选参数 182 | 183 | 以上,展示了定位参数的用法。下面让我们来看看如何添加可选参数: 184 | 185 | ```python 186 | import argparse 187 | parser = argparse.ArgumentParser() 188 | parser.add_argument("--verbosity", help="increase output verbosity") 189 | args = parser.parse_args() 190 | if args.verbosity: 191 | print "verbosity turned on" 192 | ``` 193 | 194 | 输出: 195 | 196 | ```sh 197 | $ python prog.py --verbosity 1 198 | verbosity turned on 199 | $ python prog.py 200 | $ python prog.py --help 201 | usage: prog.py [-h] [--verbosity VERBOSITY] 202 | 203 | optional arguments: 204 | -h, --help show this help message and exit 205 | --verbosity VERBOSITY 206 | increase output verbosity 207 | $ python prog.py --verbosity 208 | usage: prog.py [-h] [--verbosity VERBOSITY] 209 | prog.py: error: argument --verbosity: expected one argument 210 | ``` 211 | 212 | 结果分析: 213 | 214 | - 当指定`--verbosity`时程序就显示一些东西,没指定的时候就不显示。 215 | - 这个参数事实上是可选的,不指定它也不会出错。如果不指定可选的参数,对应的变量就被设置为None,比如本例中的`args.verbosity`, 这就是为什么示例中的 [if][4] 没有执行的原因。 216 | - 帮助信息发生了点变化 217 | - 当我们使用可选参数`--verbosity`时,也必须指定一些值。 218 | 219 | 上面的示例中可选参数`--verbosity`后面接受任意的整型值,但是对于简单的程序,实际上只需要两种值,`True`或者`False`。因此可以修改上面的代码: 220 | 221 | ```python 222 | import argparse 223 | parser = argparse.ArgumentParser() 224 | parser.add_argument("--verbose", help="increase output verbosity", 225 | action="store_true") 226 | args = parser.parse_args() 227 | if args.verbose: 228 | print "verbosity turned on" 229 | ``` 230 | 231 | 运行: 232 | 233 | ```sh 234 | $ python prog.py --verbose 235 | verbosity turned on 236 | $ python prog.py --verbose 1 237 | usage: prog.py [-h] [--verbose] 238 | prog.py: error: unrecognized arguments: 1 239 | $ python prog.py --help 240 | usage: prog.py [-h] [--verbose] 241 | 242 | optional arguments: 243 | -h, --help show this help message and exit 244 | --verbose increase output verbosity 245 | ``` 246 | 247 | 结果分析: 248 | 249 | - 现在多加一个标志来替代必须给出一些值,并修改了名称来表达我们的意思。注意现在指定了一个新的关键词`action`,并且赋值为`store_ture`。如果指定了这个可选参数,`args.verbose`就赋值为`True`,否则就为`False`。 250 | - 多指定了值,它就会发出错误提示。 251 | - 注意帮助文档有什么不同 252 | 253 | #### 简写 254 | 255 | 如果你很熟悉命令行,你可能已经注意到我在上面已经提到了参数的简写,非常的简单: 256 | 257 | ```python 258 | import argparse 259 | parser = argparse.ArgumentParser() 260 | parser.add_argument("-v", "--verbose", help="increase output verbosity", 261 | action="store_true") 262 | args = parser.parse_args() 263 | if args.verbose: 264 | print "verbosity turned on" 265 | ``` 266 | 267 | 运行如下: 268 | 269 | ```sh 270 | $ python prog.py -v 271 | verbosity turned on 272 | $ python prog.py --help 273 | usage: prog.py [-h] [-v] 274 | 275 | optional arguments: 276 | -h, --help show this help message and exit 277 | -v, --verbose increase output verbosity 278 | ``` 279 | 280 | 注意帮助信息也有相应的变化。 281 | 282 | #### 混合使用定位参数和可选参数 283 | 284 | 再复杂一点: 285 | 286 | ```python 287 | import argparse 288 | parser = argparse.ArgumentParser() 289 | parser.add_argument("square", type=int, 290 | help="display a square of a given number") 291 | parser.add_argument("-v", "--verbose", action="store_true", 292 | help="increase output verbosity") 293 | args = parser.parse_args() 294 | answer = args.square**2 295 | if args.verbose: 296 | print "the square of {} equals {}".format(args.square, answer) 297 | else: 298 | print answer 299 | ``` 300 | 301 | 运行: 302 | 303 | ```sh 304 | $ python prog.py 305 | usage: prog.py [-h] [-v] square 306 | prog.py: error: the following arguments are required: square 307 | $ python prog.py 4 308 | 16 309 | $ python prog.py 4 --verbose 310 | the square of 4 equals 16 311 | $ python prog.py --verbose 4 312 | the square of 4 equals 16 313 | ``` 314 | 315 | - 为了让程序复杂点,我们重新加上了定位参数。 316 | - 注意到参数的顺序是没有影响的。 317 | 318 | 来看看为程序加上处理重复参数的能力会怎么样: 319 | 320 | ```python 321 | import argparse 322 | parser = argparse.ArgumentParser() 323 | parser.add_argument("square", type=int, 324 | help="display a square of a given number") 325 | parser.add_argument("-v", "--verbosity", type=int, 326 | help="increase output verbosity") 327 | args = parser.parse_args() 328 | answer = args.square**2 329 | if args.verbosity == 2: 330 | print "the square of {} equals {}".format(args.square, answer) 331 | elif args.verbosity == 1: 332 | print "{}^2 == {}".format(args.square, answer) 333 | else: 334 | print answer 335 | ``` 336 | 337 | 运行: 338 | 339 | ```sh 340 | $ python prog.py 4 341 | 16 342 | $ python prog.py 4 -v 343 | usage: prog.py [-h] [-v VERBOSITY] square 344 | prog.py: error: argument -v/--verbosity: expected one argument 345 | $ python prog.py 4 -v 1 346 | 4^2 == 16 347 | $ python prog.py 4 -v 2 348 | the square of 4 equals 16 349 | $ python prog.py 4 -v 3 350 | 16 351 | ``` 352 | 353 | 除了最后一个暴露了一个bug,其他的看起都来运行良好。让我们通过限制`--verbosity`后面跟的值来修正: 354 | 355 | ```python 356 | import argparse 357 | parser = argparse.ArgumentParser() 358 | parser.add_argument("square", type=int, 359 | help="display a square of a given number") 360 | parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2], 361 | help="increase output verbosity") 362 | args = parser.parse_args() 363 | answer = args.square**2 364 | if args.verbosity == 2: 365 | print "the square of {} equals {}".format(args.square, answer) 366 | elif args.verbosity == 1: 367 | print "{}^2 == {}".format(args.square, answer) 368 | else: 369 | print answer 370 | ``` 371 | 372 | 运行: 373 | 374 | ```sh 375 | $ python prog.py 4 -v 3 376 | usage: prog.py [-h] [-v {0,1,2}] square 377 | prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, 1, 2) 378 | $ python prog.py 4 -h 379 | usage: prog.py [-h] [-v {0,1,2}] square 380 | 381 | positional arguments: 382 | square display a square of a given number 383 | 384 | optional arguments: 385 | -h, --help show this help message and exit 386 | -v {0,1,2}, --verbosity {0,1,2} 387 | increase output verbosity 388 | ``` 389 | 390 | 注意帮助信息和错误信息都发生了变化。 391 | 392 | 现在让我们用一种更常用的方法来处理,类似`CPython`处理自己的参数(参考`python --help`): 393 | 394 | ```python 395 | import argparse 396 | parser = argparse.ArgumentParser() 397 | parser.add_argument("square", type=int, 398 | help="display the square of a given number") 399 | parser.add_argument("-v", "--verbosity", action="count", 400 | help="increase output verbosity") 401 | args = parser.parse_args() 402 | answer = args.square**2 403 | if args.verbosity == 2: 404 | print "the square of {} equals {}".format(args.square, answer) 405 | elif args.verbosity == 1: 406 | print "{}^2 == {}".format(args.square, answer) 407 | else: 408 | print answer 409 | ``` 410 | 411 | 我们引入了另一个关键词`count`来统计可选参数出现的次数: 412 | 413 | ```sh 414 | $ python prog.py 4 415 | 16 416 | $ python prog.py 4 -v 417 | 4^2 == 16 418 | $ python prog.py 4 -vv 419 | the square of 4 equals 16 420 | $ python prog.py 4 --verbosity --verbosity 421 | the square of 4 equals 16 422 | $ python prog.py 4 -v 1 423 | usage: prog.py [-h] [-v] square 424 | prog.py: error: unrecognized arguments: 1 425 | $ python prog.py 4 -h 426 | usage: prog.py [-h] [-v] square 427 | 428 | positional arguments: 429 | square display a square of a given number 430 | 431 | optional arguments: 432 | -h, --help show this help message and exit 433 | -v, --verbosity increase output verbosity 434 | $ python prog.py 4 -vvv 435 | 16 436 | ``` 437 | 438 | - 和前面的版本相比这里多了一个关键词(类似`action="store_true"`)。 439 | - 行为上也类似`store_true`。 440 | - `count`关键词的示范,大家可能在其他地方已经看过了。 441 | - 就像`store_ture`,如果不指定`-v`,响应变量就会被设置为`None`。 442 | - 指定完整的名称和简写效果是一样的。 443 | - 但是不爽的是,帮助信息并没有做出有用的提示,不过可以通过修改`help`来改善这个问题。 444 | - 最后那个输出又暴露了程序的bug 445 | 446 | 修改一下: 447 | 448 | ```python 449 | import argparse 450 | parser = argparse.ArgumentParser() 451 | parser.add_argument("square", type=int, 452 | help="display a square of a given number") 453 | parser.add_argument("-v", "--verbosity", action="count", 454 | help="increase output verbosity") 455 | args = parser.parse_args() 456 | answer = args.square**2 457 | 458 | # bugfix: replace == with >= 459 | if args.verbosity >= 2: 460 | print "the square of {} equals {}".format(args.square, answer) 461 | elif args.verbosity >= 1: 462 | print "{}^2 == {}".format(args.square, answer) 463 | else: 464 | print answer 465 | ``` 466 | 467 | 运行如下: 468 | 469 | ```sh 470 | $ python prog.py 4 -vvv 471 | the square of 4 equals 16 472 | $ python prog.py 4 -vvvv 473 | the square of 4 equals 16 474 | $ python prog.py 4 475 | Traceback (most recent call last): 476 | File "prog.py", line 11, in 477 | if args.verbosity >= 2: 478 | TypeError: unorderable types: NoneType() >= int() 479 | ``` 480 | 481 | - 第一个输出是正确的,修正了上个版本的问题,参数出现次数>=2时都能显示详细的信息。 482 | - 第三个输出还是有问题 483 | 484 | 再来修改下: 485 | 486 | ```python 487 | import argparse 488 | parser = argparse.ArgumentParser() 489 | parser.add_argument("square", type=int, 490 | help="display a square of a given number") 491 | parser.add_argument("-v", "--verbosity", action="count", default=0, 492 | help="increase output verbosity") 493 | args = parser.parse_args() 494 | answer = args.square**2 495 | if args.verbosity >= 2: 496 | print "the square of {} equals {}".format(args.square, answer) 497 | elif args.verbosity >= 1: 498 | print "{}^2 == {}".format(args.square, answer) 499 | else: 500 | print answer 501 | ``` 502 | 503 | 我们又加入了一个关键词`default`。设置它的默认值为0,这样可以让它兼容其他整型。注意,如果一个可选参数没有指定,它就会被设置成`None`,`None`是不能和整型比较的(触发`[TypeError][5]异常`)。 504 | 505 | 运行结果: 506 | 507 | ```sh 508 | $ python prog.py 4 509 | 16 510 | ``` 511 | 512 | 你可以使用我们所学来做很多事情,但是这仅仅是皮毛而已。`argparse`模块非常强大,下面来看看更多的用法。 513 | 514 | #### 高级用法 515 | 516 | 如果我们想扩展程序的功能,而不仅仅是求平方: 517 | 518 | ```python 519 | import argparse 520 | parser = argparse.ArgumentParser() 521 | parser.add_argument("x", type=int, help="the base") 522 | parser.add_argument("y", type=int, help="the exponent") 523 | parser.add_argument("-v", "--verbosity", action="count", default=0) 524 | args = parser.parse_args() 525 | answer = args.x**args.y 526 | if args.verbosity >= 2: 527 | print "{} to the power {} equals {}".format(args.x, args.y, answer) 528 | elif args.verbosity >= 1: 529 | print "{}^{} == {}".format(args.x, args.y, answer) 530 | else: 531 | print answer 532 | ``` 533 | 534 | 输出: 535 | 536 | ```sh 537 | $ python prog.py 538 | usage: prog.py [-h] [-v] x y 539 | prog.py: error: the following arguments are required: x, y 540 | $ python prog.py -h 541 | usage: prog.py [-h] [-v] x y 542 | 543 | positional arguments: 544 | x the base 545 | y the exponent 546 | 547 | optional arguments: 548 | -h, --help show this help message and exit 549 | -v, --verbosity 550 | $ python prog.py 4 2 -v 551 | 4^2 == 16 552 | ``` 553 | 554 | 截止到目前,我们都在利用详细的级别来*改变*输出,下面的示例演示了利用详细的级别来显示*更多*输出: 555 | 556 | ```python 557 | import argparse 558 | parser = argparse.ArgumentParser() 559 | parser.add_argument("x", type=int, help="the base") 560 | parser.add_argument("y", type=int, help="the exponent") 561 | parser.add_argument("-v", "--verbosity", action="count", default=0) 562 | args = parser.parse_args() 563 | answer = args.x**args.y 564 | if args.verbosity >= 2: 565 | print "Running '{}'".format(__file__) 566 | if args.verbosity >= 1: 567 | print "{}^{} ==".format(args.x, args.y), 568 | print answer 569 | ``` 570 | 571 | 输出: 572 | 573 | ```sh 574 | $ python prog.py 4 2 575 | 16 576 | $ python prog.py 4 2 -v 577 | 4^2 == 16 578 | $ python prog.py 4 2 -vv 579 | Running 'prog.py' 580 | 4^2 == 16 581 | ``` 582 | 583 | #### 参数冲突 584 | 585 | 迄今为止,我们已经使用到了`[argparse.ArgumentParser][6]`的两个方法,来看看他的另一个方法`add_mutually_exclusive_group()`。它可以让我们指定某个参数和其他参数冲突。下面来修改下程序以对这个新方法有更多的了解:我们将加入参数`--quiet`,它和参数`--verbose`冲突,不能同时指定: 586 | 587 | ```python 588 | import argparse 589 | 590 | parser = argparse.ArgumentParser() 591 | group = parser.add_mutually_exclusive_group() 592 | group.add_argument("-v", "--verbose", action="store_true") 593 | group.add_argument("-q", "--quiet", action="store_true") 594 | parser.add_argument("x", type=int, help="the base") 595 | parser.add_argument("y", type=int, help="the exponent") 596 | args = parser.parse_args() 597 | answer = args.x**args.y 598 | 599 | if args.quiet: 600 | print answer 601 | elif args.verbose: 602 | print "{} to the power {} equals {}".format(args.x, args.y, answer) 603 | else: 604 | print "{}^{} == {}".format(args.x, args.y, answer) 605 | ``` 606 | 607 | 程序很简单,为了演示冲突,去掉了其他功能特性展示,运行结果: 608 | 609 | ```sh 610 | $ python prog.py 4 2 611 | 4^2 == 16 612 | $ python prog.py 4 2 -q 613 | 16 614 | $ python prog.py 4 2 -v 615 | 4 to the power 2 equals 16 616 | $ python prog.py 4 2 -vq 617 | usage: prog.py [-h] [-v | -q] x y 618 | prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose 619 | $ python prog.py 4 2 -v --quiet 620 | usage: prog.py [-h] [-v | -q] x y 621 | prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose 622 | ``` 623 | 624 | 很好理解,我们添加最后那个输出是为了展示灵活性,比如,指定参数时可以同时混用参数全称和简写。 625 | 626 | 通过前面的学习,为了以防万一,你可能想通过帮助信息来告诉用户如何使用你的程序: 627 | 628 | ```python 629 | import argparse 630 | 631 | parser = argparse.ArgumentParser(description="calculate X to the power of Y") 632 | group = parser.add_mutually_exclusive_group() 633 | group.add_argument("-v", "--verbose", action="store_true") 634 | group.add_argument("-q", "--quiet", action="store_true") 635 | parser.add_argument("x", type=int, help="the base") 636 | parser.add_argument("y", type=int, help="the exponent") 637 | args = parser.parse_args() 638 | answer = args.x**args.y 639 | 640 | if args.quiet: 641 | print answer 642 | elif args.verbose: 643 | print "{} to the power {} equals {}".format(args.x, args.y, answer) 644 | else: 645 | print "{}^{} == {}".format(args.x, args.y, answer) 646 | ``` 647 | 648 | 注意下面的帮助信息,`[-v | -q]`表明了可以使用`-v`或者`-q`,但是不能同时使用。 649 | 650 | ```sh 651 | $ python prog.py --help 652 | usage: prog.py [-h] [-v | -q] x y 653 | 654 | calculate X to the power of Y 655 | 656 | positional arguments: 657 | x the base 658 | y the exponent 659 | 660 | optional arguments: 661 | -h, --help show this help message and exit 662 | -v, --verbose 663 | -q, --quiet 664 | ``` 665 | 666 | #### 总结 667 | 668 | `argparse`模块提供了比我们展示的多得多的功能。它的文档更加详尽和深入,并且配了大量的示例。自己去深入阅读下,文档很容易理解。 669 | 670 | 原文地址:[Argparse Tutorial][7] 671 | 官方文档:[argparse][8] 672 | 另外一篇:[argparse - 命令行选项与参数解析(译)][9] 673 | 674 | PS:第一次翻译文档,感觉到英语真的太差了~~o(>_<)o ~~ 675 | 676 | 677 | [1]: http://docs.python.org/2/library/argparse.html#module-argparse 678 | [2]: http://docs.python.org/2/library/getopt.html#module-getopt 679 | [3]: http://docs.python.org/2/library/optparse.html#module-optparse 680 | [4]: http://docs.python.org/2/reference/compound_stmts.html#if 681 | [5]: http://docs.python.org/2/library/exceptions.html#exceptions.TypeError 682 | [6]: http://docs.python.org/2/library/argparse.html#argparse.ArgumentParser 683 | [7]: http://docs.python.org/2/howto/argparse.html 684 | [8]: http://docs.python.org/2/library/argparse.html 685 | [9]: http://youngsterxyf.github.io/2013/03/30/argparse/ 686 | -------------------------------------------------------------------------------- /_posts/2013-12-31-the-2013.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 2013年总结 4 | tags: [2013] 5 | --- 6 | 7 | > 停留的是记忆,不停留的是年华似水 8 | 9 | 从大学开始,时间像磕了药般越跑越快,来不及回首,13年也悄然远去... 10 | 11 | 这一年好像什么都没变,又好像什么都变了; 好像得到很多,又好像什么都不曾拥有。 12 | 13 | 14 | 15 | #### 关于家人 16 | 17 | `孝而不顺`始终是我自知的缺点,每每看到父母渐渐苍老的面容和丝丝泛白的发梢,都会感到深深的愧疚。不是不明白你们的期盼(在你们身边工作,给你们个儿媳妇), 只是现在还做不到. 18 | 19 | 这个年龄,不应该在你们的呵护下,况且好多事情并不想让你们知道,人总要学会长大,当某天觉得自己长大的时候,我肯定就回去了. 20 | 21 | 想起这件事情的时候,也许我在听着[彼岸 - 汪峰][1] 22 | 23 | #### 关于朋友 24 | 25 | > 偶尔想起,觉得温暖便是朋友 26 | 27 | 朋友始终是个温暖的词。我一向不是个善于社交的人,主动联系也几乎不会发生在我的身上,幸运的是世上有朋友这种东西,时间和距离不会冷淡朋友的关系。 28 | 29 | 有些人,今年甚至几年都没怎么联系,甚至以后都不会见面,但如果有幸见面,我们依然可以不说话也不会感到尴尬。 30 | 31 | 耳机中响起[最佳损友 - 陈奕迅][2],或许是我在想起你... 32 | 33 | #### 关于爱情 34 | 35 | > 爱情是什么?我不知道,我只知道什么不是 36 | 37 | 爱情依旧是遥不可及。一个人这么多年,所有的事情都习惯了,更加难以接受另一个人的出现。和身边好多人一样,满心期待着恋人的出现,但是如果出现了会怎样呢?会不会退却逃走呢?不知道,爱情的不确定性也许恰恰是它最美好的。 38 | 39 | 人真是一个奇怪的东西,`患得患失`。没有足够的能力,没有强大的内心,害怕失去也同样害怕得到。所谓的安全感其实只是内心的平静。 40 | 41 | 得不到的永远在骚动,被偏爱的都有恃无恐。爱情这东西可遇不可求,不知道什么时候会出现,或许永远都不会遇到,我们能做的只是让自己变得更好。 42 | 43 | #### 关于工作 44 | 45 | 平平淡淡,没有什么起色。 46 | 47 | 年初完成斗地主开发后,一直处以闲人状态,修修补补没有任何新意,期间的断断续续的做了些斗地主机器人和比赛的工作,部门转型,最后搁置。在这期间是非常迷茫的,人总是害怕闲下来,因为一闲下来就要思考,而思考本事是痛苦的。 48 | 49 | 现在回想起来,正如[@璇爷][3]所说,迷茫痛苦的时刻也许是收获最多的时候。那段时间,看了不少书,虽然技术上没多少提升,也学习了不东西。 50 | 51 | 最后这两个多月,做联网版象棋,目前基本上算完工了,期间也接触了一些新的东西protobuf,memcache,python,gdb等。 52 | 53 | #### 关于生活 54 | 55 | 青春有太多的话语无处安放,累的时候不想说话,生活照旧一塌糊涂,除了吃饭睡觉洗衣服,基本上所有时间都花费在工作上。其实这种状态并不好,每天都很疲劳,间歇性神经只是为了每天亢奋的状态。 56 | 57 | 这种状态在工作迷茫或者闲暇的时候,就会突然感觉到没什么都是可以守护,所以除了工作应该还有其他可以守护的东西。 58 | 59 | #### 关于青春 60 | 61 | 有人说青春理应奋斗,有人说青春本该旅行;有人叹少壮不努力,有人诲年少未远游。`这是最好的时刻`,我们年轻,可以随意挥霍时间和身体;`这是最坏的时刻`,我们稚嫩,迷茫颓废四处碰壁。 62 | 63 | 曾经你喜欢的,也对你回头一笑的女生,如今却在别人的床上呻吟;今天你职场风光无限,明天或许就卷铺盖走人;此刻身体还是金刚不坏,下一刻或许就会自挂东南枝。青春最残酷也最迷人的地方或许就是它的不确定性,我们永远不知道下一秒会发生什么。 64 | 65 | 顺着年龄的增大,越来越不喜欢话及自己,更不愿谈论未来。现实的残酷,自身的渺小,年少轻狂以为可以改变世界,最后受挫企图拯救自己,如今却发现根本就没人会在意,那些曾经的豪言壮语再也不会随意说出,那些自以为顺其自然的事或许永远不会发生。 66 | 67 | 青春如同不能后退的路口,我们能做的只有选择一条路,然后走下去,也许路上荆棘遍布,但是也无需后悔,因为我们不知道走另一条会遇到什么。 68 | 69 | #### 关于健康 70 | 71 | 貌似长高了,体检发现肾结石,脚崴了两次,没啥大事。 72 | 73 | #### 关于游玩 74 | 75 | 3月份部门组织去了凤凰岭,途中听闻,星座是按阳历算的-_-!。 76 | 77 | 端午节众基友去了北戴河,第一次去海边,泡泡脚,意外的收获是坏了2个多月的脚好了。 78 | 79 | 7月份部门组织去了长岛,拍了好多照片,不过竟然全是鹅卵石,在上面踢球脚真疼,第一次下海狗刨,好累,除了恐怖的苍蝇,长岛的风景不错,看了日出,话说3天的海鲜有挑战性。 80 | 81 | 8月底基友,老表和同事四人去了居庸关,拍到了帝都最蓝的天。 82 | 83 | #### 关于读书 84 | 85 | 今年最大的收获可能就是一时兴起买了个kindle,读了一些书。其中有几本(非技术)记忆比较深刻: 86 | 87 | 1. [看见][4]:不要因为走得太远,忘了我们为什么出发 88 | 2. [大数据时代][5]:量变引起质变 89 | 3. [黑客与画家][6]:为什么贫富差距不是一件坏事 90 | 91 | #### 关于三观 92 | 93 | > 一入豆瓣(知乎)深似海,从此节操为路人 94 | 95 | 三观总是要毁掉重建的。这一年确实改变了一些看法: 96 | 97 | - 机会其实并没那么重要,选择大于努力 98 | - 心慢下来,行动才能快起来 99 | - 你想获得你不曾拥有的,那么你必须去做 100 | - 秋香最后一句话让唐伯虎回到了起点 101 | - 大话西游那句“他好像一条狗耶”才是点睛之语 102 | - 任何事情不是非黑即白的 103 | ... 104 | 105 | #### 关于北京 106 | 107 | 有人说北京和巴黎一样脏乱差,但是却离不开。有人说北京是一个可以穷,可以普通活着的城市。也许它会葬送我们的青春,但人这一辈子,总得来一次。 108 | 109 | #### 关于2014 110 | 111 | 明年本命年,要穿红内裤^_^, 计划不再和基友们住了,这个年龄留点时间享受独处,该注重些生活质量,学习一些生活上的基本技能。工作上主要精力放在linux上面,多接触和尝试新的东西,搞清楚服务器框架的底层。坚持锻炼身体,打球跑步。 112 | 113 | > 继续走,继续失去,在我还来不及意识到的青春...... 114 | 115 | 116 | [1]: http://music.baidu.com/song/406958 117 | [2]: http://music.baidu.com/song/339744 118 | [3]: http://t.qq.com/milkpig526 119 | [4]: http://book.douban.com/subject/20429677/ 120 | [5]: http://book.douban.com/subject/20429677/ 121 | [6]: http://book.douban.com/subject/6021440/ 122 | -------------------------------------------------------------------------------- /_posts/2014-01-09-samba.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: ubuntu下samba配置 4 | tags: [samba,linux,ubuntu] 5 | --- 6 | 7 | 年底2个月开发移动联机游戏,此次使用新的后台框架:python和c++的组合。交互协议使用protobuf,数据库是mysql,缓存是memcache(后期会缓存redis),lua来处理配置,日志用到了log4cplus。 8 | 9 | 这次的后台系统运行在linux下,开发还是使用vs,每次修改完代码,都去linux下make。本来想有ftp,挺麻烦的,最后发现了samba,下面记录下配置。 10 | 11 | 12 | 13 | #### 简介 14 | 15 | SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通信协议,它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。SMB协议是客户机/服务器型协议,客户机通过该协议可以访问服务器上的共享文件系统、打印机及其他资源。通过设置“NetBIOS over TCP/IP”使得Samba不但能与局域网络主机分享资源,还能与全世界的电脑分享资源。 16 | 17 | #### 安装 18 | 19 | 首先安装samba: 20 | 21 | ```sh 22 | sudo apt-get install samba 23 | sudo apt-get install smbfs 24 | ``` 25 | 26 | #### 配置 27 | 28 | 创建共享目录:/data 29 | 30 | ```sh 31 | cd / 32 | sudo mkdir data 33 | chmod 777 data 34 | ``` 35 | 36 | 修改配置文件/etc/samba/smb.conf,搜索`; security = user`,替换为下面: 37 | 38 | ``` 39 | security = user 40 | username map = /etc/samba/smbusers 41 | ``` 42 | 43 | 最下面增加: 44 | 45 | ``` 46 | [data] 47 | comment = data 48 | path = /data 49 | public = yes 50 | writable = true 51 | valid users = king 52 | create mask = 0664 53 | directory mask = 0775 54 | force user = king 55 | force group = king 56 | available = yes 57 | browseable = yes 58 | ``` 59 | 60 | 添加用户,king是我的账号,如果是其他账号,可以自己创建: 61 | 62 | ```sh 63 | sudo smbpassed -a king #添加king,并设置密码 64 | sudo vi /etc/samba/smbusers #创建sambausers,并修改为king = "king" 65 | ``` 66 | 67 | 测试并重新启动: 68 | 69 | ```sh 70 | sudo testparam 71 | sudo /etc/init.d/samba restart 72 | ``` 73 | 74 | #### 使用 75 | 76 | windows下右键 我的电脑 -> 映射网络驱动器 -> 文件夹,选择映射的驱动器,输入`\\你的ip\data`, 点完成,然后输入用户名密码就行了。这时候就可以访问samba共享的目录data了。 77 | 78 | #### 问题 79 | 80 | 由于项目比较分散,最后发现samba下N多的配置项,够凌乱,开始我忍了。直到后来,在vs下开发,很多时候想查看一些库的定义,由于没有包含进来所以找不到定义,最后想到使用ln来创建软连接,这样可以减少samba下的共享文件夹的个数。 81 | 82 | 在网上搜索了下,需要设置添加下面三行: 83 | 84 | ``` 85 | wide links = yes 86 | follow symlinks = yes 87 | unix extensions = no 88 | ``` 89 | 90 | 好了,这下可以在映射的驱动器中看到ln的目录了,但是访问的时候提示没有权限。查看了samba的日志提示,好多类似下面的提示: 91 | 92 | > [2014/01/09 13:37:53.659863, 0] param/loadparm.c:10344(widelinks_warning) 93 | > Share 'data' has wide links and unix extensions enabled. These parameters are incompatible. Wide links will be disabled for this share 94 | 95 | google了N次,找到一篇文章[Samba and symlinks][1], 原来是我填写错了,`unix extensions = no ` 必须要放在 `[global]`下,我直接放在了`[data]`下,问题解决,samba还有好多高级用法以后再折腾。 96 | 97 | 扩展阅读: 98 | 99 | - [维基百科][2] 100 | - [samba官网][3] 101 | - [专题:Samba服务器安装配置全攻略][4] 102 | 103 | 104 | [1]: https://bbs.archlinux.org/viewtopic.php?id=92183 105 | [2]: http://en.wikipedia.org/wiki/Samba 106 | [3]: http://www.samba.org/ 107 | [4]: http://os.51cto.com/art/200512/12843.htm 108 | -------------------------------------------------------------------------------- /_posts/2014-01-11-ubuntuone-command-line.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Ubuntu One命令行工具 4 | tags: [python,linux,ubuntu,dropbox] 5 | --- 6 | 7 | 前段时间翻译了[Argparse简易教程][1],刚学python,业余时间做了个[Ubuntu One][2]的命令行工具练下手,现在基本上可以使用了,有很多地方没有优化处理,大家可以自己修改下,源码在[ubuntuone_uploader][3],下面说说一些用法。 8 | 9 | 10 | 11 | #### 安装 12 | 13 | 脚本依赖`oauth2`, ubuntu 下可以 `sudo apt-get install python-oauth2` 安装。 14 | 15 | ```sh 16 | git clone https://github.com/likebeta/ubuntuone_uploader.git 17 | cd ubuntuone_uploader 18 | chmod +x ubuntuone_uploader.py 19 | ``` 20 | 21 | #### 帮助 22 | 23 | 使用`-h`查看命令参数: 24 | 25 | ```sh 26 | king@ubuntu:~/ubuntuone_uploader$ ./ubuntuone_uploader.py -h 27 | usage: ubuntuone_uploader.py [-h] [-v] 28 | 29 | {auth,quota,list,download,upload,delete,mkdir,move,copy,share} 30 | ... 31 | 32 | It is a command-line tool to operate ubuntu one 33 | 34 | optional arguments: 35 | -h, --help show this help message and exit 36 | -v, --version show program's version number and exit 37 | 38 | sub-commands: 39 | {auth,quota,list,download,upload,delete,mkdir,move,copy,share} 40 | auth authorize to access your account 41 | quota quota info 42 | list list file of the directory 43 | download download file from ubuntu one and output to screen 44 | upload upload file to ubuntu one 45 | delete delete file from ubuntu one 46 | mkdir create directory 47 | move move file 48 | copy copy file 49 | share share or cancel share file,list share file 50 | ``` 51 | 52 | 参看子命令`upload`使用方法: 53 | 54 | ```sh 55 | king@ubuntu:~/ubuntuone_uploader$ ./ubuntuone_uploader.py upload -h 56 | usage: ubuntuone_uploader.py upload [-h] [-r remote_path] local_path 57 | 58 | positional arguments: 59 | local_path which to upload 60 | 61 | optional arguments: 62 | -h, --help show this help message and exit 63 | -r remote_path where to save 64 | ``` 65 | 66 | 详细用法说明参看[ubuntuone_uploader][4],Ubuntu One中的文件共享后可以直链访问(类似早期注册的Dropbox用户的public文件夹),有需要的可以使用我的推荐链接注册,我可以得到500M空间,邀请链接是[Ubuntu One][5]和[Dropbox][6]。 67 | 68 | 69 | [1]: http://blog.9527.eu.org/argparse.html 70 | [2]: https://one.ubuntu.com/referrals/referee/1698584/ 71 | [3]: https://github.com/likebeta/ubuntuone_uploader 72 | [4]: https://github.com/likebeta/ubuntuone_uploader 73 | [5]: https://one.ubuntu.com/referrals/referee/1698584/ 74 | [6]: http://db.tt/jacpdIw -------------------------------------------------------------------------------- /_posts/2014-10-16-centos-die-on-boot.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: CentOS开机卡在进度条的解决方法 4 | tags: [centos, linux] 5 | --- 6 | 7 | 好久没更新了,换工作有一只都很忙。今天在虚拟机中同时开了windows 7 和 centos 后,centos 莫名其妙的开始在进度条, google之。 8 | 9 | #### 还原/boot/grub/menu.lst 10 | 11 | 网上说可能是/boot/grub/menu.lst中的信息丢失,还原就好。进入grub后操作如下: 12 | 13 | 14 | 15 | > grub>root (sda1) 按[Enter] // 这是linux所在的分区符号(一般情况下是在sda1分区上) 16 | > grub>kernel /vmlinuz-2.6.32-358.el5 按[Enter] // 加载内核(一定要输入原内核版本号,可按[Tab]键补全) 17 | > grub>initrd /initrd-2.6.32-358.el5.img 按[Enter] // 初始化linux镜像 18 | > grub>boot 19 | 20 | 不是这个问题,继续查找。 21 | 22 | #### 开机启动软件异常 23 | 24 | 找到几个和我的情况差不多综合后解决了问题, 操作如下: 25 | 26 | > 1. 进入grub 27 | > 2. 选择centos输入`e`进行编辑,选择`kernel`行输入`e`进行编辑,去掉命令后面的quiet,`enter`确认 28 | > 3. 输入`b`启动 29 | > 4. 卡住后,按`F5`切换到文字界面, 查看卡在哪里(卡在uwsgi开机启动) 30 | > 5. 重启,再次到`kernel`行编辑, quiet后面加上single, 进入单人模式 31 | > 6. `chkconfig`关闭uwsgi开机启动 32 | > 7. `init 0` 重启 33 | 34 | 问题解决了,但是为啥会卡在uwsgi呢? 35 | -------------------------------------------------------------------------------- /_posts/2014-10-21-python-import-test.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Python import 测试 4 | tags: [python] 5 | --- 6 | 7 | 成千上万的package和module是python最强大得威力,最近在使用python的import时有点晕,做了个小的test想弄清楚各种import的不同之处, 下面是我的一个小实验,看来python的基础只是不扎实呀-_-! 8 | 9 | 10 | 11 | #### 目录结构 12 |
13 | foo/
14 | ├── bar/
15 | |   ├── __init__.py
16 | |   └── main.py
17 | ├── case.py
18 | ├── case1.py
19 | ├── case2.py
20 | ├── case3.py
21 | └── case4.py
22 | 
23 | 24 | #### 测试代码 25 | 26 | [likebeta/test](https://github.com/likebeta/test/tree/master/python/test_import) 27 | 28 | #### 运行结果 29 | 30 | ``` 31 | [mj@model_3 foo]$ python case.py 32 | case.py 33 | /home/work/foo/bar/__init__.py 34 | {'bar': , '__builtins__': , '__file__': 'case.py', '__package__': None, '__name__': '__main__', '__doc__': None} 35 | bar_init 36 | ``` 37 | 38 | ``` 39 | [mj@model_3 foo]$ python case1.py 40 | case1.py 41 | /home/work/foo/bar/__init__.pyc 42 | /home/work/foo/bar/main.py 43 | {'bar': , '__builtins__': , '__file__': 'case1.py', '__package__': None, '__name__': '__main__', '__doc__': None} 44 | bar_init 45 | bar_main 46 | ``` 47 | 48 | ``` 49 | [mj@model_3 foo]$ python case2.py 50 | case2.py 51 | /home/work/foo/bar/__init__.pyc 52 | {'bar_init': , '__builtins__': , '__file__': 'case2.py', '__package__': None, '__name__': '__main__', '__doc__': None} 53 | bar_init 54 | Traceback (most recent call last): 55 | File "case2.py", line 11, in 56 | main.bar_main() 57 | NameError: name 'main' is not defined 58 | ``` 59 | 60 | ``` 61 | [mj@model_3 foo]$ python case3.py 62 | case3.py 63 | /home/work/foo/bar/__init__.pyc 64 | /home/work/foo/bar/main.pyc 65 | {'__builtins__': , '__file__': 'case3.py', '__package__': None, '__name__': '__main__', 'main': , '__doc__': None} 66 | bar_main 67 | Traceback (most recent call last): 68 | File "case3.py", line 11, in 69 | bar_init() 70 | NameError: name 'bar_init' is not defined 71 | ``` 72 | 73 | ``` 74 | [mj@model_3 foo]$ python case4.py 75 | case4.py 76 | /home/work/foo/bar/__init__.pyc 77 | /home/work/foo/bar/main.pyc 78 | {'bar_main': , '__builtins__': , '__file__': 'case4.py', '__package__': None, '__name__': '__main__', '__doc__': None} 79 | bar_main 80 | Traceback (most recent call last): 81 | File "case4.py", line 11, in 82 | bar_init() 83 | NameError: name 'bar_init' is not defined 84 | ``` 85 | 86 | -------------------------------------------------------------------------------- /_posts/2014-12-29-python-reference.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Python引用中的坑 4 | tags: [python] 5 | --- 6 | 7 | 早就知道,python中万物皆对象,参数的传递都是"对象引用"的传递,这个和c++中值传递和参数传递都不一样,与两者的结合体有点神似。 c++中分为指针传递(含引用)和值传递,传递方式可以指定; python中分为可变对象传递和不可变对象传递,传递方式不可指定。自从转向python后,已经踏了3次引用的大坑。 8 | 9 | 10 | 11 | #### 第一次 12 | 13 | 当时场景是这样的,我们有个config类用于读取并缓存redis中的配置,config本身是封装了一个dict,每10秒清空一次,访问时如果命中就直接返回cache,否则读取redis缓存并返回。有个特殊处理,我在读取配置后修改了返回值,而返回值本身是config的某项的引用,这样就造成下一个玩家取得的配置是上个玩家的。但是这个bug测试没有发现,线上才发现,因为测试的时候基本上第二次请求这个配置的时候都超过了10秒。这个bug是另外一个同事帮忙找出来的,所以后面我对修改返回值都特别的小心。 14 | 15 | #### 第二次 16 | 17 | 这一次的问题是游戏结束,发送结算消息,由于有些信息是共有的,所以就创建了一个message初始化了相关共有信息, 然后针对各个玩家发送不同的信息,其实就是个for循环,在message中填充各自的消息,一般情况下应该是没有问题的,但是如果某项信息是可选的,上一个玩家A填充了这个信息,而下一个玩家B不需要填充这个信息,这个时候B却错误的拥有了这个信息。 18 | 19 | #### 再次 20 | 21 | 时隔N久,又栽在它的手里。但是四川麻将要添加定缺和换三张功能,所以修改了下算法,随手修改了两处看起来不太优雅的代码,噩梦开始了,妈妈的,打牌中会多出很多牌,场面极其淫乱,哦, sorry,是凌乱...混乱。我是对着代码看了N+1次也没有发现哪个修改会造成这种问题,实在没办法了,打印终极log。 22 | 23 | 好了,混乱的场面又出现了,看了下log: 24 | 25 | ``` 26 | 18066:12-29 15:47:05.443175 -D 280364104 before setPeng [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]] 27 | 18067:12-29 15:47:05.443454 -D 280364104 after setPeng [[3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0]] 28 | ``` 29 | 30 | 好像不太对了,一次设置修改了所有的值,联想下前面的改动,尼玛,肯定是应用的问题。下面打开python做实验看看。 31 | 32 | ``` 33 | Python 2.7.8 (a980ebb26592ed26706cd33a4e05eb45b5d3ea09, Sep 24 2014, 00:40:40) 34 | [PyPy 2.4.0 with GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2 35 | Type "help", "copyright", "credits" or "license" for more information. 36 | >>>> a = [[0,0] for i in range(9)] 37 | >>>> a 38 | [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]] 39 | >>>> b = [[0,0]] * 9 40 | >>>> b 41 | [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]] 42 | >>>> a[0][0] = 1 43 | >>>> a 44 | [[1, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]] 45 | >>>> b[0][0] = 1 46 | >>>> b 47 | [[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [1, 0]] 48 | >>>> print id(a[0]), id(a[1]) 49 | 140486007588960 140486007588984 50 | >>>> print id(b[0]), id(b[1]) 51 | 140486007612216 140486007612216 52 | ``` 53 | 54 | 但是就是强迫症修改了 `[[0,0] for i in range(9)]` 为 `[[0,0]] * 9`。 55 | 56 | #### 教训 57 | 58 | python很简单,使用中很灵活,但是底层其实还有好多东西需要了解,内部的一些机制还是需要细心动手去弄明白,编程中要时刻提醒自己。有几篇文章大家没事也可以看看,加深下理解: 59 | 60 | 1. [Python FAQ : 参数传递](http://python-china.org/topic/738) 61 | 2. [python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域](http://my.oschina.net/leejun2005/blog/145911) 62 | 63 | -------------------------------------------------------------------------------- /_posts/2015-02-26-the-2014.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 2014年总结 4 | tags: [2014] 5 | --- 6 | 7 | 迟到的总结,原本应该出现在2个月前,想了好多次都没有下笔。说白了对自己不满意,不太好总结,不太敢面对。去年是我的本命年,发生了好多事情,有好的,有坏的,有些大家知道,有些会一辈子烂在肚子里。总体来说这一年太颓废,斗志低迷,进步不够。 8 | 9 | 10 | 11 | #### 关于家人 12 | 13 | 除了每个人年龄的增长,父母加深的皱纹和泛白的发梢,家庭来说今年没太大变化。又是一年的叮嘱,热切的期盼,离别时强忍的泪水。。。 14 | 15 | 一切一切提醒着我,父母的青春不再,最最期盼的就是我们了,没什么事就顺着他们吧。 16 | 17 | #### 关于朋友 18 | 19 | 和朋友联系更少了,不是忘记,也不是不想,可能就只是长大了而已 20 | 21 | #### 关于爱情 22 | 23 | 没有电影中曲折的剧情,神奇的遭遇,一切都很自然。安安静静,平平淡淡,遇见她,足矣。。。 24 | 25 | #### 关于工作 26 | 27 | 4月份换了工作, 依然是棋牌游戏。 28 | 29 | 工作要求接触了Python,Twisted和Stackless,这些或许是最大的收获。 30 | 31 | #### 关于生活 32 | 33 | 生活上今年变化挺大的。本命年说不好有什么不同,不过总觉得是个分水岭。 34 | 35 | 这一年小伙伴们有的离去,有的分开,各自生活,或许今年变化会更大,终究各自散天涯。 36 | 37 | 偶尔会做点饭,不好吃,熟了就行。 38 | 39 | #### 关于青春 40 | 41 | 颓废,迷茫,浮躁。。。 42 | 43 | #### 关于健康 44 | 45 | 长胖了,肚子上出现肥肉,体检结石不见了。自从换了工作,基本上没有运动了,身体每况愈下,时常有头晕乏力的感觉。 46 | 47 | #### 关于游玩 48 | 49 | 4月份公司去参观了爱斐堡酒庄,游了桃源仙谷,爬了观峰台。 50 | 51 | 中秋节几个小伙伴去了丰宁坝上,虽然没看到想象中得草原,但是还挺不错的。 52 | 53 | #### 关于读书 54 | 55 | 书也读了几本,没有什么印象深刻的,太浮躁 56 | 57 | #### 关于北京 58 | 59 | 讨厌却不忍离去 60 | 61 | #### 关于计划 62 | 63 | + 运动:身体是需要运动,精神上也需要,感觉运动和意志力有很大关系 64 | + 看书:读书学习,修正心态 65 | + 编程:深入学习,完整开发一个联网手游 66 | + 成长:遇见她让我知道自己很不成熟,很多事情需要学习 67 | + 理财:财政一塌糊涂,该想想钱的事了 68 | -------------------------------------------------------------------------------- /_posts/2015-09-27-uwsgi-fork-trap.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: uwsgi中fork的陷阱 4 | tags: [uwsgi, fork, web.py, python, pypy, nginx] 5 | --- 6 | 7 | 游戏的sdk使用的是 `nginx+uwsgi+web.py`, 虽然用了一段时间了, 但是很多细节并没有仔细去推敲。最近要测试游戏端(tcp)的逻辑,用了5000个并发来测试。由于 sdk的日子都打印在一个log文件中, 并发打印的时候无法分辨一个请求处理过程中打印的完整请求,所以想加个标识, 结果引出来一系列的疑问。 8 | 9 | 10 | 11 | #### 请求为何会并发 12 | 13 | 由于开发的时候请求很少, 基本上没有看到多个请求的日志交错出现,而并发测试的时候出现了。这个问题很容易, 日志交错要么是异步执行, 要么是并发执行导致的。web.py没有提供异步支持, 那就是并发了。 看配置看到uwsgi配置的是4个worker,这样就好解释了。 但是这里犯了个严重的错误, 想当然的把worker看成worker线程了, ps明明显示的是进程。 14 | 15 | #### 变量的疑惑 16 | 17 | 既然是多线程(捂脸), web.ctx及session是类似单例模式,并发的时候这个ctx和session值是多少呢?貌似有问题,但是测试并没问题。经过查看源码发现ctx及session都是使用了ThreadedDict,也就类似TLS,这里不能理解为全局变量。^—^,想明白了,开心, sb的我此时还没有发现是多进程。 18 | 19 | #### 无尽的惨败 20 | 21 | 加个标识呗, 小case! 首先想到的是每个日志前加个`id(web.ctx)`表示每个线程的请求。不用我说结果就是并发时候这个值是一样的,当然和初始化打出的log中的不一样, 但是理解的是主线程。 22 | 23 | 没想明白, 换一种方法吧, 因为web.py中可以添加hook或者processors, 用于在request执行前和执行后进行一些处理工作。可以在初始化的时候在web中添加变量, 然后在每次request执行前后累加这个变量并放入各自的web.ctx中保存(加锁), 每次打印log的时候从web.ctx中取出打印这个变量,。乍一看起来也是对的, 信心满满的测试,结果4个worker分别在累加, 完全分辨不出来。把这个变量换成新对象比如(time.time()), 随机数等都会出现重,此时已经有点迷茫了。 24 | 25 | 想了会, 没明白 , 时间不多, 再换方法。现在想到的是直接打印线程id,改吧改吧再试。 我勒个操了, 4个worker线程id全部一样,并且和主线程id也一样, 尼玛已经接近崩溃。 26 | 27 | 后面各种修改各种换,都是各种惨败, 已经绝望。 28 | 29 | #### 一丝曙光 30 | 31 | 此时已经中午, 吃完午饭再想吧,然后蹲坑。突然想到了fork这个函数,会不会和他有关系, 但我没有调用fork呀, 对, 应该是多进程, 麻痹了。不拉了有点希望了,先去验证验证。 32 | 33 | 首先加上进程id的打印, 测试发现果然进程id不同, 其实到这里基本上加标识的问题可以解决了, 但是还有疑问,为毛初始化只有一次呢, 哦, fork, 应该和这个有关系, 去查uwsgi的文档,找到[如下描述](https://uwsgi.atupal.org/zh_CN/latest/RackQuickstart.html#fork): 34 | 35 | > uWSGI is “Perlish” in a way, there is nothing we can do to hide that. 36 | > Most of its choices (starting from “There’s more than one way to do 37 | > it”) came from the Perl world (and more generally from classical UNIX 38 | > sysadmin approaches). 39 | > 40 | > 有时候其他语言/平台上使用这些方法会导致不在意料中的行为发生。 41 | > 42 | > 当你开始学习 uWSGI 的时候一个你可能会面对的”问题”之一就是它的 fork() 使用。 43 | > 44 | > 默认情况下 uWSGI 在第一个 spawned 的进程里加载你的应用,然后在这个进程里面调用 fork() 多次。 45 | > 46 | > 这意味这你的应用被单独加载一次然后被复制。 47 | > 48 | > 虽然这个方法加速了服务器的启动,但有些应用可能会因为这个技术造成一些问题(特别是这些在启动的 49 | > 时候初始化数据库连接的,因为连接的文件描述符会在字进程中继承)。 50 | > 51 | > 如果你确定应不应该使用 uWSGI 野蛮的预-fork方式,那就使用 --lazy-apps 选项禁用掉它。 它将会强制你的应用在每个 52 | > worker 里都会完整加载一次。 53 | 54 | 好吧, 修改下试试, 果然初始化了4次, 当然这不是我想要的。 55 | 56 | #### 总结 57 | 58 | 到目前我们可以对一些现象进行解释: 59 | 60 | 1. web.py的web.ctx及一些变量实际上是线程相关的,一般情况下上层不用再考虑并发的读取问题。 61 | 2. uwsgi可以配置多进程, 默认加载一次, 然后根据配置fork出N份, 初始化代码只会执行一次,fork后相当于有N个子进程和一个父进程, 他们的各种变量环境都一样。 62 | 3. POSIX规定一个进程中线程id是唯一的, 进程id在系统中唯一。 这样看来如果是fork产生的进程, 线程id理论上是可以相同的, 不过貌似大部分系统实现的是系统唯一线程id。 63 | 4. python中的取得的线程id好像不是真实的, 按照网上说的[调用c模块来获取线程id](http://blog.devork.be/2010/09/finding-linux-thread-id-from-within.html)的方法, 我测试得到的线程id和进程id相同。 64 | 65 | #### 疑问 66 | 67 | 但目前为止, 只能说猜测, 有几个问题还没得到证实,时间比较紧, 想记下来: 68 | 69 | 1. fork出来的进程是否虚拟地址空间都一样, 变量的地址都一样。 70 | 2. fork出来的进程是否线程id可以相同。 71 | 3. 如果这些进程再创建线程, 线程id会怎样。 72 | 4. 测试的时候虽然线程id相同, 但是线程名称不同,但是后来再测试却都想通了, 一时复现不了。 73 | 74 | 后面有时间验证了再来补充, 说不定猜测根本不对, 实际上是别的原因? 75 | -------------------------------------------------------------------------------- /_posts/2015-11-08-raspberry-pi-first-time.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 树莓派之初体验 4 | tags: [raspberrypi, raspbian] 5 | --- 6 | 7 | 前段时间入手了一个树莓派2,ARM的板子虽然比不上x86的性能, 极低的功耗和4核1G的配置还是很不错的,比较适合24小时运行, 拿来跑个脚本,架个NAS或者下载机都可以。 8 | 9 | 10 | 11 | #### 安装系统 12 | 13 | 去[树莓派官网](https://www.raspberrypi.org/)先这个镜像,推荐[raspbian](https://www.raspberrypi.org/downloads/raspbian/),除了平台的区别基本上就可以当做debian来玩。 14 | 15 | Mac或者Linux下直接用`dd`向sd卡写入镜像, Windows下可以借助`Win32DiskImager`, 网上教程很多, 不细说。目前镜像都比较友好, 第一次启动的时候会进入配置界面, 按照提示一步一步来,很简单; 当然如果后面还想用这样的界面配置, 可以直接调用`raspi-config`。 16 | 17 | #### 配置网络 18 | 19 | 如果特殊修改网络的情况下, 第一次启动后应该已经连上网了, 此时是DHCP获取到的动态ip, 下面来给它配置个静态ip。 20 | 21 | `vim /etc/network/interfaces`, 按照自己的网络修改, 大致如下: 22 | 23 | ``` 24 | auto lo 25 | iface lo inet loopback 26 | 27 | # dns 28 | dns-nameservers 119.29.29.29 29 | dns-nameservers 223.5.5.5 30 | 31 | auto eth0 32 | allow-hotplug eth0 33 | iface eth0 inet static 34 | address 192.168.2.125 35 | gateway 192.168.2.1 36 | netmask 255.255.255.0 37 | network 192.168.2.0 38 | broadcast 192.168.2.255 39 | ``` 40 | 41 | `/etc/init.d/networking restart`重启网络, 现在树莓派已经是固定IP了, 最好在路由器上绑定下避免ip冲突。 42 | 43 | #### 无线网络 44 | 45 | 可以通过安装个usb无线网卡来让树莓派支持无线网,不用局限于网线的束缚,这样更加便携, 通过配置可以让树莓派在多个无线wifi中切换。假设有两个无线wifi,一个是公司一个是家里。 46 | 47 | `/etc/network/interfaces`中添加如下配置: 48 | 49 | ``` 50 | auto wlan0 51 | allow-hotplug wlan0 52 | iface wlan0 inet manual 53 | wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf 54 | 55 | # work 56 | iface work inet static 57 | address 192.168.1.108 58 | gateway 192.168.1.1 59 | netmask 255.255.255.0 60 | 61 | # home 62 | iface home inet static 63 | address 192.168.0.108 64 | gateway 192.168.0.1 65 | netmask 255.255.255.0 66 | ``` 67 | 68 | 修改`/etc/wpa_supplicant/wpa_supplicant.conf`如下所示: 69 | 70 | ``` 71 | ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev 72 | update_config=1 73 | 74 | network={ 75 | ssid="9527" 76 | psk="passwd" 77 | priority=5 78 | id_str="work" 79 | } 80 | 81 | network={ 82 | ssid="TP-7-1-402" 83 | psk="passwd" 84 | priority=4 85 | id_str="home" 86 | } 87 | ``` 88 | 89 | 重启网络后,树莓派应该可以使用无线网了,但目前还是有个问题,虽然wpa_supplicant声称可以自动重连, 我的实验结果是拔掉再插可以,但是有时候如果无线wifi出现问题, 树莓派并不会自动重连上。 90 | 91 | #### 守护脚本 92 | 93 | 上面的问题, 网上也有这个说法, 解决办法是定时用脚本来判断网络,自动重启网络, 如果长时间无法连接, 重启树莓派。 94 | 95 | #### 总结 96 | 97 | 如果连接网络有问题, ssh无法使用的时候, 就需要给树莓派连上键盘和显示器,显示器的连接需要修改`config.txt`。 折腾这到这里基本上可以告一段落了, 虽然废了很多精力遇到不少问题, 总体来说树莓派的资源还是挺多的, 问题通过Google基本都能解决, 下一节继续折腾。。。 98 | -------------------------------------------------------------------------------- /_posts/2016-06-10-texture-unpacker.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 分割还原TexturePacker打包的小图 4 | tags: [TexturePacker, TextureUnPacker, Cocos2d] 5 | --- 6 | 7 | 最近练手cocos2d-js, 苦于没有美术素材, 东拼西凑想弄个基本的界面, 网上扒了一些图片, 大部分都是只要其中的一个小图, 所以想着有没有简单的将TexturePacker打包的大图片切割还原成小图片, 然后自己打包需要的一部分小图. 8 | 9 | 10 | 11 | 因为网上找的图片都是有plist, 应该是有办法的. 网上搜了下, 有几个实现了我想要的功能, 下载使用都有各种问题. 仔细看了下, 我这边的plist中的format是3, 找到的现成的都是对老格式做的处理. 12 | 13 | 有一个貌似挺厉害的, 支持没有plist的情况下分割出小图, 不过已经收费了, 还是自己动手吧. 14 | 15 | TexturePacker打包的plist其实挺简单的, 就几个属性, 顾名思义大部分都能猜到含义, 主要就是spriteOffset没整明白, 开始搞错以为是左上角的偏移点, 最后搜了一篇介绍老格式文章-[cocos2dx plist中各个属性含义][1], 弄明白了原来是中心的偏移量. 16 | 17 | Python借助PIL的Image实现起来很简单, 稍作处理就可以, 处理textureRotated的时候遇到点问题, 很好解决. 基本上实现了我要的功能, 没有对老格式和plist以外的格式支持, 后面有需求再加上. 18 | 19 | 源码和示例在这里: [TextureUnPacker][2] 20 | 21 | 22 | [1]: http://blog.csdn.net/ranky2009/article/details/19566479 23 | [2]: https://github.com/likebeta/TextureUnPacker 24 | -------------------------------------------------------------------------------- /_posts/2016-07-02-animations-and-spritesheets-in-cocos2d-x.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 在Cocos2d-x v3中使用帧动画 4 | tags: [TexturePacker, Cocos2d] 5 | --- 6 | 7 | 你将会学到以下几点: 8 | 9 | 1. 为何要使用精灵图表 10 | 2. 在不同的设备和分辨率中设计和运行游戏 11 | 3. 创建优化的精灵图表 12 | 4. 创建动画 13 | 5. 播放角色动画 14 | 15 | 一句话就是: 一次开发, 到处运行(赚钱) 16 | 17 | 18 | 19 | #### 安装cocos2d-x 20 | 21 | 以mac上的xcode为例,其他平台可以参考官方文档。 22 | 23 | 首先从`http://www.cocos2d-x.org/download`下载`cocos2d-x`, 本文以3.9为例,除了多边形部分也适用老版本。 24 | 25 | 解压,然后移动到你需要放置的目录, 打开命令行,切换到此目录, 执行以下命令: 26 | 27 | ``` 28 | cd cocos2d-x-3.9 29 | python setup.py 30 | ``` 31 | 32 | 安装脚本会根据你的环境提示输入相应的目录; 如果需要开发`android`程序, 你需要输入`android`的`sdk`和`ndk`的地址,如果只是开发MacOS或者iOS程序, 直接**enter**略过就行了。 33 | 34 | 注意:`cocos2d-x`需要`python 2.7`,`MacOS`上已经自带,`windows`需要自己去`python.org`下载, 注意下载32位的版本, 64位的`cocos2d-x`会出现各种问题。 35 | 36 | 关闭此命令行, 然后再打开, 你会发现已经多了一个命令:`cocos`, 你可以用它来创建工程。 37 | 38 | #### 创建第一个游戏 39 | 40 | 使用以下命令创建一个空工程: 41 | 42 | ``` 43 | cocos new -l cpp -d ~/cocos2d-x-games Cocos2dx-SpriteSheetTutorial 44 | ``` 45 | 46 | > **注意**:如果出现这个错误:`ValueError: unknown local: UTF-8` 47 | > 48 | > 设置下locale变量: 49 | > 50 | > ``` 51 | > export LC_ALL=en_US.UTF-8 52 | > export LANG=en_US.UTF-8 53 | > ``` 54 | > 55 | > 然后重新运行创建的命令。 56 | 57 | 该命令会新建一个`cocos2d-x`工程,位于`~/cocos2d-x-games`下的子目录`Cocos2dx-SpriteSheetTutorial`中。 58 | 59 | 该工程是`c++`, 你也可以创建`lua`和`javascript`工程, 本教程以c++为例。 60 | 61 | `Cocos2dx-SpriteSheetTutorial`下面有一些列以`proj.`开头的目录, 这些目录对应不同的开发环境,包括`Visual Studio`,`XCode`, 已经一些其他平台。 62 | 63 | 选择你最喜欢的来开发就好了, 当需要支持其他平台的时候, 随时都可以在其他平台编译运行。 64 | 65 | 开发的时候,最重要的事情就是避免使用平台相关的特殊代码和库, cocos2d-x底层已经为我们做好了跨平台。 66 | 67 | 这篇教程主要是针对mac下的xcode来写的, 你可以很简单的按照教程在其他平台上做,主要就是加入文件和打开模拟器稍微有点不同。 68 | 69 | 打开工程, 编译运行, 你会看到一个显示着`hello world`的程序。 70 | 71 | 该程序包含了两个类:`AppDelegate`和`HelloWorldScene` 72 | 73 | #### 为何要使用精灵图表 74 | 75 | 如果你想在游戏中使用不同的精灵和动画,笨方法就是把它们全部添加到工程, 然后循环加载。 76 | 77 | 这个方法有几个问题: 78 | 79 | 1. 加载每个文件都需要耗费时间 80 | 2. 每个精灵都需要单独的加载到显存中 81 | 3. 切换纹理代价很大 82 | 4. 精灵无法优化,减少不必要的绘制 83 | 84 | 来看下面的精灵, 这是个角色走动的动画,下面章节要用到它。精灵图片中的空白区域是为了对其动画相位。 85 | 86 | ![animationphases.png](images/2016/animationphases.png) 87 | 88 | 透明区域似乎不包含任何有用的信息,但是GPU却不关心这一点。它会逐像素的进行渲染,不管是否可见。如上图透明区域达到了68%。 89 | 90 | 最简单的方法就是缩减绘制区域,让它只包含非透明区域,防止GPU对透明区域的绘制。这种方法可以减少24%的透明区域。 91 | 92 | 更好的方法就是用多边形标识出非透明区域。 93 | 94 | 好消息是: 当你使用TexturePacker的时候, 不需要关心这些,它会自动为精灵裁剪出cocos2d-x可以读取识别的矩形和多边形区域。 95 | 96 | ![trim-and-polygon-trim.png](images/2016/trim-and-polygon-trim.png) 97 | 98 | #### 多分辨率设计 99 | 100 | cocos2d-x是一个具有高度的可移植性的游戏框架,它已经对不同设备的支持做了很多工作,同样的代码可以运行在所有平台。 101 | 102 | 但是你需要关心设计问题,有些设备(比如iPad)的宽高比是4:3, 有些是16:9, 还有一些介于他们之间的奇葩比例。 103 | 104 | #### 手机统计 105 | 106 | 新发布的手机都有很高的分辨率,但是还是有很多老手机存在。下面图标展示了截止到2015底手机和平板的屏幕分辨率统计,有将近69%的设备的分辨率等于或者低于1280 x 720. 107 | 108 | 109 | ![device-stats.png](images/2016/device-stats.png) 110 | 111 | 新机和平板都具有很高分辨率甚至全高清的分辨率,但是只占了30%. 112 | 113 | | Model | Resolution | Aspect Ratio | 114 | | :---------------------- | :---------- | :----------- | 115 | | iPhone 6s | 1334 x 750 | 16:9 | 116 | | iPhone 6s Plus | 2208 x 1242 | 16:9 | 117 | | HTC One M8 | 1920 x 1080 | 16:9 | 118 | | Samsung Galaxy S6 | 2560 x 1440 | 16:9 | 119 | | Sony Xperia Z3 | 1920 x 1080 | 16:9 | 120 | | iPad (retina) | 2048 x 1536 | 4:3 | 121 | | Microsoft Surface Pro 4 | 2736 x 1824 | 3:2 | 122 | | Amazon Kindle Fire HD 7 | 1280 x 800 | 16:10 | 123 | 124 | #### 设计的两个难点 125 | 126 | 两个难点:不同的分辨率和不同的屏幕宽高比。 127 | 128 | **不同的分辨率** 129 | 130 | 不同的分辨率其实并不算是问题,只要你的游戏不包含太多复杂的对象和小的字体。你可以使用高分辨率来设计游戏, 然后通过缩放来适配小分辨率的设备。 131 | 132 | 对于低性能的小分辨率设备,内存可能是个问题。对于这种设备比较好的方法就是为他们加载缩放版本的精灵图表。一个2048x2048分辨率真色彩精灵需要16M内存,如果缩放50%就只有4M了。 133 | 134 | TexturePacker可以快速创建各种缩放版本的精灵图表。 135 | 136 | **不同的宽高比** 137 | 138 | 不同的宽高比是个棘手的问题,因为他会影响游戏的运行效果。有3中处理方法: 139 | 140 | 1. 为4:3和16:9分别设计一套UI 141 | 2. 以16:9或者4:3来设计,然后加上黑边 142 | 3. 以16:9来设计,通过缩放来填充适配4:3 143 | 144 | ![black-bars.png](images/2016/black-bars.png) 145 | 146 |

使用黑边, 分数显示在外面

147 | 148 | ![extended-scene.png](images/2016/extended-scene.png) 149 | 150 |

缩放场景

151 | 152 | 第一种方法可能是最好的,但是会增加大量的工作, 并且会影响到游戏展现,带来更大的挑战。 153 | 154 | 第二种看起来有点像90年代的设计。 155 | 156 | 我比较推荐第三种,它给玩家一致的体验。本教程的资源是为4:3宽高比做的,但是内容主要是针对16:9。 157 | 158 | #### 使用TexturePacker来创建精灵图表 159 | 160 | 首先从这里下载安装:https://www.codeandweb.com/texturepacker/download 161 | 162 | 拖拽cityscene文件夹到左侧面板,TexturePacker会添加包含的精灵到表中,并且保持文件的结构。当添加或者删除精灵图片是也会自动更新精灵表。 163 | 164 | ![texturepacker-add-sprites.png](images/2016/texturepacker-add-sprites.png) 165 | 166 | `Data Format`选择`cocos2d-x`, 不要选择`cocos2d`,`cocos2d`不支持多边形打包。 167 | 168 | ![texturepacker-select-cocos2d-x.png](images/2016/texturepacker-select-cocos2d-x.png) 169 | 170 | 开启多边形支持:`Trim mode`选择`polygon`, 你可以通过调节`Tracer tolerance`来控制精灵的多边形顶点数量,越多的顶点就可以越精确的标识非空白区域,减少绘制量, 但是尽量别控制顶点的数量, 以为顶点的计算需要消耗CPU的资源。 171 | 172 | 因为背景图片是个非透明矩形,所以这个精灵表过度绘制依然达到了95%。 173 | 174 | ![texturepacker-polygon-sprites.png](images/2016/texturepacker-polygon-sprites.png) 175 | 176 | 为不同的分辨率设备添加缩放比例,右边面板点击`Scaling variants`选择`cocos2d-x HDR/HD/SD`,点击`Apply`,你会看到三个缩放比例:`/HDR/`不缩放,`/HD/`缩放比例 0.5 和`/SD/`缩放比例0.25。如果你不是你想要的, 你可以删除它们,点击`Close`返回精灵表。 177 | 178 | 你会看到3个tab标签,点击标签可以预览相应缩放比例的精灵表。 179 | 180 | ![texturepacker-scaling-variants.png](images/2016/texturepacker-scaling-variants.png) 181 | 182 | 点击`Data file`后面的文件夹图标,将文件命名`cityscene.png`, 并保存在你工程下面的res目录中。你会得到一个错误,提示你需要在文件名中包含一个占位符`{v}`。 将文件名从`.../res/cityscene.plist`改为`.../res/{v}/cityscene.plist`。当保存文件的时候,这里的占位符会被替换成缩放比例的名字。 183 | 184 | 点击工具栏中的`Publish sprite sheet`,你将会在工程中看到6个文件: 185 | 186 | + res 187 | - HDR 188 | + cityscene.plist 189 | + cityscene.png 190 | - HD 191 | + cityscene.plist 192 | + cityscene.png 193 | - SD 194 | + cityscene.plist 195 | + cityscene.png 196 | 197 | #### AppDelegate中的启动代码 198 | 199 | 现在让我们开始写点代码吧。在开始使用精灵图表前,我们先来做点基础工作。如果`AppDelegate`中代码处理的好的话,可以让你游戏和分辨率保持解耦。 200 | 201 | #### 启动和分辨率处理 202 | 203 | 用以下代码替换`AppDelegate.h`中的代码: 204 | 205 | ``` 206 | #ifndef _APP_DELEGATE_H_ 207 | #define _APP_DELEGATE_H_ 208 | 209 | #include "cocos2d.h" 210 | 211 | class AppDelegate : private cocos2d::Application 212 | { 213 | public: 214 | virtual void initGLContextAttrs(); 215 | virtual bool applicationDidFinishLaunching(); 216 | virtual void applicationDidEnterBackground(); 217 | virtual void applicationWillEnterForeground(); 218 | 219 | private: 220 | void initOpenGL(); 221 | void initMultiResolution(); 222 | void initDirector(); 223 | void createAndRunScene(); 224 | }; 225 | 226 | #endif 227 | ``` 228 | 229 | 程序会在不同的时机调用这些`public`虚函数,你需要实现定义在`ApplicationProtocol`中的纯虚函数。这里的`private`函数帮助我们更好的组织整个过程。 230 | 231 | 删除并用以下代码替换`AppDelegate.cpp`中的内容: 232 | 233 | ``` 234 | #include "AppDelegate.h" 235 | #include "HelloWorldScene.h" 236 | 237 | USING_NS_CC; 238 | 239 | static cocos2d::Size designResolutionSize = cocos2d::Size(2048, 1536); 240 | 241 | static cocos2d::Size smallResolutionSize = cocos2d::Size(512, 384); 242 | static cocos2d::Size mediumResolutionSize = cocos2d::Size(1024, 768); 243 | static cocos2d::Size largeResolutionSize = cocos2d::Size(2048, 1536); 244 | ``` 245 | 246 | `designResolutionSize`表示游戏的设计大小。你可以根据自己的需要随意设置它,不过业界用的比较多的下面两个值: 247 | 248 | 1. (512, 384): 在低分辨率设备中1单元对应1像素 249 | 2. (2048x1536): 在你的设计中1单元对应1像素 250 | 251 | 在cocos2d-x中想做到像素级别的完美设计很困难,最简单的原因,如果你想在Android设备上运行游戏, 你就需要面对大量的不同分辨率设备,就连iOS的设备大小和比例也都不同。 252 | 253 | 我个人比较建议使用高分辨率作为`designResolutionSize`, 因为这样能更容易的在图形编辑器中权衡和设置大小和位置。 但是如果一个对象放置的坐标位置不能被4整除,可能会低分辨率设备上有点误差。但是考虑到缩放,其实并不是个大问题。 254 | 255 | `smallResolutionSize`,`mediumResolutionSize`and`largeResolutionSize`这3个值表示不同屏幕的设备提供的缩放的设计尺寸。他们会对应`TexturePacker`打包成的缩放版的精灵表。 256 | 257 | 添加下面的函数, 它负责加载缩放版本的图片资源。 258 | 259 | ``` 260 | void AppDelegate::initMultiResolution() 261 | { 262 | auto director = Director::getInstance(); 263 | auto glview = director->getOpenGLView(); 264 | 265 | glview->setDesignResolutionSize( 266 | designResolutionSize.width, 267 | designResolutionSize.height, 268 | ResolutionPolicy::NO_BORDER 269 | ); 270 | 271 | ... 272 | ``` 273 | 274 | `setDesignResolutionSize`用来设置游戏的设计尺寸,`ResolutionPolicy::NO_BORDER`表示场景会被拉升填满整个屏幕, 该参数还有几个值可以选择: 275 | 276 | 值 | 描述 277 | ------------ | ----------- 278 | EXACT_FIT | 拉升填充整个屏幕,但不是宽高等比拉升,某些情况整个画面是扭曲变形的。 279 | NO_BORDER | 等比拉升,填满整个屏幕,可能超出屏幕外,有些部分不可见 280 | SHOW_ALL | 等比拉升,但是不会超出屏幕外,如果比例不一样,就用黑边填充两边的空白区域 281 | FIXED_HEIGHT | 以高为准,宽进行缩放适配 282 | FIXED_WIDTH | 以宽为准,高进行缩放适配 283 | 284 | 实际使用中`EXACT_FIT`基本上都不会采用,`NO_BORDER`可能是最简单的方法了。 285 | 286 | 继续补充`initMultiResolution()`函数: 287 | 288 | ``` 289 | ... 290 | 291 | std::vector searchPaths; 292 | float scaleFactor = 1.0f; 293 | Size frameSize = glview->getFrameSize(); 294 | 295 | if (frameSize.height > mediumResolutionSize.height) 296 | { 297 | searchPaths.push_back("res/HDR"); 298 | scaleFactor = largeResolutionSize.height/designResolutionSize.height; 299 | } 300 | else if (frameSize.height > smallResolutionSize.height) 301 | { 302 | searchPaths.push_back("res/HD"); 303 | scaleFactor = mediumResolutionSize.height/designResolutionSize.height; 304 | } 305 | else 306 | { 307 | searchPaths.push_back("res/SD"); 308 | scaleFactor = smallResolutionSize.height/designResolutionSize.height; 309 | } 310 | 311 | director->setContentScaleFactor(scaleFactor); 312 | FileUtils::getInstance()->setSearchPaths(searchPaths); 313 | } 314 | ``` 315 | 316 | `getFrameSize()`可以得到设备的显示尺寸,与预设的几种尺寸的高度进行比较来选择尽量高分辨率的设计方案。 317 | 318 | 高 | 精灵表 319 | ---- | ---- 320 | h < 512 | SD 321 | 513 < h < 1024 | HD 322 | h > 1024 | HDR 323 | 324 | 代码还设置了资源的搜索路径,这样的好处是不需要硬编码,只要指定加载`cityscene.plist`, cocos2d-x 就会为我们加载正确的文件。 325 | 326 | 还有一些模板代码,我们直接复制就行了,比如用来创建`OpenGL view`的。 327 | 328 | #### AppDelegate添加更多代码 329 | 330 | 下面的一坨代码也必须要添加进去,用来响应游戏进入前台/切入后台。 331 | 332 | ``` 333 | void AppDelegate::initOpenGL() 334 | { 335 | auto director = Director::getInstance(); 336 | auto glview = director->getOpenGLView(); 337 | if(!glview) 338 | { 339 | #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || 340 | (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || 341 | (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX) 342 | glview = GLViewImpl::createWithRect("Cocos2dx-SpriteSheetTutorial", 343 | Rect(0, 0, designResolutionSize.width, designResolutionSize.height)); 344 | #else 345 | glview = GLViewImpl::create("Cocos2dx-SpriteSheetTutorial"); 346 | #endif 347 | director->setOpenGLView(glview); 348 | } 349 | } 350 | ``` 351 | 352 | 下面代码用来初始化`Director`, 设置刷新帧率,开启右下角显示帧率等统计信息。 353 | 354 | ``` 355 | void AppDelegate::initDirector() 356 | { 357 | auto director = Director::getInstance(); 358 | director->setAnimationInterval(1.0 / 60); 359 | director->setDisplayStats(true); 360 | } 361 | ``` 362 | 363 | 下面代码创建并运行游戏场景,下面还需要为场景创建`HelloWorld`层。 364 | 365 | ``` 366 | void AppDelegate::createAndRunScene() 367 | { 368 | auto scene = HelloWorld::createScene(); 369 | Director::getInstance()->runWithScene(scene); 370 | } 371 | ``` 372 | 373 | 下面方法会在cocos2d-x初始化完成后调用前面创建的所有方法。 374 | 375 | ``` 376 | bool AppDelegate::applicationDidFinishLaunching() 377 | { 378 | initOpenGL(); 379 | initDirector(); 380 | initMultiResolution(); 381 | createAndRunScene(); 382 | return true; 383 | } 384 | ``` 385 | 386 | 下面的两个函数会在你切入后台或者进入前台的时候调用。可以暂停所有动画和音效,也可以停止一些运算等等。 387 | 388 | ``` 389 | void AppDelegate::applicationDidEnterBackground() 390 | { 391 | Director::getInstance()->stopAnimation(); 392 | // SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); 393 | } 394 | 395 | void AppDelegate::applicationWillEnterForeground() 396 | { 397 | Director::getInstance()->startAnimation(); 398 | // SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); 399 | } 400 | ``` 401 | 402 | 最后一个需要的函数是`initGLContextAttrs()`, 它用来设置一些OpenGL绘制时的上下文环境。如果没有特殊的需求, 最好别修改它。 403 | 404 | ``` 405 | void AppDelegate::initGLContextAttrs() 406 | { 407 | //set OpenGL context attributions,now can only set six attributions: 408 | //red,green,blue,alpha,depth,stencil 409 | GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8}; 410 | GLView::setGLContextAttrs(glContextAttrs); 411 | } 412 | ``` 413 | 414 | #### 使用精灵图表 415 | 416 | After the less interesting tasks of initializing the app you'll now get the 精灵图表 to work. 417 | 经过一些初始化工作, 现在可以使用精灵图表了。 418 | 419 | 在`HelloWorldScene.h`中添加以下代码: 420 | 421 | ``` 422 | #ifndef __HELLOWORLD_SCENE_H__ 423 | #define __HELLOWORLD_SCENE_H__ 424 | 425 | #include "cocos2d.h" 426 | 427 | class HelloWorld : public cocos2d::Layer 428 | { 429 | public: 430 | static cocos2d::Scene* createScene(); 431 | virtual bool init(); 432 | CREATE_FUNC(HelloWorld); 433 | 434 | private: 435 | cocos2d::Vector getAnimation(const char *format, int count); 436 | }; 437 | 438 | #endif 439 | ``` 440 | 441 | 这里包含了是个函数声明: 442 | 443 | ``` 444 | createScene() 445 | ``` 446 | 447 | 用来创建一个包含`HelloWorld`层的场景。场景类似一个容器,包含了众多的层以及游戏数据。它会在`AppDelegate::createAndRunScene`中的`runWithScene()`被`Director`使用。 448 | 449 | ``` 450 | init() 451 | ``` 452 | 453 | Init用来初始化`HelloWorld`对象,并创建游戏对象和动画。 454 | 455 | ``` 456 | CREATE_FUNC(HelloWorld) 457 | ``` 458 | 459 | `CREATE_FUNC`是一个宏, 创建了一个静态方法`HelloWorld::create()`, 这个方法会创建一个`HelloWorld`对象,进行内存管理, 然后调用`init()`。 460 | 461 | ``` 462 | getAnimation() 463 | ``` 464 | 465 | 此方法封装了从精灵表创建动画。 466 | 467 | 下面来看看`HelloWorldScene.cpp`。 468 | 469 | ``` 470 | #include "HelloWorldScene.h" 471 | 472 | USING_NS_CC; 473 | 474 | Scene* HelloWorld::createScene() 475 | { 476 | auto scene = Scene::create(); 477 | auto layer = HelloWorld::create(); 478 | scene->addChild(layer); 479 | return scene; 480 | } 481 | ``` 482 | 483 | 如上所述:此方法封装了场景的创建,添加`HelloWorld`层,然后返回场景给`Director`使用。 484 | 485 | #### 添加静态背景 486 | 487 | > **不用使用 SpriteBatchNode** 。 488 | > 489 | > 在`Cocos2d-x V2`中一般会使用`CCSpriteBatchNode`来提高精灵表的性能,为了兼容,此方法在`Cocos2d-x V3`中也存在,叫做`SpriteBatchNode`, 但hi已经被标记为废弃。 490 | > 491 | >`Cocos2d-x V3`中会自动进行批处理,不需要显示调用。多边形的精灵会被分割成小块,因为批处理只支持矩形。 492 | 493 | 下一个函数是`init()`: 494 | 495 | ``` 496 | bool HelloWorld::init() 497 | { 498 | if ( !Layer::init() ) 499 | { 500 | return false; 501 | } 502 | 503 | SpriteFrameCache::getInstance()->addSpriteFramesWithFile("cityscene.plist"); 504 | 505 | Vec2 origin = Director::getInstance()->getVisibleOrigin(); 506 | Vec2 visibleSize = Director::getInstance()->getVisibleSize(); 507 | 508 | // background 509 | auto background = Sprite::createWithSpriteFrameName("background.png"); 510 | background->setPosition(origin.x + visibleSize.x / 2,origin.y + visibleSize.y/2); 511 | this->addChild(background); 512 | 513 | return true; 514 | } 515 | ``` 516 | 517 | 首先调用父类初始化。 518 | 519 | 使用前你需要先加载精灵表,你可以使用`addSpriteFramesWithFile`来加载plist文件,plist文件中包含了精灵表信息,`cocos2d-x`会被自动加载。 520 | 521 | 注意这里并没有分辨率相关的处理,`AppDelegate`中的代码保证了`addSpriteFramesWithFile`会加载对应的资源。 522 | 523 | 下面两行返回了屏幕原点和尺寸,这些坐标是依据设计尺寸的值。下面可以使用这两个值来让背景居中显示。 524 | 525 | 调用`Sprite::createWithSpriteFrameName()`来创建精灵,参数是加载到`TexturePacker`中是使用的名字。 526 | 527 | 设置背景居中, 在4:3设备中你会看到更多的天空和街道,而在16:9的设备中是居中的。 528 | 529 | 最后一行将背景对象添加到层中。 530 | 531 | 编译运行, 你会看到如下场景: 532 | 533 | ![gamescene-just-background.png](images/2016/gamescene-just-background.png) 534 | 535 | #### 播放动画 536 | 537 | `cocos2d-x`中你需要告诉她使用哪些精灵帧来播放动画。最简单的方法就是使用下面的函数,他返回精灵帧组成的数组: 538 | 539 | ``` 540 | Vector HelloWorld::getAnimation(const char *format, int count) 541 | { 542 | auto spritecache = SpriteFrameCache::getInstance(); 543 | Vector animFrames; 544 | char str[100]; 545 | for(int i = 1; i <= count; i++) 546 | { 547 | sprintf(str, format, i); 548 | animFrames.pushBack(spritecache->getSpriteFrameByName(str)); 549 | } 550 | return animFrames; 551 | } 552 | ``` 553 | 554 | 这个函数以给定的格式从精灵表中检索精灵帧,你可以这样调用: 555 | 556 | ``` 557 | Vector frames = getAnimation("capguy/walk/%04d.png", 8); 558 | ``` 559 | 560 | `%04d`格式字符串会生成一0填充的4个数字前缀的字符串:0001, 0002, 0003,... 561 | 562 | 调用此函数会返回8个精灵帧的数组:capguy/walk/0001.png,... capguy/walk/0008.png 563 | 564 | 在`HelloWorldScene.cpp`中的`init()`返回前添加添加以下代码: 565 | 566 | ``` 567 | // sprite 568 | auto frames = getAnimation("capguy/walk/%04d.png", 8); 569 | auto sprite = Sprite::createWithSpriteFrame(frames.front()); 570 | background->addChild(sprite); 571 | sprite->setPosition(100,620); 572 | 573 | auto animation = Animation::createWithSpriteFrames(frames, 1.0f/8); 574 | sprite->runAction(RepeatForever::create(Animate::create(animation))); 575 | ``` 576 | 577 | 第一行就是获取精灵帧数组,然后用第一帧创建一个精灵。 578 | 579 | 将精灵作为子节点加到背景中,这里不是作为场景的子节点。确保将精灵添加到背景上正确的位置。 580 | 581 | 第二块代码用精灵帧创建了动画,并设置帧率为`1.0f/8`, 一秒播放8帧。 注意这里是`1.0f/8`而不是`1/8`,后者会是一个整型,这里就是0,动画永远都不会被运行。 582 | 583 | 最后一行组合了3个函数的调用: 584 | 585 | - 创建一个动画对象,用来播放动画 586 | - 创建一个`RepeatForever`循环播放动画 587 | - 将`RepeatForever`对象传递给精灵执行 588 | 589 | 编译运行,你会看到一个`Capguy`在原地行走。 590 | 591 | ![gamescene-capguy.png](images/2016/gamescene-capguy.png) 592 | 593 | #### 让精灵移动起来 594 | 595 | 我们来让`Capguy`从左往右走起来,`cocos2d-x`可以使用一个`MoveTo`的动作。它有两个参数: 持续时间(秒)和目标位置坐标。 596 | 597 | 在`HelloWorldScene.cpp`中的`init()`返回前添加添加以下代码: 598 | 599 | ``` 600 | auto movement = MoveTo::create(10, Vec2(2148,620)); 601 | auto resetPosition = MoveTo::create(0, Vec2(-150,620)); 602 | auto sequence = Sequence::create(movement, resetPosition, NULL); 603 | sprite->runAction(RepeatForever::create(sequence)); 604 | ``` 605 | 606 | `resetPosition`重置`Capguy`的位置成屏幕最左边, 时间为0会立马完成动作。 607 | 608 | `Sequence`创建了一个动作序列, 会一个接一个的执行, 你可以同时添加几个动作, 但是要保证以NULL结尾。 609 | 610 | 最后,将动作使用`RepeatForever`包裹传递给精灵执行。 611 | 612 | 编译运行, 你会看到`Capguy`在街上散步。 613 | 614 | ![gamescene-animated.png](images/2016/gamescene-animated.png) 615 | 616 | 原文: [Tutorial: Using sprite sheet animations in cocos2d-x V3](https://www.codeandweb.com/blog/2015/12/15/animations-and-spritesheets-in-cocos2d-x) 617 | -------------------------------------------------------------------------------- /about.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | layout: page 4 | about: true 5 | --- 6 | 7 | #### 我 8 | 9 | 男,与80后一起长大的90后,非典型天蝎,职业coder,纯北漂,蜗居北京朝阳某处,想法挺多,成就没有,爱好篮球,看书,各种YY. 10 | 11 | #### 技术 12 | 13 | Linux, C/C++, Python, Golang, Javascript, PHP, Lua, Redis, Mysql 14 | 15 | #### 工作 16 | 17 | + ***2017.02 - 0000.00:*** working at [九九](http://www.x9mj.com "北京九九鼎盛网络科技有限公司") 18 | + ***2015.04 - 2017.01:*** work at [qifan](http://www.dapai178.com "北京起凡互娱科技有限公司") 19 | + ***2014.04 - 2015.03:*** work at [tuyoo](http://www.tuyoo.com "在线途游(北京)科技有限公司") 20 | + ***2012.03 - 2014.04:*** work at [7k7k](http://www.7k7k.com "北京奇客创想信息技术有限公司") 21 | + ***2008.06 - 2012.06:*** study in [haust](http://www.haust.edu.cn "河南科技大学") 22 | 23 | #### 博客 24 | 25 | 本站架构: Jekyll + Markdown + Github Pages 26 | 27 | #### 联系 28 | 29 | + [github/likebeta](https://github.com/likebeta) 30 | + [email/likebeta]({{site.author.qqmail}}) 31 | 32 |
33 | -------------------------------------------------------------------------------- /archives.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: archives 3 | layout: page 4 | archives: true 5 | --- 6 | 7 |
8 |
9 | {% for post in site.posts %} 10 | {% capture y %}{{post.date | date:"%Y"}}{% endcapture %} 11 | {% if year != y %} 12 | {% assign year = y %} 13 | {% if forloop.first %} 14 | {% else %} 15 | 16 | {% endif %} 17 |

{{ y }}

    18 | {% endif %} 19 |
  • 20 | 21 | {{ post.title }} 22 |
  • 23 | {% if forloop.next %} 24 |
25 | {% endif %} 26 | {% endfor %} 27 |
28 |
29 | -------------------------------------------------------------------------------- /atom.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: null 3 | --- 4 | 5 | 6 | {{ site.title | xml_escape }} 7 | {{ site.time | date_to_xmlschema }} 8 | {{ site.url }}/ 9 | 10 | 11 | Jekyll 12 | 13 | {{ site.owner.name }} 14 | {{ site.url }}{{ site.baseur }}/ 15 | {{ site.email }} 16 | 17 | 18 | {% for post in site.posts %} 19 | 20 | <![CDATA[{{ post.title | cdata_escape }}]]> 21 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 22 | {{ site.url }}{{ post.id }} 23 | {% if post.modified %}{{ post.modified | to_xmlschema }}T00:00:00-00:00 24 | {{ post.date | date_to_xmlschema }} 25 | {% else %}{{ post.date | date_to_xmlschema }} 26 | {{ post.date | date_to_xmlschema }}{% endif %} 27 | 28 | {{ site.owner.name }} 29 | {{ site.url }}{{ site.baseurl }} 30 | {{ site.email }} 31 | 32 | {{ post.content | xml_escape }} 33 | 34 | 35 | {% endfor %} 36 | 37 | 38 | -------------------------------------------------------------------------------- /avater.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Avater 3 | layout: page 4 | photo: true 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |                                                  .   .
12 |                                             .:@3@@@@X@@A.#3,A@M5r
13 |                                         i@M@@@@@@@@@@@@@@@@@@@@@@@@
14 |                                     .,#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#5@@
15 |                                   i@@@@@@#@##M@#M###@@@#@@@@@@@@@@@@@@@@@H;:
16 |                                 2@@@@@#MB#@@H#@@@@#@@@@@@@@#@@@@@@@@@@@@@@@@;
17 |                               ;@@@@MBB##B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.
18 |                              h@@@MHBMM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
19 |                             @@@HABM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
20 |                          ;@@@#AHB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:.
21 |                        .@@@@HM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
22 |                       ,@@#HAAH#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@r
23 |                       r@MAM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@i
24 |                      h@#H&#@@@@@@@@@@@@@M#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S
25 |                     ;@@AAAGM@@@@@@@@S,    ., .rri9@AXHi2:.S;.9sr@M&HA9XXH@@@@@@@@@@@@@@@
26 |                      @#AAABM@@@@@#.                                         ;@@@@@@@@@@@
27 |                     S@MAA&A@@@@@s                           ,... ........     B@@@@@@@@@
28 |                      @MAAA@@@@@     ...........       .... .;:::::::::::,,,,   M@@@@@@@@i
29 |                     2@HAA&#@@@.  ...........................;::::::::::::::::   @@@@@@@@A
30 |                     ;@BAAAA@@@  ............................;:::::::::::::::;:  @@@@@@@@.
31 |                     ,@MAA&#@@@  ...........................:;:::::::::::::::::,.@@@@@@@@#
32 |                     ,@#AAH#@@@    .          ..............;;::::,.       ,:::,.@@@@@@@@;
33 |                     ;@M&M@@@@@. .:;rrssiir;,    .......... ::.   ,;5hHAS3: .::.,@@@@@@@@@
34 |                     ;@MAH@@@@@ ;@@@@@@@@@@@@@@9. .........   r&@@@@@@@@@@@@,,:..@@@@@@@@
35 |                     ,@MA@@@@A  ;@@MHAAAAAAA#@@@@;  ...... ;@@@@@@@@@@@@@@@@2.:, @@@@@@@@r
36 |                     G@AH@@@H    ,;;rsiSS55iss;:r: .,,,:::,AGr;rrrrsisr;:. .   . 5@@@@@@#
37 |                     s@AM@@@.,#@@@@#&GAB@@##H@@@@@Bi:,:::,:SB@@@#M#@@@@@@@@@@#i   @@@@@@@
38 |                     .@@H@@@@@@@r   H@@@X#@&r. ,i#@@@@@@@@@@Hs.:XA@9G@#3X..sM@@@@,5@@@@@@
39 |                      ;@@@@@@@@&  :@A.5@9@@s,X2    &@@@HM@@r  .@52@A@@A.;SG.   M@@@@@@@@@.
40 |                        @@@@@@@; .:,    :,,:,    , &@s   :@@  ,.   :,. ,  :... ,@@@@@@@@s
41 |                        3@@& #@i    .   isi:    ,..@@     @@A ...;2ii; .    .: r@@@@@@@#
42 |                     &h:  5:  @@M:             .,r@@,   . ;@@s             .,..@@h;@#iss2G
43 |                    @5    X:   h@@@@@@@@@####@@@@@@,  . ., r@@@@Ms:,....,;;rsh@@X  G    ,X@
44 |                   SB rr: @,      ,r2hH#@@@@@@@#i.   ....,,  ;3#@@@@@@@@@@@@@@#;   M ..,;.M&
45 |                   #;;H9MS#.                          ..   ,.     .,:::;;;::.   ,, @.:&HX,;@
46 |                   #:.,..S@, ..                  .,.  ...    ,,,              .::: #iBr  ,:@
47 |                   29 :,,i@s .........       ,;,:;;.  ...  .   .:,            .;:: @@rr5s.s#
48 |                    @: ,MiiA ..............,;:;@sr;MM:,::;h@X.rH,:;,.....   . .;:: @i;rsh,@.
49 |                     @r : ;@  ............:;;  rA9;SMr;;;;Gh2H#;  .;,....::,. .;:, #    :@;
50 |                      H9   @; .....,,,,::;r;:        ,;;:.  ..   .......,;r;;::;:.;H ,r&A
51 |                       rHS.&A .....,rrrr;;:.                    ..........:;;;;:: MB5&5.
52 |                         :rX@  ..........    ...  .  ,35S     ....,, ....  :;::::,@;
53 |                            @; .....     .:s.   ..,,..:;,.,,....  ;i, .... .;:::.iG
54 |                            ;@  ..........;H@HAAAAAA&32Xh&&AAA&AAG@G;:.... ,;::: @,
55 |                             @r ..........,,,:,,,,. .,,..    .,:;;:.::.... :;::.i#
56 |                             .@,  .......         ,r:,,,:;i23r,,,     ....:;::,:@
57 |                              r@,. ........       ,SG&&&hXir;:::   ......:;::,:@:
58 |                               i@;,. .............  ,,,..,,,:::,........:;::.;@,
59 |                                ;@9:,. ...........         ...  .......;;:,:GM.
60 |                                  9@X:.  ...........          .......,;;,;hM;
61 |                                    h@&;.  ........................:;::sAA;
62 |                                      iB#X;.   ...............,,:;::r3B3,
63 |                                        .iH#Gi:..   .,,::::::;:::r2A&r
64 |                                            ;XABA3S;;;;;;;;;rsiXG3r
65 |                                                ,rS@AAAAAAAA&X#M
66 |                                                   #:.,:,,,,. rG
67 |                                                  ,@,.,::::,,,:@,
68 |                                               .sAr@.  ...:::,.@@HAi
69 |                                             A@@h  3,     .;::.2X @@@i
70 |                                            G@@@;    ...  ,;::,.,.@@@@2
71 |                                           5@@H@@,    .:,,::::,  #@B#@#3
72 |                                          ,@@#HM@@2:.   ,,....,s@@HA#@ @;
73 |                                          X.r#AAAAMHh2isiiii53AMHAAA#2,:9
74 |             
75 |
76 |
77 |
78 | -------------------------------------------------------------------------------- /categories.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: categories 3 | layout: page 4 | --- 5 | 6 |
7 |
8 | {% for categorie in site.categories %} 9 |

{{ categorie[0] }}

10 |
    11 | {% for post in categorie[1] %} 12 |
  • 13 | 14 | {{ post.title }} 15 |
  • 16 | {% endfor %} 17 |
18 | {% endfor %} 19 |
20 |
21 | 27 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/favicon.ico -------------------------------------------------------------------------------- /feed.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: null 3 | --- 4 | 5 | 6 | {{ site.title | xml_escape }} 7 | {{ site.time | date_to_xmlschema }} 8 | {{ site.url }}/ 9 | 10 | 11 | Jekyll 12 | 13 | {{ site.owner.name }} 14 | {{ site.url }}{{ site.baseur }}/ 15 | {{ site.email }} 16 | 17 | 18 | {% for post in site.posts %} 19 | 20 | <![CDATA[{{ post.title | cdata_escape }}]]> 21 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 22 | {{ site.url }}{{ post.id }} 23 | {% if post.modified %}{{ post.modified | to_xmlschema }}T00:00:00-00:00 24 | {{ post.date | date_to_xmlschema }} 25 | {% else %}{{ post.date | date_to_xmlschema }} 26 | {{ post.date | date_to_xmlschema }}{% endif %} 27 | 28 | {{ site.owner.name }} 29 | {{ site.url }}{{ site.baseurl }} 30 | {{ site.email }} 31 | 32 | {{ post.content | xml_escape }} 33 | 34 | 35 | {% endfor %} 36 | 37 | 38 | -------------------------------------------------------------------------------- /images/2016/animationphases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/animationphases.png -------------------------------------------------------------------------------- /images/2016/black-bars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/black-bars.png -------------------------------------------------------------------------------- /images/2016/device-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/device-stats.png -------------------------------------------------------------------------------- /images/2016/extended-scene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/extended-scene.png -------------------------------------------------------------------------------- /images/2016/gamescene-animated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/gamescene-animated.png -------------------------------------------------------------------------------- /images/2016/gamescene-capguy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/gamescene-capguy.png -------------------------------------------------------------------------------- /images/2016/gamescene-just-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/gamescene-just-background.png -------------------------------------------------------------------------------- /images/2016/texturepacker-add-sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/texturepacker-add-sprites.png -------------------------------------------------------------------------------- /images/2016/texturepacker-polygon-sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/texturepacker-polygon-sprites.png -------------------------------------------------------------------------------- /images/2016/texturepacker-scaling-variants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/texturepacker-scaling-variants.png -------------------------------------------------------------------------------- /images/2016/texturepacker-select-cocos2d-x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/texturepacker-select-cocos2d-x.png -------------------------------------------------------------------------------- /images/2016/trim-and-polygon-trim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/images/2016/trim-and-polygon-trim.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: index 3 | index: true 4 | --- 5 | 6 | {% for post in site.posts limit:32 %} 7 |
8 |
9 | {{ post.date | date:"%d" }} 10 | {{ post.date | date:"%b" }} 11 | {{ post.date | date:"%Y" }} 12 |
13 |
14 |

{{ post.title }}

15 |
16 |
17 |

18 | {{ post.content | split:'' | first | strip_html }} 19 | [继续阅读] 20 |

21 |
22 |
23 | {% endfor %} 24 | -------------------------------------------------------------------------------- /media/css/highlight.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #f8f8f8; } 3 | .highlight .c { color: #408080; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 8 | .highlight .cp { color: #BC7A00 } /* Comment.Preproc */ 9 | .highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ 10 | .highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ 11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 16 | .highlight .go { color: #808080 } /* Generic.Output */ 17 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 18 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 20 | .highlight .gt { color: #0040D0 } /* Generic.Traceback */ 21 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 22 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 23 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 24 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */ 25 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #B00040 } /* Keyword.Type */ 27 | .highlight .m { color: #666666 } /* Literal.Number */ 28 | .highlight .s { color: #BA2121 } /* Literal.String */ 29 | .highlight .na { color: #7D9029 } /* Name.Attribute */ 30 | .highlight .nb { color: #008000 } /* Name.Builtin */ 31 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #880000 } /* Name.Constant */ 33 | .highlight .nd { color: #AA22FF } /* Name.Decorator */ 34 | .highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ 35 | .highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 36 | .highlight .nf { color: #0000FF } /* Name.Function */ 37 | .highlight .nl { color: #A0A000 } /* Name.Label */ 38 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 39 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ 40 | .highlight .nv { color: #19177C } /* Name.Variable */ 41 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 43 | .highlight .mf { color: #666666 } /* Literal.Number.Float */ 44 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */ 45 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */ 46 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */ 47 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ 48 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */ 49 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 50 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ 51 | .highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 52 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ 53 | .highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 54 | .highlight .sx { color: #008000 } /* Literal.String.Other */ 55 | .highlight .sr { color: #BB6688 } /* Literal.String.Regex */ 56 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ 57 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */ 58 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ 59 | .highlight .vc { color: #19177C } /* Name.Variable.Class */ 60 | .highlight .vg { color: #19177C } /* Name.Variable.Global */ 61 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */ 62 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ 63 | -------------------------------------------------------------------------------- /media/css/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | author:cho 3 | site:http://pagecho.com 4 | css-flie-last-update:2012.5.19 5 | */ 6 | ::-webkit-scrollbar-track-piece { 7 | background-color: #EEE; 8 | border-radius: 0; 9 | -webkit-border-radius: 0; 10 | } 11 | 12 | ::-webkit-scrollbar { 13 | width: 16px; 14 | height: 8px; 15 | } 16 | 17 | ::-webkit-scrollbar-thumb { 18 | height: 50px; 19 | background-color: #DDD; 20 | border-radius: 4px; 21 | -webkit-border-radius: 4px; 22 | outline: 2px solid #EEE; 23 | outline-offset: -2px; 24 | border: 2px solid #EEE; 25 | } 26 | 27 | ::-webkit-scrollbar-thumb:hover { 28 | height: 50px; 29 | background-color: #40AA52; 30 | border-radius: 4px; 31 | -webkit-border-radius: 4px; 32 | } 33 | 34 | img { 35 | border: 0; 36 | } 37 | 38 | ::selection { 39 | color: #fff; 40 | background-color: #40AA52; 41 | text-shadow: none; 42 | } 43 | 44 | ::-moz-selection { 45 | color: #fff; 46 | background-color: #40AA52; 47 | text-shadow: none; 48 | } 49 | 50 | * { 51 | margin: 0; 52 | padding: 0; 53 | } 54 | 55 | input { 56 | outline: none; 57 | } 58 | 59 | textarea { 60 | outline: none; 61 | } 62 | 63 | .clear { 64 | clear: both; 65 | } 66 | 67 | body { 68 | line-height: 180%; 69 | font-size: 12px; 70 | font-family: 'Microsoft Yahei', Verdana, Arial, Helvetica, sans-serif; 71 | text-align: center; 72 | color: #333; 73 | margin: 0; 74 | } 75 | 76 | body, 77 | .hover { 78 | background: #eeeeee; 79 | } 80 | 81 | #menu ul .current a { 82 | color: #40aa52; 83 | /*background:url(images/menu-current.png) no-repeat center 28px;*/ 84 | } 85 | 86 | div, 87 | form, 88 | img, 89 | ul, 90 | ol, 91 | li, 92 | dl, 93 | dt, 94 | dd { 95 | border: 0; 96 | text-align: left; 97 | margin: 0; 98 | padding: 0; 99 | } 100 | 101 | h1, 102 | h2, 103 | h3, 104 | h4, 105 | h5, 106 | h6 { 107 | font-weight: 400; 108 | margin: 0 auto; 109 | padding: 0; 110 | } 111 | 112 | table, 113 | td, 114 | tr, 115 | th { 116 | font-size: 12px; 117 | } 118 | 119 | li { 120 | list-style-type: none; 121 | } 122 | 123 | .hover { 124 | position: absolute; 125 | width: 80px; 126 | display: block; 127 | left: 45px; 128 | top: 17px; 129 | } 130 | 131 | .clear { 132 | clear: both; 133 | } 134 | 135 | blockquote, 136 | .archivetitle { 137 | /*background:url(images/quote.png) no-repeat bottom right;*/ 138 | background-color: #e2e2e2; 139 | padding: 0.5em 1em; 140 | ; 141 | border-radius: 3px 3px 3px 3px; 142 | -webkit-border-radius: 3px 3px 3px 3px; 143 | -moz-border-radius: 3px; 144 | color: #555; 145 | margin: 15px 0 10px 0; 146 | text-shadow: none; 147 | border: 1px solid #ccc; 148 | border-left: 0.4em solid #bbb; 149 | } 150 | 151 | blockquote code { 152 | margin: 0; 153 | border: 0; 154 | } 155 | 156 | h2.archivetitle { 157 | margin: 0 0 20px 0; 158 | } 159 | 160 | ul, 161 | li { 162 | list-style: none; 163 | } 164 | 165 | a { 166 | color: #40aa52; 167 | text-decoration: none; 168 | } 169 | 170 | a:hover { 171 | color: #40aa52; 172 | } 173 | 174 | form, 175 | embed { 176 | display: inline; 177 | margin: 0; 178 | padding: 0; 179 | } 180 | 181 | #wrap { 182 | position: relative; 183 | table-layout: fixed; 184 | word-break: break-all; 185 | margin: 0 auto; 186 | width: 930px; 187 | min-height: 300px; 188 | display: inline-block; 189 | padding: 0 5px 0 5px; 190 | 191 | } 192 | 193 | #bottombar { 194 | height: 120px; 195 | margin-top: -200px; 196 | } 197 | 198 | #header { 199 | position: relative; 200 | margin: 40px 20px 0 20px; 201 | padding: 0 0 20px 0; 202 | border-bottom: 1px solid #ddd; 203 | height: 46px; 204 | } 205 | 206 | #blog_title { 207 | float: left; 208 | } 209 | 210 | #header #blog_title h1 a { 211 | font-size: 52px; 212 | color: #40aa52; 213 | height: 55px; 214 | overflow: hidden; 215 | display: block; 216 | line-height: 52px; 217 | font-family: impact, 'Microsoft Yahei'; 218 | } 219 | 220 | #header #blog_title h1 b { 221 | background: #40aa52; 222 | color: white; 223 | font-style: normal; 224 | font-weight: 500; 225 | } 226 | 227 | .subtitle { 228 | margin-left: 22px; 229 | } 230 | 231 | #menu { 232 | color: black; 233 | margin: 25px 5px 0 0; 234 | text-shadow: none; 235 | overflow: hidden; 236 | height: 42px; 237 | float: right; 238 | } 239 | 240 | #menu ul { 241 | overflow: hidden; 242 | float: left; 243 | } 244 | 245 | #menu ul li { 246 | float: left; 247 | } 248 | 249 | #menu ul li a { 250 | /*text-transform:uppercase;*/ 251 | font-size: 14px; 252 | padding: 0 15px 30px 15px; 253 | height: 12px; 254 | color: black; 255 | display: block; 256 | } 257 | 258 | #menu ul li a:hover { 259 | color: black; 260 | } 261 | 262 | #menu ul .current a:hover { 263 | color: black; 264 | } 265 | 266 | .menu-rss { 267 | background: url(../img/rss.png) no-repeat right 2px; 268 | } 269 | 270 | .head-search input { 271 | padding: 5px 5px 5px 30px; 272 | border: 1px solid #CBCBCB; 273 | line-height: 16px; 274 | /*background:#F7F7F7 url(images/sb.png) no-repeat 10px 7px;*/ 275 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset; 276 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset; 277 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset; 278 | -o-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset; 279 | border-radius: 25px; 280 | -moz-border-radius: 25px; 281 | -webkit-border-radius: 25px; 282 | -o-border-radius: 25px; 283 | width: 197px; 284 | } 285 | 286 | #content { 287 | float: left; 288 | /*width:618px;*/ 289 | padding: 0 20px 0 20px; 290 | margin-top: 25px; 291 | } 292 | 293 | .sidebar { 294 | float: right; 295 | width: 266px; 296 | overflow: hidden; 297 | margin-top: 22px; 298 | } 299 | 300 | .sidebar-fixed { 301 | width: 265px; 302 | float: right; 303 | border-left: 1px solid #DDD; 304 | } 305 | 306 | .post { 307 | clear: both; 308 | position: relative; 309 | } 310 | 311 | .postunder { 312 | clear: both; 313 | position: relative; 314 | margin: 10px 0 10px; 315 | } 316 | 317 | .date { 318 | color: #333; 319 | text-transform: uppercase; 320 | font-family: Georgia, serif; 321 | font-weight: normal; 322 | text-shadow: 1px 1px 0 #ddd; 323 | width: 80px; 324 | height: 30px; 325 | float: left; 326 | margin: 4px 10px 0 0; 327 | padding: 0 10px 0 0; 328 | border-right: 1px solid #ddd; 329 | } 330 | 331 | .date .day { 332 | font-size: 30px; 333 | float: left; 334 | line-height: 56px; 335 | margin-top: -14px; 336 | color: #40aa52; 337 | font-weight: 800; 338 | } 339 | 340 | .post .date .month { 341 | font-size: 12px; 342 | position: relative; 343 | top: -4px; 344 | width: 35px; 345 | float: right; 346 | } 347 | 348 | .date .year { 349 | font-size: 12px; 350 | position: relative; 351 | top: -12px; 352 | width: 35px; 353 | float: right; 354 | } 355 | 356 | .post h2 a { 357 | color: #40aa52; 358 | } 359 | 360 | .post h2 a:hover { 361 | color: #555; 362 | } 363 | 364 | .post h2 { 365 | padding: 7px 0 0 0; 366 | } 367 | 368 | .post h2, 369 | #comments h4 { 370 | font-size: 18px; 371 | color: #40aa52; 372 | text-decoration: none; 373 | font-weight: normal; 374 | } 375 | 376 | #comments h4 { 377 | height: 28px; 378 | } 379 | 380 | #comments #response { 381 | border-bottom: 1px solid #ddd; 382 | } 383 | 384 | .post h3 { 385 | color: #40aa52; 386 | margin-top: 8px; 387 | border-left: solid 5px #40aa52; 388 | padding-left: 15px; 389 | } 390 | 391 | .post .blue { 392 | font-family: 'Courier New', 'Microsoft Yahei', Helvetica, sans-serif; 393 | white-space: pre-wrap; 394 | background-color: #eaf7ff; 395 | } 396 | 397 | .post .con ul { 398 | margin: 5px 0; 399 | } 400 | 401 | .post .con li { 402 | list-style-type: none; 403 | min-height: 20px; 404 | line-height: 1.4em; 405 | padding: 4px 0px; 406 | margin-left: 1.1em; 407 | } 408 | 409 | .post .con ul li { 410 | list-style: disc inside; 411 | } 412 | 413 | .post .con ol li { 414 | list-style: decimal inside; 415 | } 416 | 417 | .page .post .con ul li { 418 | list-style: none; 419 | } 420 | 421 | .page .post .con ol li { 422 | list-style: none; 423 | } 424 | 425 | .post .con .oddli { 426 | -webkit-transition: background .3s linear; 427 | -moz-transition: background .3s linear; 428 | -o-transition: background .3s linear; 429 | transition: background .3s linear; 430 | } 431 | 432 | .post .info { 433 | line-height: 22px; 434 | padding: 10px 0 0 10px; 435 | color: #666; 436 | text-transform: uppercase; 437 | float: right; 438 | } 439 | 440 | .post .con .tags ul { 441 | margin: 0; 442 | } 443 | 444 | .tags { 445 | overflow: auto; 446 | margin: 12px 0 0 0; 447 | } 448 | 449 | .post .tags ul li { 450 | float: left; 451 | list-style-type: none; 452 | margin-right: 9px; 453 | padding: 0 3px 0 0; 454 | /*background:url(images/tags.png) no-repeat right -25px;*/ 455 | } 456 | 457 | .post .tags ul li a { 458 | /*background:url(images/tags.png) no-repeat 0 0px;*/ 459 | float: left; 460 | height: 19px; 461 | line-height: 17px; 462 | color: white; 463 | padding: 0 4px 0 7px; 464 | white-space: nowrap; 465 | font-size: 12px; 466 | } 467 | 468 | .bicolumn ul li { 469 | text-transform: uppercase; 470 | } 471 | 472 | .post .pageinfo { 473 | height: 4px; 474 | margin-top: 12px; 475 | /*background:url(images/post_h2.gif) top no-repeat;*/ 476 | position: relative; 477 | padding: 2px 0 0; 478 | } 479 | 480 | .post .info span a { 481 | color: #666; 482 | } 483 | 484 | .post .intro { 485 | font-size: 14px; 486 | margin: 10px 3px; 487 | } 488 | 489 | .post .intro p { 490 | text-align: justify; 491 | text-justify: inter-ideograph; 492 | padding: 5px 0; 493 | } 494 | 495 | .post p.read-more { 496 | /*background:url(images/icons.gif) 0 -315px no-repeat;*/ 497 | padding-left: 17px; 498 | font-size: 12px; 499 | } 500 | 501 | .post .intro p img { 502 | max-width: 600px; 503 | } 504 | 505 | .post .con { 506 | font-family: 'Microsoft Yahei', Verdana, Arial, Helvetica, sans-serif; 507 | color: #555; 508 | padding: 18px 0 30px 0; 509 | } 510 | 511 | .post .con img { 512 | -moz-border-radius: 3px; 513 | -webkit-border-radius: 3px; 514 | border-radius: 3px; 515 | max-width: 600px; 516 | padding: 5px; 517 | border: solid 1px #ddd; 518 | } 519 | 520 | .post .con img { 521 | max-width: 600px; 522 | } 523 | 524 | .post .con .about-img { 525 | vertical-align: middle; 526 | margin-right: 5px; 527 | width: 16px; 528 | height: 16px; 529 | } 530 | 531 | .imgtitle { 532 | position: absolute; 533 | margin: -41px 0 0 12px; 534 | color: 535 | /*#11648A*/ 536 | #fff; 537 | font-size: 11px; 538 | } 539 | 540 | .imgtitle em { 541 | font-style: normal; 542 | } 543 | 544 | .box { 545 | background: url(images/ico-com.png) 3px 3px no-repeat; 546 | padding-left: 20px; 547 | height: 20px; 548 | line-height: 20px; 549 | color: #40aa52; 550 | position: relative; 551 | margin: 0 20px 8px 13px; 552 | } 553 | 554 | .place { 555 | background: url(images/icons.gif) 3px -222px no-repeat; 556 | padding-left: 20px; 557 | height: 18px; 558 | line-height: 18px; 559 | margin: 38px 0 0; 560 | position: absolute; 561 | right: 335px; 562 | } 563 | 564 | .post .con p { 565 | text-align: justify; 566 | text-justify: inter-ideograph; 567 | padding: 8px 0; 568 | /*text-indent:2em;*/ 569 | } 570 | 571 | .post .con div p { 572 | text-align: justify; 573 | text-justify: inter-ideograph; 574 | padding: 0; 575 | text-indent: 0; 576 | } 577 | 578 | .post .con p.imgc { 579 | text-align: center; 580 | } 581 | 582 | .post .con p a { 583 | color: #40aa52; 584 | text-decoration: none; 585 | } 586 | 587 | .post .con p.more a { 588 | margin: 0; 589 | } 590 | 591 | .post .con p a:hover { 592 | text-decoration: underline; 593 | } 594 | 595 | code { 596 | /*margin: 0px 3px; 597 | padding: 3px 6px;*/ 598 | margin: 0 0.5em; 599 | padding: 0.1em 0.5em; 600 | white-space: nowrap; 601 | border: 1px solid #CCCCCC; 602 | background-color: #E2E2E2; 603 | border-radius: 3px; 604 | } 605 | 606 | .post .con pre code { 607 | display: block; 608 | padding: 0.5em 1em; 609 | margin: 1em 0; 610 | border: 1px solid #CCCCCC; 611 | background: #E2E2E2; 612 | font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif; 613 | /*overflow: auto; 614 | max-height: 500px;*/ 615 | line-height: 18px; 616 | white-space: pre-wrap; 617 | word-wrap: break-word 618 | } 619 | 620 | ol.page-navigator { 621 | color: #666; 622 | list-style: none; 623 | font-size: 12px; 624 | line-height: 30px; 625 | font-family: "Lucida Grande", Verdana, "Bitstream Vera Sans", Arial, sans-serif; 626 | margin: -10px auto 0 auto; 627 | text-align: center; 628 | } 629 | 630 | #comments ol.page-navigator { 631 | float: right; 632 | margin-top: -31px; 633 | height: 20px; 634 | } 635 | 636 | ol.page-navigator li { 637 | display: inline; 638 | margin: 0 5px 0 0; 639 | } 640 | 641 | #comments ol.page-navigator li { 642 | margin: 0 0 0 5px; 643 | } 644 | 645 | ol.page-navigator li a { 646 | text-decoration: none; 647 | padding: 5px 9px; 648 | } 649 | 650 | ol.page-navigator li.current a { 651 | border-bottom: 3px #40aa52 solid; 652 | } 653 | 654 | ol.page-navigator li a:hover { 655 | border-bottom: 3px #40aa52 solid; 656 | } 657 | 658 | .under { 659 | clear: both; 660 | border: 1px #ddd dashed; 661 | font-size: 12px; 662 | margin: 10px 0; 663 | padding: 5px 10px; 664 | } 665 | 666 | .under a { 667 | color: #616161; 668 | } 669 | 670 | #postnavi { 671 | overflow: hidden; 672 | margin: 0 0 20px; 673 | } 674 | 675 | #postnavi .next { 676 | float: right; 677 | } 678 | 679 | .related { 680 | margin: 10px 10px 0 15px; 681 | } 682 | 683 | .related h4 { 684 | height: 25px; 685 | line-height: 25px; 686 | border-bottom: 1px #d0d4c8 solid; 687 | font-size: 12px; 688 | padding-left: 10px; 689 | background: #f0f7e2; 690 | } 691 | 692 | .related ul { 693 | padding: 5px 0; 694 | } 695 | 696 | .related li { 697 | height: 25px; 698 | line-height: 25px; 699 | border-bottom: 1px #d0d4c8 dashed; 700 | /*background:url(images/ico-1.gif) 5px 11px no-repeat;*/ 701 | padding-left: 15px; 702 | } 703 | 704 | .related li span { 705 | float: right; 706 | font-size: 11px; 707 | color: #999; 708 | } 709 | 710 | .block { 711 | margin: 0 0 10px 10px; 712 | padding: 0 0 0 12px; 713 | display: block; 714 | zoom: 1; 715 | overflow: hidden; 716 | } 717 | 718 | .sidebar .block h3 { 719 | color: #40aa52; 720 | text-shadow: #fff 2px 2px 0; 721 | height: 25px; 722 | line-height: 25px; 723 | font-size: 14px; 724 | padding-left: 5px; 725 | } 726 | 727 | .sidebar .block li.rc_item { 728 | background: none; 729 | display: inline-block; 730 | border-bottom: 1px #d0d4c8 dashed; 731 | margin-bottom: 5px; 732 | padding: 0 0 5px; 733 | } 734 | 735 | .sidebar .block.feed_form ul { 736 | display: inline-block; 737 | padding: 5px; 738 | } 739 | 740 | .sidebar .block.feed_form li { 741 | float: left; 742 | margin-right: 5px; 743 | background: none; 744 | padding: 0; 745 | } 746 | 747 | .sidebar .block.comment div { 748 | display: inline; 749 | } 750 | 751 | .sidebar .block.comment li { 752 | width: 284px; 753 | height: 21px; 754 | overflow: hidden; 755 | } 756 | 757 | .sidebar .block.comment li span { 758 | padding: 0 8px 0 0; 759 | } 760 | 761 | .sidebar .bicolumn ul li { 762 | float: left; 763 | width: 64px; 764 | } 765 | 766 | .sidebar .links ul, 767 | .sidebar .block-s ul { 768 | margin-right: -30px; 769 | overflow: auto; 770 | } 771 | 772 | .sidebar .links ul li { 773 | float: left; 774 | width: 104px; 775 | margin-right: 20px; 776 | border-bottom: 1px dashed #AAA; 777 | } 778 | 779 | .sidebar .block-s ul li { 780 | margin-right: 19px; 781 | border-bottom: 1px dashed #AAA; 782 | } 783 | 784 | .block-s { 785 | max-height: 120px; 786 | overflow: hidden; 787 | margin-right: -30px; 788 | } 789 | 790 | #footer { 791 | padding: 20px 20px 41px 20px; 792 | display: block; 793 | } 794 | 795 | .foot, 796 | #foot-menu { 797 | position: relative; 798 | margin: 0 auto; 799 | } 800 | 801 | .foot { 802 | border-top: 1px #E3E3E3 solid; 803 | } 804 | 805 | .foot #gotop { 806 | float: right; 807 | } 808 | 809 | .foot .copy, 810 | .foot #gotop { 811 | margin-left: 0px; 812 | padding-top: 8px; 813 | } 814 | 815 | #errorbox { 816 | margin: 10px 80px 10px 85px; 817 | } 818 | 819 | .post .con .oddli { 820 | padding: 6px 10px; 821 | } 822 | 823 | #comment_form { 824 | display: block; 825 | padding: 20px 10px 0 0; 826 | padding-right: 200px; 827 | overflow: hidden; 828 | position: relative; 829 | } 830 | 831 | .ie6show { 832 | height: 3px; 833 | display: none; 834 | _display: block; 835 | } 836 | 837 | .col2, 838 | .col1 { 839 | padding: 0; 840 | margin: 0; 841 | /*background:url(images/commentbox-bg.png) no-repeat;*/ 842 | } 843 | 844 | .col1 { 845 | width: 194px; 846 | float: left; 847 | padding: 0 5px 0; 848 | margin-left: -205px; 849 | left: 205px; 850 | position: relative; 851 | overflow: hidden; 852 | background-position: right top; 853 | } 854 | 855 | .col2 { 856 | width: 100%; 857 | height: auto; 858 | float: left; 859 | position: relative; 860 | background-position: 0 0; 861 | } 862 | 863 | #comment_form textarea { 864 | width: 95%; 865 | height: 124px; 866 | padding: 10px; 867 | overflow: auto; 868 | margin: 0; 869 | line-height: 17px; 870 | font-family: Verdana, 'Microsoft Yahei', Arial, Helvetica, sans-serif; 871 | color: #222; 872 | height: 102px; 873 | width: 88%; 874 | } 875 | 876 | .comments ol li { 877 | margin: 0 0 1em; 878 | } 879 | 880 | input#author, 881 | input#mail, 882 | input#url, 883 | textarea#comment { 884 | height: 13px; 885 | } 886 | 887 | input#author, 888 | input#mail, 889 | input#url { 890 | color: #333; 891 | font-size: 12px; 892 | padding: 4px 10px 4px 40px; 893 | line-height: 12px; 894 | } 895 | 896 | .com { 897 | position: relative; 898 | } 899 | 900 | .com p { 901 | margin: 0; 902 | } 903 | 904 | .addcomment { 905 | width: 26px; 906 | height: 25px; 907 | background-position: 0 -124px; 908 | position: absolute; 909 | left: 0; 910 | } 911 | 912 | ol.comment-list { 913 | position: relative; 914 | } 915 | 916 | ol.comment-list, 917 | ol.comment-list ol, 918 | div.comment-box, 919 | div.comment-box ol { 920 | list-style: none; 921 | margin: 0; 922 | } 923 | 924 | 925 | ol.comment-list li { 926 | overflow: hidden; 927 | margin: 0; 928 | padding: 10px 0 0 0; 929 | } 930 | 931 | div.comment-box { 932 | overflow: hidden; 933 | margin: 10px 0 0; 934 | overflow: auto; 935 | } 936 | 937 | ol.comment-list li .comment-reply { 938 | float: right; 939 | } 940 | 941 | ol.comment-list li .comment-reply a { 942 | font-size: 11px; 943 | border: none; 944 | color: #aaa; 945 | } 946 | 947 | .comment-children { 948 | padding-left: 20px; 949 | /*64px*/ 950 | /*background:url(images/menu-current.png) no-repeat 11px -17px;*/ 951 | } 952 | 953 | .comment-reply a { 954 | margin-top: -200px; 955 | } 956 | 957 | .comment-meta { 958 | padding: 0 0 0 65px; 959 | color: #999; 960 | font-size: 12px; 961 | } 962 | 963 | .avatar { 964 | background: #fff; 965 | padding: 1px; 966 | border: 1px #ddd solid; 967 | } 968 | 969 | .comment-author { 970 | float: left; 971 | display: block; 972 | text-align: center; 973 | margin: 5px 0 0 0; 974 | width: 48px; 975 | } 976 | 977 | .fn a { 978 | color: #40aa52; 979 | height: 16px; 980 | overflow: hidden; 981 | } 982 | 983 | .fn a:hover { 984 | color: #555; 985 | } 986 | 987 | cite.fn { 988 | font-style: normal; 989 | font-size: 12px; 990 | color: #40aa52; 991 | padding-right: 7px; 992 | } 993 | 994 | #comment_form textarea, 995 | input#author, 996 | input#mail, 997 | input#url, 998 | textarea#comment, 999 | .post .con .oddli { 1000 | -moz-box-sizing: border-box; 1001 | -webkit-box-sizing: border-box; 1002 | -ms-box-sizing: border-box; 1003 | box-sizing: border-box; 1004 | border: solid 1px #E8E8E8; 1005 | -moz-border-radius: 4px; 1006 | -webkit-border-radius: 4px; 1007 | -o-border-radius: 4px; 1008 | -ms-border-radius: 4px; 1009 | -khtml-border-radius: 4px; 1010 | border-radius: 4px; 1011 | background: #F9F9F9; 1012 | -moz-box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5); 1013 | -webkit-box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5); 1014 | -o-box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5); 1015 | box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5); 1016 | } 1017 | 1018 | .comment-parent { 1019 | border-top: solid 1px #E8E8E8; 1020 | } 1021 | 1022 | .comment-child { 1023 | border-top: solid 1px #E8E8E8; 1024 | } 1025 | 1026 | .comment-p { 1027 | margin-left: 64px; 1028 | overflow: hidden; 1029 | padding: 3px 0 10px 0; 1030 | position: relative; 1031 | } 1032 | 1033 | .post .con .oddli { 1034 | padding: 6px 10px; 1035 | } 1036 | 1037 | ol.comment-list li .respond { 1038 | padding: 5px 0; 1039 | } 1040 | 1041 | .respond .cancel-comment-reply a { 1042 | height: 22px; 1043 | display: block; 1044 | float: right; 1045 | border: none; 1046 | color: #aaa; 1047 | font-size: 12px; 1048 | } 1049 | 1050 | #comment_form label { 1051 | float: left; 1052 | position: absolute; 1053 | margin: 0 0 0 10px; 1054 | color: #555; 1055 | font-size: 12px; 1056 | margin-top: 3px; 1057 | display: block; 1058 | } 1059 | 1060 | #comment_form label .required { 1061 | color: #C04E37; 1062 | } 1063 | 1064 | #comment_form .text { 1065 | width: 100%; 1066 | } 1067 | 1068 | #comment_form p { 1069 | margin-bottom: 8px; 1070 | } 1071 | 1072 | .submit { 1073 | font-size: 12px; 1074 | width: 100%; 1075 | border: none; 1076 | margin-top: 2px; 1077 | font-family: Verdana, 'Microsoft Yahei', Arial, Helvetica, sans-serif; 1078 | color: #fff; 1079 | height: 22px; 1080 | display: block; 1081 | font-size: 12px; 1082 | border: none; 1083 | font-family: 'Microsoft Yahei', Verdana, Arial, Helvetica, sans-serif; 1084 | color: white; 1085 | display: block; 1086 | background: #959595; 1087 | -moz-border-radius: 4px; 1088 | -webkit-border-radius: 4px; 1089 | -o-border-radius: 4px; 1090 | -ms-border-radius: 4px; 1091 | -khtml-border-radius: 4px; 1092 | border-radius: 4px; 1093 | } 1094 | 1095 | .submit:hover { 1096 | color: white; 1097 | background: #DC2509; 1098 | } 1099 | 1100 | .form .go, 1101 | .display-none { 1102 | display: none; 1103 | } 1104 | 1105 | .navigation .nav-previous, 1106 | #postnavi .prev { 1107 | float: left; 1108 | } 1109 | 1110 | .post .con, 1111 | .lab { 1112 | line-height: 1.8; 1113 | font-size: 14px; 1114 | } 1115 | 1116 | .sidebar .block ul, 1117 | .sidebar .block.categories ul, 1118 | .sidebar .block#tag_cloud p { 1119 | padding: 5px; 1120 | } 1121 | 1122 | .sidebar .block.comment li a, 1123 | #respond #commentform p { 1124 | padding: 0; 1125 | } 1126 | 1127 | ol.comment-list li .comment-reply a:hover, 1128 | .respond .cancel-comment-reply a:hover { 1129 | color: #444; 1130 | } 1131 | 1132 | #foot-menu ul { 1133 | margin: 5px 0; 1134 | } 1135 | 1136 | #foot-menu li { 1137 | display: inline; 1138 | margin: 0 5px; 1139 | } 1140 | 1141 | .div-line { 1142 | border-bottom: 1px solid #DDD; 1143 | height: 1px; 1144 | text-indent: -9999px; 1145 | margin: 0 0 8px 0; 1146 | } 1147 | 1148 | .post h4 { 1149 | color: #40aa52; 1150 | margin-top: 8px; 1151 | border-left: solid 5px #40aa52; 1152 | padding-left: 15px; 1153 | } 1154 | 1155 | .rc-item { 1156 | padding: 2px 0; 1157 | } 1158 | 1159 | .rc-item .rc-info, 1160 | .rc-item .rc-excerpt { 1161 | margin-top: -2px; 1162 | margin-left: 44px; 1163 | } 1164 | 1165 | .rc-item .rc-timestamp { 1166 | margin-left: 8px; 1167 | font-size: 10px; 1168 | color: #999; 1169 | } 1170 | 1171 | .rc-item .avatar { 1172 | display: inline; 1173 | float: left; 1174 | } 1175 | 1176 | .post .douban li { 1177 | list-style: none outside none; 1178 | float: left; 1179 | width: 80px; 1180 | padding: 0; 1181 | } 1182 | 1183 | .post .douban li img { 1184 | width: 70px; 1185 | height: 100px; 1186 | } 1187 | 1188 | .post .wall { 1189 | line-height: 18px; 1190 | overflow: hidden; 1191 | text-align: left; 1192 | } 1193 | 1194 | .post .wall li { 1195 | list-style: none outside none; 1196 | float: left; 1197 | width: 178px; 1198 | padding: 0; 1199 | } 1200 | 1201 | .post .wall li a { 1202 | border: 1px solid #CBCBCB; 1203 | border-radius: 2px 2px 2px 2px; 1204 | box-shadow: 0 0 2px #EEE; 1205 | color: #999; 1206 | display: block; 1207 | height: 42px; 1208 | margin: 4px; 1209 | overflow: hidden; 1210 | padding: 4px 4px 4px 44px; 1211 | position: relative; 1212 | text-decoration: none; 1213 | } 1214 | 1215 | .post .wall li a, 1216 | .post-text .wall li a:hover strong { 1217 | background-color: #F7F7F7; 1218 | background-image: 0; 1219 | } 1220 | 1221 | .post .wall li a:hover, 1222 | .post .wall li strong:hover { 1223 | color: #47AFD5; 1224 | } 1225 | 1226 | .post .wall li a img { 1227 | border-radius: 2px 2px 2px 2px; 1228 | float: left; 1229 | height: 36px; 1230 | margin: 0 8px 0 -40px; 1231 | width: 36px; 1232 | padding: 2px; 1233 | } 1234 | 1235 | .post .wall li a em { 1236 | color: #666; 1237 | font-style: normal; 1238 | margin-right: 10px; 1239 | } 1240 | 1241 | .post .wall li a strong { 1242 | color: #DDD; 1243 | font: bold 14px/16px microsoft yahei; 1244 | position: absolute; 1245 | right: 6px; 1246 | text-align: right; 1247 | top: 5px; 1248 | width: 40px; 1249 | } 1250 | 1251 | .post .wall li a div.active-bg { 1252 | width: 106px; 1253 | height: 6px; 1254 | _font-size: 0; 1255 | margin: 10px 0 0 11px; 1256 | background: #DFDFDF; 1257 | border-radius: 3px 3px 3px 3px; 1258 | } 1259 | 1260 | .post .wall li a div.active-degree { 1261 | background: #009DFF; 1262 | width: 12px; 1263 | height: 6px; 1264 | _font-size: 0; 1265 | border-radius: 3px 3px 3px 3px; 1266 | } 1267 | 1268 | .page { 1269 | padding-bottom: 30px !important; 1270 | padding-top: 20px !important; 1271 | width: 890px !important; 1272 | } 1273 | 1274 | .fir { 1275 | float: left; 1276 | position: relative; 1277 | width: 563px; 1278 | } 1279 | 1280 | .sec { 1281 | float: right; 1282 | margin: 0 12px 0 0; 1283 | position: relative; 1284 | width: 240px; 1285 | } 1286 | 1287 | .disk-left { 1288 | float: left; 1289 | position: relative; 1290 | width: 130px; 1291 | border-right: 1px solid #DDDDDD; 1292 | } 1293 | 1294 | .disk-rigth { 1295 | margin: 0 0 0 135px; 1296 | padding: 0 0 0 5px; 1297 | } 1298 | 1299 | .disk-left ol li a, 1300 | .disk-rigth ol li a { 1301 | font-size: 14px; 1302 | line-height: 180%; 1303 | text-decoration: none; 1304 | } 1305 | 1306 | .disk-left ol li a { 1307 | padding: 15px 26px; 1308 | text-align: center; 1309 | } 1310 | 1311 | .disk-rigth ol li a { 1312 | text-align: left; 1313 | } 1314 | 1315 | .page-bg { 1316 | background: none repeat scroll 0 0 #CC4F27; 1317 | color: white; 1318 | display: inline; 1319 | font-family: 'Passion One', impact, Verdana, Arial, Helvetica, sans-serif; 1320 | font-size: 32px; 1321 | height: 30px; 1322 | letter-spacing: 3px; 1323 | line-height: 30px; 1324 | padding: 3px 88px 3px 20px; 1325 | position: absolute; 1326 | right: 0; 1327 | top: 169px; 1328 | z-index: 2; 1329 | } 1330 | 1331 | #s_d li { 1332 | margin-bottom: 1em; 1333 | } 1334 | 1335 | #s_d li a { 1336 | line-height: 25px; 1337 | font-size: 14px; 1338 | color: #40aa52; 1339 | } 1340 | 1341 | #s_d li img { 1342 | float: right; 1343 | } 1344 | 1345 | #s_d li p b { 1346 | color: #C00; 1347 | } 1348 | 1349 | #s_d li span { 1350 | color: green; 1351 | } 1352 | 1353 | #s_d li.s_m a { 1354 | padding-right: 1em; 1355 | } 1356 | 1357 | #header-comments { 1358 | position: relative; 1359 | margin: 5px 20px 0 20px; 1360 | padding: 0 0 5px 0; 1361 | border-bottom: 1px solid #ddd; 1362 | } 1363 | 1364 | #header-comments ul { 1365 | overflow: hidden; 1366 | float: left; 1367 | } 1368 | 1369 | #header-comments ul li { 1370 | float: left; 1371 | list-style: none; 1372 | } 1373 | 1374 | .prev_and_next { 1375 | font-size: 14px; 1376 | } 1377 | 1378 | .prev_and_next a { 1379 | color: #40AA52; 1380 | } 1381 | 1382 | .prev_and_next div { 1383 | line-height: 30px; 1384 | } 1385 | 1386 | .prev_and_next div span { 1387 | font-weight: normal; 1388 | color: #666; 1389 | margin-left: 10px; 1390 | font-size: 12px; 1391 | } 1392 | 1393 | .download { 1394 | margin: 10px 0px; 1395 | padding: 15px 15px 15px 70px; 1396 | font-size: 12px; 1397 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); 1398 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); 1399 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); 1400 | border-radius: 5px; 1401 | -webkit-border-radius: 5px; 1402 | -moz-border-radius: 5px; 1403 | -khtml-border-radius: 5px; 1404 | /*background:url(images/download.png) no-repeat 20px 50% #EFEFEF;*/ 1405 | border: 1px solid #ddd; 1406 | color: #999; 1407 | } 1408 | 1409 | .download a { 1410 | color: #CC4F27 !important; 1411 | } 1412 | 1413 | .download b { 1414 | padding: 0px; 1415 | margin: 0px; 1416 | background: none; 1417 | font-weight: bold; 1418 | border-radius: 0px; 1419 | -moz-border-radius: 0px; 1420 | } 1421 | 1422 | #clickload { 1423 | display: none; 1424 | background: #40AA52; 1425 | color: #FFF; 1426 | text-align: center; 1427 | overflow: hidden; 1428 | position: fixed; 1429 | table-layout: fixed; 1430 | word-break: break-all; 1431 | left: 50%; 1432 | margin-left: -115px; 1433 | padding: 5px; 1434 | width: 220px; 1435 | top: 0; 1436 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); 1437 | zoom: 1; 1438 | z-index: 999; 1439 | } 1440 | 1441 | .mod_lost_child { 1442 | width: auto; 1443 | } 1444 | 1445 | .fir ul li a { 1446 | color: #40aa52; 1447 | padding-left: 1em; 1448 | } 1449 | 1450 | .douban-list ul li { 1451 | width: 80px; 1452 | float: left; 1453 | list-style: none outside none; 1454 | } 1455 | 1456 | .douban-list ul li img { 1457 | width: 70px; 1458 | height: 100px; 1459 | border: solid 1px #DDD; 1460 | } 1461 | 1462 | .flickr, 1463 | .instagram { 1464 | margin-top: 5px; 1465 | } 1466 | 1467 | .flickr ul li { 1468 | width: 276px; 1469 | float: left; 1470 | list-style: none outside none; 1471 | } 1472 | 1473 | .flickr ul li img { 1474 | width: 256px; 1475 | /* height: 100px;*/ 1476 | border: solid 1px #DDD; 1477 | } 1478 | 1479 | .instagram ul li { 1480 | float: left; 1481 | list-style: none outside none; 1482 | } 1483 | 1484 | .instagram ul li img { 1485 | border: solid 1px #DDD; 1486 | } 1487 | 1488 | .avater { 1489 | width: 760px; 1490 | margin: auto; 1491 | } 1492 | 1493 | .avater pre { 1494 | font-family: "Lucida Console", monospace; 1495 | font-size: 9pt; 1496 | margin: auto 10px; 1497 | color: #40AA52; 1498 | float: left; 1499 | line-height: 12px; 1500 | } 1501 | 1502 | #nprogress .bar { 1503 | background: #40aa52; 1504 | } -------------------------------------------------------------------------------- /media/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/media/img/favicon.png -------------------------------------------------------------------------------- /media/img/rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likebeta/blog/4fea9f8c71b247eda0b82ac4a45963a0c24b4bdb/media/img/rss.png -------------------------------------------------------------------------------- /media/js/base.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function($){ 2 | // /*oneBit = new OneBit('../usr/plugins/BinjooKit/1bit/1bit.swf'); 3 | // oneBit.ready(function() { 4 | // oneBit.specify('color', '#40AA52'); 5 | // oneBit.specify('playerSize', '10'); 6 | // oneBit.specify('analytics', true); 7 | // oneBit.apply('a.mp3'); 8 | // });*/ 9 | //go top 10 | $("a#gotop").click(function(){$("html,body").animate({scrollTop:"0px"},600);return false}); 11 | // //email显示 12 | // $(".myemail").click(function(){var d="9527.eu.org";var f="gmail.com";var e=d+"@"+f;$(this).hide();setTimeout(function(){var g=$(".myemail");g.next().hide();g.text(e);g.attr("href","mailto:"+e).unbind("click");g.fadeIn(2000)},1)}); 13 | // //网盘 14 | // /*$(".disk-left ol li a").click(function() { 15 | // //var v = $(this).attr("class"); 16 | // $(".disk-rigth ol").hide(100).empty(); 17 | // var d = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=" + this.href + "/rss.xml&num=100&callback=?"; 18 | // $.getJSON(d, 19 | // function(e) { 20 | // $(e.responseData.feed.entries).each(function(g, j) { 21 | // var l = j.title, 22 | // h = j.link, 23 | // f = j.content; 24 | // $(".disk-rigth ol").append("
  • " + l + "
  • ") 25 | // }); 26 | // $(".disk-rigth ol").slideDown(300) 27 | // }); 28 | // return false 29 | // }) 30 | // */ 31 | // //新窗口打开 32 | // $("#content .post .con a:not(a[rel=nofollow], a[href^=javascript], a[class=more]), #comments .comment-list a[rel*=nofollow]").attr({ 33 | // target:"_blank" 34 | // }); 35 | // //loading... 36 | // $('a:not(a[href^="javascript"], a[href^="https"], a[target="_blank"], a[href*="#"])').click(function(e){ 37 | // if(e.which == 2){ 38 | // return true; 39 | // }else{ 40 | // $('#clickload').slideDown(200); 41 | // } 42 | // }); 43 | }); 44 | NProgress.configure({ showSpinner: false, minimum: 0.1 }); 45 | NProgress.start(); 46 | $(window).load(function() { 47 | NProgress.done(true); 48 | $('.fade').removeClass('out'); 49 | }); 50 | -------------------------------------------------------------------------------- /photo.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Photo 3 | layout: page 4 | photo: true 5 | --- 6 | 7 |
    8 |
    9 |
    10 |

    instagram

    11 |
    12 |
      13 |
      14 |
      15 |

      flickr

      16 |
      17 |
      18 |
      19 |
      20 | 21 | 51 | -------------------------------------------------------------------------------- /read.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Read 3 | layout: page 4 | read: true 5 | --- 6 | 7 |
      8 |
      9 |
      10 |
      11 |
      12 |
      13 |
      14 |
      15 |
      16 | 17 | 23 | -------------------------------------------------------------------------------- /resume.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Resume 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tags.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: tags 3 | layout: page 4 | --- 5 | 6 |
      7 |
      8 | {% for tag in site.tags %} 9 |

      {{ tag[0] }}

      10 |
        11 | {% for post in tag[1] %} 12 |
      • 13 | 14 | {{ post.title }} 15 |
      • 16 | {% endfor %} 17 |
      18 | {% endfor %} 19 |
      20 |
      21 | 27 | -------------------------------------------------------------------------------- /wish.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Wish 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------