Hegel2011的博客

读书 - 工作 - 生活 - 笔记

Iptables 的一些解释

物理机部署的年代里,组网通常是分层而建。例如所有的服务器都接到二层交换机组成内网,随后交换机上联三层交换机及防火墙。彼时,防火墙通常由专用 的设备承担。所有的路由规则、端口开放等也均在网络设备上进行配置。对于服务器而言,通常最简单的做法就是关闭iptables,在内部实现完全互通,而把防护任务交给专用设备。

然而转到云部署的年代,专用的网络设备大都收归云所有,此时虽然还有内网的概念,但已经模糊,从而要求把防火墙建在主机上。做到几个域的隔离。

iptables的配法有命令行和配置文件,此处以配置文件/etc/sysconfig/iptables为例,说明一些概念。

对于安全类的防护,集中在*filter上,nat 等是管映射和路由的

1
2
3
4
*filter
:INPUT ACCEPT [1194191:146127015]
:FORWARD ACCEPT [159938:8304428]
:OUTPUT ACCEPT [1044829:126818322]

上面这段代码表示对三种包的处理状态及已处理的包和字节数量。 INPUT就是输入的包,ACCEPT表示默认都可以进入,如果设置成DROP就是都废弃输入包了。如果主要以开白名单的方式,INPUT后可以接DROP。中括号里面的数字,冒号前是包数量统计,冒号后是字节数统计。
FORWARD表示转发,OUTPUT表示输出访问,通常这两个可以设置成ACCEPT即表示允许。
这3个表示的是基础的规则,类似默认路由,优先级是最低的。

1
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

随后就是很重要的这一段。这段的含义表示对连接状态是ESTABLISHED, RELATED的链接全部放行。iptables中的链接共有4种,established表示链接已建立,related的含义是由已建立的链接产生的链接,此外还有newinvalid两种链接状态, 其实这段话的含义也可以理解成invalid链接放弃,new状态之外的连接则允许通过。 这个指示关键的原因在于,比如本机设置了禁止外网访问本机的各个端口,同时本机作为客户端访问了另一个外网服务,那么外网服务的响应信息允许被接收。否则,就会面临只有一个单工链路的情况。

1
2
3
4
5
6
7
8
9
10
-A INPUT -d 192.168.1.202 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -d 192.168.1.202 -p tcp -m tcp --dport 8080 -j ACCEPT
-A INPUT -d 192.168.1.202 -p tcp -m tcp --dport 8081 -j ACCEPT
-A INPUT -d 192.168.1.202 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -d 192.168.1.202 -p tcp -m tcp --dport 21 -j ACCEPT
-A INPUT -d 192.168.1.202 -p tcp -m tcp --dport 20 -j ACCEPT
-A INPUT -d 192.168.1.202 -s 10.3.1.0/24 -j ACCEPT
-A INPUT -d 192.168.1.202 -j DROP

-A INPUT -d 10.10.10.222 -j DROP

这个机器有两块网卡,分别有两个地址192.168.1.20210.10.10.222,对于后者,只允许从这个口子发出包以及收入已建立连接的包(通过上面的 -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT)。
而对于前一个地址,则打开了http相关的80 8080 8081端口,开放了ssh和ftp端口,并对来自10.3.1.0网段的全部IP开放访问权限。

对于包的动作有ACCEPT DROP 和REJECT,后两个都表示拒绝,只是REJECT是明确拒绝,DROP只是沉默不答。

对于iptables,简单的用用,安全防护做到这样也就够了。

两次苏州游

阳春三月,正是江南好风景,3月初和4月中旬分别去了苏州的阳澄湖和金鸡湖。出行的方式选择了自驾。 两次自驾类似的地方很多,都是从家里出发,经内环走武宁路到G2京沪高速,高速上开50KM左右后从苏州工业园区出口下去,再开10公里左右即可抵达目的地。车程基本在一个半小时到两小时之间。

比较让人费解的是,明明都是度假区,但整个新区的正式名字却叫苏州工业园区,可能早年间这个区就叫这个名字,产业也以传统工业为主, 近来度假旅游经济兴起,才搞出了度假村,建了很多四五星级的酒店吧。

4月金鸡湖

入驻的是苏州凯宾斯基酒店,一路很顺,只开了1小时40分钟不到就到了酒店。车直接停在酒店大堂门口。 由于是周日12点之前到的,正直退房高峰且房间都在打扫中,check in需要等待,于是带孩子去后面的后花园转了一下。

花园在酒店的南面,所对的湖面是独墅湖。 image image

花园转了一圈后去酒店的中餐厅吃饭,吃完后继续去办理check in,这回终于有房了。 前台等待期间拿了一粒糖给小家伙吃。最近懂事很多,反问我这个不用付(钱)就能吃啦? 我只能简单地告诉他这个东西是免费的,可以拿了就吃。

入住房间对应的就是金鸡湖了。其实整个凯宾斯基就是位于南北两个湖中间。 从房间正中望出去可以看见金鸡湖大致的样子。 image

摩天轮在右面,左面则是苏州的新地标东方之门,俗称秋裤。

从酒店出发,开七八公里就可以到这个摩天轮公园。 image

要去需要趁早,5点就不让客人进去了。整个新区的停车倒还很友好,大部分停车场是不要钱的。 商场下面的停车场也有3小时免费的政策。整个新区开车的节奏很慢,红绿灯起步比上海还要慢一倍。

夜景也还不错,关键是这个地方的人口密度确实比上海低很多了,后来百科一下,整个新区其实只有100万人,其中本地户籍的40万,还有60万外来人口。所以感觉密度低是正常的。 image

这个金融中心还有诚品书店,不过似乎都是光看不买的,很可能会步百思买的后尘。 而比较后悔的是没去逛逛附近的Flexa专卖。 image image

然后在苏浙汇吃完饭就开车回酒店了。正好赶上当地人在酒店办婚礼,二楼大堂门前的车位客满, 只能停到一楼的车库里面去了。

第二天酒店用完早餐,和小家伙在后面的草坪打了会儿童羽毛球,随后就出发去拙政园了。

原本也没打算去苏州市中心,老婆提了一下我又研究了一下路线,发现其实新区离市中心很近, 所以决定开过去了还是。顺道去看了看东方之门。 image 其实对比名字,倒也不算刮三。 iamge 整个广场其实还行。秋裤其实也还在建设中,并未完工。可惜湖面的喷泉没开。

拙政园倒是不错的去处,尤其是这个游览时间特别好。门票也是够贵的了,现在是旺季,单人就要90元了。淡季稍便宜20。

拙政园的南北其实都有较大的停车场,但南面的路不好走,最后我还是停到北面去了。两三个小时下来最后付了12块停车费。这也是此次苏州之行唯一付停车费的地方。 从北停车场过去有450米的距离,走走其实也还可以。

对园林的欣赏一方面是因为年纪渐长,另一方面也是因为如今的园林确实修补的比小时候要号许多。 image image image image image

逛完拙政园,在旁边马路的朱鸿兴吃完中饭,就开车返程了。一路还算顺利,就上内环高架堵了一下,最后用了 2个小时回到家中。

3月阳澄湖

阳澄湖去的是苏州阳澄湖澜廷度假酒店,在阳澄湖半岛上,半岛上还有一个重元寺。

image 酒店是泰式风格的,没有金鸡湖的酒店大,整个半岛其实还在大规模地建设中。 工地比较多。但封闭性好,更适合在岛上骑自行车游玩。

停车场的充电桩很多。 image 苏州度假区的酒店此类东西其实都不少。不过最喜欢的还是直接走坡道上去停在大堂门口。 image image

第二天就去了重元寺。跟灵隐寺的布局有很多类似的地方,但依水而建是其一大特色,环境非常不错,寺庙也很整洁。 image image

在庙里吃完一碗素面之后,就开车回家了。

三四月确实是出行的好时节,这个季节去周边玩玩还是挺心旷神怡的。

Maven的Dependency和打包

使用Maven一大便捷之处就是管理依赖变得方便了,另一个好处就是打包更加灵活。

以前全部用jar包加入到工程里面,如果实际部署的时候需要剔除个别包,就需要自己手工在war包里删除。 而实际上需要这么干的情况还是有一些的,比如一些公共的包像ojdbc.jar,都已经放到容器里面了,如果war包里再有,则容易引发冲突。 删除公共的包,另一个好处就是可以给war包瘦身,这样在传递、部署时都会更加便捷。

6种范围依赖:

  • compile: 默认的选项,会在export的时候加入全部依赖
  • provided: 由其他环境提供,如容器或jdk,但在编译和测试的时候还是会导入,对于容器公共的包,可以使用这个选项
  • runtime
  • test
  • system: 和provided很类似,但需要自己指名jar所处的位置,类似于以前直接把jar包加到工程里面的做法
  • import

个人用的比较多的还是compile和provided两种。

JPA的naming Strategy

JPA的配置通常如下即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  <!-- Jpa Entity Manager 配置 -->
  <bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
    <property name="packagesToScan" value="com.sanss." />
    <property name="jpaProperties">
      <props>
        <!-- 命名规则 My_NAME->MyName -->
        <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.DefaultComponentSafeNamingStrategy</prop>
        <prop key="hibernate.show_sql">true</prop>
      </props>
    </property>
  </bean>

其中值得注意的是Resposity的生成其实依赖于里面的packagesToScan,而表名、表字段和对象之间的映射转换则依赖于hibernate.ejb.naming_strategy

此属性共有四个选项:

1
2
3
4
org.hibernate.cfg.DefaultComponentSafeNamingStrategy
org.hibernate.cfg.DefaultNamingStrategy
org.hibernate.cfg.EJB3NamingStrategy
org.hibernate.cfg.ImprovedNamingStrategy

首两个选项基本就是不做命名的转换,后面两个会把大小写的骆驼写法转换成带下划线的小写字符。同时,这个类可以自己继承并进行扩展定制,如果命名要求实在特殊,可以自行编写。 甚至表名后带日期等均可以自行定制。

Openwrt N56u 和iptv

四年以前写的上海电信IPTV的VLAN ID和通过交换机连接两路IPTV,而由于4k高清IPTV机顶盒的推广, 当时的内容已经有些不合时宜。尽管,用一个交换机还是可以实现连接两路iptv。

区别主要在于新的4k高清机顶盒同小红等盒子一样,需要双平面才能跑得起来。所谓双平面就是在专网之外机顶盒也要能够连接公网。 这个变化其实是带来一大好处的,即通过一个路由设备接光猫的一个口子,也可以让iptv和公网业务同时跑起来。下面记录一下操作过程。

openwrt

首先,这么灵活的配法,当前asus netgear等原厂的固件是不支持此种功能的,所以需要第三方固件,如openwrt dd-wrt。我选择了openwrt,是因为其官网支持asus-n56u路由器。 官方链接 ,可以从前面这个链接获得操作过程和固件。注意下载squashfs-factory.bin,不要下载chaos版。我就误下了chaos版,导致只能采用reset的办法重新装回了华硕的固件。openwrt很贴心的一点就是在网页里提供了恢复固件的操作步骤

1
2
3
4
5
6
7
8
Download & Install the asus "Firmware Restoration" from asus website
Download the factory image from asus
Enter Recovery Mode
Unplug Router
Hold Reset Button and Plug in Router
Release button when front LED flashes slowly
Use the following to set up your TCP/IP settings:IP address: 192.168.1.x Subnet mask: 255.255.255.0
Select firmware *.trx and upload

要点是把本机的ip设置成192.168.1.2,而且如果本机有多块网卡(包括虚拟网卡)则只保留一个连接路由器lan口的网口活跃。这样华硕的固件才 明确会打开这个网口并同已进入恢复模式的路由器相连。有了这个恢复模式存在,意味着asus的这款路由器基本是刷不死的。

安装完openwrt,设置好基本的wan口,我是采用的dhcp方式获取wan地址,就可以进入配置iptv vlan的过程了。

关于4k高清机顶盒获取公网和专网IP的流程

参考上海电信光猫一体机配合Openwrt拨号正常使用OTT 4K IPTV, 找到了iptv dhcp的流程 image

看清流程后,就可以知道: 1. 要先让4k iptv机顶盒接入公网
2. 路由器要支持DHCP-Option:125
3. 路由器要支持vlan 85的进出

公网配置是基础,剩余两点的配置可以归纳为

  1. 接在自备路由器上时,将路由器WAN口、CPU口、接IPTV的口 一起新建一个VLAN 85,3个端口全部为tagged

  2. /etc/dnsmasq.conf中要加入dhcp-option-force=125,00:00:00:00:1b:02:06:48:47:57:2d:43:54:03:05:48:47:32:32:31:0a:02:20:00:0b:02:00:55:0d:02:00:2e ,即对Option 125的支持

做完这些之后,至少目前中兴的机顶盒是全面支持了。

配置附录

/etc/config/network

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
config switch
        option name 'switch0'
        option reset '1'
        option enable_vlan '1'
        option enable_vlan4k '1'

config switch_vlan
        option device 'switch0'
        option vlan '1'
        option ports '0 1 2 3 8t'

config switch_vlan
        option device 'switch0'
        option vlan '2'
        option ports '4 8t'

config switch_vlan
        option device 'switch0'
        option vlan '85'
        option vid '85'
        option ports '1t 2t 4t 8t'

/etc/dnsmasq.conf

1
2
#cname=bertand,bert
dhcp-option-force=125,00:00:00:00:1b:02:06:48:47:57:2d:43:54:03:05:48:47:32:32:31:0a:02:20:00:0b:02:00:55:0d:02:00:2e

试用Cap3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
diff --git a/Capfile b/Capfile
new file mode 100644
index 0000000..51c3955
--- /dev/null
+++ b/Capfile
@@ -0,0 +1,29 @@
+# Load DSL and set up stages
+require 'capistrano/setup'
+
+# Include default deployment tasks
+require 'capistrano/deploy'
+
+require 'capistrano/rails'
+
+# Include tasks from other gems included in your Gemfile
+#
+# For documentation on these, see for example:
+#
+#   https://github.com/capistrano/rvm
+#   https://github.com/capistrano/rbenv
+#   https://github.com/capistrano/chruby
+#   https://github.com/capistrano/bundler
+#   https://github.com/capistrano/rails
+#   https://github.com/capistrano/passenger
+#
+# require 'capistrano/rvm'
+# require 'capistrano/rbenv'
+# require 'capistrano/chruby'
+# require 'capistrano/bundler'
+# require 'capistrano/rails/assets'
+# require 'capistrano/rails/migrations'
+# require 'capistrano/passenger'
+
+# Load custom tasks from `lib/capistrano/tasks` if you have any defined
+Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
diff --git a/Gemfile b/Gemfile
index 9786bc1..60dd07d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -10,11 +10,11 @@ gem 'mysql2'
 # Use SCSS for stylesheets
 gem 'sass-rails', '~> 5.0.0.beta1'
 # Use Uglifier as compressor for JavaScript assets
-gem 'uglifier', '>= 1.3.0'
+#gem 'uglifier', '>= 1.3.0'
 # Use CoffeeScript for .js.coffee assets and views
 gem 'coffee-rails', '~> 4.1.0'
 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
-# gem 'therubyracer',  platforms: :ruby
+gem 'therubyracer',  platforms: :ruby
 
 # Use jquery as the JavaScript library
 gem 'jquery-rails'
@@ -46,7 +46,10 @@ gem 'unicorn'
 gem 'thin'
 # Use Capistrano for deployment
 # gem 'capistrano-rails', group: :development
-
+group :development do
+    gem 'capistrano', '~> 3.1'
+    gem 'capistrano-rails', '~> 1.1'
+end
 
 gem 'kaminari', github: 'amatsuda/kaminari', branch: 'master'
 gem 'nokogiri'
diff --git a/config/deploy.rb b/config/deploy.rb
new file mode 100644
index 0000000..7af9419
--- /dev/null
+++ b/config/deploy.rb
@@ -0,0 +1,60 @@
+# config valid only for current version of Capistrano
+lock '3.4.0'
+
+set :application, 'xincheping'
+set :repo_url, 'git@github.com:swachian/xincheping.git'
+
+# Default branch is :master
+# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
+
+# Default deploy_to directory is /var/www/my_app_name
+set :deploy_to, '/opt/deploy/xincheping'
+
+# Default value for :scm is :git
+# set :scm, :git
+
+# Default value for :format is :pretty
+# set :format, :pretty
+
+# Default value for :log_level is :debug
+# set :log_level, :debug
+
+# Default value for :pty is false
+# set :pty, true
+
+# Default value for :linked_files is []
+set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
+
+# Default value for linked_dirs is []
+# set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
+ set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets')
+
+# Default value for default_env is {}
+set :default_env, { path: "/home/zhangyu/.rbenv/versions/ruby-2.3/bin:$PATH" }
+
+# Default value for keep_releases is 5
+# set :keep_releases, 5
+
+namespace :deploy do
+
+  after :restart, :clear_cache do
+    on roles(:web), in: :groups, limit: 3, wait: 10 do
+      # Here we can do anything such as:
+      # within release_path do
+      #   execute :rake, 'cache:clear'
+      # end
+    end
+  end
+
+  task :restart_server do
+    on roles(:web) do
+      within current_path do
+        with rails_env: fetch(:rails_env), rails_relative_url_root: '/xincheping' do
+          execute :rake, 'thin:restart', env: {rails_env: fetch(:rails_env) }
+        end
+      end
+    end
+  end
+  after "deploy:published", "restart_server"
+
+end
diff --git a/config/deploy/production.rb b/config/deploy/production.rb
new file mode 100644
index 0000000..a396f40
--- /dev/null
+++ b/config/deploy/production.rb
@@ -0,0 +1,61 @@
+# server-based syntax
+# ======================
+# Defines a single server with a list of roles and multiple properties.
+# You can define all roles on a single server, or split them:
+
+# server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value
+# server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value
+# server 'db.example.com', user: 'deploy', roles: %w{db}
+
+
+
+# role-based syntax
+# ==================
+
+# Defines a role with one or multiple servers. The primary server in each
+# group is considered to be the first unless any  hosts have the primary
+# property set. Specify the username and a domain or IP for the server.
+# Don't use `:all`, it's a meta role.
+
+role :app, %w{zhangyu@192.168.203.198}, my_property: :my_value
+role :web, %w{zhangyu@192.168.203.198}, other_property: :other_value
+role :db,  %w{zhangyu@192.168.203.198}
+
+
+
+# Configuration
+# =============
+# You can set any configuration variable like in config/deploy.rb
+# These variables are then only loaded and set in this stage.
+# For available Capistrano configuration variables see the documentation page.
+# http://capistranorb.com/documentation/getting-started/configuration/
+# Feel free to add new variables to customise your setup.
+
+
+
+# Custom SSH Options
+# ==================
+# You may pass any option but keep in mind that net/ssh understands a
+# limited set of options, consult the Net::SSH documentation.
+# http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
+#
+# Global options
+# --------------
+#  set :ssh_options, {
+#    keys: %w(/home/rlisowski/.ssh/id_rsa),
+#    forward_agent: false,
+#    auth_methods: %w(password)
+#  }
+#
+# The server-based syntax can be used to override options:
+# ------------------------------------
+# server 'example.com',
+#   user: 'user_name',
+#   roles: %w{web app},
+#   ssh_options: {
+#     user: 'user_name', # overrides user setting above
+#     keys: %w(/home/user_name/.ssh/id_rsa),
+#     forward_agent: false,
+#     auth_methods: %w(publickey password)
+#     # password: 'please use keys'
+#   }
diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb
new file mode 100644
index 0000000..4fc06fa
--- /dev/null
+++ b/config/deploy/staging.rb
@@ -0,0 +1,61 @@
+# server-based syntax
+# ======================
+# Defines a single server with a list of roles and multiple properties.
+# You can define all roles on a single server, or split them:
+
+# server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value
+# server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value
+# server 'db.example.com', user: 'deploy', roles: %w{db}
+
+
+
+# role-based syntax
+# ==================
+
+# Defines a role with one or multiple servers. The primary server in each
+# group is considered to be the first unless any  hosts have the primary
+# property set. Specify the username and a domain or IP for the server.
+# Don't use `:all`, it's a meta role.
+
+# role :app, %w{deploy@example.com}, my_property: :my_value
+# role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value
+# role :db,  %w{deploy@example.com}
+
+
+
+# Configuration
+# =============
+# You can set any configuration variable like in config/deploy.rb
+# These variables are then only loaded and set in this stage.
+# For available Capistrano configuration variables see the documentation page.
+# http://capistranorb.com/documentation/getting-started/configuration/
+# Feel free to add new variables to customise your setup.
+
+
+
+# Custom SSH Options
+# ==================
+# You may pass any option but keep in mind that net/ssh understands a
+# limited set of options, consult the Net::SSH documentation.
+# http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
+#
+# Global options
+# --------------
+#  set :ssh_options, {
+#    keys: %w(/home/rlisowski/.ssh/id_rsa),
+#    forward_agent: false,
+#    auth_methods: %w(password)
+#  }
+#
+# The server-based syntax can be used to override options:
+# ------------------------------------
+# server 'example.com',
+#   user: 'user_name',
+#   roles: %w{web app},
+#   ssh_options: {
+#     user: 'user_name', # overrides user setting above
+#     keys: %w(/home/user_name/.ssh/id_rsa),
+#     forward_agent: false,
+#     auth_methods: %w(publickey password)
+#     # password: 'please use keys'
+#   }
diff --git a/config/environments/production.rb b/config/environments/production.rb
index f572341..cd0d766 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -19,7 +19,7 @@ Rails.application.configure do
   config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
 
   # Compress JavaScripts and CSS.
-  config.assets.js_compressor = :uglifier
+  #config.assets.js_compressor = :uglifier
   # config.assets.css_compressor = :sass
 
   # Do not fallback to assets pipeline if a precompiled asset is missed.
 
diff --git a/lib/tasks/sync.rake b/lib/tasks/sync.rake
index 6d371d6..bd87ca3 100644
--- a/lib/tasks/sync.rake
+++ b/lib/tasks/sync.rake
@@ -1,10 +1,10 @@
 namespace :sync do
-  desc "TODO"
+  desc "长测新车评同步"
   task changce: :environment do
     Changce.fetch
   end
 
-  desc "TODO"
+  desc "新车评内容全部同步"
   task all: :environment do
     Daogoulist.all.each {|dgl| dgl.sync_daogous(2)}
     Guandian.fetch
@@ -12,4 +12,8 @@ namespace :sync do
     Changce.fetch_changceing
   end
 
+  desc "同sh.122.gov.cn同步电子警察信息"
+  task police2: :environment do
+    ElectronicPoloce2.test_fetch_one_page
+  end
 end
diff --git a/lib/tasks/thin.rake b/lib/tasks/thin.rake
new file mode 100644
index 0000000..9fa35cd
--- /dev/null
+++ b/lib/tasks/thin.rake
@@ -0,0 +1,8 @@
+namespace :thin do
+  desc "重启thin"
+  task restart: :environment do
+    system " if [ -f tmp/pids/thin.pid ]; then kill `cat tmp/pids/thin.pid` && rm tmp/pids/thin.pid; fi"
+    system  "./bin/thin start --prefix=/xincheping  -p 3001 -P tmp/pids/thin.pid -d"
+  end
+
+end
diff --git a/lib/tasks/unicorn.rake b/lib/tasks/unicorn.rake
new file mode 100644
index 0000000..7df54be
--- /dev/null
+++ b/lib/tasks/unicorn.rake
@@ -0,0 +1,8 @@
+namespace :unicorn do
+  desc "重启unicorn"
+  task restart: :environment do
+    system " if [ -f tmp/pids/unicorn.pid ]; then kill `cat tmp/pids/unicorn.pid`; fi"
+    system  "./bin/unicorn -c unicorn.conf.rb -D"
+  end
+
+end

时间长了发现还是挺喜欢本田的

开CRV有半年多了,近来发现越发喜欢这个车甚至本田这个品牌。喜欢的原因首先是来源于和日产两个细节的比较。
东本CRV的说明书是写的比日产好许多的,读起来很易读,不像日产是标准的非面向人类的说明书。而且这个说明书 里面还会教用户如何自己拆换空调滤芯,而日产翻遍了也是没有的。在说明书的信息化方面,东本的app有详细的pdf说明书可供参考检索, 而日产在这一部分是完全空白。对于和用户实际沟通上,本田要好出许多。

另一个细节则来自智能钥匙。根据同事八代雅阁的经历,五六年前本田的智能钥匙是一块很简陋的电路板,更换电池时是直接 以电路板示人的。但经过几年发展后,我的CRV上这个细节得到了很大的改善,电路板不再是粗糙地打开即见,然而仍然可以换电池。 轮到日产的话,则所有的钥匙还是本田五六年前的水准,一块电路板大大裸露在外面。

这个车之所以越开越喜欢,主要原因就是确实很对技术男的味。实际上美版的前雷达什么更对我的胃口,只是被东本改乱了。

而之前一直不满的手机连接导航,用的多了感觉还是可以的。尽管连线比较麻烦,系统也还不够稳定,发展方向却是极其正确的。 目前的水平也足以一用,虽然希望可以更方便些更快捷些更稳定些。对本田的倒车无力和杂音遍地有各种不满,至今依然不满,但鉴于CRV和本田实际各种良好的体验, 这车确实越来越让人喜欢了。

Mac 上折腾Ruby 2.2(续)

又是一年圣诞了,继去年Mac上折腾Ruby之后,这次继续折腾。只是版本换成了2.2.4 2.3 以及 是为了解决readline的问题。

按 https://github.com/guard/guard/wiki/Add-Readline-support-to-Ruby-on-Mac-OS-X
的说法:

If you are on Mac OS X and have problems with either Guard not reacting to file changes or Pry behaving strangely, then you probably suffer under a Ruby build that uses libedit instead of readline.

所以在前次的基础上,要进一步增加编译选项。

1
./configure --with-openssl-dir=`brew --prefix openssl` --disable-install-doc --prefix=/Users/me/.rbenv/versions/ruby-2.3  --with-readline-dir=`brew --prefix readline`

其中

1
--with-readline-dir=`brew --prefix readline`

就是针对readline增加的选项。

加上之后,irb支持中文了,pry也支持历史记录浏览了。

Deutschland Holiday

8月底9月初的德国之旅,不过拖了很久才发上来。

D0: 浦东机场12小时航班直飞法兰克福,难得一见公务舱登机也要排长队。

D1:飞行12小时后,当地时间凌晨5点抵达法兰克福机场,出关取行李因为是凌晨都很迅速。随后买从法兰克福去斯图加特的高铁票,单人单程63欧/张,一个半小时后抵达斯图加特。德国的火车站都没检票口,导致我们寻找车站入口还费了点脑筋。 到斯图加特火车站旁的旅馆checkin,由于太早只能寄存行李,随后坐地铁S线前往奔驰博物馆。中午游览完毕后回酒店休息。

D2: 德国的礼拜天,商场全部关门,于是前往路德维希堡,距离斯图加特坐火车20分钟。王宫在广场的参观都是不要门票的,德国大部分王宫都是这个样子的,只有内饰参观才要买门票,而且习惯是让一个导游带着10来个人一起走。内部参观要持续一个半小时,不过一圈下来基本各个房间都了解了,之后几天参观其他王宫也差不多是一样的格局。

D3: 麦琴根购物村购物。斯图加特出发火车半个多小时可达。这其实是一个outlets,东西还是比较多的,当然本身都是打折货品。

D4: 海德堡。海德堡和斯图加特一样都位于德国巴符州,所以可以买巴符州的州票,州票比较便宜28欧两个人可以当天在州内随意坐火车和各类公交。就是海德堡在巴符州的西北角,州票只能坐慢车,将近两个小时才到。古堡本身是破损的,不过这个山区小镇倒是让人想起中国的庐山。回程走了一下商业街,长一公里多,里面东西还是蛮多的,也是很适合购物的商业街。

D5: 斯图加特的游程基本结束,坐高铁前往慕尼黑,2个小时不到即可到达,不过慕尼黑开始下雨了。提前一天买票,优惠还是很大的,这次的距离比第一天坐的还要长,但两人票单程只要48欧,相当于原价的40%。中午抵达慕尼黑后,这次倒是可以直接入住酒店了。随后坐公共电车前往宁芬堡宫。宁芬堡很棒,绝对值得一去。里面的马车展览让我很感叹,德国人会造车绝非偶然。

D6: 天鹅堡。去传说中的天鹅堡。买巴伐利亚州的州票即可,天鹅堡实际位于小镇福森境内,坐两个小时的火车可以抵达,随后坐公交10分钟即可。这个地方很商业化了,城堡外墙也是在不断翻新的。其实德国的景区都是不用买票的,爬爬山拍拍照其实已经足够了。如果要进去参观城堡内饰,就需要买票,买完票还要在门口等待排队入场。堪比世博会,等了将近两个小时才进去草草参观了15分钟。但由此才终于明白德国的景区本身确实都是不收费的,我们的排队纯粹是按中国旅游思维导致的自找麻烦。

D7:雨中的天鹅堡并不太好玩,本来我们想隔天再去国王湖的,但一看天气预报隔天国王湖那边下雨,而D7倒是一个好天气,于是临时调整行程前往国王湖。国王湖实际上位于贝希特斯加登小镇上,离奥地利的萨尔茨堡很近只要40分钟车程。慕尼黑和萨尔茨堡之间的交通很密集,M线几乎每小时就有一班,只要一小时多一些即可到达萨尔茨堡。但从慕尼黑只坐火车周转需要2个半小时才能到贝希斯特加登。国王湖本身不错,但整个小镇更有意思。可惜我们安排的不好,这地方应该住个两晚,这样就能把耶拿峰和著名的鹰巢都玩到。国王湖游船中的小号回声表演,本来以为是很无聊的一个项目,但实际参加下来却感觉很有意思,也是开开心心付给了表演导游小费。当天下午4点折回慕尼黑,一天总计坐了5个小时火车,也是坐的累了。当天是周五而当晚正好是德国国家足球队对阵波兰的欧洲杯预选赛,火车开过基姆湖后,一车子上很多球迷,大部分是年轻的德国男女,普遍穿着巴伐利亚传统服装外加一人一瓶啤酒,一路上吵吵闹闹,老外确实能吵。

D8: 宝马博物馆和慕尼黑奥林匹克体育场。宝马博物馆比奔驰差了许多。奥林匹克公园倒是鸟巢+世纪公园,当天是周六,老外周六不少也是在公园遛娃遛狗的。下午可以趁着周日商店关门前继续购物。慕尼黑是个商业发达的城市,买东西还是很方便的。

D9: 上午慕尼黑市中心参观。到了周日人就很少了,马路上基本只有游客,所以一早很空,顺便还去了王宫博物馆,也看见了玛利亚广场是钟人表演。下午则是去安联足球场和拜仁慕尼黑足球纪念馆参观,对中国人来讲也就是看一个水立方的体育场版本。

D10: 上午又在市中心逛了一下,随后就直接出发去慕尼黑机场,地铁40分钟可达,距离类似上海从市中心去虹桥机场。早早checkin,随后等登机,又经过10小时的飞行我们终于回到了上海。回程的飞机经济舱没卖光,商务舱却都售罄了。不过这种直飞的长途,经济舱和公务舱的差异确实类似以前火车硬座和软卧的差异。也难怪公务舱的比例会那么高。慕尼黑后3天都碰到了难民问题。我们住在火车站旁边,所以看见很多难民和警察,秩序虽不乱但总让我感到紧张。回来后,还是发现上海更好。

文艺的HashMap初始化

多年以来,受制于java没有初始设置hash对-值的方法,例如js有:

1
2
3
var obj = {
  a: 1, b: 2
};

ruby在借鉴js的文法之前,有著名的rocket标注

1
obj = {:a=>1, :b=:2}

而java则只能继续使用过程定义来描述

1
2
3
Map<String, integer> map = new HashMap<String, integer>();
map.put("a", 1);
map.put("b", 2);

而最近发现了一种文艺一些的写法:

1
2
3
4
5
6
Map<String, integer> map = new HashMap<String, integer>(){
  {
    put("a", 1);
    put("b", 2);
  }
}

此种写法是利用了创建一个匿名类的文法,该匿名类直接继承自HashMap,而第二套花括弧则是实例初始化。

实例初始化是对应于静态初始化,后者属于整个类,而前者属于某个对象初始化时进行。

1
2
3
4
5
6
7
8
9
public class demo {
  static {
    do sth of class
  }

  {
    do sth of instance
  }
}

其实这种写法的代码行数并不少,但是语意,主要是段落的分割清楚了许多。

Included file 'twitter_sharing.html' not found in _includes directory