vimrc配置(带注释版)

“=========================================================================
” DesCRiption: 适合自己使用的vimrc文件,for Linux/Windows, GUI/Console

” Last Change: 2010年08月02日 15时13分

” Version:     1.80

“=========================================================================
set nocompatible            ” 关闭 vi 兼容模式
syntax on                   ” 自动语法高亮
colorscheme molokai         ” 设定配色方案
set number                  ” 显示行号
set cursorline              ” 突出显示当前行
set ruler                   ” 打开状态栏标尺
set shiftwidth=4            ” 设定 << 和 >> 命令移动时的宽度为 4
set softtabstop=4           ” 使得按退格键时可以一次删掉 4 个空格
set tabstop=4               ” 设定 tab 长度为 4
set nobackup                ” 覆盖文件时不备份
set autochdir               ” 自动切换当前目录为当前文件所在的目录
filetype plugin indent on   ” 开启插件
set backupcopy=yes          ” 设置备份时的行为为覆盖
set ignorecase smartcase    ” 搜索时忽略大小写,但在有一个或以上大写字母时仍保持对大小写敏感
set nowrapscan              ” 禁止在搜索到文件两端时重新搜索
set incsearch               ” 输入搜索内容时就显示搜索结果
set hlsearch                ” 搜索时高亮显示被找到的文本
set noerrorbells            ” 关闭错误信息响铃
set novisualbell            ” 关闭使用可视响铃代替呼叫
set t_vb=                   ” 置空错误铃声的终端代码
” set showmatch               ” 插入括号时,短暂地跳转到匹配的对应括号
” set matchtime=2             ” 短暂跳转到匹配括号的时间
set magic                   ” 设置魔术
set hidden                  ” 允许在有未保存的修改时切换缓冲区,此时的修改由 vim 负责保存
set guioptions-=T           ” 隐藏工具栏
set guioptions-=m           ” 隐藏菜单栏
set smartindent             ” 开启新行时使用智能自动缩进
set backspace=indent,eol,start
” 不设定在插入状态无法用退格键和 Delete 键删除回车符
set cmdheight=1             ” 设定命令行的行数为 1
set laststatus=2            ” 显示状态栏 (默认值为 1, 无法显示状态栏)
set statusline=\ %<%F[%1*%M%*%n%R%H]%=\ %y\ %0(%{&fileformat}\ %{&encoding}\ %c:%l/%L%)\
” 设置在状态行显示的信息
set foldenable              ” 开始折叠
set foldmethod=syntax       ” 设置语法折叠
set foldcolumn=0            ” 设置折叠区域的宽度
setlocal foldlevel=1        ” 设置折叠层数为
” set foldclose=all           ” 设置为自动关闭折叠
” nnoremap <space> @=((foldclosed(line(‘.’)) < 0) ? ‘zc’ : ‘zo’)<CR>
” 用空格键来开关折叠

” return OS type, eg: windows, or linux, mac, et.st..
function! MySys()
if has(“win16”) || has(“win32”) || has(“win64”) || has(“win95”)
return “windows”
elseif has(“unix”)
return “linux”
endif
endfunction
” 用户目录变量$VIMFILES
if MySys() == “windows”
let $VIMFILES = $VIM.’/vimfiles’
elseif MySys() == “linux”
let $VIMFILES = $HOME.’/.vim’
endif
” 设定doc文档目录
let helptags=$VIMFILES.’/doc’
” 设置字体 以及中文支持
if has(“win32″)
set guifont=Inconsolata:h12:cANSI
endif
” 配置多语言环境
if has(“multi_byte”)
” UTF-8 编码
set encoding=utf-8
set termencoding=utf-8
set formatoptions+=mM
set fencs=utf-8,gbk
if v:lang =~? ‘^zh\|ja\|ko
set ambiwidth=double
endif
if has(“win32”)
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
language messages zh_CN.utf-8
endif
else
echoerr “Sorry, this version of (g)vim was not compiled with +multi_byte”
endif
” Buffers操作快捷方式!
nnoremap <C-RETURN> :bnext<CR>
nnoremap <C-S-RETURN> :bprevious<CR>
” Tab操作快捷方式!
nnoremap <C-TAB> :tabnext<CR>
nnoremap <C-S-TAB> :tabprev<CR>
“关于tab的快捷键
” map tn :tabnext<cr>
” map tp :tabprevious<cr>
” map td :tabnew .<cr>
” map te :tabedit
” map tc :tabclose<cr>
“窗口分割时,进行切换的按键热键需要连接两次,比如从下方窗口移动
“光标到上方窗口,需要<c-w><c-w>k,非常麻烦,现在重映射为<c-k>,切换的
“时候会变得非常方便.
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
“一些不错的映射转换语法(如果在一个文件中混合了不同语言时有用)
nnoremap <leader>1 :set filetype=xhtml<CR>
nnoremap <leader>2 :set filetype=css<CR>
nnoremap <leader>3 :set filetype=javascript<CR>
nnoremap <leader>4 :set filetype=php<CR>
” set fileformats=unix,dos,mac
” nmap <leader>fd :se fileformat=dos<CR>
” nmap <leader>fu :se fileformat=unix<CR>
” use Ctrl+[l|n|p|cc] to list|next|previous|jump to count the result
” map <C-x>l <ESC>:cl<CR>
” map <C-x>n <ESC>:cn<CR>
” map <C-x>p <ESC>:cp<CR>
” map <C-x>c <ESC>:cc<CR>

” 让 Tohtml 产生有 CSS 语法的 html
” syntax/2html.vim,可以用:runtime! syntax/2html.vim
let html_use_css=1
” Python 文件的一般设置,比如不要 tab 等
autocmd FileType python set tabstop=4 shiftwidth=4 expandtab
autocmd FileType python map <F12> :!python %<CR>
” 选中状态下 Ctrl+c 复制
vmap <C-c> “+y
” 打开javascript折叠
let b:javascript_fold=1
” 打开javascript对dom、html和css的支持
let javascript_enable_domhtmlcss=1
” 设置字典 ~/.vim/dict/文件的路径
autocmd filetype javascript set dictionary=$VIMFILES/dict/javascript.dict
autocmd filetype css set dictionary=$VIMFILES/dict/css.dict
autocmd filetype php set dictionary=$VIMFILES/dict/php.dict
“—————————————————————–
” plugin – bufexplorer.vim Buffers切换
” \be 全屏方式查看全部打开的文件列表
” \bv 左右方式查看   \bs 上下方式查看
“—————————————————————–
“—————————————————————–
” plugin – taglist.vim  查看函数列表,需要ctags程序
” F4 打开隐藏taglist窗口
“—————————————————————–
if MySys() == “windows”                ” 设定windows系统中ctags程序的位置
let Tlist_Ctags_Cmd = ‘”‘.$VIMRUNTIME.’/ctags.exe”‘
elseif MySys() == “linux”              ” 设定windows系统中ctags程序的位置
let Tlist_Ctags_Cmd = ‘/usr/bin/ctags’
endif
nnoremap <silent><F4> :TlistToggle<CR>
let Tlist_Show_One_File = 1            ” 不同时显示多个文件的tag,只显示当前文件的
let Tlist_Exit_OnlyWindow = 1          ” 如果taglist窗口是最后一个窗口,则退出vim
let Tlist_Use_Right_Window = 1         ” 在右侧窗口中显示taglist窗口
let Tlist_File_Fold_Auto_Close=1       ” 自动折叠当前非编辑文件的方法列表
let Tlist_Auto_Open = 0
let Tlist_Auto_Update = 1
let Tlist_Hightlight_Tag_On_BufEnter = 1
let Tlist_Enable_Fold_Column = 0
let Tlist_Process_File_Always = 1
let Tlist_Display_Prototype = 0
let Tlist_Compact_Format = 1

“—————————————————————–
” plugin – mark.vim 给各种tags标记不同的颜色,便于观看调式的插件。
” \m  mark or unmark the word under (or before) the cursor
” \r  manually input a regular expression. 用于搜索.
” \n  clear this mark (i.e. the mark under the cursor), or clear all highlighted marks .
” \*  当前MarkWord的下一个     \#  当前MarkWord的上一个
” \/  所有MarkWords的下一个    \?  所有MarkWords的上一个
“—————————————————————–

“—————————————————————–
” plugin – NERD_tree.vim 以树状方式浏览系统中的文件和目录
” :ERDtree 打开NERD_tree         :NERDtreeClose    关闭NERD_tree
” o 打开关闭文件或者目录         t 在标签页中打开
” T 在后台标签页中打开           ! 执行此文件
” p 到上层目录                   P 到根目录
” K 到第一个节点                 J 到最后一个节点
” u 打开上层目录                 m 显示文件系统菜单(添加、删除、移动操作)
” r 递归刷新当前目录             R 递归刷新当前根目录
“—————————————————————–
” F3 NERDTree 切换
map <F3> :NERDTreeToggle<CR>
imap <F3> <ESC>:NERDTreeToggle<CR>

“—————————————————————–
” plugin – NERD_commenter.vim   注释代码用的,
” [count],cc 光标以下count行逐行添加注释(7,cc)
” [count],cu 光标以下count行逐行取消注释(7,cu)
” [count],cm 光标以下count行尝试添加块注释(7,cm)
” ,cA 在行尾插入 /* */,并且进入插入模式。 这个命令方便写注释。
” 注:count参数可选,无则默认为选中行或当前行
“—————————————————————–
let NERDSpaceDelims=1       ” 让注释符与语句之间留一个空格
let NERDCompactSexyComs=1   ” 多行注释时样子更好看

“—————————————————————–
” plugin – DoxygenToolkit.vim  由注释生成文档,并且能够快速生成函数标准注释
“—————————————————————–
let g:DoxygenToolkit_authorName=”Asins – asinsimple AT gmail DOT com”
let g:DoxygenToolkit_briefTag_funcName=”yes”
map <leader>da :DoxAuthor<CR>
map <leader>df :Dox<CR>
map <leader>db :DoxBlock<CR>
map <leader>dc a /*  */<LEFT><LEFT><LEFT>

“—————————————————————–
” plugin – ZenCoding.vim 很酷的插件,HTML代码生成
” 插件最新版:http://github.com/mattn/zencoding-vim
” 常用命令可看:http://nootn.com/blog/Tool/23/
“—————————————————————–
“—————————————————————–
” plugin – checksyntax.vim    JavaScript常见语法错误检查
” 默认快捷方式为 F5
“—————————————————————–
let g:checksyntax_auto = 0 ” 不自动检查
“—————————————————————–
” plugin – NeoComplCache.vim    自动补全插件
“—————————————————————–
let g:AutoComplPop_NotEnableAtStartup = 1
let g:NeoComplCache_EnableAtStartup = 1
let g:NeoComplCache_SmartCase = 1
let g:NeoComplCache_TagsAutoUpdate = 1
let g:NeoComplCache_EnableInfo = 1
let g:NeoComplCache_EnableCamelCaseCompletion = 1
let g:NeoComplCache_MinSyntaxLength = 3
let g:NeoComplCache_EnableSkipCompletion = 1
let g:NeoComplCache_SkipInputTime = ‘0.5’
let g:NeoComplCache_SnippetsDir = $VIMFILES.’/snippets’
” <TAB> completion.
inoremap <expr><TAB> pumvisible() ? “\<C-n>” : “\<TAB>”
” snippets expand key
imap <silent> <C-e> <Plug>(neocomplcache_snippets_expand)
smap <silent> <C-e> <Plug>(neocomplcache_snippets_expand)
“—————————————————————–
” plugin – matchit.vim   对%命令进行扩展使得能在嵌套标签和语句之间跳转
” % 正向匹配      g% 反向匹配
” [% 定位块首     ]% 定位块尾
“—————————————————————–
“—————————————————————–
” plugin – vcscommand.vim   对%命令进行扩展使得能在嵌套标签和语句之间跳转
” SVN/git管理工具
“—————————————————————–
“—————————————————————–
” plugin – a.vim

“—————————————————————–

[转载自:http://www.cnblogs.com/zourrou/archive/2011/04/16/2018493.html]

使用反向ssh从外网访问内网主机的方法详解

由于我们自己使用的电脑未必有外网ip,因此我们需要一个有固定外网ip的服务器(随便搞个腾讯云,阿里云的小机子就行),然后用这台服务器与内网的机子进行通信,我们到时候要先登陆自己的服务器,然后再利用这个服务器去访问内网的主机。
1、准备好有固定ip的服务器A,以及待访问的内网机器B。两者都开着sshd服务,端口号默认都是22。顺便做好ssh免密码登陆。
2、内网主机B主动连接服务器A,执行以下命令:
 >$ ssh -NfR 10000:localhost:22 username@servername -p 22
这条命令的意思是在后台执行(-f),不实际连接而是做port forwarding(-N),做反向ssh(-R),将远程服务器的10000端口映射成连接本机(B)与该服务器的反向ssh的端口。
附:这里有必要加强一下记忆,这个端口号一不小心就容易搞混

man文档中的参数命令是这样的:

-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket

bind_address以及其后面的port是指远程主机的ip以及端口,host以及其后的hostport是指本机的ip和端口。由于ssh命令本身需要远程主机的ip(上上条命令中的servername),因此这个bind_address原则上是可以省略的。
执行完这条命令,我们可以在服务器A上看到他的10000端口已经开始监听:
~]$ ss -ant | grep 10000
LISTEN 0 128 127.0.0.1:10000 *:*
3、在上面的操作中,这个1111端口就已经映射成了内网主机B的22端口了,现在我们只要ssh到自己的这个端口就行了。在服务器A中执行:
 >$ ssh username@localhost -p 10000
这样就成功的登陆了内网的主机了。
功能优化
上面的做法其实有一个问题,就是反向ssh可能会不稳定,主机B对服务器A的端口映射可能会断掉,那么这时候就需要主机B重新链接,而显然远在外地的我无法登陆B

这其实有一个非常简单的解决方案,就是用autossh替代步骤2中的ssh:
C:\ > autossh -M 2222 -NfR 10000:localhost:22 username@servername -p 22
后面的参数跟ssh都一样,只是多了一个-M参数,这个参数的意思就是用本机的2222端口来监听ssh,每当他断了就重新把他连起来。。。不过man文档中也说了,这个端口又叫echo port,他其实是有一对端口的形式出现,第二个端口就是这个端口号加一。因此我们要保证这个端口号和这个端口号加一的端口号不被占用。

有时,我们会想在局域网外访问局域网内的机器。这时,我们可以使用SSH的反向连接来实现。
设备A:位于局域网内,可以访问代理服务器B。 假设该设备IP:A.A.A.A,用户名userA
设备B:位于局域网外,作为访问设备A的代理服务器,不可访问A。假设该设备IP:B.B.B.B,用户名userB
设备C:想要访问A的设备,可以访问B,无法直接访问A。假设该设备IP:C.C.C.C,用户名userC

目标:设备C可以通过SSH访问局域网内设备C

条件:三台设备都需要包含SSH客户端,A,B设备需要包含SSH服务端。

在A设备上建立A设备到B设备的反向代理:

ssh -fCNR <port_b1>:localhost:22 userB@B.B.B.B

例如:ssh -fCNR 10000:localhost:22 userB@B.B.B.B (此时B设备上已经可以通过ssh -p 10000 userA@localhost连接到设备A)

<port_b1>:建立在B机器上,用来代理设备A机器22端口的端口。

userB@B.B.B.B :B机器的用户名和IP地址。

在B设备上建立B设备到A设备的正向代理:(这样做的目的是为了实现和外网的通信)

ssh -fCNL *:<port_b2>:localhost:<port_b1> userB@localhost

例如:ssh -fCNL *:10001:localhost:10000 userB@localhost

<port_b2>:用作本地转发的端口,用来和外网通信,并将数据转发到<port_b1>,实现从其他机器可以访问。

*代表可以接受来自任意机器的访问。

现在C机器上可以通过B机器SSH到A机器

ssh -p<port_b2> userA@B.B.B.B

参数介绍

-f 后台运行-C 允许压缩数据-N 不执行任何命令-R 将端口绑定到远程服务器,反向代理-L 将端口绑定到本地客户端,正向代理

STUN协议,探测NAT类型

1, STUN客户端(101:10)向STUN服务器(404:40)发送请求,要求得到自身经NAT映射后的地址(202:20):
      a,收不到服务器回复,则认为UDP被防火墙阻断,不能通信,网络类型:Blocked.
      b,收到服务器回复(地址要嘛是映射地址要嘛就是源地址),对比本地地址,如果相同(直接返回的就是源地址101:10),则认为无NAT设备(没经过NAT映射转换),进入第2步,否则认为有NAT设备,进入3步.
   2,(已确认无NAT设备)STUN客户端向STUN服务器发送请求,要求服务器从其他IP和PORT(505:50)向客户端回复包:
      a,收不到服务器从其他IP地址的回复,认为包被前置防火墙阻断,网络类型:Symmetric UDPFirewall.(如果没有NAT的话是无论如何都能收到回复的,只有一点受到防火墙的阻断,有时候杀毒软件也阻断)

b,收到则认为客户端处在一个开放的网络上,网络类型:Opened.

   3,(已确认存在NAT设备)STUN客户端(101:10)向STUN服务器(404:40)发送请求,要求服务器从其他IP和PORT(505:50)向客户端回复包:

a,收不到服务器从其他IP地址(包括IP和Port)的回复,认为包被前置NAT设备阻断,进入第4步.(如果不是前置的就相当于全开Opened或Full ConeNat类型,无论那个IP和端口都能接收到回复)
      b,收到则认为NAT设备类型为Full Cone,即网络类型:Full Cone NAT.(此没有什么限制的基本和没有NAT一样Opened)
  4, STUN客户端(101:10)向STUN服务器(404:40)的另外一个IP地址(505:40,端口不能改变)发送请求,要求得到自身经NAT映射后的地址(202:20,如果不是对称的应该返回这个映射地址),并对比之(与第一步中返回的映射地址比对)
      a,地址不相同,则网络类型:Symmetric NAT.(如果是对称类型,则101:10在向一个不同的IP地址(505,端口不变)发送请求时会映射一个新的端口,此处相当于生成一个202:21,比对不相同)
      b,相同则认为是Restricted NAT(受限的),进入第5步,进一步确认类型.
5, (已确认RestrictedNAT设备)STUN客户端(101:10)向STUN服务器(404:40)发送请求,要求服务器从相同IP(404)的其他PORT(41)向客户端回复包:
      a,收不到服务器从其他PORT地址的回复,认为包被前置NAT设备阻断,网络类型:Port Restricted coneNAT.(端口改变了,端口受限相当于我一个人A(101)向B(404)要右手(40端口)的苹果,而B左手(41端口)有个香蕉,A只要B的右手苹果,而B给了A一个左手的香蕉,A肯定是不要的,相当于收不到回复)
      b,收到则认为网络类型: Restricted cone NAT.(IP受限,对端口没什么要求,只要是404

这个IP就行,无论用那个端口都行)

以上实现过程作为服务器只有双IP的服务器才能实现,针对我们这些电脑只有一个IP的开发者来说,我们就得通过两台电脑来模拟实现双IP了,这地方上面请求的服务器地址就得改变一下了,个人认为这里的Server1:404地址的端口必须和Server2:505地址的端口一样,才能实现,端口相同也不会影响测试效果的.

来源:http://blog.csdn.net/hack8/article/details/6593768

客户端主机所在网络可以分为以下类型:

1, Opened: 即主机拥有公网IP,并且没有防火墙,可自由与外部通信.

2, Full Cone NAT: 主机前有NAT设备,

NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,并且从任意外部地址发送到该NAT设备UDP端口B的包都会被转到主机端口A.

3, Restricted cone NAT: 主机前有NAT设备,

 NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,但只有从之前该主机发出包的目的IP发出到该NAT设备UDP端口B的包才会被转到主机端口A.

4, Port Restricted cone NAT: 主机前有NAT设备,

  NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,但只有从之前该主机发出包的目的IP/

历经 4 年半的开发,Sublime Text 3.0 正式版终发布

Sublime Text 3.0 正式发布:提供 Linux 软件包仓库支持

历经 4 年半的开发,Sublime Text 3.0  正式版终于发布了!3.0 带来了崭新的 UI 主题,新的颜色主题以及新的图标。此外,在格式高亮方面有较大改进,也支持 Windows 上的触摸板输入、支持 macOS 的 Touch Bar,以及为 Linux 提供了软件包仓库支持!

相对于 Sublime Text 2 而言,新版编辑器几乎每一个方面都有改进,所以即便是主要变更列表也显得太长了,具体可以关注这个页面

3.0 版的新特性包括:定义跳转、新的语义高亮引擎、新的用户界面和丰富的 API。改进拼写检查和自动缩进,自动换行能也更好的处理源代码,对高分屏支持更好,任意跳转也更加智能。

在 Sublime Text 3 中最令人骄傲的一点是性能:它比历史上发布过的任何一个 Sublime Text 2 版本都要快得多,启动快、打开文件快、甚至内容滚动都快。虽然它的体积比 2 要大,但是却更轻快。

J2EE框架 Spring

J2EE框架 Spring 推荐

J2EE框架 面向方面AOP/IoC Web框架
Apache
Java
跨平台

Spring Framework 是一个开源的Java/Java EE全功能栈(full-stack)的应用程序框架,以Apache许可证形式发布,也有.NET平台上的移植版本。该框架基于 Expert One-on-One Java EE Design and Development(ISBN 0-7645-4385-7)一书中的代码,最初由 Rod Johnson 和 Juergen Hoeller等开发。Spring Framework 提供了一个简易的开发方式,这种开发方式,将避免那些可能致使底层代码变得繁杂混乱的大量的属性文件和帮助类。

Spring 中包含的关键特性:

  • 强大的基于 JavaBeans 的采用控制翻转(Inversion of Control,IoC)原则的配置管理,使得应用程序的组建更加快捷简易。
  • 一个可用于从 applet 到 Java EE 等不同运行环境的核心 Bean 工厂。
  • 数据库事务的一般化抽象层,允许宣告式(Declarative)事务管理器,简化事务的划分使之与底层无关。
  • 内建的针对 JTA 和 单个 JDBC 数据源的一般化策略,使 Spring 的事务支持不要求 Java EE 环境,这与一般的 JTA 或者 EJB CMT 相反。
  • JDBC 抽象层提供了有针对性的异常等级(不再从SQL异常中提取原始代码), 简化了错误处理, 大大减少了程序员的编码量. 再次利用JDBC时,你无需再写出另一个 ‘终止’ (finally) 模块. 并且面向JDBC的异常与Spring 通用数据访问对象 (Data Access Object) 异常等级相一致.
  • 以资源容器,DAO 实现和事务策略等形式与 Hibernate,JDO 和 iBATIS SQL Maps 集成。利用众多的翻转控制方便特性来全面支持, 解决了许多典型的Hibernate集成问题. 所有这些全部遵从Spring通用事务处理和通用数据访问对象异常等级规范.
  • 灵活的基于核心 Spring 功能的 MVC 网页应用程序框架。开发者通过策略接口将拥有对该框架的高度控制,因而该框架将适应于多种呈现(View)技术,例如 JSP,FreeMarker,Velocity,Tiles,iText 以及 POI。值得注意的是,Spring 中间层可以轻易地结合于任何基于 MVC 框架的网页层,例如 Struts,WebWork,或 Tapestry。
  • 提供诸如事务管理等服务的面向方面编程框架。

在设计应用程序Model时,MVC 模式(例如Struts)通常难于给出一个简洁明了的框架结构。Spring却具有能够让这部分工作变得简单的能力。程序开发员们可以使用Spring的 JDBC 抽象层重新设计那些复杂的框架结构。

高性能PHP框架 Phalcon

BSD
PHP,C
跨平台

PhalconPHP 是一个使用 C 扩展开发的 PHP Web 框架,提供高性能和低资源占用。

Phalcon 是一个开源的、全堆栈的 PHP 5 框架,使用 C 扩展编写,专门为高性能优化。无需学习和使用 C 语言,所有函数都以 PHP 类的方式曾现。Phalcon 是一个松耦合的框架。

使用时需在 php.ini 中添加:extension=phalcon.so

参考:https://www.oschina.net/p/phalcon

卡巴斯基悲催:美国全力封杀全球第一杀软

虽然在AV-TEST最新杀软评测中,卡巴斯基得到了满分成为第一,但美国依然不允许它出现在政府采购名录中,而这个封杀的事态还在加剧。

据外媒CNET报道称,除了美国的政府机构外,FBI也在悄悄暗示那些私营机构停止使用卡巴斯基,情况十分严重。

报道中提到,能源行业以及使用工业控制系统等企业,都在被警告的名单中,而按照美国的意思,就是先让该国企业尽可能快的从其系统中移除卡巴斯基。

虽然卡巴严正否认自己进行涉嫌收集不法信息的“间谍”活动,甚至可以交出软件源代码,但目前的情况是,这丝毫没有打动当局控制者,而消息中还透露,俄罗斯也正努力移除美国科技公司如微软的操作系统。

对于微软来说,这件事他们暗地里非常开心,因为这样可以让更多的用户来换用Windows Defender,尤其是随着创意者更新全面升级的“新安全中心”。

来自:驱动之家

转自:https://www.oschina.net/news/87919/kaspersky-banned-by-american-government

IceGrid应用配置[转]

1.  概述1.1 配置目标

本文档是描述Ice中间件中的IceGrid服务的应用配置,通过使用IceGrid服务来实现:

1.  服务器端服务分布式部署。

2.  服务器端服务按需激活。

3.  服务器端服务多节点负载均衡。

4.  注册服务主/从热备(Master/Slaves)

5.  集成IceBox服务

1.2 实验环境

1.  硬件:hp服务器,3台

2.  操作环境:Red Hat 5

3.  服务器程序:ServerApp.jar

4.  说明:实际应用中,服务器节点可任意扩充、操作系统可被更换、服务器程序可用实际项目的服务程序替换,本文档所描述的配置方式具有通用性,适用但不局限于当前实验环境。

1.3 局限

本文档不详细描述IceGrid服务的运行机制和实现原理,不详细介绍服务器端和客户端程序的实现,主要描述IceGrid服务应用的配置步骤、主要配置项及验证配置结果等。

2.  配置过程

2.1  服务器端配置

配置步骤:

1.  创建主注册服务(Master)的配置文件config_master.grid,文件名称可以任意

2.  创建从注册服务(Slave)的配置文件 config_slave.grid, 文件名称可以任意

3.  创建各节点服务的配置文件config.node,文件名称可以任意

4.  创建分布式应用配置文件app.xml,文件名称可以任意,但格式最好定义成xml

5.  运行Ice提供的工具,启动我们的分布式应用,主要有如下两个工具:icegridnode和icegridadmin。详细启动过程如下:

1) icegridnode–Ice.Config=config_master.grid  启动主注册服务

2) icegridnode–Ice.Config=config_slave.grid  启动从注册服务

3) icegridadmin–Ice.Config= config_master.grid -e “application add app.xml”   部署分布式服务

icegridadmin –Ice.Config= config_master.grid-e “application update app.xml”  重新部署分布式服务

4) icegridnode–Ice.Config=config.node  将各节点注册到注册服务的注册表中

配置文件清单:

假设有n个节点(n > 0), 其中从注册服务有x个,(x > 0)

config_master.grid   ———- 主注册服务配置文件 ———  1份

config_slave.grid   ———– 从注册服务配置文件 ———  x份

config.node  —————– 节点配置文件  ————–  n份

app.xml ———————- 部署配置文件  ————–  1份

通常情况下,由于注册服务占用资源很少,所以一般都会和一个节点集成在一起,并且可以和节点服务在一个进程中运行。因此,如果假设服务部署到n个服务器,通常情况下配置文件清单如下:

config_master.grid– 主注册服务配置文件 — 1份  — 主注册服务信息+节点信息

config_slave.grid— 从注册服务配置文件 — x份  — 从注册服务信息+节点信息

config.node——— 节点配置文件 —- n-1-x份  — 节点信息

app.xml————- 部署配置文件 ——– 1份  — 部署信息

其中app.xml要和config_master.grid放在一台服务器上,下面的各章节将详细介绍各配置文件。

2.1.1  主注册服务配置

config_master.grid的内容:

#

# The IceGrid InstanceName

#

IceGrid.InstanceName=IceGridRDDataSource    # 1

 

#

# The IceGridlocator proxy.

#

Ice.Default.Locator=IceGridRDDataSource/Locator:default-h 10.0.5.201 -p 12000:default -h 10.0.5.202-p 12000         #2

 

#

# IceGridregistry configuration.

#

IceGrid.Registry.Client.Endpoints=default-p 12000   #3

IceGrid.Registry.Server.Endpoints=default    #4

IceGrid.Registry.Internal.Endpoints=default   #5

IceGrid.Registry.Data=master      #6

IceGrid.Registry.PermissionsVerifier=IceGridRDDataSource/NullPermissionsVerifier     #7

IceGrid.Registry.AdminPermissionsVerifier=IceGridRDDataSource/NullPermissionsVerifier#8

IceGrid.Registry.SSLPermissionsVerifier=IceGridRDDataSource/NullSSLPermissionsVerifier#9

IceGrid.Registry.AdminSSLPermissionsVerifier=IceGridRDDataSource/NullSSLPermissionsVerifier    #10

 

#

# IceGrid SQLconfiguration if using SQL database.

#

#Ice.Plugin.DB=IceGridSqlDB:createSqlDB     #11

#IceGrid.SQL.DatabaseType=QSQLITE      #12

#IceGrid.SQL.DatabaseName=register/Registry.db       #13

#

 

#

#Ice Error andStandard output Set

#

#Ice.StdErr=master/stderr.txt                  #14

#Ice.StdOut= master/stdout.txt    #15

 

#

#Trace Registryproperties

#

Ice.ProgramName=Master     #16

IceGrid.Registry.Trace.Node=3        #17

IceGrid.Registry.Trace.Replica=3    #18

 

#

# IceGrid nodeconfiguration.

#

IceGrid.Node.Name=node_1                              #19

IceGrid.Node.Endpoints=default                         #20

IceGrid.Node.Data=node_1               #21

IceGrid.Node.CollocateRegistry=1                      #22

#IceGrid.Node.Output=node_1            #23

#IceGrid.Node.RedirectErrToOut=1         #24

 

# Traceproperties.

#

IceGrid.Node.Trace.Activator=1             #25

#IceGrid.Node.Trace.Adapter=2             #26

#IceGrid.Node.Trace.Server=3              #27

 

#

# Dummy usernameand password for icegridadmin.

#

IceGridAdmin.Username=mygrid           #28

IceGridAdmin.Password=mygrid            #29

配置项说明:

#1 为这个应用实例指定一个唯一的标识

# 2  注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到

# 3  客户端访问注册服务器的端点信息

# 4  服务访问注册服务器的端点信息,通常是default

# 5  内部访问端点信息,通常是default,节点用这个端口和注册服务通信

# 6  注册服务的数据目录的路径

# 7  设定防火墙安全代理,从而控制客户端访问注册表时可用的权限

# 8  设定防火墙安全代理,从而控制注册表管理者可用的权限

# 9  设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制

# 10  设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制

# 11  指定Ice对象序列化的机制,如果不设置,默认用Freeze机制

# 12  指定使用数据库的类型

#13  指定使用数据库的名称

#14  指定标准错误输出文件

#15  指定标准输出文件

#16  指定主注册服务的名称

#17  指定主注册服务跟踪节点信息的级别(0~3),默认为0

#18  指定主/从热备注册服务的跟踪级别(0~3),默认为0

# 19  定义节点的名称,必须唯一

# 20 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default

# 21  节点的数据目录的路径

# 22  定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置

# 23  节点标准输出信息重定向蹈的目录路径,会自动生成输出文件

# 24  节点上的服务程序的标准错误重定向到标准输出

# 25  激活器跟踪级别,通常有0,1,2,3级,默认是0

# 26  对象适配器跟踪级别,通常有0,1,2,3级,默认是0

# 27  服务跟踪级别,通常有0,1,2,3级,默认是0

# 28  IceGrid管理器登录该应用的用户名

# 29  IceGrid管理器登录该应用的密码

未涉及的属性还有一些,如果需要请参考官方文档。

2.1.2  从注册服务配置

config_slave.grid的内容:

 

#

# The IceGridlocator proxy.

#

Ice.Default.Locator=IceGridRDDataSource/Locator:default-h 10.0.2.241 -p 12000:default -h 10.0.2.242-p 12000         #1

 

#

# IceGridregistry configuration.

#

IceGrid.Registry.Client.Endpoints=default-p 12000   #2

IceGrid.Registry.Server.Endpoints=default    #3

IceGrid.Registry.Internal.Endpoints=default   #4

IceGrid.Registry.Data=slave_1        #5

IceGrid.Registry.ReplicaName=slave_1   #6

IceGrid.Registry.PermissionsVerifier=IceGridRDDataSource/NullPermissionsVerifier     #7

IceGrid.Registry.AdminPermissionsVerifier=IceGridRDDataSource/NullPermissionsVerifier#8

IceGrid.Registry.SSLPermissionsVerifier=IceGridRDDataSource/NullSSLPermissionsVerifier#9

IceGrid.Registry.AdminSSLPermissionsVerifier=IceGridRDDataSource/NullSSLPermissionsVerifier    #10

 

#

# IceGrid SQLconfiguration if using SQL database.

#

#Ice.Plugin.DB=IceGridSqlDB:createSqlDB     #11

#IceGrid.SQL.DatabaseType=QSQLITE      #12

#IceGrid.SQL.DatabaseName=register/Registry.db       #13

#

 

#

#Ice Error andStandard output Set

#

#Ice.StdErr=slave_1/stderr.txt                 #14

#Ice.StdOut=slave_1/stdout.txt     #15

 

#

#Trace Registryproperties

#

Ice.ProgramName=Slave_1     #16

IceGrid.Registry.Trace.Node=3        #17

IceGrid.Registry.Trace.Replica=3    #18

 

#

# IceGrid nodeconfiguration.

#

IceGrid.Node.Name=node_2                              #19

IceGrid.Node.Endpoints=default                         #20

IceGrid.Node.Data=node_2               #21

IceGrid.Node.CollocateRegistry=1                      #22

#IceGrid.Node.Output=node_2            #23

#IceGrid.Node.RedirectErrToOut=1         #24

 

# Traceproperties.

#

IceGrid.Node.Trace.Activator=1             #25

#IceGrid.Node.Trace.Adapter=2             #26

#IceGrid.Node.Trace.Server=3              #27

 

#

# Dummy usernameand password for icegridadmin.

#

IceGridAdmin.Username=mygrid           #28

IceGridAdmin.Password=mygrid            #29

配置项说明:

其实这个文件和主注册配置文件基本一样,差别只有一点:

1.       没有指定应用实例名,因为在主注册服务中已经有了定义

2.       多了第6行,IceGrid.Registry.ReplicaName=slave_1,指定从注册服务的名称

其它的基本就没有差别了,大部分属性项在config_master.grid里面都有定义,为了方便阅读,下面也将用到的各项给出说明:

# 1  注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到

# 2  客户端访问注册服务器的端点信息

# 3  服务访问注册服务器的端点信息,通常是default

#4  内部访问端点信息,通常是default,节点用这个端口和注册服务通信

# 5  注册服务的数据目录的路径

# 6  指定从注册服务的名称

# 7  设定防火墙安全代理,从而控制客户端访问注册表时可用的权限

#8  设定防火墙安全代理,从而控制注册表管理者可用的权限

# 9  设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制

#10  设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制

# 11  指定Ice对象序列化的机制,如果不设置,默认用Freeze机制

# 12  指定使用数据库的类型

#13  指定使用数据库的名称

#14  指定标准错误输出文件

#15  指定标准输出文件

#16  指定从注册服务运行时程序名称

#17  指定从注册服务跟踪节点信息的级别(0~3),默认为0

#18  指定主/从热备注册服务的跟踪级别(0~3),默认为0

# 19  定义节点的名称,必须唯一

# 20  节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default

# 21  节点的数据目录的路径

# 22  定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置

# 23  节点标准输出信息重定向蹈的目录路径,会自动生成输出文件

# 24  节点上的服务程序的标准错误重定向到标准输出

# 25  激活器跟踪级别,通常有0,1,2,3级,默认是0

# 26  对象适配器跟踪级别,通常有0,1,2,3级,默认是0

# 27  服务跟踪级别,通常有0,1,2,3级,默认是0

# 28  IceGrid管理器登录该应用的用户名

# 29  IceGrid管理器登录该应用的密码

2.1.3  应用部署配置

app.xml配置文件内容:

1<icegrid>

2  <application name=“RTDSSystem”>

3    <server-template id=“RTDSSystemServer”>

4      <parameter name=“index”/>

5      <server id=“RTDSSystemServer-${index}”exe=Java                                          activation=“on-demand”>

6        <adapter name=“RTDataSysytem” endpoints=“tcp”                                          replica-group=“ReplicatedRTDataSysytemAdp”/>

7        <option>-jar</option>

8        <option>ServerApp.jar</option>

9      </server>

10    </server-template>

11

12    <replica-group id=“ReplicatedRTDataSysytemAdp”>

13      <load-balancing type=“round-robin”/>

14      <object identity=“RTDataSource”                                                      type=“::RTDataSystem::RTDataSource”/>

15    </replica-group>

16

17    <node name=“node_1”>

18      <server-instance template=“RTDSSystemServer” index=“1”/>

19      <server-instance template=“RTDSSystemServer” index=“11”/>

20      <server-instance template=“RTDSSystemServer” index=“111”/>

21    </node>

22    <node name=“node_2”>

23      <server-instance template=“RTDSSystemServer” index=“2”/>

24      <!–server-instancetemplate=”RTDSSystemServer” index=”22″/–>

25      <!–server-instancetemplate=”RTDSSystemServer” index=”222″/–>

26    </node>

27    <node name=“node_3”>

28      <server-instance template=“RTDSSystemServer” index=“3”/>

29      <!–server-instancetemplate=”RTDSSystemServer” index=”33″/–>

30      <!–server-instancetemplate=”RTDSSystemServer” index=”333″/–>

31    </node>

32  </application>

33</icegrid>

配置文件结构分析:

IceGrid里,部署是一个在注册服务中表述一个应用(Application)的过程,而部署配置文件就是来描述这些配置信息的文件,这个配置文件是用xml标记性语言来描述的。通常一个部署应该包含如下信息:

1.  应用标签(application),name属性定义这个应用的名字

2.  服务(server), 一个逻辑上的服务器,能够通过exe命令而启动的一个服务程序。activation属性,是设置服务的启动方式,on-demand是最常用的方式,另外还有always等启动方式;option标签是exe执行命令命令行的参数;

3.  适配器(adpter),定义服务器端的适配器。

name属性唯一标志这个适配器;

endpoints属性指定端点信息;

replica-group属性标示该适配器是个可复制组集群,并指定这个可复制组的名称;

register-process属性定义了是否这个节点是否可以被icegrid关闭;

4.  节点(node),它应该代表了一个物理上的节点。

name属性指定节点的名字,并且是唯一的。

5.  可复制组(replica-group),一组对象适配器的集合。

id属性唯一标识一个可复制组;

load-balancing子项中type属性指定负载均衡策略,icegrid提供了四种负载均衡策略: Random (随机方式)

       Adaptive(适配方式)

       Round Robin(最近最少使用)

       Ordered(顺序方式)

object子项定义适配器绑定的服务对象信息。其中identity属性指定对象的标识,type属性指定了对象的层次结构类型。这两个属性都可以唯一的标识一个服务对象。

6.  服务模板(server-temple),服务模板是对服务的一个抽象,避免了重复定义。这样,在节点中描述服务时只需要实例化它的服务模板就可以了。

id属性唯一标识一个服务模板;

parameter子项定义服务模板的参数,可包含多个,主要实例化服务时用;

server子项就是上面2中的服务定义;

另外还有一些特殊的服务模板,比如:icebox服务模板,它的定义和通用的服务模板的定义不太一样。

解析app.xml文件:

通过对配置文件结构的分析,来解析一下app.xml。

第1行,标识这是一个icegrid的配置文件;

第2行,标识应用的名称为RTDSSystem,这个名称是唯一的;

第3~10行,定义了一个服务模板RTDSSystemServer,并有一个参数index;

          其中5~9定义了这个模板包含的服务定义,第6行是这个服务包含的对象适配器

          的定义;

第12~15行,是对可复制组的定义,包括服务对象的定义和负载均衡策略;

第17~21行,是对节点node_1的定义,指定了节点的名称,包含的服务(3个服务);

第22~26行,是对节点node_2的定义

第27~31行,是对节点node_3的定义

最后两行是闭合标签,至此一个icegrid的分布式部署配置文件就完成了。

部署配置文件的扩展:

app.xml中对服务模板、适配器、服务对象等的配置都是一个,事实上这些可以在文件中定义多个,比如可以有多个服务模板,一个服务里可以有多个适配器,可以有多个可复制组,一个节点里可以有多个不同类型的服务等。

另外,app.xml可以包含其它的xml。

2.1.4  节点配置

config.grid文件的内容:

#

# The IceGridlocator proxy.

#

Ice.Default.Locator=IceGridRDDataSource/Locator:default-h 10.0.2.241 -p 12000:default -h 10.0.2.242-p 12000         #1

 

#

# IceGrid nodeconfiguration.

#

IceGrid.Node.Name=node_2                  #2

IceGrid.Node.Endpoints=default              #3

IceGrid.Node.Data=node_2                       #4

IceGrid.Node.Output=node_2             #5

IceGrid.Node.RedirectErrToOut=1           #6

 

# Trace properties.

#

IceGrid.Node.Trace.Activator=1             #7

#IceGrid.Node.Trace.Adapter=2             #8

#IceGrid.Node.Trace.Server=3              #9

配置项说明:

事实上,这个文件里面的配置项,在config_slave.grid中都有描述,但这里也列出来,方便阅读。

#1   注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到

#2   定义节点的名称,必须唯一

#3   节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default

#4   节点的数据目录的路径

#5   节点标准输出信息重定向的目录路径,会自动生成输出文件

#6 节点上的服务程序的标准错误重定向到标准输出

#7   激活器跟踪级别,通常有0,1,2,3级,默认是0

#8   对象适配器跟踪级别,通常有0,1,2,3级,默认是0

#9   服务跟踪级别,通常有0,1,2,3级,默认是0

2.2     客户端配置

客户端的配置很简单,和分布式相关的配置就一项,添加如下:

#

# The IceGridlocator proxy.

#

Ice.Default.Locator=IceGridRDDataSource/Locator:default-h 10.0.2.241 -p 12000:default -h 10.0.2.242-p 12000 #注册服务的端点信息(主注册服务和所有的从注册服务),用于定位

3. 结果验证

3.1  程序方式

1. 启动服务器

1) icegridnode–Ice.Config=config_master.grid  启动主注册服务和节点1

2) icegridnode–Ice.Config=config_slave.grid   启动从注册服务和节点2

3) icegridadmin–Ice.Config=config_master.grid -e “application add app.xml”   部署分布式服务

4) icegridnode–Ice.Config=config.node 启动节点3

2. 启动客户端,进行多次远程调用,根据执行情况就可以判断服务器端是否配置成功。

3.2  工具方式

用Ice官方提供的可视化管理工具IceGridGUI.jar来验证和管理icegrid的部署。

打开dos窗口,在命令行下进入C:\Program Files\ZeroC\Ice-3.4.1\bin目录下,然后运行“java –jar IceGridGUI.jar”,弹出IceGrid Admin的主界面

1. 高级应用配置

4.1  集成IceBox

在文档《IceBox开发和配置》(当前是1.0版)中,介绍了一个IceBox服务程序的开发方法和单独应用中配置和管理的过程。在实际的应用中,IceBox服务通常集成到IceGrid中,并通过IceGrid进行激活和部署。

本章节中IceBox服务是集成在IceGrid中,并通过IceGrid进行部署,所以IceBox服务的配置信息不再同《IceBox开发和配置》中一样在config.icebox中描述,而是直接配置在部署文件app.xml中。那也就是说,IceGrid集成IceBox服务,只需要在app.xml文件中添加Icebox服务相关的配置信息就可以了。事实上,有关Ice所有的配置信息(除IceGrid自身的配置信息),都可以添加到app.xml中,并通过icegrid部署后生效。

下面各节详细描述IceBox服务的集成过程。

4.1.1  IceBox服务程序编写

请参考文档《IceBox开发和配置》,这里不再详述。由于IceBox服务相关的配置信息都放在了app.xml中,并且服务是通过IceGrid按需激活的,因此这里程序代码略有调整。下面列出IceBox服务的实现代码:

文件名:ServerService.java

import main.java.DataSource;

import IceBox.Service;

public class ServerService implements IceBox.Service {

    /**

    * @param name 配置文件中的service名称

    * @param communicator对象,由IceBox.ServiceManager负责创建和销毁。

    *          可能同时被其他服务共享使用(由配置文件决定),object Adapter的名

    *          称必须是唯一的;

    * @param args  配置文件中的参数列表

    * @Override

     **/

    public void start(String name,Ice.Communicator communicator,

                      String[] args){

       //创建objectAdapter,名称有配置文件决定

       Adapter =communicator.createObjectAdapter(

                            “RTDataSystem-“+name);

       //创建servant

       StringRTDataSourceIdentity = communicator.getProperties().

                                  getProperty(“RTDataSource.Identity”);

       DataSourceobjDataSrc = new DataSource(“dataSource”);

        Adapter.add(objDataSrc,

           communicator.stringToIdentity(RTDataSourceIdentity));

        Adapter.activate();

    }

    /**

     *

    * @param args

    * @Override

     *

    **/

    public void stop()

    {

       Adapter.destroy();

    }

    private Ice.ObjectAdapter Adapter;

}

4.1.2  IceGrid集成IceBox服务

IceGrid集成IceBox只和部署文件(app.xml)有关,IceBox服务(service)的粒度和普通的server是一样的,因此IceBoxservice的部署和普通的server非常类似,它同样有模板、服务(service)和实例化的概念,可以将IceBox service理解为一个特殊的server。

为了能更清楚的描述这个集成配置的过程,在IceGrid配置的基础上,添加IceBox服务。具体目标如下:

1.      集成ServerService服务(service),并且ServerService服务(service)使用的服务对象和之前server的服务对象使用同一个(type–::RTDataSystem::RTDataSource)

2.      在节点1(node_1)上添加IceBox服务功能(IceBox-Node1),这个IceBox服务包含了5个ServerService服务;同样的在节点2(node_2)上也添加一个IceBox服务功能(IceBox-Node2),也包含了5个ServerService服务

3.      这些IceBox服务中分布的多个服务(service)和之前已经存在的服务(server)一起通过IceGrid实现负载均衡

为了实现上述的功能,需要添加IceBox服务的相关配置,首先看一下此时app.xml的变化,变化和添加部分用浅灰阴影标出。

app.xml

<?xml version=”1.0″encoding=”UTF-8″ ?>

<icegrid>

<applicationname=”RTDSSystem“>

<server-templateid=”RTDSSystemServer“>

<parameter name=”index“/>

<server id=”RTDSSystemServer-${index}” exe=”java“activation=”on-demand“>

<adapter name=”RTDataSysytem“endpoints=”tcp

replica-group=”RTDataSystemGroup“/>

<option>jar</option>

<option>ServerApp.jar</option>

</server>

</server-template>

 

<!— begin服务模板定义–>

1   <service-templateid=”RTDSystemService“>

2       <parameter name=”name“/>

3       <service name=”${name}” entry=”ServerService“>

4           <description>A simple service named after ${name}</description>

5           <properties>

6             <property name=”RTDataSource.Identity” value=”RTDataSource“/>

7           </properties>

8           <adapter name=”RTDataSystem-${name}” endpoints=”tcp

id=”RTDataSystem-${name}” replica-group=”RTDataSystemGroup

server-lifetime=”false“/>

11      </service>

12  </service-template>

<!– end服务模板定义–>

 

<replica-groupid=”RTDataSystemGroup“>

<load-balancingtype=”round-robin“/>

<!–load-balancingtype=”ordered” /–>

<!–load-balancingtype=”adaptive” /–>

<!–load-balancingtype=”random” n-replicas=”0″/–>

<object identity=”RTDataSource” type=”::RTDataSystem::RTDataSource“/>

</replica-group>

 

 

<node name=”node_1“>

<server-instancetemplate=”RTDSSystemServer” index=”1“/>

<server-instancetemplate=”RTDSSystemServer” index=”11“/>

<server-instancetemplate=”RTDSSystemServer” index=”111“/>

<!— begin IceBox服务配置 IceBox-Node1–>

1     <icebox id=”IceBox-Node1” activation=”on-demand“exe=”java”>

2        <description>Asample IceBox server IceBox-Node1</description>

3        <option>IceBox.Server</option>

4        <properties>

5           <property name=”IceBox.InstanceName” value=”${server}“/>

6           <property name=”Ice.Admin.Endpoints” value=”tcp -h 10.0.2.241“/>

7           <property name=”IceBox.Trace.ServiceObserver” value=”1“/>

8        </properties>

9        <service-instance template=”RTDSystemService” name=”one“/>

10       <service-instancetemplate=”RTDSystemService” name=”two“/>

11       <service-instancetemplate=”RTDSystemService” name=”three“/>

12       <service-instancetemplate=”RTDSystemService” name=”four“/>

13       <service-instancetemplate=”RTDSystemService” name=”five“/>

14     </icebox>

<!— end IceBox服务配置 IceBox-Node1–>

</node>

<node name=”node_2“>

<server-instancetemplate=”RTDSSystemServer” index=”2“/>

<server-instancetemplate=”RTDSSystemServer” index=”22“/>

<server-instancetemplate=”RTDSSystemServer” index=”222“/>

<!— begin IceBox服务配置 IceBox-Node2–>

1     <icebox id=”IceBox-Node2” activation=”on-demand“exe=”java“>

2        <description>Asample IceBox server IceBox-Node2</description>

3        <option>IceBox.Server</option>

4        <properties>

5           <property name=”IceBox.InstanceName” value=”${server}“/>

6           <property name=”Ice.Admin.Endpoints” value=”tcp -h 10.0.2.242“/>

7           <property name=”IceBox.Trace.ServiceObserver” value=”1“/>

8        </properties>

9        <service-instancetemplate=”RTDSystemService” name=”2-one”/>

10       <service-instancetemplate=”RTDSystemService” name=”2-two“/>

11       <service-instancetemplate=”RTDSystemService” name=”2-three“/>

12       <service-instancetemplate=”RTDSystemService” name=”2-four“/>

13       <service-instancetemplate=”RTDSystemService” name=”2-five“/>

14     </icebox>

<!— begin IceBox服务配置 IceBox-Node2–>

</node>

<node name=”node_3“>

<server-instancetemplate=”RTDSSystemServer” index=”3“/>

</node>

</application>

</icegrid>

app.xml中增加的IceBox服务相关的配置部分如下:

n  服务摸板(Service Template):

可以对比一下servertemplate的定义,两者基本上没有什么区别,最大的不同是

Server template中server是指定一个可执行的程序,而service中指定的是动态加载

的组件入口。以下解释上述配置中的服务模板的定义:

第1行指定定义模板的id,唯一标志一个服务模板,第12是闭合标签;

第2行定义了一个参数name,默认值是“name”;

第3~11行定义了模板中使用的服务(service),并在该service中指定了名称、

入口、描述信息、配置属性,定义了一个对象适配器;

第4行,是该服务的描述信息;

第5~7行,是属性定义列表,这里定义了一个属性RTDataSource.Identity,并

指定其值为RTDataSource;

第8行,定义了一个对象适配器,指定了其name、endpoints、id、replica-group

等属性信息,这个基本上和server中adapter的定义没有什么区别

 

以上内容就是service模板的定义。

n  IceBox服务(IceBox-Node1):

                 icebox服务的定义被包含在分布的服务器节点中,主要包括三部分的信息:

1.      IceBox服务的启动配置信息

2.      IceBox的属性配置信息

3.      Service服务实例化列表

下面解释这块内容:

第1~3行,指定了IceBox服务的名称,启动方式,启动执行程序等

第4~8行,指定了IceBox服务的属性配置列表,这里定义了IceBox服务的实

例名称、管理器访问端点以及service被跟踪的级别

第9~13行,实例化了5个service服务

至此,一个包含了5个serverservice服务的IceBox服务被集成在node1中。

n  IceBox服务(IceBox-Node2)

同IceBox服务(IceBox-Node1)中描述,只是具体value有所不同,这里不再解释。

  4.1.3  测试验证

验证方式同第3章,这里不再赘述。部署完成后,就可以通过IceGridGUI.jar程序来进行管理

来源:http://blog.csdn.net/educast/article/details/9414789

苹果下架中国区主流VPN应用

苹果下架中国区主流VPN应用

雷锋网(公众号:雷锋网)消息,根据纽约时报的报道,苹果下架了中国区App Store的一些主流VPN应用。

据报道,一些公司收到了来自苹果的通知,称他们的APP已从中国区应用市场下架。

一个名为ExpressVPN的应用在其博客上称,苹果给出的解释是产品违反了中国法律,应用中包含一些非法的内容。这家公司还称,他们发现所有的主流iOS端VPN应用都被下架了。

苹果下架中国区主流VPN应用

ExpressVPN收到的通知

另一家名为Star VPN的应用也称收到了同样的通知。

雷锋网以VPN为关键词搜索中国区苹果商店,发现还是有很多应用可以下载。不过上述两家的应用确实搜不到。

之前有消息称,明年2月国内会停止所有VPN服务,不过后来工信部称,规范对象主要是未经电信主管部门批准,无国际通信业务经营资质企业和个人。

苹果越来越重视中国市场。不久前雷锋网报道,苹果将在贵州建其在中国的首个数据中心。另外,一个多星期前,苹果还宣布任命原苹果无线技术副总裁葛越女士担任大中华区董事总经理,全面负责中国的业务和团队,而且这一职位为新设立的。

雷锋网原创文章,未经授权禁止转载。详情见转载须知

来源:https://www.leiphone.com/news/201707/nB4mZxwvxz3iYaPy.html

此地址使用了一个通常用于网络浏览以外的端口。出于安全原因,Firefox 取消了该请求

此地址使用了一个通常用于网络浏览以外的端口。出于安全原因,Firefox 取消了该请求

FirFox打开80以外的端口,会弹出以下提示:

“此地址使用了一个通常用于网络浏览以外的端口。出于安全原因,Firefox 取消了该请求。”。

其实是使用了不安全的端口,解决方法如下:

1.在Firefox地址栏输入about:config

2.在右键新建一个字符串键 network.security.ports.banned.override

将需访问网站的端口号添加到,值就是那个端口号即可。
如有多个,就半角逗号隔开,例:81,88,98

在能保证安全的前提下,还简化成这样写1025-65535。

这样,就可以浏览指定范围任意端口的网站了。

chrome 参考:http://my.liyunde.com/chrome-err_unsafe_port/

chrome 谷歌浏览器出现 错误代码:ERR_UNSAFE_PORT 的解决办法

1、问题描述:

使用谷歌浏览器访问一个WEB项目,该项目设置的端口号为6000,结果不能访问:
 
2、问题所在:
出现此类问题的原因不是服务器端的问题,而是谷歌浏览器(FF浏览器也有)对一些特殊的端口进行了限制,具体有哪些端口进行了访问限制,请参见本文末。
 
3、问题解决:
最简单的办法就是直接修改搭建项目的端口号,避开这些谷歌限制的端口号。
 
谷歌浏览器限制的一些端口号:
1:    // tcpmux
7:    // echo
9:    // discard
11:   // systat
13:   // daytime
15:   // netstat
17:   // qotd
19:   // chargen
20:   // ftp data
21:   // ftp access
22:   // ssh
23:   // telnet
25:   // smtp
37:   // time
42:   // name
43:   // nicname
53:   // domain
77:   // priv-rjs
79:   // finger
87:   // ttylink
95:   // supdup
101:  // hostriame
102:  // iso-tsap
103:  // gppitnp
104:  // acr-nema
109:  // pop2
110:  // pop3
111:  // sunrpc
113:  // auth
115:  // sftp
117:  // uucp-path
119:  // nntp
123:  // NTP
135:  // loc-srv /epmap
139:  // netbios
143:  // imap2
179:  // BGP
389:  // ldap
465:  // smtp+ssl
512:  // print / exec
513:  // login
514:  // shell
515:  // printer
526:  // tempo
530:  // courier
531:  // chat
532:  // netnews
540:  // uucp
556:  // remotefs
563:  // nntp+ssl
587:  // stmp?
601:  // ??
636:  // ldap+ssl
993:  // ldap+ssl
995:  // pop3+ssl
2049: // nfs
3659: // apple-sasl / PasswordServer
4045: // lockd
6000: // X11
6665: // Alternate IRC [Apple addition]
6666: // Alternate IRC [Apple addition]
6667: // Standard IRC [Apple addition]
6668: // Alternate IRC [Apple addition]
6669: // Alternate IRC [Apple addition]

Log4j2.xml Eclipse 添加自动提示

参考:https://issues.apache.org/jira/browse/LOG4J2-411

Support of XSD/DTD linked to the configuration file

It would be very nice, if the the XML configuration uses an dedicated namespace, e.g. http://logging.apache.org/log4j/2.0/config.
This feature allows using XML catalogs to locate the schema locally, e.g. with Eclipse IDE.
The Log4j-events.xsd contains already such a declaration:

targetNamespace="http://logging.apache.org/log4j/2.0/events"

Then the configuration XML file needs only a small extension:

log4j2.xml
<?xml version="1.0" encoding="utf-8"?>
<Configuration status="WARN" xmlns="http://logging.apache.org/log4j/2.0/config">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
    </Console>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>

Java9新功能之HTTP2和REPL

本文转自:云栖社区云

【摘要】对Java 9的炒作将不再局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正作为Java增强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。 在这篇文章中,我们将重点关注一些或将在Java 9整个生命周期中,对开发者的工作生…

对Java 9的炒作将不再局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正作为Java增强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。

在这篇文章中,我们将重点关注一些或将在Java 9整个生命周期中,对开发者的工作生活影响最大的JEP,包括新的HTTP/2支持和JShell REPL(读取-求值-打印-循环),后者带来了基于shell的交互式Java开发环境和探索性开发API。

HTTP/2

HTTP/2标准是HTTP协议的最新版本。当前版本HTTP/1.1始于1999年,存在着非常严重的问题,包括:

对头阻塞

在HTTP/1.1中,响应接收的顺序和请求发送的顺序相同。这意味着,例如,当查看一个包含许多小图像的大HTML页面时,图像资源将不得不在HTML页面资源之后排队,在浏览器完全加载完HTML页面之前,图像资源无法被发送。这就是“对头阻塞”,会导致许多潜在的页面渲染问题。

在HTTP/2中,响应数据可以按块(chunk)传输,甚至可以交叉传输,因此真正实现了请求和响应的多路复用。

一个站点的连接数限制

在HTTP/1.1标准中有这样的描述:“一个单用户的客户端不能与任何服务器保持2个以上的连接”。这个限制和对头阻塞问题一起,严重限制了页面的性能。

HTTP/2打破这种限制并认为连接是持久的,只有当用户跳转后或者发生技术性故障事件时,连接才会关闭。对多路复用的使用将有助于降低页面性能瓶颈。

HTTP控制头的开销

当前的HTTP版本使用简单的、基于文本的HTTP头信息来控制通信。这样做的优点是非常简单且易于理解,调试也很简单,只需通过连接指定端口并输入一些文本。然而,使用基于文本的协议会让小的响应包不成比例地膨胀。此外,大量的HTTP响应几乎没有或者根本没有有效负载(比如,HEAD请求只是要确定资源是否发生变化)。为实际上只包含最后修改时间的响应,使用完全基于文本的头信息(大约有700个字节,在HTTP1.1中,它们不能被压缩,尽管很容易做到)是当前HTTP标准中,不可思议的浪费。

另一个思路是对HTTP头信息使用二进制编码。这种方式能够极大地提高较小请求的速度且占用的网络带宽非常小。这正是HTTP/2已经选择的方法,虽然以协议精神制定标准应该选择基于文本的协议,但是二进制的效率有令人信服的理由,让我们这样做。

HTTP/2带来的期望

HTTP/2标准是由IETF HTTP工作组创建的,该组织由来自Mozilla、Google、 Microsoft、Apple,以及其他公司的代表和工程师组成,由来自CDN领军公司Akamai的高级工程师Mark Nottingham任主 席。因此,HTTP/2是一个为优化大型、高流量的网站而生的版本,它在实现简单、易于调试的基础上,确保了性能和网络带宽消耗。

该组织主 席总结了一些HTTP/2的关键属性:

相同的HTTP API成本更低的请求网络和服务器端友好缓存推送思维革命更多加密方式

带给Java的意义

自从1.0版本开始,Java就支持HTTP,但是多数代码出自完全不同的时代。例如,Java对HTTP的支持是围绕相对协议无关的框架(URL类)设计的,因此在网站成为主导地位的90年代,这种实现显得很不清晰。

Java对HTTP的支持是基于当时最好的设计思想,但是时过境迁,最重要的是Java对HTTP原始的支持出来时,HTTPS还没有出现。因此,Java的API将HTTPS作为一种移花接木,导致了不能简化的复杂性。

在现代社会,HTTPS开始变得无所不在,让HTTP日渐成为落后的技术。甚至,美国政府现在都通过了完全迁到HTTPS-only的计划。

JDK内核对HTTP的支持已经无法跟上现实网络的发展步伐。实际上,甚至JDK8也只不过是交付了一个支持HTTP/1.0的客户端,然而,大多数的开发者早已转而使用第三方客户端库了,比如Apache的HttpComponents。

所有这一切意味着,对HTTP/2的支持将是Java未来十年的核心功能。这也让我们重新审视我们的固有思维,重新写一套API并提供重新来过的机会。HTTP/2将是未来数年内,每位开发者主要面对的API。

新的API不再坚持协议中立性,使开发者可以完全抛弃过去的使用方式。这套API只关注HTTP协议,但是要进一步理解的是HTTP/2并没有从根本上改变原有的语义。因此,这套API是HTTP协议独立的,同时提供了对新协议中帧和连接处理的支持。

在新的API中,一个简单的HTTP请求,可以这样创建和处理:

HttpResponse response = HttpRequest .create(new URI(“http://www.infoq.com”)) .body(noBody()) .GET().send(); int responseCode = response.responseCode(); String responseBody = response.body(asString()); System.out.println(responseBody);

这种符合流畅风格/建造者模式(fluent/builder)的API,与现存的遗留系统相比,对开发者来说,更具现代感和舒适感。

虽然当前的代码库只支持HTTP/1.1,但是已经包含了新的API。这使得在对HTTP/2支持完成对过程中,开发者可以实验性地使用和验证新的API。

相关代码已经进入OpenJDK沙箱仓库中,并很快登陆JDK 9的主干。到那个时候,新的API将开始自动构建到Oracle的二进制beta版本中。现在,对HTTP/2的支持已经可用,并将在未来数月内最终完成。

在此期间,你可以使用Mercurial迁出源代码,并根据AdoptOpenJDK构建指导编译你迁出地代码,这样你就可以实验性地使用新的API了。

第一批完成的功能之一是当前版本力不能及的异步API。这个功能让长期运行的请求,可以通过sendAsync()方法,切换到VM管理的后台线程中:

HttpRequest req = HttpRequest .create(new URI(“http://www.infoq.com”)) .body(noBody()) .GET(); CompletableFuture<HttpResponse> aResp = req.sendAsync(); Thread.sleep(10); if (!aResp.isDone()) { aResp.cancel(true); System.out.println(“Failed to reply quickly…”); return; } HttpResponse response = aResp.get();

相比HTTP/1.1的实现,新的API带给开发者最多的是方便性,因为HTTP/1.1没有提供对已经发送到服务器端的请求的取消机制,而HTTP/2可以让客户端向已经被服务器端处理的请求,发送取消命令。

JShell

很多语言都为探索性开发提供了交互式环境。在某些情况下(特别是Clojure和其他Lisp方言),交互式环境占据了开发者的大部分编码时间,甚至是全部。其他语言,比如Scala或者JRuby也广泛使用REPL。

当然,此前Java曾经推出过Beanshell脚本语言,但是它没有实现完全标准化,而且近年来,该项目已经处于不活跃状态。在Java 8(以及jjs REPL)中引入的Nashorn Java实现打开了更广泛地考虑REPL并将交互式开发成为可能的大门。

一项努力将现代REPL引入Java 9的工作,以JEP 222作为开始,收录在OpenJDK的Kulla项目中。Kulla这个名字来自古巴比伦神话,是建造之神。该项目的主旨是提供最近距离的“完整Java”体验。该项目没有引入新的非Java语义,并禁用了Java语言中对交互式开发没有用处的语义(比如上层的访问控制修改或同步的语义)。

与所有REPL一样,JShell提供了命令行,而不是类似IDE的体验。语句和表达式能够在执行状态上下文中,被立即求值,而不是非得打包到类中。方法也是自由浮动的,而不必属于某个特定的类。相反,JShell使用代码片断“snippets”来提供上层执行环境。

与HTTP/2 API相似,JShell已经在独立的项目开发,以免在快速发展的时期影响主干构建的稳定性。JShell预计在2015年8月期间合并到主干。

现在,开发者可以参考AdoptOpenJDK说明指导,从头构建Kulla(源代码可以从Mercurial地址获得)。

对于一些上手实验,最简单的可能是使用一个独立的试验jar。这些jar包是社区专为不想从头构建的开发者构建好的。

这些试验jar包可以从AdoptOpenJDK CloudBees的CI构建实例中获得。

要使用它们,你需要安装Java 9 beta版(或者OpenJDK 9的构建版本)。然后下载jar文件,重命名为kulla.jar,然后在命令行输入如下:

$ java -jar kulla.jar | Welcome to JShell — Version 0.610 | Type /help for help ->

这是REPL的标准界面,和往常一样,命令是从单个字符开始并最终发出的。

JShell有一个相当完整(但仍在发展)的帮助语法,可以通过如下命令轻松获得:

-> /help Type a Java language expression, statement, or declaration. Or type one of the following commands: /l or /list [all] — list the source you have typed /seteditor <executable> — set the external editor command to use /e or /edit <name or id> — edit a source entry referenced by name or id /d or /drop <name or id> — delete a source entry referenced by name or id /s or /save [all|history] <file> — save the source you have typed /o or /open <file> — open a file as source input /v or /vars — list the declared variables and their values /m or /methods — list the declared methods and their signatures /c or /classes — list the declared classes /x or /exit — exit the REPL /r or /reset — reset everything in the REPL /f or /feedback <level> — feedback information: off, concise, normal, verbose, default, or ? /p or /prompt — toggle display of a prompt /cp or /classpath <path> — add a path to the classpath /h or /history — history of what you have typed /setstart <file> — read file and set as the new start-up definitions /savestart <file> — save the default start-up definitions to the file /? or /help — this help message /! — re-run last snippet /<n> — re-run n-th snippet /-<n> — re-run n-th previous snippet Supported shortcuts include: — show possible completions for the current text Shift- — for current method or constructor invocation, show a synopsis of the method/constructor

JShell支持TAB键自动补全, 因此我们可以很容易找到println()或者其他我们想使用的方法:

-> System.out.print print( printf( println(

传统的表达式求值也很容易,但是相比其他动态类型语言,Java的静态类型特征会更严格一点。JShell会自动创建临时变量来保存表达式的值,并确保它们保持在上下文域内供以后使用:

-> 3 * (4 + 5) | Expression value is: 27 | assigned to temporary variable $1 of type int -> System.out.println($1); 27

我们还可以使用/list命令,查看到目前为止输入的所有源代码:

-> /list 9 : 3 * (4 + 5) 10 : System.out.println($1);

使用/vars命令显示所有的变量(包括显式定义的和临时的),以及他们当前持有的值:

-> String s = “Dydh da” | Added variable s of type String with initial value “Dydh da” -> /vars | int $1 = 27 | String s = “Dydh da”

除了支持简单的代码行,REPL还允许非常简单地创建类和其它用户定义的类型。例如,可以用如下短短一行来创建类(请注意,开始和结束括号是必需的):

-> class Pet {} | Added class Pet -> class Cat extends Pet {} | Added class Cat

JShell代码非常简洁、自由浮动的性质意味着我们可以非常简单地使用REPL来演示Java语言的功能。例如,让我们来看看著名的类型问题,即Java数组的协变问题:

-> Pet[] pets = new Pet[1] | Added variable pets of type Pet[] with initial value [LPet;@2be94b0f -> Cat[] cats = new Cat[1] | Added variable cats of type Cat[] with initial value [LCat;@3ac42916 -> pets = cats | Variable pets has been assigned the value [LCat;@3ac42916 -> pets[0] = new Pet() | java.lang.ArrayStoreException thrown: REPL.$REPL13$Pet | at (#20:1)

这样的功能使JShell成为一种伟大的教学或研究工具,而且最接近Scala REPL的体验。使用/classpath切换,可以加载额外的jar包,从而可以在REPL直接使用互动式探索性API。

参与

主要的IDE已开始提供支持JDK 9早期版本的构建——包括Netbeans和Eclipse Mars。[urlhttps://www.jetbrains.com/idea/download/?spm=5176.blog26632.yqblogcon1.14.tXFWPP=””]IntelliJ 14.1[/url]据称支持JDK9,但目前还不清楚对新的模块化JDK扩展的支持力度。

到目前为止,这些IDE还不支持HTTP/2和JShell,因为这些功能还没有登陆OpenJDK的主干,但是开发者应该很期望它们能够早日出现在标准的JDK beta版本中,并且有IDE插件可以紧随其后。这些API仍在开发中,项目的领导者正在积极寻求最终用户的使用和参与。

The JDK 9 Outreach programme is also underway to encourage developers to test their code and applications on JDK 9 before it arrives. HTTP/2 & JShell aren’t the only new features being worked on – other new JDK 9 functionality under development as JEPs includes

JDK 9的宣传计划也正在鼓励开发者测试他们的代码并在JDK 9上运行应用程序。正在开发的新功能不止包括HTTP/2和JShell—— 其他作为JEP,JDK 9正在开发的新功能还包括:

102 Process API的更新(Process API Updates)165 编译器控制(Compiler Control)227 Unicode 7.0245 验证虚拟机代码行标记参数(Validate JVM Command-Line Flag Arguments)248: G1作为默认的垃圾回收器(Make G1 the Default Garbage Collector)TLS的一系列更新(TLS Updates) (JEP 219, 244, 249)

目前正在审议(以及考虑应该放在哪个Java版本)的所有JEP的完整列表可以在这里找到。

开发高效率 Git命令 Cherry-Pick 摘樱桃

在实际的项目开发中(使用Git版本控制),在所难免会遇到没有切换分支开发、需要在另一个分支修改bug然后合并到当前分支的情况。之前遇到这种第一反应就是将分支合并过去来解决问题。如果你那些提交当中也穿插了其他人的提交而且他们的提交不可以合并到另一个分支,那么使用分支的合并将明显变得困难。下面分享给大家一个非常好用Git的命令Cherry-Pick来处理这些情况,从而提高开发的效率。

git Cherry-Pick 命令可以选择某一个分支中的一个或几个commit(s)来进行操作。你可以理解merge的个性定制版本

多次使用时要按提交的顺序进行合并,不然会导致某些文件发生冲突。这也是 容易 踩的坑。

  1. 当你的需求还没有完成的时候,其他人应该切换到另一分支开发的时候,你可以先在当前分支继续开发完,然后再选择Cherry-Pick命令合并过去就可以了。
  2. 当你需要将某个人的commits合并到另一开分时候,可以选择Cherry-Pick命令。(在实际的项目开发中,在所难免有人会提交错分支)
  3. 当你切换到某条分支修改Bug后,需要将修改提交合并另一分支,可以选择Cherry-Pick命令。

Linux Kernel 3.18 LTS 终止支持 请升至 4.9 或 4.4 分支

在发布最后一个维护版本更新之后,Linux 稳定版内核维护者 Greg Kroah-Hartman 宣布 Linux Kernel 3.18 分支走到了生命的尽头。而 3.18 LTS 原计划于今年 1 月终止支持。

Linux Kernel 3.18.48 LTS 是该分支的最后版本,根据短日志显示该版本共计调整了 50 个文件,插入 159 处删除 351 处。升级网络堆栈的同时改善了 Bluetooth, Bridge, IPv4, IPv6, CAIF 和 Netfilter,并升级了 USB, SCSI, ATA, media, GPU, ATM, HID, MTD, SPI 和网络(有线和无线)驱动。新发布的 3.18.48 还修正了 3.18.47 和 3.18.27 中的一个 bug。

LTS 版通常会提供大约两年的支持时间,3.18 是在 2014 年 12 月发布的。如果你当前还在使用该内核分支,那么现在你应该升级至更新的 LTS 版本,例如 Linux Kernel 4.9 或者 4.4,这两个版本要比 3.18 更加的安全和强悍。不过 Linux Kernel 3.18 主要被 Google 和其他供应商应用于一些 Android 设备、部分 Chromebook 上,Kroah-Hartman 建议用户拒绝购买仍然使用 3.18 LTS 的供应商的设备。如果无法升级内核开发者也提供了一些建议。

“如果你在使用 Linux Kernel 3.18 中有困难,那么我可以给你提供一些帮助。首先,你需要和硬件供应商反馈,要求尽快升级否则不再购买他们的产品。如果供应商还是不升级,请致信我们让我们出面和厂商进行沟通,出现这个问题的肯定不止你一个人。”

来源:http://www.oschina.net/news/81799/linux-kernel-3-18-48-released

Eloquent ORM Laravel 5.3 创建 配置与使用

1、简介

Laravel 自带的 Eloquent ORM 提供了一个美观、简单的与数据库打交道的 ActiveRecord 实现,每张数据表都对应一个与该表进行交互的“模型”,模型允许你在表中进行数据查询,以及插入、更新、删除等操作。

在开始之前,确保在config/database.php文件中配置好了数据库连接。更多关于数据库配置的信息,请查看文档。

2、定义模型

作为开始,让我们创建一个 Eloquent 模型,模型通常位于app目录下,你也可以将其放在其他可以被composer.json文件自动加载的地方。所有Eloquent模型都继承自 Illuminate\Database\Eloquent\Model类。

创建模型实例最简单的办法就是使用 Artisan 命令make:model

php artisan make:model User

如果你想要在生成模型时生成数据库迁移,可以使用--migration-m选项:

php artisan make:model User --migration
php artisan make:model User -m

Eloquent 模型约定

现在,让我们来看一个 Flight 模型类例子,我们将用该类获取和存取数据表flights中的信息:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    //
}

表名

注意我们并没有告诉 Eloquent 我们的Flight模型使用哪张表。默认规则是模型类名的复数作为与其对应的表名,除非在模型类中明确指定了其它名称。所以,在本例中,Eloquent 认为Flight模型存储记录在flights表中。你也可以在模型中定义table属性来指定自定义的表名:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 关联到模型的数据表
     *
     * @var string
     */
    protected $table = 'my_flights';
}

主键

Eloquent 默认每张表的主键名为id,你可以在模型类中定义一个$primaryKey属性来覆盖该约定。

此外,Eloquent默认主键字段是自增的整型数据,这意味着主键将会被自动转化为int类型,如果你想要使用非自增或非数字类型主键,必须在对应模型中设置$incrementing属性为false

时间戳

默认情况下,Eloquent 期望created_atupdated_at已经存在于数据表中,如果你不想要这些 Laravel 自动管理的列,在模型类中设置$timestamps属性为false

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 表明模型是否应该被打上时间戳
     *
     * @var bool
     */
    public $timestamps = false;
}

如果你需要自定义时间戳格式,设置模型中的$dateFormat属性。该属性决定日期被如何存储到数据库中,以及模型被序列化为数组或 JSON 时日期的格式:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 模型日期列的存储格式
     *
     * @var string
     */
    protected $dateFormat = 'U';
}

数据库连接
 
默认情况下,所有的 Eloquent 模型使用应用配置中的默认数据库连接,如果你想要为模型指定不同的连接,可以通过$connection 属性来设置:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * The connection name for the model.
     *
     * @var string
     */
    protected $connection = 'connection-name';
}

3、获取模型

创建完模型及其关联的数据表后,就要准备从数据库中获取数据。将Eloquent模型看作功能强大的查询构建器,你可以使用它来流畅的查询与其关联的数据表。例如:

<?php

use App\Flight;

$flights = App\Flight::all();

foreach ($flights as $flight) {
    echo $flight->name;
}

添加额外约束

Eloquent 的all方法返回模型表的所有结果,由于每一个Eloquent模型都是一个查询构建器,你还可以添加约束条件到查询,然后使用get方法获取对应结果:

$flights = App\Flight::where('active', 1)
               ->orderBy('name', 'desc')
               ->take(10)
               ->get();

注意:由于 Eloquent 模型本质上就是查询构建器,你可以在Eloquent查询中使用查询构建器的所有方法。

集合

对 Eloquent 中获取多个结果的方法(比如allget)而言,其返回值是Illuminate\Database\Eloquent\Collection的一个实例,Collection类提供了多个有用的函数来处理Eloquent结果集:

$flights = $flights->reject(function ($flight) {
    return $flight->cancelled;
});

当然,你也可以像数组一样循环遍历该集合:

foreach ($flights as $flight) {
    echo $flight->name;
}

组块结果集

如果你需要处理成千上万个 Eloquent 结果,可以使用chunk命令。chunk方法会获取一个“组块”的 Eloquent 模型,并将其填充到给定闭包进行处理。使用chunk方法能够在处理大量数据集合时有效减少内存消耗:

Flight::chunk(200, function ($flights) {
    foreach ($flights as $flight) {
        //
    }
});

传递给该方法的第一个参数是你想要获取的“组块”数目,闭包作为第二个参数被调用用于处理每个从数据库获取的区块数据。

使用游标

cursor
方法允许你使用游标迭代处理数据库记录,一次只执行单个查询,在处理大批量数据时,cursor方法可大幅减少内存消耗:

foreach (Flight::where('foo', 'bar')->cursor() as $flight) {
    //
}

4、获取单个模型/聚合

当然,除了从给定表中获取所有记录之外,还可以使用findfirst获取单个记录。这些方法返回单个模型实例而不是返回模型集合:

// 通过主键获取模型...
$flight = App\Flight::find(1);
// 获取匹配查询条件的第一个模型...
$flight = App\Flight::where('active', 1)->first();

还可以通过传递主键数组来调用find方法,这将会返回匹配记录集合:

$flights = App\Flight::find([1, 2, 3]);

Not Found 异常

有时候你可能想要在模型找不到的时候抛出异常,这在路由或控制器中非常有用,findOrFailfirstOrFail方法会获取查询到的第一个结果。然而,如果没有任何查询结果,Illuminate\Database\Eloquent\ModelNotFoundException异常将会被抛出:

$model = App\Flight::findOrFail(1);
$model = App\Flight::where('legs', '>', 100)->firstOrFail();

如果异常没有被捕获,那么HTTP 404 响应将会被发送给用户,所以在使用这些方法的时候没有必要对返回404响应编写明确的检查:

Route::get('/api/flights/{id}', function ($id) {
    return App\Flight::findOrFail($id);
});

获取聚合

当然,你还可以使用查询构建器聚合方法,例如countsummax,以及其它查询构建器提供的聚合方法。这些方法返回计算后的结果而不是整个模型实例:

$count = App\Flight::where('active', 1)->count();
$max = App\Flight::where('active', 1)->max('price');

5、插入/更新模型

插入

想要在数据库中插入新的记录,只需创建一个新的模型实例,设置模型的属性,然后调用save方法:

<?php

namespace App\Http\Controllers;

use App\Flight;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class FlightController extends Controller{
    /**
     * 创建一个新的航班实例
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Validate the request...

        $flight = new Flight;

        $flight->name = $request->name;

        $flight->save();
    }
}

在这个例子中,我们只是简单分配HTTP请求中的name参数值给App\Flight模型实例的那么属性,当我们调用save方法时,一条记录将会被插入数据库。created_atupdated_at时间戳在save方法被调用时会自动被设置,所以没必要手动设置它们。

更新

save方法还可以用于更新数据库中已存在的模型。要更新一个模型,应该先获取它,设置你想要更新的属性,然后调用save方法。同样,updated_at时间戳会被自动更新,所以没必要手动设置其值:

$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save();

更新操作还可以同时修改给定查询提供的多个模型实例,在本例中,所有有效且destination=San Diego的航班都被标记为延迟:

App\Flight::where('active', 1)
          ->where('destination', 'San Diego')
          ->update(['delayed' => 1]);

update方法要求以数组形式传递键值对参数,代表着数据表中应该被更新的列。

注:通过Eloquent进行批量更新时,savedupdated模型事件将不会在更新模型时触发。这是因为在进行批量更新时并没有从数据库获取模型。

批量赋值

还可以使用create方法保存一个新的模型。该方法返回被插入的模型实例。但是,在此之前,你需要指定模型的fillableguarded属性,因为所有Eloquent模型都通过批量赋值(Mass Assignment)进行保护。

当用户通过 HTTP 请求传递一个不被期望的参数值时就会出现安全隐患,然后该参数以不被期望的方式修改数据库中的列值。例如,恶意用户通过 HTTP 请求发送一个is_admin参数,然后该参数映射到模型的create方法,从而允许用户将自己变成管理员。

所以,你应该在模型中定义哪些属性是可以进行赋值的,使用模型上的$fillable属性即可实现。例如,我们设置Flight模型上的name属性可以被赋值:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 可以被批量赋值的属性.
     *
     * @var array
     */
    protected $fillable = ['name'];
}

设置完可以被赋值的属性之后,我们就可以使用create方法在数据库中插入一条新的记录。create方法返回保存后的模型实例:

$flight = App\Flight::create(['name' => 'Flight 10']);

黑名单属性

$fillable就像是可以被赋值属性的“白名单”,还可以选择使用$guarded$guarded属性包含你不想被赋值的属性数组。所以不被包含在其中的属性都是可以被赋值的,因此,$guarded功能就像“黑名单”。当然,这两个属性你只能同时使用其中一个——而不能一起使用,因为它们是互斥的:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 不能被批量赋值的属性
     *
     * @var array
     */
    protected $guarded = ['price'];
}

如果你想要让所有属性都是可批量赋值的,可以将$guarded属性设置为空数组:

/**
 * The attributes that aren't mass assignable.
 *
 * @var array
 */
protected $guarded = [];

其它创建方法

还有其它两种可以用来创建模型的方法:firstOrCreatefirstOrNewfirstOrCreate方法先尝试通过给定列/值对在数据库中查找记录,如果没有找到的话则通过给定属性创建一个新的记录。

firstOrNew方法和firstOrCreate方法一样先尝试在数据库中查找匹配的记录,如果没有找到,则返回一个的模型实例。注意通过firstOrNew方法返回的模型实例并没有持久化到数据库中,你还需要调用save方法手动持久化:

// 通过属性获取航班, 如果不存在则创建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);
// 通过属性获取航班, 如果不存在初始化一个新的实例...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);

6、删除模型

要删除一个模型,调用模型实例上的delete方法:

$flight = App\Flight::find(1);
$flight->delete();

通过主键删除模型

在上面的例子中,我们在调用delete方法之前从数据库中获取该模型,然而,如果你知道模型的主键的话,可以调用destroy方法直接删除而不需要获取它:

App\Flight::destroy(1);
App\Flight::destroy([1, 2, 3]);
App\Flight::destroy(1, 2, 3);

通过查询删除模型

当然,你还可以通过查询删除多个模型,在本例中,我们删除所有被标记为无效的航班:

$deletedRows = App\Flight::where('active', 0)->delete();

注:通过Eloquent进行批量删除时,deletingdeleted模型事件在删除模型时不会被触发,这是因为在进行模型删除时不会获取模型。

软删除

除了从数据库删除记录外,Eloquent还可以对模型进行“软删除”。当模型被软删除后,它们并没有真的从数据库删除,而是在模型上设置一个deleted_at属性并插入数据库,如果模型有一个非空deleted_at值,那么该模型已经被软删除了。要启用模型的软删除功能,可以使用模型上的Illuminate\Database\Eloquent\SoftDeletestrait并添加deleted_at列到$dates属性:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model{
    use SoftDeletes;

    /**
     * 应该被调整为日期的属性
     *
     * @var array
     */
    protected $dates = ['deleted_at'];
}

当然,应该添加deleted_at列到数据表。Laravel Schema构建器包含一个帮助函数来创建该列:

Schema::table('flights', function ($table) {
    $table->softDeletes();
});

现在,当调用模型的delete方法时,deleted_at列将被设置为当前日期和时间,并且,当查询一个使用软删除的模型时,被软删除的模型将会自动从查询结果中排除。

判断给定模型实例是否被软删除,可以使用trashed方法:

if ($flight->trashed()) {
    //
}

查询被软删除的模型

包含软删除模型

正如上面提到的,软删除模型将会自动从查询结果中排除,但是,如果你想要软删除模型出现在查询结果中,可以使用withTrashed方法:

$flights = App\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();

withTrashed方法也可以用于关联查询中:

$flight->history()->withTrashed()->get();

只获取软删除模型

onlyTrashed方法之获取软删除模型:

$flights = App\Flight::onlyTrashed()
                ->where('airline_id', 1)
                ->get();

恢复软删除模型

有时候你希望恢复一个被软删除的模型,可以使用restore方法:

$flight->restore();

你还可以在查询中使用restore方法来快速恢复多个模型:

App\Flight::withTrashed()
        ->where('airline_id', 1)
        ->restore();

withTrashed方法一样,restore方法也可以用于关联查询:

$flight->history()->restore();

永久删除模型

有时候你真的需要从数据库中删除一个模型,可以使用forceDelete方法:

// 强制删除单个模型实例...
$flight->forceDelete();
// 强制删除所有关联模型...
$flight->history()->forceDelete();

7、查询作用域

全局作用域

全局作用域允许我们为给定模型的所有查询添加条件约束。Laravel 自带的软删除功能就使用了全局作用域来从数据库中拉出所有没有被删除的模型。编写自定义的全局作用域可以提供一种方便的、简单的方式来确保给定模型的每个查询都有特定的条件约束。

编写全局作用域

自定义全局作用域很简单,首先定义一个实现 Illuminate\Database\Eloquent\Scope 接口的类,该接口要求你实现一个方法:apply。需要的话可以在 apply 方法中添加 where 条件到查询:

<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class AgeScope implements Scope{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        return $builder->where('age', '>', 200);
    }
}

注:Laravel应用默认并没有为作用域预定义文件夹,所以你可以按照自己的喜好在app目录下创建Scopes目录。

应用全局作用域

要将全局作用域分配给模型,需要重写给定模型的 boot 方法并使用 addGlobalScope 方法:

<?php

namespace App;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new AgeScope);
    }
}

添加作用域后,如果使用 User::all() 查询则会生成如下SQL语句:

select * from `users` where `age` > 200

匿名的全局作用域

Eloquent还允许我们使用闭包定义全局作用域,这在实现简单作用域的时候特别有用,这样的话,我们就没必要定义一个单独的类了:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class User extends Model{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('age', function(Builder $builder) {
            $builder->where('age', '>', 200);
        });
    }
}

我们还可以通过以下方式移除全局作用:

User::withoutGlobalScope('age')->get();

移除全局作用域

如果想要在给定查询中移除指定全局作用域,可以使用 withoutGlobalScope

User::withoutGlobalScope(AgeScope::class)->get();

如果你想要移除某几个或全部全局作用域,可以使用 withoutGlobalScopes 方法:

User::withoutGlobalScopes()->get();
User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get();

本地作用域

本地作用域允许我们定义通用的约束集合以便在应用中复用。例如,你可能经常需要获取最受欢迎的用户,要定义这样的一个作用域,只需简单在对应Eloquent模型方法前加上一个scope前缀。

作用域总是返回查询构建器实例:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 只包含活跃用户的查询作用域
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

    /**
     * 只包含激活用户的查询作用域
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

使用本地作用域

作用域被定义好了之后,就可以在查询模型的时候调用作用域方法,但调用时不需要加上scope前缀,你甚至可以在同时调用多个作用域,例如:

$users = App\User::popular()->active()->orderBy('created_at')->get();

动态作用域

有时候你可能想要定义一个可以接收参数的作用域,你只需要将额外的参数添加到你的作用域即可。作用域参数应该被定义在$query参数之后:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 只包含给用类型用户的查询作用域
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOfType($query, $type)
    {
        return $query->where('type', $type);
    }
}

现在,你可以在调用作用域时传递参数了:

$users = App\User::ofType('admin')->get();

8、事件

Eloquent模型可以触发事件,允许你在模型生命周期中的多个时间点调用如下这些方法:creatingcreatedupdatingupdatedsavingsaved,deletingdeletedrestoringrestored。事件允许你在一个指定模型类每次保存或更新的时候执行代码。

基本使用

一个新模型被首次保存的时候,creatingcreated事件会被触发。如果一个模型已经在数据库中存在并调用save方法,updating/updated事件会被触发,无论是创建还是更新,saving/saved事件都会被调用。

举个例子,我们在服务提供者中定义一个Eloquent事件监听器,在事件监听器中,我们会调用给定模型的isValid方法,如果模型无效会返回false。如果从Eloquent事件监听器中返回false则取消save/update操作:

<?php

namespace App\Providers;

use App\User;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider{
    /**
     * 启动所有应用服务
     *
     * @return void
     */
    public function boot()
    {
        User::creating(function ($user) {
            return $user->isValid();
        });
    }

    /**
     * 注册服务提供者.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

观察者

如果你在给定模型中监听多个事件,可以使用观察者来对所有监听器进行分组,观察者类拥有反射你想要监听的Eloquent事件对应的方法名,每个方法接收模型作为唯一参数。Laravel并没有为监听器提供默认目录,所以你可以创建任意目录来存放观察者类:

<?php

namespace App\Observers;

use App\User;

class UserObserver
{
    /**
     * Listen to the User created event.
     *
     * @param  User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }

    /**
     * Listen to the User deleting event.
     *
     * @param  User  $user
     * @return void
     */
    public function deleting(User $user)
    {
        //
    }
}

要监听观察者,使用你想要观察模型的observe方法,你可以在某个服务提供者的boot方法中注册观察者,在本例中,我们在AppServiceProvider中注册观察者:

<?php

namespace App\Providers;

use App\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Firebug 宣布不再维护,讲不出再见!

Firebug 在其官方网站上宣布 —— “Firebug 扩展不再进行开发或维护,我们邀请您使用 Firefox 的内置开发工具以代替”。

Firebug 是 Firefox 下的一款开发类插件,现属于 Firefox 的五星级强力推荐插件之一。它集 HTML 查看和编辑、Javascript 控制台、网络状况监视器于一体,是开发 JavaScript、CSS、HTML 和 Ajax 的得力助手。Firebug 如同一把精巧的瑞士军刀,从各个不同的角度剖析 Web 页面内部的细节层面,给 Web 开发者带来很大的便利。

来自:http://getfirebug.com/

Adding SQLCipher to Xcode Projects IOS MAC

Adding SQLCipher to Xcode Projects

SQLite is already a popular API for persistent data storage in iOS apps so the upside for development is obvious. As a programmer you work with a stable, well-documented API that happens to have many good wrappers available in Objective-C, such as FMDB and Encrypted Core Data. All security concerns are cleanly decoupled from application code and managed by the underlying framework.

The framework code of the SQLCipher project is open source, so users can be confident that an application isn’t using insecure or proprietary security code. In addition, SQLCipher can also be compiled on Android, Linux, OS X and Windows for those developing cross-platform applications.

Using SQLCipher in an iOS app is fairly straightforward. This document describes integrating SQLCipher into an existing iOS project using the Community Edition source code build process. This tutorial assumes some familiarity with basic iOS app development and a working install of Xcode (6.1.1). The same basic steps can be applied to OS X projects as well.

🔥 Hot Tip: Commercial Edition static libraries are available for you to drop right into your project if you’d like to skip all this and receive personalized support from our crack development team! Binaries and helpful projects integrations are available for all supported platforms. Learn more »

Prerequisites

Xcode with an iOS or OS X SDK installed. Visit the Apple Developer site for more information on downloading the latest Xcode and iOS and OS X SDKs.

OpenSSL

OpenSSL is no longer required for building SQLCipher on iOS and OS X, as the project by default uses Apple’s CommonCrypto framework for hardware-accelerated encryption. You can still build SQLCipher with other crypto providers like OpenSSL if you’d prefer, or you can write your own.

SQLCipher

Fire up the Terminal app, switch into your project’s root directory and checkout the SQLCipher project code using Git:

$ cd ~/Documents/code/SQLCipherApp
$ git clone https://github.com/sqlcipher/sqlcipher.git

Xcode Project Configuration

The SQLCipher source provides a sqlcipher.xcodeproj project file that we’ll add to your project to build a static library that you’ll link from your main application target.

Add Project Reference

Open your iOS app’s project or workspace in Xcode, open the Project Navigator (command+1), and click on the top-level Project icon for your iOS app. Right click on the project and choose “Add Files to “My App”” (the label will vary depending on your app’s name). Since we cloned SQLCipher directly into the same folder as your iOS app you should see a sqlcipher folder in your root project folder. Open this folder and select sqlcipher.xcodeproj:

Add Files to 'My App'

Project References

Project Settings

Navigate to your Project settings (make sure you don’t select the application target level). Select the Build Settings pane. In the search field, type in “Header Search Paths”. Double-click on the field under the target column and add the following path: $(PROJECT_DIR)/sqlcipher/src:

Next, add a setting to ensure that SQLCipher is the first library linked with your application in the “Other Linker Flags” setting. Start typing “Other Linker Flags” into the search field until the setting appears, double click to edit it, and add the following value: $(BUILT_PRODUCTS_DIR)/libsqlcipher.a

You will next edit one other setting on your Project to ensure the SQLCipher builds correctly—”Other C Flags.” Start typing “Other C Flags” into the search field until the setting appears, double click to edit it, and in the pop-up add the following value: -DSQLITE_HAS_CODEC

Target Settings

Next, navigate to the Target Level settings. Add a Target dependency to each of your application targets to ensure that SQLCipher is compiled before the application code. In Xcode’s Project Navigator (command+1), select your app’s Project file and in the Editor pane select Build Phases and your app’s main target (not the project file).

Expand Target Dependencies and click on the + button at the end of the list. In the browser that opens, select the sqlcipher static library target:

Add Target Dependency

Expand Link Binary With Libraries, click on the +button at the end of the list, and select the libsqlcipher.a library.

Link Binary With Libraries

Finally, also under Link With Libraries, add Security.framework.

🔥 Hot Tip: If libsqlite3.dylib or another SQLite framework is listed in your Link Binary With Libraries list be sure to remove it!

Repeat these steps for any other targets in your project that will depend on SQLCipher, i.e. unit tests.

Integration Code

Now that the SQLCipher library is incorporated into the project you can start using the library immediately. Telling SQLCipher to encrypt a database is easy:

  • Open the database
  • Use the sqlite3_key function to provide key material. In most cases this should occur as the first operation after opening the database.
  • Run a query to verify the database can be opened (i.e. by querying the schema)
  • As a precautionary measure, run a query to ensure that the application is using SQLCipher on the active connection
#import <sqlite3.h>

...
NSString *databasePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
                          stringByAppendingPathComponent: @"sqlcipher.db"];
sqlite3 *db;
bool sqlcipher_valid = NO;

if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) {
    const char* key = [@"BIGSecret" UTF8String];
    sqlite3_key(db, key, strlen(key));
    if (sqlite3_exec(db, (const char*) "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
      if(sqlite3_prepare_v2(database, "PRAGMA cipher_version;", -1, &stmt, NULL) == SQLITE_OK) {
        if(sqlite3_step(stmt)== SQLITE_ROW) {
          const unsigned char *ver = sqlite3_column_text(stmt, 0);
          if(ver != NULL) {
            sqlcipher_valid = YES;

            // password is correct (or database initialize), and verified to be using sqlcipher

          }
        }
        sqlite3_finalize(stmt);
      }
    }
    sqlite3_close(db);
}

In most cases SQLCipher uses PBKDF2, a salted and iterated key derivation function, to obtain the encryption key. Alternately, an application can tell SQLCipher to use a specific binary key in blob notation (note that SQLCipher requires exactly 256 bits of key material), i.e.

PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";

Once the key is set SQLCipher will automatically encrypt all data in the database! Note that if you don’t set a key then SQLCipher will operate identically to a standard SQLite database.

Testing and Verification

There are a number of ways that you can verify SQLCipher is working as expected in your applications before its release to users.

After the application is wired up to use SQLCipher, take a peek at the resulting data files to make sure everything is in order. An ordinary SQLite database will look something like the following under hexdump. Note that the file type, schema, and data are clearly readable.

% hexdump -C plaintext.db
00000000  53 51 4c 69 74 65 20 66  6f 72 6d 61 74 20 33 00  |SQLite format 3.|
00000010  04 00 01 01 00 40 20 20  00 00 00 04 00 00 00 00  |.....@  ........|
...
000003b0  00 00 00 00 24 02 06 17  11 11 01 35 74 61 62 6c  |....$......5tabl|
000003c0  65 74 32 74 32 03 43 52  45 41 54 45 20 54 41 42  |et2t2.CREATE TAB|
000003d0  4c 45 20 74 32 28 61 2c  62 29 24 01 06 17 11 11  |LE t2(a,b)$.....|
000003e0  01 35 74 61 62 6c 65 74  31 74 31 02 43 52 45 41  |.5tablet1t1.CREA|
000003f0  54 45 20 54 41 42 4c 45  20 74 31 28 61 2c 62 29  |TE TABLE t1(a,b)|
...
000007d0  00 00 00 14 02 03 01 2d  02 74 77 6f 20 66 6f 72  |.......-.two for|
000007e0  20 74 68 65 20 73 68 6f  77 15 01 03 01 2f 01 6f  | the show..../.o|
000007f0  6e 65 20 66 6f 72 20 74  68 65 20 6d 6f 6e 65 79  |ne for the money|

Fire up the SQLCipher application in simulator and look for the application database files under /Users/sjlombardo/Library/Application Support/iPhone Simulator/5.0/Applications/<Instance ID>/Documents. Try running hexdump on the application database. With SQLCipher the output should looks completely random, with no discerning characteristics at all.

% hexdump -C sqlcipher.db
00000000  1b 31 3c e3 aa 71 ae 39  6d 06 f6 21 63 85 a6 ae  |.1<..q.9m..!c...|
00000010  ca 70 91 3e f5 a5 03 e5  b3 32 67 2e 82 18 97 5a  |.p.>.....2g....Z|
00000020  34 d8 65 95 eb 17 10 47  a7 5e 23 20 21 21 d4 d1  |4.e....G.^# !!..|
...
000007d0  af e8 21 ea 0d 4f 44 fe  15 b7 c2 94 7b ee ca 0b  |..!..OD.....{...|
000007e0  29 8b 72 93 1d 21 e9 91  d4 3c 99 fc aa 64 d2 55  |).r..!...<...d.U|
000007f0  d5 e9 3f 91 18 a9 c5 4b  25 cb 84 86 82 0a 08 7f  |..?....K%.......|
00000800

Other sensible testing steps include:

  • Attempt to open a database with a correct key and verify that the operation succeeds
  • Attempt to open a database with an incorrect key and verify that the operation fails
  • Attempt to open a database without any key, and verify the operation fails
  • Programtically inspect the first 16 bytes of the database file and ensure that it contains random data (i.e. not the string SQLite Format 3\0)

来源:https://www.zetetic.net/sqlcipher/ios-tutorial/

每个程序员都应该收藏的算法复杂度速查表

英文:http://bigocheatsheet.com/
编译:Linux中国
链接:https://linux.cn/article-7480-1.html

这篇文章覆盖了计算机科学里面常见算法的时间和空间的大 OBig-O 复杂度。我之前在参加面试前,经常需要花费很多时间从互联网上查找各种搜索和排序算法的优劣,以便我在面试时不会被问住。最近这几年,我面试了几家硅谷的初创企业和一些更大一些的公司,如 Yahoo、eBay、LinkedIn 和 Google,每次我都需要准备这个,我就在问自己,“为什么没有人创建一个漂亮的大 O 速查表呢?”所以,为了节省大家的时间,我就创建了这个,希望你喜欢!

— Eric[1]

图例

数据结构操作

数组排序算法

图操作

堆操作

大 O 复杂度图表

Big O 复杂度

推荐阅读

  • Cracking the Coding Interview: 150 Programming Questions and Solutions[33]
  • Introduction to Algorithms, 3rd Edition[34]
  • Data Structures and Algorithms in Java (2nd Edition)[35]
  • High Performance Java (Build Faster Web Application Interfaces)[36]

关注「算法爱好者」

Web的十大可疑顶级域名,你知道么?

就像所有城市一样,互联网也有一些频繁发生可疑活动的地区,比如垃圾邮件、网络诈骗、有潜在威胁的软件、恶意软件、僵尸网络、网络钓鱼等。

企业安全公司Blue Coat System定期分析来自1万5千家企业和7500万用户的Web请求,跟踪互联网上的可疑活动。该公司在上个月发布了与恶意网站有所联系的十大顶级域名。

Web的十大可疑顶级域名,你知道么?
主流的顶级域名以前有在过去的几年中数量激增,从.com、.net和.org扩展出了更多种类。新兴的顶级域通常会吸引大量威胁源,因为使用它们进行注册的成本比起著名的顶级域名要低得多。

Blue Coat建议组织采取措施进行防护,比如屏蔽高风险顶级域名,或者在用户连接到托管在这些顶级域名上的网站时发出警告。Blue Coat还建议用户在不确定目标链接的具体地址时将光标移到超链接对象上,查看目标的具体地址。如果使用移动设备,可以通过点击并长按执行相同的操作。以下是十大最可疑的顶级域名:

1 .zip

这份名单的内容变化很快。.zip域名在Blue Coat于九月份发布报告时还高居榜首,但其排位之后大幅下滑。Blue Coat公司恶意软件研究小组负责人克里斯·拉尔森指出,让.zip高居榜首的原因在于它其实仅有一个活跃域nic.zip,ta是Google的预注册页面,会将用户中继到google.com下属的一个页面,其中介绍了他们新的顶级域名。

拉尔森说:“来自.zip的URL的确出现在了我们的流量日志中,根据公司的WebPulse系统记录,每天我们的客户都会发出10亿匿名访问Web的请求。如果你仔细研究,记录中的大多数都是文件名,而不是URL,但它们最终肯定是以某种方式作为URL出现在了某人的浏览器上,并且被判定成了可疑链接。”

大多数请求都是看上去很搞笑的URL,它们并不能解析,因此被标记为可疑。但拉尔森补充称很多客户雇佣的安全公司都发现.zip域名和Cryptowall、MiniDionis和CozyBear等恶意软件家族间存在联系。

2 .review

尽管.zip从第一的位置上跌落,顶级域名.review仍稳坐全网第二大可疑域名。拉尔森解释称这主要是由于它托管的诈骗网站。

“只要看一看域列表,你就会发现前15个都是诈骗网站,其中至少12个都与中国某保健品诈骗网站同属一个家族。.review可能并没有对驱逐坏人们作出任何努力。”

3 .country

顶级域名.country最近已经在Blue Coat公司的排名中获得了第一,但在报告9月份发布时它还位居第三。

“.country并不像是.click、.link和.rock这些顶级域名,为了弄清它究竟托管了多少恶意网站,我开始时查看了公司的日志。我发现所有近期注册的.country域名都是可疑的。因此如果你想在Web网关上完全屏蔽该域名,我不会怪你。如果有心情的话,你还可以屏蔽.click域名,尽管它并没有像.country这么糟糕。”

该顶级域名似乎已经完全成为了以有奖游戏/调查为名进行钓鱼的诈骗网站殖民地。拉尔森提示,Blue Coat没有直接发现任何与此网络相关的恶意软件,但有些它的配套广告网络与可疑软件存在密切联系。

4 .kim

.kim顶级域名在Blue Coat报告中排位第四。但拉尔森提示称.kim和.xyz(并不属于排名前十)的域名注册商都已经联系了Blue Coat公司,以消除他们顶级域名下的一些可疑活动。

“我们在最近的流量中发现了改变。他们做得更好了,这理应得到称赞。”

该顶级域名确实托管了一些合法的域,最著名的是韩国的某科技博客和土耳其的几家网站(Kim在土耳其语里是“谁”的意思)。但该域名与可疑软件和诈骗网站间存在联系,而且至少有一个域上托管了域名生成算法,该算法能够生成可被恶意软件利用的域名。因此,.kim理应榜上有名。

5 .cricket

.cricket取名自世界上第二大流行的运动:板球。该顶级域名被列为全网第五大可疑顶级域名。

拉尔森指出,尽管它也托管了一些合法网站,但其中存在大量搜索引擎毒化的实例。例如,StarWarsMovie.cricket从其它地方拉来了大量星球大战相关周边的图片,以获取流量,其中有些图片显然就是从其它地方盗取的。如果在页面上点击,将跳转到销售蓝光《星球大战第六部:绝地归来》的网站。

6 .science

第六大可疑顶级域名很大程度上成了其营销策略的牺牲品。为了提升顶级域名的名气,域名注册商曾免费开放.science域的注册。

“他们以低价倾销,基本可以肯定会遇上麻烦。如果花一块钱就能注册一个域名,坏人将蜂拥而至。”

拉尔森说,相比可疑软件和诈骗,.science域和sao’rao的关系最紧密。他指出,可疑活动包括一个大型电子书网站,它的下载页面曾存在可疑软件活动。另一个网站则销售定制的学术论文。

7 .work

顶级域名.work看上去和骚扰及诈骗离得更近,离恶意软件比较远。然而拉尔森的小组找到了一些指向可疑软件分发网络的尝试性链接。拉尔森指出,虽然存在一些合法网站,它仍旧值得屏蔽。举例而言,它托管了一家土耳其色情网站和巴基斯坦的一家视频剪辑网站,这两个网站极其相似。

8 .party

.party位列第八。这里的很多网站乍一看都是合法的。比如排名第一位的FashionOnly.party,页面上展示了女性婚纱礼服和休闲服装。

拉尔森说:“有一些小黄旗,这些图片都有点烂,所有都像是从原格式转换出来的。很多照片的背景中都有其他网站的水印。这是一个没有意义的网站。在评论中也没有任何内容”

这些都是搜索引擎毒化的标志。该顶级域名还托管了一大堆MP3网站,它们有可能是盗版或者恶意软件传播平台。另有一家网站托管了可疑的Tracker。

9 .gq

.gq是赤道几内亚的国家代码。Blue Coat的报告公布以来,.gq已经滑出前10位。但拉尔森指出,它在许多方面能够获得终身成就奖。

“如果翻看数据库中所有与.gq相关的评分,超过7500条的的评价中有99%是可疑的。”

Blue Coat报告中称,大多数对.gq的滥用都属于搜索引擎毒化,一大部分作为Cookie截取器的可疑视频都和恶意软件相关。它还托管了一些自称“震撼视频”的骚扰/诈骗网站,以及少量的其它恶意软件、钓鱼和色情网站。

10 .link

.link是Blue Coat名单的最后一位。该顶级域名充斥着色情内容分发网络和盗版网站,但这都不是Blue Coat标记为可疑的对象。有一家日本网站专门提供关于橄榄球的体育内容,另一家网站则转发美国一些广播电台的新闻内容。但在这些合法域之外还存在很多诈骗网站。

“根据历史来看,这是一个滋生骚扰网站的顶级域。”拉尔森说。

人名与术语

克里斯·拉尔森(Chris Larsen)

顶级域名(Top Level Domain,TLD)

域名生成算法(Domain Generation Algorithm,DGA)

搜索引擎毒化(Search Engine Poisoning)

本文业界资讯相关术语:网络安全论文 网络安全密钥 网络安全工程师 网络安全技术与应用 网络安全概念股 网络安全知识 网络安全宣传周 网络安全知识竞赛 网络安全事件

Json Web Token 详解 [转]

Understanding JWT

JSON Web Tokens (JWT) are a standard way of representing security claims between the add-on and the Atlassian host product. A JWT token is simply a signed JSON object which contains information which enables the receiver to authenticate the sender of the request.

Table of contents

Structure of a JWT token

A JWT token looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzODY4OTkxMzEsImlzcyI6ImppcmE6MTU0ODk1OTUiLCJxc2giOiI4MDYzZmY0Y2ExZTQxZGY3YmM5MGM4YWI2ZDBmNjIwN2Q0OTFjZjZkYWQ3YzY2ZWE3OTdiNDYxNGI3MTkyMmU5IiwiaWF0IjoxMzg2ODk4OTUxfQ.uKqU9dTB6gKwG6jQCuXYAiMNdfNRw98Hw_IWuA5MaMo

Once you understand the format, it’s actually pretty simple:

<base64url-encoded header>.<base64url-encoded claims>.<base64url-encoded signature>

In other words:

  • You create a header object, with the JSON format. Then you encode it in base64url
  • You create a claims object, with the JSON format. Then you encode it in base64url
  • You create a signature for the URI (we’ll get into that later). Then you encode it in base64url
  • You concatenate the three items, with the “.” separator

You shouldn’t actually have to do this manually, as there are libraries available in most languages, as we describe in the JWT libraries section. However it is important you understand the fields in the JSON header and claims objects described in the next sections:

Header

The header object declares the type of the encoded object and the algorithm used for the cryptographic signature. Atlassian Connect always uses the same values for these. The typ property will be “JWT” and the alg property will be “HS256”.

{
“typ”:”JWT”,
“alg”:”HS256″
}
Attribute Type Description
“typ” String Type for the token, defaulted to “JWT”. Specifies that this is a JWT token
“alg” (mandatory) String Algorithm. specifies the algorithm used to sign the token. In atlassian-connect version 1.0 we support the HMAC SHA-256 algorithm, which the JWT specificationidentifies using the string “HS256”.

Important

Your JWT library or implementation should discard any tokens which specify alg: none as this can provide a bypass of the token verification.

Claims

The claims object contains security information about the message you’re transmitting. The attributes of this object provide information to ensure the authenticity of the claim. The information includes the issuer, when the token was issued, when the token will expire, and other contextual information, described below.

{
“iss”: “jira:1314039”,
“iat”: 1300819370,
“exp”: 1300819380,
“qsh”: “8063ff4ca1e41df7bc90c8ab6d0f6207d491cf6dad7c66ea797b4614b71922e9”,
“sub”: “batman”,
“context”: {
“user”: {
“userKey”: “batman”,
“username”: “bwayne”,
“displayName”: “Bruce Wayne”
}
}
}
Attribute Type Description
iss(mandatory) String the issuer of the claim. Connect uses it to identify the application making the call. for example:

  • If the Atlassian product is the calling application: contains the unique identifier of the tenant. This is the clientKey that you receive in theinstalled callback. You should reject unrecognised issuers.
  • If the add-on is the calling application: the add-on key specified in the add-on descriptor
iat(mandatory) Long Issued-at time. Contains the UTC Unix time at which this token was issued. There are no hard requirements around this claim but it does not make sense for it to be significantly in the future. Also, significantly old issued-at times may indicate the replay of suspiciously old tokens.
exp(mandatory) Long Expiration time. It contains the UTC Unix time after which you should no longer accept this token. It should be after the issued-at time.
qsh(mandatory) String query string hash. A custom Atlassian claim that prevents URL tampering.
sub(optional) String The subject of this token. This is the user associated with the relevant action, and may not be present if there is no logged in user.
aud(optional) String or String[] The audience(s) of this token. For REST API calls from an add-on to a product, the audience claim can be used to disambiguate the intended recipients. This attribute is not used for JIRA and Confluence at the moment, but will become mandatory when making REST calls from an add-on to e.g. the bitbucket.org domain.
context(optional) Object The context claim is an extension added by Atlassian Connect which may contain useful context for outbound requests (from the product to your add-on). The current user (the same user in the sub claim) is added to the context. This contains the userKey, username and display name for the subject.

"context": {
    "user": {
        "userKey": "batman",
        "username": "bwayne",
        "displayName": "Bruce Wayne"
    }
}
  • userKey — the primary key of the user. Anytime you want to store a reference to a user in long term storage (eg a database or index) you should use the key because it can never change. The user key should never be displayed to the user as it may be a non human readable value.
  • username — a unique secondary key, but should not be stored in long-term storage because it can change over time. This is the value that the user logs into the application with, and may be displayed to the user.
  • displayName — the user’s name.

You should use a little leeway when processing time-based claims, as clocks may drift apart. The JWT specification suggests no more than a few minutes. Judicious use of the time-based claims allows for replays within a limited window. This can be useful when all or part of a page is refreshed or when it is valid for a user to repeatedly perform identical actions (e.g. clicking the same button).

Signature

The signature of the token is a combination of a hashing algorithm combined with the header and claims sections of the token. This provides a way to verify that the claims and headers haven’t been been compromised during transmission. The signature will also detect if a different secret is used for signing. In the JWT spec, there are multiple algorithms you can use to create the signature, but Atlassian Connect uses the HMAC SHA-256 algorithm. If the JWT token has no specified algorithm, you should discard that token as they’re not able to be signature verified.

JWT libraries

Most modern languages have JWT libraries available. We recommend you use one of these libraries (or other JWT-compatible libraries) before trying to hand-craft the JWT token.

Language Library
Java atlassian-jwt and jsontoken
Python pyjwt
Node.js node-jwt-simple
Ruby ruby-jwt
PHP firebase php-jwt and luciferous jwt
.NET jwt
Haskell haskell-jwt

The JWT decoder is a handy web based decoder for Atlassian Connect JWT tokens.

Creating a JWT token

Here is an example of creating a JWT token, in Java, using atlassian-jwt and nimbus-jwt (last tested with atlassian-jwt version 1.5.3 and nimbus-jwt version 2.16):

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import com.atlassian.jwt.*;
import com.atlassian.jwt.core.writer.*;
import com.atlassian.jwt.httpclient.CanonicalHttpUriRequest;
import com.atlassian.jwt.writer.JwtJsonBuilder;
import com.atlassian.jwt.writer.JwtWriterFactory;public class JWTSample {

public String createUriWithJwt()
throws UnsupportedEncodingException, NoSuchAlgorithmException {
long issuedAt = System.currentTimeMillis() / 1000L;
long expiresAt = issuedAt + 180L;
String key = “atlassian-connect-addon”; //the key from the add-on descriptor
String sharedSecret = “…”;    //the sharedsecret key received
//during the add-on installation handshake
String method = “GET”;
String baseUrl = “https://<my-dev-environment>.atlassian.net/”;
String contextPath = “/”;
String apiPath = “/rest/api/latest/serverInfo”;

JwtJsonBuilder jwtBuilder = new JsonSmartJwtJsonBuilder()
.issuedAt(issuedAt)
.expirationTime(expiresAt)
.issuer(key);

CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(method,
apiPath, contextPath, new HashMap());
JwtClaimsBuilder.appendHttpRequestClaims(jwtBuilder, canonical);

JwtWriterFactory jwtWriterFactory = new NimbusJwtWriterFactory();
String jwtbuilt = jwtBuilder.build();
String jwtToken = jwtWriterFactory.macSigningWriter(SigningAlgorithm.HS256,
sharedSecret).jsonToJwt(jwtbuilt);

String apiUrl = baseUrl + apiPath + “?jwt=” + jwtToken;
return apiUrl;
}
}

Decoding and verifying a JWT token

Here is a minimal example of decoding and verifying a JWT token, in Java, using atlassian-jwt and nimbus-jwt (last tested with atlassian-jwt version 1.5.3 and nimbus-jwt version 2.16).

NOTE: This example does not include any error handling. See AbstractJwtAuthenticator from atlassian-jwt for recommendations of how to handle the different error cases.

import com.atlassian.jwt.*;
import com.atlassian.jwt.core.http.JavaxJwtRequestExtractor;
import com.atlassian.jwt.core.reader.*;
import com.atlassian.jwt.exception.*;
import com.atlassian.jwt.reader.*;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

public class JWTVerificationSample {

public Jwt verifyRequest(HttpServletRequest request,
JwtIssuerValidator issuerValidator,
JwtIssuerSharedSecretService issuerSharedSecretService)
throws UnsupportedEncodingException, NoSuchAlgorithmException,
JwtVerificationException, JwtIssuerLacksSharedSecretException,
JwtUnknownIssuerException, JwtParseException {
JwtReaderFactory jwtReaderFactory = new NimbusJwtReaderFactory(
issuerValidator, issuerSharedSecretService);
JavaxJwtRequestExtractor jwtRequestExtractor = new JavaxJwtRequestExtractor();
CanonicalHttpRequest canonicalHttpRequest
= jwtRequestExtractor.getCanonicalHttpRequest(request);
Map requiredClaims = JwtClaimVerifiersBuilder.build(canonicalHttpRequest);
String jwt = jwtRequestExtractor.extractJwt(request);
return jwtReaderFactory.getReader(jwt).readAndVerify(jwt, requiredClaims);
}
}

Decoding a JWT token

Decoding the JWT token reverses the steps followed during the creation of the token, to extract the header, claims and signature. Here is an example in Java:

String jwtToken = …;//e.g. extracted from the request
String[] base64UrlEncodedSegments = jwtToken.split(‘.’);
String base64UrlEncodedHeader = base64UrlEncodedSegments[0];
String base64UrlEncodedClaims = base64UrlEncodedSegments[1];
String signature = base64UrlEncodedSegments[2];
String header = base64Urldecode(base64UrlEncodedHeader);
String claims = base64Urldecode(base64UrlEncodedClaims);

This gives us the following:

Header:

{
“alg”: “HS256”,
“typ”: “JWT”
}

Claims:

 {
“iss”: “jira:15489595”,
“iat”: 1386898951,
“qsh”: “8063ff4ca1e41df7bc90c8ab6d0f6207d491cf6dad7c66ea797b4614b71922e9”,
“exp”:
}

Signature:

uKqU9dTB6gKwG6jQCuXYAiMNdfNRw98Hw_IWuA5MaMo

Verifying a JWT token

JWT libraries typically provide methods to be able to verify a received JWT token. Here is an example using nimbus-jose-jwt and json-smart:

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import net.minidev.json.JSONObject;public JWTClaimsSet read(String jwt, JWSVerifier verifier) throws ParseException, JOSEException
{
JWSObject jwsObject = JWSObject.parse(jwt);

if (!jwsObject.verify(verifier))
{
throw new IllegalArgumentException(“Fraudulent JWT token: ” + jwt);
}

JSONObject jsonPayload = jwsObject.getPayload().toJSONObject();
return JWTClaimsSet.parse(jsonPayload);
}

Creating a query string hash

A query string hash is a signed canonical request for the URI of the API you want to call.

1
qsh = `sign(canonical-request)`
2
canonical-request = `canonical-method + '&' + canonical-URI + '&' + canonical-query-string`

A canonical request is a normalised representation of the URI. Here is an example. For the following URL, assuming you want to do a “GET” operation:

"https://<my-dev-environment>.atlassian.net/path/to/service?zee_last=param&repeated=parameter 1&first=param&repeated=parameter 2"

The canonical request is

"GET&/path/to/service&first=param&repeated=parameter%201,parameter%202&zee_last=param"

To create a query string hash, follow the detailed instructions below:

  1. Compute canonical method
    • Simply the upper-case of the method name (e.g. "GET" or "PUT")
  2. Append the character '&'
  3. Compute canonical URI
    • Discard the protocol, server, port, context path and query parameters from the full URL.
      • For requests targeting add-ons discard the baseUrl in the add-on descriptor.
    • Removing the context path allows a reverse proxy to redirect incoming requests for"jira.example.com/getsomething" to "example.com/jira/getsomething" without breaking authentication. The requester cannot know that the reverse proxy will prepend the context path"/jira" to the originally requested path "/getsomething"
    • Empty-string is not permitted; use "/" instead.
    • Url-encode any '&' characters in the path.
    • Do not suffix with a '/' character unless it is the only character. e.g.
      • Canonical URI of "https://example.atlassian.net/wiki/some/path/?param=value" is"/some/path"
      • Canonical URI of "https://example.atlassian.net" is "/"
  4. Append the character '&'
  5. Compute canonical query string
    • The query string will use percent-encoding.
    • Sort the query parameters primarily by their percent-encoded names and secondarily by their percent-encoded values.
    • Sorting is by codepoint: sort(["a", "A", "b", "B"]) => ["A", "B", "a", "b"]
    • For each parameter append its percent-encoded name, the '=' character and then its percent-encoded value.
    • In the case of repeated parameters append the ',' character and subsequent percent-encoded values.
    • Ignore the jwt parameter, if present.
    • Some particular values to be aware of:
      • A whitespace character is encoded as "%20",
      • "+" as "%2B",
      • "*" as "%2A" and
      • "~" as "~".
        (These values used for consistency with OAuth1.)
  6. Convert the canonical request string to bytes
    • The encoding used to represent characters as bytes is UTF-8
  7. Hash the canonical request bytes using the SHA-256 algorithm
    • e.g. The SHA-256 hash of "foo" is `”2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae

Advanced: Creating a JWT token manually

Disclaimer

You should only need to read this section if you are planning to create JWT tokens manually, i.e. if you are not using one of the libraries listed in the previous section

More details on JWT tokens

The format of a JWT token is simple: <base64url-encoded header>.<base64url-encoded claims>.<signature>.

  • Each section is separated from the others by a period character (.).
  • Each section is base64url encoded, so you will need to decode each one to make them human-readable. Note that encoding with base64 and not base64url will result in an incorrect JWT token for payloads with non UTF-8 characters.
  • The header specifies a very small amount of information that the receiver needs in order to parse and verify the JWT token.
    • All JWT token headers state that the type is “JWT”.
    • The algorithm used to sign the JWT token is needed so that the receiver can verify the signature.
  • The claims are a list of assertions that the issuer is making: each says that “this named field” has “this value”.
    • Some, like the “iss” claim, which identifies the issuer of this JWT token, have standard names and uses.
    • Others are custom claims. We limit our use of custom claims as much as possible, for ease of implementation.
  • The signature is computed by using an algorithm such as HMAC SHA-256 plus the header and claims sections.
    • The receiver verifies that the signature must have been computed using the genuine JWT header and claims sections, the indicated algorithm and a previously established secret.
    • An attacker tampering with the header or claims will cause signature verification to fail.
    • An attacker signing with a different secret will cause signature verification to fail.
    • There are various algorithm choices legal in the JWT spec. In atlassian-connect version 1.0 we support HMAC SHA-256. Important: your implementation should discard any JWT tokens which specify alg: none as these are not subject to signature verification.

Steps to Follow

  1. Create a header JSON object
  2. Convert the header JSON object to a UTF-8 encoded string and base64url encode it. That gives you encodedHeader.
  3. Create a claims JSON object, including a query string hash
  4. Convert the claims JSON object to a UTF-8 encoded string and base64url encode it. That gives you encodedClaims.
  5. Concatenate the encoded header, a period character (.) and the encoded claims set. That gives you signingInput = encodedHeader+ “.” + encodedClaims.
  6. Compute the signature of signingInput using the JWT or cryptographic library of your choice. Then base64url encode it. That gives you encodedSignature.
  7. concatenate the signing input, another period character and the signature, which gives you the JWT token. jwtToken = signingInput + “.” + encodedSignature

Example

Here is an example in Java using gson, commons-codec, and the Java security and crypto libraries:

public class JwtClaims {
protected String iss;
protected long iat;
protected long exp;
protected String qsh;
protected String sub;
// + getters/setters/constructors
}
[…]
public class JwtHeader {
protected String alg;
protected String typ;
// + getters/setters/constructors
}
[…]
import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString;
import static org.apache.commons.codec.binary.Hex.encodeHexString;
import java.io.UnsupportedEncodingException;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import com.google.gson.Gson;
public class JwtBuilder {
public static String generateJWTToken(String requestUrl, String canonicalUrl,
String key, String sharedSecret)
throws NoSuchAlgorithmException, UnsupportedEncodingException,
InvalidKeyException {
JwtClaims claims = new JwtClaims();
claims.setIss(key);
claims.setIat(System.currentTimeMillis() / 1000L);
claims.setExp(claims.getIat() + 180L);
claims.setQsh(getQueryStringHash(canonicalUrl));
String jwtToken = sign(claims, sharedSecret);
return jwtToken;
}
private static String sign(JwtClaims claims, String sharedSecret)
throws InvalidKeyException, NoSuchAlgorithmException {
String signingInput = getSigningInput(claims, sharedSecret);
String signed256 = signHmac256(signingInput, sharedSecret);
return signingInput + “.” + signed256;
}
private static String getSigningInput(JwtClaims claims, String sharedSecret)
throws InvalidKeyException, NoSuchAlgorithmException {
JwtHeader header = new JwtHeader();
header.alg = “HS256”;
header.typ = “JWT”;
Gson gson = new Gson();
String headerJsonString = gson.toJson(header);
String claimsJsonString = gson.toJson(claims);
String signingInput = encodeBase64URLSafeString(headerJsonString
.getBytes())
+ “.”
+ encodeBase64URLSafeString(claimsJsonString.getBytes());
return signingInput;
}
private static String signHmac256(String signingInput, String sharedSecret)
throws NoSuchAlgorithmException, InvalidKeyException {
SecretKey key = new SecretKeySpec(sharedSecret.getBytes(), “HmacSHA256”);
Mac mac = Mac.getInstance(“HmacSHA256”);
mac.init(key);
return encodeBase64URLSafeString(mac.doFinal(signingInput.getBytes()));
}
private static String getQueryStringHash(String canonicalUrl)
throws NoSuchAlgorithmException,UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance(“SHA-256”);
md.update(canonicalUrl.getBytes(“UTF-8”));
byte[] digest = md.digest();
return encodeHexString(digest);
}
}
[…]
public class Sample {
public String getUrlSample() throws Exception {
String requestUrl =
“https://<my-dev-environment>.atlassian.net/rest/atlassian-connect/latest/license”;
String canonicalUrl = “GET&/rest/atlassian-connect/latest/license&”;
String key = “…”;     //from the add-on descriptor
//and received during installation handshake
String sharedSecret = “…”; //received during installation Handshake
String jwtToken = JwtBuilder.generateJWTToken(
requestUrl, canonicalUrl, key, sharedSecret);
String restAPIUrl = requestUrl + “?jwt=” + jwtToken;
return restAPIUrl;
}
}

Stateless Authentication implementation using JWT, Nginx+Lua and Memcached

If you already have an idea on stateless authentication and JWT then proceed with this implementation blog otherwise just go through the previous blog Stateless Authentication to get an idea.

As i mentioned in my previous blog JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA.

Client can access the the resources from different applications. So to validate the token at applications, we require the secret or a public/private key.

Problems of validating the token in every application

  1. We have to maintain the secret key in all the applications and have to write or inject the token validation logic in every application. The validation logic may include more than token validation like fingerprint mismatch, session idle time out and many more based on the requirement.
  2. If the applications are developed in different languages then we have to implement the token validation logic based on application technology stack and maintenance is very difficult.

Solution

Instead of maintaining the validation logic in every application, we can write our validation logic at one common place so that every request can make use of that logic irrespective of application (Note: Here Applications could be developed in any language). I have chosen reverse proxy server (Nginx) to maintain the validation logic with the help of Lua.

Advantages

  1. We don’t need to maintain the secret or private/public key in every application. Just maintain at authentication server side to generate a token and at proxy server (Nginx) to validate the token.
  2. Maintenance of the validation logic easy.

Before jumping in to the flow and implementation let’s see why we have chosen this technology stack.

Why JWT ? 

To achieve the stateless authentication we have chosen JWT (JSON Web Token). We can easily, securely transmitting information between parties as a JSON object. If we want to put some sensitive information in JWT token, we can encrypt the JWT payload itself using the JSON Web Encryption (JWE) specification.

Why Nginx + Lua ?

Nginx+Lua is a self-contained web server embedding the scripting language Lua. Powerful applications can be written directly inside Nginx without using cgi, fastcgi, or uwsgi. By adding a little Lua code to an existing Nginx configuration file, it is easy to add small features.

One of the core benefits of Nginx+Lua is that it is fully asynchronous. Nginx+Lua inherits the same event loop model that has made Nginx a popular choice of webserver. “Asynchronous” simply means that Nginx can interrupt your code when it is waiting on a blocking operation, such as an outgoing connection or reading a file, and run the code of another incoming HTTP Request.

Why Memcached ?

To keep the application more secured, along with the token validation we are doing the fingerprint check and handling idle time out as well. Means, if the user is idle for some time and not doing any action then user has to be logged out from the application. To do the fingerprint check and idle time out check, some information needs to be shared across the applications. To share the information across the applications we have chosen Memcached (Distributed Cache).

Note: If you don’t want to do fingerprint mismatch check and idle time out check, then you can simply ignore the Memcached component from the flow.

Flow

 

Untitled presentation (2)

 

Step 1

Client try to access the resource from the application with out JWT token or invalid token. As shown in the flow, request goes to the proxy server (Nginx).

Step 2

Nginx looks for the auth header (X-AUTH-TOKEN) and validates the token with the help of Lua.

 

Step 3

As token is not present or invalid, nginx sends below response to the client.

 

Step 4

Now user has to login in to the system, So client will load the login page.

Step 5

Client will send a request to the authenticate server to authenticate the user. Along with username and password client sends the fingerprint also. Here we are considering fingerprint to make sure that all the requests are initiating from the same device where user logged in to the system.

Sample authenticate request body

 

Step 6

Authenticate server validates the credentials and create a JWT token with TokenId (random generated UUID) as a claim and this tokenId is useful to uniquely identify the user. And set the JWT token in response header (X-AUTH-TOKEN).

Create JWT Token

Add this dependency to your pom.xml to work on JWT

While creating the token you can set any number of claims.

CustomClaim.java

Generated JWT token looks like below

And the JWT token payload looks like below. You can put what ever data you want like roles & permissions associated to him and so on…

 

Step 7

Put TokenId as a key and user meta information like fingerprint, last access time etc… as a value in memcached which is useful to verify the fingerprint and session idle time out at nginx side using Lua.

Sample Memcached content

 

Put Content in Memcached

Add this dependency to your pom.xml to work on Memcached

 

 

Step 8

Send back response to the client from authentication server with response header X-AUTH-TOKEN

 

Step 9

Fetch the token from response header and store it in local storage at client side. So that we can send this token in request header from next request onwards.

Step 10

Now client access the resource from application with valid JWT token. As shown in the flow request goes to the proxy server (Nginx). With every request client will send a fingerprint in some header and consider header name as “FINGER-PRINT”.

Step 11

Nginx validates the token. As token is valid, extract the TokenId from the JWT token to fetch the user meta information from memcached.

If there is no entry in the memcached with “TokenId” then Nginx simply senda a response as “LOGGED_OUT” to the client.

But in our case user is logged in into the system, So there will be an entry in memcached with TokenId. So fetch that user meta information to do the following checks.

Fingerprint mismatch : While sending the authenticate request, client is sending fingerprint along with username and password. We are storing that fingerprint value in memcached and we use this value to compare with the fingerprint which is coming in every request. If fingerprint matches, then it’s proceed further. Otherwise nginx will send a response to client saying that fingerprint is mismatched.

Session idle time out :  While successful authentication of a user at authentication server side, we are putting configured session_idle_timeout of a user in memcached. If it’s configured as “-1”, then we simply skip the session idle time out check. Otherwise for every request just we check whether session is idle or not. If session is not idle, we update the last_access_time value to current system time in memcached. If session is idle then Nginx send below response to the client.

Complete Validation Logic at Nginx using Lua

base-validation.lua

Step 12

Once the request gone through the above mentioned validation logic, Nginx proxy_pass the request to the application.

sample-nginx.conf

Step 13

Application sends a response of requested resource to the client.

How to achieve logout ?

There is a open question (unanswered) regarding how to achieve the log out at server side, if we go by the stateless authentication using JWT.

Mostly people are discussing about handling the log out at client side.

  • When user clicks on logout, simply client can remove the token from local storage.

But i come up with a solution to achieve the logout at server side by make use of Memcached.

  • When user clicks on logout, Remove the entry from Memcached which  we put it in Step 7. And client also can delete the token from local storage as well. If you see the validation logic which i have completely covered in Step 11, there i’m checking the entry in memcached. If there is no entry in memcached, means user logged out from the application.

如何在Git中撤销一切

翻译:李伟
审校:张帆
译自:Github

blob.png

任何一个版本控制系统中,最有用的特性之一莫过于 “撤销(undo)”操作。在Git中,“撤销”有很多种含义。

当你完成了一次新的提交(commit),Git会及时存储当前时刻仓库(repository)的快照(snapshot);你能够使用Git将项目回退到任何之前的版本。

下文中,我将列举几个常见的、需要“撤销”的场景,并且展示如何使用Git来完成这些操作。

一、撤销一个公共修改 Undo a “public” change

场景:你刚刚用git push将本地修改推送到了GitHub,这时你意识到在提交中有一个错误。你想撤销这次提交。

使用撤销命令:git revert

发生了什么:git revert将根据给定SHA的相反值,创建一个新的提交。如果旧提交是“matter”,那么新的提交就是“anti-matter”——旧提交中所有已移除的东西将会被添加进到新提交中,旧提交中增加的东西将在新提交中移除。

这是Git最安全、也是最简单的“撤销”场景,因为这样不会修改历史记录——你现在可以git push下刚刚revert之后的提交来纠正错误了。

二、修改最近一次的提交信息 Fix the last commit message

场景:你只是在最后的提交信息中敲错了字,比如你敲了git commit -m “Fxies bug #42″,而在执行git push之前你已经意识到你应该敲”Fixes bug #42″。

使用撤销命令:git commit –amend或git commit –amend -m “Fixes bug #42”

发生了什么:git commit –amend将使用一个包含了刚刚错误提交所有变更的新提交,来更新并替换这个错误提交。由于没有staged的提交,所以实际上这个提交只是重写了先前的提交信息。

三、撤销本地更改 Undo “local” changes

场景:当你的猫爬过键盘时,你正在编辑的文件恰好被保存了,你的编辑器也恰在此时崩溃了。此时你并没有提交过代码。你期望撤销这个文件中的所有修改——将这个文件回退到上次提交的状态。

使用撤销命令:git checkout —

发生了什么:git checkout将工作目录(working directory)里的文件修改成先前Git已知的状态。你可以提供一个期待回退分支的名字或者一个确切的SHA码,Git也会默认检出HEAD——即:当前分支的上一次提交。

注意:用这种方法“撤销”的修改都将真正的消失。它们永远不会被提交。因此Git不能恢复它们。此时,一定要明确自己在做什么!(或许可以用git diff来确定)

四、重置本地修改 Reset “local” changes

场景:你已经在本地做了一些提交(还没push),但所有的东西都糟糕透了,你想撤销最近的三次提交——就像它们从没发生过一样。

使用撤销命令:git reset或git reset –hard

发生了什么:git reset将你的仓库纪录一直回退到指定的最后一个SHA代表的提交,那些提交就像从未发生过一样。默认情况下,git reset会保留工作目录(working directory)。这些提交虽然消失了,但是内容还在磁盘上。这是最安全的做法,但通常情况是:你想使用一个命令来“撤销”所有提交和本地修改——那 么请使用–hard参数吧。

五、撤销本地后重做 Redo after undo “local”

场景:你已经提交了一些内容,并使用git reset –hard撤销了这些更改(见上面),突然意识到:你想还原这些修改!

使用撤销命令:git reflog和git reset, 或者git checkout

发生了什么:git reflog是一个用来恢复项目历史记录的好办法。你可以通过git reflog恢复几乎任何已提交的内容。

你或许对git log命令比较熟悉,它能显示提交列表。git reflog与之类似,只不过git reflog显示的是HEAD变更次数的列表。

一些说明:

1. 只有HEAD会改变。当你切换分支时,用git commit提交变更时,或是用git reset撤销提交时,HEAD都会改变。但当你用git checkout –时, HEAD不会发生改变。(就像上文提到的情形,那些更改根本就没有提交,因此reflog就不能帮助我们进行恢复了)

2.  git reflog不会永远存在。Git将会定期清理那些“不可达(unreachable)”的对象。不要期望能够在reflog里找到数月前的提交记录。

3.  reflog只是你个人的。你不能用你的reflog来恢复其他开发者未push的提交。

blob.png

因此,怎样合理使用reflog来找回之前“未完成”的提交呢?这要看你究竟要做什么:

1. 如果你想恢复项目历史到某次提交,那请使用git reset –hard

2. 如果你想在工作目录(working direcotry)中恢复某次提交中的一个或多个文件,并且不改变提交历史,那请使用git checkout–

3. 如果你想确切的回滚到某次提交,那么请使用git cherry-pick。

六、与分支有关的那些事 Once more, with branching

场景:你提交了一些变更,然后你意识到你正在master分支上,但你期望的是在feature分支上执行这些提交。

使用撤销命令:git branch feature, git reset –hard origin/master, 和 git checkout feature

发生了什么:你可能用的是git checkout -b来建立新的分支,这是创建和检出分支的便捷方法——但实际你并不想立刻切换分支。git branch feature会建立一个叫feature的分支,这个分支指向你最近的提交,但是你还停留在master分支上。

git reset –hard将master回退至origin/master,并忽略所有新提交。别担心,那些提交都还保留在feature上。

最后,git checkout将分支切换到feature,这个分支原封不动的保留了你最近的所有工作。

七、事半功倍处理分支 Branch in time saves nine

场景:你基于master新建了一个feature分支,但是master分支远远落后与origin/master。现在master分支与origin/master同步了,你期望此刻能在feature下立刻commit代码,并且不是在远远落后master的情况下。

使用撤销命令:git checkout feature和git rebase master

发生了什么:你也许已经敲了命令:git reset(但是没用–hard,有意在磁盘上保存这些提交内容),然后敲了git checkout -b,之后重新提交更改,但是那样的话,你将失去本地的提交记录。不过,一个更好的方法:

使用git rebase master可以做到一些事情:

1.首先,它定位你当前检出分支和master之间的共同祖先节点(common ancestor)。

2.然后,它将当前检出的分支重置到祖先节点(ancestor),并将后来所有的提交都暂存起来。

3.最后,它将当前检出分支推进至master末尾,同时在master最后一次提交之后,再次提交那些在暂存区的变更。

八、批量撤销/找回 Mass undo/redo

场景:你开始朝一个既定目标开发功能,但是中途你感觉用另一个方法更好。你已经有十几个提交,但是你只想要其中的某几个,其他的都可以删除不要。

使用撤销命令:git rebase -i

发生了什么:-i将rebases设置为“交互模式(interactive mode)”。rebase开始执行的操作就像上文讨论的一样,但是在重新执行某个提交时,它会暂停下来,让你修改每一次提交。

rebase –i将会打开你的默认文本编辑器,然后列出正在执行的提交,就像这样:

blob.png

前两列最关键:第一列是选择命令,它会根据第二列中的SHA码选择相应的提交。默认情况下,rebase –i会认为每个更改都正通过pick命令被提交。

要撤销一个提交,直接在编辑器删除对应的行就可以了。如果在你的项目不再需要这些错误的提交,你可以直接删除上图中的第1行和3-4行。

如 果你想保留提交但修改提交信息,你可以使用reword命令。即,将命令关键字pick换成reword(或者r)。你现在可能想立刻修改提交消息,但这 么做不会生效——rebase –i将忽略SHA列后的所有东西。现有的提交信息会帮助我们记住0835fe2代表什么。当你敲完rebase –i命令后,Git才开始提示你重写那些新提交消息。

如果你需要将2个提交合并,你可以用squash或者fixup命令,如下图:

blob.png

squash和fixup都是“向上”结合的——那些用了这些合并命令(编者按:指squash、fixup)的提交,将会和它之前的提交合并:上图中,0835fe2和6943e85将会合并成一个提交,而38f5e4e和af67f82将会合并成另一个提交。

当 你用squash时,Git将会提示是否填写新的提交消息;fixup则会给出列表中第一个提交的提交信息。在上图中,af67f82是一个 “Ooops”信息,因为这个提交信息已经同38f5e4e一样了。但是你可以为0835fe2和6943e85合并的新提交编写提交信息。

当你保存并退出编辑器时,Git将会按照从上到下的顺序执行你的提交。你可以在保存这些提交之前,修改提交的执行顺序。如果有需要,你可以将af67f82和0835fe2合并,并且可以这样排序:

blob.png

九、修复早先的提交 Fix an earlier commit

场景:之前的提交里落下了一个文件,如果先前的提交能有你留下的东西就好了。你还没有push,并且这个提交也不是最近的提交,因此你不能用commit –amend。

使用撤销命令:git commit –squash和git rebase –autosquash -i

发生了什么:git commit –squash将会创建一个新的提交,该提交信息可能像这样“squash! Earlier commit”。(你也可以手写这些提交信息,commit –squash只是省得让你打字了)。

如果你不想为合并的提交编写信息,也可以考虑使用命令git commit –fixup。这种情况下,你可能会使用commit –fixup,因为你仅希望在rebase中使用之前的提交信息。

rebase –autosquash –i将会启动rebase交互编辑器,编辑器会列出任何已完成的squash!和fixup!提交,如下图:

blob.png

当 使用–squash和–fixup时,你或许记不清你想修复的某个提交的SHA码——只知道它可能在一个或五个提交之前。你或许可以使用Git的^和~ 操作符手动找回。HEAD^表示HEAD的前一次提交。HEAD~4表示HEAD前的4次提交,加起来总共是前5次提交。

十、停止跟踪一个已被跟踪的文件 Stop tracking a tracked file

场景:你意外将application.log添加到仓库中,现在你每次运行程序,Git都提示application.log中有unstaged的提交。你在.gitignore中写上”*.log”,但仍旧没用——怎样告诉Git“撤销”跟踪这个文件的变化呢?

使用撤销命令: git rm –cached application.log

发生了什么:尽 管.gitignore阻止Git跟踪文件的变化,甚至是之前没被跟踪的文件是否存在,但是,一旦文件被add或者commit,Git会开始持续跟踪这 个文件的变化。类似的,如果你用git add –f来“强制”add,或者覆盖.gitignore,Git还是会继续监视变化。所以以后最好不要使用–f来add .gitignore文件。

如果你希望移除那些应当被忽略的文件,git rm –cached可以帮助你,并将这些文件保留在磁盘上。因为这个文件现在被忽略了,你将不会在git status中看到它,也不会再把这个文件commit了。

以上就是如何在Git上撤销的方法。如果你想学习更多Git命令用法,可以移步下面相关的文档:

原文地址:Github

译文地址:http://www.jointforce.com/jfperiodical/article/show/796?m=d03

常用Web Service汇总(天气预报、时刻表等)

现成的Web Service中有很多很好用的,比如天气预报,IP地址搜索,火车时刻表等等。本文汇总的一些常用Web Service,希望对大家有所帮助。

下面总结了一些常用的Web Service,是平时乱逛时收集的,希望对大家有用。

============================================

天气预报Web Service,数据来源于中国气象局

Endpoint

Disco

WSDL

IP地址来源搜索Web Service(是目前最完整的IP地址数据)

Endpoint

Disco

WSDL

随机英文、数字和中文简体字Web Service

Endpoint

Disco

WSDL

中国邮政编码 <-> 地址信息双向查询/搜索Web Service

Endpoint

Disco

WSDL

验证码图片Web Service 支持中文、字母、数字 图像和多媒体

Endpoint

Disco

WSDL

Email 电子邮件地址验证Web Service

Endpoint

Disco

WSDL

中文简体字 <->繁体字转换Web Service

Endpoint

Disco

WSDL

中文 <-> 英文双向翻译Web Service

Endpoint

Disco

WSDL

火车时刻表Web Service (第六次提速最新列车时刻表)

Endpoint

Disco

WSDL

中国股票行情数据Web Service(支持深圳和上海股市的基金、债券和股票)

Endpoint

Disco

WSDL

即时外汇汇率数据Web Service

Endpoint

Disco

WSDL

腾讯QQ在线状态Web Service

Endpoint

Disco

WSDL

中国电视节目预告(电视节目表)Web Service

Endpoint

Disco

WSDL

外汇-人民币即时报价Web Service

Endpoint

Disco

WSDL

中国股票行情分时走势预览缩略图Web Service

Endpoint

Disco

WSDL

国内飞机航班时刻表 Web Service

Endpoint

Disco

WSDL

中国开放式基金数据Web Service

Endpoint

Disco

WSDL

股票行情数据 Web Service(支持香港、深圳、上海基金、债券和股票;支持多股票同时查询)

Endpoint

Disco

WSDL

来源:http://developer.51cto.com/art/200908/147125.htm

打造你的php安全程序第一步:禁止掉不安全的php函数(php.ini)

为了使php程序更安全,很多站长都选择了禁用一些比较敏感的函数,那影响php安全的函数到底有哪些呢,下面我们列出了一些:
1、phpinfo()
功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。
危险等级:中
2、passthru()
功能描述:允许执行一个外部程序并回显输出,类似于 exec()。
危险等级:高
3、exec()
功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。
危险等级:高
4、system()
功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。
危险等级:高
5、chroot()
功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式
PHP 时才能工作,且该函数不适用于 Windows 系统。
危险等级:高
6、scandir()
功能描述:列出指定路径中的文件和目录。
危险等级:中
7、chgrp()
功能描述:改变文件或目录所属的用户组。
危险等级:高
8、chown()
功能描述:改变文件或目录的所有者。
危险等级:高
9、shell_exec()
功能描述:通过 Shell 执行命令,并将执行结果作为字符串返回。
危险等级:高
10、proc_open()
功能描述:执行一个命令并打开文件指针用于读取以及写入。
危险等级:高
11、proc_get_status()
功能描述:获取使用 proc_open() 所打开进程的信息。
危险等级:高
12、error_log()
功能描述:将错误信息发送到指定位置(文件)。
安全备注:在某些版本的 PHP 中,可使用 error_log() 绕过 PHP safe mode,
执行任意命令。
危险等级:低
13、ini_alter()
功能描述:是 ini_set() 函数的一个别名函数,功能与 ini_set() 相同。
具体参见 ini_set()。
危险等级:高
14、ini_set()
功能描述:可用于修改、设置 PHP 环境配置参数。
危险等级:高
15、ini_restore()
功能描述:可用于恢复 PHP 环境配置参数到其初始值。
危险等级:高
16、dl()
功能描述:在 PHP 进行运行过程当中(而非启动时)加载一个 PHP 外部模块。
危险等级:高
17、pfsockopen()
功能描述:建立一个 Internet 或 UNIX 域的 socket 持久连接。
危险等级:高
18、syslog()
功能描述:可调用 UNIX 系统的系统层 syslog() 函数。
危险等级:中
19、readlink()
功能描述:返回符号连接指向的目标文件内容。
危险等级:中
20、symlink()
功能描述:在 UNIX 系统中建立一个符号链接。
危险等级:高
21、popen()
功能描述:可通过 popen() 的参数传递一条命令,并对 popen() 所打开的文件进行执行。
危险等级:高
22、stream_socket_server()
功能描述:建立一个 Internet 或 UNIX 服务器连接。
危险等级:中
23、putenv()
功能描述:用于在 PHP 运行时改变系统字符集环境。在低于 5.2.6 版本的 PHP 中,可利用该函数
修改系统字符集环境后,利用 sendmail 指令发送特殊参数执行系统 SHELL 命令。
危险等级:高

禁用方法如下:
打开/etc/php.ini文件,
查找到 disable_functions ,添加需禁用的函数名,如下:
phpinfo,eval,passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status

看过这些函数,站长们应该去检查一下自己的php.ini 看看这些函数是否禁用了。

当然禁止了这些可能会引起安全因素的php函数。你还必须在php.ini里,进一步把php的错误给关闭,这样才更加有针对性的排除你的php被别人利用错误信息进行攻击。
在php.ini里把
display_error = On
改为:
display_error = Off 即可;

高富帅们的Git技巧

Git是一个分布式版本控制系统,拥有许多神奇而易用的特性(比如:分支),这让它可以轻松适应各种工作流程。这篇文章不涉及Git的基本使用,而是介绍了一些高级却有用的小技巧。让我们一起来看看高富帅们的Git技巧,准备好逆袭吧!

以“块”形式暂存你的改动

你肯定已经很熟悉的使用git add命令来将改动暂存到暂存区(staging area)了。你可能也会偶然因为两个不同的原因而做了一次改动,却没有分别提交(仅仅提交了一次),所以,当你执行git log时,会看到诸如这样的提交信息:“修改X,改动无关的Y”。如果这看起来像是你的工作方式,交互式add将是你的有力工具。

交互式add(或者叫add块),将会一个块一个快的循环你的改动。使用命令git add -p时,你可以在每个改动“块”(即:连续的改动会被组织到一起)时进行一些选择,比如:切分当前块为更小的块、跳过一个改动块、甚至手动的编辑该块,你 可以敲入?来查看所有该命令提供的选项。

开始以“块”形式暂存改动简单到只需一条命令(括号部分替换为特定文件):

git add -p (path/file)

译者注:感觉这条命令平常用的较少,我遇到需要分别提交的情况时,都是手动来add然后提交,该命令是这种方法的高级版本。我们平常可能对提交历史的重视比较低,常常出现一些无用的、无意义的提交信息,可以试试这条命令。

切换到最后所在分支

作为一个善良的码农,当你需要快速做些修正或是清理工作时,你都应该花些时间来对待。如果你的工作流程是十分依赖分支的话(译者注:强烈建议如 此),你可能不希望无关的修正影响到现在正在进行功能开发的分支。这意味着,你应该使用git stash命令来暂时存放你的改动,然后切到master分支(译者注:或是其它啥分支,我一般是取名为fix),在那个分支进行修正。(译者注:修正完 了,可以切回正在进行功能开发的分支,执行git stash pop来弹出之前暂存的改动,继续进行开发)。在不同分支间切换很乏味,幸好这里有个快捷命令可以切换到你最后所在的分支:

git checkout -

这个语法对于使用linux的高富帅们来说一定不陌生,cd命令有个类似的缩写cd -,表示切换到你最后所在的目录。当你需要切回功能开发分支时,你根本不用关心那个分支是啥名,只需git checkout -。

译者注:感觉tab键的自动补全也挺好用的,不过这条命令可以少敲点字。有了这条命令,妈妈再也不用担心我的分支切换了。

显示哪些分支被合并了(或是哪些没有被合并)

在使用git时,你可能会创建许多分支,导致执行git branch命令列出分支时变得有些杂乱。于是,你想处理那些已经合并到master分支的无用分支,但是,当你执行git checkout -d 来删除分支时可能会遇到“麻烦”(译者注:git会拒绝删除未合并的分支并提示你),如果使用以下命令,你将不再需要三思而后删,可以自信的处理那些已经 合并了的分支。

如果你想要看看你的本地分支里哪些分支是已经合并进你当前所在的分支时,可以使用:

git branch --merged

反过来,如果需要查看哪些分支还没有合并进当前所在的分支,可以使用:

git branch --no-merged

结合高富帅的UNIX工具,你可以轻松的删除那些已经合并了的分支:

git branch --merged | xargs git branch -d

译者注:xargs是UNIX平台的一个工具,它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。如果git branch –merged显示的是a,b,c三个分支已经合并,上面的命令会转换为:git branch -d a b c。更多xargs的信息:http://zh.wikipedia.org/wiki/Xargs

从另一分支获取文件内容而不用切换分支

设想你正在进行重构,你创建了好几个分支并在各分支下进行改动。这时,你想把另一个分支里某一个文件的改动引入到当前工作的分支里,为了达到目的你 可能需要好几步:git stash你的改动;切换到那个分支;获取文件的改动;切回工作分支(当然是使用git checkout -);继续进行编辑(译者注:别忘了git stash pop)。但是,你也可以直接检出另一分支的文件,并且合并到你当前所在的工作分支,使用命令(括号部分替换为对应的分支和文件):

git checkout (branch) -- (path/file)

以最后提交排序的Git分支

想必你已经使用上面的tip处理了杂乱的分支,有一些是用–merged选项标志来清理的吧。那其它的分支咋办呢?你咋知道哪些是有用的,哪些是 完全过期无用的呢?git for-each-ref命令可以打印出一个列表,该列表显示每个分支最后一次提交的引用(reference)信息。我们可以自定义输出来包含一些有用 的信息,更重要的是我们还可以按日期排序。可以使用下面的命令来输出一个列表,该表将显示按时间先后排序的每个分支的最后提交信息、提交者等信息:

git for-each-ref --sort=-committerdate --format="%(committername)@%(refname:short) [%(committerdate:short)] %(contents)"

还可以把它定义在gitconfig里:

[alias]
  latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\"

译者注:定义后就只需执行git latest了。注意双引号需要转义!

在玻璃房内的人们别用git blame

或者说,在玻璃房内的人们不应该直接使用git blame而不带下文的选项标志。(译者注:玻璃房内的人是完全能被别人看到的人。这里的意思应该是想说,你每一次提交的变动都会被记录到git仓库的历 史,对于git仓库来说,你就像是住在玻璃房里的人,没有任何秘密,你根本逃不过git的”责问“)git blame是很有用的命令,它就像使用科学来证明你是正确的!但是请注意,许多文件的变动是很表面的,发现问题的来源需要更多的探索。像是移除空白、移动 内容到新行、移动内容到另一文件等动作都可以使用选项来忽略掉,以便更容易的找到代码变动的始作俑者。

在你blame(责备)他人前,记得用以下命令看看结果:

git blame -w  # 忽略移除空白这类改动
git blame -M  # 忽略移动文本内容这类改动
git blame -C  # 忽略移动文本内容到其它文件这类改动

译者注:git blame用来显示一份文件每一行的最近一次提交的提交hash值和提交者。当你跟别人说“我真的没改过这个文件啊”之前,就得git blame下。

在整个git仓库提交历史中找寻内容(然后删掉它)

你有时可能需要查找一行你写的代码,但是就是无法找到。它可能安放在了一些已经被遗忘的分支,或是删除了很久,又或是就在那显而易见的地方。无论哪种方式,你都可以通过一些命令在整个git仓库的历史中搜寻特定的字符串。

首先,我们需要拿到所有的提交,然后,使用git grep来搜寻特定的字符串。如下:

git rev-list --all | xargs git grep -F '搜寻的字符串'

你可能有一个粗心的朋友不小心在仓库里提交了诸如,用户名、密码、外婆的大蒜食谱等敏感信息。首先,他们得更改用户名、密码(并向外婆道歉)。然 后,你需要搜寻这些得罪人的文件,并将他们从整个仓库的历史里抹去(这听起来好像很容易)。经过这个处理,那些执行git pull的伙计们就会发现所有提交中包含的敏感信息都被清理干净了,而那些没有合并你的远程改动的家伙还是拥有敏感信息(所以,千万别忘记先改用户名和密 码)。我们来看看怎么操作。

首先,重写每个分支的历史,移除敏感信息:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch (filename)' --prune-empty --tag-name-filter cat -- --all

然后,将记录敏感信息的文件增加到.gitignore文件,并提交(括号部分替换为对应文件名):

echo (filename) >> .gitignore
git add .gitignore
git commit -m "Add sensitive (filename) file to gitignore"

接着,由于我们改写了历史,我们需要“强制”的将改动推到远程:

git push origin master --force
# 译者注:还可以使用命令
git push origin +master

最后,这个文件还在你的本地仓库里,还需要将它完全抹除:

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

你这粗心的朋友从敏感文件的危机中解脱,而你用你高超的git知识成功逆袭,成为了他的英雄!

译者注:一天,妹子叫我去她家帮她把她的三围信息从git仓库的历史里完全删除,我研究了很久不得要领。妹子说,不如我们做点其它的事吧。我觉得我的git知识被她鄙视了,坚定的说,我一定要把它删掉!然后,就没有然后了… …

忽略文件跟踪

在和他人合作时可能常常意味着你需要更改一些配置才能让应用在环境里跑起来,这时,常常会不小心把这些只对你有意义的配置文件也给提交了。为了不再 常常关注这些文件,看着它们在git status时放肆的显示“modified”,你可以告诉git忽略它们的改动。这种方式,可以看成是一种和仓库绑定的gitignore文件(括号部 分替换为对应文件):

  git update-index --assume-unchanged (path/file)

译者注:感觉,.gitignore文件更方便和好理解。

让分支的历史归零

不管出于啥理由,有时从头开始正是你需要的。也许是你接手了一个不确信能安全开源的代码仓库;也许是你要着手做些全新的事情;也许是你想创建用于其 它目的一个新分支,又希望继续在仓库里维护它(比如:github页面,项目的文档一类的东西)。上述的情形下,你可以非常简单的创建一个没有提交历史的 分支(括号部分替换为对应分支):

  git checkout --orphan (branch)

译者注:我们知道,分支只是对提交的一个引用,所以,每当从当前分支创建一个分支时,被创建的分支都会延续之前的历史,但是这种方式却不会,是一个完完全全干净的git分支,没有任何的提交!

你一定离不开的别名

不讨论能节省大量敲击时间的“git别名(git alias)”技巧的git文章一定都是在耍流氓。停止输入冗长的命令,使用超级有用的别名吧!git别名可以加到.gitconfig文件里,或是使用 命令(译者注:本质就是改写.gitconfig命令)来增加(括号部分替换为别名和对应的命令):

    git config --global alias.(name) "(command)"
  1. 在依赖分支的工作流程中,你常常要在不同分支间切换,每次敲击节约你6个字母。
    co = checkout
    
  2. 在提交前瞧瞧你将要提交的都有什么改动是一个好习惯,这可以帮助你发现拼写错误、不小心的提交敏感信息、将代码组织成符合逻辑的组。使用git add暂存你的改动,然后使用git ds查看你将要提交的改动动。
    ds = diff --staged
    
  3. 你可能十分熟悉git输出的详细状态信息了,当到达一定境界时,你可能需要忽略所有那些描述,直击问题的核心。这个别名输出将输出git status的简短形式和分支的详细信息。
    st = status -sb
    
  4. 你是否在提交后才发现忘记git add某个文件了,或是提交了才想再改动些啥?amend(修正)暂存区到最近的一次提交吧。(译者注:这个命令不太好理解,–amend是重写提交历 史,-C是重用某次提交的提交信息。场景是当你提交完了发现还有些改动没提交,又不想写什么“改动了X,再次提交”这种狗血的提交信息。重新git add并git amend后,重用上次的提交信息再次提交,替换上次的不完整提交。特别注意–amend重写了提交,如果你已经push到远程了,慎用这条命令!)
    amend = commit --amend -C HEAD
    
  5. 有时上面的修正可能不好使了,你需要undo(撤销)。undo会回退到上次提交,暂存区也会回退到那次提交时的状态。你可以进行额外的改动,用新的提交信息来再次进行提交。
    undo = reset --soft HEAD^
    
  6. 维护一个多人编辑的代码仓库常常意味着试着发现何人在改动什么,这个别名可以输出提交者和提交日期的log信息。
    ls = log --pretty=format:'%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green) [%cn]' --decorate --date=short
    
  7. 这个别名用来在一天的开启时回顾你昨天做了啥,或是在早晨刷新你的记忆(括号内替换为自己的email)。
    standup = log --since '1 day ago' --oneline --author (YOUREMAIL)
    
  8. 一个复杂的仓库可能很难用直线式的输出来查看,这个别名可以用图表的形式向你展示提交是怎样及何时被加到当前分支的。
    graph = log --graph --pretty=format:'%C(yellow)%h %C(blue)%d %C(reset)%s %C(white)%an, %ar%C(reset)'
    

译者注:我根据上面的别名进行了一些整理修改,这是我现在的.gitconfig里的别名配置:

[alias]
  st = status -sb
  co = checkout
  br = branch
  mg = merge
  ci = commit
  ds = diff --staged
  dt = difftool
  mt = mergetool
  last = log -1 HEAD
  latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\"
  ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short
  hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short
  type = cat-file -t
  dump = cat-file -p

via alimama mux
作者:Chris Kelly 译者:栖邀
英文原文

来源:http://segmentfault.com/a/1190000002448847

服务器的瞬时 Diffie-Hellman 公共密钥过弱

服务器的瞬时 Diffie-Hellman 公共密钥过弱

ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY

该错误会在连接到安全 (HTTPS) 服务器时发生。 这意味着服务器正在尝试建立安全连接, 但由于严重的配置错误,连接会很不安全!

在这种情况下, 服务器需要进行修复。 为了保护您的隐私, “Google Chrome”不会使用不安全的连接。

以前可以跳过,现在不行了

方法:

1.更改服务器加密协议为TSL,chrome 45 版本后不再支持SSL v2 v3了

Firefox 可以使用 禁止dhe,不过不推荐

2.使用更高强度的证书,可以自签,也可使用免费证书(不过都有时间限制)

当然如果不差钱,可以购买一个证书,这样解决问题彻底

WordPress通过文章ID获取文章标题内容等信息

使用Wordpress的朋友可能遇到这样的问题,在非single.php页面中我们有时候想要调用当前文章的标题、内容等信息,而Wordpress在生成文章页的时候在各个页面中唯一不变的只有当前的文章ID,那么如何根据这个ID获取到当前文章的标题、内容等信息呢?可以通过下面的代码实现:

<?php 
$id=//这里是文章的ID 
$title = get_post($id)->post_title;
echo $title;//输出文章的 标题
?>

其他信息可以通过改变get_post($id)->post_title中的post_title来实现:

post_author:(整数)文章作者的编号
post_date:(字符)文章发表的日期和时间(YYYY-MM-DD HH-MM-SS)
post_date_gmt:(字符)文章发表的格林尼治标准时间(GMT) (YYYY-MM-DD HH-MM-SS)
post_content:(字符)文章内容
post_title:(字符)文章标题
post_category:(整数)文章类别的编号。注意:该值在WordPress 2.1之后的版本总为0。定义文章的类别时可使用 get_the_category()函数。
post_excerpt:(字符)文章摘要
post_status:(字符)文章状态(publish|pending|draft|private|static|object|attachment|inherit|future)
comment_status:(字符)评论状态(open|closed|registered_only)
ping_status:(字符)pingback/trackback状态(open|closed)
post_password:(字符)文章密码
post_name:(字符)文章的URL嵌套
to_ping:(字符)要引用的URL链接
pinged:(字符)引用过的链接
post_modified:(字符)文章最后修改时间(YYYY-MM-DD HH-MM-SS)
post_modified_gmt:(字符)文章最后修改GMT时间(YYYY-MM-DD HH-MM-SS)
post_parent:(整数)父级文章编号(供附件等)
guid:(字符)文章的一个链接。注意:不能将GUID作为永久链接(虽然在2.5之前的版本中它的确被当作永久链接),也不能将它作为文章的可用链接。GUID是一种独有的标识符,只是目前恰巧成为文章的一个链接。
post_type:(字符)(日志 | 页面 | 附件)
post_mime_type:(字符)Mime类型(供附件等)
comment_count:(整数)评论总数

dedecms经常出现mysql”连接数据库失败,可能数据库密码不对”解决方案

DEDE 5.5 版本经常出理以下错误

Error page: /dede/xxx

Error infos: DedeCms错误警告:连接数据库失败,可能数据库密码不对或数据库服务器出错

是随机出现并不是一直就这样,这样就可以排除是MYSQL用户名密码设置的问题了。

在网上找了一下基本上可以肯定就是 微软 KB967723 这个补丁所引起来了。

第一种方案

删除 KB967723  补丁 这个不建议大家操作,会引起网络断掉并无法链网的情况。

那我们就用微软件推荐的第二种方案吧

本方法是微软给出的修改注册表修复该Bug的的方法,原因是默认最大的临时 TCP 端口的数是 5000 适用于一节中包含的产品中。 在这些产品中添加一个新参数。 要提高临时端口的上限,请按照下列步骤操作:

1.启动注册表编辑器。
2.在的注册表中找到以下子项,然后单击 参数 :
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
3.在 编辑 菜单上单击 新建 ,,,然后添加下面的注册表项:
数值名称: MaxUserPort
值类型: DWORD
值数据: 65534
有效范围: 5000-65534 (十进制)
默认值: 0x1388 (5000 十进制)
说明: 此参数将控制程序从系统

微软官方关于这个补丁的说明:  http://support.microsoft.com/kb/q196271

当您试图从大于 5000 的 TCP 端口连接时收到错误 WSAENOBUFS (10055)

建议大家和我们下面导出来的注册表,导进去就可以了

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters]
"MaxUserPort"=dword:0000fffe

把上面的内存COPY起来 复制到记录本中,保存为 .reg 再双击导入就OK了

不过记得重启一下电脑。

WordPress添加文章形式

要让自己的博客支持更多的文章形式,需要在主题的functions.php文件中调用add_theme_surpport()方法。形式如下:

add_theme_support('post-formats', array( 'aside', 'gallery' ));

第一个参数指添加的是文章形式,第二个参数是要添加的文章形式数组。但是只调用这个方法并没有效果,还需要用到WordPress的 add_action()方法,add_action()方法可以将我们自定义的php函数钩入WordPress,相当于激活这个函数。具体代码如下:

add_action('after_setup_theme','custom_post_formats_setup');
    function custom_post_formats_setup(){
    add_theme_support( 'post-formats', array( 'chat', 'image', 'link', 'quote', 'status', 'video', 'audio' ) );
}

add_action()的第一个参数是用到的钩子,第二个参数是自定义方法的名称。

网站第三方社会化插件推荐

 来源: 卢松松博客

从评论系统到分享按钮,从智能推荐插件到社会化登陆,社会化插件已经入侵了网站的方方面面,我就推荐写适合个人网站使用的第三方社会化插件。
搜索引擎认为最有价值的(按先后顺序):

1:内容

2:社会化

3:用户体验

4:链接建设

5:SEO

这是从ZAC博客中分享的一个Bing人员总结的高度浓缩的SEO技术,其实适用于所有搜索引擎。由此可见社会化的重要性。

那么,既然知道了社会化分享的重要性,今天卢松松推荐的插件可以用过一张图来表明。

我们看到,如果网站全权使用第三方社会化插件的话,除了网页基本框架和内容之外,其他功能都可以由插件来完成了。

1:分享插件

现在在各个网站上我们都能见到分享的按钮,目前Jiathis、bshare、百度分享这三款算是很火的分享按钮了。

下面的示意图可以说明分享按钮的作用,例如:通过用户A分享到他的微博下,这样他的粉丝就能看到该网站的内容,从而影响更多的人。

卢松松博客目前用的是Jiathis,因为它出是早,而且可分享的网站也非常多,而且在分享数据分析方面做的也很全面。Bshare还没用过,不过多评论了。

后起之秀,百度分享是很厉害,因为还不清楚百度的分享和它的收录、排名有什么关系,为了保险起见,许多站长都换成百度分享了,而且刷百度分享数的人也不在少数。

2:评论插件

第三方社会化评论系统我在之前的博文中已介绍过,目前评论插件有:评论啦、友言、贝米,和刚刚诞生的“多说”。

它们的功能大多类似,如上图所示,去处装上一段JS代码即可使用,比如社会化登陆、分享按钮、添加图片视频等等,在评论框中一应俱全。而且现在这些社会化评论系统已经支持SEO了,同时评论的数据也支持导入/导出了。

3:智能推荐插件

无觅是一个较早推出智能推荐插件的,我真正使用无觅这个插件还是在去年,因为之前Truman Lam给我推荐了好久。在加上他们的工具确实靠谱,所以我就用上了。智能推荐插件就是可以把同一个网站不同程序下的相关文章聚合到一起,主要是增加相关文 章精准度。同时无觅的“喜欢”功能就类似于分享按钮,可以把“喜欢”的文章推送到绑定的微博中,

友荐:和无觅一样的功能,不过部分还在内测中,它最大的特色就是JS代码只有一行。

需要注意的是友荐、友言已被Jiathis(加网)收购,从“分享按钮”到“智能推荐”再到“评论框”,Jiathis已经形成了一套完整的社会化插件体系。

同时Jiathis推出的趣一网的个性化阅读也与新版无觅网的个性化阅读形成了正面竞争。需要注意的是,只有你的博客安装了其中任何一方插件的用户才可能进入他们自家的热门排行榜,带来流量,二选一,你选吧。

写在最后:

分享按钮,可以让用户帮你推广网站;社会化评论框,可以提交评论、载入速度,方便管理评论;智能推荐插件,可以提高网站PV,增强用户黏性。

它们有很直接有优点,也有最大的缺点:你会发现网页中有一大堆第三方JS,牵一发则动全身。

作者:卢松松 本文地址:http://lusongsong.com/reed/436.html

WordPress子目录Rewrite的404问题

这些天有个问题一直困扰着我,由于我的WordPress是放在网站的根目录下,因此我建立的一些子目录跑一些其他的应用,我发现这些应用被WordPress的.htaccess文件的RewriteRule所干扰,我费了好大劲修改.htaccess文件,使得子目录的文件的RewriteRule可以工作正常,却发现调用子目录的应用总是返回404状态,但是内容却是正常的。

其实,如果建立一个子目录放Discuz论坛,则论坛的RewriteRule也会被干扰,这个问题实在令人困惑,特别是返回404状态后,所有文件将不会被搜索引擎所收录。

经过一番调试和修改,我发现了一个很怪异的方法可以解决这个问题,就是在子目录的PHP文件中加入下面这一行代码:

header(“Status: 200 OK”);

之后我使用一些HTTP Status测试工具测试,该目录和文件就不再返回404状态了,而是返回200状态,之后我会观察一下该子目录在搜索引擎的收录情况,估计应该也会恢复正常了。WordPress的某些特性实在是令人奇怪,搞不懂为什么会是这样。

WordPress 真的飞不起來

来源: Willin Kan的博客

wordpress

或许有人会告诉你:WordPress 是最好的博客程序!是的,不过那已是以前的事了。

您是否觉得 WordPress 越来越臃肿? 再加上几个插件会更形笨拙。就像一部大客车, 起步相当耗油, 而且换档加速相当慢。 当客人一多, 上下车的时间更是拖慢了整个行程。其中最大的好处, 就是您可以在车上轻松睡一觉, 醒来刚好到站。

所有空间商最头痛的还是 WordPress, 严重消耗了大量内存和 CPU, 以下先引用某空间商的一段话:

WordPress is often using too much CPU Usage, which causes the server to slow down.

You‘ll need to get rid of your WordPress installation or look for an alternative, we want all users to note this issue.

大意是说:WordPress 太耗CPU了,您应该换成其它程序。是的,大家都应该换掉,千万别让WordPress 搞垮您的空间。直到最近,反对的声浪越来越烈,WordPress团队是该彻底检讨了。

以前我还说过 WordPress 将是下一个 IE,但没想到竟来的这么快。近四年来我都在挖掘 WordPress,也写了不少代码简化程序。探究越深, 越觉得无趣,因为它用了很多不需要的动作。 绕了一大圈才进城。尤其是后台用了很多外链链接到官网, 有些是rss, 有些是检查更新, 其实这些都没有必要。

以前还曾发现后台的几则新闻的rss竟高达2M,一般用户对这些资料连看都不看,这样rss有何作用?深窥 WordPress的心态,是借机取得PR,用户链接越多PR越高。终究还是个商业手段,为了赚钱?

有个口号:能用代码解决的,绝不用插件,因为插件太耗资源了。WordPress已具备丰富的函式库, 写插件的门槛非常低,连生手也很容易写出个插件。然而,这个插件耗费多少资源,却没人会去过问。记得 All in one 的插件吗? 因为太耗资源,用过的人都后悔了。现在google一下,还是有人在推荐All in one,为什么?

网络资讯应该要即时更新, 那些旧资料就删了吧! 别再误导别人落入陷阱。

顺便提一下 SBO (看不懂的把 B 改成 E),搜索结果都是十几年前的旧资料。 满城尽说 SBO, 殊不知都是狗屁。现在只要文章中提到SBO, 或是链接到SBO的网站,您的网站保証会被降权,因为会被当成作弊。这也难怪我在这边用 SBO 替代字。

时代一直在进步, 旧资料就别再拿出来害人了, 我这边不再提供以前的代码, 为的是各位的服务器, 请各位谅解。不是那些代码不好,而是WordPress 程序核心太大了,不使用任何插件的情况下都有点吃力,何况再加上插件。

就听我的建议,换个博客程序吧!至于改用哪个,可要自己挑了,我不敢推荐。

文章来源:Willin Kan 的博客

WordPress文章ID不连续的解决方法

2012-03-28 16:47  来源: congblog.cn

最近看到有许多朋友提到“WordPress文章ID不连续”怎么办?,其实笔者刚刚接触WordPress的时候就发现了这个问题,所以也是一开始就把WordPress的自动保存以及文章修订版本功能隐蔽。但是固定连接如果不用postid命名的话也许发现不了,但是大葱一直使用的就是这种固定链接。如果你网速不佳的时候,这会影响到文章的编辑以及发表页面的载入速度;另外每一次自动保存的文章草稿它都会自动写入我们的数据库,这样的话无形之中也就大大了数据库的储存,冗余数据太多的话也会影响到数据库的工作效率,另外也就是我们之前提到的文章ID不连续。

WordPress仪表盘并没有直接的提供关闭这个功能的选项,那么今天就给大家讲讲如何把这个功能完完全全的隐蔽掉。

方法1:

WordPress默认是每60秒就会对文章进行自动保存,我个人是觉得太频繁了,那么我们可以打开博客根目录下的wp-config.php文件,搜索“require_once(ABSPATH . ‘wp-settings.php’);”在其前面/上面添加如下代码:

//自动保存10小时一次

define(‘AUTOSAVE_INTERVAL’, 36000);

//取消自动修订版

define(‘WP_POST_REVISIONS’,false);

方法2:

代码来源于国外网站,使用环境:WordPress 3.3.1,原理上 3.0 以上都支持,WP3.0.x 大葱没有进行测试。在我们当前使用主题的 functions.php 文件加入如下代码即可:

/* 取消自动保存和修订版本 */

remove_action(‘pre_post_update’, ‘wp_save_post_revision’);

add_action(‘wp_print_scripts’, ‘disable_autosave’);

function disable_autosave() {

wp_deregister_script(‘autosave’);

}

清理数据库中以前的文章历史修订版本

自动保存和修订版本我们都解决了,接下来我们进行删除数据库中的冗余文章和修订版本,数据库操作之前大葱建议大家先进行备份。我们登录phpmyadmin 中进行数据库管理,SQL语句命令行中写入以下运行代码执行(如果更改了数据库表名的前缀,需要将数据表名称中wp改成你的前缀):

delete from wp_posts where post_type=’revision’;

本文固定链接:http://www.congblog.cn/878.html | 大葱博客

WordPress支持用户以Twitter帐号登录评论

据国外媒体报道,博客网站WordPress.com今日宣布,用户今后可通过登录Twitter或Facebook账户在WordPress网站上发表评论。

分析称尽管表面看来这仅是非常小的新功能,但它同时也为WordPress博客网站提供更多的发表评论的机会。第三方评论系统如Disqus以及Echo等网站目前均允许用户通过Twitter或Facebook账户发表评论,但这一功能对于博客平台网站来说是一个巨大的进步。

WordPress高层斯科特·波尔克(Scott Berkun)在官方博客中表示,新的登录系统可以使用户在同一时间登录不同的服务网站。这对于一些想通过Twitter或Facebook账户发表评论的用户来说非常方便。

据悉,用户通过Twitter或Facebook账户发表的评论将不会在社交网站上显示。该登陆方式仅是WordPress验证用户身份的方式。WordPress将来有可能会允许用户在Facebook或Twitter上分享及发布评论。

WordPress博客用户通过Facebook及Twitter发表的评论将会通过由Automattic开发的JetPack插件进行验证。

修改WordPress语言包的方法和工具

修改或者制作主题的时候,要做到个性十足、称心如意,就需要对Wordpress的语言包进行调整修改。在主题的目录下面语言包文件夹中我们会找到两个文件:zh_CN.po和zh_CN.mo,其中前者是需要编译的中文语言包,在经过编译后生成的文件就是后者,其中.mo文件才是Wordpress可以直接调用的中文语言包。但是.mo文件不能用记事本类的工具直接修改编辑,这时就要用到po-edit了。
这在我们制作中文主题时必备的工具:

1、找到目录的语言包,位置在(这里以inove主题风格为例):

zh_CN.po的位置: \wp-content\themes\inove\languages
zh_CN.mo的位置:\wp-content\themes\inove

2、下载并安装po-edit软件:

软件官方网站:http://www.poedit.net/
安装以后首先是设定软件界面语言,选择chinese(simplified)即可。

3、从软件中选择打开zh_CN.po文件,然后就可以看到各个条目的信息了,找到你想编辑的修改即可。

4、修改后,点击“另存为”找到合适的地方存储即可(po-edit会自动创建生成zh_CN.mo文件)。

5、将这两个文件分别上传到对应的目录(步骤1中所示)覆盖原文件,然后刷新主页看一下吧。

信阳光山大美女,信阳网络电视台美女记者

信阳光山大美女,信阳网络电视台美女记者
中共信阳市第四次代表大会第三次全体代表大会召开_信阳网络电视台…
2011年9月2日…信阳网络电视台9月2日讯 (记者 程芳) 9月2日上午,中国共产党信阳市第四次代表大会第三次全体会议在百花之声会议中心召开。 大会执行主席王铁、郭…
www.xytv.cn/NEWS/shizhengyaowen/2011/0902 … 2011-9-2 – 百度快照
台湾金门高粱酒落户信阳_信阳网络电视台 信阳电视网 视频 新闻 信…
2011年7月12日…开业盛况 信阳电视网(记者 程芳)讯 7 月 9 日上午,金门高粱 两岸飘香台湾金门高粱酒信阳旗舰店开业典礼在行政路经典花园隆重举行,并正面向县区诚征…
www.xytv.cn/NEWS/shizhengxinwen/2011/0709 … 2011-7-12 – 百度快照
中共信阳市第四次代表大会主席团第六次会议召开_信阳网络电视台 …
2011年9月2日…信阳网络电视台9月2日讯 (记者 程芳) 9月2日上午,中国共产党信阳市第四次代表大会主席团第六次会议在百花之声召开。 主席团成员应到 70 名,因…
www.xytv.cn/NEWS/shizhengyaowen/2011/0902 … 2011-9-2 – 百度快照
更多资料请点击信阳网络电视台
芳芳

wordpress模板各文件函数解析

修改主题时发现好多WordPress主题函数都不了解,网上摘抄了一份放在自己博客上,便于以后好找。
在WordPress中如何按你的意愿显示页面,关键看你是否了解WordPress主题模板页面。这里所说的主题文件是指显示页面的主题文件,而非实现评论、侧边栏等功能的主题文件。大多数用户不使用WordPress安装时自带的默认主题,他们会在互联网上下载免费主题。这是一种设计博客版式的好方法,但不是所有主题开发者都用相同的方式编写主题。主题的表现很大程度上取决于开发者用在主题上的开发时间和对WordPress的了解。
下面我会为大家介绍设计主题页面的所有相关知识,通过这些下面的信息你甚至可以开始为自己设计一个主题。除非你是专家级的主题开发者,否则都可以从这里学到些新的东西。
WordPress如何工作
首先需要了解的是WordPress的模板层级,或者说是“WordPress调用页面的顺序”。 “index.php”是唯一一个所有WordPress主题的PHP文件中都必须具备的文件。“index.php”可以执行WordPress的所有单独功能。
每当有WordPress页面被调用时,WordPress的“引擎”会判断(通过排除法)页面的类型。 这类似于询问“我在哪儿?”。 WordPress回答“我在…类型的页面上”,然后以特定顺序调用页面。 WordPress找不到需要的PHP文件时,会使用“index.php”文件来代替所需文件。 WordPress首先会寻找以下九种基本页面:
首页
如果WordPress判断是在首页上,会先调用“home.php”文件然后再调用“index.php”。
日志页
如果是(单篇)日志页,首先调用“single.php”然后默认调用“index.php”。
“页面”页
如果是静态页面或“页面型”页面(应用了模板的页面),WordPress首先调用“pagetemplate.php”然后默认调用“index.php”。
“分类”页
如果WordPress判断是分类页,则首先调用该类别编号的页面,例如“category-7.php”。找不到相应文件时可以查找“category.php”(category.php可以用于所有类别页)。如果没有“category.php”则继续查找“archive.php”,最后默认调用“index.php”。
标签页
如果WordPress判断是标签页,会首先加载“tag-slug.php”文件,以具体的slug(别名)为标签名。如果标签是“wordpress hacks”,那么标签别名页就是“tag-wordpress-hacks.php”。如果加载不成,WP会继续查找“tag.php”文件,该文件可用于所有标签页,然后调用“archive.php”,最后默认调用 “index.php”。
作者页
博客拥有多个作者时,WP会首先寻找“author.php”文件以显示作者详情。如果没有“author.php”则继续查找“archive.php”,最后默认调用“index.php”。
存档页
WP为之前的日志加载信息页面时,同时也加载了存档页。 WP首先加载“date.php”,其次“archive.php”,最后默认加载“index.php”。
搜索页或404页
若WP判断是在搜索结果页或404(页面未找到)页,会尝试加载search.php或404.php文件。如果无法加载search.php或404.php,WP仍然默认加载“index.php”。
附件页
附件页是所有WordPress主题模板页面中使用次数最少的一种页面类型。 WordPress通常用这些特殊的附件页来加载若干信息,这些信息解释首先查找“image.php”, “audio.php”, “video.php”, 以及“application.php”的原因。然后WP查找“attachment.php”或“single.php”,如果这两个文件不可用,默认查找“index.php”。
WP主题模板内部运行情况
可以用单独的index.php文件来调用以上九种类型的页面,这在上面也提到过。也可以在一些条件标签中编写代码,我在这篇文章的结尾部分会告诉大家如何操作。一个页面中可能含有很多代码,有时甚至有些混乱,这样我们要修改代码来进行设计就不太方便了。
不过凑巧的是,就像WordPress查找九种基本页面一样,每个主题模板页面也包含九种基本的WordPress元素:
调用页眉
开启the loop(主循环)
调用永久链接与(若干)meta
用以通知WordPress应获取的信息的调用
用以获取获取文章内容或摘要的调用
(可能有)更多的meta
关闭the loop(主循环)
调用侧边栏
调用页脚
这是WordPress元素,能让这些元素运行的PHP代码分布在不同的地方,让你的主题版面和平面设计保持正常工作。下面我要详细介绍一下这些元素,以便大家进一步了解如何设计主题模板页面。
调用页眉,侧边栏以及页脚
这三种元素基本类似。 当你在模板中看到以下代码:
<?php get_header(); ?>
表明WordPress打开了“header.php”文件。 get_sidebar() (sidebar.php) 和 get_footer() (footer.php)也是同样的道理。你可能会有很多页眉、页脚和侧边栏,这时可以点击上面的“条件标签”查看相关内容。
开启the loop(主循环)
“Wordpress Loop”会在数据库中持续调用文件,直到WordPress终止调用。 “the loop”的结构随显示页面类型而变,WordPress尝试加载的每个基本类型页面都有一个“loop”。
下面是开启the loop的代码:
<?php if ( have_posts() ) : <?php if ( have_posts() ) : the_post(); ?>
我们可以看到,代码被拆分开来,have_posts用以定义条件标签,while和the_post则各成一部分,但这仍然是the loop,在所有页面中基本都是这样。 多行loop时的一个用法是:用query_posts在“if have_posts”和代码的剩余部分之间放置一个参数,用来显示单篇文章、某一时段的文章、最近一篇文章或者某一类别中的文章,也可以改变the loop中迭代文章的顺序。
调用永久链接与(若干)meta
通过the loop的每次迭代,开放The loop的最后部分(the_post)能够激活元素数据。这里的个体数据通常是指“post meta”,尤其是永久链接(URL)、标题、时间这样的meta。大多数主题会在单篇文章内容前显示一些信息,然后在文章内容后也显示一些信息——比如文章类别和标签。
下面是一些你可以在post meta中调用的内容: the_permalink, the_ID, the_title, the_time, the_author, the_author_email, the_author_posts_link, the_category, single_cat_title, the_tags, single_tag_titls, edit_post_link, comments_popup_link, comments_rss_link
下面是Post meta的代码示例:
<div class=”post” id=”post-<?php the_ID(); ?>”>
<h2><a href=”<?php the_permalink() ?>” rel=”bookmark”><?php the_title(); ?></a></h2>
</div>
用以通知WordPress应获取的信息的调用
之后WordPress会决定所显示的单篇文章内容的详细程度。文章详细程度取决于你的主题使用的是“the_content”(显示全文)或“the_excerpt”(显示摘要)。
(可能有)更多的meta
上面提到过,文章下方都有指定的类别或标签,有时你还可能看到“edit”链接。 一些主题甚至在文章内容后添加了date published meta。
关闭the loop(主循环)
代码如下:
<?php else : ?>
<?php endif; ?>
这是一个多行代码,你可以在其中添加其它信息,例如“Sorry, we didn’t find anything”。你可以在侧边栏之后、调用侧边栏和页脚之前找到“next”“previous”导航链接。
Loops
大多数loops与我在上面所举的例子都差不多,但这并不表示你不能随意修改这些loops。 推荐大家阅读WP Codex上的文章The Loop in Action,文章中列举了存档、类别以及单篇文章以及静态首页中的the loop。
WP Codex上the loop中也有一些在同一页面上放置多个loop的示例。 Perishable Press上有一篇关于多loop,多栏内容的精彩教程。 Perishable Press上还有一些很好的loop模板,以及一篇关于两栏水平序列文章的教程。
(一)WordPress基本模板文件,一套完整的WordPress模板包括如下文件,但是只有index.php和style.css是不能缺少的:
style.css : CSS(样式表)文件,不可缺少版权部分,真正CSS样式表可以放在其他文件;
index.php : 主页模板,不可缺少;
archive.php : Archive/Category模板,如果缺少,默认为index.php的显示;
404.php : Not Found 错误页模板,如果缺少,默认为index.php的显示;
comments.php : 留言/回复模板,不可缺少;
footer.php : Footer模板,可合并到index.php;
header.php : Header模板,可合并到index.php;
sidebar.php : 侧栏模板,可合并到index.php;
page.php : 内容页(Page)模板,如果缺少,默认为index.php的显示;
single.php : 内容页(Post)模板,如果缺少,默认为index.php的显示;
searchform.php : 搜索表单模板,可合并到index.php;
search.php : 搜索结果模板,如果缺少,默认为index.php的显示;
(二)基本条件判断Tag
is_home() : 是否为主页
is_single() : 是否为内容页(Post)
is_page() : 是否为内容页(Page)
is_category() : 是否为Category/Archive页
is_tag() : 是否为Tag存档页
is_date() : 是否为指定日期存档页
is_year() : 是否为指定年份存档页
is_month() : 是否为指定月份存档页
is_day() : 是否为指定日存档页
is_time() : 是否为指定时间存档页
is_archive() : 是否为存档页
is_search() : 是否为搜索结果页
is_404() : 是否为 “HTTP 404: Not Found” 错误页
is_paged() : 主页/Category/Archive页是否以多页显示
(三)Header部分常用到的PHP函数
<?php bloginfo(’name’); ?> : 博客名称(Title)
<?php bloginfo(’stylesheet_url’); ?> : CSS文件路径
<?php bloginfo(’pingback_url’); ?> : PingBack Url
<?php bloginfo(’template_url’); ?> : 模板文件路径
<?php bloginfo(’version’); ?> : WordPress版本
<?php bloginfo(’atom_url’); ?> : Atom Url
<?php bloginfo(’rss2_url’); ?> : RSS 2.o Url
<?php bloginfo(’url’); ?> : 博客 Url
<?php bloginfo(’html_type’); ?> : 博客网页Html类型
<?php bloginfo(’charset’); ?> : 博客网页编码
<?php bloginfo(’description’); ?> : 博客描述
<?php wp_title(); ?> : 特定内容页(Post/Page)的标题
(四)模板常用的PHP函数及命令
<?php get_header(); ?> : 调用Header模板
<?php get_sidebar(); ?> : 调用Sidebar模板
<?php get_footer(); ?> : 调用Footer模板
<?php the_content(); ?> : 显示内容(Post/Page)
<?php if(have_posts()) : ?> : 检查是否存在Post/Page
<?php while(have_posts()) : the_post(); ?> : 如果存在Post/Page则予以显示
<?php endwhile; ?> : While 结束
<?php endif; ?> : If 结束
<?php the_time(’字符串’) ?> : 显示时间,时间格式由“字符串”参数决定,具体参考PHP手册
<?php comments_popup_link(); ?> : 正文中的留言链接。如果使用 comments_popup_script() ,则留言会在新窗口中打开,反之,则在当前窗口打开
<?php the_title(); ?> : 内容页(Post/Page)标题
<?php the_permalink() ?> : 内容页(Post/Page) Url
<?php the_category(’,’) ?> : 特定内容页(Post/Page)所属Category
<?php the_author(); ?> : 作者
<?php the_ID(); ?> : 特定内容页(Post/Page) ID
<?php edit_post_link(); ?> : 如果用户已登录并具有权限,显示编辑链接
<?php get_links_list(); ?> : 显示Blogroll中的链接
<?php comments_template(); ?> : 调用留言/回复模板
<?php wp_list_pages(); ?> : 显示Page列表
<?php wp_list_categories(); ?> : 显示Categories列表
<?php next_post_link(’%link’); ?> : 下一篇文章链接
<?php previous_post_link(’%link’); ?> : 上一篇文章链接
<?php get_calendar(); ?> : 日历
<?php wp_get_archives() ?> : 显示内容存档
<?php posts_nav_link(); ?> : 导航,显示上一篇/下一篇文章链接
<?php include(TEMPLATEPATH . ‘/文件名’); ?> : 嵌入其他文件,可为定制的模板或其他类型文件
(五)与模板相关的其他函数
<?php the_search_query(); ?> 搜索表单的值
<?php _e(’Message’); ?> : 输出相应信息
<?php wp_register(); ?> : 显示注册链接
<?php wp_loginout(); ?> : 显示登录/注销链接
<?php wp_meta(); ?> 显示管理员的相关控制信息(为插件API HOOK用)
<!–next page–> : 将当前内容分页
<!–more–> : 将当前内容截断,以不在主页/目录页显示全部内容
<?php timer_stop(1); ?> : 网页加载时间(秒)
<?php echo get_num_queries(); ?> : 网页加载查询量
显示最新文章
<?php query_posts(’showposts=5′); ?>
<ul>
<?php while (have_posts()) : the_post(); ?>
<li><a href=”<?php the_permalink() ?>”><?php the_title(); ?></a></li>
<?php endwhile;?>
</ul>
显示最新评论
<?php global $wpdb; $sql = “SELECT DISTINCT ID, post_title, post_password, comment_ID, comment_post_ID, comment_author, comment_date_gmt, comment_approved, comment_type,comment_author_url, SUBSTRING(comment_content,1,30) AS com_excerpt FROM $wpdb->comments LEFT OUTER JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID = $wpdb->posts.ID) WHERE comment_approved = ‘1′ AND comment_type = ” AND post_password = ” ORDER BY comment_date_gmt DESC LIMIT 10″; $comments = $wpdb->get_results($sql); $output = $pre_HTML; $output .= “\n<ul>”; foreach ($comments as $comment) { $output .= “\n<li>”.strip_tags($comment->comment_author) .”:” . “<a href=\”” . get_permalink($comment->ID) . “#comment-” . $comment->comment_ID . “\” title=\”on ” . $comment->post_title . “\”>” . strip_tags($comment->com_excerpt) .”</a></li>”; } $output .= “\n</ul>”; $output .= $post_HTML; echo $output;?>
显示热评文章
<?php $result = $wpdb->get_results(”SELECT comment_count,ID,post_title FROM $wpdb->posts ORDER BY comment_count DESC LIMIT 0 , 10″); foreach ($result as $topten) { $postid = $topten->ID; $title = $topten->post_title; $commentcount = $topten->comment_count; if ($commentcount != 0) { ?>
<li><a href=”<?php echo get_permalink($postid); ?>” title=”<?php echo $title ?>”><?php echo $title ?></a></li>
<?php } } ?>
显示文章分类
<h2>Categories</h2>
<ul><?php wp_list_cats(’sort_column=name’); ?></ul>
显示归档
<h2>Archives</h2>
<ul><?php wp_get_archives(’type=monthly’); ?></ul>
在侧栏显示页面列表
<h2>Pages</h2>
<ul><?php wp_list_pages(’title_li=’); ?></ul>
调用Gravatar(只适应2.5以上)
<?php if(function_exists(’get_avatar’)){ echo get_avatar($comment, ‘50?);} ?>
显示友情链接
<ul><?php get_links_list(); ?></ul>
显示管理员链接
<ul><?php wp_register(); ?>
<li><?php wp_loginout(); ?></li>
<li><a href=”http://www.wordpress.org/”>WordPress</a></li>
<?php wp_meta(); ?>
<li><a href=”http://validator.w3.org/check?uri=referer”>XHTML</a></li>
</ul>
在侧栏显示页面的子页面
<?php$children = wp_list_pages(’title_li=&child_of=’.$post->ID.’&echo=0′);if ($children) { ?>
<ul><?php echo $children; ?></ul>
<?php } ?>
显示Wordpress标签
<?php the_tags(); ?>
显示Wordpress标签云
<?php wp_tag_cloud(’smallest=8&largest=36&’); ?>
模板标题
<?php ?>
动态标题标签
<title><?phpif (is_home()) { echo bloginfo(’name’); } elseif (is_404()) { echo ‘404 Not Found’; } elseif (is_category()) { echo ‘Category:’; wp_title(”); } elseif (is_search()) { echo ‘Search Results’; } elseif ( is_day() || is_month() || is_year() ) { echo ‘Archives:’; wp_title(”); } else { echo wp_title(”); } ?></title>
在独立页面中运行PHP
<?php if ( is_home() ) { include (’file.php’); } ?>
结论
只要掌握了一点这方面的知识,你就可以随意修改任何WordPress主题模板页面了。现在你已经充分了解了WordPress的页面和the loop的运行,就可以征服任何难题了。现在就开始你的博客主题设计之旅吧!

浙江一青年现身兑取5.65亿巨奖 捐2000万创纪录

2011-08-29 14:34:16 来源: 公益时报

核心提示:时隔一个月,浙江5.14亿与5140万已于8月29日上午被兑取,经确认,这5.65亿巨奖为一人独揽……

 

公益时报讯(记者常鹏 王征)8月 29日中午,福彩“双色球”5.65亿元巨奖得主现身浙江省福彩中心,领走我国彩票史上最高的奖金,并主动捐赠 2000万元用于支持新昌县老年人福利事业和困难儿童的救助。由此,他创下了我国彩票史上多项纪录:个人中奖奖金最高、中奖奖金纳税额最大(1.09亿元)、内地中奖公益捐款最多。

中奖彩民是通过浙江省福彩中心绿色通道办理兑奖手续的。在兑奖处,该彩民面带笑容,神色淡定,举止从容,还不时主动与工作人员讲述中奖后的心情。福彩中心工作人员集中在现场完成相关验票、审核、兑付等一系列手续,银行提供了安全快捷的现场服务。根据《彩票管理条例》第二十七条“彩票发行机构、彩票销售机构、彩票代销者以及其他因职务或者业务便利知悉彩票中奖者个人信息的人员,应当对彩票中奖者个人信息予以保密”的规定,应中奖者要求,兑奖过程采取严格的保密措施。福彩中心主管部门和监管部门派出相关人员现场监督全过程。

在兑奖前,中奖彩民先咨询了有关捐赠的问题,工作人员作了详细的解答。兑奖时,中奖人主动提出从奖金中提取2000    万元,捐赠给绍兴市的新昌县,用于老年人福利事业和困难儿童救助。中奖彩民说:“我是在绍兴新昌中的,在这里生活了几十年了,这里也是我中奖福地,所以我十分乐意捐赠一部分奖金,用于帮助老年人和困难儿童。我家本来不困难,以前我们就帮助过一些人,我与爱人商量了,今后每年都会拿出部分钱继续做善事的。” 按照规定,中奖者捐款部分不需要纳税,所以该彩民本次实际缴税为 1.09亿元,他成为我国彩票发行24年来中奖奖金和中奖纳税最高的彩民。

在完成了相关手续后,中奖者戴上早以准备好的憨厚可爱的国宝“熊猫”头套,穿上福彩文化衫,在兑奖现场拍照留念。并愉快谈起了他的中奖过程。

中奖者称,他买彩票已经11年,之前中过1万多元的奖,因为自己做生意,经济条件较好,一般都是采用复式和加倍投注方法。7月26日那天午饭后,要去看朋友,买了送朋友的礼品后还剩下250元,因为“250”不好听,就买了200元,也就是100注同样号码的彩票。其中3个红色号码是他自己选的,那天6点起床就选了“6”,7点吃早饭就选了“7”,吃饭花了9元钱就选了“9”,其他几个是他和爱人平时经常买的号码,因为他和爱人都是9月出生,所以蓝色球就选了“9”。傍晚的时候,到朋友家吃饭,在一个小店里买了点东西,还剩20元零钱,就在边上另一个彩票销售站买了同样号码的10注彩票。所以,三张彩票共110注一等奖都是他一人所中。

工作人员问他有什么话要对全国彩民说?中奖者说:“自己买彩票完全是出于好玩,平时有的时候买了彩票却经常忘记去对奖。这次买了后就到外地去了,知道中奖是10天后的事情,是我爱人听别人谈起,我才想起自己买的彩票。当时,我就以为是老天跟我开了个玩笑,想不到是真的。我中奖完全是运气,没有什么技巧,是运气砸中了我。还有,买彩票一定要根据自己的实力,没有很大实力千万不要买太多,千万不要失去理智,中奖的期望也不要太高。”

浙江省福彩中心主任徐文忠在兑奖现场谈了他的看法:“双色球”是目前全国、也是我省彩民群体最大、销量最高、中出大奖最多的游戏,每次开奖都是电视现场直播的,已经成为福利彩票最知名品牌游戏。但是,彩票是一种低概率、无规律的爱心幸运游戏,中奖号码都是随机产生的。我们长期倡导“寓募于乐、多人少买,量力而行、理性投注”的购买方式,希望广大彩民在不影响生活的基础上用零花钱以娱乐的心态理性购买彩票,把福利彩票当成一个可以经常性参与公益慈善的平台,把购买福利彩票当作一种健康快乐的文化生活方式,以平和的心态对待中奖,量力而行,理智投注。

不少业内人士也特别提醒社会和彩民,彩票是机遇游戏,千万不要把彩票误为投资理财的渠道;要以平常心看待和善待中大奖彩民尤其是中巨奖彩民,为他们能在当地继续平静、美好生活创造最好的社会环境。

梅西当选首届欧洲最佳球员 足坛之王再度加冕

55175886

梅西荣膺新科欧洲最佳球员

腾讯体育讯 北京时间8月26日凌晨,欧足联在摩纳哥蒙特卡洛举行了盛大的欧冠抽签暨颁奖仪式,在引人瞩目的“欧洲最佳球员”(UEFA BEST PLAYER IN EUROPE AWARD)奖项的争夺中,巴萨球星梅西(微博 博客)笑到了最后。阿根廷球星以38票的优势荣膺首届欧洲足球先生,哈维(微博)和C罗分别得到11票和3票。梅西随后也通过腾讯微博第一时间感谢了支持帮助他获得成绩的队友们。

众所周知,在与国际足联的“世界足球先生”奖项合并前,由《法国足球》杂志社主办的“欧洲金球奖”,是世界足坛上最富盛名,影响力最大的足球奖项评选。作为欧足联主席,普拉蒂尼并不甘心“欧洲足球先生”的消亡,在他的倡议下,欧足联决定推出新的“欧洲足球先生”奖项,他们和欧洲体育媒体联盟(ESM)合作,由他们作为欧洲最佳球员的主要评审机构。

新“欧洲足球先生”的评审团将包括53个欧洲国家的体育记者,每名记者按照排名顺序提供一份3人的最佳球员名单,第一选择的球员得到5分,第二选择的球员得到3分,第三选择的球员得到1分。在第一轮投票中,得票数最多的三名球员,将入围到最后一轮的投票中,欧足联已经在7月25日公布了入围决选的三人,分别是梅西、哈维和C罗。此前入围了FIFA金球奖最终候选的伊涅斯塔(微博)以微弱的差距落选。

此次评选,53名体育记者在现场即时投票,主持人将梅西、哈维和C罗三人请到台上,并进行了短暂的采访。经过紧张的投票,欧足联主席普拉蒂尼现身将沉甸甸的“欧洲足球先生”奖座交到了梅西手里,奖座的背后已经刻好了梅西的名字。

作为当今足坛最炙手可热的球星,梅西在过去一个赛季,拿出了非常精彩的表现,他在各项赛事中55次出场打进53球并有24次助攻,跟随巴萨夺得西甲、欧冠和西班牙超级杯三项冠军,虽然在国家队赛事中表现比较平淡,但梅西仍然得到了绝大多数人的认可,这也是跳蚤继荣膺首届FIFA金球奖后,再获殊荣。

(kerlon)

WordPress CKEditor smiley表情图标定制化

WordPress默认的编辑器不是很好用,我习惯将它替换成CKEditor,安装CKEditor For WordPress即可。安装后编辑器将被替换,评论框的编辑器默认会被替换成CKEditor,有时候会导致模板样式错乱,可以在CKEditor->Basic Settings中禁用。

CKEditor默认的smiley表情不适合中国,我们可以将表情改造一下换成自己喜欢的表情,方法如下。

1. 下载你想要的表情包,一般是gif格式的图片,假设这些图片所在的文件夹叫mysmiley,将该文件夹拷贝到插件的表情目录中,路径为

wp-content/plugins/ckeditor-for-wordpress/ckeditor/plugins/smiley/images

2. 修改配置文件wp-content/plugins/ckeditor-for-wordpress/ckeditor.config.js

在CKEDITOR.editorConfig = function(config) { … }中添加如下代码

config.smiley_path=CKEDITOR.basePath+’plugins/smiley/images/mysmiley/’;

config.smiley_images=[‘1.gif’,’2.gif’];

第一行代码定义了表情文件所在的文件夹的路径,第二行是表情文件名字的数组。这样点击编辑器的表情按钮,自定义图标就会显示出来。

当你的图标过多时,由于显示不开会导致一部分图标无法显示,而且表情图标对话框没有滚动条,为了避免这种问题,我们可以修改一下css文件。找到wp-content/plugins/ckeditor-for-wordpress/ckeditor/skins/kama/dialog.css(假定你使用了默认的皮肤kama),在最后一行添加如下代码

.cke_dialog_ui_html{height:350px;overflow:auto;}

这个文件是经过压缩的,所以添加代码时注意不要有空格。height定义对话框的高度,可以根据自己的需要写。这样表情多时会出现滚动条,就可以正常使用了。如果你的表情很少,就不要做这个改动,不然显示会出问题。

下面是几个已经做好的表情包和大家分享一下,配置语句写在压缩包的readme.txt中

1. 洋葱头系列表情

下载地址:CKEditor洋葱头表情图标下载

2. qq表情图标

下载地址:CKEditor QQ表情

sqlserver 迁移到mysql详细步骤数据库表结构迁移

最近在开发的一个项目,需要从MS SQLServer迁移到MYSQL,以下把迁移过程记录下来,与大家共享!

sqlserver迁移到mysql 在数据库方面的工作主要是表的迁移,以及存储过程的迁移,这里先说说表的迁移.

首先先将MSSQL Server表结构导出为.sql文件. 表迁移,mysql一律不能运行带有[,],dbo.等带有sqlserver特征的脚步, 所以在导出的sqlserver脚步里面,首先要把这些字符全部过滤掉(可使用editplus进行过滤),在表创建方面的不支持的字符如下:[,],[dbo].,GO, on primary,.

在过滤完以上的字符后, 由于导出的sql文件都包含多个表, 为了能够一次性装载完所有的scripts并运行,需要在每个表的create语句后面加上分号, (同时还有加上ENGINE=InnoDB),否则你会发现只能一个一个表的进行运行,比如原来是这样:

CREATE TABLE bmapnamebidsg (
bword nvarchar (100) NOT NULL ,
bids text NULL ,
status int NOT NULL ,
cr_date datetime NOT NULL
)

CREATE TABLE BookStaticSortStatus (
sid int NOT NULL ,
sortStatus int NOT NULL ,
mxReviewStatus int NOT NULL ,
lReviewStatus int NOT NULL ,
up_date datetime NOT NULL
)

改动后是这样的:

CREATE TABLE bmapnamebidsg (
bword nvarchar (100) NOT NULL ,
bids text NULL ,
status int NOT NULL ,
cr_date datetime NOT NULL
)ENGINE=InnoDB ;

CREATE TABLE BookStaticSortStatus (
sid int NOT NULL ,
sortStatus int NOT NULL ,
mxReviewStatus int NOT NULL ,
lReviewStatus int NOT NULL ,
up_date datetime NOT NULL
)ENGINE=InnoDB ;

接下来就是数据类型了!

在数据类型方面,mysql基本对应了sqlserver的数据类型, 向bit,text,varchar,等,都对应得比较好, 但是,mysql并不支持smalldatetime(这个是sqlserver特有的),需要转成datetime,另外, sqlserver中的identity自增长属性在mysql中则表现为auto_increament属性,并且声明该属性的列必须是key!

最后我们看看主键,索引以及缺省值如何对应,一些是MS SQLServer(建一个主键,为两个字段定义缺省值,再为一个字段定义成索引):

ALTER TABLE BookStaticSortStatus WITH NOCHECK ADD
CONSTRAINT PK_BookStaticSortStatus PRIMARY KEY CLUSTERED
(
sid
)

ALTER TABLE BookStaticSortStatus ADD
CONSTRAINT DF_BookStaticSortStatus_status DEFAULT ((-1)) FOR sortStatus,
CONSTRAINT DF_BookStaticSortStatus_up_date DEFAULT (getdate()) FOR up_date

CREATE INDEX [sort2_books] ON [dbo].[books]([s2id]) ON [PRIMARY]

MySQL:

CREATE TABLE `bmapnamebidsg` (
`bword` varchar(100) character set utf8 NOT NULL default ‘1’,
`bids` text NOT NULL,
`status` int(11) NOT NULL,
`cr_date` datetime NOT NULL,
PRIMARY KEY (`bword`),
KEY `bids` (`bids`(1))
) ENGINE=InnoDB DEFAULT CHARSET=latin1

完成以上动作,表结构的迁移就基本完成了!

基于xmlrpc的PingBack 规范形象介绍 在wordpress中广泛使用

Pingback是在博客圈的背景下诞生的一个新鲜玩意,说白了,其目的等同于csdn上的trackback。不过,它有更加完善的机制,而且用php很容易实现。
传统的博客是这样的,我写了篇很牛X的文章,你不巧看到了,但是我的观点你不同意,而且更不巧,你还非常喜欢抬杠,为了能和我抬杠,你就得在我的博客上留言,而且你啰里啰唆的打了1000个字上去。问题是,我不喜欢抬杠,所以我限制留言字数为100字。
问题来了,如果你对我的博客文章有几K个字节的感想,单单发表在我的博客评论里显得有点屈才。你可以在你的博客里重新发布一篇文章,为了让我知道你的大作,以便我们抬杠,你还得给我发封电子邮件告诉我。这个流程虽然不怎么复杂,但还是很麻烦。
Pingback简化了这个流程,只要在你啰里啰唆的评论里加个超链接,指向我的文章。我就会收到有关你的评论,而且还会自动显示在我的博客评论中。
神奇吧,神奇的背后是老瓶装新酒。要理解Pingback,最好有点web服务的知识,不知道也没关系,所谓web服务就是俩服务器之间没事倒腾数据玩,当然,俩服务器得使用同一种语言进行交流。目前,有两种倒腾语言,SOAP和xmlrpc,php5已全面支持。SOAP稳定可靠,但是很复杂,xmlrpc就简单实用的多。pingback就是基于xmlrpc实现的。
来看看具体的操作流程:
1、首先我发布文章,我的文章地址是:http://www.renseng.com/learning/dede-cms-remove-page-index-html.html。如果你乐意打开这个网页,并看下源文件,会注意到,在页面上有个link元素,内容是<link rel=”pingback” href=”http://www.renseng.com/xmlrpc.php” />。这玩意标示了一个pingback服务器的地址:http://www.renseng.com/xmlrpc.php。
2、然后你看了文章,开始在你的博客写你的啰里啰唆的评论,评论一开始可能会这样:carche在<a href=”http://www.renseng.com/learning/dede-cms-remove-page-index-html.html”>CURL……….</a>中 提到,我对此不敢苟同…………….
3、之后提交你的文章,如果你的blog系统是wordpress架构,当你提交文章之后,wordpress会扫描你文章中提到的链接,这时它发现了http://www.renseng.com/learning/dede-cms-remove-page-index-html.html这个链接。wordpress会抓取这篇文章,然后用一个像这样的正则表达式  ”/<link\s+rel=\”?pingback\”?\s+href=\”?(^>*)\”?\s+>/” 来寻找pingback服务器地址,找到这个地址后,开始倒腾数据。
4、你的blog系统会给找到的pingback服务器发送以下信息:你好,在某某博客文章中曾经引用了http://www.renseng.com/learning/dede-cms-remove-page-index-html.html这个超链接。
5、我的pingback服务器收到信息之后,先检查一下是不是确实有这回事,如果是就返回随便什么字符;如果不是,就返回一段错误码。之后,我的blog系统会根据你请求的信息,到你的评论里面抓取内容,并显示在我的blog评论中。
大致流程是这样的,如果要看详细的规范,参考:http://www.hixie.ch/specs/pingback/pingback

什么样的女人会被老公一生捧在手心?

1[9]   

 2 2 

在老公眼中每个女人都应是一朵永不凋谢的花。
如果有一天,你感觉到自己在老公眼中,已经开始失去某种独特的魅力,那么聪明的女人应该做的,不是怨恨老公的花心,不是埋怨世界的诱惑,不应任其漠视,甚至摆出一副弃妇的可怜相,怨妇的可悲相,而是该认真地反省一下自身了。
1、你是否还在意自己在他面前的形像,这个形像不仅包括衣着、举止、谈吐、更包括内在的修练,如含蓄、如知识面、如韵味、如对人和事的包容之心、爱心、对生活和事物的热情度等。
2、生活比树叶还稠。人活在这个世上,会遭遇到很多不如意事。老公其实比你面对的更沉重更繁多,他肩上的担子更重,其实,他的表面坚强,但他的身心也许远比女人更脆弱。即使年轻时他是处处关护你的,日积月累,你必得学会关护他。而且随着年纪的增长,你还得能像母亲爱孩子那样去小心体贴他,才能使他在外面的风雨之后,感受到家的温暖,越来越依恋家的安全与安宁。
3、是最重要的,也往往是女人会忽略的。女人往往会认为,老公理当养家。其实这个世界上,真正成功的人并不多。绝大多数都是为了基本的生存而努力,为孩子、老人、为基本的生存环境,为房、为车、为暖气费、为人情来往、为体面一些状态。女人,也必得努力分担老公在养家上的辛苦。其实很多女人也这样做了。但是你不能以为你也和丈夫一样挣钱并工作了,而抱怨老公,抱怨生活,怨天尤人,甚至怒气冲冲。
其实如果你天命如此,不管你当初选择嫁给的是谁,日子一样还有别的意料不到的烦恼和坎坷。即使你不嫁人,也好不到哪里去。因为夫妻相互搀扶着过日子,相互关爱,日子可能过得更容易些。你也许只能显得更年轻一些,身心也更为健康一些。
4、有些女人经过努力和拚打,可能会比男人对家的贡献更大一些。更要切记:为家做了些贡献后,女人更不能不可一世,颐指气使,这样你就真的是尊贵威严的女王,做为丈夫,除非他是天生的爱做奴仆,他心理最需要的,你必得首先仍旧还要是一个妻子。
很多有本事的女人,一旦遗弃原来的伴侣,会发觉好的、新的伴侣并不像原来想的那么容易寻到。如果你是聪明女人乘你有成就,最该扶持和提携的人,其实恰恰就是你身边的人。但切记:要不动声色,不要处处提醒他报恩记恩。
你对别人付出的,不管是任何人,也不管是你多么亲近的人,你提醒别人记住的次数越多,层度越重,你得到的结果正好相反。如果不信,你换位思考一下:哪个曾给了你帮助,他老是在你面前不停地提醒你记住,你会怎么想?你会不会想:他老提这个,是怕我忘了?还是想让我加倍回报?
其实不管你嫁了谁,你都一样还得这么活着。你的青春一样都要渐渐失去,红颜仍旧要一天天的裉却。虽说你衰老的程度与生活有关,但是你的衰老,其实与丈夫无关。
5、在这世界上,真正能天天窝在沙发里看书、上网、看肥皂剧,而不为家庭、不为孩子、也不为丈夫操一点心的主妇没有几个。真正那样的女人,即使你再美丽年轻,你的美丽也会随着无聊的日子而渐渐变得苍白失血。没有一个女人魅力,会永远无所事事还能始终保鲜的。
随着年纪的增长女人的魅力,说穿了在于内在的修练,在于能力的增长,在于智慧和知识的增加。武则天有一句话,应该对每人女人都极有用处:以色侍君,岂能长久?
6、丈夫为什么会有恋母情结?那正好说明了男人其实心理上一样渴望关爱的。
对于孩子女人是母亲,是慈祥的可依可靠的安全的港湾。对于丈夫年长日久,女人其实也一定会是丈夫可依可靠的宁静港湾。你表层要把他当成天来爱,内心你还要允许他有时还是个大孩子。要鼓励他的自信,有时偶尔也要严厉指出他的沉沦。
但更多的仍旧还是让他感觉到你对他的依恋和依赖,你也可以随时玩些小花招儿——是那种不断给他些意外的惊喜的小花招儿,他会越来越贪恋你的这份“母爱”。当然,在他明显无理时,而且劝说他不动时,你也可以突然玩一下“假失踪”,让他感觉一下失去你的孤独和失落。
7、爱笑,爱哭也许都不是丈夫憎恶你的原因。相反还是他怜惜你的理由。
可怕的是,你的怒气和怨气,你的永无止境的抱怨,会使原本十分热爱你甚至离不开你的丈夫离你而去。即使他在形体上还没有离开你,他的心也迟早会离你而去。夫妻有了一点矛盾,切忌不要呕气。“把儿活”的男人女人,都比死倔彆子的可爱,易相处。有了不快,迅速忘记,或是迅速找别的有趣的话题茬开,才是聪明的妻子。
智慧的女人,会赞美丈夫。晦气的女人,只知道报怨他人,得到的也只能是晦气。比如:丈夫突然心血来潮,为你做了一碗面,虽说很难吃,你也千万不要打击他的积极性。他出差回来,给你带了一件衣服,虽说不合你的意,可是,他都是对你的一份惦记和情意啊。此时,你该做的是赞美,由衷地赞美他对你的这份情爱,感受和品味这份情,他会越来越爱你,乐意为你付出。
姐妹们人活在这个世上,更多的时间是不如意的,是艰难的。所以当你们夫妻回到家中,彼此能做的,能维护幸福一生的事,就是尽量删除不良情绪的病毒,不要因为亲人之间没必要的内斗和内耗,损失毁了你们享受快乐、享受幸福、享受宁静的空间。
家是属于你们共同的天地。在这个世界上,有这个家,太不容易了,有这份夫妻情份,也是几百年多少世修来的缘份。只要你宽厚了,努力了,做到了,悟透了,不管是在生活中,还是在工作中,你不仅能成为一个被丈夫宠爱的幸福的快乐的小女人,也会是一个被朋友和同事,被父母和兄妹欢迎的大女子。 
333
如何哄得丈夫一生一世永远爱你不变? 如何做才能永远不会失去丈夫的爱?
有一种现象,一种婚姻中很可怕和的现象:在许多老年人当中,到了生命老迈时期,往往很多家庭,只剩下一位老年女的,丈夫会比妻子要早许多年就因为种种病因而过世了。
我们到晚年,不管年纪多大,也不管身体状态怎么样,只要有老公始终陪着你,就算活到八十,活到九十,活到一百,你也不会感到凄凉和孤独。即使到了暮年,夫妻相伴,白天一起看电视看报纸听收音机,一起旅游一起到好朋友家喝茶聊天,一起到花园和草坪散步,那份快乐,那份自得,其实是多少儿女都无法替代的,也是任何人都无法替代的。更何况现在的人,大多也只能有一个孩子。
按一般人的认识,男人比女人坚强,女人生儿育女,肯定身体不如男人。可是为什么许多老人,大多都是老公撇下老妻先走了呢?其实,男人并非像女人以为的那样坚强。他们的坚强,是因为他们把人生遇到的所有屈辱、失落、挫败、病痛、沮丧、生活的压力和人生的沉重,全都隐忍在自己心中,不肯说出来,不肯表现出来罢。而所有的这些隐忍在心的情绪,其实,全都像一个又一个的“电脑病毒”积累到最后,结果就是崩盘,死机。
男人为什么会醺酒?为什么会抽烟?为什么会沉思?
更多的原因,其实是他心理已经积存了太多的病毒。就因为他是男人,他不能轻易流泪,更不能轻易向人诉说。他必得在妻子,在儿女,在父母面前做出硬汉子的形象。
而女人却习惯哪怕一点点的委屈,都会向丈夫,向父母,向姐妹们,向好友倾诉出来,女人病毒不会积存。她会在每一次的倾诉和泪水中,清理皆净。
而人类几乎所有的疾病,更多的原因就是郁积出来的。所以情绪爱喧泄出来的女人,往往寿命长久。而男人却早于妻子离开人世。
44 
怎么样才能让老公尽可能活得更长久尽可能陪你到老?从现在做立即行动!那么你该着手做些什么事?
一、当老公回到家中,尽可能给他营造一个温馨轻松的环境。其实没有重要客人来访,干嘛一定非要把地拖得一尘不染?衣服干嘛非要当时就洗?为什么一定要把本该在家中休闲放松的时间,弄得两人都紧紧张张的?而夫妻两口,磨嘴的时候,多是家务。
二、当老公在外面不快时,即使他不说,你也要尽可能去察觉,一面用爱心关怀他,给他做个下酒菜,倒一杯酒,讲些幽默的段子,先转移他的不快,接着慢慢寻问。
如果他不想告诉你,甚至不想提及,你一定不要再继续打听。他一定是受了很重的内伤,此时男人是习惯自己舔伤口的。你能做的是一个字:爱!体贴!温柔!这虽不一定能排解他的内心的郁积和伤口,但一定会是止痛剂和消炎药。
如果他肯说了,那么不管他说出来的是什么事,你都不能在此时抱怨他了。你能做的,就是开导和疏导他转移不良情绪。其实他的所有不快,说穿了决不会超过“名利”二字的范围。再则就是和人起了争执,受了领导的指责。
如果你最在意的是老公的健康,是老公能陪你到老,你就不该最在意丈夫的名利,命中该有的终须会有。没有的挣死,也来不了。硬撑着挣来的,还会失去。不在这方面失去,必会在另一方面失去,这是铁定的规律。 你如果不在意了,丈夫会活得十分轻松。这种轻松恰恰会成就你们得到许多的惊喜!
三、酒不可过量。酒场上逞英雄的,其实大家表面夸他,转脸都会当他是傻瓜。烟如果实在断不了,尽可能不要吸劣质烟,但一定说服他少吸烟。
四、如果必须得和年老的婆母同住,没有条件和并不年老的婆母分开居住,你就一定要接受现实,尽量和婆母搞好关系。因为你容不下丈夫的母亲,你们的矛盾,你们的每一场战争,都必会减弱丈夫数月一年甚至几年的寿命。反过来他如果天天和你母亲不和吵闹,你该怎么办?压抑而无奈又夹在板中的你,肯定一样也会减寿的 。
做到以上四点,下面的就容易多了:
你要是爱你丈夫,就不要多弄那些煎炸烹炒的食物给他吃,这个不能由着他的性子。多做一些素菜和凉拌菜。要像哄孩子那样哄他吃这些。
当他吃完这些清淡的素菜之后,他也会发觉,过去那种老吃油水大的煎炸食物后,莫名其妙的头昏脑涨,无精打彩和昏昏欲睡等等说不出原因的不良状态,会骤然改善。
你要是想丈夫陪你到老,你要和尽可能让丈夫参回有氧活动:跑步、快走、打球、旅行、爬山、打拳、哪怕没有条件,在屋内活动一下筋骨,地板上打几个滚,都一样能起到锻炼的目的。
你要想你丈夫陪你到生命的尽头,你就要关护他像关护孩子一样。只要你是真爱他那个人的,而没有太多的附加条件,你一定乐意试试。
你这样做了你会发现,他会活得很开心,会活得很热烈,会活得很有成就感,会活得很健康,他一定会回报你的。那是你始料不及的。
即使他很普通,但他一定是真爱你的,他也一定不会先走,他会一直陪着你,活得很久很久,一直陪你到生命的尽头。
姐妹们,当我们老到白发苍苍时,当我们老到腿脚酸疼时,当我们老到腰弯,可是只要有老公陪在身边,你会知道千万资产,也不如一个陪了你一生一世的老公为你端来一杯热茶,数来几片药片。
当我们老到满脸皱纹时,多少昂贵的礼服和化妆品,也不如老公轻轻地挽着你的胳臂走在夕阳的草丛中。当我们老得只能在摇椅里甚至轮椅里摇啊推时,你会发觉,什么豪宅权威功名,也抵不上夜半变天时,老公为你加打开电热毯和一声问侯。
为什么要从现在做起而不是将来?
因为一棵树,越早矫正它就直得越早,老公也如此,越早注意对他的关爱,他的身心就会一直健康,即使有了病毒,也会被你的爱及时清除,而不至于积留到未来。
你能做到这些,能使他的身心得到健康的同时,因为你们是一起生活的,所以你自己也必将快乐和健康,在督促他进取的同时,你也必将懂得努力修炼,增加自己的核心竞争力。
姐妹们!为了你的晚年不会冷清孤独,为了你和所爱的人都长寿并健康,其实这世上其它的身外之物,又算得了什么?现在就开始行动吧!

偶尔看到,非常喜欢,转载过来于朋友们分享,所有的爱都是从点滴做起
朋友们好好珍惜爱你的人和你爱的人哦!

服务员冲厨房喊道:"出来个师傅,帮这位顾客把这块牛肉切一下!"

男子喊道:"服务员,过来一下!" 服务员:"您好,什么事?" 男子怒问:"我20块钱一碗的牛肉面,怎么才一块牛肉?" 服务员:"先生,那您希望有几块?" 男子想了想说:"怎么也得五六块牛肉吧。" 服务员冲厨房喊道:"出来个师傅,帮这位顾客把这块牛肉切一下!"

留意留意!!有没有这样的人?外表活泼内心孤僻的人会做的事

【外表活泼内心孤僻的人会做的事】1手机不离身;2对待不同的人有不同的性格;3从小懂得很多道理;4有时候很神经 有时候很镇静;5会因为别人一句话伤心 但不会被发现;6安慰很多人 但自己却没人安慰;7会怀念从前 讨厌现在;8有时候会笑的没心没肺 有时却很沉默。你是这样吗?

Live Writer WordPress XMLRPC Error Invalid

The response to the metaWeblog.newPost method received from the weblog server was invalid:
Invalid response document returned from XmlRpc server

前几天用lw发文章突然出现上面错误,在网上找了很多方法都没能解决,最后仔细回想,我最近更改了主题

我查看了最近更改的所有文件,最后发现 functions.php文件是UTF-8 带BOM的,赶紧移除,问题解决。

小结:用windows 平台编辑UTF-8 编码文件,上传之前最后做一下移除BOM的操作,要不出现问题时找起来很费力气,因为程式是没有问题的

XML Schema 与 XML DTD的技术比较与分析

引言

XML DTD(XML的文档类型定义)是近几年来XML技术领域所使用的最广泛的一种模式。但是,由于XML DTD并不能完全满足XML自动化处理的要求,例如不能很好实现应用程序不同模块间的相互协调,缺乏对文档结构、属性、数据类型等约束的足够描述等等,所以W3C于2001年5月正式推荐XML Schema为XML 的标准模式。显然,W3C希望以XML Schema来作为XML模式描述语言的主流,并逐渐代替XML DTD。那么XML Schema与XML DTD相比到底有哪些优势呢,XML DTD是否真的会在XML的模式描述领域中逐渐消失呢?

XML模式与XML格式

XML模式是指用来描述XML结构、约束等因素的语言,例如XML Schema、XML DTD、XDR,SOX等等。XML格式则是XML文档本身所具有的格式。本文以XML Schema来代表W3C所推荐的XML Schema模式标准,而以”XML模式”来代表所有的XML模式描述语言。

从模式的描述语言来说,XML Schema和XML DTD都属于语法模式。与概念模式不同,语法模式在对同一事物描述时,可以采用不同的语法,例如在对关系模式描述时,无论是使用XML Schema还是XML DTD,都既可以用元素也可以用属性来描述关系模式的列。

模式必须以某种格式来表示,XML Schema的格式与XML DTD的格式有着非常明显的区别,XML Schema事实上也是XML的一种应用,也就是说XML Schema的格式与XML的格式是完全相同的,而作为SGML DTD的一个子集,XML DTD具有着与XML格式完全不同的格式。这种区别会给XML Schema的使用带来许多好处:

  1. XML用户在使用XML Schema的时候,不需要为了理解XML Schema而重新学习,节省了时间;
  2. 由于XML Schema本身也是一种XML,所以许多的XML编辑工具、API 开发包、XML语法分析器可以直接的应用到XML Schema,而不需要修改。
  3. 作为XML的一个应用,XML Schema理所当然的继承了XML的自描述性和可扩展性,这使得XML Schema 更具有可读性和灵活性。
  4. 由于格式完全与XML一样,XML Schema除了可以像XML一样处理外,也可以同它所描述的XML文档以同样的方式存储在一起,方便管理。
  5. XML Schema与XML格式的一致性,使得以XML为数据交换的应用系统之间,也可以方便的进行模式交换。
  6. XML有非常高的合法性要求,XML DTD对XML的描述,往往也被用作验证XML合法性的一个基础,但是XML DTD本身的合法性却缺少较好的验证机制,必需独立处理。XML Schema则不同,它与XML有着同样的合法性验证机制。

数据类型

或许,对于许多开发人员来讲,XML Schema与XML DTD相比的一个最显著的特征,就是其对数据类型的支持了。这完全是因为XML DTD提供的数据类型只有CDATA 、Enumerated、NMTOKEN 、NMTOKENS等十种内置(built-in)数据类型。这样少的数据类型通常无法满足文档的可理解性和数据交换的需要。XML Schema则不同,它内置了三十七种数据类型,如long,int,short,double等常用的数据类型,并通过将数据类型表示为由value space、lexical space和facet三部分组成的三元组而获得更大的灵活性。但是, XML Schema数据类型的真正灵活性来自于其对用户自定义类型的支持。XML Schema提供两种方式来实现数据类型的定义。

1)简单类型定义(simpleType),即在XML Schema内置的数据类型基础上或其它由XML Schema内置的数据类型继承或定义所得到的简单的数据类型(simpleType)基础上,通过restriction,list 或者 union方式定义新的数据类型。

 

更多信息:http://www.ibm.com/developerworks/cn/xml/x-sd/