每个人的声音都面向世界

木受绳则直,金就砺则利,君子博学而日参省乎己,则知明而行无过矣。

Linux-有用的命令

下面我将和大家分享一些学习Linux命令行的技巧,希望能对大家有所助益。如果在本文中遇到不太熟悉的命令,可以在终端中键入以下命令寻求帮助。 Man Linux入门必备 了解bash:没有必要钻研长篇累牍的bash使用手册,通过man bash学习即可。 了解vi:你在工作中也许会使用Emacs或Eclipse,但vi不可替代。 了解ssh:学习无密码验证的基础知识。 bash作业管理基础知识:如使用&、Ctrl-C、fg、bg、Ctrl-Z、jobs和kill等。 文件管理命令:如硬链接和软链接,权限等。 网络管理命令:如ifconfig等。 如何使用正则表达式,如何使用grep、sed等。 学习使用apt-get和yum管理软件包。 提升日常工作效率

在bash中,可以使用Ctrl+R命令搜索命令行历史记录。 在bash中,可以使用Ctrl+W删除最后一个单词,使用Ctrl+U删除整行。 使用cd -命令返回之前的工作目录,使用cd ..命令返回上层目录。 学习如何使用xargs: $ find . -name *.py | xargs grep some_function
$ cat hosts | xargs -I{} ssh root@{} hostnameX 使用pstree -p命令查看进程树。 了解不同的信号。例如,使用kill -STOP [PID]终止进程。详细的信号列表可以在man 7 signal中查看。 如果你想让进程永远在后台运行,可以使用nohup和disown命令。 使用netstat -lntp命令查看侦听进程,并参考lsof命令。 在bash脚本中使用subshells对命令进行分组:

do something in current dir

(cd /some/other/dir; other-command)

continue in original dir

字符串修剪(Trimming Strings):${var%suffix}和${var#prefix}。例如if var=foo.pdf then echo ${var%.pdf}.txt prints “foo.txt”。 命令的输出可以当做文件使用。例如,比较本地和远程的/etc/hosts文件: diff /etc/hosts <(ssh somehost cat /etc/hosts) 了解bash中的“here documents”。 了解标准输出和标准错误重定向。 了解ASCII代码表。可以在终端中运行man ascii命令作为参考。 当通过ssh远程工作时,可以使用screen 或 dtach保存回话。 对Web开发者而言,curl、wget等命令非常实用。 将HTML页面转化文本文件: lynx -dump -stdin 如果要掌握XML,xmlstarlet命令是非常好的工具。 了解ssh端口映射。 使用Alt+shift+3快捷键可以在行前添加注释“#”。 数据处理

了解sort和uniq命令。 了解cut、paste和join命令。 了解如何对文本文件做交集、并集和差集: cat a b | sort | uniq > c # c is a union b
cat a b | sort | uniq -d > c # c is a intersect b
cat a b b | sort | uniq -u > c # c is set difference a – b 对文本文件的第二列做摘要,下面的代码要比同样的Python代码更精炼、快速(3倍): awk ‘{ x += $2 } END { print x }’ 了解字符串和grep命令。 文件分割:了解split(按大小分割)和csplit(按匹配分割)命令。 系统诊断

使用iostat、netstat、top和dstat命令查看磁盘、处理器和网络的状态。 使用free、vmstat等命令了解系统内存状态。 使用mtr网络诊断工具。 使用iftop、nethogs等工具查看占用带宽的进程和带宽。 使用ab工具快速洞悉Web服务器的性能。 以wireshark和tshark命令应对复杂网络诊断。 学习如何使用strace,并用于诊断运行的进程。这对分析程序运行错误的原因,非常有帮助。 使用ldd命令查看共享库文件。 了解如何使用gdb连接到运行中的进程,并进行堆栈跟踪。 有关/proc的知识非常重要。 如何诊断已发生的错误?Sar命令是一种很好的选择,它可以收集、保存并报告系统信息。

Apache处理http请求的生命周期

Apache请求处理循环的11个阶段都做了哪些事情呢?

  1. Post-Read-Request阶段: 在正常请求处理流程中,这是模块可以插入钩子的第一个阶段。对于那些想很早进入处理请求的模块来说,这个阶段可以被利用。
  2. URI Translation阶段 : Apache在本阶段的主要工作:将请求的URL映射到本地文件系统。模块可以在这阶段插入钩子,执行自己的映射逻辑。mod_alias就是利用这个阶段工作的。
  3. Header Parsing阶段 : Apache在本阶段的主要工作:检查请求的头部。由于模块可以在请求处理流程的任何一个点上执行检查请求头部的任务,因此这个钩子很少被使用。mod_setenvif就是利用这个阶段工作的。
  4. Access Control阶段 : Apache在本阶段的主要工作:根据配置文件检查是否允许访问请求的资源。Apache的标准逻辑实现了允许和拒绝指令。mod_authz_host就是利用这个阶段工作的。
  5. Authentication阶段 : Apache在本阶段的主要工作:按照配置文件设定的策略对用户进行认证,并设定用户名区域。模块可以在这阶段插入钩子,实现一个认证方法。
  6. Authorization阶段 : Apache在本阶段的主要工作:根据配置文件检查是否允许认证过的用户执行请求的操作。模块可以在这阶段插入钩子,实现一个用户权限管理的方法。
  7. MIME Type Checking阶段 : Apache在本阶段的主要工作:根据请求资源的MIME类型的相关规则,判定将要使用的内容处理函数。标准模块mod_negotiation和mod_mime实现了这个钩子。
  8. FixUp阶段 : 这是一个通用的阶段,允许模块在内容生成器之前,运行任何必要的处理流程。和Post_Read_Request类似,这是一个能够捕获任何信息的钩子,也是最常使用的钩子。
  9. Response阶段 : Apache在本阶段的主要工作:生成返回客户端的内容,负责给客户端发送一个恰当的回复。这个阶段是整个处理流程的核心部分。
  10. Logging阶段 : Apache在本阶段的主要工作:在回复已经发送给客户端之后记录事务。模块可能修改或者替换Apache的标准日志记录。
  11. CleanUp阶段 : Apache在本阶段的主要工作:清理本次请求事务处理完成之后遗留的环境,比如文件、目录的处理或者Socket的关闭等等,这是Apache一次请求处理的最后一个阶段。

PHP Break 关键字

php的break关键字可以接受一个可选的数字参数来决定跳出几重循环 break 结束当前 for,foreach,while,do-while 或者 switch 结构的执行。 break可以接受一个可选的数字参数来决定跳出几重循环。

<?php
    $arr = array('one', 'two', 'three', 'four', 'stop', 'five');
    while (list (, $val) = each($arr)) {
        if ($val == 'stop') {
            break;    /* You could also write 'break 1;' here. */
        }
        echo "$val<br />\n";
    }

    /* Using the optional argument. */

    $i = 0;
    while (++$i) {
        switch ($i) {
        case 5:
            echo "At 5<br />\n";
            break 1;  /* Exit only the switch. */
        case 10:
            echo "At 10; quitting<br />\n";
            break2;  /* Exit the switch and the while. */
        default:
            break;
        }
    }

Octopress添加分类到侧边栏

增加category_list插件

保存以下代码到plugins/category_list_tag.rb:

module Jekyll
  class CategoryListTag < Liquid::Tag
    def render(context)
      html = ""
      categories = context.registers[:site].categories.keys
      categories.sort.each do |category|
        posts_in_category = context.registers[:site].categories[category].size
        category_dir = context.registers[:site].config['category_dir']
        category_url = File.join(category_dir, category.gsub(/_|\P{Word}/, '-').gsub(/-{2,}/, '-').downcase)
        html << "<li class='category'><a href='/#{category_url}/'>#{category} (#{posts_in_category})</a></li>\n"
      end
      html
    end
  end
end

Liquid::Template.register_tag(‘category_list’, Jekyll::CategoryListTag)
这个插件会向liquid注册一个名为category_list的tag,该tag就是以li的形式将站点所有的category组织起来。如果要将category加入到侧边导航栏,需要增加一个aside。

增加aside

复制以下代码到source/_includes/asides/category_list.html。

<section>
  <h1>Categories</h1>
  <ul id="categories">
    { % category_list % }
  </ul>
</section>

配置侧边栏需要修改_config.yml文件,修改其default_asides项:

default_asides: [asides/category_list.html, asides/recent_posts.html]
以上asides根据自己的需求调整。

一致性哈希算法浅析

在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括:

  • 轮循算法(Round Robin)
  • 哈希算法(HASH)
  • 最少连接算法(Least Connection)
  • 响应速度算法(Response Time)
  • 加权法(Weighted )等

其中哈希算法是最为常用的算法. 典型的应用场景是: 有N台服务器提供缓存服务,需要对服务器进行负载均衡,将请求平均分发到每台服务器上,每台机器负责1/N的服务。 常用的算法是对hash结果取余数 (hash() mod N):对机器编号从0到N-1,按照自定义的hash()算法,对每个请求的hash()值按N取模,得到余数i,然后将请求分发到编号为i的机器。但这样的算法方法存在致命问题,如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将当掉的服务器从算法从去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;如果新增一台机器,会有N /(N+1)的服务器的缓存数据需要进行重新计算。对于系统而言,这通常是不可接受的颠簸(因为这意味着大量缓存的失效或者数据需要转移)。那么,如何设计一个负载均衡策略,使得受到影响的请求尽可能的少呢? 在Memcached、Key-Value Store、Bittorrent DHT、LVS中都采用了Consistent Hashing算法,可以说Consistent Hashing 是分布式系统负载均衡的首选算法。 1、Consistent Hashing算法描述 下面以Memcached中的Consisten Hashing算法为例说明。 由于hash算法结果一般为unsigned int型,因此对于hash函数的结果应该均匀分布在[0,232-1]间,如果我们把一个圆环用232 个点来进行均匀切割,首先按照hash(key)函数算出服务器(节点)的哈希值, 并将其分布到0~232的圆上。 用同样的hash(key)函数求出需要存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器(节点)上。

consistent hashing

Consistent Hashing原理示意图 新增一个节点的时候,只有在圆环上新增节点逆时针方向的第一个节点的数据会受到影响。删除一个节点的时候,只有在圆环上原来删除节点顺时针方向的第一个节点的数据会受到影响,因此通过Consistent Hashing很好地解决了负载均衡中由于新增节点、删除节点引起的hash值颠簸问题。

consistent hashing

Consistent Hashing添加服务器示意图 虚拟节点(virtual nodes):之所以要引进虚拟节点是因为在服务器(节点)数较少的情况下(例如只有3台服务器),通过hash(key)算出节点的哈希值在圆环上并不是均匀分布的(稀疏的),仍然会出现各节点负载不均衡的问题。虚拟节点可以认为是实际节点的复制品(replicas),本质上与实际节点实际上是一样的(key并不相同)。引入虚拟节点后,通过将每个实际的服务器(节点)数按照一定的比例(例如200倍)扩大后并计算其hash(key)值以均匀分布到圆环上。在进行负载均衡时候,落到虚拟节点的哈希值实际就落到了实际的节点上。由于所有的实际节点是按照相同的比例复制成虚拟节点的,因此解决了节点数较少的情况下哈希值在圆环上均匀分布的问题。

consistent hashing

虚拟节点对Consistent Hashing结果的影响 从上图可以看出,在节点数为10个的情况下,每个实际节点的虚拟节点数为实际节点的100-200倍的时候,结果还是很均衡的。

第3段中有这些文字:“但这样的算法方法存在致命问题,如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将当掉的服务器从算法从去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;” 为何是 (N-1)/N 呢?解释如下: 比如有 3 台机器,hash值 1-6 在这3台上的分布就是: host 1: 1 4 host 2: 2 5 host 3: 3 6 如果挂掉一台,只剩两台,模数取 2 ,那么分布情况就变成: host 1: 1 3 5 host 2: 2 4 6 可以看到,还在数据位置不变的只有2个: 1,2,位置发生改变的有4个,占共6个数据的比率是 4/6 = 2/3 这样的话,受影响的数据太多了,势必太多的数据需要重新从 DB 加载到 cache 中,严重影响性能

【consistent hashing 的办法】 上面提到的 hash 取模,模数取的比较小,一般是负载的数量,而 consistent hashing 的本质是将模数取的比较大,为 2的32次方减1,即一个最大的 32 位整数。然后,就可以从容的安排数据导向了,那个图还是挺直观的 以下部分为一致性哈希算法的一种PHP实现。 下载地址 :http://zwzweb.googlecode.com/files/Consistent%20Hashing.php

jQuery.extend()函数注释说明

  • // 第一个参数是true,则会迭代合并
  • // 合并两个或更多对象的属性到第一个对象中,jQuery后续的大部分功能都通过该函数扩展
  • // 通过jQuery.fn.extend扩展的函数,大部分都会调用通过jQuery.extend扩展的同名函数
  • // 如果传入两个或多个对象,所有对象的属性会被添加到第一个对象target
  • // 如果只传入一个对象,则将对象的属性添加到jQuery对象中。
  • // 用这种方式,我们可以为jQuery命名空间增加新的方法。可以用于编写jQuery插件。
  • // 如果不想改变传入的对象,可以传入一个空对象:$.extend({}, object1, object2);
  • // 默认合并操作是不迭代的,即便target的某个属性是对象或属性,也会被完全覆盖而不是合并
  • // 从object原型继承的属性会被拷贝
  • // undefined值不会被拷贝
  • // 因为性能原因,JavaScript自带类型的属性不会合并
  • // jQuery.extend( target, [ object1 ], [ objectN ] )
  • // jQuery.extend( [ deep ], target, object1, [ objectN ] )
    jQuery.extend = jQuery.fn.extend = function() {
        var options, name, src, copy, copyIsArray, clone,
           target = arguments[0] || {},
           i = 1,
           length = arguments.length,
           deep = false;

        // Handle a deep copy situation
        // 如果第一个参数是boolean型,可能是深度拷贝
        if ( typeof target === "boolean" ) {
           deep = target;
           target = arguments[1] || {};
           // skip the boolean and the target
           // 跳过boolean和target,从第3个开始
           i = 2;
        }

        // Handle case when target is a string or something (possible in deep copy)
        // target不是对象也不是函数,则强制设置为空对象
        if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
           target = {};
        }

        // extend jQuery itself if only one argument is passed
        // 如果只传入一个参数,则认为是对jQuery扩展
        if ( length === i ) {
           target = this;
           --i;
        }

        for ( ; i < length; i++ ) {
           // Only deal with non-null/undefined values
           // 只处理非空参数
           if ( (options = arguments[ i ]) != null ) {
               // Extend the base object
               for ( name in options ) {
                  src = target[ name ];
                  copy = options[ name ];

                  // Prevent never-ending loop
                  // 避免循环引用
                  if ( target === copy ) {
                      continue;
                  }

                  // Recurse if we're merging plain objects or arrays
                  // 深度拷贝且值是纯对象或数组,则递归
                  if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                      // 如果copy是数组
                      if ( copyIsArray ) {
                         copyIsArray = false;
                         // clone为src的修正值
                         clone = src && jQuery.isArray(src) ? src : [];
                      // 如果copy的是对象
                      } else {
                         // clone为src的修正值
                         clone = src && jQuery.isPlainObject(src) ? src : {};
                      }

                      // Never move original objects, clone them
                      // 递归调用jQuery.extend
                      target[ name ] = jQuery.extend( deep, clone, copy );

                  // Don't bring in undefined values
                  // 不能拷贝空值
                  } else if ( copy !== undefined ) {
                      target[ name ] = copy;
                  }
               }
           }
        }

        // Return the modified object
        // 返回更改后的对象
        return target;
    };

使用栈来找路径

示例图片-01 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
<!DOCTYPE html>
<html>
<head>
<title> 数据结构-栈的应用 </title>
<meta http-equiv="Content-type" content="text/html;charset=utf-8;" >
<style>
*{margin:0;padding:0;}
#container .line{display:block;float:left;}
.block{width:15px;height:15px;float:left;font-size:8px;border-right:1px solid #111;border-bottom:1px solid #111;}
.bld{background:black;color:#fff;}
.start{background:red;color:#fff;}
.end{background:red;color:#f00;}
.route{background:red;}
</style>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.12.1/jquery.min.js"></script>
</head>
<body>
    <h1>使用栈来找路径</h1>
    <p>
    查找从左上角到右下角的路径,图中的方块表示障碍;点击方块可以改变其状态(通或者不通)
    </p>
<button text='clear' id="btn-clear">清除路径</button>
<button text='clear' id="btn-find">查找路径</button>
  <div id='container'></div>
  <script type="text/javascript">
<!--
/***** 入口函数 ****/
$(function(){
    init();
    addEvents();
});
   
function init(){
   
    window.M_x = 70;  //矩阵的宽和高
    window.M_y = 45;
    window.Matrix = createMatrix(M_x , M_y);
   
    showMatrixAsDivBlock(M_x , M_y);
    setDisableBlocks(M_x , M_y , 1100);
   
    var n1 = [2  , 2];
    var n2 = [M_y-2 ,M_x-2];
    window.startNode = n1;
    window.endNode = n2;
   
    $(getid(n1)).addClass('start').addClass('route').text('from');
    $(getid(n2)).addClass('end').addClass('route').text('end');
}
   
/****创建界面****/
function showMatrixAsDivBlock(x , y){
    var div =[]
    var line=[];
    var i , j;
    for(i = 1 ; i < y ; i++){
        for(j = 1 ; j < x ; j++){
            line[j] = "<div id='b-"+i+'-'+j+"' class='block'></div>";
        }
        div[i] = '<div class="line">' + line.join('') + '</div>';
    }
    $('#container').html(div.join('')+'<div style="clear:both;"></div>');
}
   
/*****创建矩阵****/
function createMatrix(M_x , M_y){
    var Matrix = [];
    for(i = 1; i < M_y; i++){
        Matrix[i] = [];
        for(j = 1; j < M_x; j++){
            if(i==1 || i==M_y-1 || j==1 || j==M_x-1){
                var s = true;
            }else{
                var s = false;
            }
            Matrix[i][j] = {
                disable :s    /// 标示当前的节点是否为阻断 1 :阻断 ,0 :联通
                ,x      :i   /// 标示当前节点的x坐标
                ,y      :j   /// 标示当前节点的y坐标
                ,inRoute:false ///标示当前节点是否在路径中
                ,direction:{    /// 标示当前节点四个方向是否被遍历过
                    left:0 , bottom:0 , right:0 , top:0
                }
            };
        }
    }
    return Matrix;
}
   
/*将所有的障碍设置起来*/
function setDisableBlocks(M_x , M_y , count){
       
    var i ; var j;
    for(i=1 ; i< M_y ; i++){
        for(j=1 ; j < M_x ; j++){
            if(i==1 || j == 1 || i == M_y-1 || j == M_x-1){
                Matrix[i][j].disable = true;
                $('#b-'+i+'-'+j).addClass('bld');    
            }
        }
    }
    while(count){
        i = parseInt((Math.random() * 10000))% M_y;
        j = parseInt((Math.random() * 10000))% M_x;
        if((i==2 && j==2) || (i==M_y-2 && j ==M_x-2)){
            continue;
        }
        if(i > 1 && i < M_y && j > 1 && j < M_x){
               
            Matrix[i][j].disable = true;
            $('#b-'+i+'-'+j).addClass('bld');
            count--;
        }                
    }
}
   
/***设置所有“方块”以及两个按钮的单击事件***/
function addEvents(){
   
    /**清除路径按钮**/
    $('#btn-clear').click(function(){
        for(i = 1 ; i < M_y ; i++){
            for(j = 1 ; j < M_x ; j++){
               var o = window.Matrix[i][j];
               o.inRoute = false;
               o.direction={left:0 , bottom:0 , right:0 , top:0};
            }
        }
        if(window.Stack){
            for(i=0 ; i < Stack.length ; i++){
                var o = Stack[i];
                $(getid([o.x , o.y])).removeClass('route').html('');
            }
        }
    });
   
    /**查找路径按钮**/
    $('#btn-find').click(function(){
        $('#btn-clear').click();
        find(window.Matrix ,window.startNode , window.endNode);
    });
       
    /** 方块单击事件**/
    $('.block').click(function(){
        var id = $(this).attr('id');
        var ary = id.split('-');
        var i = ary[1];
        var j = ary[2];
        if(i == 1 || j == 1 || i == M_y || j == M_x){;}else{// 不能改变四个边的状态   
            Matrix[i][j].disable = !Matrix[i][j].disable;
            $('#'+id).toggleClass('bld');
        }
    });
}
   
// 查找路径
function find(Matrix , n1 , n2){
    // 先标示 起点和终点
    $(getid(n1)).addClass('start').addClass('route').text('from');
    $(getid(n2)).addClass('end').addClass('route').text('end');
       
    var start = getObject(Matrix , n1);
    var end   = getObject(Matrix , n2)
    var cur = start;
   
    window.Stack = Stack = [];
    start.inRoute = true;
   
    while(true){
        if(cur.direction.left == 0 && (o = getObject(Matrix , [cur.x , cur.y+1])) && !o.disable ){// && !o.inRoute){
               
            cur.direction.left=1;
            o.direction.right=1;
            o.inRoute = true;
            Stack.push(cur);
            Stack.push(o);
            cur = o;
   
        }else if(cur.direction.bottom == 0 && (o = getObject(Matrix , [cur.x+1 , cur.y])) && !o.disable ){// && !o.inRoute){
       
            cur.direction.bottom=1;
            o.direction.top=1;
            o.inRoute = true;
            Stack.push(cur);
            Stack.push(o);  
            cur = o;
   
        }else if(cur.direction.right == 0 && (o = getObject(Matrix , [cur.x , cur.y-1])) && !o.disable){// && !o.inRoute){
               
            cur.direction.right=1;
            o.direction.left=1;
            o.inRoute = true;
            Stack.push(cur);
            Stack.push(o);  
            cur = o;
   
        }else if(cur.direction.top == 0 && (o = getObject(Matrix , [cur.x-1 , cur.y])) && !o.disable ){// && !o.inRoute){
            cur.direction.top=1;
            o.direction.bottom=1;
            o.inRoute = true;
            Stack.push(cur);
            Stack.push(o);  
            cur = o;
   
        }else{
            cur = Stack.pop();
            if(cur){
                cur.inRoute = false;
            }else{
                showMsg('没有路径连接两个点!');
                break;
            }
        }
           
        if( cur.x == start.x && cur.y == start.y && start.direction.left && start.direction.bottom && start.direction.right && start.direction.top){
            showMsg('没有路径连接两个点!');
            break;
        }
   
        if( cur.x == end.x && cur.y == end.y){
            break;
        }
    }
       
    for(i=0 ; i < Stack.length ; i++){
        var tmp = Stack[i];
        $(getid([tmp.x , tmp.y])).addClass('route').html(i/2);
    }
}
   
// 显示信息
function showMsg(msg){
    alert(msg);
}
   
function getObject(Matrix , arg){
   
    if(Matrix[arg[0]] && Matrix[arg[0]][arg[1]]){
        return Matrix[arg[0]][arg[1]];
    }else{
        return null
    }
}
   
/**
* 将基于javascript 数组形式的 arg 转换为 jquery id形式
* 用来查找页面中的方块
* 如 : [3,4] => “#b-3-4” 
**/
function getid(arg){
    return '#b-'+arg[0]+'-'+arg[1];
}
//-->
</script>
 </body>
</html>

IT 岗位说明书(岗位职责)

岗位:程序员

  程序员(英文Programmer)是从事程序开发、维护的专业人员。一般我们将程序员分为程序设计人员和程序编码员,但两者的界限并不非常清楚,特别是在中国。   作一个真正合格的程序员,应该具有的素质。 1:团队精神和协作能力   团队精神和协作能力是作为一个程序员应具备的最基本的素质。软件工程 已经提了将近三十年了,当今的软件开发已经不是编程了,而是工程。独行侠可以写一些程序也能赚钱发财,但是进入研发团队,从事商业化和产品化的开发任务, 就必须具备这种素质。可以毫不夸张的说这种素质是一个程序员乃至一个团队的安身立命之本。 2:文档习惯   文档是一个软件系统的生命力。一个公司的产品再好、技术含量再高,如果没有缺乏文档,知识就没有继承,公司还是一个来料加工的软件作坊。作为代码程序员,必须将30%的工作时间写用于技术文档。没有文档的程序员势必会被淘汰。 3:规范化的代码编写习惯   知名软件公司的代码的变量命名、注释格式,甚至嵌套中行缩进的长度和函数间的空行数字都有明确规定,良好的编写习惯,不但有助于代码的移植和纠错,也有助于不同技术人员之间的协作。一些所谓的高手甚至叫嚣高手写的代码一般人看不懂,我只能说他不是一名合格的程序员。 4:需求理解能力   程序员要能正确理解任务单中描述的需求。在这里要明确一点,程序员不 仅仅要注意到软件的功能需求,还应注意软件的性能需求,要能正确评估自己的模块对整个项目中的影响及潜在的威胁,如果有着两到三年项目经验的熟练程序员对 这一点没有体会的话,只能说明他或许是认真工作过,但是没有用心工作。 5:模块化思维能力   作为一个优秀的程序员,他的思想不能在局限当前的工作任务里面,要想 想看自己写的模块是否可以脱离当前系统存在,通过简单的封装在其他系统中或其他模块中直接使用。这样做可以使代码能重复利用,减少重复的劳动,也能是系统 结构越趋合理。模块化思维能力的提高是一个程序员的技术水平提高的一项重要指标。 6:测试习惯   测试是软件工程质量保证的重要环节,但是测试不仅仅是测试工程师的工作,而是每个程序员的一种基本职责。程序员要认识测试不仅是正常的程序调试,而要是要进行有目的有针对性的异常调用测试,这一点要结合需求理解能力。 7:学习和总结的能力   程序员是很容易被淘汰的职业,所以要善于学习总结。许多程序员喜欢盲 目追求一些编码的小技巧,这样的技术人员无论学了多少语言,代码写起来多熟练,我们只能说他是一名熟练的代码民工,他永远都不会有质的提高。一个善于学习 的程序员会经常总结自己的技术水平,对自己的技术层面要有良好的定位,这样才能有目的地提高自己。这样才能逐步提高,从程序员升级为软件设计师、系统分析 员。    作为高级程序员,乃至于设计师而言,除了应该具备上述全部素质之外,还需要具备以下素质: 1、 需求分析能力 2、 整体框架能力 3、 流程处理能力 4、 模块分解能力 5、 整体项目评估能力 6、 团队组织管理能力  

岗位:项目经理

主要职责: 1、 计划: a)项目范围、项目质量、项目时间、项目成本的确认。 b)项目过程/活动的标准化、规范化。 c)根据项目范围、质量、时间与成本的综合因素的考虑,进行项目的总体规划与阶段计划。 d)各项计划得到上级领导、客户方及项目组成员认可。 2、 组织: a)组织项目所需的各项资源。 b)设置项目组中的各种角色,并分配好各角色的责任与权限。 c)定制项目组内外的沟通计划。(必要时可按配置管理要求写项目策划目录中的《项目沟通计划》) d)安排组内需求分析师、客户联系人等角色与客户的沟通与交流。 e)处理项目组与其它项目干系人之间的关系。 f)处理项目组内各角色之间的关系、处理项目组内各成员之间的关系。 g)安排客户培训工作。 3、 领导: a)保证项目组目标明确且理解一致。 b)创建项目组的开发环境及氛围,在项目范围内保证项目组成员不受项目其它方面的影响。 c)提升项目组士气,加强项目组凝聚力。 d)合理安排项目组各成员的工作,使各成员工作都能达到一定的饱满度。 e)制定项目组需要的招聘或培训人员的计划。 f)定期组织项目组成员进行相关技术培训以及与项目相关的行业培训等。 g)及时发现项目组中出现的问题。 h)及时处理项目组中出现的问题。 4、 控制 a)保证项目在预算成本范围内按规定的质量和进度达到项目目标。 b)在项目生命周期的各个阶段,跟踪、检查项目组成员的工作质量; c)定期向领导汇报项目工作进度以及项目开发过程中的难题。 d)对项目进行配置管理与规划。 e)控制项目组各成员的工作进度,即时了解项目组成员的工作情况,并能快速的解决项目组成员所碰到的难题。 f)不定期组织项目组成员进行项目以外的短期活动,以培养团队精神。 结语: 项目经理是在整个项目开发过程中项目组内对所有非技术性重要事情做出最终决定的人。

岗位:系统架构师(技术总监)

主要功能及职责: 1、系统架构师是软件项目的总体设计师,是软件组织新产品的开发与集成、新技术体系的构建者。 2、系统架构师是在技术上对所有重要事情做出决定的人。(系统架构师在整个软件开发过程中都起着重要作用,并随着开发进程的推进而其职责或关注点不断地变化。) 3、 需求阶段,软件架构师负责理解和管理非功能性系统需求,比如软件的可维护性、性能、复用性、可靠性、有效性和可测试性等。审查客户和市场人员所提出的需 求,确认开发团队所提出的设计;组织开发团队成员和开发过程的定义;协助需求分析师完成《用户需求说明书》、《需求变更说明书》。 4、设计阶段,架构师负责对整个软件架构、关键构件、接口的设计。协助系统分析师完成《系统概要设计说明书》 5、编码阶段,架构师则成为程序员的顾问,并且经常性地要举行一些技术研讨会、技术培训班等; 6、测试及实施阶段,随着软件开始测试、集成和交付,集成和测试支持将成为软件架构师的工作重点; 结语: 系统架构师也可以理解成技术总监。系统架构师是在部门内所有软件项目中,对技术上所有重要的事情做出决定的人。

岗位:需求分析师

主要职责: 1、在项目前期根据《需求调研计划》对客户进行需求调研。 2、收集整理客户需求,负责编写《用户需求说明书》。 3、代表项目组与用户沟通与项目需求有关的所有事项。 4、代表客户与项目组成员沟通项目需求有关的所有事项。 5、负责《用户需求说明书》得到用户的认可与签字。 6、负责将完成的项目模块给客户做演示,并收集对完成模块的意见。 7、完成《需求变更说明书》,并得到用户的认可与签字。 8、并协助系统架构师、系统分析师对需求进行理解。 结语: 需求分析师是项目前期与客户方打交道最多的人,对于客户来说,他可以代表整个项目组,对与项目组成员来说他的意见可以代表客户方的意见,项目组内所有与客户需求相关的事情必需得到他的认可。

岗位:系统分析师

主要职责: 1、 协助需求分析师进行需求调研。 2、分析、解析《用户需求说明书》,将系统需求整理成《软件需求规格说明书》; 3、负责解决《软件需求规格说明书》被评审后发现的问题; 4、在分析系统前,负责向架构设计师解释《软件需求规格说明书》的内容。 5、协助架构设计师进行架构设计,并协助其完成《系统架构说明书》。 6、根据《系统架构说明书》对系统进行建模; 7、系统分析及建模完成后,负责将建模成果转化为《系统概要设计》; 8、协助数据库设计师按《系统概要设计说明书》进行数据库逻辑设计和物理设计,完成数据库CDM及PDM图,并协助其完成《数据库设计说明书》 9、协助软件设计师按《系统概要设计说明书》进行《系统详细设计说明书》。 10、指导软件工程师按《系统详细设计说明书》进行代码实现。 11、 负责重点代码检查; 12、协助项目经理进行配置管理,并提供优化改进建议; 13、定期对项目组成员进行技术方面的培训。 结语: 系统分析师是项目组中的首席执行官,他涉及项目的所有方面,是项目进度的推动者,也是项目成功的关键。

岗位:数据库设计师

主要职责: 1、根据《系统架构说明书》与系统架构师、系统分析师一同进行数据库建模。 2、根据数据库建模结果,绘制数据库CDM与PDM图。 3、 根据数据库PDM图进行数据库建库。 4、 对数据库进行维护、备份、恢复、同步。 5、 负责客户数据的导入导出。 6、 对数据库进行初始化操作。 7、协助软件设计师完成《系统详细设计说明书》中与数据库相关的部分。 8、根据《系统详细设计说明书》编写对应的视图、存储过程、函数、触发器等。 9、对项目组其它成员进行SQL方面的指导。 10、定期对项目组其它成员进行数据库方面知识的培训。 11、为测试经理及测试工程师建立测试数据。 结语: 数据库设计师又称DBA,是项目组中唯一能对数据库进行直接的操作的人。对项目中与数据库相关的所有重要的事做最终决定的人。

岗位:软件设计师(模块)

1、根据《系统概要设计说明书》编写分模块的《系统详细说明书》。
2、负责对软件工程师讲解《系统详细设计说明书》内容。
3、协助软件工程师按《系统详细设计说明书》进行代码实现。
4、 控制本模块的开发进度。

结语: 软件设计师又称模块设计师,协助系统分析师对分模块进行详细设计,并直接管控该模块的进度,对于本模块中所有重要的事做最终决定的人。

岗位:软件工程师

主要职责: 1.根据《系统详细设计说明书》进行代码实现; 2.对自己代码进行复查,并进行简单的测试; 结语: 软件工程师是最终实现代码的成员。

岗位:测试经理

主要职责: 1.独立编写测试计划; 2.独立编写测试用例; 3.协调测试团队内部的工作以及与开发团队之间的工作; 4.完成“执行测试”的工作; 5.掌握较深层次的测试方法、测试技术和较复杂的业务流程; 6.负责测试过程工具的研究、推广与维护,负责测试数据库维护工作; 7.负责编写《用户手册》、《操作手册》和相关培训教材; 8.负责项目的质量审查。 结语: 测试经理其实应该是整个项目中最关心项目质量的人,他的主要工作就是找到项目中存在的不合理、不合格的部份,并要求项目其它成员按其给定的项目质量完成项目。

岗位:测试工程师

主要职责: 1.在测试经理的安排和指导下,编写测试用例; 2.在测试经理的安排和指导下,完成“执行测试”的工作; 3.在测试经理的指导下,按测试计划进行测试工作; 4.按测试用例进行测试工作。 5.负责被分派项目的质量审计。 6.了解项目的基本流程,可以熟练的进行项目中各种流程的操作。 结语: 测试工程师是项目质量的保证,是最终进行项目测试的成员。

岗位:实施经理

主要职责: 1.负责制定项目实施计划; 2.在项目实施计划的约束下,协调项目组相关资源,完成系统实施相关工作(包括系统安装、用户培训、系统上线、系统试运行等); 3.在项目实施阶段,跟踪、检查实施人员的工作质量; 5.负责协助用户进行“用户确认测试”和编写《确认测试报告》。

岗位:实施工程师

主要职责: 1.在实施经理安排和指导下,执行项目用户现场实施任务; 2.参与编写《用户手册》、《操作手册》和相关培训教材; 3.参与进行“用户确认测试”和编写《确认测试报告》。

岗位:美术工程师

主要职责: 1.负责完成软件设计师安排的功能界面设计。 2.负责对项目整体色彩的调配。 3.向系统分析师提出项目美化的建议。 4.为BS项目提供一套或几套CSS样式表及HTML结构表 5.为CS项目提供符合项目内容的静态、动态图片。 6.并为软件设计师提供界面指导。

岗位:客户经理(当所开发的项目属于定制型的项目时设立,可由项目经理或部门经理兼)

主要职责: 1.策划并独立完成目标客户的拜访和沟通; 2.定期分析、整理客户需求,制定有针对性的方案; 3.进行重点客户的关系维护,了解并整理重点客户的需求,为开发更符合用户需求的产品提供富有价值的市场信息; 4.参与产品定位的研讨,为产品策划献计献策。

岗位:产品经理(当所开发的项目为产品型项目时设立,可由市场部成员兼)

主要职责: 1.对所负责的产品进行策划和管理; 2.对所负责的产品进行市场调研和分析,及时提出应对措施; 3.负责产品实现的内部管理,保证产品功能的顺利实现以及时满足市场需求; 4.负责产品对外宣传与推广,开拓市场,提高产品品牌知名度和认可度; 5.配合销售制订产品销售策略,支持市场销售业务。

RSA加密算法简单介绍

这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。 算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。   RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个 才能解密。   RSA的算法涉及三个参数,n、e、d。   其中,n是两个大质数p、q的积。n的二进制表示时所占用的位数,就是所谓的密钥长度。   e和d是一对相关的值,e可以任意取,但要求满足e<(p-1)(q-1)并具 e与(p-1)(q-1)互质(就是最大公约数为1); 再选择d,要求(de)mod((p-1)(q-1))=1。   (n及e),(n及d)就是密钥对。   RSA加解密的算法完全相同,设M为明文,c为密文,则: 加密:C=Me mod n; 解密:m=cd mod n;   注:上面两式中的e和d可以互换。
n d两个数构成公钥,可以告诉别人; n e两个数构成私钥,e自己保留,不让任何人知道。 给别人发送的信息使用私钥e加密,只要别人能用公钥d解开就证明信息是由你发送的,构成了签名机制,起验证身份的作用。 别人给你发送信息时使用d加密,这样只有拥有e的你能够对其解密,起到数据保密的作用。
整理一下: 为实现RSA的加解密 最终目标:找三个参数 n,e,d 1、n = pq (p,q 是两个质数) 2、 1)、φ(N)=(p-1)(q-1) 2)、取任何一个数e,要求满足e<φ(N)并且e与φ(N)互质 3、(d*e) modφ(N)=1 //================================================================ 加密的明文长度不能超过RSA密钥的长度-11,比如1024位的,明文长度不能超过117。
密文的长度总是密钥的长度的一半,比如1024位的,密文长度是64,如果是1032位,密文长度是65位。

Linux命令行技巧

编辑命令

* Ctrl + a :移到命令行首
* Ctrl + e :移到命令行尾
* Ctrl + f :按字符前移(右向)
* Ctrl + b :按字符后移(左向)
* Alt + f :按单词前移(右向)
* Alt + b :按单词后移(左向)
* Ctrl + xx:在命令行首和光标之间移动
* Ctrl + u :从光标处删除至命令行首
* Ctrl + k :从光标处删除至命令行尾
* Ctrl + w :从光标处删除至字首
* Alt + d :从光标处删除至字尾
* Ctrl + d :删除光标处的字符
* Ctrl + h :删除光标前的字符
* Ctrl + y :粘贴至光标后
* Alt + c :从光标处更改为首字母大写的单词
* Alt + u :从光标处更改为全部大写的单词
* Alt + l :从光标处更改为全部小写的单词
* Ctrl + t :交换光标处和之前的字符
* Alt + t :交换光标处和之前的单词
* Alt + Backspace:与 Ctrl + w 相同类似

重新执行命令

* Ctrl + r:逆向搜索命令历史
* Ctrl + g:从历史搜索模式退出
* Ctrl + p:历史中的上一条命令
* Ctrl + n:历史中的下一条命令
* Alt + .:使用上一条命令的最后一个参数

控制命令

* Ctrl + l:清屏
* Ctrl + o:执行当前命令,并选择上一条命令
* Ctrl + s:阻止屏幕输出
* Ctrl + q:允许屏幕输出
* Ctrl + c:终止命令
* Ctrl + z:挂起命令

Bang (!) 命令

* !!:执行上一条命令
* !blah:执行最近的以 blah 开头的命令,如 !ls
* !blah:p:仅打印输出,而不执行
* !$:上一条命令的最后一个参数,与 Alt + . 相同
* !$:p:打印输出 !$ 的内容
* !*:上一条命令的所有参数
* !*:p:打印输出 !* 的内容
* ^blah:删除上一条命令中的 blah
* ^blah^foo:将上一条命令中的 blah 替换为 foo
* ^blah^foo^:将上一条命令中所有的 blah 都替换为 foo

注意:

1. 以上介绍的大多数 Bash 快捷键仅当在 emacs 编辑模式时有效,若你将 Bash 配置为 vi 编辑模式,那将遵循 vi 的按键绑定。Bash 默认为 emacs 编辑模式。如果你的 Bash 不在 emacs 编辑模式,可通过 set -o emacs 设置。
2. ^S、^Q、^C、^Z 是由终端设备处理的,可用 stty 命令设置。