如题,最近在用mac上的日历看时间时总是没有完整的农历日期,用起来很是不爽。
不包含农历日期
添加订阅农历日期的方法如下:
1、打开日历应用点击菜单上的文件->新建日历订阅操作
2、订阅地址填写 http://iweek.me/m/ical/nong.php?starty=2015&county=3
大功告成~~~
如题,最近在用mac上的日历看时间时总是没有完整的农历日期,用起来很是不爽。
不包含农历日期
添加订阅农历日期的方法如下:
1、打开日历应用点击菜单上的文件->新建日历订阅操作
2、订阅地址填写 http://iweek.me/m/ical/nong.php?starty=2015&county=3
大功告成~~~
操作系统:Centos
SSH登陆后,如果长时间没有响应则自动LOGOUT的设置如下,其时非常简单:
1)vi /etc/profile,编辑profile文件,在最后面添加如下行:
1 |
export TMOUT=60 |
注:TMOUT是一个控制超时的环境变量,此处设置为60秒无响应,就会自动LOGOUT
2)使用SecureCRT工具登陆进行测试,60秒无操作会自动LOGOUT,如下所示:
1 |
[root@centos ~]# timed out waiting for input: auto-logout |
1 2 3 |
crontab -e 0 */1 * * * command 0 */2 * * * command |
1 2 3 4 |
crontab -l 0 */1 * * * command 0 */2 * * * command |
1 |
30 21 * * * /usr/local/etc/rc.d/lighttpd restart |
1 |
45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart |
1 |
10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart |
1 |
0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart |
1 |
0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart |
1 |
* */1 * * * /usr/local/etc/rc.d/lighttpd restart |
1 |
* 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart |
1 |
0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart |
1 |
0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart |
众所周知,在github上新建项目无非是以下两种情况
github
上开源或者存放。然而,无论是哪种情况,都得先在github
新建一个项目的仓库。登录github
后,找到下图中的Repositories
这个tab,然后点击红框中的new
来新建一个项目仓库。
新建项目仓库的界面如下所示:
然后由上往下输入你项目的名字、项目的描述,选择这个项目是不是公开(Public)或是作为私人项目(Private)。
如果自己本地有很多项目需要导入到github上,再或者网络不太稳定,每次都打开github页面来创建岂不是很麻烦?
现在我就来教你如何通过命令行创建github项目
1. 新建一个API token
打开github的个人设置页面,在Developer settings
分组中找到Personal access tokens
菜单,或点击 https://github.com/settings/tokens 直接进入。
然后选择Generate new Token
按钮来创建一个token,写入description,选择scopes(设置此token持有者的权限)。
记住personal access token(也就是那一串字符和数字)!这一串东西只出现一次,下次查看不到。
1 2 3 4 5 |
mkdir test cd test git init git add . git commit -m 'test information' |
1. 命令行模式
这是最直接的一种形式,直接把参数写到命令行搞定:
1 |
curl -u "$username:$token" https://api.github.com/user/repos -d '{"name":"'$repo_name'"}' |
注:这里需要把$username和$token分别换成实际的用户名和刚才记住的personal access token,把$repo_name换成任何想要的repo name。
如果想在github上自己创建的组织下新建,则需要把地址修改为https://api.github.com/orgs/$organization/repos
注:这里需要把$organization换成实际的组织名。
2. bash脚本形式
我们可以把命令行写成bash脚本,下次只要执行里面的简单命令就可以执行以上整条命令。
1 2 3 |
[github] user = your user name token = the token you get |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
github-create() { repo_name=$1 dir_name=`basename $(pwd)` if [ "$repo_name" = "" ]; then echo "Repo name (hit enter to use '$dir_name')?" read repo_name fi if [ "$repo_name" = "" ]; then repo_name=$dir_name fi username=`git config github.user` if [ "$username" = "" ]; then echo "Could not find username, run 'git config --global github.user <username>'" invalid_credentials=1 fi token=`git config github.token` if [ "$token" = "" ]; then echo "Could not find token, run 'git config --global github.token <token>'" invalid_credentials=1 fi if [ "$invalid_credentials" == "1" ]; then return 1 fi echo -n "Creating Github repository '$repo_name' ..." curl -u "$username:$token" https://api.github.com/user/repos -d '{"name":"'$repo_name'"}' > /dev/null 2>&1 echo " done." echo -n "Pushing local code to remote ..." git remote add origin git remote add origin https://github.com/$username/$repo_name.git > /dev/null 2>&1 git push -u origin master > /dev/null 2>&1 echo " done." } |
1 |
Source ~/.bash_profile |
1 |
github-create [repo name] |
如果你不想用默认repo名(也就是当前目录名)创建repo可以重新输入另一个名字,否则直接按回车执行。
这是一种比较健壮的形式,其username,token,repo name 都有很大的自由度,接下来这种非常简单,但在不同情况下有时需要被直接修改。
以下是我用的简化版,仅供参考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
sample-create() { if [ $1 ] then repo_name=$1 else echo "Repo name?" read repo_name fi username=`git config github.user` token=`git config github.token` curl -u "$username:$token" https://api.github.com/orgs/sample/repos -d '{"name":"'$repo_name'"}' if [ ! -d "$repo_name" ]; then mkdir $repo_name fi cd $repo_name touch README.md git init git add . git commit -m 'init' git remote add origin https://github.com/sample/$repo_name.git git push -u origin master cd .. } |
出现的问题现象:
1 直接在命令行运行PHP脚本返回数据正常
2 通过nginx访问返回数据被截断
经过排查是fastcgi_temp目录的读写权限问题,Nginx的错误日志出现大量类似如下的错误:
1 2 3 |
2017/06/07 00:41:28 [crit] 32763#0: *5439 open() "/usr/local/nginx/fastcgi_temp/5/02/0000000025" failed (13: Permission denied) while reading upstream, client: 203.171.237.2, server: www.36nu.com, request: "GET /thread.html HTTP/1.0", upstream: "f astcgi://127.0.0.1:9000",... |
从这句判断应该是返回的数据过大要以文件的形式存放 ,但是nginx有没有读写权限造成.于是给fastcgi_temp读写权限,问题解决.
1 |
chmod -R 764 /usr/local/nginx/fastcgi_temp/ |
下面简单说一下原理,Nginx的buffer机制是Nginx将来自FastCGI Server的Response缓冲到内存中,然后依次发送到客户端。缓冲区的大小由 fastcgi_buffers 和 fastcgi_buffer_size 两个值控制。
比如如下配置:
1 2 |
fastcgi_buffers 8 4K; fastcgi_buffer_size 4K; |
fastcgi_buffers 控制 nginx 最多创建 8 个大小为 4K 的缓冲区,而 fastcgi_buffer_size 则是处理 Response 时第一个缓冲区的大小,不包含在前者中。所以总计能创建的最大内存缓冲区大小是 8*4K+4K = 36k。而这些缓冲区是根据实际的 Response 大小动态生成的,并不是一次性创建的。比如一个 8K 的页面,Nginx 会创建 2*4K 共 2 个 buffers。当 Response 小于等于 36k 时,所有数据当然全部在内存中处理。如果 Response 大于 36k 呢?fastcgi_temp 的作用就在于此。多出来的数据会被临时写入到文件中,放在这个目录下面。内存中缓冲了 36Kb,剩下的会写入的文件中。而实际的情况是,运行 Nginx Process 的用户并没有 fastcgi_temp 目录的读写权限,解决方法就比较简单了,给fastcgi_temp 目录赋读写权限可以解决问题。
ES6(ECMAScript2015)的出现,无疑给前端开发人员带来了新的惊喜,它包含了一些很棒的新特性,可以更加方便的实现很多复杂的操作,提高开发人员的效率。
本文主要针对ES6做一个简要介绍。 主要译自: http://webapplog.com/ES6/comment-page-1/。也许你还不知道ES6是什么, 实际上, 它是一种新的javascript规范。在这个大家都很忙碌的时代,如果你想对ES6有一个快速的了解,那么请继续往下读,去了解当今最流行的编程语言JavaScript最新一代的十大特性。
以下是ES6排名前十的最佳特性列表(排名不分先后):
声明:这些列表仅是个人主观意见。它绝不是为了削弱ES6其它功能,这里只列出了10条比较常用的特性。
首先回顾一下JavaScript的历史,不清楚历史的人,很难理解JavaScript为什么会这样发展。下面就是一个简单的JavaScript发展时间轴:
1、1995:JavaScript诞生,它的初始名叫LiveScript。
2、1997:ECMAScript标准确立。
3、1999:ES3出现,与此同时IE5风靡一时。
4、2000–2005: XMLHttpRequest又名AJAX, 在Outlook Web Access (2000)、Oddpost (2002),Gmail (2004)和Google Maps (2005)大受重用。
5、2009: ES5出现,(就是我们大多数人现在使用的)例如foreach,Object.keys,Object.create和JSON标准。
6、2015:ES6/ECMAScript2015出现。
历史回顾就先到此,现让我们进入正题。
还记得我们以前不得不通过下面方式来定义默认参数:
1 2 3 4 5 6 |
var link = function (height, color, url) { var height = height || 50; var color = color || 'red'; var url = url || 'http://azat.co'; ... } |
一切工作都是正常的,直到参数值是0后,就有问题了,因为在JavaScript中,0表示fasly,它是默认被hard-coded的值,而不能变成参数本身的值。当然,如果你非要用0作为值,我们可以忽略这一缺陷并且使用逻辑OR就行了!但在ES6,我们可以直接把默认值放在函数申明里:
1 2 3 |
var link = function(height = 50, color = 'red', url = 'http://azat.co') { ... } |
顺便说一句,这个语法类似于Ruby!
在其它语言中,使用模板和插入值是在字符串里面输出变量的一种方式。因此,在ES5,我们可以这样组合一个字符串:
1 2 |
var name = 'Your name is ' + first + ' ' + last + '.'; var url = 'http://localhost:3000/api/messages/' + id; |
幸运的是,在ES6中,我们可以使用新的语法$ {NAME},并把它放在反引号里:
1 2 |
var name = `Your name is ${first} ${last}. `; var url = `http://localhost:3000/api/messages/${id}`; |
ES6的多行字符串是一个非常实用的功能。在ES5中,我们不得不使用以下方法来表示多行字符串:
1 2 3 4 5 6 7 |
var roadPoem = 'Then took the other, as just as fair,nt' + 'And having perhaps the better claimnt' + 'Because it was grassy and wanted wear,nt' + 'Though as for that the passing therent' + 'Had worn them really about the same,nt'; var fourAgreements = 'You have the right to be you.n You can only be you when you do your best.'; |
然而在ES6中,仅仅用反引号就可以解决了:
1 2 3 4 5 6 7 |
var roadPoem = `Then took the other, as just as fair, And having perhaps the better claim Because it was grassy and wanted wear, Though as for that the passing there Had worn them really about the same,`; var fourAgreements = `You have the right to be you. You can only be you when you do your best.`; |
解构可能是一个比较难以掌握的概念。先从一个简单的赋值讲起,其中house 和 mouse是key,同时house 和mouse也是一个变量,在ES5中是这样:
1 2 3 |
var data = $('body').data(), // data has properties house and mouse house = data.house, mouse = data.mouse; |
以及在node.js中用ES5是这样:
1 2 3 4 |
var jsonMiddleware = require('body-parser').jsonMiddleware ; var body = req.body, // body has username and password username = body.username, password = body.password; |
在ES6,我们可以使用这些语句代替上面的ES5代码:
1 2 3 |
var { house, mouse} = $('body').data(); // we'll get house and mouse variables var {jsonMiddleware} = require('body-parser'); var {username, password} = req.body; |
这个同样也适用于数组,非常赞的用法:
1 2 |
var [col1, col2] = $('.column'), [line1, line2, line3, , line5] = file.split('n'); |
我们可能需要一些时间来习惯解构赋值语法的使用,但是它确实能给我们带来许多意外的收获。
使用对象文本可以做许多让人意想不到的事情!通过ES6,我们可以把ES5中的JSON变得更加接近于一个类。
下面是一个典型ES5对象文本,里面有一些方法和属性:
1 2 3 4 5 6 7 8 9 10 11 12 |
var serviceBase = {port: 3000, url: 'azat.co'}, getAccounts = function(){return [1,2,3]}; var accountServiceES5 = { port: serviceBase.port, url: serviceBase.url, getAccounts: getAccounts, toString: function() { return JSON.stringify(this.valueOf()); }, getUrl: function() {return "http://" + this.url + ':' + this.port}, valueOf_1_2_3: getAccounts() } |
如果我们想让它更有意思,我们可以用Object.create从serviceBase继承原型的方法:
1 2 3 4 5 6 7 8 9 |
var accountServiceES5ObjectCreate = Object.create(serviceBase) var accountServiceES5ObjectCreate = { getAccounts: getAccounts, toString: function() { return JSON.stringify(this.valueOf()); }, getUrl: function() {return "http://" + this.url + ':' + this.port}, valueOf_1_2_3: getAccounts() } |
我们知道,accountServiceES5ObjectCreate 和accountServiceES5 并不是完全一致的,因为一个对象(accountServiceES5)在__proto__对象中将有下面这些属性:
为了方便举例,我们将考虑它们的相似处。所以在ES6的对象文本中,既可以直接分配getAccounts: getAccounts,也可以只需用一个getAccounts,此外,我们在这里通过__proto__(并不是通过’proto’)设置属性,如下所示:
1 2 3 4 5 |
var serviceBase = {port: 3000, url: 'azat.co'}, getAccounts = function(){return [1,2,3]}; var accountService = { __proto__: serviceBase, getAccounts, |
另外,我们可以调用super防范,以及使用动态key值(valueOf_1_2_3):
1 2 3 4 5 6 7 |
toString() { return JSON.stringify((super.valueOf())); }, getUrl() {return "http://" + this.url + ':' + this.port}, [ 'valueOf_' + getAccounts().join('_') ]: getAccounts() }; console.log(accountService) |
ES6对象文本是一个很大的进步对于旧版的对象文本来说。
这是我迫不及待想讲的一个特征,CoffeeScript 就是因为它丰富的箭头函数让很多开发者喜爱。在ES6中,也有了丰富的箭头函数。这些丰富的箭头是令人惊讶的因为它们将使许多操作变成现实,比如,
以前我们使用闭包,this总是预期之外地产生改变,而箭头函数的迷人之处在于,现在你的this可以按照你的预期使用了,身处箭头函数里面,this还是原来的this。
有了箭头函数在ES6中, 我们就不必用that = this或 self = this 或 _this = this 或.bind(this)。例如,下面的代码用ES5就不是很优雅:
1 2 3 4 |
var _this = this; $('.btn').click(function(event){ _this.sendData(); }) |
在ES6中就不需要用 _this = this:
1 2 3 |
$('.btn').click((event) =>{ this.sendData(); }) |
不幸的是,ES6委员会决定,以前的function的传递方式也是一个很好的方案,所以它们仍然保留了以前的功能。
下面这是一个另外的例子,我们通过call传递文本给logUpperCase() 函数在ES5中:
1 2 3 4 5 6 7 8 9 10 |
var logUpperCase = function() { var _this = this; this.string = this.string.toUpperCase(); return function () { return console.log(_this.string); } } logUpperCase.call({ string: 'ES6 rocks' })(); |
而在ES6,我们并不需要用_this浪费时间:
1 2 3 4 5 |
var logUpperCase = function() { this.string = this.string.toUpperCase(); return () => console.log(this.string); } logUpperCase.call({ string: 'ES6 rocks' })(); |
请注意,只要你愿意,在ES6中=>可以混合和匹配老的函数一起使用。当在一行代码中用了箭头函数,它就变成了一个表达式。它将暗地里返回单个语句的结果。如果你超过了一行,将需要明确使用return。
这是用ES5代码创建一个消息数组:
1 2 3 4 |
var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; var messages = ids.map(function (value) { return "ID is " + value; // explicit return }); |
用ES6是这样:
1 2 |
var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; var messages = ids.map(value => `ID is ${value}`); // implicit return |
请注意,这里用了字符串模板。
在箭头函数中,对于单个参数,括号()是可选的,但当你超过一个参数的时候你就需要他们。
在ES5代码有明确的返回功能:
1 2 3 4 |
var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9']; var messages = ids.map(function (value, index, list) { return 'ID of ' + index + ' element is ' + value + ' '; // explicit return }); |
在ES6中有更加严谨的版本,参数需要被包含在括号里并且它是隐式的返回:
1 2 |
var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; var messages = ids.map((value, index, list) => `ID of ${index} element is ${value} `); // implicit return |
Promises 是一个有争议的话题。因此有许多略微不同的promise 实现语法。Q,bluebird,deferred.js,vow, avow, jquery 一些可以列出名字的。也有人说我们不需要promises,仅仅使用异步,生成器,回调等就够了。但令人高兴的是,在ES6中有标准的Promise实现。
下面是一个简单的用setTimeout()实现的异步延迟加载函数:
1 2 3 |
setTimeout(function(){ console.log('Yay!'); }, 1000); |
在ES6中,我们可以用promise重写:
1 2 3 4 5 |
var wait1000 = new Promise(function(resolve, reject) { setTimeout(resolve, 1000); }).then(function() { console.log('Yay!'); }); |
或者用ES6的箭头函数:
1 2 3 4 5 |
var wait1000 = new Promise((resolve, reject)=> { setTimeout(resolve, 1000); }).then(()=> { console.log('Yay!'); }); |
到目前为止,代码的行数从三行增加到五行,并没有任何明显的好处。确实,如果我们有更多的嵌套逻辑在setTimeout()回调函数中,我们将发现更多好处:
1 2 3 4 5 6 |
setTimeout(function(){ console.log('Yay!'); setTimeout(function(){ console.log('Wheeyee!'); }, 1000) }, 1000); |
在ES6中我们可以用promises重写:
1 2 3 4 5 6 7 8 9 |
var wait1000 = ()=> new Promise((resolve, reject)=> {setTimeout(resolve, 1000)}); wait1000() .then(function() { console.log('Yay!') return wait1000() }) .then(function() { console.log('Wheeyee!') }); |
还是不确信Promises 比普通回调更好?其实我也不确信,我认为一旦你有回调的想法,那么就没有必要额外增加promises的复杂性。
虽然,ES6 有让人崇拜的Promises 。Promises 是一个有利有弊的回调但是确实是一个好的特性,更多详细的信息关于promise:Introduction to ES6 Promises.
在ES6代码中,你可能已经看到那熟悉的身影let。在ES6里let并不是一个花俏的特性,它是更复杂的。Let是一种新的变量申明方式,它允许你把变量作用域控制在块级里面。我们用大括号定义代码块,在ES5中,块级作用域起不了任何作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function calculateTotalAmount (vip) { var amount = 0; if (vip) { var amount = 1; } { // more crazy blocks! var amount = 100; { var amount = 1000; } } return amount; } console.log(calculateTotalAmount(true)); |
结果将返回1000,这真是一个bug。在ES6中,我们用let限制块级作用域。而var是限制函数作用域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function calculateTotalAmount (vip) { var amount = 0; // probably should also be let, but you can mix var and let if (vip) { let amount = 1; // first amount is still 0 } { // more crazy blocks! let amount = 100; // first amount is still 0 { let amount = 1000; // first amount is still 0 } } return amount; } console.log(calculateTotalAmount(true)); |
这个结果将会是0,因为块作用域中有了let。如果(amount=1).那么这个表达式将返回1。谈到const,就更加容易了;它就是一个不变量,也是块级作用域就像let一样。下面是一个演示,这里有一堆常量,它们互不影响,因为它们属于不同的块级作用域:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function calculateTotalAmount (vip) { const amount = 0; if (vip) { const amount = 1; } { // more crazy blocks! const amount = 100 ; { const amount = 1000; } } return amount; } console.log(calculateTotalAmount(true)); |
从我个人看来,let 和const使这个语言变复杂了。没有它们的话,我们只需考虑一种方式,现在有许多种场景需要考虑。
如果你喜欢面向对象编程(OOP),那么你将喜爱这个特性。以后写一个类和继承将变得跟在facebook上写一个评论那么容易。
类的创建和使用真是一件令人头疼的事情在过去的ES5中,因为没有一个关键字class (它被保留,但是什么也不能做)。在此之上,大量的继承模型像pseudo classical, classical, functional 更加增加了混乱,JavaScript 之间的宗教战争只会更加火上浇油。
用ES5写一个类,有很多种方法,这里就先不说了。现在就来看看如何用ES6写一个类吧。ES6没有用函数, 而是使用原型实现类。我们创建一个类baseModel ,并且在这个类里定义了一个constructor 和一个 getName()方法:
1 2 3 4 5 6 7 8 9 10 11 12 |
class baseModel { constructor(options, data) { // class constructor,node.js 5.6暂时不支持options = {}, data = []这样传参 this.name = 'Base'; this.url = 'http://azat.co/api'; this.data = data; this.options = options; } getName() { // class method console.log(`Class name: ${this.name}`); } } |
注意我们对options 和data使用了默认参数值。此外方法名也不需要加function关键字,而且冒号(:)也不需要了。另外一个大的区别就是你不需要分配属性this。现在设置一个属性的值,只需简单的在构造函数中分配。
AccountModel 从类baseModel 中继承而来:
1 2 |
class AccountModel extends baseModel { constructor(options, data) { |
为了调用父级构造函数,可以毫不费力的唤起super()用参数传递:
1 2 3 4 |
super({private: true}, ['32113123123', '524214691']); //call the parent method with super this.name = 'Account Model'; this.url +='/accounts/'; } |
如果你想做些更好玩的,你可以把 accountData 设置成一个属性:
1 2 3 4 5 |
get accountsData() { //calculated attribute getter // ... make XHR return this.data; } } |
那么,你如何调用他们呢?它是非常容易的:
1 2 3 |
let accounts = new AccountModel(5); accounts.getName(); console.log('Data is %s', accounts.accountsData); |
结果令人惊讶,输出是:
Class name: Account Model
Data is 32113123123,524214691
众所周知,在ES6以前JavaScript并不支持本地的模块。人们想出了AMD,RequireJS,CommonJS以及其它解决方法。现在ES6中可以用模块import 和export 操作了。
在ES5中,你可以在 <script>中直接写可以运行的代码(简称IIFE),或者一些库像AMD。然而在ES6中,你可以用export导入你的类。下面举个例子,在ES5中,module.js有port变量和getAccounts 方法:
1 2 3 4 5 6 |
module.exports = { port: 3000, getAccounts: function() { ... } } |
在ES5中,main.js需要依赖require(‘module’) 导入module.js:
1 2 |
var service = require('module.js'); console.log(service.port); // 3000 |
但在ES6中,我们将用export and import。例如,这是我们用ES6 写的module.js文件库:
1 2 3 4 |
export var port = 3000; export function getAccounts(url) { ... } |
如果用ES6来导入到文件main.js中,我们需用import {name} from ‘my-module’语法,例如:
1 2 |
import {port, getAccounts} from 'module'; console.log(port); // 3000 |
或者我们可以在main.js中把整个模块导入, 并命名为 service:
1 2 |
import * as service from 'module'; console.log(service.port); // 3000 |
从我个人角度来说,我觉得ES6模块是让人困惑的。但可以肯定的事,它们使语言更加灵活了。
并不是所有的浏览器都支持ES6模块,所以你需要使用一些像jspm去支持ES6模块。
更多的信息和例子关于ES6模块,请看 this text。不管怎样,请写模块化的JavaScript。
ES6已经敲定,但并不是所有的浏览器都完全支持,详见:http://kangax.github.io/compat-table/es6/。要使用ES6,需要一个编译器例如:babel。你可以把它作为一个独立的工具使用,也可以把它放在构建中。grunt,gulp和webpack中都有可以支持babel的插件。
这是一个gulp案列,安装gulp-babel插件:
1 |
$ npm install --save-dev gulp-babel |
在gulpfile.js中,定义一个任务build,放入src/app.js,并且编译它进入构建文件中。
1 2 3 4 5 6 7 |
var gulp = require('gulp'), babel = require('gulp-babel'); gulp.task('build', function () { return gulp.src('src/app.js') .pipe(babel()) .pipe(gulp.dest('build')); }) |
在nodejs中,你可以用构建工具或者独立的Babel模块 babel-core 来编译你的Node.js文件。安装如下:
1 |
$ npm install --save-dev babel-core |
然后在node.js中,你可以调用这个函数:
1 |
require("babel-core").transform(ES5Code, options); |
这里还有许多ES6的其它特性你可能会使用到,排名不分先后:
1、全新的Math, Number, String, Array 和 Object 方法
2、二进制和八进制数据类型
3、默认参数不定参数扩展运算符
4、Symbols符号
5、tail调用
6、Generators (生成器)
7、New data structures like Map and Set(新的数据构造对像MAP和set)
在使用nginx进行 反向代理配置时通过正则表达式配置location后发现
通过$_SERVER[‘SCRIPT_NAME’]; 与$_SERVER[‘PATH_INFO’] 发现直接获取了整个uri地址
访问uri: 127.0.0.1/index.PHP/site/login
正常情况应该为index.php
现获取为index.php/site/login
以下是解决方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
server { listen 80; server_name test.com; access_log /home/swin/oaih/dev/logs/access.log; error_log /home/swin/oaih/dev/logs/error.log; root /home/swin/oaih/dev/public; index index.php index.html index.htm; location / { if (!-e $request_filename) { rewrite ^/(.*)$ /index.php/$1 last; } } location ~ .php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include /etc/nginx/fastcgi_params; } location ~ .php($|/) { set $script $uri; set $path_info ""; if ($uri ~ "^(.+.php)(/.+)") { set $script $1; set $path_info $2; } fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$script; fastcgi_param SCRIPT_NAME $script; fastcgi_param PATH_INFO $path_info; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; } } |
第一个位置指令设立的基本选项,而第二个location指令匹配一个请求到自身的index.php,并把它传递到FastCGI来处理。下一次请求index.php是没有进行正确的配置。
在处理我们的问题的整个配置文件的关键部分是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
location ~ .php($|/) { set $script $uri; set $path_info ""; if ($uri ~ "^(.+.php)(/.+)") { set $script $1; set $path_info $2; } fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$script; fastcgi_param SCRIPT_NAME $script; fastcgi_param PATH_INFO $path_info; } |
location指定匹配所有的php请求将不指定为先前的全部uri, 它还清空$path-info变量, if语句匹配任何类似下面的请求:http://mysite/index.php/foo和放入的index.php的$script变量和/ foo $path_info变量。$script and $path_info将被插入到服务器变量SCRIPT_NAME和PATH_INFO的fastcgi的参数,并允许PHP妥善处理请求。
替换brew.git:
1 2 |
cd "$(brew --repo)" git remote set-url origin https://mirrors.ustc.edu.cn/brew.git |
替换homebrew-core.git:
1 2 |
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git |
替换Homebrew Bottles源
对于bash用户:
1 2 |
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bash_profile source ~/.bash_profile |
对于zsh用户
1 2 |
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.zshrc source ~/.zshrc |
在中科大源失效或宕机时可以切换回官方源
重置brew.git:
1 2 |
cd "$(brew --repo)" git remote set-url origin https://github.com/Homebrew/brew.git |
重置homebrew-core.git:
1 2 |
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" git remote set-url origin https://github.com/Homebrew/homebrew-core.git |
最近有同事有个针对PHP-fpm进程的监护需求,也即:如果php-fpm的master进程意外退出(可能是crash,也可能是被误kill),那么希望master进程能被自动拉起,以免中断服务。
我们知道,supervisor是一个非常强大的进程监控(monitor & control)工具,它理论上可以实现php-fpm master进程的守护需求。因此,我帮同事试验了如何用supervisor完成他的需求,结果表明,supervisor确实是神器,只需一个合理的配置文件,它就能解决问题。
下面是我在网上找资料最终实现php-fpm主进程守护功能的配置步骤,在此做个记录,也希望能帮助到别人。
1、安装supervisor
可参考:https://blog.zzstudio.net/system/article_1061.html
2、修改php-fpm.conf中的daemonize
编辑./etc/php-fpm.conf,设置daemonize = no,默认是yes
3、在supervisor配置中加入Php-fpm的配置
1 2 3 4 5 6 7 8 9 |
[program:php-fpm] command=bash -c "sleep 1 && /usr/local/php/sbin/php-fpm --fpm-config /usr/local/php/etc/php-fpm.conf --pid /var/run/php-fpm.pid" ; the program (relative uses PATH, can take args) process_name=%(program_name)s ; process_name expr (default %(program_name)s) autostart=true ; start at supervisord start (default: true) autorestart=true ; whether/when to restart (default: unexpected) startretries=5 ; max # of serial start failures (default 3) exitcodes=0,2,70 ; 'expected' exit codes for process (default 0,2) stopsignal=QUIT ; signal used to kill process (default TERM) stopwaitsecs=2 ; max num secs to wait b4 SIGKILL (default 10) |
4、到supervisorctl中reload配置即可
在配置时有两个注意点:
1) command
它指定了supervisor要监控的进程的启动命令,可以看到,这里我们没有给php-fpm传入daemonize参数,其余参数只是展开了php安装包中php-fpm.sh中的shell变量而已。
大家已经注意到,command也不是直接调起php-fpm,而是通过bash -c执行了两个命令,而第一个命令是sleep 1。这是由于php-fpm在stop后,其占用的端口通常不能立即释放,此时,supervisor以极快的速度试图重新拉起进程时,可能会由于报如下错误而导致几次retry均失败:
1 2 3 |
## var/log/php-fpm.error.log [18-Jul-2015 21:35:28] ERROR: unable to bind listening socket for address '127.0.0.1:9002': Address already in use (98) [18-Jul-2015 21:35:28] ERROR: FPM initialization failed |
而supervisor目前还不支持delay restart功能,因此,这里只能通过先sleep再启动的略显tricky的方法来解决问题,结果表明,疗效不错且无副作用。
其文档描述如下:
1 |
May be one of false, unexpected, or true. If false, the process will never be autorestarted. If unexpected, the process will be restart when the program exits with an exit code that is not one of the exit codes associated with this process’ configuration (see exitcodes). If true, the process will be unconditionally restarted when it exits, without regard to its exit code. |
其默认值是unexpected,表示若被监护进程的exit code异常时,supervisor才会重新拉起进程。这里设置为true,表明任何时候进程退出均会被再次拉起。
这样配置好后,运行如下命令即可完成supervisor对php-fpm master进程的监护:
1 |
shell> supervisord -c /etc/supervisor/conf.d/php-fpm.ini |
然后,通过ps x | fgrep fpm可以看到,php-fpm主进程已经被拉起了。
然后,kill掉php-fpm主进程,再次ps x | fgrep fpm可以看到,一个新的php-fpm主进程会被supervisor创建出来。
至此,用supervisor守护php-fpm主进程以实现php-fpm的自动重启的需求已经解决了。
composer是一个PHP的依赖管理工具,windos下安装经常被墙,现提供一个手动安装的方法,仅供参考
一、安装前准备
(1)Composer需要PHP 5.3.2+才能运行
(2)php运行目录加入path变量。即确保任何地方打开cmd都能直接运行php -v
(3)确保php 开启openssl扩展到php.ini里搜索OpenSSL,去掉前面的分号,保存重启服务器。
二、安装配置composer
(1)下载composer.phar
https://getcomposer.org/composer.phar 下载到本地(例如D:\tools\composer)
cmd 运行
1 2 3 |
cd D:\tools\composer D: php composer.phar -v |
(2)将composer.phar所在目录加入path环境变量
(3)创建composer快捷命令
1 2 3 |
cd D:\tools\composer D: echo @php "%~dp0composer.phar" %*>composer.bat |
则在D:\tools\composer 创建了一个composer.bat批处理文件,而D:\tools\composer已经加到环境变量中,以后再任意地方输入composer可同等于
php composer.phar
(4)修改镜像
中国镜像地址:https://packagist.phpcomposer.com
可以全局设置也可以按需要设置
为了避免安装包的时候都要执行两次查询,切记要添加禁用 packagist 的设置
全局设置
查看 composer 主目录:通过 composer config -l -g 命令可以列出 composer 的全局配置信息,在这些信息中查找[home] 配置项就是 composer 的主目录。
进入 composer 的主目录,打开 config.json 文件(如果没有就自己创建一个),然后增加本镜像服务的配置信息,最终内容如下:
1 2 3 4 5 6 7 8 9 |
{ "config": { }, "repositories": [ {"type": "composer", "url": "https://packagist.phpcomposer.com"}, {"packagist": false} ] } |
也可以直接执行
1 |
composer config -g repo.packagist composer https://packagist.phpcomposer.com |
按需设置
如果只需要特定的项目指定特定的镜像,则不需修改全局设置,在需要的地方进行修改当前项目的 composer.json 配置文件
打开命令行窗口(windows用户)或控制台(Linux、Mac 用户),进入你的项目的根目录(也就是 composer.json 文件所在目录),执行如下命令:
1 |
composer config repo.packagist composer https://packagist.phpcomposer.com |
上述命令将会在当前项目中的 composer.json 文件的末尾自动添加镜像的配置信息(你也可以自己手工添加):
1 2 3 4 5 6 |
"repositories": { "packagist": { "type": "composer", "url": "https://packagist.phpcomposer.com" } } |
OK,一切搞定!试一下 composer install 来体验飞一般的速度吧!
镜像原理:
一般情况下,安装包的数据(主要是 zip 文件)一般是从 github.com 上下载的,安装包的元数据是从 packagist.org 上下载的。
然而,由于众所周知的原因,国外的网站连接速度很慢,并且随时可能被“墙”甚至“不存在”。
“Packagist 中国全量镜像”所做的就是缓存所有安装包和元数据到国内的机房并通过国内的 CDN 进行加速,这样就不必再去向国外的网站发起请求,从而达到加速 composer install 以及 composer update 的过程,并且更加快速、稳定。因此,即使 packagist.org、github.com 发生故障(主要是连接速度太慢和被墙),你仍然可以下载、更新安装包。