├── .gitignore ├── CNAME ├── Gemfile ├── LICENSE ├── README.md ├── _config.yml ├── _data ├── links.yml ├── nav.yml └── sites.yml ├── _drafts ├── 2013-07-31-hello-world.md ├── 2013-07-31-welcome-to-jekyll.markdown ├── 2013-08-20-jquery-study-1.md ├── 2013-08-26-resume.md ├── 2013-08-31-chatroom.md ├── 2013-09-03-mongodb.md ├── 2013-09-06-forum.md ├── 2013-11-19-write-git.md ├── 2013-12-22-write-A-forum.md ├── 2014-01-07-for-person-know-me.md ├── 2014-1-21-amd-bundle.md ├── 2014-4-12-treat-people-like-girl.md ├── 2014-5-18-objc-start.md ├── 2015-1-1-resume.md ├── generator-and-async.md ├── jianli.md └── mianshiti.md ├── _layouts ├── default.html ├── post.html └── resume.html ├── _posts ├── 2013-07-27-nginx-1.md ├── 2013-07-28-nginx-2.md ├── 2013-07-31-hello-world.md ├── 2013-08-01-use-jekyll.md ├── 2013-08-03-jekyll-summary.md ├── 2013-08-04-nginx-strtype.md ├── 2013-08-06-nginx-learn.md ├── 2013-08-09-nginx-hello-world.md ├── 2013-08-10-nginx-handler.md ├── 2013-08-10-nginx-set.md ├── 2013-08-12-file-description.md ├── 2013-08-13-socket.md ├── 2013-08-17-linux-study.md ├── 2013-08-24-how-to-write-resume.md ├── 2013-08-24-jquery-handwrite-1.md ├── 2013-08-25-semantic-web.md ├── 2013-08-25-web-developper-resume.md ├── 2013-09-06-no-topic.md ├── 2013-09-08-luntan.md ├── 2013-09-09-sql-so-much.md ├── 2013-11-10-Im-weak-out.md ├── 2013-11-15-goto-beijing.md ├── 2013-12-09-css-grid.md ├── 2013-12-21-harmony-generator.md ├── 2013-12-27-compat-IE6.md ├── 2013-12-28-why-koa-so-cool.md ├── 2014-01-05-fuck-mysql.md ├── 2014-02-01-easy-fuck-gfw.md ├── 2014-02-22-understand-data-in-jquery.md ├── 2014-02-25-simple-amd-loader.md ├── 2014-03-01-I-promise-I-resolve-v2.md ├── 2014-03-01-simple-mvvm.md ├── 2014-03-16-tdd.md ├── 2014-03-19-css-counter.md ├── 2014-03-21-mvvm-bugs.md ├── 2014-03-24-worksum-eval-dom.md ├── 2014-04-01-lushichuanshuo-1.md ├── 2014-04-02-lushichuanshuo-2.md ├── 2014-08-13-lua-nginx.md ├── 2014-09-08-useful-nginx-fragment.md ├── 2014-09-11-cmder.md ├── 2014-09-14-ie6-support-method.md ├── 2014-09-21-why-I-like-guy-without-semicolon.md ├── 2014-09-29-print-anything-in-as3.md ├── 2014-1-12-I-promise-I-resolve.md ├── 2014-1-22-img-bottom-3-5px.md ├── 2014-1-8-what-can-i-yield.md ├── 2014-10-09-start-simple-life.md ├── 2014-11-09-learn-c-from-zero-1.md ├── 2014-11-15-photoshop-01-select.md ├── 2014-11-19-autoproxy-rule.md ├── 2014-11-20-docker-start.md ├── 2014-4-12-compiler-1.md ├── 2014-4-23-new-orm.md ├── 2014-4-5-simple-web-component.md ├── 2014-4-7-gentoo-install-1.md ├── 2014-6-17-lua-c-module-hello-world.md └── 2014-7-15-keep-code-clean.md ├── about.html ├── categories.html ├── css ├── main.css ├── normalize.css ├── pygments.css ├── pygments.css.bak ├── reset.css ├── style.css └── syntax.css ├── index.html ├── links.html ├── sites.html └── tags.html /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | _posts/2013-08-26-resume.md 3 | nohup 4 | Gemfile.lock 5 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | bg.biedalian.com 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | gem 'github-pages' 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 chunpu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | blog 2 | ==== 3 | 4 | 5 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | name: 叫我小通就好 2 | markdown: redcarpet 3 | highlighter: pygments 4 | gems: 5 | - jemoji 6 | redcarpet: 7 | extensions: 8 | - tables 9 | - autolink 10 | static: http://fimg.qiniudn.com/ 11 | -------------------------------------------------------------------------------- /_data/links.yml: -------------------------------------------------------------------------------- 1 | - name: Mriiiron 2 | blog: http://mriiiron.sykeval.org/ 3 | 4 | - name: vczh 5 | blog: http://www.cppblog.com/vczh/ 6 | 7 | - name: yutingzhao 8 | blog: http://yutingzhao.com/ 9 | 10 | - name: Belleve Invis 11 | blog: http://typeof.net/ 12 | 13 | - name: 樱宝宝 14 | blog: http://www.xuanmingyi.com/ 15 | 16 | - name: chaojiwudi 17 | blog: http://www.chaojiwudi.com/ 18 | 19 | - name: yuange 20 | blog: http://hi.baidu.com/yuange1975 21 | 22 | - name: 死月 23 | blog: http://xcoder.in/ 24 | 25 | - name: Hjin 26 | blog: http://huangj.in/ 27 | -------------------------------------------------------------------------------- /_data/nav.yml: -------------------------------------------------------------------------------- 1 | - href: 2 | title: home 3 | 4 | - href: tags.html 5 | title: tags 6 | 7 | - href: about.html 8 | title: about 9 | 10 | - href: links.html 11 | title: links 12 | 13 | - href: sites.html 14 | title: sites 15 | -------------------------------------------------------------------------------- /_data/sites.yml: -------------------------------------------------------------------------------- 1 | - name: tech 2 | notes: 编程技术 3 | links: 4 | - name: Hacker News 5 | url: https://news.ycombinator.com/ 6 | notes: HN 7 | 8 | - name: v2ex 9 | url: http://www.v2ex.com/ 10 | notes: 程序员论坛 11 | 12 | - name: reddit 13 | url: http://www.reddit.com/ 14 | notes: 互联网资讯 15 | 16 | - name: tutsplus 17 | url: http://tutsplus.com/ 18 | notes: 技术学习 19 | 20 | - name: startup news 21 | url: http://news.dbanotes.net/ 22 | notes: 类HN网站,大feng维护 23 | 24 | - name: tea 25 | url: http://tea.tisiwi.com/ 26 | notes: 类HN网站 27 | 28 | - name: art 29 | notes: 前端&设计 30 | links: 31 | - name: Taobao UED 32 | url: http://ued.taobao.org/blog/ 33 | notes: 淘宝UED 34 | 35 | - name: behance 36 | url: http://www.behance.net/ 37 | notes: 国外站 38 | 39 | - name: 大软坊 40 | url: http://app.hustonline.net/ 41 | notes: 各种软件集合 42 | 43 | - name: thx 44 | url: http://thx.alibaba-inc.com/ 45 | notes: thx 46 | 47 | - name: MDN 48 | url: https://developer.mozilla.org/zh-CN/ 49 | notes: 前端查询 50 | 51 | - name: Medium 52 | url: https://medium.com 53 | notes: really cool 54 | 55 | - name: html5rocks 56 | url: http://www.html5rocks.com/ 57 | notes: promise site... 58 | 59 | - name: cool site 60 | notes: 酷站 61 | links: 62 | - name: cloudup 63 | url: https://cloudup.com/ 64 | notes: share video & photo 65 | -------------------------------------------------------------------------------- /_drafts/2013-07-31-hello-world.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 尝试一下jekyll! 4 | tag: 5 | - life 6 | - github 7 | --- 8 | 9 | 我觉得jekyll真棒啊,这是一个测试. 10 | 11 | 我是用了 `redcarpet` 这个markdown解析器, 据说是`Github flavored markdown` 12 | 13 | 现在我们来看下效果.注意,在_config.yml中的markdown值为`redcarpet` 14 | 15 | ```javascript 16 | function() { 17 | var love = true; 18 | if (love == true) { 19 | console.log("my love is " + love); 20 | } 21 | } 22 | ``` 23 | 24 | It works! 25 | 26 | -------------------------------------------------------------------------------- /_drafts/2013-07-31-welcome-to-jekyll.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Welcome to Jekyll!" 4 | date: 2013-07-31 07:35:12 5 | categories: jekyll update 6 | --- 7 | 8 | You'll find this post in your `_posts` directory - edit this post and re-build (or run with the `-w` switch) to see your changes! 9 | To add new posts, simply add a file in the `_posts` directory that follows the convention: YYYY-MM-DD-name-of-post.ext. 10 | 11 | Jekyll also offers powerful support for code snippets: 12 | 13 | {% highlight ruby %} 14 | def print_hi(name) 15 | puts "Hi, #{name}" 16 | end 17 | print_hi('Tom') 18 | #=> prints 'Hi, Tom' to STDOUT. 19 | {% endhighlight %} 20 | 21 | Check out the [Jekyll docs][jekyll] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll's GitHub repo][jekyll-gh]. 22 | 23 | [jekyll-gh]: https://github.com/mojombo/jekyll 24 | [jekyll]: http://jekyllrb.com 25 | -------------------------------------------------------------------------------- /_drafts/2013-08-20-jquery-study-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: jQuery初步介绍 4 | tags: 5 | - jQuery 6 | - js 7 | --- 8 | 9 | chainable 10 | 11 | .show().hide(); 12 | 13 | $('div').draggable(); 14 | 15 | why $('document').ready(); not window.onload = function() 16 | 17 | $('div').click() we can add so many but how to delete 18 | 19 | short => $(function) 20 | 21 | $.map(array, fn); // oo? 不污染array 22 | 23 | 函数式编程 24 | 25 | each 26 | ---------- 27 | 28 | $.each(arr, function() {alert(this)}) // value 29 | 30 | $.each(dict, function(k, v){}) 31 | 32 | return what 33 | 34 | $ doms has each function 35 | 36 | 37 | event 38 | ---- 39 | change, onclick moveover 40 | 41 | 触发条件 42 | 43 | 疑问? document.querySelectors? 44 | 45 | $对象是否可呼吸 46 | 47 | 最难得不分 this的环境 48 | 49 | why css 50 | 51 | because we can handle nodelist and css hash 52 | 53 | 嵌套 54 | 55 | $("div", "ul") 56 | 57 | 尝试输出所有function的this环境 58 | 59 | $('div').onclick(function() { 60 | $('ul', $(this)) ...this is click ul 相对选择器 61 | 62 | css table:gt(3):lt(2) this is css? 63 | 64 | $('select :selected') ?? 没空格 why? 65 | }) 66 | 67 | 68 | 69 | css selector 70 | ----- 71 | :header => h1 - h6 72 | 73 | :input => input textarea select button 74 | 75 | :text => input[type=text] 76 | 77 | :password => input[type=password] 78 | 79 | 还有:radio :checkbox :image 80 | 81 | attr 82 | ------- 83 | removeAttr => display! 84 | 85 | 创建节点! 86 | ------- 87 | var link = $('baidu') 88 | $('div').append(link); 89 | 90 | $('wqqwwdq') will return what 91 | 92 | 删除节点 93 | ---- 94 | remove(); 95 | 96 | 如何从$ dom中选择dom remove 会返回被删除节点 97 | 98 | $('div').click(function() { 99 | $(this).text(xxx) 100 | }); 101 | 102 | dom replace 103 | 104 | replaceWith 105 | 106 | 包裹 107 | wrap() 108 | 109 | 110 | filter! 111 | ---- 112 | 113 | $('div').has('p') 114 | $('div').not('.myClss') 115 | $('div').filter('.myClass') 116 | 117 | $('div').find('h3').eq(2).html('Hello') 118 | 119 | next(),parent(),children(); 120 | 121 | 122 | .end() // 回退一级 123 | 124 | 125 | $('div').find('h3').eq(2).html('Hello') 126 | .end().eq(4).css(xxx) 127 | 128 | html() html('xx') get and set 129 | 130 | move 131 | --- 132 | 133 | $('div1').insertAfter($('div2')) // return div1 134 | $('div2').after($('div1')) // div2 135 | 136 | appendTo and append 137 | 138 | copy 139 | ---- 140 | 141 | clone 142 | 143 | 小工具 144 | --- 145 | 146 | trim() 147 | 148 | bind('click mouseover', function(){}) 149 | 150 | return false可以组织冒泡..厉害 151 | 152 | toggle(function() {}, function() {}); // click? 153 | 154 | css3效果! 155 | ---- 156 | fadeIn, fadeOut, slideDown, slideUp, animate, stop 157 | -------------------------------------------------------------------------------- /_drafts/2013-08-26-resume.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: resume test 4 | --- 5 | 6 | 冯通 | 男 | 1992/6 | 中国科学技术大学本科 7 | 8 | 邮箱: 527653908@qq.com | 电话: 18914114612 9 | 10 | 应聘职位: 前端开发工程师 11 | 12 | IT技能 13 | --- 14 | 15 | ### 前端开发 16 | 17 | - 熟悉__HTML__,深刻理解HTML语义化,擅长使用HTML模板引擎 18 | 19 | - 熟悉__CSS__布局,并擅长使用CSS预编译器 20 | 21 | - 熟悉__Javascript__,熟悉JS面向对象编程 22 | 23 | - 深刻理解__Web语义化__,W3C标准 24 | 25 | - 了解__HTML5__新技术,熟练使用HTML5 API 26 | 27 | - 熟练使用__jQuery__,并了解其原理 28 | 29 | - 熟悉__Ajax__网络编程 30 | 31 | - 熟悉Angular,Backbone等__MVW__框架,深刻理解表现与数据分离 32 | 33 | 34 | ### 后端开发 35 | 36 | - 熟悉__Node.js__网络开发,精通__Express__框架 37 | 38 | - 了解__Nginx__模块开发 39 | 40 | - 熟悉__Perl CGI__编程 41 | 42 | - 熟练使用__Python Django__ 43 | 44 | - 熟悉并深刻理解__HTTP__协议 45 | 46 | 47 | ### Linux 48 | 49 | - 熟悉__Shell__,__Perl__脚本 50 | 51 | - 熟悉域名配置,有集群经验 52 | 53 | - 熟悉__Linux__常用命令 54 | 55 | - 熟悉MongoDB,Redis,MySQL等数据库 56 | 57 | - 熟练使用__vim__,__ssh__等工具 58 | 59 | - 熟练使用__svn__,__git__版本控制 60 | 61 | 62 | ### 规范 63 | 64 | - 认为自己有标准的__编码规范__ 65 | 66 | - 有__持续集成__经验 67 | 68 | - 熟悉__单元测试__ 69 | 70 | 71 | 项目经验 72 | --- 73 | 74 | - 根据新浪微博API开发手机版微博网页 75 | 76 | - 使用Node.js开发百度PCS个人存储的SDK 77 | 78 | - 使用Node.js和Web前端技术独立开发markdown文本生成博客网站工具 79 | 80 | - 使用HTML5技术实现在线实时Markdown编辑器 81 | 82 | - 使用Node.js开发简单易用的类Express框架 83 | 84 | - 使用Node.js和Redis开发聊天室应用 85 | 86 | - 使用Express和MongoDB开发简易论坛 87 | 88 | 89 | 90 | 工作经验 91 | --- 92 | 93 | - 从2012/11月至今在北京般固科技股份有限公司负责产品的__前端__和__后端__开发工作 94 | 95 | 96 | 97 | 其他信息 98 | --- 99 | 100 | - 英语__六级__,阅读文档无障碍 101 | 102 | - 有Android,Java,C,PHP,Erlang等开发经验 103 | 104 | - 平时爱写博客 105 | 106 | > 博客地址1 107 | 108 | > 博客地址2 109 | 110 | - Github地址 111 | 112 | > 113 | -------------------------------------------------------------------------------- /_drafts/2013-08-31-chatroom.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 聊天室 4 | --- 5 | 6 | 这次想玩下jquery+express+redis 7 | 8 | 想了一下做个聊天室好了 9 | 10 | 做前先要确定redis的数据结构,由于redis的数据结构很少,互相比较一下就知道什么好什么不好了 11 | 12 | 首先是每个房间的名字是key,可以这么写`room:hello`,redis习惯用分号,貌似没什么特殊含义,我很想用点 13 | 14 | 房间的值就是其timeline,由于是有顺序的,因此必然是list 15 | 16 | 不过每条说话都是至少有三个属性,说话的人,说话的时间,说话的内容 17 | 18 | redis是一维的key value,显然是不能嵌套的,因此我们使用`|`来分隔这三个属性 19 | 20 | 比如`name|time|content`,这样的坏处是结构定死,但如果单独把聊天作为一个key的话,会多了一层逻辑 21 | 22 | 除了房间的数据结构,还有用户的数据结构 23 | 24 | 用户的数据结构可以这么设置 25 | 26 | 首先user_id是一个hash的数据结构,可以这样保存 27 | 28 | ``` 29 | user:000001 => { 30 | passwd: md5(mypasswd), 31 | name: myname, 32 | room: myhome 33 | ... 34 | } 35 | ``` 36 | 37 | 不过这样是不够的,登陆场景中,我们是通过用户名和密码登陆 38 | 39 | 我们需要先从用户名获取id,然后才能对比其密码,因此需要保存一个 40 | 41 | ``` 42 | name => userid 43 | ``` 44 | 45 | 由于name是可以自定义的,我们和userid一样为其加上前缀,防止污染命名空间 46 | 47 | ``` 48 | name:myname => user_id 49 | ``` 50 | 51 | 不过我们也可以将其变为一个hash 52 | 53 | ``` 54 | name2id => { 55 | 'myname': user_id 56 | } 57 | ``` 58 | 59 | 除了name转id,id转name,还需要一个类似session的功能 60 | 61 | 就是我们为其生成一个token的cookie,同时我们也在redis中保存这个token,那用户访问主页的时候光凭token就可以免登陆 62 | 63 | 在服务器端也保存cookie,在我看来就形成了session 64 | 65 | 这里用到redis一个非常碉堡的功能,就是`setex`,只能配置expire,碉堡了 66 | 67 | 数据结构如下 68 | 69 | ``` 70 | token:averycomplextoken => user_id 71 | ``` 72 | 73 | 要注意这里的token可以是任意唯一的值,比如一个十几位的随机数,不过为了以防随机数出现重复,可以在前面加上user_name 74 | 75 | 以上仅仅是登陆,聊天室还需要什么呢? 76 | 77 | 用户还需要一个状态,就是他在哪个聊天室,因为如果仅凭post的url来区分的话,厉害的点的黑客完全可以通过url到处发聊天,而且也无法统计聊天室所在的人数 78 | 79 | 聊天室需要两个主要结构 80 | 81 | ``` 82 | room:xxxx:timeline (list) 83 | room:xxxx:users (set) # 需要使用srem 84 | ``` 85 | 86 | 而用户的hash中还有一个所在的room,这样就差不多了 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /_drafts/2013-09-03-mongodb.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: mongodb做论坛 4 | tags: 5 | - mongodb 6 | --- 7 | 8 | mongodb比redis要强大许多,不过它的体积和占用的内存也特别高 9 | 10 | mongodb是文档型的NoSQL,它的collection类似表,表中是一个一个文档 11 | 12 | 基本操作是 13 | 14 | ``` 15 | show dbs # 显示全部数据库 16 | use test # 使用test数据库 17 | show collections # 显示test中全部collections 18 | ``` 19 | 20 | 对于collection的插入和搜索 21 | 22 | ``` 23 | db.collection.save({ .. }) 24 | db.collection.find() 25 | ``` 26 | 27 | save在我看来就像是向collection数组中push一个对象 28 | 29 | mongodb的巨大优势在于它是schema free的 30 | 31 | 这是什么意思呢,如果是mysql,一个表是哪些表头,早就已经确定了,想要改的话也是一次性全改,无法每一列不同。因此,为了保证全面,mysql必须设置大量的表头,然后存入空来占位 32 | 33 | mongodb则不同,它每个插入的元素都是简单的js对象,可以是数组,时间等随意换,这就是所谓的schema free 34 | 35 | 不过在[mongoose](http://mongoosejs.com/)中,我们还是会定义一个schema,你可能会说,mongoose这样不是脑残么,其实不然,mongoose的schema仅仅是帮助我们过滤通过schema实例化的Model,为其设置默认值,去掉多余的属性,设置其格式,也为了之后的子文档 36 | 37 | 首先是用户的model,在redis中,我们不得不用多个hash互相表示,才能满足一些互相查询的需要,在mongo中实在是省事太多 38 | 39 | ```javascript 40 | new Schema({ 41 | name: {type: String, index: true, unique: true}, 42 | passwd: String, 43 | create_at: {type: Date, default: Date.now}, 44 | update_at: {type: Date, default: Date.now} 45 | }) 46 | ``` 47 | 48 | 可以看到非常简洁,mongoose也为我们提供了很好的model过滤schema,比如name,它的类型是String,它是索引,因为至少在登录的时候我们常常是以此为查询的,unique,我们觉得name应该是不能重复的。在create_at中,类型为时间,默认为当前时间。 49 | 50 | 为什么没有id呢?这是因为在mongodb中如果不定义id,就会有自己生成一个`_id`,这是一个很长的字符,不仅有多个时间戳,还有本机识别号,最后再加上一个自增,保证了不会重复,因此,我们再也不需要为mongodb保存id啦。在mongoose中可以用`mongoose.Schema.ObjectID`表示类型 51 | 52 | 对于token,上次redis的做法显然不够好,因为token是每个页面都需要检查的,如果仅仅是简单的访问都要查询redis的话显然很浪费,而且也对集群化很不利 53 | 54 | 正确的做法是用一个key加密,每次访问都进行解密,并查询是否存在该id(话说还是查询了。。) 55 | 56 | 不过这样的好处至少是不需要保存expires了,但也有问题,如果用户修改cookie保存时间,那就一直登陆了 57 | 58 | 同样的,我们定义一个帖子的model 59 | 60 | ``` 61 | new Schema({ 62 | title: String, 63 | content: String, 64 | author: ObjectID, 65 | reply_count: Number, 66 | visit_count: Number, 67 | create_at: {type: Date, default: Date.now}, 68 | update_at: {type: Date, default: Date.now} 69 | }) 70 | ``` 71 | 72 | 这里并没有什么疑点,需要纠结的就是anthor是保存id还是name,保存name的理由就是我们的一篇文章是显示作者的名字,而不是id,id岂不是还要查询一次?这里只能存放的原因仅仅因为name可以修改 73 | 74 | 我们甚至可以在文中加入category来对其分组,分栏,这样取出某个栏就直接是`find({section: 'xxx'})`就行了,都不用去专门定义一个collection 75 | 76 | 正因为mongo提供强大的搜索,我们不再会纠结比如搜索某个用户发表的主题这种事了 77 | 78 | 另一个重要功能是按时间取出前面n个document。这个无比常用,因为我们经常的按时间查询doc,我们完全可以用sort和limit配合找出合适的值,但每次这样搜索无疑会增加压力,数据库中一个很重要的东西就是即便每秒钟执行一次query,也要比每次请求都执行一次query好 79 | 80 | 因此,不如每过1秒遍历全部帖子的doc,按时间取出一个列表,然后放在js的内存中操作 81 | 82 | 按顺序取在mongo中是用`aggregate` 83 | 84 | ``` 85 | Posts.aggregate({ 86 | $sort: {create_at: 1} 87 | }) 88 | ``` 89 | 90 | 倒叙的话就是设置为`-1`,不过如果要取出前n个呢?我们首先想到使用`$limit`,不过我发现这样的话会直接导致顺序混乱,也就是说才遍历limit个就结束了,根本不会去sort,因此我至今不知道该怎么办 91 | 92 | 但是用mongoose的话可以这么写 93 | 94 | ```javascript 95 | Posts.find() 96 | .sort({create_at: 1}) 97 | .limit(10) 98 | .exec(console.log) 99 | ``` 100 | 101 | 这样就取出前10了,可以这样链式操作的原因是mongoose中每个query函数都返回query对象,而本身mongo中是返回cursor对象 102 | 103 | 104 | 105 | 对于只显示collections的某些值 106 | 107 | ``` 108 | Posts.find({ 109 | {}, 110 | { 111 | name: true, 112 | author: true 113 | } 114 | }) 115 | ``` 116 | 第一个参数完全可以用空对象代替 117 | 118 | mongo自带的$where也非常强大 119 | 120 | ```javascript 121 | Posts.find({ 122 | $where: function() { 123 | if (this.num > 30 && this.num < 40) { 124 | return true 125 | } 126 | } 127 | }, console.log) 128 | ``` 129 | 简直就是强大 130 | 131 | 132 | 还有一个难点是全文搜索,我发现这果然是一个巨难的功能,首先可以用正则,但这样非常慢,也可以用runCommand来搜索,不过貌似不支持中文,还可以配合其他程序一起,不过这样就复杂了,因此就先不管全文搜索了 133 | 134 | 恩,忘了说`mongoose`的强大之处了,先写一个简单的博客与评论schema,并对其save 135 | 136 | ``` 137 | var CommentSchema = mongoose.Schema({ 138 | author: String, 139 | content: String, 140 | post_id: Id 141 | }) 142 | 143 | var PostSchema = mongoose.Schema({ 144 | title: String, 145 | content: String, 146 | author: {type: String, default: 'admin'}, 147 | create_at: {type: Date, default: Date.now}, 148 | num: Number, 149 | comments: [CommentSchema] 150 | }) 151 | var Post = mongoose.model('posts', PostSchema) 152 | var Comment = mongoose.model('comments', CommentSchema) 153 | var comment = new Comment({ 154 | author: 'admin', 155 | content: 'good' 156 | }) 157 | 158 | var post = new Post({ 159 | title: 'xxx', 160 | content: 'qqq', 161 | }) 162 | post.save() 163 | 164 | ``` 165 | 结果是这样的 166 | 167 | ``` 168 | 169 | > db.posts.find() 170 | { "title" : "xxx", "content" : "qqq", "_id" : ObjectId("52258d05cffb16fb63000003"), "comments" : [ ], "create_at" : ISODate("2013-09-03T07:17:25.168Z"), "author" : "admin", "__v" : 0 } 171 | ``` 172 | 173 | 然后我们在save后继续给post中的评论数组中添加数组 174 | 175 | ```javascript 176 | post.save() 177 | // 在save之后 178 | post.comments.push(comment) 179 | ``` 180 | 181 | 结果是这样 182 | 183 | ``` 184 | > db.posts.find() 185 | { "title" : "xxx", "content" : "qqq", "_id" : ObjectId("52258d05cffb16fb63000003"), "comments" : [ ], "create_at" : ISODate("2013-09-03T07:17:25.168Z"), "author" : "admin", "__v" : 0 } 186 | { "title" : "xxx", "content" : "qqq", "_id" : ObjectId("52258d305c7b1a1a64000003"), "comments" : [ { "_id" : ObjectId("52258d305c7b1a1a64000002"), "content" : "good", "author" : "admin" } ], "create_at" : ISODate("2013-09-03T07:18:08.437Z"), "author" : "admin", "__v" : 0 } 187 | ``` 188 | 189 | 可以看到post和真实的doc完全呼应,js对象变化的同时mongo中也变了,很显然mongoose中的push并不是数组的push函数 190 | 191 | 不过这儿仅仅是举一个例子,真实情况并不会这么做,真实情景是回复的schema中存着`post_id`。显示一篇文章的评论我们只需要检索全部评论满足的`post_id`即可 192 | 193 | -------------------------------------------------------------------------------- /_drafts/2013-09-06-forum.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 论坛实现 4 | --- 5 | 6 | ### 板块功能 7 | 8 | 板块功能最简单的做法是在post schema中加上一个section属性,这样我们取出这个板块只需要用section这个键找即可 9 | 10 | 但这样有如下这几个坏处 11 | 12 | - 无法列出所有板块 13 | 14 | - 无法给板块加上描述,如这个板块是用来干什么的 15 | 16 | - 给板块改名字很难 17 | 18 | 因此,我们必须加入section这个schema,然后在post中引用section的id 19 | 20 | ```javascript 21 | var SectionSchema = new mongoose.Schema({ 22 | name: {type: String, unique: true}, 23 | description: String, 24 | visit_count: {type: Number, default: 0}, 25 | post_count: {type: Number, default: 0}, 26 | reply_count: {type: Number, default: 0}, 27 | score: {type: Number, default: 0}, // for sort 28 | admin: Id 29 | }) 30 | ``` 31 | 32 | 这样就可以干很多事了,比如最火板块,显示访问数,回复数,板块排序,管理者等等 33 | 34 | 注意,标签是不需要的,只需要一个属性 35 | 36 | 37 | -------------------------------------------------------------------------------- /_drafts/2013-11-19-write-git.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 手写git 3 | date: 17:12 2013/11/19 4 | tags: 5 | - git 6 | layout: post 7 | --- 8 | 9 | 准备工作 10 | --- 11 | 12 | 首先要知道git的几个底层命令,这些命令对应函数 13 | 14 | cat-file -p: 将zlib数据变成正常的text,反向函数text压缩函数(还不知道名字) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /_drafts/2013-12-22-write-A-forum.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 做论坛之心不死 4 | data: 9:28 2013/12/22 5 | tags: 6 | - nodejs 7 | - javascript 8 | --- 9 | 10 | 很早前就想做论坛, 不幸的是搁浅了, 现在想来幸好是搁浅了, 当时的技术实在是渣, 正所谓, 士别三日, 当刮目相看, 我现在看我自己一个月前的代码就是一坨大翔 11 | 12 | 总有人没怎么用nodejs就说nodejs没法应付复杂逻辑, 没法用数据库, 但在我看来, 只有node才能真正发挥数据库的速度, 原因也很简单, 它是异步IO. es6的出现使得异步函数不再是噩梦, 让人想想都兴奋, 使得我周日早早来到办公室, 实践论坛制作 13 | 14 | 论坛和博客, 这是两个完全不同重量级的东西, 论坛大概比博客复杂一个维度, 做一个博客大概需要100行, 做一个论坛, 预计要1000行左右, 我建议是没做一个项目前都要预计它的复杂度, 代码量, 不然很难有走到终点的力气 15 | 16 | 这次论坛将参照[小米论坛](http://bbs.xiaomi.cn/)来做(真是小米虐我千百遍, 我待小米如初恋啊), 虽然小米把我拒了, 但论坛绝对是做的一级棒, 特别是刚出来的bbs v5 17 | 18 | 选小米论坛的另一个原因是它非常的复杂, 在首页上每一条都有 19 | 20 | - 浏览量 21 | - 回复量 22 | - 最后回复 23 | - 版块名 24 | 25 | 看到这里我虚了一口气, 也不是很复杂嘛, 比起新浪微博, 复杂度低太多了, 因为新浪微博还要知道每条微博的点赞数, 评论数, 转发数, 我是否收藏, 我是否点赞, 特别是最后两个功能, 想想都复杂 26 | 27 | 所幸小米的收藏, 最后谁回复 等都是在点进去才出现的, 不然复杂度又提升一个档次 28 | 29 | 由于偶完全不懂数据库, 就随意设计数据库结构了.. 30 | 31 | post的schema 32 | 33 | - 标题: title: 34 | - 内容: content 35 | - 作者id: userid 36 | - 板块id: sectionid 37 | - 发表时间: createtime (不想用created_at) 38 | - 修改时间: updatetime 39 | - 最后回复时间: lastreplytime 40 | - 阅读数: readcount 41 | - 回复数: replycount 42 | - 收藏数: collectcount 43 | - 点赞数: upcount 44 | - 是否加精: isdigest 45 | - 是否置顶: istop 46 | - 是否官方: isofficial 47 | - 是否推荐: isrecommend 48 | 49 | 最后那几个是否还能像小米那样有数字来表示权重, 这样如果都是置顶也能分出次序来了. 50 | 51 | comment的schema 52 | 53 | - postid or commentid 54 | - userid 55 | - username 56 | - content 57 | 58 | 59 | mysql学习 60 | --- 61 | 62 | 还是先学习一下mysql吧... 63 | 64 | 0. 登陆mysql 65 | 66 | ```shell 67 | mysql -uroot -p 68 | 输入密码 69 | ``` 70 | 71 | 1. 首先要选择databse 72 | 73 | ```shell 74 | create database testdb; 75 | show databases; # 显示全部 76 | use testdb; 77 | show status; # 显示当前状态, 可以看到是否切换数据库了 78 | ``` 79 | 80 | 2. 建一个表 81 | 82 | ```shell 83 | # 如post table 84 | create table post_table(id bigint primary key, title varchar(20), text content, userid bigint, sectionid bigint, createtime datetime, updatetime datetime, lastreplytime datetime); 85 | ``` 86 | 87 | 3. 插入数据 88 | 89 | ```shell 90 | insert into post_table values(1234, 'title', 'this is content', 4321, 2345, now, now, now); 91 | ``` 92 | 93 | 4. 查询数据(如第二页: 第20-40条) 94 | 95 | ```shell 96 | select * from post_table order by lastreplytime desc limit 20, 20; 97 | ``` 98 | 99 | 5. 关联查询(查20条而且还要通过userid查到username) 100 | 101 | ```shell 102 | select * from user_table, post_table where users.id=posts.userid; 103 | ``` 104 | 105 | 数据库到这儿就结束啦 106 | -------------------------------------------------------------------------------- /_drafts/2014-01-07-for-person-know-me.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 士为知己者死 4 | date: 22:33 14/01/07 5 | tags: 6 | - life 7 | --- 8 | 9 | 最近心态有点不好,甚至有点怀才不遇的感觉(捂脸),分配到的任务都是一些几分钟就可以改好的小事情。我担心其他人是不是认为我能力不行,甚至让公司的后端来做一些前端的活。不过我也乐得自在,每天干完那芝麻大的活就开始和网友扯淡,鼓捣些有趣的东西 10 | 11 | 不过让我伤心的是,大公司的光环在我心中彻底破灭了,后端帮忙做完一个组件后,同事妹子直呼太厉害了,后端和前端都这么强。我做完一个页面,主管表示像实习生做的 12 | 13 | 之所以敢发这种牢骚完全是看了王垠大神的新博文[我和权威的故事](http://www.yinwang.org/blog-cn/2014/01/04/authority/) 14 | 15 | 王垠绝对是我的偶像,在文中,他表示经常找人谈自己的想法,甚至发邮件表示想和那些所谓的牛人聊聊。我想也许很多人都做过类似的事,和他们说出自己的想法,希望得到认可,得到帮助。但通常对方总是装出一副听懂的样子,抑或是直接表示不可行或者根本不想听下去 16 | 17 | 王垠是一个比较极端的人,他就曾经从linux崇拜者的极端走到linux黑的极端,这是我崇拜他的原因,不是因为他是极端主义者,而是他能把自己极端的想法清晰的写出来,又敢于否定自己极端的想法 18 | 19 | 我一直坚定的认为目前的项目从本质上就是错误的,但我同时也赞同"谁吐槽,谁改进"的说法,不过这个项目吐槽点实在太多,我不得不修改bug的同时自己重写这整个项目。当然这完全是自己写着玩,要是这让同事看了,他们多半也会说:这啥玩意儿,你自己玩玩可以,还是要专注项目啊 20 | 21 | 不过leader没错,正如王垠所说,教授不喜欢自己的学生有自己的想法。领导又何尝不是呢,他们当然是喜欢能帮助实现他们自己想法的人,谁又会喜欢一个推翻自己想法的人,谁又肯承认你的水平比他高? 22 | 23 | 在工作中,屡屡被否定自己想法的我,也是越来越多的按着leader的想法来,渐渐的习惯了把自己的想法和质疑咽回去 24 | 25 | 现实总有些残酷,今天听到项目中同事说前端人手不够,而我却闲着专心致志鼓捣es6,感觉心里酸酸的,你一定会说你这么吊为什么不上,我只能说最近真的心态欠佳,很怕别人又说你才新来不熟(ji)悉(shu)业(bu)务(xing) 26 | 27 | 完全业务驱动的公司,很难探讨技术,和他们讨论一些最近火热的动态,他们多半是说没听过啊,反倒是一些又老又极其常识性的问题,他们会讨论上半天。我甚至都觉得当初有点犹豫还进来真的是个错误,我当时犹豫的正是其面试题太过简单,而且面了一会儿就结束了,隐隐觉得不大对劲,来了之后果然是这样。反而他们说我的面试评价是“理解含糊不清”。看着他们漏洞百出的代码,我只能说企业级编程真的连个人作品都不如.很多大公司为了赶进度,甚至不经过n*1小时的面试,只要觉得你确实做过这方面,就直接招进来,越是赶进度的部门员工水平普遍偏低就是这么来的 28 | 29 | “你这样的人我见多了”,这是不少前辈对晚辈说的最多的话,用于警告晚辈不要太跳。如果你有幸碰到一个前辈对你的想法说,“咦,这想法不错啊”,那一定要好好在心底感激他,毕竟赏识你的伯乐,一辈子都很难有几个 30 | 31 | 乔峰和阿朱相识不久,不惜闯入虎穴聚贤庄与众高手过招,愿拿自己性命换神医为阿朱疗伤。起初觉得乔峰实在太过意气用事,现在想来,如果全天下都觉得你是恶魔,只有她坚信你是善良的,她若不在世,自己又何必苟活 32 | 33 | 所以呐,长的丑也有好处,因为100个女生会有99个说你丑,剩下的那个就是自己该去奋斗的目标,反倒是高富帅白富美们,每天都有人说他们好看,难以分辨谁才是自己的心上人 34 | 35 | 步入社会,不必去攀什么高富帅白富美,也不必挤破脑袋混入上流,更不必为了一点虚荣扰乱自己的判断。找一个志同道合的朋友,找一个赏识自己的公司,找一个认可自己的伴儿,足以 36 | -------------------------------------------------------------------------------- /_drafts/2014-1-21-amd-bundle.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | titile: amd bundle 4 | --- 5 | 6 | 转换无非三种 7 | 8 | ### 1. 9 | 10 | ```javascript 11 | define('/var/arr', [], function() { 12 | return [] 13 | }) 14 | 15 | // to 16 | 17 | var arr = []; 18 | ``` 19 | 20 | 非常简单 21 | 22 | ### 2. 23 | 24 | ```javascript 25 | define('core', [], function() { 26 | var jQuery = {} 27 | return jQuery 28 | }) 29 | 30 | // to 31 | 32 | var jQuery = {} 33 | 34 | ``` 35 | 36 | 同样简单 37 | 38 | 39 | ### 3. 40 | 41 | ```javascript 42 | define('foo', ['./core'], function(jQuery) { 43 | jQuery.foo = {} 44 | }) 45 | 46 | // to 47 | 48 | jQuery.foo = {} 49 | 50 | ``` 51 | 52 | 甚至没有return要删 53 | 54 | 55 | ### 4. 56 | 57 | ```javascript 58 | (function(window) { 59 | var Sizzle = {} 60 | // EXPOSE 61 | if (typeof define === 'function' && define.amd) { 62 | define(function() { 63 | return Sizzle 64 | }) 65 | } 66 | // EXPOSE 67 | })(window) 68 | 69 | // to 70 | 71 | (function(window) { 72 | var Sizzle = {} 73 | })(window) 74 | ``` 75 | 注意, 有expose, define就肯定在里面 76 | 也就是把EXPOSE中的东西删掉 77 | 78 | 79 | 80 | 规则一下子就出来了 81 | 82 | 1. 如果只有return语句, 那就是定义 83 | 84 | 2. 否则, 如果是多行且有return, 就去掉return, 取函数部分 85 | 86 | 3. 否则, 如果是多行且没有return, 直接取函数部分 87 | -------------------------------------------------------------------------------- /_drafts/2014-4-12-treat-people-like-girl.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 像对女神那样对待别人 4 | tags: 5 | - life 6 | --- 7 | 8 | 最近发生了一些事, 我才知道自己的社交是那么糟糕, 对此, 我想了很久, 希望改善它. 9 | 其实程序员之间互相看不起, 这是一件再正常不过的事儿了, 但即便这样, 大多数团队依然能一起工作的很好. 10 | 如果我是老板, 我情愿招一个看不起我水平的人, 也不会招一个说啥干啥的人, 因为自负的人在和别人做对比的时候往往都能认真对待自己的代码, 他们也能从别人的代码轻松看出别人的水平, 这时候code review就起到很重要的作用, 互相吐槽, 互相严谨 11 | 12 | 不过这就跑题了, 违背了本文的初衷, 因为如果互相看不起不能变为互相吐槽, 而是直接不经过别人商量直接修改, 往往会让人觉得压抑, 感受到深深的恶意 13 | 14 | 纸牌屋教我们, 笨的人想方设法压制对手, 聪明的人和对手做朋友, 像对女神那样对待别人, 就是改善社交, 尊重他人的基础 15 | 16 | 在自己准备说出很尖锐的话时, 先想一下对方是美女你会这么说嘛? 17 | 18 | 如果女神不知道计算机的一些常识, 你会借机笑话她或者从心里觉得自己比她高一等嘛? 不会的, 你只会耐心的和她讲解, 她没兴趣的话再换个话题 19 | 20 | 如果女神非要买一个大的, 你会因为小的有很多优点去和她辩解嘛, 不会的, 马上掏钱才是大多数人的做法 21 | 22 | 如果女神突然冷落你, 或者说你不行, 你会在心里怒骂"你才不行"嘛? 更不会了, 你只会说: 我错了, 我一定改好好进步 23 | 24 | 待人如待女神, 才能和气生财 25 | -------------------------------------------------------------------------------- /_drafts/2014-5-18-objc-start.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: objective-c初学 4 | tags: 5 | - objc 6 | - ios 7 | --- 8 | 9 | 首先要注意, objc的程序大多是对armv7架构的, 想像C++那样直接用vim, 然后clang编译, 运行, 这是很难办到的, 也就是说, 你必须要有xcode 10 | 11 | `.m`表示implement 12 | `[]` 消息表达式 13 | `id` 表示随便, 即存放一个指针 14 | + 类方法 15 | - 实例方法 16 | 17 | ### @autoreleasepool 18 | 19 | 新建一个模板, 我们知道, 文件的入口就是main.m中的main函数, 里面有个autoreleasepool. 不管用不用ARC(Automatic Reference Counting自动引用记数)都推荐的内存管理方法, [官方说明](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html). 内存的事既然交给了编译器, 那我们也不用去管release啥的, 更不用去深究其原理 20 | 21 | 22 | ### xml storyboard 23 | 24 | ### outlet, action, outlet collection 25 | 26 | 27 | 28 | jsExport.h 29 | -------------------------------------------------------------------------------- /_drafts/2015-1-1-resume.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: resume 3 | --- 4 | 5 | 冯通 | 男 | 中国科学技术大学 6 | 7 | 邮箱: 527653908@qq.com | 电话: 18914114612 8 | 9 | 应聘职位: 全栈工程师 10 | 11 | IT技能 12 | === 13 | 14 | 前端开发 15 | --- 16 | 17 | - 熟悉**HTML**, 深刻理解HTML语义化, 擅长使用HTML模板(**jade**, **ejs**) 18 | 19 | - 熟悉**CSS**布局, 响应式设计, 浏览器兼容, 擅长使用CSS预编译器(**Less**) 20 | 21 | - 擅长**Javascript**, 深刻理解JS面向对象, 函数式等特性 22 | 23 | - 理解**Web语义化**, W3C标准 24 | 25 | - 了解**HTML5**新技术, 熟练使用HTML5 API 26 | 27 | - 精通**jQuery** 28 | 29 | - 熟悉**Ajax**网络编程 30 | 31 | - 熟悉**MVVM框架**, 自制框架实现[TodoMVC](http://chunpu.github.io/mvvm2/demo/todomvc/) 32 | 33 | 34 | 后端开发 35 | --- 36 | 37 | - 熟悉**Node.js**网络开发, 精通**Express**, **Koa**等流行框架, 精通Node.js异步开发 38 | 39 | - 了解**Nginx**模块开发 40 | 41 | - 熟悉Perl CGI编程 42 | 43 | - 熟悉Python Django框架 44 | 45 | - 精通**HTTP**协议 46 | 47 | 48 | Linux 49 | --- 50 | 51 | - 熟悉**Shell**, **Perl**脚本 52 | 53 | - 熟悉**Linux**常用命令 54 | 55 | - 熟练使用**vim**, **ssh**等工具 56 | 57 | - 熟练使用**svn**, **git**版本控制 58 | 59 | 60 | 其他 61 | --- 62 | 63 | - 认为自己有标准的**编码规范** 64 | 65 | - 有详尽的JS**单元测试**和**持续集成**经验 66 | 67 | 68 | 项目经验 69 | === 70 | 71 | - 公司后台复杂表单交互管理页面开发 72 | 73 | - 使用Node.js开发论坛与聊天室 74 | 75 | - 大量前端小项目: 代码编辑器, Promise异步垫片, AMD加载... 76 | 77 | - 大量Node.js小项目: 基于Socket.io对战游戏, markdown博客, 类Express框架... 78 | 79 | - 擅长使用Open API, 使用Node.js开发新浪微博, 人人, 微信等简易客户端 80 | 81 | > 大部分项目都可在我**Github**中找到 82 | 83 | 84 | 其他信息 85 | === 86 | 87 | - 英语**六级**, 阅读文档无障碍 88 | 89 | - 有Android, Erlang, C, PHP, Java等开发经验 90 | 91 | - 平时爱写**博客** 92 | -------------------------------------------------------------------------------- /_drafts/generator-and-async.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | --- 4 | -------------------------------------------------------------------------------- /_drafts/jianli.md: -------------------------------------------------------------------------------- 1 | 如何写一份简历 2 | 3 | 版式 4 | 5 | 学校,pdf word 6 | 7 | github=>(大标题,小标题,列表) 8 | 9 | 关键字加粗,如excel,word技能等 10 | 11 | 突出重点 12 | 13 | 绝不造假(实习时间对不上) 14 | 15 | 绝不造假是基于自信,没必要,没精通就是没精通. 16 | 17 | 好简历稀缺,普通简历泛滥 18 | 19 | 空谈无用,(羽毛球大赛,xx实习) 20 | 21 | 不要ppt,不要html,不要xxx 22 | 23 | 热爱运动即可代替 24 | 25 | 重点 26 | --- 27 | 经验 28 | 29 | 技能(暴露你的能力) 30 | 31 | 技能匹配(相关度) 32 | 33 | 关键字匹配(海投,软件区分.简历必须要定制的) 34 | 35 | 没必要说我爱你们公司,就算你真的很喜欢 36 | 37 | 步骤 38 | 39 | HR删选80% 40 | 41 | 该职位相关删选50% 42 | 43 | 具体查看(github,blog,作品) 44 | 45 | 剩下的才是面试 46 | 47 | 个人资料不要放前面. 48 | 49 | 除非是设计类的,不要封面,不要花里胡哨 50 | 51 | 52 | 可用icon 53 | 54 | 第一块: 职位匹配 55 | 56 | 细节: 57 | --- 58 | 59 | 哪些要写: 姓名,年龄,性别,最近教育信息 60 | 61 | 哪些不要写: 地域,班级,名族,政治面貌(党员要写) 62 | 63 | 要不要放照片..不帅就不要放了. 64 | 65 | 一定要是企业的核心部分.(比如体育大学学策划,小米公司搞网页.) 66 | 67 | 简历不是写出来的,而是用脚走出来的. 68 | 69 | HR20秒查看是否符合岗位需求 70 | 71 | 爱生活爱拉芳 海飞丝去屑 怕上火喝王老吉 72 | 73 | 发邮件怎么发, 74 | 75 | 求职信,有您好,感谢等这样的标准发邮件方式,以及你知道的渠道,比如校友会,内推等 76 | 77 | 标题: 78 | --- 79 | 有格式,最简单 80 | 81 | 没格式: 应聘Web开发工程师_冯通_中科大_18914114612 82 | 83 | 求职邮件 84 | 85 | 86 | 87 | 后面放正文markdown,详细见附件.,附件pdf 88 | 89 | 其他: 我是一个有趣的人,喜欢折腾 90 | -------------------------------------------------------------------------------- /_drafts/mianshiti.md: -------------------------------------------------------------------------------- 1 | (function(window) { 2 | 3 | })(window) 4 | 5 | why window? for gzip 6 | 7 | (function(window, undefined) { 8 | 9 | }) 10 | 11 | why undefine? undefined can be var in old ie 12 | 13 | 14 | function jQuery() { 15 | return new jQuery.fn.init() 16 | } 17 | 18 | jQuery.fn = jQuery.prototype 19 | 20 | jQuery.prototype.init.prototype = jQuery.prototype 21 | 22 | jQuery.get(-1) 23 | 24 | jQuery.eq(-1) 25 | 26 | expando data() 27 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ page.title }} 7 | 8 | 9 | 10 | 15 | 16 | 17 |
18 | 27 |
28 | 29 |
30 | {{ content }} 31 |
32 | 33 |
34 | Chunpu Copyright © 2014 blog.biedalian.com 35 |
36 | 37 | 38 | 39 | 47 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 |

{{ page.title }}

6 | {% for tag in page.tag %} 7 | {% endfor %} 8 | 11 | 14 |
15 | {{ content }} 16 |
17 | 23 | 24 |
25 | 26 | 27 |
28 |
29 | {% if page.previous %} 30 | 31 | {% endif %} 32 |
33 |
34 | {% if page.next %} 35 | 36 | {% endif %} 37 |
38 |
39 |
40 | 41 |
42 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /_layouts/resume.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ page.title }} 7 | 8 | 9 | 10 | 15 | 16 | 17 |
18 | {{ content }} 19 |
20 | 21 |
22 | Chunpu Copyright © 2014 blog.biedalian.com 23 |
24 | 25 | 26 | 27 | 35 | -------------------------------------------------------------------------------- /_posts/2013-07-27-nginx-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 22:46 2013/7/27 3 | title: nginx学习1 4 | layout: post 5 | tags: 6 | - nginx 7 | - c 8 | --- 9 | 10 | 最近看了下nginx源码。有点头大。首先是我没用过nginx,第二是我不会c语言。 11 | 12 | 因此想借着看nginx源码学习下c语言。之所以学习nginx是因为nginx非常实用,而且代码写得好,并且已经有不少的源码分析博客。不会的话至少有个参考。 13 | 14 | nginx有模块这个概念,可以自定义模块,这是入口点。 15 | 16 | nginx模块的基本原理我总结了一下,基本就是靠用函数当参数,在特定地方调用函数。 17 | 18 | 写过js的一定对这个非常熟悉。因为js的cps风格就是不断的用函数做参数进行回调的。 19 | 20 | nginx也可以叫回调,反正也是基于epoll和kqueue的嘛。 21 | 22 | 学习了一下c,发现c实现回调函数是用函数指针的。整个nginx使用模块的方法大概如下 23 | 24 | #include 25 | 26 | void init(char *str) { 27 | printf("init: %s\n\n", str); 28 | } 29 | 30 | void bye(char *str) { 31 | printf("bye: %s\n\n", str); 32 | } 33 | 34 | struct ngx_module_t { 35 | char *name; 36 | int type; 37 | void (*init)(char *); 38 | void (*handle)(char *); 39 | void (*bye)(char *); 40 | } ngx = { 41 | "my_module", 42 | 3, 43 | &init, 44 | NULL, 45 | &bye 46 | }; 47 | 48 | int main() { 49 | if (ngx.init) 50 | ngx.init("welcome"); 51 | printf("I'm handle the request\n"); 52 | if (ngx.handle) 53 | ngx.handle("handle it!\n"); 54 | if (ngx.bye) 55 | ngx.bye("have finished!"); 56 | return 1; 57 | } 58 | 59 | 基本就是说你要给nginx一个struct,里面有你定的type, name啥的,同时要定义你的事件触发函数。 60 | 61 | 因为nginx整个模块是一个数组, 每执行到一个可以触发事件的地方,都会遍历所有模块,也就是那个结构体,然后访问模块结构体中的指定函数,比如刚进来的时候触发init事件,那就遍历所有模块,调用其init的函数。原理很简单。 62 | 63 | 虽然还没看具体代码,不过应该充斥着 64 | 65 | if (ngx.xxx) { 66 | ngx.xxx( ... ) 67 | } 68 | 69 | 这样的代码。 70 | 71 | 话说c的声明,调用实在是太罗嗦了。用c真的会局限人的思维,程序员需要花太多时间在c语言本身上。 72 | 73 | 明天继续,争取写一个hello world模块出来。 74 | -------------------------------------------------------------------------------- /_posts/2013-07-28-nginx-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: nginx学习2 3 | date: 9:29 2013/7/28 4 | layout: post 5 | tags: 6 | - nginx 7 | - c 8 | --- 9 | 10 | 今天尝试写一个模块 11 | 12 | ngx_http_module_t 13 | ------- 14 | 15 | 这里面初始化所有8个成员全部是函数指针,同样是可选的,用NULL放弃使用回调。 16 | 17 | ### create_loc_conf 18 | 19 | 此函数接受的参数是`ngx_conf_t *`, 也就是nginx配置结构体的指针 20 | 21 | 返回结果会被放在`ctx->loc_conf[mi]`中,mi是module index的缩写 22 | 23 | 返回一个有字符串和整数的结构体, 24 | 25 | 作用是告诉总的配置文件, 我需要一个啥结构体, 保存哪些信息 26 | 27 | 这个函数貌似不重要..不管了 28 | 29 | ### merge_loc_conf 30 | 31 | 可以不写,和上面一样,没啥用 32 | 33 | ngx_command_t 34 | ---------- 35 | 36 | struct ngx_command_s { 37 | ngx_str_t name; 38 | ngx_uint_t type; 39 | char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 40 | ngx_uint_t conf; 41 | ngx_uint_t offset; 42 | void *post; 43 | }; 44 | 45 | 其中主要是set这一个回调函数 46 | 47 | set函数给这个模块加上了handler. 48 | 49 | ngx_http_handler_pt handler 50 | 51 | handler函数 52 | ------- 53 | 54 | 核心部分 55 | 56 | 昨天没写出个模块,因为有太多很杂的东西了. 57 | 58 | 其实和大部分web程序一样, handler才是核心内容. 59 | 60 | ngx_http_get_module_loc_conf(r, ngx_http_hi_module)这个函数可以(应该是把配置文件中的信息给r) 61 | 62 | 假设返回结果放到cglcf中了. 63 | 64 | 然后就是设置content-type,这永远都是必须的,注意nginx设置字符串全部是用data和len两个属性. 65 | 66 | 比如 67 | 68 | r->headers_out.content_type.len = sizeof("text/html"); 69 | r->headers_out.content_type.data = (u_char *) "text/html"; 70 | 71 | 当然也要设置状态码. 72 | 73 | r->headers_out.status = NGX_HTTP_OK; // 这当然就是200 74 | 75 | 设置content_length_n, 不得不说我在nodejs和django中并没有发现返回数据的时候要写content-length.我猜这个content_length_n可能并不是http首部content-length.设置长度很简单 76 | 77 | r->headers_out.content_lenght_n = cglcf->ecdata.len; 78 | 79 | 设置buffer. 80 | 81 | b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); 82 | 83 | b里面是什么东西呢,我也看不懂,大概是一些起始和末尾位置,chain位置. 84 | 85 | 设置out, 就是output啦. 86 | 87 | out.buf = b; 88 | out.next = NULL; // out可以是一个buffer chain,这里表示后面没有了 89 | 90 | 调整b的pos地址,指向需要返回字符串的初始位置. 91 | 92 | b->pos = cglcf->ecdata.data; // ecdata是网上抄的例子中的,实际自己取名 93 | 94 | 设置结束地址 95 | 96 | b->last = cglcf->ecdata.data + (cglcf->ecdata.len) 97 | 98 | 可以把buffer放入memory 99 | 100 | b->memory = 1; 101 | b->last_buf = 1; // 这是最后一个buffer,我不知道这跟上面的next = NULL有啥区别 102 | 103 | 104 | 跟上面的发送头部一样先把头部发出去, 头部都存在r->headers_out中 105 | 106 | rc = ngx_http_send_header(r); 107 | 108 | 如果成功的话, 继续发送output 109 | 110 | return ngx_http_output_filter(r, &out); 111 | 112 | 这个filter啥意思呢? 113 | 114 | 其实filter有两个,一个是header filter,在r传进来之前就filter了header. 115 | 116 | 另一个filter就是这个body filter,是传输body的开始函数. 117 | 118 | filter函数是链, 可以把它传给比如gzip这样的filter 119 | 120 | 交给filter, handler的任务就完成了. 121 | 122 | 总结一下 123 | 124 | 1. 先设置头部,必要的有content-type, status, content-length. 125 | 126 | 2. 设置要返回的buffer, 是通过设置buf的pos来定位字符串的. 127 | 128 | 3. 发送头部 129 | 130 | 4. 交给filter 131 | 132 | 明天计划写一个静态文件模块. 133 | 134 | -------------------------------------------------------------------------------- /_posts/2013-07-31-hello-world.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 尝试一下jekyll! 4 | tag: 5 | - life 6 | - github 7 | --- 8 | 9 | 我觉得jekyll真棒啊,这是一个测试. 10 | 11 | 我是用了 `redcarpet` 这个markdown解析器, 据说是`Github flavored markdown` 12 | 13 | 现在我们来看下效果.注意,在_config.yml中的markdown值为`redcarpet` 14 | 15 | ```javascript 16 | function() { 17 | var love = true; 18 | if (love == true) { 19 | console.log("my love is " + love); 20 | } 21 | } 22 | ``` 23 | 24 | It works! 25 | 26 | -------------------------------------------------------------------------------- /_posts/2013-08-01-use-jekyll.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: jekyll学习 4 | tags: jekyll github markdown 5 | --- 6 | 7 | jekyll真的是太棒了,特别是代码显示部分,我指的是jekyll官网的css效果,我直接复制粘贴了他的css文件. 8 | 9 | 一开始我觉得jekyll所有post要求统一命名,比如`2013-08-01-hello-world.md`感觉很蠢.现在觉得挺好的,因为对于一篇随笔,你可能只是要一个时间. 10 | 11 | 我已经在考虑是否要完全使用jekyll写博客了,因为github的pages就是用jekyll渲染的,不用白不用. 12 | 13 | 放弃自己写博客生成是因为已经开始工作,这些东西看起来有点幼稚,而且不再有大量的时间放在自己的兴趣上了.需要赶紧补一下C语言. 14 | 15 | 挑选更纯粹的工具,才能更加高效.下面是学习jekyll的心得, 好的话以后就不自己折腾博客了.. 16 | 17 | 文件夹结构 18 | ------- 19 | 20 | ``` 21 | . 22 | ├── _config.yml 23 | ├── _drafts 24 | | ├── begin-with-the-crazy-ideas.textile 25 | | └── on-simplicity-in-technology.markdown 26 | ├── _includes 27 | | ├── footer.html 28 | | └── header.html 29 | ├── _layouts 30 | | ├── default.html 31 | | └── post.html 32 | ├── _posts 33 | | ├── 2007-10-29-why-every-programmer-should-play-nethack.textile 34 | | └── 2009-04-26-barcamp-boston-4-roundup.textile 35 | ├── _site 36 | └── index.html 37 | ``` 38 | 39 | `_posts`文件夹就是放markdown格式的博客的. 40 | 41 | `_includes`用于放子模版, 一般不需要. 42 | 43 | `_layouts`用于放父模板,默认有`default.html`和`post.html` 44 | 45 | `_sites`是自动生成的,需要用`.gitignore`忽略 46 | 47 | `_drafts`你可以建一个草稿文件夹放还没写完的文章. 48 | 49 | 可以新建其他文件夹,并且像静态服务器那样访问他们, 50 | 比如可以新建一个about文件夹,里面放一个`index.html`放置自己的简历或者自我介绍, 51 | 同样你也可以直接在跟目录下放一个about.html 52 | 我试了下放markdown文件,结果报错了,不知道哪里出了问题. 53 | 54 | _config.yml 55 | --------- 56 | 57 | 配置文件,配置文件完全可以不管,这是非常好的,因为它提供默认值. 58 | 59 | 其中默认的键值pygments是代码高亮,我特别喜欢. 60 | 61 | 不得不重提一下markdown解析器,`markdown: redcarpet`, 这是能像Github-Flavored-Markdown解析出的结果那样.更重要的是code也能用python那种注释来包含,当然也是github的风格.这让我觉得爽极了,我以前的博客代码高亮是靠marked这个插件自己猜的..非常不好. 62 | 63 | jekyll的redcarpet配合highlight样式以及Monokai(sublime默认配色),我觉得已经完美.看起来非常舒服. 64 | 平时上网搜问题,看到别人排版拙鸡的博客和挤在一坨的代码,不满的同时有点小小的优越感.. 65 | 66 | 要注意解析器不能乱写,redcarpet是github自带的.github支持的jekyll插件在列全了,而且有版本号, 本地测试的时候最好也要下一样的版本. 67 | 68 | 其他配置等了解后再补充 69 | 70 | front-matter 71 | ----- 72 | 73 | ``` 74 | --- 75 | layout: post 76 | title: Blogging Like a Hacker 77 | --- 78 | ``` 79 | 80 | 这种放在最前的博客信息我一看就明白,因为我已经也是这样做的,原因是因为单靠ctime,mtime啊来判断时间并不靠谱. 81 | 82 | jekyll的头部信息强制要求是yaml格式的.我觉得这点很棒.规范了格式.可以这么写 83 | 84 | ``` 85 | --- 86 | layout: post 87 | title: Jekyll is Cool 88 | tags: 89 | - jekyll 90 | - github 91 | - blog 92 | categories: 93 | - blog 94 | --- 95 | ``` 96 | 97 | 要注意的是这个头部信息是可选的,可写也可以不写. 98 | 99 | 预设的博客格式属性有如下几个 100 | 101 | - layout: 这个不多说.就是父模板 102 | 103 | - pemalink: 访问该博客的连接, 默认是像这样子`/2013/08/01/hello/world.html` 104 | 105 | - published: boolean类型,默认是true 106 | 107 | - category: 分类 108 | 109 | - categories: 可以是列表,就是属于多个分类. 110 | 111 | - tags: 标签.(说实话我搞不清categories和tags的区别, 觉得他们功能重合了..) 112 | 113 | - date: 日期, 可以覆盖外面的文件名日期, 日期写法很丰富,反正notepad中F5出来的日期是可以用的. 114 | 115 | 文章模板 116 | ----- 117 | 118 | 文章模板是用一个叫Liquid template language做的,初步看来这不是一个全功能模板.不过语法属于大众语法, 119 | {{ page.title }}表示插入, {% some code %}表示执行.没有太多学习成本. 120 | 121 | > 注意我第一次提交的时候发现github,没有更新文章,我还以为是github不自动更新呢, 后来才知道模板没有编译通过 122 | 原因是我在文章中加入了{% %}, 这即便包含在反义符中都是没用的,因为模板解析在markdown解析之前,我只所以能打出来, 123 | 是因为我输入的是`{% %}`, 用的html编码。html编码很简单,在chrome的调试里直接输入 124 | 125 | ```javascript 126 | var code = '%'.charCodeAt(0); // 就能获取%的ascii次序 127 | // html编码就是'&#' + code + ';' 128 | ``` 129 | 所以如果修改文章导致jekyll编译不过, 那原因基本就是模板编译错误 130 | 131 | > {{ }} 字符串插入不会导致模板编译错误,没有的话只会返回空字符串 132 | 133 | > {% %} 语句错了就一定会导致模板编译不过 134 | 135 | jekyll提供的默认变量很多 136 | 137 | ### 大变量site. 138 | 139 | - `site.posts`: 所有博客的hash. 140 | 141 | - `site.pages`: 所有page, 元素的属性page和post应该没啥区别 142 | 143 | - `site.related_posts`: 显示相关联的10个博客,不知道这相关联是怎么取的, 目测是时间.. 144 | 145 | - `site.categories.CATEGORY`: 显示这个分类下的博客列表 146 | 147 | - `site.tags.TAG`: 显示这个标签下的博客列表 148 | 149 | - `post`: site.posts单个值, 有url, title, excerpt等子属性, 注意excerpt就是预览文本,取前面一小段. 150 | 151 | - `page`: 这是针对单个文章的全局变量, 作用等同于post, 同样拥有url, title, excerpt等属性. 152 | 153 | ### Paginator 154 | 155 | 貌似中文叫页码.其中提供了获取上一篇 和 下一篇的功能 156 | 157 | - `paginator.per_page` 158 | 159 | - `paginator.posts` 160 | 161 | - `paginator.total_posts` 162 | 163 | - `paginator.total_pages` 164 | 165 | - `paginator.page` 166 | 167 | - `paginator.previous_page`: 上一页 168 | 169 | - `paginator.previous_page_path`: 上一页路径 170 | 171 | - `paginator.next_page`: 下一页 172 | 173 | - `paginator.next_page_path`: 下一页路径 174 | 175 | 注意, 这个paginator只能在index文件中使用, 坑爹啊. 176 | 177 | paginator原来是总的页数的意思, 可以在_config.yml中设置, 比如 178 | 179 | ```yaml 180 | paginate: 5 181 | ``` 182 | 183 | 那就是5篇文章一页. 184 | 185 | 上一篇和下一篇的路径分别是用`page.previous.url` 和 `page.next.url`获取的. 186 | 187 | jekyll的文档中貌似并没有说这俩个page的自属性. 188 | 189 | 暂时就看到这些文档, 感觉够用了, 剩下的就是继续去了解一下那个模板了. 190 | -------------------------------------------------------------------------------- /_posts/2013-08-03-jekyll-summary.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: jekyll小结 3 | layout: post 4 | tags: 5 | - jekyll 6 | --- 7 | 8 | 又玩了一会jekyll, 感觉挺不错的,但功能不全. 9 | 10 | 首先是因为Liquid这个模板并不是一个全功能的模板.使用起来并不是很舒畅. 11 | 12 | 然后就是它的`Front-matter`,也就是每篇markdown中最开头的头部信息.layout是必须写的,我们无法通过修改_config.yml来设置默认的layout.比如我设置 13 | 14 | ```yaml 15 | layout_defaults: 16 | - 17 | layout: page.html 18 | - 19 | path: _posts 20 | layout: post.html 21 | ``` 22 | 23 | 这使得我每次写文章都要加上`layout: post`这句废话, 尽管我就是在_post文件夹下写的.这不是一个好的设计,而且破坏人们写作的心情,不少人提出了这个问题, 比如这个issue, 作者注意到了却没去实现. 24 | 25 | jekyll允许通过插件来自定义新功能, 可惜github的jekyll是不支持的,这肯定不能支持, 不然写个死循环就要跑坏github的服务器了.所以jekyll虽然很纯净, 但少了一些基本的功能. 26 | 27 | 写完这篇我在手机上阅读时发现有横向滚动条,原来是没有断词 28 | 29 | ```css 30 | word-wrap: break-word; 31 | ``` 32 | 33 | 加上自动断词即可解决. 34 | 35 | 横向滚动条在移动设备的响应式网页上是大忌.话说今天在写media query的css的时候,偶才知道屏幕分辨率不等同于浏览器分辨率 36 | 37 | 浏览器的分辨率通过`window.screen.height`和`window.screen.width`获取. 38 | 39 | 关于设备宽度和浏览器宽度的区别可以参照 40 | 41 | 可以通过`window.devicePixelRatio`获取设备和浏览器像素密度的比例. 42 | 43 | 比如小米2的像素比是2, 小米2的分辨率是`720 x 1280`, 于是它的浏览器分辨率就是`360 x 640`.640 x 960的iphone也是2.但768 x 1024的ipad就是1, 因此用ipad横屏浏览桌面版网页是不会有x轴滑动条的.但ipad3则是2, 因为超过1000的分辨率是没有意义的.这是因为大多数定死宽度的网页都采用940-980px之间的数值.所以不要担心手机分辨率太高用media-query分辨不出来.屏幕越小, 分辨率越大, 则`window.devicePixelRatio`越大, 这样保证了使用viewport的时候字体大小是正常的. 44 | -------------------------------------------------------------------------------- /_posts/2013-08-04-nginx-strtype.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: nginx基本数据类型 3 | layout: post 4 | --- 5 | 6 | 我的参考来自这里 7 | 8 | `ngx_str_t` 9 | ----- 10 | 11 | ```c 12 | typedef struct { 13 | size_t len; 14 | u_char *data; 15 | } ngx_str_t; 16 | ``` 17 | 18 | 声明文件: `core/ngx_string.h` 19 | 20 | 最小的数据结构, 就是一个字符串,跟传统以`\000`来判断字符串结尾不同,`ngx_str_t`通过长度来判断字符串结尾.这样做有什么好处呢? 21 | 22 | - 减少计算字符串长度的操作,不再需要老是用strlen来算长度了. 23 | 24 | - data是指针, 使用的时候指过去就行了, 不需要copy字符串. 25 | 26 | - 坏处是glibc提供原生字符串的api, 使用时需要先吧`ngx_str_t`变成原生字符串才能用,略显啰嗦. 27 | 28 | ### `ngx_str_t`的api 29 | 30 | ```c 31 | ngx_string(str) 32 | 33 | // 本质就是 34 | 35 | #define ngx_string(str) {sizeof(str) - 1, (u_char *)str} 36 | ``` 37 | 38 | 宏定义,构造函数, 通过一个标准字符串构造出一个nginx字符串. 39 | 40 | 只能用来初始化. 41 | 42 | ```c 43 | ngx_str_t str = ngx_string("hello"); 44 | 45 | // error 46 | ngx_str_t str; 47 | str = ngx_string("hello"); 48 | ``` 49 | 50 | 这是因为结构体初始化后不能直接赋值 51 | 52 | 我实在不理解为何要这么做, 直接写有多打几个字么?可能是c开发者都喜欢建立自己的世界观吧. 53 | 54 | ```c 55 | ngx_null_string 56 | ``` 57 | 58 | 宏定义`ngx_str_t`空字符串,也就是`{0, NULL}` 59 | 60 | 61 | ```c 62 | ngx_str_set(&str, text); 63 | 64 | // --- 65 | 66 | define ngx_str_set(&str, text) str->len = sizeof(text) - 1; str->data = (u_char *)text 67 | ``` 68 | 69 | 此为宏定义,str为`ngx_str_t`的指针, 用法是把标准字符串赋值给`ngx_str_t`这个str指针. 70 | 71 | 这个text是常量字符串,而不是指针,否则len永远是3. 72 | 73 | 然后ngx就提供了很多ngx前缀的字符串方法.比如`ngx_atoi`, `ngx_strcmp`等, 不知道这样重复造轮子有啥真正的好处.. 74 | -------------------------------------------------------------------------------- /_posts/2013-08-06-nginx-learn.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: nginx学习日记 3 | layout: post 4 | tags: 5 | - nginx 6 | --- 7 | 8 | 哎,说起这两天nginx的学习, 还是毫无进展, 上次我还吹牛说要写个静态服务器模块, 现在看来纯属扯淡. 9 | 10 | nginx实在是复杂, 一个最简单的模块, 比如就是接管路径访问一个hello吧, 就要至少70多行.相比起express, 不过3行, 实在差距太大. 11 | 12 | 而且不少人说nginx代码写的好,我实在是看不出来,一个函数长的不行,却还是看不出啥意思.相比express的源码, 每次看都觉得酷毙了, 就应该这么写. 13 | 14 | 不过我对nginx有心理障碍也难怪, 几天前我根本不会c, 现在也等于不会, 看起来吃力是必然的. 15 | 16 | 写的太少是最大的问题, nodejs够简单了吧, 那个简单http服务器的例子, 我写了十几遍才能独立一边写对. 17 | 18 | nginx最简单的模块我已经写了两遍了, 离独立写出来还有一段距离, 估计要写个20遍才能独立写出来, 那时候在去看nginx源码吧. 19 | 20 | 总结这次教训, 一口吃不成大胖子[ku] 21 | -------------------------------------------------------------------------------- /_posts/2013-08-09-nginx-hello-world.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Nginx模块开发之最简单的Hello模块 4 | tags: 5 | - nginx 6 | --- 7 | 8 | nginx模块开发并不是那么容易, 从行数上来讲, 淘宝给出的tengine给出的那个所谓hello模块的长度也到了245行, 要想真正独立写出这么多代码, 对于我来说是非常难的. 9 | 10 | 245行, 如果是nodejs, 已经可以写一个比较完善的文件服务器了. 要想完全理解这个hello模块, 有c基础的也怕是要花不少时间, 像我这样没有c经验的, 更是难上加难. 11 | 12 | 我决定写一个真正的hello模块,也就是最最简单的那种,能自己写出来,也算是至少nginx模块开发入门了. 13 | 14 | 这个hello模块作用就是当访问`/test`的时候, 返回一段固定的html代码(一个字符串). 15 | 16 | 此模块一共不到60行, 理解此模块比理解淘宝教程的模块要简单几倍. 17 | 18 | 先上全代码 19 | 20 | ```c 21 | #include 22 | #include 23 | #include 24 | 25 | static char *set(ngx_conf_t *, ngx_command_t *, void *); 26 | static ngx_int_t handler(ngx_http_request_t *); 27 | 28 | static ngx_command_t test_commands[] = { 29 | { 30 | ngx_string("test"), 31 | NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, 32 | set, 33 | NGX_HTTP_LOC_CONF_OFFSET, 34 | 0, 35 | NULL 36 | }, 37 | ngx_null_command 38 | }; 39 | 40 | static ngx_http_module_t test_ctx = { 41 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 42 | }; 43 | 44 | ngx_module_t ngx_http_test_module = { 45 | NGX_MODULE_V1, 46 | &test_ctx, 47 | test_commands, 48 | NGX_HTTP_MODULE, 49 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, 50 | NGX_MODULE_V1_PADDING 51 | }; 52 | 53 | static char *set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 54 | ngx_http_core_loc_conf_t *corecf; 55 | corecf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 56 | corecf->handler = handler; 57 | return NGX_CONF_OK; 58 | }; 59 | 60 | static ngx_int_t handler(ngx_http_request_t *req) { 61 | u_char html[1024] = "

This is Test Page!

"; 62 | req->headers_out.status = 200; 63 | int len = sizeof(html) - 1; 64 | req->headers_out.content_length_n = len; 65 | ngx_str_set(&req->headers_out.content_type, "text/html"); 66 | ngx_http_send_header(req); 67 | 68 | ngx_buf_t *b; 69 | b = ngx_pcalloc(req->pool, sizeof(ngx_buf_t)); 70 | ngx_chain_t out; 71 | out.buf = b; 72 | out.next = NULL; 73 | b->pos = html; 74 | b->last = html + len; 75 | b->memory = 1; 76 | b->last_buf = 1; 77 | 78 | return ngx_http_output_filter(req, &out); 79 | } 80 | ``` 81 | 82 | 这个文件的路径是`src/http/module/ngx_http_test_module.c`. 83 | 84 | 光是放这个是nginx的makefile是不知道的,它不会去编译新增的模块, 还需要在`auto/modules`这个文件中加入 85 | 86 | ```bash 87 | if [ $HTTP_ACCESS = YES ]; then 88 | HTTP_MODULES="$HTTP_MODULES $HTTP_ACCESS_MODULE" 89 | HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS" 90 | fi 91 | # 上面是原有的, 这里才是加上的 92 | 93 | HTTP_MODULES="$HTTP_MODULES ngx_http_test_module" 94 | HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_test_module.c" 95 | ``` 96 | 97 | 98 | auto是用来生成Makefile的很多shell脚本,Nginx没有用那些构建工具来制作自己的Makefile, 而是自己写了大量的shell脚本, 学习这些脚本对于自己的shell编程也是很有帮助的. nginx的编译的生成文件都在`objs`中, 清晰明了, 因此`make clean`也只是调用`rm -rf objs`即可, 非常简洁. 99 | 100 | 总之加上上面两句话, nginx就知道你要新增这个模块了, 顺序应该不是很要紧(其实我是没试过). 101 | 102 | 这样我们的模块依然不起作用, 还需要修改配置文件, nginx启动完全依靠那个`conf/nginx.conf`的配置文件! 103 | 104 | 105 | 106 | ``` 107 | server { 108 | listen 80; 109 | server_name localhost; 110 | 111 | #charset koi8-r; 112 | 113 | #access_log logs/host.access.log main; 114 | 115 | location / { 116 | root html; 117 | index index.html index.htm; 118 | } 119 | location /test { 120 | test; 121 | } 122 | ``` 123 | 124 | 我们在http中的server中加上`location /test`来插入我们的模块. 125 | 126 | 运行之, 在浏览器中访问`你的域名/test`就能看到`This is Test Page`几个大字, 因为是`

`的嘛! 127 | 128 | 解释下这段代码吧. 129 | 130 | ```c 131 | #include 132 | #include 133 | #include 134 | ``` 135 | 136 | 包含三个关键头文件, 这没什么异议, 注意, 我们写的模块基本都是http的. 137 | 138 | ```c 139 | static char *set(ngx_conf_t *, ngx_command_t *, void *); 140 | static ngx_int_t handler(ngx_http_request_t *); 141 | ``` 142 | 143 | 声明两个函数, 这是两个非常重要的函数, 后面主要讲. 144 | 145 | ### command注册 146 | 147 | ```c 148 | static ngx_command_t test_commands[] = { 149 | { 150 | ngx_string("test"), 151 | NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, 152 | set, 153 | NGX_HTTP_LOC_CONF_OFFSET, 154 | 0, 155 | NULL 156 | }, 157 | ngx_null_command 158 | }; 159 | ``` 160 | 161 | 这是定义一个配置命令信息数组(为何是数组暂时还真不知道), 数组最后一个元素都是ngx_null_command. 162 | 163 | 结构体第一个参数尤为重要, 这里是test, 指的是我们在配置文件中输入test(不是路径的`/test`).这样指定后, nginx在读取配置的时候读到test命令, 才会把接管权给我们.也就是把请求转给我们去处理. 164 | 165 | 第二个参数代表我们的模块注册的是http location的命令, 并且接受0个参数.http location当然就是指这个命令触发是跟路径有关的. 166 | 167 | > 事实上大量的模块触发都跟路径相关, 比如php, php就是接管所有后缀是`.php`的location.php的nginx模块配置如下所示 168 | 169 | ``` 170 | location ~ \.php$ { 171 | root /home/www; 172 | fastcgi_pass 127.0.0.1:3344; 173 | fastcgi_index index.php; 174 | fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; 175 | include fastcgi_params; 176 | } 177 | ``` 178 | 179 | 第三个参数是set, 这是一个函数指针,也就是我们一开始声明的两个关键函数中的一个,读到我们注册的`test`这个命令的时候触发的, 我们一般在set中写上托管http请求的handler函数. 180 | 181 | 第四个参数是offset类型, 用来结构体的偏移的, 不再hello模块的讨论范围, loc conf类型就直接是`NGX_HTTP_LOC_CONF_OFFSET`就行. 182 | 183 | 第五个参数就是具体offset的值, 我们这里只有一个命令, 没有参数, 输入0即可. 184 | 185 | 第六个参数NULL即可, 作用未知. 186 | 187 | ### 回调函数 188 | 189 | 写完命令注册, 我们还需要一个context,至于为何叫上下文我也不知道, 但这种把函数作为参数的方法在nodejs中一般叫回调函数,内核程序员喜欢叫它hook, 钩子函数, 我觉得也很形象.但是在hello模块中,我们可以完全不用这些回调机会. 190 | 191 | ```c 192 | static ngx_http_module_t test_ctx = { 193 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 194 | }; 195 | ``` 196 | 197 | nginx一共提供8个回调机会, 具体是什么时候用不在hello模块讨论范围, 这里都设置为NULL即可. 198 | 199 | ### 模块结构体 200 | 201 | 最后写上真正暴露给外面的模块结构体 202 | 203 | ```c 204 | ngx_module_t ngx_http_test_module = { 205 | NGX_MODULE_V1, 206 | &test_ctx, 207 | test_commands, 208 | NGX_HTTP_MODULE, 209 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, 210 | NGX_MODULE_V1_PADDING 211 | }; 212 | ``` 213 | 214 | 其中`NGX_MODULE_V1`和`NGX_MODULE_V1_PADDING`都是宏定义, 不必去管 215 | 216 | 只需知道第二个放上回调函数数组, 第三个是注册命令, 第四个是模块类型即可.后面7个NULL. 217 | 218 | ### set函数 219 | 220 | 前面说到, set函数就是给配置信息挂上托管http请求的handler函数的. 221 | 222 | ```c 223 | static char *set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 224 | ngx_http_core_loc_conf_t *corecf; 225 | corecf = ngx_http_conf_get_module_loc_conf(cf->pool, ngx_http_core_module); 226 | corecf->handler = handler; 227 | return NGX_CONF_OK; 228 | } 229 | ``` 230 | 231 | 返回类型是`char *`,它有两种返回值, 一个是`NGX_CONF_OK`也就是NULL, 另一个是`NGX_CONF_ERROR`也就是`(void *) -1`. 232 | 233 | 里面最重要的就是`corecf->handler = handler`了, 这句话把handler函数挂到corecf的handler属性上. 234 | 235 | ### handler函数 236 | 237 | 这是最重要的函数, nodejs中写http服务器, 完全只要写个handler就行了.nginx却要写前面一堆废话. 238 | 239 | ```c 240 | static ngx_int_t handler(ngx_http_request_t *req) { 241 | char html[1024] = "

This is Test Page

"; 242 | int len = sizeof(html) - 1; 243 | req->headers_out.status = 200; 244 | req->headers_out.content_length_n = len; 245 | ngx_str_set(&req->headers_out.content_type, "text/html"); 246 | ngx_http_send_header(req); 247 | 248 | ngx_buf_t *b; 249 | b = ngx_pcalloc(req->pool, sizeof(ngx_buf_t)); 250 | b->pos = html; 251 | b->last = html + len; 252 | b->memory = 1; 253 | b->last_buf = 1; 254 | ngx_chain_t out; 255 | out.buf = b; 256 | out.next = NULL; 257 | return ngx_http_output_filter(req, &out); 258 | }; 259 | ``` 260 | 261 | 其实主菜才是最直观的, 前面是设置http的返回头部, 后面是设置http body.简单至极.每每写到handler部分都神清气爽, 感觉自己也会用c了.. 262 | 263 | 补充一下. 我在用jekyll写博客的时候又出现的编译错误, 原因是使用了高亮`shell`, 不知道是不是因为没有shell, 反正它居然报错了, 修改成bash后显示正确, 这实在让我费解, 我仅仅是写一个博客而已, 你居然来个编译错误.不支持你就不管呗. jekyll用的液体模板并不能报出模板哪里错了, 总之出错了,不得不用排除法去猜, 让人郁闷. 264 | 265 | 牛逼的是我发现github貌似也使用的`redcarpet`,见github blog 266 | 267 | github的[GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown),支持的高亮语言有这些: 268 | 269 | 非常可惜的是我们没法用这么全的. 270 | -------------------------------------------------------------------------------- /_posts/2013-08-10-nginx-handler.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: nginx模块开发之handler函数 3 | layout: post 4 | tags: 5 | - nginx 6 | --- 7 | 8 | http handler是http模块中最重要的函数, 直接托管http请求. 9 | 10 | 和前文set不同, set是在nginx启动的时候读取配置的过程中被触发的, 而handler函数是在真实请求到那个路径上时被触发的. 11 | 12 | 也就是浏览器请求多少次, handler就触发多少次. 13 | 14 | ### 返回值 15 | 16 | handler的返回类型是`ngx_int_t`, 因为一般的http handler定义好body后就能交给http filter函数了, 比如我们hello模块的`ngx_http_output_filter`, 而filter函数都是返回整形数的.比如error就是-1. 17 | 18 | ### 参数 19 | 20 | handler参数只有一个, `ngx_http_request_t *req`, 这个简单的出奇, 不过我用过不少http服务器框架, 也就只有nodejs分了`request, response`两个参数. 21 | 22 | req是一个巨大的结构体. 23 | 24 | 不过这样的后果就是response的信息都写在request这个结构体上, 比如头部信息就是`request.headers_out`中. 25 | 26 | 请求的头部在`headers_in`中. 27 | 28 | 我们可以清楚的看到各种请求信息, 比如user_agent: 29 | 30 | ``` 31 | (gdb) p *req->headers_in.user_agent 32 | p *req->headers_in.user_agent 33 | $3 = {hash = 3194399592611459, key = {len = 10, data = 0x6eaa37 "User-Agent"}, v 34 | data = 0x6eaa43 "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHT 35 | lowcase_key = 0x6ebc69 "user-agentaccept-encodingaccept-languagecookie"} 36 | ``` 37 | 在print`headers_in`的时候我们还发现nginx已经通过user_agent帮你分辨好了浏览器..还专门列出了msie6.. 当然还有很多重要的头部信息, 比如`if_modified_since`, `chunked`, `cookie`等. 38 | 39 | 在req中也有全部的我们需要的信息, 有`method`但不是保存字符串, 使用数字代表的, 比如get就是2. 还有`http_version`, 比如http1.1就是1001. 40 | 41 | 但是想uri, request_line, method_name, 都是显示一个request, line, 并没有做解析, 直接是生肉`GET /test HTTP/1.1\r\nHost` 42 | 43 | 但拥有全部http请求信息的我们也完全可以写出所有http相关的模块了. 44 | 45 | ### 源代码中是如何触发handler的 46 | 47 | 第一次使用gdb调试的时候发现调试不了, 马上就想起来nginx是分master和worker进程的, 在调试的时候, 我们不仅需要关掉daemmon后台运行, 以及master进程, 仅仅使用一个worker进程进行调试. 48 | 49 | 方法是修改nginx配置文件`conf/nginx.conf`, 50 | 51 | ``` 52 | daemon off; 53 | master_process off; 54 | ``` 55 | 56 | 这样就可以用gdb调试了. 57 | 58 | handler函数在`src/http/ngx_http_core_module.c`中被调用.可以看到我们的handler函数被当成request结构体的`content_handler`属性. 59 | 60 | 返回`ngx_http_output_filter(req, &out)`的时候, 一次完整的请求+返回就完成了. 61 | -------------------------------------------------------------------------------- /_posts/2013-08-10-nginx-set.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Nginx模块开发之set函数 4 | tags: 5 | - nginx 6 | --- 7 | 8 | set函数就是上一篇提到的很重要的函数之一, 是command命令结构体中的第三个参数.在读取命令时候触发的回调函数. 9 | 10 | set是一个函数指针, 原型是这样的. 11 | 12 | ```c 13 | char * (*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 14 | ``` 15 | 16 | ### 返回值 17 | 18 | `char *`, 返回值可以是NGX_CONF_OK, 或者NGX_CONF_ERROR. 也就是0或者-1的指针. 19 | 20 | ### 参数 21 | 22 | `ngx_conf_t *cf`含义未知 23 | 24 | `ngx_command_t *cmd` 表示自己所在的那个command结构体 25 | 26 | `void *conf` 当然是空 27 | 28 | ### 如何在set函数中挂上handler 29 | 30 | ```c 31 | ngx_http_core_loc_conf_t *corecf; 32 | corecf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 33 | corecf->handler = handler; 34 | ``` 35 | `corecf`为何物?, 其实就是读到test命令时的配置状态, corecf是一个巨大的结构体, name属性是"/test", 也就是我们定义的那个路径.后面还有regex等属性, 应该也是用来匹配路径的. 36 | 37 | 应该可以猜测, 给corecf的handler属性赋值后, 如果请求的路径匹配corecf的name或者正则等, 就会触发我们挂载的handler函数. 38 | 39 | 挂完后返回`NGX_CONF_OK`即可. 40 | 41 | ### 源代码中如何调用set函数 42 | 43 | set在`ngx_conf_handler.c`文件在`ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)`函数中被调用. 44 | 45 | 显然set函数的第一个参数cf就是这个大函数中的第一个参数. 46 | 47 | 第二个参数cmd, 是每一个模块的cmd, 在gdb中print每个模块的cmd, 可以发现daemon, error_log都是command. 48 | 49 | `ngx_conf_handler`函数的作用就是遍历所有模块, 然后带着cf和cmd参数触发cmd的set函数,仅此而已. 50 | 51 | -------------------------------------------------------------------------------- /_posts/2013-08-12-file-description.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Unix 文件描述符 4 | tags: 5 | - linux 6 | --- 7 | 8 | Linux通过文件来提供底层接口, 有句话说的好, Linux中一切都是文件. 9 | 10 | 不管是系统信息(`/proc`)还是目录, 甚至是socket套接字, 都是文件. 11 | 12 | 程序使用文件是通过文件描述符, 英文叫file description. 通常简写为fd. 13 | 14 | 文件描述符是一个非负整形. 15 | 16 | 程序进程运行的时候, 会默认有三个预置的文件描述符,分别是: 17 | 18 | - 0. 标准输入, stdin 19 | 20 | - 1. 标准输出, stdout 21 | 22 | - 2. 标准错误输出, stderr 23 | 24 | 在shell中, 我们用小于号`<`给程序提供标准输入 25 | 26 | ```bash 27 | nc -n 192.168.1.2 1111 < somefile 28 | 29 | ``` 30 | 31 | 用大于号`>`提供标准输出 32 | 33 | ```bash 34 | svn log > /tmp/svnlog 35 | ``` 36 | 37 | 用`2>`提供错误输出 38 | 39 | ```bash 40 | ping 192.168.1.100 2> /tmp/pingerr 41 | 42 | ``` 43 | 44 | Linux提供标准的POSIX接口, 什么是POSIX? 45 | 46 | > POSIX 表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX 是为了读音更像 UNIX) 47 | 48 | 其中主要的有4个函数, read, write, open, close 49 | 50 | 他们的接口果然很标准, 很好记 51 | 52 | ```c 53 | read(fd, buf, len); 54 | 55 | write(fd, pos, last - pos); 56 | 57 | open(filename, flags); // return fd 58 | 59 | close(fd); 60 | ``` 61 | 62 | 他们打开的时候如果错误, 都是返回负数, 所以习惯上把他们写在if语句中. 63 | 64 | 使用这些POSIX接口的时候, 必须要引入一个库`unistd.h` 65 | 66 | 因为标准输出是1, 所以我们可以写出一个最简单的hello world. 67 | 68 | ```c 69 | #include 70 | 71 | int main() { 72 | char str[] = "hello world!"; 73 | write(1, str, sizeof(str)); 74 | return 1; 75 | } 76 | ``` 77 | 78 | 这里不得不提一下, 我刚开始学c的时候, hello world是用printf写的. 79 | 80 | 我一直很好奇printf是啥, 有学长跟同学跟我说是print file. 我还是很疑惑, print file是啥玩意儿, 然后就得知Linux中一切都是文件的说法, 屏幕也是文件. 81 | 82 | 不过man一下printf就知道就是`print format`的意思, 联想一下erlang的`io:format`即可. 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /_posts/2013-08-13-socket.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Linux下的socket编程 4 | tags: 5 | - socket 6 | - linux 7 | - c 8 | --- 9 | 10 | 我发现c语言学习环境极为恶劣, 有问题上网找, 首先c关键词太弱..而且c语言的博客根本没法看, 一段代码基本是不能跑的, 如果有缩进我都已经感激涕零了. 不得不感叹还是js好啊, 毕竟会js的文章不会太丑. 11 | 12 | 所以我写c有关的学习博客, 都只求代码美观, 能直接运行. 13 | 14 | ### socket 15 | 16 | socket方法是用来获取一个文件描述符的。 17 | 18 | ```c 19 | int fd = socket(PF_INET, SOCK_STREAM, 0); 20 | ``` 21 | 22 | `SOCK_STREAM`表示流式数据,也就是tcp协议,udp的参数是`SOCK_DGRAM`.全程叫datagram,数据豌豆,也就是我们常说的数据报啦。 23 | 24 | 这下我终于明白为啥nodejs中使用udp协议是`require("dgram");`了 25 | 26 | ###`AF_INET`和`PF_INET` 27 | 28 | 在网上找例子的时候, 会看到有的写AF_INET, 有的写PF_INET, AF是address family的缩写, PF是protocol family的缩写 29 | 30 | 这两个完全相同 31 | 32 | ``` 33 | AF_INET = 2 34 | PF_INET = 2 35 | AF_INET6 = 10 36 | PF_INET6 = 10 37 | ``` 38 | 39 | 他们的区别在于, AF是BSD的, 而PF是POSIX的.在windows上完全相同, 在我看来直接用2没什么问题. 40 | 41 | ### bind 42 | 43 | ```c 44 | int bind(int fd, struct sockaddr *addr, socklen_t addrlen); 45 | ``` 46 | 47 | 但我们一般不适用sockaddr, 因为sockaddr只有两个属性, 不能语义化的体现一个套接字地址.(ip, 协议, 端口) 48 | 49 | 因此我们使用`sockaddr_in`这个结构体代替, 这两个结构体长度相同, 可以直接强制转换(其实ipv6的sockaddr_in6长度不同依然是强制转换). 50 | 51 | 真正使用的时候一般是这样 52 | 53 | ```c 54 | int bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 55 | ``` 56 | 57 | ### sockaddr_in 58 | 59 | 一般使用`sockaddr_in`这个更加语义化的结构体来表示ipv4的套接字地址, ipv6为`sockaddr_in6`,需要引用`netinet/in.h`. 60 | 61 | ```c 62 | struct sockaddr_in { 63 | sa_family_t sin_family; 64 | in_port_t sin_port; 65 | struct in_addr sin_addr; 66 | unsigned char sin_zero[8]; 67 | } 68 | ``` 69 | 70 | 这么多sin是啥意思, 我猜可能是socket inet的缩写. 71 | 72 | `sin_family_t`就是前面的unsigned short类型的PF_INET, 也就是2. 73 | 74 | `sin_port`当然就是端口, 但不能直接写, 需要用例如`honts(80);`转化. 75 | 76 | `sin_addr.s_addr`同样需要转换,`addr.sin_addr.s_addr = inet_addr("0.0.0.0");` 77 | 78 | `sin_zero`仅仅是用来对齐sockaddr大小的。 79 | 80 | ### accept 81 | 82 | accept函数是接到请求的时触发的,一般网络出错调试,都可以在accept上设置断点,然后逐步调试,但要注意的是accept并不是进行3步握手, 3步握手是更加底层的系统完成的,accept只是把完成握手的请求从系统中拿出来。 83 | 84 | accept是放在while 1中的,这样它永远尝试着去获取新的socket文件描述符。 85 | 86 | ```c 87 | int len = sizeof(addr); 88 | while (1) { 89 | req_fd = accept(fd, (struct sockaddr *)&addr, &len); 90 | ... 91 | } 92 | ``` 93 | 94 | 第二个参数类型是sockaddr, 存在`sockaddr_in`中,这样方便我们读取其ip和端口信息 95 | 96 | 第三个参数居然是地址,以我的水平是无法理解的。 97 | 98 | accept的任务是获取一个新的请求fd。于是我们就可以通过这个新的fd进行接收数据和发送数据了。 99 | 100 | ### 接收数据 recv 101 | 102 | ```c 103 | char buf[1000]; 104 | recv(req_fd, buff, sizeof(buf), 0); 105 | ``` 106 | 107 | 这函数api很清楚,从req_fd中读数据,放入buf中,buf长度为参数3. 108 | 109 | 那如果请求头太长怎么办呢?比如一个GET的路径就1k大了。这时候如果长度超出会怎样呢?我们可以做一个小实验。 110 | 111 | ```c 112 | int req_fd; 113 | int size, size2; 114 | char[300] buf; 115 | char[300] buf2; 116 | 117 | while (1) { 118 | if ((req_fd = accept(fd, addr, &len) == -1) { 119 | exit(1); 120 | } 121 | size = recv(req_fd, buf, 300, 0); 122 | size2 = recv(req_fd, buf, 300, 0); 123 | } 124 | ``` 125 | 这时候我们发现size等于300, size2等于133.(这是使用中文chrome请求时的头部),可以看出,size2还没装满300,说明缓冲区已经被我们拿完了,那我们继续recv会怎样呢?我尝试了一下,程序直接没反应了,也没有报错。 126 | 127 | 128 | 129 | 130 | ### 发送数据 send 131 | 132 | ```c 133 | char res_str[] = "HTTP/1.1 200 OK\nContent-Type: text/html ..."; 134 | send(req_fd, res_str, sizeof(res_str), 0); 135 | ``` 136 | 137 | 可以看到send和recv确实是一对api,参数基本一样,第四个参数都可以不管直接写0 138 | 139 | 140 | -------------------------------------------------------------------------------- /_posts/2013-08-24-how-to-write-resume.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 如何写一份简历 4 | date: 18:55 2013/8/24 5 | tags: 6 | - job 7 | - resume 8 | --- 9 | 10 | 以前写简历一直很认真,但还是被同学嘲笑.这次专门学习了一下怎么写简历 11 | 12 | 首先看简历是如何被筛选的 13 | 14 | 1. HR收邮件,把简历下载下来,以大约20秒一封的速度看简历,HR筛选大约筛掉80% 15 | 16 | 2. HR将技能匹配的,条件较为优秀的简历交给此职位专业人员(可能是面试官),专业人员以专业的眼光筛掉自己认为不行的简历,比例不定,可能也高达80%. 17 | 18 | 3. 然后才有可能收到面试通知 19 | 20 | 看上去非常吓人,一封简历寄过去,十有八九是被扔到垃圾桶里. 21 | 22 | 但事实我们不用太害怕,我以前的简历蠢爆了,也可以有一面二面. 23 | 24 | 原因是因为目前的形式都是: 普通简历泛滥,好简历稀缺 25 | 26 | 因为不少使用大街网,51Job这样的童鞋都是海投的,这些简历并不能大比例匹配技能,经常会被刷掉,因此写简历是不能一招鲜吃遍天的,需要"定制"相关简历. 27 | 28 | 个人资料 29 | --- 30 | 个人资料只需两行或三行 31 | 32 | ``` 33 | 冯通 | 男 | 1992/6 | 中国科学技术大学本科 34 | 邮箱: 527653908@qq.com | 电话: 18900000001 35 | 应聘职位: 软件工程师 36 | ``` 37 | 第一行资料,第二行联系方式 38 | 39 | 这里唯一的难点在于哪些要写那些不要写 40 | 41 | 首先地域,名族,政治面貌都不用写.除非是党员,党员是个加分项,不是就不用写 42 | 43 | 年龄也是个问题,有人说不写,但我觉得年轻更加可塑有活力,也能算是加分项 44 | 45 | 教育信息直接写上最近的教育信息就可以了,不需要中学小学都写上 46 | 47 | 48 | 第一块:职位匹配 49 | ---- 50 | 51 | 职位匹配就是自己与招聘信息匹配的东西,比如公司招的是数据库,你就该写上熟悉mysql,Sqlserver,mongodb等.公司需要熟练office,你就该明确写上熟练word,excel. 52 | 53 | 职位匹配是最最关键的,从高中开始写作文老师就告诉我们一定要点题,离题属于不及格作文.因此职位匹配是要放在第一块,HR不用碰滚动条就能看到的信息.具体怎么写请看下一篇具体分析,前端工程师 54 | 55 | 第二块:项目经验 56 | --- 57 | 58 | 这也是比较重要的部分,能具体看出你做过什么 59 | 60 | 项目经验非常重要,面试官可以看到你做过什么,从字里行间能窥探你的实际水平,因此在表述的时候不要吝啬使用专业词汇 61 | 62 | 但注意不要把项目细节讲出来,毕竟不是讲故事,只需要说用什么技能做出了什么,比如 63 | 64 | > 使用Canvas画布独立开发2D塔防游戏 65 | 66 | 这里简介的说明了使用的技术,以及完成的成果,并且用独立两字表示这并不是团队项目. 67 | 68 | 对于大的项目来说,还需要多两行描述具体信息.要是又能看到效果的项目,应尽量加上地址 69 | 70 | 要注意的是项目经验并不一定是一个作品,也可能就是项目经验,比如运维和管理,运维不是很高级的话不会去做开发的事情,因此也不会有作品产生,但我们依然可以写到,熟悉网络配置,熟悉使用数据库等等作为我们的项目经验 71 | 72 | 面试官很有可能一半时间都是围绕你做的项目进行提问,比如问你做的时候有什么难题,是怎么解决的,等等 73 | 74 | 第三块: 工作经验 75 | --- 76 | 77 | 这并不是重要的,但大多招聘要求1-3年工作经验,最好是写上之前的工作时间和公司名称. 78 | 79 | 第四块: 其他相关 80 | --- 81 | 82 | 最后一块是用来阐述自己的加分项,你认为能加分的都可以写上,但不要写无关的兴趣爱好,比如"我喜欢养狗", "喜欢打篮球".根本没有人管你喜欢什么.面试官要看的是你能为公司做什么.也不用写外向内向. 83 | 84 | 加分项我认为有用的是 85 | 86 | #### 看过的书单 87 | 88 | 书单可以体现你的知识量,面试官从你看过的书名大概就能猜测你的水平. 89 | 90 | 同样书单也提供面试官问你的机会,同行的话肯定是愿意交流看书心得的. 91 | 92 | #### 博客地址 93 | 94 | 现在招聘有时直接会说最好能写上你的微博和博客地址. 95 | 96 | 因为微博直接暴露了一个人的大概,从他的每条微博,关注的人都能详尽的了解一个人 97 | 98 | 不幸的是我的微博都是`卧槽救命233`被面试官看到直接扔垃圾桶的货.因此一般是附上自己的博客地址.因为博客地址都是用脑子写的,不是手滑转发的 99 | 100 | 对于技术博客,从我的面试经验来看,是一个很大的加分项 101 | 102 | #### 专业网站ID 103 | 104 | 对于设计,绝对要贴上自己dribble ID,方便面试官看你的作品 105 | 106 | 同样程序员应该放上你的Github地址 107 | 108 | 不过Github分量太重了,你的代码水平,规范程度,思想高度全部暴露 109 | 110 | 如果你觉得代码写的太挫了,那还是不要贴Github地址了 111 | 112 | 值得一提的是,就算招聘要求里说明了贴上Github地址加分,敢于在简历中加Github地址的人也是几乎没有的. 113 | 114 | 因此,不少公司说"招不到人","连份像样的简历都没有",这些可能都是真的. 115 | 116 | 同样有作用的网站ID有 117 | 118 | - 知乎 119 | 120 | - StackOverFlow 121 | 122 | - Quora 123 | 124 | - CSDN 125 | 126 | 127 | 发邮件 128 | ======== 129 | 130 | 标题 131 | --- 132 | 133 | 标题的大忌就是直接写简历两字,不过还真是很多人这么做. 134 | 135 | 标题如果有要求的话最简单,直接按要求 136 | 137 | 如果没有,格式可以写 138 | 139 | ``` 140 | 应聘软件工程师_冯通_中科大_189000000 141 | ``` 142 | 143 | 首先加上应聘,是为了让HR方便区分求职邮件和其他邮件 144 | 145 | 其次你必须清楚的写明应聘职位,因为一个公司经常都是同时招几个职位.不同部门分管不同职位,便于HR转发邮件. 146 | 147 | 第三是写上姓名,方便HR搜索到你的邮件 148 | 149 | 第四是写上你的加分项,比如我觉得我的学校是全国前十,那我写上学校名字就能比那些其他学校的厉害了.HR会更有兴趣点开看.如果你有"xx冠军", "xxApp作者",那就更要写上了,没准就直接进了. 150 | 151 | 最后是写上联系方式,因为我们打心底想接到面试通知,当然要方便HR找号码咯 152 | 153 | 邮件内容 154 | ---- 155 | 156 | 千万不要在邮件中写你的简历,因为你不能保证HR的邮箱显示正确. 157 | 158 | 你需要的只是写一段简单的陈述 159 | 160 | 您好,我是xxx,是xxx大学xxx专业的毕业生,认为具有(符合要求),申请贵公司xxx职位 161 | 附件中是我的简历,如果您对我的条件感兴趣,请联系189xxxx.谢谢关注 162 | 163 | 然后在附件中放上pdf简历. 164 | 165 | > 哦,为什么是pdf? 166 | 167 | 肯定有朋友会这么问.主要是因为word是一个排版工具,打开看肯定是不够整洁,而且office和wps软件本身占很大的屏幕,会让人看起来很不爽. 168 | 169 | 而pdf就不同了,他的优点很多 170 | 171 | - pdf无法编辑,HR可以在上面随意点击 172 | 173 | - pdf的格式完全兼容,不会因为打开软件不同而格式混乱 174 | 175 | - pdf提供更纯碎的阅读(很多pdf软件几乎是全屏的) 176 | 177 | 千万不要使用ppt, html, 等特殊格式,这并不能体现你的创意,反而会让HR觉得很麻烦,都懒的打开了 178 | 179 | 排版 180 | --- 181 | 182 | 强烈建议排版全部是左对齐,居中是没有任何必要的 183 | 184 | 一定要充分利用缩进列表,看起来会很清晰 185 | 186 | 同样,如果能把关键字加粗就更好了 187 | 188 | 最后来句有哲理的话结尾 189 | 190 | > 简历不是写出来的,而是用脚走出来的. 191 | -------------------------------------------------------------------------------- /_posts/2013-08-24-jquery-handwrite-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: jQuery原理窥探 4 | tags: 5 | - jquery 6 | - javascript 7 | --- 8 | 9 | jQuery是一个伟大的库,但我一直没有去专门学习它.不过jQuery非常的人性化,导致于我们不需要像backbone那样去看说明书. 10 | 11 | 不过不看说明书的后果就是我对jQuery产生很多误区. 12 | 13 | 这些误区直接暴露在我几个月前的面试中,比如 14 | 15 | > 我会原生Javascript,同时也会jQuery 16 | 17 | [@朴灵](http://weibo.com/shyvo)大大听后立马纠正我,jQuery也是原生Javascript. 18 | 19 | 这点我在此次学习中算是了解了,jQuery确实是完全的Javascript,除了两个全局变量`$`和`jQuery`外,做到了完全没有污染其他空间. 20 | 21 | 也就是说如果引进了jQuery,照样可以写原生的js,完全不妨碍. 22 | 23 | > jQuery自已定义了dom,用起来不舒服 24 | 25 | 我现在想起自己的回答都想找个缝钻进去,当时的我根本没意识到所有的jQuery DOM对象都是一个类数组(Arraylike) 26 | 27 | 选择器 28 | ------- 29 | 30 | jQuery从名字上讲,是一个js的dom选择器.我们熟知的dom选择器是`document.getElementById`和`document.getElementsByTagName` 31 | 32 | 但我们知道CSS的选择器非常实用,比如`div h1.title`,他一下子表达了很多意思,想一下子选出这些dom在css中很快,但是在JS中却非常难办. 33 | 34 | jQuery本身主要是为了解决这个问题.要注意的是现代浏览器都提供了`document.querySelectorAll`让我们开发者也能用css选择器的接口 35 | 36 | 让人大跌眼镜的是很多同学,甚至是一些jQuery讲师,居然不知道这个接口.jQuery和css选择器接口的返回值都是一个NodeList,他们都是类数组 37 | 38 | > 类数组是指键是从0,1,2,...这样像数组那样排列,可能有length属性,但没有数组中prototype的比如push,pop等方法的对象 39 | 40 | jQuery和css选择器返回的NodeList都不是动态的(getElementsByTagName是动态的),jQuery返回的NodeList有大量的proto方法,比如bind,click等等,正是这些proto方法让jQuery变得如此简单易用. 41 | 42 | 43 | jQuery的nodeList 44 | ---- 45 | 46 | 正是这个nodeList让我刚学js的时候困惑不解.我天真的以为在选id的时候就是调用`getElementById`而其他的时候是调用其他高级选择器. 47 | 48 | 就是说我根本无法理解我明明是选定一个id,它怎么可能返回一个类数组. 49 | 50 | 因此我才会在面试的时候说jquery返回的不是原生的dom对象,比如不能用`myDiv.innerHTML`来获取innerHTML. 51 | 52 | 我们知道jQuery获取innerHTML的方法是`$('xxx').html()`. 53 | 54 | 看到上面这个api,我当然是以为`$('xxx')`是返回一个自己封装的dom对象,我当时抱怨为何把innerHTML的属性给删了.真是怎么也想不到我们这样是对一个列表调用`.html()` 55 | 56 | `$('xxx').html()`返回的当然是字符串,不是数组,因此实际上`$('xxx').html()`的返回值就是`$('xxx')[0].innerHTML` 57 | 58 | 但我敢肯定,新人在碰到这个api的时候都会想一下:"为什么jQuery不直接提供`$('xxx').html`"的值啊,非要做成一个函数.jQuery只能哭着说"臣妾做不到啊." 59 | 60 | 而相反的,`$('for').html('bar')`又是对整个nodeList进行innerHTML赋值 61 | 62 | 63 | jQuery的链式编程 64 | --- 65 | 66 | jQuery的链式(chainable)编程一直是被人称道的,他可以这么写 67 | 68 | ```javascript 69 | $('div').find('h3').eq(2).html('Hello') 70 | .end().eq(4).css(xxx) 71 | ``` 72 | 73 | 但原理说穿了不值一提,就是每个proto方法返回`return this`罢了. 74 | 75 | ```javascript 76 | $('div1').insertAfter($('div2')) // return div1 77 | $('div2').after($('div1')) // return div2 78 | ``` 79 | 80 | 虽然很简单,但我们依然要注意每条链主语,上面两句作用一样,但主语不同,同理还有`appendTo`和`append` 81 | 82 | 上面还有一个`.end()`这个函数可以返回上一个主语. 83 | 84 | jQuery事件触发 85 | ----- 86 | 87 | jQuery事件触发也和我们常用的不同,平常的我在注册click事件的时候都是 88 | 89 | ```javascript 90 | myBtn.onclick = function() { 91 | doSomething() 92 | } 93 | ``` 94 | 95 | 这样的问题是如果有别人也想用到这个onclick事件,就会把之前注册的函数覆盖了. 96 | 97 | jQuery的做法是 98 | 99 | ```javascript 100 | $('myDiv').click(function() { 101 | doSomething() 102 | }) 103 | ``` 104 | 105 | 这样的好处是不会覆盖之前的click事件函数,我们可以猜测它内部应该是使用了`addEventListener` 106 | 107 | 这样只是说对了一半,如果单单使用`addEventListener`,那我们在webkit inspector的event listener中应该能看到绑定的所有函数. 108 | 109 | 但事实上我们用jQuery绑定事件永远只看到一个奇怪的函数. 110 | 111 | 据说这就是jQuery处理多事件高效的原因..(一个函数托管所有事件) 112 | 113 | 那他是怎么实现的呢,我看了一下源码,发现根本看不懂..一个大大说过,源码看不懂,就自己实现,在对比源码,如果不一样,那不是你傻逼了,就是作者傻逼了. 114 | 115 | ```javascript 116 | var fn = {} 117 | $.fn = fn 118 | var eventList = [] 119 | function handler(e) { 120 | for (var i = 0; ev = eventList[i]; i++) { 121 | if (ev.target === e.target && ev.type === e.type) { 122 | // event match 123 | if (ev.handler(e) === false) { 124 | e.preventDefault() 125 | e.stopPropagation() 126 | } 127 | } 128 | } 129 | return this 130 | } 131 | 132 | fn.__proto__.bind = function(evType, fn) { 133 | for (var i = 0; i < this.length; i++) { 134 | this[i].addEventListener(evType, handler) 135 | eventList.push({ 136 | handler: fn, 137 | type: evType, 138 | target: this[i] 139 | }) 140 | } 141 | return this 142 | } 143 | 144 | ;['click', 'dbclick', 'mousedown', 'mousemove', 'mouseover', 'mouseout', 'mouseup'].forEach(function(evType) { 145 | fn.__proto__[evType] = function(fn) { 146 | return this.bind(evType, fn) 147 | } 148 | }) 149 | ``` 150 | 151 | 随手写了一下,简单的说就是注册一个事件的时候,不管是什么事件,直接dom绑定handler函数,然后把事件的类型和dom对象以及其函数加到一个内部的数组eventList中. 这样所有的事件函数都在这个数组中了. 152 | 153 | 当事件触发的时候,从头遍历eventList,如果`e.type`和`e.target`都相同了,那就调用此函数. 154 | 155 | > 可能有同学会问,你每次bind都去`addEventListener`会注册多个handler啊,其实不会的 156 | 157 | ```javascript 158 | function handler(){} 159 | myDiv.addEventListener('click', handler) 160 | myDiv.addEventListener('click', handler) // 最终还是只有一个事件 161 | ``` 162 | 163 | 提一下jQuery中如果事件函数返回值是`return false`就是取消冒泡事件和默认事件,也就是上面代码中这一段 164 | 165 | ```javascript 166 | if (ev.handler(e) === false) { 167 | e.preventDefault() 168 | e.stopPropagation() 169 | } 170 | ``` 171 | 172 | 实现的干净利索,方便实用,居家旅行必备 173 | 174 | ps: 上文提到的原理均为自己猜测,jQuery具体实现比我瞎想的要复杂且健壮10倍多. 175 | 176 | -------------------------------------------------------------------------------- /_posts/2013-08-25-semantic-web.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Web语义化 4 | date: 10:24 2013/8/25 5 | tags: 6 | - html 7 | - web 8 | --- 9 | 10 | Web语义化主要分两个 11 | 12 | 1. `HTTP`语义化 13 | 14 | 2. `HTML`语义化 15 | 16 | HTTP语义化 17 | ----- 18 | 19 | HTTP语义化是针对HTTP协议来说的,最有代表性的是`Rest API` 20 | 21 | ### path 22 | 23 | 首先是path,路径,对于有大量接口的服务器,我们需要仔细的设计自己的API 24 | 25 | 比如看新浪微博的API 26 | 27 | 一般的话path用`/`来表示嵌套关系, 用querystring来表示filter,和属性值 28 | 29 | ### HTTP method 30 | 31 | HTTP method也具有语义化 32 | 33 | 一般来说普通服务器只用`GET`和`POST`,但还有`PUT`和`DELETE`来对应数据库操作.不过说实话在实践的过程中,我还是觉得只用`GET`和`POST`好 34 | 35 | ### 无状态HTTP 36 | 37 | HTTP必须要是无状态的,所谓无状态,说细点就是用户带着你给用户配的`token`,可以访问任意的带有自己`私钥`的服务器. 38 | 39 | HTTP无状态,说白了就是为了负载均衡. 40 | 41 | 如果HTTP是有状态的,你在后台保存着用户的session,那用户就只能访问你这台服务器,除非你还做了session同步 42 | 43 | 另一种方法是在负载均衡中配置会话保持,一般的方法是使用cookie保存server的ID,也可以是保存一张IP HASH表,但很显然这会产生其他问题 44 | 45 | 可以看出牵连会话的HTTP对于性能会有巨大的损失,而且如果一个服务器坏了,那上面的用户都没法继续会话了 46 | 47 | HTML语义化 48 | ------- 49 | 50 | 这才是重头戏,上文说了,Web语义化是为了让机器读懂.我觉得这个说的太玄乎. 51 | 52 | 系分到HTML语义化,一句话概括就是 53 | 54 | > `块元素不出现
, 行内元素不出现` 55 | 56 | 有朋友要问了,"现在主流不都是div+css么,你看看xx网站, 各种div,全部div啊" 57 | 58 | div确实很全能,但这都是css的功劳,这使得我们连表格也都可以用div来完成 59 | 60 | 现在谁再用``标签,可能会被同行认为过时吧 61 | 62 | 可是HTML语义化在显示二维数据的时候就推荐用table.因为table就是用来显示表格的啊!不然W3C设计这个标签干嘛的.因此我们所说的不用table,完全是指你不该在整个网站上套table. 63 | 64 | 理解HTML语义化,就是理解HTML标签. 65 | 66 | [kejunz](http://weibo.com/kejunz)大大曾说过,最好的html代码是这个 67 | 68 | ```html 69 |
70 |
71 |
72 |
73 | ``` 74 | 75 | [玉伯](http://weibo.com/lifesinger)大大发[ISSUE](https://github.com/lifesinger/lifesinger.github.com/issues/105)表示赞成 76 | 77 | 其中也说道为何不用`
/
/