rsync结合inotify实现实时同步
rysnc备份服务结合inotify
搭建
服务器端
1.首先关闭selinux,iptables
xxxxxxxxxx
setenfore 0
systemctl stop firewalld
上面是临时关闭,永久关闭如下:
xxxxxxxxxx
sed -ir 's/SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
source /etc/selinux/config
systemctl disable firewalld
2.编辑 /etc/rsyncd.conf文件
xxxxxxxxxx
uid = rsync
gid = rsync
use chroot = no
max connections = 100
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsyncd.lock
log file = /var/log/rsyncd.log
[backup]
path = /var/backup
comment = rsync backup directory
ignore errors
read only = no
hosts allow = *
list = false
auth users = rsync_backup
secrets file = /etc/rsync.passwd
3.创建密码文件并修改权限
xxxxxxxxxx
[root@controller ~]# vim /etc/rsync.passwd
rysnc_backup:123456
[root@controller ~]# chmod 600 /etc/rsync.passwd
4.创建备份目录,并修改权限
xxxxxxxxxx
[root@controller ~]# mkdir /var/backup
[root@controller ~]# chown rsync.rsync /var/backup
5.重启服务即可
xxxxxxxxxx
systemctl restart rsyncd
客户端
1.配置密码文件/etc/rsync.passwd
xxxxxxxxxx
[root@node1 ~]# vim /etc/rsync.passwd
123456
2.推送文件到服务器
xxxxxxxxxx
[root@node1 ~]# rsync -avz test.txt rsync://rsync_backup@192.168.139.105/backup --password-file=/etc/rsync.passwd
#或者
[root@node1 ~]# rsync -avz test.txt rsync_backup@192.168.139.105::backup --password-file=/etc/rsync.passwd
#将以上命令写进cron定时任务实现定时备份
结合inotify实现实时同步
1.安装inotify工具
xxxxxxxxxx
yum -y install inotify-tools
2.选项说明
- -m 持续监控
- -r 递归
- -q 静默,仅打印时间信息
- –timefmt 指定输出时间格式
- –format 指定事件输出格式
%Xe 事件
%w 目录
%f 文件 - -e 指定监控的事件
access 访问
modify 内容修改
attrib 属性修改
close_write 修改真实文件内容
open 打开
create 创建
delete 删除
umount 卸载 - inotify监控效果如下
xxxxxxxxxx
[root@node1 ~]# /usr/bin/inotifywait -mrq --format '%Xe %w %f' -e create,modify,delete,attrib,close_write /tmp
MODIFY /tmp/ test
CLOSE_WRITEXCLOSE /tmp/ test
ATTRIB /tmp/ test
rsync+inotify 脚本
简洁版
xxxxxxxxxx
[root@node1 ~]# vim rsyn-inotify.sh
[root@node1 ~]# cat rsyn-inotify.sh
#!/bin/bash
dir=/tmp/backup
/usr/bin/inotifywait -mrq --format '%w %f' -e create,delete,attrib,close_write $dir | while read line;do
cd $dir && rsync -az -R --delete . rsync_backup@192.168.139.105::backup --password-file=/etc/rsync.passwd >/dev/null 2>&1
done &
优化版:
#!/bin/bash
src=/tmp/backup # 需要同步的源路径
des=backup # 目标服务器上 rsync --daemon 发布的名称,rsync --daemon这里就不做介绍了,网上搜一下,比较简单。
rsync_passwd_file=/etc/rsyncd.passwd # rsync验证的密码文件
ip1=192.168.139.105 # 目标服务器1
#ip2=192.168.0.19 # 目标服务器2
user=rsync_backup # rsync --daemon定义的验证用户名
cd ${src} # 此方法中,由于rsync同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致,有兴趣的同学可以进行各种尝试观看其效果
/usr/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib,close_write,move ./ | while read file # 把监控到有发生更改的"文件路径列表"循环
do
INO_EVENT=$(echo $file | awk '{print $1}') # 把inotify输出切割 把事件类型部分赋值给INO_EVENT
INO_FILE=$(echo $file | awk '{print $2}') # 把inotify输出切割 把文件路径部分赋值给INO_FILE
# echo "-------------------------------$(date)------------------------------------"
# echo $file
#增加、修改、写入完成、移动进事件
#增、改放在同一个判断,因为他们都肯定是针对文件的操作,即使是新建目录,要同步的也只是一个空目录,不会影响速度。
if [[ $INO_EVENT =~ 'CREATE' ]] || [[ $INO_EVENT =~ 'MODIFY' ]] || [[ $INO_EVENT =~ 'CLOSE_WRITE' ]] || [[ $INO_EVENT =~ 'MOVED_TO' ]] # 判断事件类型
then
# echo 'CREATE or MODIFY or CLOSE_WRITE or MOVED_TO'
rsync -azcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} >/dev/null 2>&1 #&& # INO_FILE变量代表路径哦 -c校验文件内容
#rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
#仔细看 上面的rsync同步命令 源是用了$(dirname ${INO_FILE})变量 即每次只针对性的同步发生改变的文件的目录(只同步目标文件的方法在生产环境的某些极端环境下会漏文件 现在可以在不漏>文件下也有不错的速度 做到平衡) 然后用-R参数把源的目录结构递归到目标后面 保证目录结构一致性
fi
#删除、移动出事件
if [[ $INO_EVENT =~ 'DELETE' ]] || [[ $INO_EVENT =~ 'MOVED_FROM' ]]
then
# echo 'DELETE or MOVED_FROM'
rsync -azR --delete --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} >/dev/null 2>&1 # &&
# rsync -avzR --delete --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
#看rsync命令 如果直接同步已删除的路径${INO_FILE}会报no such or directory错误 所以这里同步的源是被删文件或目录的上一级路径,并加上--delete来删除目标上有而源中没有的文件,这里不
能做到指定文件删除,如果删除的路径越靠近根,则同步的目录月多,同步删除的操作就越花时间。
fi
#修改属性事件 指 touch chgrp chmod chown等操作
if [[ $INO_EVENT =~ 'ATTRIB' ]]
then
# echo 'ATTRIB'
if [ ! -d "$INO_FILE" ] # 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync会顺带更新此目录。
then
rsync -azcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} >/dev/null 2>&1 #&&
# rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
fi
fi
done &
html,body { font-size: 12pt }
body { font-family: Helvetica, “Hiragino Sans GB”, “微软雅黑”, “Microsoft YaHei UI”, SimSun, SimHei, arial, sans-serif; line-height: 1.6; margin: 0 auto; padding: 1.25rem 1rem }
h1,h2,h3,h4,h5,h6 { margin: 1.25rem 0 0.625rem; padding: 0; font-weight: bold }
h1 { font-size: 1.67rem }
h2 { font-size: 1.5rem }
h3 { font-size: 1.25rem }
h4 { font-size: 1.17rem }
h5 { font-size: 1rem }
h6 { font-size: 1rem; color: #777777; margin: 1rem 0 }
div,p,ul,ol,dl,li { margin: 0 }
blockquote,table,pre,code { margin: 8px 0 }
ul,ol { padding-left: 2rem }
ol.wiz-list-level1>li { list-style-type: decimal }
ol.wiz-list-level2>li { list-style-type: lower-latin }
ol.wiz-list-level3>li { list-style-type: lower-roman }
blockquote { padding: 0 0.75rem }
blockquote>:first-child { margin-top: 0 }
blockquote>:last-child { margin-bottom: 0 }
img { border: 0; max-width: 100%; height: auto !important; margin: 2px 0 }
table { border-collapse: collapse; border: 1px solid #bbbbbb }
td,th { padding: 4px 8px; border-collapse: collapse; border: 1px solid #bbbbbb; min-height: 28px }
.wiz-hide { display: none !important }
html { height: 100% }
body { min-height: 100% }
a { }
img::selection { background-color: rgba(0, 0, 255, 0.3) }
.wiz-table-container { border: 0px !important }
.wiz-table-body { border: 0px !important; position: relative; margin: 10px 0 }
.wiz-table-body table { margin: 0; outline: none }
td,th { outline: none }
undefinedundefined
–> { }
.MathJax_Hover_Frame { border: 1px solid #A6D !important; display: inline-block; position: absolute }
.MathJax_Menu_Button .MathJax_Hover_Arrow { position: absolute; cursor: pointer; display: inline-block; border: 2px solid #AAA; font-family: “Courier New”, Courier; font-size: 9px; color: #F0F0F0 }
.MathJax_Menu_Button .MathJax_Hover_Arrow span { display: block; background-color: #AAA; border: 1px solid; line-height: 0; padding: 4px }
.MathJax_Hover_Arrow:hover { color: white !important; border: 2px solid #CCC !important }
.MathJax_Hover_Arrow:hover span { background-color: #CCC !important }
#MathJax_About { position: fixed; left: 50%; width: auto; text-align: center; border: 3px outset; padding: 1em 2em; background-color: #DDDDDD; color: black; cursor: default; font-family: message-box; font-size: 120%; font-style: normal; text-indent: 0; text-transform: none; line-height: normal; letter-spacing: normal; word-spacing: normal; white-space: nowrap; float: none; z-index: 201 }
#MathJax_About.MathJax_MousePost { outline: none }
.MathJax_Menu { position: absolute; background-color: white; color: black; width: auto; padding: 2px; border: 1px solid #CCCCCC; margin: 0; cursor: default; font: menu; text-align: left; text-indent: 0; text-transform: none; line-height: normal; letter-spacing: normal; word-spacing: normal; white-space: nowrap; float: none; z-index: 201 }
.MathJax_MenuItem { padding: 2px 2em; background: transparent }
.MathJax_MenuArrow { position: absolute; right: .5em; padding-top: .25em; color: #666666; font-size: .75em }
.MathJax_MenuActive .MathJax_MenuArrow { color: white }
.MathJax_MenuArrow.RTL { left: .5em; right: auto }
.MathJax_MenuCheck { position: absolute; left: .7em }
.MathJax_MenuCheck.RTL { right: .7em; left: auto }
.MathJax_MenuRadioCheck { position: absolute; left: 1em }
.MathJax_MenuRadioCheck.RTL { right: 1em; left: auto }
.MathJax_MenuLabel { padding: 2px 2em 4px 1.33em; font-style: italic }
.MathJax_MenuRule { border-top: 1px solid #CCCCCC; margin: 4px 1px 0px }
.MathJax_MenuDisabled { color: GrayText }
.MathJax_MenuActive { background-color: Highlight; color: HighlightText }
.MathJax_MenuDisabled:focus,.MathJax_MenuLabel:focus { background-color: #E8E8E8 }
.MathJax_ContextMenu:focus { outline: none }
.MathJax_ContextMenu .MathJax_MenuItem:focus { outline: none }
#MathJax_AboutClose { top: .2em; right: .2em }
.MathJax_Menu .MathJax_MenuClose { top: -10px; left: -10px }
.MathJax_MenuClose { position: absolute; cursor: pointer; display: inline-block; border: 2px solid #AAA; font-family: “Courier New”, Courier; font-size: 24px; color: #F0F0F0 }
.MathJax_MenuClose span { display: block; background-color: #AAA; border: 1.5px solid; line-height: 0; padding: 8px 0 6px }
.MathJax_MenuClose:hover { color: white !important; border: 2px solid #CCC !important }
.MathJax_MenuClose:hover span { background-color: #CCC !important }
.MathJax_MenuClose:hover:focus { outline: none }
.MathJax_Preview .MJXf-math { color: inherit !important }
.MJX_Assistive_MathML { position: absolute !important; top: 0; left: 0; clip: rect(1px, 1px, 1px, 1px); padding: 1px 0 0 0 !important; border: 0 !important; height: 1px !important; width: 1px !important; overflow: hidden !important; display: block !important }
.MJX_Assistive_MathML.MJX_Assistive_MathML_Block { width: 100% !important }
#MathJax_Zoom { position: absolute; background-color: #F0F0F0; overflow: auto; display: block; z-index: 301; padding: .5em; border: 1px solid black; margin: 0; font-weight: normal; font-style: normal; text-align: left; text-indent: 0; text-transform: none; line-height: normal; letter-spacing: normal; word-spacing: normal; white-space: nowrap; float: none }
#MathJax_ZoomOverlay { position: absolute; left: 0; top: 0; z-index: 300; display: inline-block; width: 100%; height: 100%; border: 0; padding: 0; margin: 0; background-color: white; opacity: 0 }
#MathJax_ZoomFrame { position: relative; display: inline-block; height: 0; width: 0 }
#MathJax_ZoomEventTrap { position: absolute; left: 0; top: 0; z-index: 302; display: inline-block; border: 0; padding: 0; margin: 0; background-color: white; opacity: 0 }
.MathJax_Preview { color: #888 }
#MathJax_Message { position: fixed; left: 1px; bottom: 2px; background-color: #E6E6E6; border: 1px solid #959595; margin: 0px; padding: 2px 8px; z-index: 102; color: black; font-size: 80%; width: auto; white-space: nowrap }
#MathJax_MSIE_Frame { position: absolute; top: 0; left: 0; width: 0px; z-index: 101; border: 0px; margin: 0px; padding: 0px }
.MathJax_Error { color: #CC0000; font-style: italic }
.MJXp-script { font-size: .8em }
.MJXp-right { }
.MJXp-bold { font-weight: bold }
.MJXp-italic { font-style: italic }
.MJXp-scr { font-family: MathJax_Script, “Times New Roman”, Times, STIXGeneral, serif }
.MJXp-frak { font-family: MathJax_Fraktur, “Times New Roman”, Times, STIXGeneral, serif }
.MJXp-sf { font-family: MathJax_SansSerif, “Times New Roman”, Times, STIXGeneral, serif }
.MJXp-cal { font-family: MathJax_Caligraphic, “Times New Roman”, Times, STIXGeneral, serif }
.MJXp-mono { font-family: MathJax_Typewriter, “Times New Roman”, Times, STIXGeneral, serif }
.MJXp-largeop { font-size: 150% }
.MJXp-largeop.MJXp-int { vertical-align: -.2em }
.MJXp-math { display: inline-block; line-height: 1.2; text-indent: 0; font-family: “Times New Roman”, Times, STIXGeneral, serif; white-space: nowrap; border-collapse: collapse }
.MJXp-display { display: block; text-align: center; margin: 1em 0 }
.MJXp-math span { display: inline-block }
.MJXp-box { display: block !important; text-align: center }
.MJXp-box::after { content: ” ” }
.MJXp-rule { display: block !important; margin-top: .1em }
.MJXp-char { display: block !important }
.MJXp-mo { margin: 0 .15em }
.MJXp-mfrac { margin: 0 .125em; vertical-align: .25em }
.MJXp-denom { display: inline-table !important; width: 100% }
.MJXp-denom>* { display: table-row !important }
.MJXp-surd { vertical-align: top }
.MJXp-surd>* { display: block !important }
.MJXp-script-box>* { display: table !important; height: 50% }
.MJXp-script-box>*>* { display: table-cell !important; vertical-align: top }
.MJXp-script-box>*:last-child>* { vertical-align: bottom }
.MJXp-script-box>*>*>* { display: block !important }
.MJXp-mphantom { visibility: hidden }
.MJXp-munderover { display: inline-table !important }
.MJXp-over { display: inline-block !important; text-align: center }
.MJXp-over>* { display: block !important }
.MJXp-munderover>* { display: table-row !important }
.MJXp-mtable { vertical-align: .25em; margin: 0 .125em }
.MJXp-mtable>* { display: inline-table !important; vertical-align: middle }
.MJXp-mtr { display: table-row !important }
.MJXp-mtd { display: table-cell !important; text-align: center; padding: .5em 0 0 .5em }
.MJXp-mtr>.MJXp-mtd:first-child { padding-left: 0 }
.MJXp-mtr:first-child>.MJXp-mtd { padding-top: 0 }
.MJXp-mlabeledtr { display: table-row !important }
.MJXp-mlabeledtr>.MJXp-mtd:first-child { padding-left: 0 }
.MJXp-mlabeledtr:first-child>.MJXp-mtd { padding-top: 0 }
.MJXp-merror { background-color: #FFFF88; color: #CC0000; border: 1px solid #CC0000; padding: 1px 3px; font-style: normal; font-size: 90% }
.MJXp-scale0 { }
.MJXp-scale1 { }
.MJXp-scale2 { }
.MJXp-scale3 { }
.MJXp-scale4 { }
.MJXp-scale5 { }
.MJXp-scale6 { }
.MJXp-scale7 { }
.MJXp-scale8 { }
.MJXp-scale9 { }
.MathJax_PHTML .noError { vertical-align: ; font-size: 90%; text-align: left; color: black; padding: 1px 3px; border: 1px solid }
.wiz-code-container { position: relative; padding: 8px 0; margin: 5px 25px 5px 5px; text-indent: 0; text-align: left }
.CodeMirror { font-family: Consolas, “Liberation Mono”, Menlo, Courier, monospace; color: black; font-size: 0.83rem }
.CodeMirror-lines { padding: 4px 0 }
.CodeMirror pre { padding: 0 4px }
.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler { background-color: white }
.CodeMirror-gutters { border-right: 1px solid #ddd; background-color: #f7f7f7; white-space: nowrap }
.CodeMirror-linenumbers { }
.CodeMirror-linenumber { padding: 0 3px 0 5px; min-width: 20px; text-align: right; color: #999; white-space: nowrap }
.CodeMirror-guttermarker { color: black }
.CodeMirror-guttermarker-subtle { color: #999 }
.CodeMirror-cursor { border-left: 1px solid black; border-right: none; width: 0 }
.CodeMirror div.CodeMirror-secondarycursor { border-left: 1px solid silver }
.cm-fat-cursor .CodeMirror-cursor { width: auto; border: 0 !important; background: #7e7 }
.cm-fat-cursor div.CodeMirror-cursors { z-index: 1 }
.cm-animate-fat-cursor { width: auto; border: 0; background-color: #7e7 }
.CodeMirror-overwrite .CodeMirror-cursor { }
.cm-tab { display: inline-block; text-decoration: inherit }
.CodeMirror-rulers { position: absolute; left: 0; right: 0; top: -50px; bottom: -20px; overflow: hidden }
.CodeMirror-ruler { border-left: 1px solid #ccc; top: 0; bottom: 0; position: absolute }
.cm-s-default .cm-header { color: blue }
.cm-s-default .cm-quote { color: #090 }
.cm-negative { color: #d44 }
.cm-positive { color: #292 }
.cm-header,.cm-strong { font-weight: bold }
.cm-em { font-style: italic }
.cm-link { text-decoration: underline }
.cm-strikethrough { text-decoration: line-through }
.cm-s-default .cm-keyword { color: #708 }
.cm-s-default .cm-atom { color: #219 }
.cm-s-default .cm-number { color: #164 }
.cm-s-default .cm-def { color: #00f }
.cm-s-default .cm-variable,.cm-s-default .cm-punctuation,.cm-s-default .cm-property,.cm-s-default .cm-operator { }
.cm-s-default .cm-variable-2 { color: #05a }
.cm-s-default .cm-variable-3 { color: #085 }
.cm-s-default .cm-comment { color: #a50 }
.cm-s-default .cm-string { color: #a11 }
.cm-s-default .cm-string-2 { color: #f50 }
.cm-s-default .cm-meta { color: #555 }
.cm-s-default .cm-qualifier { color: #555 }
.cm-s-default .cm-builtin { color: #30a }
.cm-s-default .cm-bracket { color: #997 }
.cm-s-default .cm-tag { color: #170 }
.cm-s-default .cm-attribute { color: #00c }
.cm-s-default .cm-hr { color: #999 }
.cm-s-default .cm-link { color: #00c }
.cm-s-default .cm-error { color: #f00 }
.cm-invalidchar { color: #f00 }
.CodeMirror-composing { border-bottom: 2px solid }
div.CodeMirror span.CodeMirror-matchingbracket { color: #0f0 }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: #f22 }
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3) }
.CodeMirror-activeline-background { background: #e8f2ff }
.CodeMirror { position: relative; background: #f5f5f5 }
.CodeMirror-scroll { overflow: hidden !important; margin-bottom: 0; margin-right: -30px; padding: 16px 30px 16px 0; outline: none; position: relative }
.CodeMirror-sizer { position: relative; border-right: 30px solid transparent }
.CodeMirror-vscrollbar,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none }
.CodeMirror-vscrollbar { right: 0; top: 0 }
.CodeMirror-hscrollbar { bottom: 0; left: 0 !important }
.CodeMirror-scrollbar-filler { right: 0; bottom: 0 }
.CodeMirror-gutter-filler { left: 0; bottom: 0 }
.CodeMirror-gutters { position: absolute; left: 0; top: -5px; min-height: 100%; z-index: 3 }
.CodeMirror-gutter { white-space: normal; height: inherit; display: inline-block; vertical-align: top; margin-bottom: -30px }
.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: none !important; border: none !important }
.CodeMirror-gutter-background { position: absolute; top: 0; bottom: 0; z-index: 4 }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; text-align: center }
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
.CodeMirror-lines { cursor: text; min-height: 1px }
.CodeMirror pre { border-width: 0; background: transparent; font-family: inherit; font-size: inherit; margin: 0; white-space: pre; line-height: inherit; color: inherit; z-index: 2; position: relative; overflow: visible }
.CodeMirror-wrap pre { white-space: pre-wrap }
.CodeMirror-linebackground { position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: 0 }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto }
.CodeMirror-widget { }
.CodeMirror-rtl pre { direction: rtl }
.CodeMirror-code { outline: none }
.CodeMirror-scroll,.CodeMirror-sizer,.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber { }
.CodeMirror-measure { position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden }
.CodeMirror-cursor { position: absolute }
.CodeMirror-measure pre { position: static }
div.CodeMirror-cursors { visibility: hidden; position: relative; z-index: 3 }
div.CodeMirror-dragcursors { visibility: visible }
.CodeMirror-focused div.CodeMirror-cursors { visibility: visible }
.CodeMirror-selected { background: #d9d9d9 }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0 }
.CodeMirror-crosshair { cursor: crosshair }
.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection { background: #d7d4f0 }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0 }
.cm-searching { background: rgba(255, 255, 0, .4) }
.cm-force-border { padding-right: .1px }
.cm-tab-wrap-hack::after { content: “” }
span.CodeMirror-selectedtext { background: none }
.CodeMirror-activeline-background,.CodeMirror-selected { }
.CodeMirror-blur .CodeMirror-activeline-background,.CodeMirror-blur .CodeMirror-selected { visibility: hidden }
.CodeMirror-blur .CodeMirror-matchingbracket { color: inherit !important; outline: none !important; text-decoration: none !important }
.wiz-code-tools { display: none; position: absolute; top: -32px; right: 0; opacity: .95; z-index: 10 }
.CodeMirror-focused .wiz-code-tools { display: block }
.CodeMirror-sizer { border-right: 0 !important }
body pre.prettyprint { padding: 0 }
body pre.prettyprint code { white-space: pre }
body pre.prettyprint.linenums { overflow: auto }
body pre.prettyprint.linenums ol.linenums { padding: 10px 10px 10px 40px !important }
.CodeMirror-cursors { visibility: hidden !important }