worktile角色管理
什么是角色?
在各行各业的不同企业中,面对不同的职能、岗位和业务线的要求,需要配置不同的角色、权限,以及数据范围。一般情况,企业成员的操作权限、查看数据范围是通过角色来控制的,例如企业所有者具备最全的功能权限以及查看公司全部资源,而普通成员只能操作被限定范围内的功能权限和数据。在Worktile中,系统预定义了企业所有者、管理员、部门主管、成员4个默认角色,同时还根据职务预置了财务、出纳、客服、采购、人事、行政、HR等角色。在角色管理模块中,企业可根据公司实际职能、岗位、业务线需求设置相应的角色,并为其配置相应的角色成员、权限和数据范围。
如何进行角色管理?
(1)新建角色组、角色,并添加角色成员
点击“新建角色组”创建新的角色组,然后在角色组下添加相应的角色。设置好后,添加角色成员。企业成员可以被赋予多个角色,若一个成员归属于多个角色,则此成员的权限为所在角色具有的权限合集。为了更好的帮助企业进行角色权限配置,系统预定义了企业所有者、管理员、部门主管、成员4个默认角色,同时还根据职务预置了财务、出纳、客服、采购、人事、行政、HR等角色。除了默认角色中的“所有者”的权限和数据范围默认为全部且不可修改,以及部门主管仅显示角色成员外,其余角色权限皆可修改。
默认的角色:所有者、管理员、部门主管和成员,具体说明如下图:
- 企业所有者:仅限1人,具有企业最高的功能权限和最全的数据可见范围;
- 管理员:可设置多名员工,可设置其对应的功能权限,默认情况下具有大部分功能操作权限和本人相关的数据范围,可按企业所需自行编辑修改;
- 部门主管:仅显示出企业组织架构中已设置的“部门主管”。如需添加“部门主管”,请到【成员管理】页面,在【编辑部门】中设置“部门主管”,设置完成后信息自动同步;
- 成员:系统默认角色,设置除了所有者、管理员、主管外的企业成员应有的基础功能权限和数据可见范围。
系统按照常见的“职务”预置了部分角色,如财务、出纳、客户、采购、人事、行政、HR,按照“区域”预置了东区、西区、南区、北区、华中区,企业可增删改此类角色,可根据所需配置相应的角色成员、功能权限和数据可见范围。
Tips:
(1)若一个成员归属于多个角色,则此成员的权限为所在角色具有的权限合集;
(2)系统默认角色“企业所有者”默认仅有1人,如需更换企业所有者,需要在系统后台【企业设置】页面中通过”转让企业“来更换企业所有者;
(2)设置不同角色的功能权限范围
添加完角色成员后,可继续配置角色对应的功能权限。此处的功能权限包含系统所有的基础功能权限、应用管理权限以及后台模块的管理权限配置,勾选权限并保存即可设置成功。
Tips:
(1)角色功能权限的详细说明,请戳链接:
(2)在功能权限中配置了审批、考勤、销售、简报的操作权限后,同时应配置一下此角色的可操作的数据范围。
(3)功能权限的具体说明描述如下图:
(3)设置数据的查看、管理范围
在设置了角色的成员、权限后,还可以针对审批、考勤、简报、销售等OA应用来设置该角色的查看、管理数据范围。通常,企业的数据面对不同职务的员工需要有不同的查看、管理数据范围,如销售总监可以查看全部销售、客户、合同的统计,但是销售组长只能查看本组成员范围数据,而普通的销售人员仅能查看与本人相关的数据。通过设置角色的数据查看、管理范围,可以有效的解决这类问题。常见的查看数据范围主要分为:本人相关、本部门、本部门及下属部门、全部。除了企业所有者外,其他所有角色默认的数据范围为本人相关,可根据不同角色自行调整修改。设置范围后,在产品中查看考勤、简报、客户、销售、合同统计时,不同的角色仅能查看、管理对应所设定的查看、管理范围内数据。
- 本人相关:仅限于本人创建、参与的数据;
- 本部门:本角色可查看用户所属部门数据;
- 本部门及下级部门:本角色可查看用户所属部门,及其子部门数据;
- 全部:本角色可查看全公司的数据。
Markdown语法介绍
什么是Markdown语法?
Markdown 是一种轻量级标记语言,目标是实现「易读易写」。Coding.net的许多版块都采用了Markdown语法,比如冒泡,讨论,Pull Request等。
标题
在Markdown中,你只需要在文本前面加上# 即可,同理、你还可以增加二级标题、三级标题、四级标题、五级标题和六级标题,总共六级,只需要增加# 即可,标题字号相应降低。例如:
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
点击预览可以看到效果:
锚点
Coding 会针对每个标题,在解析时都会添加锚点id,如
# 锚点
会被解析成:
<h1 id="user-content-锚点">锚点</h1>
注意我们添加了一个user-content-的前缀所以如果要自己添加跳转链接要使用markdown的形式,且链接要加一个’user-content-‘前缀,如:
[问内链接](#user-content-锚点);
###引用 Markdown 标记区块引用是使用类似 email 中用 > 的引用方式,只需要在整个段落的第一行最前面加上 > :
> Coding.net 为软件开发者提供基于云计算技术的软件开发平台,包括项目管理,代码托管,运行空间和质量控制等等。
效果图如下:
区块引用可以嵌套,只要根据层次加上不同数量的 > :
> 这是第一级引用。
>
> > 这是第二级引用。
>
> 现在回到第一级引用。
效果图如下:
引用的区块内也可以使用其他的 Markdown 语法,包括标题、列表、代码区块等:
> ## 这是一个标题。
>
> 1. 这是第一行列表项。
> 2. 这是第二行列表项。
>
> 给出一些例子代码:
>
> return shell_exec("echo $input | $markdown_script");
效果图如下:
###列表 列表项目标记通常放在最左边,项目标记后面要接一个字符的空格。 无序列表:使用星号、加号或是减号作为列表标记
- Red
- Green
- Blue
效果图如下:
有序列表:使用数字接着一个英文句点
1. Red
2. Green
3. Blue
效果图如下:
如果要在列表项目内放进引用,那 > 就需要缩进:
* Coding.net有以下主要功能:
> 代码托管平台
> 在线运行环境
> 代码质量监控
> 项目管理平台
效果图如下:
代办列表: 表示列表是否勾选状态
- [ ] 不勾选
- [x] 勾选
效果图如下:
代码
只要把你的代码块包裹在 ``` 之间,你就不需要通过无休止的缩进来标记代码块了。 在围栏式代码块中,你可以指定一个可选的语言标识符,然后我们就可以为它启用语法着色了。 举个例子,这样可以为一段 Ruby 代码着色:
```ruby
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
```
效果图如下:
强调
在Markdown中,可以使用 * 和 _ 来表示斜体和加粗。
斜体:
*Coding,让开发更简单*
_Coding,让开发更简单_
效果图如下:
加粗:
**Coding,让开发更简单**
__Coding,让开发更简单__
效果图如下:
自动链接
方括号显示说明,圆括号内显示网址, Markdown 会自动把它转成链接,例如:
[超强大的云开发平台Coding](http://coding.net)
效果图如下:
或者也可以直接用< >,将网址或者邮箱地址放在中间,也能将地址直接转成链接:
<support@coding.net>
效果图如下:
表格
在 Markdown 中,可以制作表格,例如:
```
First Header | Second Header | Third Header
------------ | ------------- | ------------
Content Cell | Content Cell | Content Cell
Content Cell | Content Cell | Content Cell
```
效果图如下:
或者也可以让表格两边内容对齐,中间内容居中,例如:
```
First Header | Second Header | Third Header
:----------- | :-----------: | -----------:
Left | Center | Right
Left | Center | Right
```
效果图如下:
分割线
在 Markdown 中,可以制作分割线,例如:
---
效果图如下:
上下标
\^表示上标, _表示下标。如果上下标的内容多于一个字符,要用{}把这些内容括起来当成一个整体。上下标是可以嵌套的,也可以同时使用。 例如:
x^{y^z}=(1+{\rm e}^x)^{-2xy^w}
效果图如下:
图片
Markdown 使用了类似链接的语法来插入图片, 包含两种形式: 内联 和 引用.
内联图片语法如下:

或

也就是:
一个感叹号: !
; 紧跟一对方括号, 包含了可选填的图片 alt 属性; 紧跟一对圆括号, 包含了图片的 URL 或者路径, 以及一个可选的用单引号或双引号包裹的 title 属性.
引用图片语法如下:
![Alt text][id]
“id” 是图片引用的名称. 图片引用使用链接定义的相同语法:
[id]: url/to/image "Optional title attribute"
大总结-JS-挖 “掘” 淘 “金” 之 前端闯关历险记学习资料汇总
世间万物,为我所用。
掘金不仅是一个很好的在线同性交友平台,也是一个学习交流和分享技术场所,更是程序猿和程序媛获取养料的精神家园。
分享是一个杂乱无章的环节,这无可厚非,因为在这里人人平等,每个人都可以分享自己看到的精品文章,也可以创作记录分享自己的成果,这是平台带给大家的优势,同时,面对零零散散的文章,对于我们来说,很困惑,我到底该学什么,从入门到精通的过程是怎样的?我该如何系统的学习这门语言?
汪洋大海,我该如何探寻所需的宝藏?
学习路途,我该如何寻找最佳的曲线?
去年开始看掘金,收藏了很多文章,也收获了很多知识,但是对于上面的疑问一直也在摸索当中,这里先感谢掘金这个平台,让我能学习到很多新的未知的东西,但在用掘金的这段时间内,也发现看的东西虽然很多,但是很杂,没有系统化的去深入了解一个东西,于是诞生了把自己看到过的,错过的,还有将要发表的,一起做一个整理和集合。
看见好的文章就收藏,后来发现收藏了几百篇,很多都是重复的,也不够系统化,资源如浩瀚大海,找起来也麻烦,无疑给自己增加了负担,在此,为了方便大家系统的学习前端这门课程,找准自己的定位,我利用空余时间,把掘金有屎以来分享的前端文章做了一个归类,方便掘金的朋友学习和收藏,喜欢的朋友可以收藏一下,这篇文章会持续更新,也欢迎关注【我的GitHub博客】获取最新动态。
贵有恒何必三更眠五更起,最无益只怕一日曝十日寒。 一天更新一点,每天看一点,坚持就是胜利,如果只整理和收藏不花时间看,一切都是徒劳。✌️
一、推荐规则
- 推荐内容全部来自广大码农朋友的分享和专栏的原创,也就是掘金能搜索到的内容;
- 每个分类原则上不多于3篇,除非这一分类优秀的文章特别多;
- 每个文章我都有粗略阅读,排名按照收藏数和个人感觉关联度;
- 文章日期全部来自2017-3月之前,会不定期更新,如果遗漏非常精彩的文章,可以及时联系我
- 由于工程量大,推荐和排版难免出错,还望见谅,如果错误请底下及时评论反馈
二、代码规范篇
没有规矩,无以成方圆。
为什么把这个放在首位呢?好的代码规范不仅自己看起来赏心悦目,心情舒畅,我怎么就这么牛逼写出这么好看的代码(熏疼自己三秒钟,这往往只是错觉),别人看起来也直观一目了然,后来接手维护的人看了这种高逼格的代码也不会出现这种情况:这尼玛什么几把玩意,简直一坨翔,坑死劳资了(反正我走了也听不到?,你就骂吧)
2.1 前端开发规范总览
2.2 HTML规范
2.3 CSS规范
2.4 JS规范
《JavaScript风格指南》
《JavaScript 代码整洁之道》
《Airbnb 的 JavaScript 编程规范》
2.5 ES6规范
三、前言
国学大师王国维自己的著作《人间词话》中说:
古今之成大事业、大学问者,必经过三重境界:
第一境界:昨夜西风凋碧树,独上高楼,望尽天涯路。
第二境界:衣带渐宽终不悔,为伊消得人憔悴。
第三境界:众里寻他千百度,蓦然回首,那人却在灯火阑珊处。
其实我觉得学习JavaScript也要经历类似的三种阶段:
第一境界:看山是山,看水是水。
第二境界:看山不是山,看水不是水。
第三境界:看山还是山,看水还是水。
国学大师王国维精妙地以三句词道破人生之路:起初的迷惘,继而的执着和最终的顿悟。
我以瞎几把乱扯三句词道破学习JavaScript之路:起初的表象,继而的本质和最终的本质回归到现象。
四、JavaScript基础篇
看是是山,看水是水。
万丈高楼平地起,胸有丘壑宏图画。
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。任何事情都要从基础做起,打好基础,不浮躁,才能做好一件事,学习一门语言也是一样,从“Hello World!"开始,踏踏实实,夯实基础,基础知识是整个学习体系的根本,没有牢固的基础知识作为根基,我们的学习和努力必将事倍功半,学习提纲是巩固基础知识的一种有效手段.
《思维导图来学习Javascript基础知识》
《多年 JavaScript 学习笔记整理》
《javascript 基础小结篇》
《前端开发基础 - JavaScript》
《你不知道的 Javascript》
五、JavaScript进阶篇
看山不是山,看水不是水。
其实地上本没有坑,踩的人多了,于是就有了。
JS是一门玄学,是一门很灵活的语言,当然里面有很多不好懂的概念,尤其是学完基础之后,对执行环境
、this
、类型转换
、作用域链
、闭包
、原型链
、继承
、eval
、JS左值与引用
、浅复制与深复制
、IIFE
、模块化
、函数式编程
等等都有着这样或那样的不解之惑,想要成为JS大神这些门槛和坑不得不踩。
5.1 内存空间
因为JavaScript具有自动垃圾回收机制,所以对于前端开发来说,内存空间并不是一个经常被提及的概念,很容易被大家忽视。特别是很多不是计算机专业的朋友在进入到前端之后,会对内存空间,内存管理,内存释放的认知比较模糊,甚至有些人干脆就是一无所知。
《前端基础进阶:详细图解 JavaScript 内存空间》
《JavaScript 内存管理》
《JavaScript 中的内存释放》
5.2 执行上下文与作用域
首先来说说js中的执行环境,所谓执行环境(也称执行上下文–execution context)它是JavaScript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据 ,决定了它们各自的行为。而每个执行环境都有一个与之相关的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链包含了执行环境栈中的每个执行环境对应的变量对象.通过作用域链,可以决定变量的访问和标识符的解析。
《前端基础进阶:详细图解 JavaScript 执行上下文》
《深入探讨 JavaScript 的执行环境和栈》
《图解 JS 上下文与作用域》
5.3 变量对象
深入理解执行上下文中的变量对象,从原理上解释变量提升,为接下来理解作用域链,闭包,原型打下坚实的理论基础,值得基础知识不牢固的盆友一阅。
5.4 作用域链与闭包
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链包含了执行环境栈中的每个执行环境对应的变量对象.通过作用域链,可以决定变量的访问和标识符的解析。
关于闭包的概念,是婆说婆有理。因而,我就翻阅了**红皮书(p178)**上对于闭包的陈述:
闭包是指有权访问另外一个函数作用域中的变量的函数
这概念有点绕,拆分一下。从概念上说,闭包有两个特点:
- 1、函数
- 2、能访问另外一个函数作用域中的变量
在ES 6之前,Javascript只有函数作用域的概念,没有块级作用域(但catch捕获的异常 只能在catch块中访问)的概念(IIFE可以创建局部作用域)。每个函数作用域都是封闭的,即外部是访问不到函数作用域中的变量。
《前端基础进阶:详细图解,彻底搞懂闭包与作用域链》
《JavaScript 闯关记之作用域和闭包》
《你想知道的关于 JavaScript 作用域的一切 (译)》
《弄懂 JavaScript 的作用域和闭包》
5.5 this
This,传说中的天使还是魔鬼?对于新手来说,this的指向一直是很头疼的地方,用的好就是天使,用的差就是魔鬼了,人人都想成为代码中的天使,为了避免成为魔鬼,我们必须好好深入学习一下this的作用机理和一些常见的坑。
《前端基础进阶:全方位解读 this》
《JavaScript 中的 this 陷阱的最全收集 -- 没有之一》
《Javascript 深入浅出 this》
《从 ECMA 规范深入理解 js 中的 this》
5.6 原型链
在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对 象共有的特点。 即:对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例 能够访问在构造函数原型中定义的属性和方法。
《JavaScript原型详解》
《三张图搞懂JavaScript的原型对象与原型链》
《JavaScript 原型中的哲学思想》
《一张图搞懂 Javascript 中的原型链、prototype、__proto__的关系》
5.7 继承
Javascript 这门语言对于习惯了众多传统 OOP 语言 (c++,Java 等) 的 coder 来说其实是一门很奇怪的语言, 因为 Javascript 的 OOP 方式是基于原型的, 而非传统的类继承,主要有原型链继承,借用构造函数继承,组合继承,寄生式继承,寄生组合继承。
《js 原型链继承,借用构造函数继承, 组合继承,寄生式继承,寄生组合继承》
《Javascript 三招两式之对象继承 (上)》
《JavaScript 三招两式之对象继承 (下)》
《征服 JavaScript 面试系列:类继承和原型继承的区别》
《谈一谈 JavaScript 继承》
5.8 arguments
每个函数都会有一个 Arguments 对象实例 arguments,它引用着函数的实参,可以用数组下标的方式”[]” 引用 arguments 的元素。arguments.length 为函数实参个数,arguments.callee 引用函数自身。
《Arguments 对象深入了解》
《javascript arguments(callee、caller) 详解》
《Javascript 中的 arguments 对象》
5.9 类型转换
如果把通过函数或方法调用,明确的将某种类型转换成另一种类型称为显示转换 ,相反则称为隐式类型转换 。google和维基百科中没有找到“显示类型转换”,“隐式类型转换”的字眼。暂且这么称呼。 JavaScript的数据类型是非常弱的(不然不会叫它做弱类型语言了)!在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可和数字相加。之所以不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的,如下是数值类型和布尔类型的相加:
3 + true; // 4
结果是一个数值型!如果是在C或者Java环境的话,上面的运算肯定会因为运算符两边的数据类型不一致而导致报错的!但
是,在JavaScript中,只有少数情况下,错误类型才会导致出错,比如调用非函数,或者读取null或者undefined的属
性时。
《从 []==![] 为 true 来剖析 JavaScript 各种蛋疼的类型转换》
《一篇文章搞定 JS 类型转换》
《聊一聊 JS 中的『隐式类型转换』》
5.10 IIFE
全拼Imdiately Invoked Function Expression,立即执行的函数表达式。立即执行函数在模块化中也大有用处。用立即执行函数处理模块化可以减少全局变量造成的空间污染,构造更多的私有变量。
立即执行函数写法大全:
// 最常用的两种写法
(function(){ /* code */ }()); // 老道推荐写法
(function(){ /* code */ })(); // 当然这种也可以
// 括号和JS的一些操作符(如 = && || ,等)可以在函数表达式和函数声明上消除歧义
// 如下代码中,解析器已经知道一个是表达式了,于是也会把另一个默认为表达式
// 但是两者交换则会报错
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
// 如果你不怕代码晦涩难读,也可以选择一元运算符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
// 你也可以这样
new function(){ /* code */ }
new function(){ /* code */ }() // 带参数
《javascript模块化编程-详解立即执行函数表达式IIFE》
《Javascript 的匿名函数与自执行》
《js 匿名自执行函数中闭包的高级使用(前端必看)》
这一篇掘金没有推荐过,不过我认为真的写的很全很详细,这里也推荐一下:
《详解javascript立即执行函数表达式(IIFE)》
5.11 setTimeout
平时的工作中,也许你会经常用到setTimeout这个方法,可是你真的了解setTimeout吗?本系列想通过总结setTimeout的用法,顺便来探索javascript里面的事件执行机制。在一个基础阶段,理解JavaScript定时器的工作原理的是非常重要的。通常它们看起来不那么直观,因为它们处于单线程中。
《[译] JavaScript 中的定时器是如何工作的?》
《关于 JavaScript 定时器我的一些小理解》
《JavaScript 定时器及相关面试题》
《【原】以 setTimeout 来聊聊 Event Loop》
5.12 Object.defineProperty()函数
该方法允许精确添加或修改对象的属性。一般情况下,我们为对象添加属性是通过赋值来创建并显示在属性枚举中(for...in 或 Object.keys 方法), 但这种方式添加的属性值可以被改变,也可以被删除。而使用 Object.defineProperty() 则允许改变这些额外细节的默认设置。例如,默认情况下,使用 Object.defineProperty() 增加的属性值是不可改变的。 对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个拥有可写或不可写值的属性。存取描述符是由一对 getter-setter 函数功能来描述的属性。描述符必须是两种形式之一;不能同时是两者。
《理解 JavaScript 的 Object.defineProperty() 函数》
《解析神奇的 Object.defineProperty》
《双向绑定的简单实现 - 基于 ES5 对象的 getter/setter 机制》
5.13 call、apply、bind
今天看博客时,看到了这样的一段js代码: var bind = Function.prototype.call.bind(Function.prototype.bind); 上面那段代码涉及到了call、bind,所以我想先区别一下call、apply、bind的用法。这三个方法的用法非常相似,将函数绑定到上下文中,即用来改变函数中this的指向。这个系列就是让大家深入理解其中的差异。
《JS 中 call、apply、bind 那些事》
《JavaScript 中的 call、apply、bind 深入理解》
《回味JS基础:call apply 与 bind》
《深入浅出妙用 Javascript 中 apply、call、bind》
5.14 深拷贝与浅拷贝
eg:有A、B两个对象,且都有子对象
深拷贝:将B对象拷贝到A对象中,包括B里面的子对象;
浅拷贝:将B对象拷贝到A对象中,但不包括B里面的子对象;
首先深复制和浅复制只针对像 Object, Array 这样的复杂对象的。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。
《JavaScript 深拷贝》
《javaScript 中的浅拷贝和深拷贝》
《深入剖析 JavaScript 的深复制》
5.15 正则表达式
还记得被称为正则小王子的jQuery作者吗?但正则表达式对于我来说一直像黑暗魔法一样的存在。手机正则去网上搜,邮箱正则去网上搜,复杂点的看看文档拼凑一下,再复杂只能厚着脸皮让其他同事给写一个。从来没有系统的学习过,搞完这个系列是不是准备拿下它。
《正则表达式 - 理论基础篇》
《正则表达式学习笔记》
《正则表达式实践篇》
《常见的正则表达式可视化描述》
《最全面的常用正则表达式大全》
5.16 事件
JavaScript 程序采用了异步事件驱动编程(Event-driven programming)模型,维基百科对它的解释是:
事件驱动程序设计(英语:Event-driven programming)是一种电脑程序设计模型。这种模型的程序运行流程是由用户的动作(如鼠标的按键,键盘的按键动作)或者是由其他程序的消息来决定的。相对于批处理程序设计(batch programming)而言,程序运行的流程是由程序员来决定。批量的程序设计在初级程序设计教学课程上是一种方式。然而,事件驱动程序设计这种设计模型是在交互程序(Interactive program)的情况下孕育而生的
《JavaScript 浏览器事件解析》
《深入理解 - 事件委托》
《我也来说说 JS 的事件机制》
《DOM 事件深入浅出(一)》
《DOM 事件深入浅出(二)》
《JS 中的事件绑定、事件监听、事件委托是什么?》
5.17 其他混淆点
其他一些容易混淆的难点就不单独开一个类型,这里就统一做一个系列说明,也是平时经常遇到的一些痛点和难点吧,主要是区分一些概念,知道彼此之间的异同,以下简称一张图系列。
《一张图看懂JavaScript中数组的迭代方法:forEach、map、filter、reduce、every、some》
《一张图看懂encodeURI、encodeURIComponent、decodeURI、decodeURIComponent的区别》
《一张图彻底掌握 scrollTop, offsetTop, scrollLeft, offsetLeft......》
《一张图看懂 Function 和 Object 的关系及简述 instanceof 运算符》
六、JavaScript高手篇
看山还是山,看水还是水。
如果学习JavaScript不是为了成为高手,那将毫无意义。
其实,高手有一颗寂寞的心,因为高手的造就本就是用寂寞堆积而成。
6.1 JavaScript数据结构与算法篇
程序设计=数据结构+算法
6.1.1 数组去重
6.1.2 排序
6.1.3 查找
6.1.4 数据结构
《学习JavaScript数据结构(一)——栈和队列》
《学习 JavaScript 数据结构(二)——链表》
《学习 JavaScript 数据结构(三)——集合》
《学习 javascript 数据结构 (四)——树》
《javaScript的数据结构与算法(五)——字典和散列表》
6.1.5 其它
《前端面试中常见的算法问题读后整理》
《常见数据结构 (一)- 栈, 队列, 堆, 哈希表》
《常见数据结构 (二)- 树 (二叉树,红黑树,B 树)》
《算法学习笔记》
《javascript array js 缓存算法、数组随机抽取、字母串转数字,数字转字符串》
《JavaScript 算法练习》
6.2 JavaScript跨域
** 由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。具体可以查看下表(来源)**
《前端跨域问题及解决方案》
《直白的话告诉你在 javascript 中如何用 jsonp 实现跨域请求》
《前端 Ajax 跨域请求方案沙里淘金》
《你所不知道的跨域资源共享(CORS)》
《带你一步一步的理解前端跨域的原理及实践》
《HTML5 跨域通信 API - window.postMessage》
《前端跨域整理》
《跨域问题,解决之道》
6.3 JavaScript设计模式
为什么要学习设计模式? 做事情之前问个为什么总是好的。关于设计模式的好坏,我在知乎上也看过一些讨论,有知友对其提出过一些疑问,里面有一些关于设计模式的观点:
- 设计模式有何不妥,所谓的荼毒体现在哪?
- 设计模式是不是有点太玄了?
任何事物的出现都有其道理,任何语言都有其不足之处,设计模式是对语言不足的补充(Peter Norvig)。设计模式也是编程经验的总结,我想学习它对像我这样的前端新手的能力会有很大的提升。
细说说它的好处:
- 设计模式能让你用更少的词汇做更充分的沟通;
- 谈话在模式层次时,不会被压低到对象和类这种琐碎的事情上;
- 懂设计模式的团队,彼此之间对于设计的看法不容易产生误解;
- 共享词汇能帮助初级人员快速成长。
《学习设计模式前需要知道的事情》
《常用的 JavaScript 设计模式》
《JavaScript 设计模式》读后感觉很复杂
《JavaScript 设计模式》
《听飞狐聊 JavaScript 设计模式系列 13》
6.4 JavaScript函数式编程
什么是函数式编程?
- 与面向对象编程(Object-oriented programming)和过程式编程(Procedural programming)并列的编程范式。
- 最主要的特征是,函数是第一等公民。
- 强调将计算过程分解成可复用的函数,典型例子就是map方法和reduce方法组合而成 MapReduce 算法。
- 只有纯的、没有副作用的函数,才是合格的函数。
《函数式编程入门教程》
《想学函数式编程?》
《给 JavaScript 开发者讲讲函数式编程》
《前端基础进阶(七):函数与函数式编程》
《『翻译』JavaScript 函数式编程》
《JavaScript 函数式编程》
6.5 JavaScript高阶函数
具体来说,在 JavaScript 中,我们可以将一个函数 A 作为参数传给另一个函数 B,或者,在函数 B 中将函数 A 作为返回值返回。那么这里的函数 B 就是上面所说的高阶函数。 在《javascript设计模式和开发实践》中是这样定义的。 函数可以作为参数被传递; 函数可以作为返回值输出。
《javascript 高阶函数介绍》
《程序媛学 JS 小记一笔——高阶函数》
《高阶函数对系统的 “提纯”》
《JavaScript 之闭包与高阶函数(一)》
6.6 JavaScript性能优化
天下武功,无坚不摧,唯快不破。
Javascript是一门非常灵活的语言,我们可以随心所欲的书写各种风格的代码,不同风格的代码也必然也会导致执行效率的差异,作用域链、闭包、原型继承、eval等特性,在提供各种神奇功能的同时也带来了各种效率问题,用之不慎就会导致执行效率低下,开发过程中零零散散地接触到许多提高代码性能的方法,整理一下平时比较常见并且容易规避的问题。
《吹毛求疵的追求优雅高性能JavaScript》
《天生就慢的 DOM 如何优化?》
《Javascript 高性能动画与页面渲染》
《一个关于 js 线程和性能优化的文档,有例子哦!》
《合理使用 IIFE 优化 JS 引擎的性能》
《高性能 JavaScript》读书笔记
6.7 JavaScript 柯里化
就像最早听到斐波拉切数列一样,第一次听到柯里化我也是懵逼的
柯里化又称部分求值,字面意思就是不会立刻求值,而是到了需要的时候再去求值。如果看的懵逼,没事,看完整篇文章再回过头来看这里你就会豁然开朗。 反柯里化的作用是,当我们调用某个方法,不用考虑这个对象在被设计时,是否拥有这个方法,只要这个方法适用于它,我们就可以对这个对象使用它。
《前端高手必备:详解 JavaScript 柯里化》
《简单理解JavaScript中的柯里化和反柯里化》
《浅谈函数式编程柯里化的魔法》
《从一道面试题谈谈函数柯里化 (Currying)》
《掌握 JavaScript 函数的柯里化》
6.8 JavaScript调试
如今 Chrome 浏览器无疑是最受前端青睐的工具,原因除了界面简洁、大量的应用插件,良好的代码规范支持、强大的 V8 解释器之外,还因为 Chrome 开发者工具提供了大量的便捷功能,方便我们前端调试代码,我们在日常开发中是越来越离不开 Chrome,是否熟练掌握 Chrome 调试技巧恐怕也会成为考量前端技术水平的标杆。 介绍 Chrome 调试技巧的文章很多,本文结合我自己的开发经验,希望从实际运用的角度为大家再一次谈一谈这些功能,也希望对大家都有所帮助和启发。 在chrome的开发者工具中,通过断点调试,我们能够非常方便的一步一步的观察JavaScript的执行过程,直观感知函数调用栈,作用域链,变量对象,闭包,this等关键信息的变化。因此,断点调试对于快速定位代码错误,快速了解代码的执行过程有着非常重要的作用,这也是我们前端开发者必不可少的一个高级技能。
《前端高手必备技能:如何在 chrome 开发者工具中观察函数调用栈、作用域链与闭包》
《比 console.log 更多-chrome 调试命令》
《JavaScript30 中文指南 - 09 Console 调试技巧指南》
《聊一聊移动端调试那些事》
《前端 chrome 浏览器调试总结》
《我的职业是前端工程师【五】: 前端工程师必会的六个调试技能》
《九个 Console 命令,让 js 调试更简单》
《再谈 Chrome 实用调试技巧》
《调试 CSS 的方法》
《前端调试效率低?试试这 10 个 Chrome 开发者工具 使用技巧》
《前端开发中的 JS 调试技巧》
6.9 前端安全
天下武功,唯快不破。算法越快,越容易破。
《如何让前端更安全?——XSS 攻击和防御详解》
《HTTPS 互联网世界的安全基础》
《关于 Web 安全,99% 的网站都忽略了这些》
《Web 前端慢加密》
6.10 技巧和效率
技巧恰似黑魔法,效率堪比加速器,都是开发过程中不可或缺的一部分,善用技巧,提高效率。
高手之所以高,很大一部分在于技巧巧妙,效率高,让人自愧不如,所以成了我们眼中的高手,其实高手也是从菜鸟过来的,由于长期的学习和经验的积累,再加上善于总结,自然一步步成长成为高手,为了加速自己成为高手,我们可以向高手取经,学习他们分享的一些技巧和解决问题思维方式。
《34 个实用的 webAPP 开发技巧分享,值得收藏》
《不造个轮子,你还真以为你会写代码了? | 掘金技术征文》
《【译】帮助你更快学习 JavaScript 的六个思维技巧》
《提升效率黑科技》
《【译】六个漂亮的 ES6 技巧》
《【译】45种 Javascript 技巧大全》
《程序员应该掌握的 10 个搜索技巧》
《你必须『收藏』的Github技巧》
《老司机教你更好的进行 CSS 编程 70 个技巧》
《聊一聊这些常见而且实用的 css 技巧》
七、JavaScript框架篇
青,取之于蓝而青于蓝;冰水为之而寒于水。
jQuery:一年没写链式JQ了,在这个人手一个MVVM框架的年代,JQuery就不做推荐,想要了解可以自行学习。
vue.js react.js,angularjs···此处省略一万篇文章和略干文字。
关于框架的学习,最好多看看官方文档,多多实践,我这里就不多做介绍了,框架太多,我用的也不多,这里也就不献丑推荐什么的,自己对框架也一知半解,没有深入去研究底层的实现,仅仅停留在够用就行没去深究的层面,大家想学什么框架可以自己去搜索相关资料和教程。
八、HTTP和HTTPS篇(待续,下一步学习中)
九、前端工程化篇
解放双手,成就你的梦想。
十、全栈篇之Node.js(待续,正在学习中nodejs)
十一、面试篇
11.1 简历模板
简历好比人的一张脸,不能丑了别人,爽了自己。
对于开发者与设计师们,一封好的的简历会让自己的面试增色不少。本次分享的简历简介精致,而且样式多种多样。包含 INDD、IDML、PDF、PSD、DOCX 等格式,方便自由修改和学习。
《Talk is cheap, show me the code - 用 github 数据辅助你完善简历》
《27 款优质简洁的个人简历打包下载》
《10+ 优秀简洁的个人简历下载(五)》
《15 款优质实用简洁的个人简历模板打包下载 (一)》
《5 款精致简洁求职简历》
11.2 面试题
任凭风吹雨打,胜似闲庭信步。
首先我希望表达的一点,就是面试的评判跟学校里的考试完全是两回事,太多的人把面试当做考试而把注意力放在题目上。 事实上面试中未必是所有题目全都回答"正确"就一定会通过或者较高评价。面试是面试官和面试者双方"挖掘与展示才能"的过程,参考前面提到的面试过程,全部回答正确的情况很可能是因为面试官不感兴趣懒得追问。 对于面试官而言,基本评判原则就是"我要不要这个人做我的同事?",多数情况下,这个答案会非常清楚。一些题目是充分的,也就是"回答对了说明这个人具有可以依靠的才能",一些题目则是必要的,也就是"回答错了说明这个人无法胜任我们的工作"。
《最近遇到的前端面试题》
《大厂前端面试题汇总》
《前端面试集合》
《前端面试题精选》
《一道 JS 面试题所引发的 "血案",透过现象寻本质,再从本质看现象》
11.3 面试技巧、经验与感悟
他山之石,可以攻玉。
经验犹如一所大学校,它能使你认识到自己是个什么样的傻瓜。
人生就是不断的推销自己,不停的面试,狭义的面试我们认为就是工作上的面试,而广义的面试就是做人的面试,到处就是展示推销自己。看看别人面试心得,取经一下,避免别人已经犯过的错误,也是一种进步。
《面试感悟:一名 3 年工作经验的程序员应该具备的技能》
《我的 web 前端面试经历 - 百度》
《1月前端面试记》
《关于前端面试》
《迟来的面试总结》
十二、资源汇总
积土成山,风雨兴焉;积水成渊,蛟龙生焉。
善于积累,善于总结,也是学习的一门功课,积累是一个循序渐进的过程,搜集总结同时也是一个费时费力的过程,看看别人的积累和总结,不禁感叹于别人的知识面和认真的态度,自己会觉得有压力从而产生动力,此时的自己会不会蠢蠢欲动,给自己所学所看来一个强势的总结呢?
《也许是史上最全的前端资源大汇总》
《JavaScript 开发者必备的资源合集》
《前端知识点大百科全书》
《100+ 超全的 web 开发工具和资源整理》
《Web 前端从入门菜鸟到实践老司机所需要的资料与指南合集》
《GitHub 上最全的前端入门资源汇总 快速入门前端》
《前端教程 & 开发模块化 / 规范化 / 工程化 / 优化 & 工具 / 调试 & 值得关注的博客 / Git & 面试 - 资源汇总》
《送给前端的你,推荐几篇前端汇总文章。 - 学习编程 - 知乎专栏》
《前端学习资源汇总——前端收藏夹》
《最全前端资源汇集》
十三、插件
插件是我们开发时候的左膀右臂。
平时自己写插件主要有下面几个问题:
(1)开发插件需要时间,可能拖延项目工期,如果工期紧急不建议选用这种方式
(2)自己造的轮子未必有现有轮子的好用,要考虑到队友是否适用
(3)需要比较高的开发水平
这里搜集一些常用的插件供大家参考使用。
十四、工具篇
工欲善其事,必先利其器。
张三和李四都要上山砍柴,但他们的斧头都有点钝了,张三没有理会,拿着斧头就上山了,因为他的斧头不利,砍的都是比较细的树柴……李四就不同了,他拿来磨刀石,用劲地把斧头先磨好,虽然他比张三慢了起步,但是他的准备工夫做到家了,砍柴砍得很快。到太阳下山了,张三只背了小小的一捆柴下来,但是李四,背着一大捆的柴下来…… 由此可见,准备工夫做好了,可以事半功倍!
《超全面 + 最流行的「前端速查表」高清版大全》
《成为专业程序员路上用到的各种优秀资料、神器及框架》
《前端切图神器 avocode》
《2015 年末必备前端工具集》
《【译】2016 年我最喜欢的前端工》
《前端新手可以浏览的网站》
《收集非常好用的 Mac 应用程序、软件以及工具,主要面向开发者和设计师。》
《工具武装的前端开发工程师》
《一个前端程序猿的 Sublime Text3 的自我修养》
《前端工程师的工具包》
十五、鸣谢
- 感谢党和国家
- 感谢美利坚创造了互联网
- 感谢掘金这个在线同性交友的场所
- 感谢掘金CEO以及工作人员创造了这个平台
- 感谢创作和分享的广大同行码农提供了本文原始素材
- 感谢各位大神愿意含辛茹苦的花时间观看鄙人这篇随便拼凑的文章
- 最后也厚颜无耻的感谢自己能静下心整理一篇文章和大家一起分享交流进步
十六、广告
本文分享首发【掘金】,同时收录在【我的GitHub博客】,觉得本文写的不算烂的,可以点击【我的GitHub博客】顺便登录一下账号给个星星✨鼓励一下,关注最新更新动态,大家一起多交流学习,欢迎随意转载交流,不要钱,文末有福利哦?,你懂的?。
登高自卑,与君共勉。
十七、福利
文武之道,一张一弛,要劳逸结合,是不是?
老司机镇楼,投币上车。骚年,看了这么多这么累,是不是该撸一发呢?,我好想射点什么,先撸一盘LOL去了,哈哈,大家别想歪了。
待续的今后继续更新完善。
Linux环境变量区别
发现自己对Linux下 /etc/profile、/etc/bashrc、~/.bashrc的区别不是特别清楚,
特此查阅了相关资料,整理下来,供以后查阅。
①/etc/profile:
该文件登录操作系统时,为每个用户设置环境信息,当用户第一次登录时,该文件被执行。也就是说这个文件对每个shell都有效,用于获取系统的环境信息。
# /etc/profile
# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
②/etc/bashrc:
为每一个运行bash shell的用户执行此文件,当bash shell被打开时,该文件被读取。也就是说,当用户shell执行了bash时,运行这个文件。
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
③~/.bashrc
该文件存储的是专属于个人bash shell的信息,当登录时以及每次打开一个新的shell时,执行这个文件。在这个文件里可以自定义用户专属的个人信息。
那么在用户登录系统时候,相关的文件执行顺序是什么呢。
在刚登录Linux时,首先启动 /etc/profile 文件,然后再启动用户目录下的
~/.bash_profile、 ~/.bash_login或 ~/.profile文件中的其中一个,
执行的顺序为:~/.bash_profile、 ~/.bash_login、 ~/.profile。
如果 ~/.bash_profile文件存在的话,一般还会执行 ~/.bashrc文件。
非常详细的/etc/passwd解释
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
desktop:x:80:80:desktop:/var/lib/menu/kde:/sbin/nologin
mengqc:x:500:500:mengqc:/home/mengqc:/bin/bash
在该文件中,每一行用户记录的各个数据段用“:”分隔,分别定义了用户的各方面属性。各个字段的顺序和含义如下:
注册名:口令:用户标识号:组标识号:用户名:用户主目录:命令解释程序
(1)注册名(login_name):用于区分不同的用户。在同一系统中注册名是惟一的。在很多系统上,该字段被限制在8个字符(字母或数字)的长度之内;并且要注意,通常在Linux系统中对字母大小写是敏感的。这与MSDOS/Windows是不一样的。
(2)口令(passwd):系统用口令来验证用户的合法性。超级用户root或某些高级用户可以使用系统命令passwd来更改系统中所有用户的口令,普通用户也可以在登录系统后使用passwd命令来更改自己的口令。
现在的Unix/Linux系统中,口令不再直接保存在passwd文件中,通常将passwd文件中的口令字段使用一个“x”来代替,将/etc /shadow作为真正的口令文件,用于保存包括个人口令在内的数据。当然shadow文件是不能被普通用户读取的,只有超级用户才有权读取。
此外,需要注意的是,如果passwd字段中的第一个字符是“*”的话,那么,就表示该账号被查封了,系统不允许持有该账号的用户登录。
(3)用户标识号(UID):UID是一个数值,是Linux系统中惟一的用户标识,用于区别不同的用户。在系统内部管理进程和文件保护时使用 UID字段。在Linux系统中,注册名和UID都可以用于标识用户,只不过对于系统来说UID更为重要;而对于用户来说注册名使用起来更方便。在某些特 定目的下,系统中可以存在多个拥有不同注册名、但UID相同的用户,事实上,这些使用不同注册名的用户实际上是同一个用户。
(4)组标识号(GID):这是当前用户的缺省工作组标识。具有相似属性的多个用户可以被分配到同一个组内,每个组都有自己的组名,且以自己的组标 识号相区分。像UID一样,用户的组标识号也存放在passwd文件中。在现代的Unix/Linux中,每个用户可以同时属于多个组。除了在 passwd文件中指定其归属的基本组之外,还在/etc/group文件中指明一个组所包含用户。
(5)用户名(user_name):包含有关用户的一些信息,如用户的真实姓名、办公室地址、联系电话等。在Linux系统中,mail和finger等程序利用这些信息来标识系统的用户。
(6)用户主目录(home_directory):该字段定义了个人用户的主目录,当用户登录后,他的Shell将把该目录作为用户的工作目录。 在Unix/Linux系统中,超级用户root的工作目录为/root;而其它个人用户在/home目录下均有自己独立的工作环境,系统在该目录下为每 个用户配置了自己的主目录。个人用户的文件都放置在各自的
主目录下。
(7)命令解释程序(Shell):Shell是当用户登录系统时运行的程序名称,通常是一个Shell程序的全路径名,
如/bin/bash。
需要注意的是,系统管理员通常没有必要直接修改passwd文件,Linux提供一些账号管理工具帮助系统管理员来创建和维护用户账号。
Linux口令管理之/etc/passwd文件
/etc/passwd文件是Linux/UNIX安全的关键文件之一.该文件用于用户登录时校验 用户的口令,当然应当仅对root可写.文件中每行的一般格式为:
LOGNAME:PASSWORD:UID:GID:USERINFO:HOME:SHELL
每行的头两项是登录名和加密后的口令,后面的两个数是UID和GID,接着的 一项是系统管理员想写入的有关该用户的任何信息,最后两项是两个路径名: 一个是分配给用户的HOME目录,第二个是用户登录后将执行的shell(若为空格则 缺省为/bin/sh).
(1)口令时效
/etc/passwd文件的格式使系统管理员能要求用户定期地改变他们的口令. 在口令文件中可以看到,有些加密后的口令有逗号,逗号后有几个字符和一个 冒号.如:
steve:xyDfccTrt180x,M.y8:0:0:admin:/:/bin/sh
restrict:pomJk109Jky41,.1:0:0:admin:/:/bin/sh
pat:xmotTVoyumjls:0:0:admin:/:/bin/sh
可以看到,steve的口令逗号后有4个字符,restrict有2个,pat没有逗号.
逗号后第一个字符是口令有效期的最大周数,第二个字符决定了用户再次 修改口信之前,原口令应使用的最小周数(这就防止了用户改了新口令后立刻 又改回成老口令).其余字符表明口令最新修改时间.
要能读懂口令中逗号后的信息,必须首先知道如何用passwd_esc计数,计 数的方法是:
.=0 /=1 0-9=2-11 A-Z=12-37 a-z=38-63
系统管理员必须将前两个字符放进/etc/passwd文件,以要求用户定期的 修改口令,另外两个字符当用户修改口令时,由passwd命令填入.
注意:若想让用户修改口令,可在最后一次口令被修改时,放两个".",则下 一次用户登录时将被要求修改自己的口令.
有两种特殊情况:
. 最大周数(第一个字符)小于最小周数(第二个字符),则不允许用户修改 口令,仅超级用户可以修改用户的口令.
. 第一个字符和第二个字符都是".",这时用户下次登录时被要求修改口 令,修改口令后,passwd命令将"."删除,此后再不会要求用户修改口令.
(2)UID和GID
/etc/passwd中UID信息很重要,系统使用UID而不是登录名区别用户.一般 来说,用户的UID应当是独一无二的,其他用户不应当有相同的UID数值.根据惯 例,从0到99的UID保留用作系统用户的UID(root,bin,uucp等).
如果在/etc/passwd文件中有两个不同的入口项有相同的UID,则这两个用 户对相互的文件具有相同的存取权限.
/etc /group文件含有关于小组的信息,/etc/passwd中的每个GID在本文件中 应当有相应的入口项,入口项中列出了小组名和小组中的用户.这样可方便地了 解每个小组的用户,否则必须根据GID在/etc/passwd文件中从头至尾地寻找同组 用户.
/etc/group文件对小组的许可权限的控制并不是必要的,因为系统用UID,GID (取自/etc/passwd)决定文件存取权限,即使/etc/group文件不存在于系统中,具 有相同的GID用户也可以小组的存取许可权限共享文件.
小组就像登录用户一样可以有口令.如果/etc/group文件入口项的第二个域 为非空,则将被认为是加密口令,newgrp命令将要求用户给出口令,然后将口令加 密,再与该域的加密口令比较.
给 小组建立口令一般不是个好作法.第一,如果小组内共享文件,若有某人猜 着小组口令,则该组的所有用户的文件就可能泄漏;其次,管理小组口令很费事, 因为对于小组没有类似的passwd命令.可用/usr/lib/makekey生成一个口令写入 /etc/group.
以下情况必须建立新组:
(1)可能要增加新用户,该用户不属于任何一个现有的小组.
(2)有的用户可能时常需要独自为一个小组.
(3)有的用户可能有一个SGID程序,需要独自为一个小组.
(4)有时可能要安装运行SGID的软件系统,该软件系统需要建立一个新组.
要 增加一个新组,必须编辑该文件,为新组加一个入口项. 由于用户登录时,系统从/etc/passwd文件中取GID,而不是从/etc/group中 取GID,所以group文件和口令文件应当具有一致性.对于一个用户的小组,UID和 GID应当是相同的.多用户小组的GID应当不同于任何用户的UID,一般为5位数,这 样在查看/etc/passwd文件时,就可根据5位数据的GID识别多用户小组,这将减少 增加新组,新用户时可能产生的混淆.
抗压面试题分析
问题1
什么样的情形会让你感到沮丧?
分析:这个问题是用来发现你的致命弱点的。它会告诉面试人,什么样的紧张和压力可以让你失去希望、动力或行动能力。
错误回答:我很少处于沮丧之中,因为我非常有弹性。有些事情会让其他人感到非常沮丧,但对我往往只会有稍微的影响。
评论:求职者没有说出任何真正的致命弱点(面试中你永远不要说出自己的致命弱点),这一点是对的。但是,求职者否认存在任何使之沮丧的情况,这会让面试人感到怀疑。此外,在这种回答中,求职者还破坏了“不要打击别人”的法则,从而暴露了自己的弱点。
正确回答:我认为会让我感到沮丧的是一件事情拖得太久,虽然这并不经常发生。我认为,对于尚未解决的问题,并不是所有的成功企业都会有回旋的余地。我希望尽可能快地找到好的对策,这样我们就可以继续开展企业的业务。
评论:这种回答提供了一种真正的答案,而且它也不是软弱无力的。这样回答既合理,又不会让面试人对求职者的能力感到担心。它会使面试人确信,求职者重视质量和时间进度。
问题2
如果你在销售一种产品,遇上一位客户一直抱怨你的售后服务很糟糕,这时你会怎么办?
分析:从这个问题的回答可以看出求职者会如何应对一些难缠的客户。面试人期待求职者不要显得那么容易屈服。
错误回答:我记得一句谚语说:“客户永远是正确的。”我能够确保客户在离开时对我的产品感到非常满意。
评论:姜还是老的辣!面试人可能在他(她)的祖父那儿就听到过“客户永远是正确的”这句谚语。不要把面试人当小孩子来看待,记住,他(她)的智商不会比你逊色,甚至还会比你高。
正确回答:我将向客户解释,我们的企业向来以产品质量和优质服务为荣。然后我将向客户保证,我会尽一切努力来改善这种状况。接下来我会听他(她)抱怨,并查找问题的根源,做出必要的改进来满足客户。
评论:这个回答比“错误回答”里的陈词滥调要高明得多,而且也表明求职者重视服务质量。这样的回答显示出求职者没有被问题所吓倒,他(她)将采取必要的措施来解决问题。
问题3
当你确信自己是正确的,但是其他人却不赞同你时,你会怎样做?
分析:这个问题可以反映求职者是否能够恰当处理反对观点、是否能够承受额外压力,还可以显示求职者处理冲突的能力和自信程度。
错误回答:首先,我努力找到一种方法让他们相信我是正确的。如果这样做不奏效——实际上经常不奏效——我会思量是否有办法实现他们的目标,这样,对于我自认为正确的方式,他们就不会再干涉。
评论:除了有自大狂的嫌疑外,这种回答还存在其他问题。它意味着,如果求职者不能从反对者那里得到支持,他(她)将采取一切必要措施实现自己的方式。这种回答说明,在面对困难或者可能存在冲突的问题时,求职者就会失去道德标准。
正确回答:首先,我会确保有足够的信息来支持自己。一旦我确信自己的观点是正确的,我就会密切关注反对者的具体反对理由。我将从他们的角度看待问题,并以此说服他们。由于互相尊重,我相信我们可以最终达成协议。
评论:这种说法实现了几个目的。它表明求职者可以从解决问题的角度,用一种双赢的态度解决冲突;也表明,如果可以真正解决问题,那么求职者能够敞开胸怀接受改变;它还表明,求职者会采取一种合作的方式来解决困难问题。
问题4
你是否觉得有能力在自己的职位上取得成功?如果感到不妥,你将如何弥补自己的缺点?
分析:同其他涉及弱点的问题一样,你必须小心应对这个问题。如果承认自己有重大缺点,而且这些缺点将妨碍你的工作,这无疑将会使你失去机会。如果确实有一些微小的缺陷需要克服,那么可以提及一下。否则,如果不怕沉默会造成误解的话,你最好还是等到上任的时候再表白自己需要改进的地方。
错误回答:这个职位对我来说是小菜一碟,我闭着眼睛都能把它做好。我想,如果你聘用了我,你一定会对我如此迅速地完成任务而感到惊奇。这个岗位上没有什么我不能做的事情。
评论:尽管这种回答听起来很有力,但求职者显得过于狂妄了。除了会使面试人怀疑他(她)夸夸其谈的背后可能隐藏了什么东西外,面试人也会怀疑求职者是否适合这个职位。如果求职者能够做如此广泛的工作,或许这份工作的挑战性还不够。
正确回答:尽管我确信自己还有很多东西要学——在每个新工作中都是这样——但我认为,你会发现我是一个学得很快的人。我相信自己的能力和天分可以满足你们的需要。我不认为前面的路上会有什么不可克服的困难。
评论:尽管承认需要学习一些新东西,但是求职者表明自己有能力完成手头的工作。
问题5
完成这个句子:成功的经理应该……
分析:这个问题可以用来评价你在企业内的发展潜力。即使你正在申请的工作没有管理职责,你的回答也可以让面试人深入了解你的管理潜力,同时可以深入了解你眼中的经理会是什么样子。
错误回答:为了确实能熟练地处理事务,我认为,除了管理别人之外,一个成功的经理还应该更多地了解有关工作的信息。这是惟一能够对员工保持控制的方式——只有知道得比他们多才能对他们加以控制。一旦你失去威望,你就很难再挽回。你必须要比自己的员工领先一步。
评论:这种回答的第一个问题在于,在求职者看来,管理责任听起来像是充满敌意的,而不是合作性的。更大的问题是,求职者认为,在被管理的所有员工中,在他们所从事的一切事情上,你都应该比他们知道得多,在他看来,这不仅是可能的,而且更是可取的。任何人,只要他了解技术、信息传播以及企业流程等方面变化的频率和速度,他就会知道这种方法是不切实际的,也是注定要失败的。
正确回答:一个成功的经理应该能够及时分析形势,确定合适的战略并采取行动。然而,我认为最重要的是能够理解别人。每个人都是独一无二的。意识到这一点并且在工作中适应每个人的工作方式,这就是成功管理的全部内容。
评论:这个回答尽管只有几句话,但它清楚而自信地表达了求职者的工作方式,说明求职者有一种行之有效的管理方法。这种回答还表明,求职者理解管理的难度——任何经理听到这种说法都会很高兴。
问题6
你能够在压力状态下工作得很好吗?
分析:很显然,这个问题是要直接了解求职者对压力的反应。
错误回答:我在压力下会茁壮成长,实际上,事情变得越乱我就越高兴。毕竟,如今的社会是一个充满竞争的社会,在这个社会里,没有压力就不会有成功。相比之下,我更怕无聊。如果无事可做,我就会变得很懒散,但应对压力我就没问题了。
评论:这种回答会让人怀疑:“真有这样的人吗?”除了不可信之外,它还表达了一种消极论调:如果没有压力,求职者就不会得到激励。
正确回答:在从事有价值的工作时,任何人都会在工作中时不时地遇到压力。我能够应付一定量的压力,甚至在有些情况下还可以承受极大的压力。对我来说,应对压力的关键是找到一种方法控制形势,从而减轻压力的剧烈程度——通过这种方式,压力就不会影响我的生产力。我知道任何工作都有压力,如果必要的话,我会在压力下工作得很好。
评论:这种回答表明,求职者对工作压力的本质和程度都有比较现实的期望。这种回答很有说服力,但又没有对压力表现出过度热情。求职者的表述还说明,他(她)在过去曾经应对过压力,而且还制定过策略有效地处理了工作中的压力。
面试提问的32个开放式问题
面试官的开放式问题。
如果你是一名求职者,或者事先准备以下问题的答案会对你的面试成功起到很大的帮助作用。
如果你是一名面试官,以下的问题正是你需要问的。
1. 说说你自己吧
2. 你的短期目标是什么?你2到5年内的目标是什么?
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. 我们为什么要雇用你?
面试是一门学问。展示自己的实力很重要。面试就如把自己卖掉。
自己就是一个产品,不但能吹,把自己吹大,还真的有两把刷子。
如果你的刷子还不够好,那么努力练习就好。
漫画赏析:Linux 内核到底长啥样
今天,我来为大家解读一幅来自 TurnOff.us 的漫画 “InSide The Linux Kernel” 。 TurnOff.us 是一个极客漫画网站,作者Daniel Stori 画了一些非常有趣的关于编程语言、Web、云计算、Linux 相关的漫画。今天解读的便是其中的一篇。
在开始,我们先来看看这幅漫画的全貌!
这幅漫画是以一个房子的侧方刨面图来绘画的。使用这样的一个房子来代表 Linux 内核。
地基
作为一个房子,最重要的莫过于其地基,在这个图片里,我们也从最下面的地基开始看起:
地基(底层)由一排排的文件柜组成,井然有序,文件柜里放置着“文件”——电脑中的文件。左上角,有一只胸前挂着 421 号牌的小企鹅,它表示着 PID(进程 ID(Process ID)) 为 421 的进程,它正在查看文件柜中的文件,这代表系统中正有一个进程在访问文件系统。在右下角有一只小狗,它是看门狗(watchdog) ,这代表对文件系统的监控。
一层(地面层)
看完了地基,接下来我们来看地基上面的一层,都有哪些东西。
在这一层,最引人瞩目的莫过于中间的一块垫子,众多小企鹅在围着着桌子坐着。这个垫子的区域代表进程表。
左上角有一个小企鹅,站着,仿佛在说些什么这显然是一位家长式的人物,不过看起来周围坐的那些小企鹅不是很听话——你看有好多走神、自顾自聊天的——“喂喂,说你呢,哇塞娃(171),转过身来”。它代表着 Linux 内核中的初始化(init)进程,也就是我们常说的 PID 为 1 的进程。桌子上坐的小企鹅都在等待状态(wait)中,等待工作任务。
瞧瞧,垫子(进程表)旁边也有一只小狗,它会监控小企鹅的状态(监控进程),当小企鹅们不听话时,它就会汪汪地叫喊起来。
在这层的左侧,有一只号牌为 1341 的小企鹅,守在门口,门上写着 80,说明这个 PID 为 1341 的小企鹅负责接待 80 端口,也就是我们常说的 HTTP (网站)的端口。小企鹅头上有一片羽毛,这片羽毛大有来历,它是著名的 HTTP 服务器 Apache 的 Logo。喏,就是这只:
向右看,我们可以看到这里仍有一扇门,门上写着 21,但是,看起来这扇门似乎年久失修,上面的门牌号都歪了,门口也没人守着。看起来这个 21 端口的 FTP 协议有点老旧了,目前用的人也比以前少了,以至于这里都没人接待了。
而在最右侧的一个门牌号 22 的们的待遇就大为不同,居然有一只带着墨镜的小企鹅在守着,看起来好酷啊,它是黑衣人叔叔吗?为什么要这么酷的一个企鹅呢,因为 22 端口是 SSH 端口,是一个非常重要的远程连接端口,通常通过这个端口进行远程管理,所以对这个端口进来的人要仔细审查。
它的身上写着 52,说明它是第 52 个小企鹅。
在图片的左上角,有一个向下台阶。这个台阶是底层(地基)的文件系统中的,进程们可以通过这个台阶,到文件系统中去读取文件,进行操作。
在这一层中,有一个身上写着 217 的小企鹅,他正满头大汗地看着自己的手表。这只小企鹅就是定时任务(Crontab),他会时刻关注时间,查看是否要去做某个工作。
在图片的中部,有两个小企鹅扛着管道(PipeLine)在行走,一只小企鹅可以把自己手上的东西通过这个管道,传递给后面的小企鹅。不过怎么看起来前面这种(男?)企鹅累得满头大汗,而后面那只(女?)企鹅似乎游刃有余——喂喂,前面那个,裤子快掉了~
在这一层还有另外的一个小企鹅,它手上拿着一杯红酒,身上写着 411,看起来有点不胜酒力。它就是红酒(Wine)小企鹅,它可以干(执行)一些来自 Windows 的任务。
跃层
在一层之上,还有一个跃层,这里有很多不同的屏幕,每个屏幕上写着 TTY(这就是对外的终端)。比如说最左边 tty4 上输入了“fre”——这是想输入“freshmeat…”么 :d ;它旁边的 tty2 和 tty3 就正常多了,看起来是比较正常的命令;tty7 显示的图形界面嗳,对,图形界面(X Window)一般就在 7 号终端;tty5 和 tty6 是空的,这表示这两个终端没人用。等等,tty1 呢?
tty(终端)是对外沟通的渠道之一,但是,不是每一个进程都需要 tty,某些进程可以直接通过其他途径(比如端口)来和外部进行通信,对外提供服务的,所以,这一层不是完整的一层,只是个跃层。
好了,我们有落下什么吗?
这小丑是谁啊?
啊哈,我也不知道,或许是病毒?你说呢?
深入浅出PageRank算法
PageRank算法是谷歌曾经独步天下的“倚天剑”,该算法由Larry Page和Sergey Brin在斯坦福大学读研时发明的,论文点击下载: The PageRank Citation Ranking: Bringing Order to the Web。
本文首先通过一些参考文献引出问题,然后给出了PageRank的几种实现算法,最后将其推广至在MapReduce框架下如何实现PageRank算法。
PageRank的核心思想有2点:
1.如果一个网页被很多其他网页链接到的话说明这个网页比较重要,也就是pagerank值会相对较高;
2.如果一个pagerank值很高的网页链接到一个其他的网页,那么被链接到的网页的pagerank值会相应地因此而提高。
下面是一张来自WikiPedia的图,每个球代表一个网页,球的大小反应了网页的pagerank值的大小。指向网页B和网页E的链接很多,所以B和E的pagerank值较高,另外,虽然很少有网页指向C,但是最重要的网页B指向了C,所以C的pagerank值比E还要大。
参考内容:
2.Google 的秘密- PageRank 彻底解说 中文版
3.数值分析与算法 Page 161 应用实例:Google的PageRank算法
4.Numeric Methods with Matlab 或者中文翻译版本Matlab数值计算
5.使用 MapReduce 思想计算 PageRank Page 62 PageRank和马尔可夫链
1.问题背景
来自参考内容3
2.数学建模
来自参考内容3,理解网页连接矩阵$G$,马尔科夫过程("网上冲浪"),转移矩阵$A$,概率$p$为用户点击当前网页中的某个链接地址的概率(一般都为0.85)。
最后得到一个等式$Ax=x$,这实际上就是求矩阵$A$的特征值为1的特征向量!
下面的内容使用圆盘定理解释了1是矩阵$A$的主特征值,所以我们可以使用幂法来求解。
关于幂法的详细介绍参考另一篇文章Numerical Methods Using Matlab: 第三章 矩阵特征值和奇异值求解
3.求解PageRank
假设有如上图右侧所示的网页链接模型。
(1) 幂法
wiki上有一个PageRank的简便算法,它不考虑转移概率,而是采用的是迭代的方式,每次都更新所有网页的pagerank值,更新的方式就是将每个网页的pagerank值平摊分给它指向的所有网页,每个网页累计所有指向它的网页平摊给它的值作为它该回合的pagerank值,直到全部网页的pagerank值收敛了或者满足一定的阈值条件就停止。
后面的MapReduce框架下PageRank算法的实现就采用了这个思想。考虑转移概率的情况和这个算法类似,乘上一个转移概率再加上一个随机跳转的概率。
根据上面的思想,下面Matlab代码实现可以得到各个网页的PageRank值。
n=6;
i=[2 3 4 4 5 6 1 6 1];
j=[1 2 2 3 3 3 4 5 6];
G=sparse(i,j,1,n,n);
% Power method
for j = 1:n
L{j} = find(G(:,j));
c(j) = length(L{j});
end
p = .85;
delta = (1-p)/n;
x = ones(n,1)/n;
z = zeros(n,1);
cnt = 0;
while max(abs(x-z)) > .0001
z = x;
x = zeros(n,1);
for j = 1:n
if c(j) == 0
x = x + z(j)/n;%转移到任意一个网页
else
x(L{j}) = x(L{j}) + z(j)/c(j);%将上次的pagerank值平摊给所有指向的网页
end
end
x = p*x + delta;
cnt = cnt+1;
end
得到的向量$x$保存了各个网页的pagerank值,虽然链接数目一样,但是网页①比网页④和网页⑤都高,而网页②的pagerank值第二高,因为网页①链接到了它上面,相当于沾了网页①的光。
x =
0.2675
0.2524
0.1323
0.1698
0.0625
0.1156
这篇文章给出该算法的一个Python版本实现,该博主使用第三方模块python-graph,python-graph模块实现了很多图算法,该模块的使用示例,使用前需要先安装,代码如下:
easy_install python-graph-core
easy_install python-graph-dot
Python版本的算法实现:
# coding=utf-8
# python-graph https://code.google.com/p/python-graph/
# Import graphviz
import graphviz as gv
# Import pygraph
from pygraph.classes.digraph import digraph
from pygraph.readwrite.dot import write
# Define pagerank function
def pagerank(graph, damping_factor=0.85, max_iterations=100, \
min_delta=0.00001):
"""
Compute and return the PageRank in an directed graph.
@type graph: digraph
@param graph: Digraph.
@type damping_factor: number
@param damping_factor: PageRank dumping factor.
@type max_iterations: number
@param max_iterations: Maximum number of iterations.
@type min_delta: number
@param min_delta: Smallest variation required for a new iteration.
@rtype: Dict
@return: Dict containing all the nodes PageRank.
"""
nodes = graph.nodes()
graph_size = len(nodes)
if graph_size == 0:
return {}
# value for nodes without inbound links
min_value = (1.0-damping_factor)/graph_size
# itialize the page rank dict with 1/N for all nodes
#pagerank = dict.fromkeys(nodes, 1.0/graph_size)
pagerank = dict.fromkeys(nodes, 1.0)
for i in range(max_iterations):
diff = 0 #total difference compared to last iteraction
# computes each node PageRank based on inbound links
for node in nodes:
rank = min_value
for referring_page in graph.incidents(node):
rank += damping_factor * pagerank[referring_page] / \
len(graph.neighbors(referring_page))
diff += abs(pagerank[node] - rank)
pagerank[node] = rank
print 'This is NO.%s iteration' % (i+1)
print pagerank
print ''
#stop if PageRank has converged
if diff < min_delta:
break
return pagerank
# Graph creation
gr = digraph()
# Add nodes and edges
gr.add_nodes(["1","2","3","4"])
gr.add_edge(("1","2"))
gr.add_edge(("1","3"))
gr.add_edge(("1","4"))
gr.add_edge(("2","3"))
gr.add_edge(("2","4"))
gr.add_edge(("3","4"))
gr.add_edge(("4","2"))
# Draw as PNG
# dot = write(gr)
# gvv = gv.readstring(dot)
# gv.layout(gvv,'dot')
# gv.render(gvv,'png','Model.png')
pagerank(gr)
经过32次迭代之后得到的结果如下,和前面的结果一致:
This is NO.32 iteration
{'1': 0.2675338708706491, '3': 0.13227261904986046, '2': 0.2524037902400518, '5': 0.062477242064127136, '4': 0.1697488529161491, '6': 0.1155828978186352}
(2) 利用马尔可夫矩阵的特殊结构
来自参考内容4,其中$\delta=\frac{1-p}{n}$
也就是将矩阵$A$进行分解,并不需要显示求出矩阵$A$,然后便是求解一个线性方程组即可。
function x = pagerank1(G)
% PAGERANK1 Google's PageRank modified version 1 - hujiawei
%if nargin < 3, p = .85; end
p=0.85;
% Eliminate any self-referential links
G = G - diag(diag(G));
% c = out-degree, r = in-degree
[n,n] = size(G);
c = sum(G,1);%each row's sum
r = sum(G,2);%each col's sum
% Scale column sums to be 1 (or 0 where there are no out links).
k = find(c~=0);
D = sparse(k,k,1./c(k),n,n);
% Solve (I - p*G*D)*x = e
e = ones(n,1);
I = speye(n,n);
x = (I - p*G*D)\e;
% Normalize so that sum(x) == 1.
x = x/sum(x);
(3) 巧妙解法:逆迭代算法
巧妙利用Matlab中的精度误差导致原本是一个奇异矩阵的$I-A$变成一个非奇异矩阵,运行时只是会有些警告提示,但是运行结果和其他算法一样。
function x = pagerank2(G)
% PAGERANK1 Google's PageRank modified version 2 - hujiawei
% using inverse iteration method
%if nargin < 3, p = .85; end
p=0.85;
% Eliminate any self-referential links
G = G - diag(diag(G));
% c = out-degree, r = in-degree
[n,n] = size(G);
c = sum(G,1);%each row's sum
r = sum(G,2);%each col's sum
% Scale column sums to be 1 (or 0 where there are no out links).
k = find(c~=0);
D = sparse(k,k,1./c(k),n,n);
% Solve (I - p*G*D)*x = e
e = ones(n,1);
I = speye(n,n);
% x = (I - p*G*D)\e;
delta=(1-p)/n;
A=p*G*D+delta;
x=(I-A)\e;
% Normalize so that sum(x) == 1.
x = x/sum(x);
最后,附上参考内容4中给出的一份好代码,用于模拟随机冲浪生成矩阵$G$的代码
function [U,G] = surfer(root,n)
% SURFER Create the adjacency graph of a portion of the Web.
% [U,G] = surfer(root,n) starts at the URL root and follows
% Web links until it forms an adjacency graph with n nodes.
% U = a cell array of n strings, the URLs of the nodes.
% G = an n-by-n sparse matrix with G(i,j)=1 if node j is linked to node i.
%
% Example: [U,G] = surfer('http://www.harvard.edu',500);
% See also PAGERANK.
%
% This function currently has two defects. (1) The algorithm for
% finding links is naive. We just look for the string 'http:'.
% (2) An attempt to read from a URL that is accessible, but very slow,
% might take an unacceptably long time to complete. In some cases,
% it may be necessary to have the operating system terminate MATLAB.
% Key words from such URLs can be added to the skip list in surfer.m.
% Initialize
clf
shg
set(gcf,'doublebuffer','on')
axis([0 n 0 n])
axis square
axis ij
box on
set(gca,'position',[.12 .20 .78 .78])
uicontrol('style','frame','units','normal','position',[.01 .09 .98 .07]);
uicontrol('style','frame','units','normal','position',[.01 .01 .98 .07]);
t1 = uicontrol('style','text','units','normal','position',[.02 .10 .94 .04], ...
'horiz','left');
t2 = uicontrol('style','text','units','normal','position',[.02 .02 .94 .04], ...
'horiz','left');
slow = uicontrol('style','toggle','units','normal', ...
'position',[.01 .24 .07 .05],'string','slow','value',0);
quit = uicontrol('style','toggle','units','normal', ...
'position',[.01 .17 .07 .05],'string','quit','value',0);
U = cell(n,1);
hash = zeros(n,1);
G = logical(sparse(n,n));
m = 1;
U{m} = root;
hash(m) = hashfun(root);
j = 1;
while j < n & get(quit,'value') == 0
% Try to open a page.
try
set(t1,'string',sprintf('%5d %s',j,U{j}))
set(t2,'string','');
drawnow
page = urlread(U{j});
catch
set(t1,'string',sprintf('fail: %5d %s',j,U{j}))
drawnow
continue
end
if get(slow,'value')
pause(.25)
end
% Follow the links from the open page.
for f = findstr('http:',page);
% A link starts with 'http:' and ends with the next quote.
e = min([findstr('"',page(f:end)) findstr('''',page(f:end))]);
if isempty(e), continue, end
url = deblank(page(f:f+e-2));
url(url<' ') = '!'; % Nonprintable characters
if url(end) == '/', url(end) = []; end
% Look for links that should be skipped.
skips = {'.gif','.jpg','.pdf','.css','lmscadsi','cybernet', ...
'search.cgi','.ram','www.w3.org', ...
'scripts','netscape','shockwave','webex','fansonly'};
skip = any(url=='!') | any(url=='?');
k = 0;
while ~skip & (k < length(skips))
k = k+1;
skip = ~isempty(findstr(url,skips{k}));
end
if skip
if isempty(findstr(url,'.gif')) & isempty(findstr(url,'.jpg'))
set(t2,'string',sprintf('skip: %s',url))
drawnow
if get(slow,'value')
pause(.25)
end
end
continue
end
% Check if page is already in url list.
i = 0;
for k = find(hash(1:m) == hashfun(url))';
if isequal(U{k},url)
i = k;
break
end
end
% Add a new url to the graph there if are fewer than n.
if (i == 0) & (m < n)
m = m+1;
U{m} = url;
hash(m) = hashfun(url);
i = m;
end
% Add a new link.
if i > 0
G(i,j) = 1;
set(t2,'string',sprintf('%5d %s',i,url))
line(j,i,'marker','.','markersize',6)
drawnow
if get(slow,'value')
pause(.25)
end
end
end
j = j+1;
end
delete(t1)
delete(t2)
delete(slow)
set(quit,'string','close','callback','close(gcf)','value',0)
%------------------------
function h = hashfun(url)
% Almost unique numeric hash code for pages already visited.
h = length(url) + 1024*sum(url);
4.MapReduce框架下PageRank算法的实现
利用前面wiki上的迭代(或者幂法)的思想来实现MapReduce框架下PageRank算法很简单,可以先阅读下参考内容5。
这篇文章using-mapreduce-to-compute-pagerank更加详细,可以参考
以下是我的大数据的一次作业,要求是参考wiki上的简便算法,实现MapReduce框架下的PageRank算法。给的数据集是Twitter的用户之间的关系,可以看做是网页之间的关系,但是助教没要求写代码以及运行这个数据集(有1G多),所以下面只是一个Python版本的理想可行版本,并没有通过实际大数据集的验证,另外,博主暂时还不太会Python的mapreduce框架中的一些函数,所以实现的是一个简明的可以测试的PageRank算法。
1.输入输出格式
map函数的输入是<节点,从该节点引出的边列表>,其中节点是一个类,包含了其当前的pagerank值,输出是<节点,反向节点pagerank值/反向节点引出边的总数>;
reduce函数的输入是<节点,反向节点pagerank值/反向节点引出边的总数>,输出是<节点,从该节点引出的边列表>,其中节点包含了其更新后的pagerank值。
伪代码: [一时犯二写了个英文形式的 ]
process the data to the form of {node i:[its adjacent node list],...}
while the sum of difference between the last two pagerank values < threshold
map({node i:[its adjacent node list],...}):
map_output={}
for every node j in adjacent node list:
put or sum up {j:(i, PageRank(i)/length(adjacent node list))} into map_output
return map_output
reduce(map_output):
reduce_output={}
for every entry {j:(i, PageRank(i)/length(adjacent node list))} in map_output:
put or sum up all values pagerank values for node j with its adjacent node list into reduce_output
return reduce_output
2.示例演示
假设用户1,2,3,4是如下图所示的关系:
假设有2个mapper(A和B)和1个reducer(C),初始时4个节点的pagerank值都是0.25
其中,关于用户1和2的数据被mapperA读取并处理,关于用户3和4的数据被mapperB读取并处理 [经验证,即使一个用户的数据是由不同的mapper来读取的,最终收敛到的结果差不多]
map的输入输出结果如下:
reduce的输入输出结果如下,输入是2个mapper的输出,输出的结果中更新了节点的pagerank值
reducer处理完了之后又将它的结果输入给mapper处理,直到迭代的次数超过了设定值或者两次迭代之后得到的所有节点的pagerank值之差的总和(也可以是取二范数)小于设定的阈值。
3.示例的实验结果
(1)首先是使用Matlab采用幂法的方式计算出在p=1.0的情况下示例得到的结果 [它的主要作用是验证后面python版本的正确性]
matlab源码如下:
n=4;
i=[2 3 4 3 4 4 1 2];
j=[1 1 1 2 2 3 3 4];
G=sparse(i,j,1,n,n);
[n,n] = size(G);
for j = 1:n
L{j} = find(G(:,j));
c(j) = length(L{j});
end
% Power method
p=1.0;
delta = (1-p)/n;
x = ones(n,1)/n;
z = zeros(n,1);
cnt = 0;
while max(abs(x-z)) > .0001
z = x;
x = zeros(n,1);
for j = 1:n
if c(j) == 0
x = x + z(j)/n;
else
x(L{j}) = x(L{j}) + z(j)/c(j);
end
end
x = p*x + delta;
cnt = cnt+1;
end
sprintf('pagerank result:')
x
结果为:
0.1072
0.3571
0.2143
0.3214
(2)matlab版本的page rank没有采用mapreduce的思想进行迭代,所以我另外写了一个python版本的利用mapreduce思想实现的pagerank算法(注:我并没有使用python的map和reduce函数去实现,而是使用更加容易明白的实现),使用的阈值为0.0001,最多迭代的次数为100次。
# coding=utf-8
__author__ = 'hujiawei'
__doc__ = 'pagerank mapreduce'
class Node:
def __init__(self,id,pk):
self.id=id
self.pk=pk
def pk_map(map_input):
map_output={}
for node,outlinks in map_input.items():
for link in outlinks:
size=len(outlinks)
if link in map_output:
map_output[link]+=(float)(node.pk)/size
else:
map_output[link]=(float)(node.pk)/size
return map_output
def pk_reduce(reduce_input):
for result in reduce_input:
for node,value in result.items():
node.pk+=value
def pk_clear(nodes):
for node in nodes:
node.pk=0
def pk_last(nodes):
lastnodes=[]
for node in nodes:
lastnodes.append(Node(node.id,node.pk))
return lastnodes
def pk_diff(nodes,lastnodes):
diff=0
for i in range(len(nodes)):
print('node pk %f, last node pk %f ' % (nodes[i].pk, lastnodes[i].pk))
diff+=abs(nodes[i].pk-lastnodes[i].pk)
return diff
def pk_test1():
node1 = Node(1, 0.25)
node2 = Node(2, 0.25)
node3 = Node(3, 0.25)
node4 = Node(4, 0.25)
nodes = [node1, node2, node3, node4]
threshold = 0.0001
max_iters = 100
for iter_count in range(max_iters):
iter_count += 1
lastnodes=pk_last(nodes)
print('============ map count %d =================' % (iter_count))
in1 = {node1: [node2, node3, node4], node2: [node3, node4]}
in2 = {node3: [node1, node4], node4: [node2]}
mapout1 = pk_map(in1)
mapout2 = pk_map(in2)
for node, value in mapout1.items():
print str(node.id) + ' ' + str(value)
for node, value in mapout2.items():
print str(node.id) + ' ' + str(value)
print('============ reduce count %d =================' % (iter_count))
reducein = [mapout1, mapout2]
pk_clear(nodes)
pk_reduce(reducein)
for node in nodes:
print str(node.id) + ' ' + str(node.pk)
diff=pk_diff(nodes,lastnodes)
if diff < threshold:
break
if __name__ == '__main__':
pk_test1()
得到的结果为如下,总共迭代了15次
1 0.107138774577
2 0.35712924859
3 0.214296601128
4 0.321435375705
上面的结果和Matlab用幂法得到的pagerank值差别很小,可以认为是正确的,所以说明了使用这种mapreduce输入输出格式的正确性。
OK,差不多了,希望对需要理解PageRank算法的人有帮助! 🙂
linux下详解ftp的常用功能
一、简介:
FTP(File Transfer Protocol, FTP)是TCP/IP网络上两台计算机传送文件的协议,FTP是在TCP/IP网络和INTERNET上最早使用的协议之一,它属于网络协议组的应用层。FTP客户机可以给服务器发出命令来下载文件,上载文件,创建或改变服务器上的目录。
FTP是应用层的协议,它基于传输层,为用户服务,它们负责进行文件的传输。FTP是一个8位的客户端-服务器协议,能操作任何类型的文件而不需要进一步处理,就像MIME或Unencode一样。但是,FTP有着极高的延时,这意味着,从开始请求到第一次接收需求数据之间的时间会非常长,并且不时的必需执行一些冗长的登陆进程。
FTP服务一般运行在20和21两个端口。端口20用于在客户端和服务器之间传输数据流,而端口21用于传输控制流,并且是命令通向ftp服务器的进口。当数据通过数据流传输时,控制流处于空闲状态。而当控制流空闲很长时间后,客户端的防火墙会将其会话置为超时,这样当大量数据通过防火墙时,会产生一些问题。此时,虽然文件可以成功的传输,但因为控制会话会被防火墙断开,传输会产生一些错误。
主动和被动模式
FTP有两种使用模式:主动和被动。主动模式要求客户端和服务器端同时打开并且监听一个端口以建立连接。在这种情况下,客户端由于安装了防火墙会产生一些问题。所以,创立了被动模式。被动模式只要求服务器端产生一个监听相应端口的进程,这样就可以绕过客户端安装了防火墙的问题。
一个主动模式的FTP连接建立要遵循以下步骤:
1.客户端打开一个随机的端口(端口号大于1024,在这里,我们称它为x),同时一个FTP进程连接至服务器的21号命令端口。此时,源端口为随机端口x,在客户端,远程端口为21,在服务器。
2.客户端开始监听端口(x+1),同时向服务器发送一个端口命令(通过服务器的21号命令端口),此命令告诉服务器客户端正在监听的端口号并且已准备好从此端口接收数据。这个端口就是我们所知的数据端口。
3.服务器打开20号源端口并且建立和客户端数据端口的连接。此时,源端口为20,远程数据端口为(x+1)。
4.客户端通过本地的数据端口建立一个和服务器20号端口的连接,然后向服务器发送一个应答,告诉服务器它已经建立好了一个连接。
被动模式FTP:
为了解决服务器发起到客户的连接的问题,人们开发了一种不同的FTP连接方式。这就是所谓的被动方式,或者叫做PASV,当客户端通知服务器它处于被动模式时才启用。
在被动方式FTP中,命令连接和数据连接都由客户端发起,这样就可以解决从服务器到客户端的数据端口的入方向连接被防火墙过滤掉的问题。
当开启一个 FTP连接时,客户端打开两个任意的非特权本地端口(N > 1024和N+1)。第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交 PASV命令。这样做的结果是服务器会开启一个任意的非特权端口(P > 1024),并发送PORT P命令给客户端。然后客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据。
对于服务器端的防火墙来说,必须允许下面的通讯才能支持被动方式的FTP:
1. 从任何大于1024的端口到服务器的21端口 (客户端的初始化连接)
2. 服务器的21端口到任何大于1024的端口 (服务器响应到客户端的控制端口的连接)
3. 从任何大于1024端口到服务器的大于1024端口 (客户端初始化数据连接到服务器指定的任意端口)
4. 服务器的大于1024端口到远程的大于1024的端口(服务器发送ACK响应和数据到客户端的数据端口)
二、常用举例:
(注意:以下根据配置文档举出常见实例)
1.安装ftp
[root@gjp99 ~]# mkdir /mnt/cdrom
[root@gjp99 ~]# mount /dev/cdrom /mnt/cdrom
mount: block device /dev/cdrom is write-protected, mounting read-only
[root@gjp99 ~]# cd /mnt/cdrom/Server
[root@gjp99 Server]# ll vsftp*
-r--r--r-- 86 root root 143838 Jul 24 2009 vsftpd-2.0.5-16.el5.i386.rpm
[root@gjp99 Server]# rpm -qip vsftpd-2.0.5-16.el5.i386.rpm
warning: vsftpd-2.0.5-16.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186
Name : vsftpd Relocations: (not relocatable)
Version : 2.0.5 Vendor: Red Hat, Inc.
Release : 16.el5 Build Date: Wed 13 May 2009 08:47:15 PM CST
Install Date: (not installed) Build Host: hs20-bc1-2.build.redhat.com
Group : System Environment/Daemons Source RPM: vsftpd-2.0.5-16.el5.src.rpm
Size : 291690 License: GPL
Signature : DSA/SHA1, Fri 24 Jul 2009 08:34:20 PM CST, Key ID 5326810137017186
Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
URL : http://vsftpd.beasts.org/
Summary : vsftpd - Very Secure Ftp Daemon
Description :
vsftpd is a Very Secure FTP daemon. It was written completely from
scratch.
[root@gjp99 Server]# rpm -ivh vsftpd-2.0.5-16.el5.i386.rpm
warning: vsftpd-2.0.5-16.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186
Preparing... ################################# [100%]
1:vsftpd ################################# [100%]
[root@gjp99 Server]# rpm -ql vsftpd |less
/etc/pam.d/vsftpd 可插拔验证模块
/etc/rc.d/init.d/vsftpd 控制脚本
/etc/vsftpd/vsftpd.conf 主配置文档
/var/ftp 匿名账号的默认目录
/var/ftp/pub
[root@gjp99 Server]# man 5 vsftpd.conf 配置手册
[root@gjp99 Server]# service vsftpd start
Starting vsftpd for vsftpd: [ OK ]
[root@gjp99 Server]# chkconfig vsftpd on 开机启动
2. 关于账号的详细配置
2.1.匿名账号:
无需输入用户名和口令! 用户名:anonymous 密码:回车或者邮箱账号
支持匿名账号:配置文档
[root@gjp99 ~]# vim /etc/vsftpd/vsftpd.conf
12 anonymous_enable=YES
2.2 本地账号:
有一定的危害性, 存放在:/etc/passwd /etc/shadow
14 # Uncomment this to allow local users to log in.
15 local_enable=YES
[root@gjp99 ~]# useradd gjp1
[root@gjp99 ~]# passwd gjp1
Changing password for user gjp1.
New UNIX password:
BAD PASSWORD: it is WAY too short
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
[root@gjp99 ~]# cd /home/gjp1
[root@gjp99 gjp1]# ll
total 0
[root@gjp99 gjp1]# echo "welcome to access me " >>index.html
[root@gjp99 gjp1]# ll
total 4
-rw-r--r-- 1 root root 22 Aug 3 14:36 index.html
2.3 用户通过网络访问资源,
网络权限[ftp http] 本地权限[相当于windows下的ntfs]
网络权限与本地权限 如果相同 ,则相同,如果不同,则选择最小的!
如果本地权限也可写,则访问时可写!
[root@gjp99 home]# ll
total 4
drwx------ 3 gjp1 gjp1 4096 Aug 3 15:00 gjp1
还可以删除!
2.4 屏蔽某些权限
文件的权限默认是666,目录的权限默认是777
刚才上传的文件在666的基础上屏蔽022 则结果是644,查看
[root@gjp99 gjp1]# ll
total 108
-rw-r--r-- 1 root root 22 Aug 3 14:36 index.html
-rw-r--r-- 1 gjp1 gjp1 100864 Aug 3 15:00 ??目实训2.doc
网络权限已可写,为什么匿名账号还不能上传呀?
[root@gjp99 home]# ll -d /var/ftp/pub
drwxr-xr-x 2 root root 4096 May 13 2009 /var/ftp/pub
pub文件夹的所有者及组都是root,只有管理员可写,其他用户不可写,由于网络权限与本地权限不同,所以选择范围比较小的,
2.5 上传功能
[root@gjp99 home]# service vsftpd restart
Shutting down vsftpd: [ OK ]
Starting vsftpd for vsftpd: [ OK ]
[root@gjp99 home]# ll -d /var/ftp/pub
drwxr-xr-x 2 root root 4096 May 13 2009 /var/ftp/pub
[root@gjp99 home]# chmod o+wt /var/ftp/pub 注意权限不仅加w,还加t
[root@gjp99 home]# ll -d /var/ftp/pub
drwxr-xrwt 2 root root 4096 May 13 2009 /var/ftp/pub 加t是仅有创建者能够删除文件!
改名,删除,创建文件夹都不可以了?
2.6 匿名用户可以创建文件夹
31 anon_mkdir_write_enable=YES 匿名用户创建文件夹
man 5 vsftpd.conf
32 anon_other_write_enable=YES 增加此行! //文件夹可以重命名,可以删除文件,上传
2.7 文件如何下载?
[root@gjp99 home]# ll /var/ftp/pub //发现文件没有读取权限
[root@gjp99 home]# ll /var/ftp/pub
total 56
-rw------- 1 ftp ftp 23040 Aug 3 15:32 ??业????.doc
-rw------- 1 ftp ftp 753 Aug 3 15:47 ???.lnk
-rw------- 1 ftp ftp 24774 Aug 3 15:55 tec.docx
任意一个文件给他个读取权限测试!
[root@gjp99 home]# chmod o+r /var/ftp/pub/tec.docx 给其他用户读权限
[root@gjp99 home]# ll /var/ftp/pub
total 56
-rw------- 1 ftp ftp 23040 Aug 3 15:32 ??业????.doc
-rw------- 1 ftp ftp 753 Aug 3 15:47 ???.lnk
-rw----r-- 1 ftp ftp 24774 Aug 3 15:55 tec.docx
24 anon_umask=073 增加此行,问题简化
现在在上传点文件做测试!
[root@gjp99 home]# ll /var/ftp/pub 自动带了一个r(刚上传过来的文件)
total 256
-rw------- 1 ftp ftp 23040 Aug 3 15:32 ??业????.doc
-rw----r-- 1 ftp ftp 165835 Aug 3 16:10 guo.docx
-rw----r-- 1 ftp ftp 32272 Aug 3 16:10 ji.docx
-rw------- 1 ftp ftp 753 Aug 3 15:47 ???.lnk
-rw----r-- 1 ftp ftp 24774 Aug 3 15:55 tecnology.docx
2.8 如何备份交换机上的系统?
只支持命令行方式访问!
2.9 如何访问ftp服务器?
2.10 如何提示友好信息?
37 dirmessage_enable=YES
测试:友好提示!
2.11 如何开启ftp的日志功能?
日志文件默认目录 /var/log/却找不到!因为日志功能默认未打开!
打开日志功能:
service vsftpd restart
[root@gjp99 pub]# lftp 127.0.0.1 //无需验证就可以登录
lftp 127.0.0.1:~> dir
drwxr-xrwt 2 0 0 4096 Aug 03 08:38 pub
lftp 127.0.0.1:/> bye
[root@gjp99 pub]# ftp 127.0.0.1 // 需要用户验证
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): anonymous
331 Please specify the password.
Password:
[root@gjp99 pub]# ll /var/log/vsftpd.log 该日志文件已存在!
-rw------- 1 root root 0 Aug 3 16:52 /var/log/vsftpd.log
2.12 如何让日志功能生效?
查手册 man 5 vsftpd.conf
56 log_ftp_protocol=YES 增加此行
57 #
58 # Switches between logging into vsftpd_log_file and xferlog_file files.
59 # NO writes to vsftpd_log_file, YES to xferlog_file
60 xferlog_std_format=NO 日志格式禁掉
[root@gjp99 pub]# tail -f /var/log/vsftpd.log //才能使用
Fri Aug 3 09:38:52 2012 [pid 21331] CONNECT: Client "192.168.10.2"
Fri Aug 3 09:38:52 2012 [pid 21331] FTP response: Client "192.168.10.2", "220 (vsFTPd 2.0.5)"
Fri Aug 3 09:38:55 2012 [pid 21331] FTP command: Client "192.168.10.2", "USER gjp1"
Fri Aug 3 09:38:55 2012 [pid 21331] [gjp1] FTP response: Client "192.168.10.2", "331 Please specify the password."
Fri Aug 3 09:38:57 2012 [pid 21331] [gjp1] FTP command: Client "192.168.10.2", "PASS <password>"
Fri Aug 3 09:38:57 2012 [pid 21330] [gjp1] OK LOGIN: Client "192.168.10.2"
Fri Aug 3 09:38:57 2012 [pid 21332] [gjp1] FTP response: Client "192.168.10.2", "230 Login successful."
2.13 拒绝服务攻击的一种方法:
拒绝某人利用某个邮箱账号作为匿名账号的密码进行登录
[root@gjp99 ~]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): anonymous
331 Please specify the password.
Password: 密码为: gjp@sina.com (即使不知道是否存在就能登录)
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
227 Entering Passive Mode (127,0,0,1,88,15)
150 Here comes the directory listing.
drwxr-xrwt 2 0 0 4096 Aug 03 09:11 pub
226 Directory send OK
[root@gjp99 pub]# echo gjp@sina.com >>/etc/vsftpd/banned_emails
[root@gjp99 ~]# service vsftpd restart
Shutting down vsftpd: [ OK ]
Starting vsftpd for vsftpd: [ OK ]
[root@gjp99 ~]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): anonymous
331 Please specify the password.
Password:
530 Login incorrect.
Login failed.
[root@gjp99 ~]# useradd user1
[root@gjp99 ~]# passwd
Changing password for user root.
New UNIX password:
BAD PASSWORD: it is WAY too short
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
[root@gjp99 ~]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/home/user1"
ftp> cd /
250 Directory successfully changed.
ftp> dir
227 Entering Passive Mode (127,0,0,1,201,20)
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Aug 03 04:05 bin
drwxr-xr-x 4 0 0 1024 Aug 02 13:26 boot
drwxr-xr-x 11 0 0 4260 Aug 03 05:42 dev
drwxr-xr-x 93 0 0 12288 Aug 03 10:06 etc
ftp> cd boot
250 Directory successfully changed.
ftp> dir
227 Entering Passive Mode (127,0,0,1,89,202)
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 954947 Aug 18 2009 System.map-2.6.18-164.el5
-rw-r--r-- 1 0 0 68663 Aug 18 2009 config-2.6.18-164.el5
drwxr-xr-x 2 0 0 1024 Aug 02 13:30 grub
-rw------- 1 0 0 2601298 Aug 02 13:26 initrd-2.6.18-164.el5.img
drwx------ 2 0 0 12288 Aug 02 21:18 lost+found
-rw-r--r-- 1 0 0 107405 Aug 18 2009 symvers-2.6.18-164.el5.gz
-rw-r--r-- 1 0 0 1855956 Aug 18 2009 vmlinuz-2.6.18-164.el5
226 Directory send OK.
可以查看许多内容,而且可以下载,没有安全性!
2.14 如何提高 ftp的安全性?
[root@gjp99 ~]# vim /etc/vsftpd/vsftpd.conf
[root@gjp99 ~]# vim /etc/vsftpd/chroot_list
[root@gjp99 ~]# cat /etc/vsftpd/chroot_list
user1 //写入到该文件的账号都被禁锢了,没有写进来的可随意切换!
[root@gjp99 ~]# service vsftpd restart
Shutting down vsftpd: [ OK ]
Starting vsftpd for vsftpd: [ OK ]
[root@gjp99 ~]# su – user1 该账号下存在属于自己的东西
[user1@gjp99 ~]$ ll
total 0
[user1@gjp99 ~]$ touch gjp.txt
[user1@gjp99 ~]$ vim gjp.txt
[user1@gjp99 ~]$ ll
total 4
-rw-rw-r-- 1 user1 user1 32 Sep 26 14:40 gjp.txt
[root@gjp99 ~]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/"
ftp> cd /
250 Directory successfully changed.
ftp> dir
227 Entering Passive Mode (127,0,0,1,119,140)
150 Here comes the directory listing.
-rw-rw-r-- 1 501 501 32 Sep 26 06:40 gjp.txt
226 Directory send OK.
ftp> bye
221 Goodbye.
[root@gjp99 ~]# useradd user2
[root@gjp99 ~]# passwd
Changing password for user root.
New UNIX password:
BAD PASSWORD: it is WAY too short
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
[root@gjp99 ~]# su - user2
[user2@gjp99 ~]$ echo "user2" >> gjp2.txt
[user2@gjp99 ~]$ ll
total 4
-rw-rw-r-- 1 user2 user2 6 Sep 26 14:45 gjp2.txt
[user2@gjp99 ~]$ logout
[root@gjp99 ~]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user2
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/home/user2"
ftp> cd /
250 Directory successfully changed.
ftp> dir
227 Entering Passive Mode (127,0,0,1,68,60)
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Aug 03 04:05 bin
drwxr-xr-x 4 0 0 1024 Aug 02 13:26 boot
drwxr-xr-x 11 0 0 4220 Sep 26 06:26 dev
drwxr-xr-x 93 0 0 12288 Sep 26 06:48 etc
drwxr-xr-x 5 0 0 4096 Sep 26 06:44 home
(没有写入该文件的账号,如user2,则可以随意切换)
实现:放入该文件里的账号能够切换目录,没放进来的不能够切换目录,man 5 vsftpd.conf
[root@gjp99 ~]# vim /etc/vsftpd/vsftpd.conf
增加此功能; chroot_local_user=YES
[root@gjp99 ~]# service vsftpd restart
Shutting down vsftpd: [ OK ]
Starting vsftpd for vsftpd: [ OK ]
[root@gjp99 ~]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user1 放进去的却没有禁锢掉
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
257 "/home/user1"
ftp> cd /
250 Directory successfully changed.
ftp> quit
221 Goodbye.
[root@gjp99 ~]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user2 没放进去的被禁锢了
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/"
ftp> cd /
250 Directory successfully changed.
ftp> dir
227 Entering Passive Mode (127,0,0,1,98,84)
150 Here comes the directory listing.
-rw-rw-r-- 1 502 502 6 Sep 26 06:45 gjp2.txt
226 Directory send OK.
ftp 的特性:
独立进程存放在: /etc/init.c /etc/rc.d/init.d 目录下!
超级守护进程:xinetd
112 listen=YES 表明独立的,不再依赖于超级守护进程
119 pam_service_name=vsftpd //ftp支持pam验证
可参考ftp的接口文件
[root@gjp99 pam.d]# vim /etc/pam.d/vsftpd 里面有相应的系统调用及参数
[root@gjp99 pam.d]# cd /etc/vsftpd
[root@gjp99 vsftpd]# ll
total 28
-rw-r--r-- 1 root root 13 Aug 3 18:00 banned_emails
-rw-r--r-- 1 root root 7 Sep 26 14:37 chroot_list
-rw------- 1 root root 125 May 13 2009 ftpusers 存入该文件的账号不能登录ftp
-rw------- 1 root root 361 May 13 2009 user_list 存入该文件的账号不能登录ftp
-rw------- 1 root root 4640 Sep 26 14:59 vsftpd.conf
-rwxr--r-- 1 root root 338 May 13 2009 vsftpd_conf_migrate.sh
[root@gjp99 vsftpd]# cat ftpusers
# Users that are not allowed to login via ftp
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody
user1 把user1添加进来作为测试!
[root@gjp99 vsftpd]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user1
331 Please specify the password.
Password: 需要输入密码,如果网络上有人抓包,则很不安全!
530 Login incorrect.
Login failed. 登录失败
把ftpusers中存放的账号user1删除,在user_list中输入user1测试!
[root@gjp99 vsftpd]# cat user_list
# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody
user1
[root@gjp99 vsftpd]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user1
530 Permission denied. 没有提示让输入密码,直接拒绝掉了
Login failed.
为了防止管理员的密码被捕获,则不允许管理员ftp
[root@gjp99 vsftpd]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): root
530 Permission denied.
Login failed.
[root@gjp99 vsftpd]# vim user_list
# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
在 /etc/vsftpd/vsftpd.conf中增加此功能: service vsftpd restart
下面测试:user1在这个文件下所以可以登录,user2不在该文件里,因此直接拒绝!
[root@gjp99 vsftpd]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
227 Entering Passive Mode (127,0,0,1,42,166)
150 Here comes the directory listing.
-rw-rw-r-- 1 501 501 32 Sep 26 06:40 gjp.txt
226 Directory send OK.
ftp> quit
221 Goodbye.
[root@gjp99 vsftpd]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user2
530 Permission denied.
Login failed.
/etc/vsftpd/vsftpd.conf 下的
122 tcp_wrappers=YES
查看某些应用支持的链接库:
[root@gjp99 vsftpd]# ldd /usr/sbin/vsftpd
linux-gate.so.1 => (0x00164000)
libssl.so.6 => /lib/libssl.so.6 (0x00a33000)
libwrap.so.0 => /lib/libwrap.so.0 (0x0067c000)
出现此文件,即说明支持tcp_wrappers=YES
需修改 /etc/hosts.allow /etc/hosts.deny
先看hosts.allow 再看hosts.deny 默认是允许的!
[root@gjp99 vsftpd]# cat /etc/hosts.allow
#
# hosts.allow This file describes the names of the hosts which are
# allowed to use the local INET services, as decided
# by the '/usr/sbin/tcpd' server.
#
vsftpd:192.168.10.2:allow 仅有192.168.10.2允许
[root@gjp99 vsftpd]# vim /etc/hosts.deny
[root@gjp99 vsftpd]# cat /etc/hosts.deny
#
# hosts.deny This file describes the names of the hosts which are
# *not* allowed to use the local INET services, as decided
# by the '/usr/sbin/tcpd' server.
#
# The portmap line is redundant, but it is left to remind you that
# the new secure portmap uses hosts.deny and hosts.allow. In particular
# you should know that NFS uses portmap!
vsftpd:all :deny 其他人拒绝
测试:windows下ftp
linux 下测试:
[root@gjp99 vsftpd]# ftp 127.0.0.1
Connected to 127.0.0.1.
421 Service not available.
ftp> quit
只有192.168.10.2不可以,其他的都可以!
[root@gjp99 vsftpd]# vim /etc/hosts.allow 只在该文件下操作,hosts.deny 空着
6 vsftpd:192.168.10.2:deny
7 vsftpd:all:allow
测试:windows下:
linux下:
[root@gjp99 vsftpd]# ftp 127.0.0.1
Connected to 127.0.0.1.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (127.0.0.1:root): user1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
227 Entering Passive Mode (127,0,0,1,208,223)
150 Here comes the directory listing.
-rw-rw-r-- 1 501 501 32 Sep 26 06:40 gjp.txt
226 Directory send OK.
ftp> quit
ftp的安全性
1. 协议 ftp 明文
2. 账号 匿名 本地账号(抓包,危险性较大) 最好选用虚拟账号
删除原有的安全特性,安装tshark
挂载光盘,安装抓包工具:
[root@gjp99 vsftpd]# mount /dev/cdrom /mnt/cdrom
mount: block device /dev/cdrom is write-protected, mounting read-only
[root@gjp99 vsftpd]# cd /mnt/cdrom/Server/
[root@gjp99 Server]# ll wireshark-*
-r--r--r-- 220 root root 11130359 Jun 11 2009 wireshark-1.0.8-1.el5_3.1.i386.rpm
-r--r--r-- 220 root root 686650 Jun 11 2009 wireshark-gnome-1.0.8-1.el5_3.1.i386.rpm
[root@gjp99 Server]# rpm -ivh libsmi-0.4.5-2.el5.i386.rpm 必须先安装此软件
warning: libsmi-0.4.5-2.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186
Preparing... ################################# [100%]
1:libsmi ################################# [100%]
[root@gjp99 Server]# rpm -ivh wire
wireless-tools-28-2.el5.i386.rpm
wireless-tools-devel-28-2.el5.i386.rpm
wireshark-1.0.8-1.el5_3.1.i386.rpm
wireshark-gnome-1.0.8-1.el5_3.1.i386.rpm
[root@gjp99 Server]# rpm -ivh wireshark-1.0.8-1.el5_3.1.i386.rpm
warning: wireshark-1.0.8-1.el5_3.1.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186
Preparing... ################################# [100%]
1:wireshark ############################### [100%]
[root@gjp99 Server]# tshark -ni eth0 -R "tcp.dstport eq 21 "
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0 已经在eth0上可以抓包了~
Xshell:\> ftp 192.168.10.98
Connecting to 192.168.10.98:21...
Connection established.
Escape character is '^@]'.
220 (vsFTPd 2.0.5)
Name (192.168.10.98:Administrator): user1
331 Please specify the password.
Password:
230 Login successful.
ftp:/home/user1>
抓包抓到的情况:
115.297511 192.168.10.2 -> 192.168.10.98 FTP Request: USER user1 用户名
115.497920 192.168.10.2 -> 192.168.10.98 TCP 53368 > 21 [ACK] Seq=13 Ack=55 Win=65536 Len=0
116.968029 192.168.10.2 -> 192.168.10.98 FTP Request: PASS 123 密码
116.996447 192.168.10.2 -> 192.168.10.98 FTP Request: PWD
117.196785 192.168.10.2 -> 192.168.10.98 TCP 53368 > 21 [ACK] Seq=28 Ack=97 Win=65536 Len=0
测试,是否能抓到管理员密码?
Xshell:\> ftp 192.168.10.98
Connecting to 192.168.10.98:21...
Connection established.
Escape character is '^@]'.
220 (vsFTPd 2.0.5)
Name (192.168.10.98:Administrator): root
530 Permission denied.
抓包抓不到密码:
243.383605 192.168.10.2 -> 192.168.10.98 FTP Request: USER root
243.583142 192.168.10.2 -> 192.168.10.98 TCP 53369 > 21 [ACK] Seq=12 Ack=45 Win=65536 Len=0
291.498211 192.168.10.2 -> 192.168.10.98 FTP Request: PWD
291.698623 192.168.10.2 -> 192.168.10.98 TCP 53368 > 21 [ACK] Seq=43 Ack=154 Win=65536 Len=0
ftps的搭建:
ftps=ftp+ssl
创建CA
[root@gjp99 Server]# cd /etc/pki
[root@gjp99 pki]# ll
total 32
drwx------ 3 root root 4096 Aug 2 21:22 CA
drwxr-xr-x 2 root root 4096 Aug 2 21:20 nssdb
drwxr-xr-x 2 root root 4096 Aug 2 21:21 rpm-gpg
drwxr-xr-x 5 root root 4096 Aug 2 21:22 tls
[root@gjp99 pki]# vim tls/openssl.cnf
45 dir = /etc/pki/CA # Where everything is kept
46 certs = $dir/certs # Where the issued certs are kept
47 crl_dir = $dir/crl # Where the issued crl are kept
48 database = $dir/index.txt # database index file.
49 #unique_subject = no # Set to 'no' to allow creation of
50 # several ctificates with same subject.
51 new_certs_dir = $dir/newcerts # default place for new certs.
52
53 certificate = $dir/cacert.pem # The CA certificate
54 serial = $dir/serial # The current serial number
55 crlnumber = $dir/crlnumber # the current crl number
56 # must be commented out to leave a V1 CRL
57 crl = $dir/crl.pem # The current CRL
58 private_key = $dir/private/cakey.pem# The private key
88 countryName = optonal
89 stateOrProvinceName = optonal
90 organizationName = optonal
[root@gjp99 pki]# ll
total 32
drwx------ 3 root root 4096 Aug 2 21:22 CA
drwxr-xr-x 2 root root 4096 Aug 2 21:20 nssdb
drwxr-xr-x 2 root root 4096 Aug 2 21:21 rpm-gpg
drwxr-xr-x 5 root root 4096 Sep 26 17:04 tls
[root@gjp99 pki]# cd CA
[root@gjp99 CA]# ll
total 8
drwx------ 2 root root 4096 Jun 30 2009 private
[root@gjp99 CA]# mkdir crl certs newcerts
[root@gjp99 CA]# touch index.txt serial
[root@gjp99 CA]# echo "01">serial
[root@gjp99 CA]# openssl genrsa 1024 >private/cakey.pem
Generating RSA private key, 1024 bit long modulus
....++++++
......++++++
e is 65537 (0x10001)
[root@gjp99 CA]# chmod 600 private/*
[root@gjp99 CA]# openssl req -new -key private/cakey.pem -x509 -out cacert.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [CN]:
State or Province Name (full name) [Shang Hai]:
Locality Name (eg, city) [Shang Hai]:
Organization Name (eg, company) [My Company Ltd]:sec center
Organizational Unit Name (eg, section) []:tec
Common Name (eg, your name or your server's hostname) []:ca.net.net
Email Address []:
私钥 请求文件 证书
[root@gjp99 CA]# mkdir /etc/vsftpd/certs
[root@gjp99 CA]# cd /etc/vsftpd/certs/
[root@gjp99 certs]# openssl genrsa 1024 >vsftpd.key 创建钥匙
Generating RSA private key, 1024 bit long modulus
.......++++++
................................................................+++
e is 65537 (0x10001)
[root@gjp99 certs]# openssl req -new -key vsftpd.key -out vsftpd.csr 产生请求
You are about to be asked to enter information that will be inco
into your certificate request.
What you are about to enter is what is called a Distinguished Na
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [CN]:
State or Province Name (full name) [Shang Hai]:
Locality Name (eg, city) [Shang Hai]:
Organization Name (eg, company) [My Company Ltd]:bht
Organizational Unit Name (eg, section) []:tec
Common Name (eg, your name or your server's hostname) []:ftp.bht.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@gjp99 certs]# ll
total 8
-rw-r--r-- 1 root root 651 Sep 26 17:17 vsftpd.csr
-rw-r--r-- 1 root root 887 Sep 26 17:15 vsftpd.key
[root@gjp99 certs]# openssl ca -in vsftpd.csr -out vsftpd.cert 生成证书
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Sep 26 09:35:33 2012 GMT
Not After : Sep 26 09:35:33 2013 GMT
Subject:
countryName = CN
stateOrProvinceName = Shang Hai
organizationName = bht
organizationalUnitName = tec
commonName = ftp.bht.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
4E:10:2C:A8:BA:A8:5E:16:D1:8E:BD:85:53:87:5C:5E:1D:B6:04:C1
X509v3 Authority Key Identifier:
keyid:DF:8C:0F:8C:D0:65:31:42:FB:AF:29:7A:52:51:4C:86:09:25:91:F4
Certificate is to be certified until Sep 26 09:35:33 2013 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
证书在哪?私钥在哪?
用man 5 vsftpd.conf
[root@gjp99 certs]# vim /etc/vsftpd/vsftpd.conf
增加以下功能:
rsa_cert_file=/etc/vsftpd/certs/vsftpd.cert
rsa_private_key_file=/etc/vsftpd/certs/vsftpd.key
ssl_tlsv1=YES
ssl_sslv3=YES
ssl_sslv2=YES
ssl_enable=YES
force_local_logins_ssl=YES
force_local_data_ssl=YES
[root@gjp99 certs]# service vsftpd restart
Shutting down vsftpd: [ OK ]
Starting vsftpd for vsftpd: [ OK ]
[root@gjp99 certs]# tshark -ni eth0 -R "tcp.dstport eq 21 "
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0
C:\Users\Administrator>ftp 192.168.10.98 命令行下无法登录(由于使用了身份验证)
连接到 192.168.10.98。
220 (vsFTPd 2.0.5)
用户(192.168.10.98:(none)): user1
530 Non-anonymous sessions must use encryption.
登录失败。
使用客户端软件:
点击应用 点击连接!
点击 “接受一次”
1331.140451 192.168.10.2 -> 192.168.10.98 FTP Request: AUTH SSL
1331.147508 192.168.10.2 -> 192.168.10.98 FTP Request: \200\310\001\003\001\000
下面都是已加密的信息,已看不到密码!