Ruby 包管理分析

本文简单的介绍 Ruby 包管理的相关原理,写的比较粗浅,欢迎补充.

大纲

  • Ruby 本身的包管理
  • Rubygems
  • Bundler
  • RVM 与 rbenv

Ruby 本身的包管理

require method

Ruby 主要通过 require 函数来引入外部的库文件. 函数原型如下:

# http://ruby-doc.org/core-1.8.7/Kernel.html#method-i-require
# http://ruby-doc.org/core-2.2.3/Kernel.html#method-i-require
require(string) => true or false

参数需要传一个 string , 文件名或文件路径.
返回值为 boolean 值, true 为 require 成功.

演示代码:

# shell
echo 'puts "a"' > /tmp/a.rb
cd /tmp
irb
require 'csv' # 文件名方式,在 $LOAD_PATH 全局变量定义的路径里搜索
require './a' # 相对路径方式,基于进程的工作目录, Dir.pwd 可以查看当前进程的工作路径
require '/tmp/a' # 绝对路径. 1.8.7 返回 true, 1.9 以后返回false. 1.9 以后同一文件,用不同的路径方式加载,也算同一文件,不会重复加载.

$LOAD_PATH

本部分基于 ruby 1.8.7 的原因是因为 ruby 1.8.7 默认还是用 ruby 自身的 require 函数, 1.8 以后,默认用的是 Rubygems 实现的 require 函数.

大部分时候,我们使用 require 使用的是文件名,而不是相对路径或绝对路径的方式,所以 $LOAD_PATH 变量是个关键点.

ruby -e "puts $:" # shell, 用 ruby 命令的 -e 参数运行单行 ruby 代码. 以下为命令执行后的输出
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/site_ruby/1.8
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/site_ruby/1.8/x86_64-linux
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/site_ruby
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/vendor_ruby/1.8
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/vendor_ruby/1.8/x86_64-linux
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/vendor_ruby
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/1.8
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/1.8/x86_64-linux

$LOAD_PATH 变量为一个数组,里面存放的路径字符串.

打印出来的有三个重要的目录分类.

  • site_ruby 默认优先级最高,安装本机相关库. 摘自<<Ruby 编程语言>> 254页.
  • vendor_ruby 操作系统供应商进行定制用的,一般为空.
  • 1.8 ruby 标准库目录. 比如 date, csv 库.

可以进入对应的目录查看一下,目录下有什么文件.

演示代码:

echo 'puts "priority2"' > /usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/vendor_ruby/1.8/prioritydemo.rb # vendor_ruby
ruby -e "require 'prioritydemo'" # puts priority2
echo 'puts"priority1"'> /usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/site_ruby/1.8/prioritydemo.rb # site_ruby
ruby -e "require 'prioritydemo'" # puts priority1

通过代码演示可以看见, require 查找的顺序是基于 $LOAD_PATH 数组里面的路径的顺序来找的,找到了就不继续往下找.

上测试代码如果要强制加载 vendor_ruby 目录下的 prioritydemo 文件,可以使用绝对路径.

Rubygems

Rubygems 主要通过 ruby 的 monkey patch 特性,重写了 require 函数的实现.

gem 一般安装到和 site_ruby 平级的 gems 目录下面,我们主要关心 gems(代码) 目录和 specifications(gemspec) 目录.

rubygems require 解析

此部分基于 2.3.4 的 ruby 源码分析.

文件跳转有点晕,觉得麻烦的朋友,可以略过.结论是把 对应的 gem 的 gems 目录添加到 $LOAD_PATH 变量里面.

  • 当加载 lib/rubygems.rb 时,会调用 Gem::Specification.load_defaults 代码 # 1.9自动加载
  • lib/rubygems/specification.rb#load_defaults 会把 specifications 目录下的所有 gemspec 文件的 files 描述的文件通过 lib/rubygems.rb#register_default_spec 方法注册到 @path_to_default_spec_map 变量. key 文件名,value为 spec 对象
  • require 方法会调用 lib/rubygems.rb#find_unresolved_default_spec , find_unresolved_default_spec 拼上 .rb .so 在 @path_to_default_spec_map 变量里查找,如果找到,则返回对应的 spec , 再调用 lib/rubygems.rb#remove_unresolved_default_spec 方法,从 @path_to_default_spec_map 变量删除这个 spec 的相关值,防止重复加载.
  • 最后再调用 lib/rubygems/core_ext/kernel_gem.rb#gem, lib/rubygems/specification.rb#activate , lib/rubygems/specification.rb#add_self_to_load_path 再把这个 gems 添加到 $LOAD_PATH 变量.

演示代码:

puts Gem.instance_eval("@path_to_default_spec_map.keys.any?{|k| k =~ /minitest/}") # true
puts $LOAD_PATH # 没有 minitest gems
puts require 'minitest' # true
puts Gem.instance_eval("@path_to_default_spec_map.keys.any?{|k| k =~ /minitest/}") # false
puts $LOAD_PATH # 有 minitest gems

可以看到在 require 之前与之后的差别,多了 minitest gem 的 lib 路径( /home/outman/.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/minitest-5.4.3/lib ) .

最终结论是 rubygems 所做的一切,只是为了把 gem 的 lib 目录添加到 $LOAD_PATH 变量里,再用原生的 require 方法加载.

Bundler

个人现在的使用习惯是 rbenv + bundler .而不是使用 rvm 的 gemset . 项目第一次执行 bundle install 加 –path=vendor/bundle 参数,把 gem 安装到项目的 vendor/bundle 目录下.再在 git 忽略此目录.

这样做就不会因为多个项目安装 gem 到系统目录,而导致系统里的 gem 冲突.

Bundler 和 Rubygems 一样,最终还是为了把项目的 gem 的 lib 目录添加到 $LOAD_PATH 变量里.

演示代码:

ruby -e 'puts $LOAD_PATH'
bundle exec ruby -e 'puts $LOAD_PATH' #可以看到 bundle 把项目 Gemfile 里定义的所有 gem 的 lib 目录都已经加到 $LOAD_PATH 变量里.

源码简单解析:

bundle exec 主要修改 PATH RUBYOPT RUBYLIB 变量,再用 exec 函数替换当前进程,从而继承修改后的 PATH RUBYOPT RUBYLIB 环境变量.

exec后的新进程读取 RUBYOPT 环境变量的 -rbundler/setup 值,从而会先加载运行 bundler/setup 这个文件的代码.

  • lib/bundler/cli/exec.rb#run 方法
  • SharedHelpers.set_bundle_environment
    • 把 bundle 的 bin 目录加到了 PATH 环境变量
      • bundle exec ruby -e ‘puts ENV[“PATH”]’
    • 再把 -rbundler/setup 添加到 RUBYOPT 变量.
      • ruby -h, -rlibrary require the library before executing your script
      • echo “puts 123” > /tmp/s.rb; ruby -r ‘/tmp/s.rb’ -e ‘puts 456’
    • 把 bundle 的 lib 目录添加到RUBYLIB 变量
      • RUBYLIB=/tmp ruby -e ‘puts $LOAD_PATH’ # 把 /tmp 添加到 $LOAD_PATH 的第一位了
  • 再执行 Kernel.exec ,用 exec 参数后面的命令替换当前进程.新进程会在修改的 ENV 执行.
  • lib/bundler/setup.rb -> Bundler.setup -> lib/bundler.rb -> load.setup -> lib/bundler/runtime.rb
  • Runtime 从 Bundler.definition 里拿到所有 specs ,再遍历 specs,调用 Bundler.rubygems.loaded_specs 方法把所有 gem 都加载到 $LOAD_PATH .
    • bundle exec ruby -e ‘puts Bundler::Runtime.new(Bundler.root, Bundler.definition).requested_specs.first.inspect

rbenv

rbenv 的原理和 bundler 差不多,主要是先修改环境变量,再调用 exec 替换当前进程.

在 rbenv 环境我们调用 which ruby 命令可以看到, ruby 执行文件总是在 ~/.rbenv/shims 目录下面. shims 目录下的 ruby 脚本会根据 .ruby-version 文件,找到对应 ruby 的执行文件路径,修改好环境变量后,再执行 exec 命令.

rvm

rvm 与 rbenv 不同, rbenv 实现类似于设计模式里的委托模式,所有的 ruby 执行都交给 ~/.rbenv/shims 目录下的执行文件.

而 rvm 简单粗暴,直接把对应版本的 ruby 的 bin 目录添加到 PATH 环境变量里.

rvm gemset解析

rvm 的 gemset 主要是通过修改环境变量 GEM_HOME 和 GEM_PATH 变量来实现的. 此两变量 rubygems 根据其值在值定义的目录查找 gem .

演示代码:

rvm gemset use 1.8.7@testset --create
env | grep GEM
GEM_HOME=/usr/local/rvm/gems/ruby-1.8.7-head@testset
GEM_PATH=/usr/local/rvm/gems/ruby-1.8.7-head@testset:/usr/local/rvm/gems/ruby-1.8.7-head@global
gem install rack
cd /usr/local/rvm/gems/ruby-1.8.7-head@testset; ls
#bin  build_info  cachedoc  environment  gemsspecificationswrappers
ruby -e 'require "rubygems"; puts Gem.paths.path.inspect'
#["/usr/local/rvm/gems/ruby-1.8.7-head@testset", "/usr/local/rvm/gems/ruby-1.8.7-head@global"]

可以看到把 gemset 的目录添加到 Gem.paths 变量里面去了. 而且固定有 global 目录,这样当我们把 gem 安装到 global 的 gemset 里,当在我们自己的 gemset 里找不到时,会去 global 的 gemset 目录里面找.

总结

$LOAD_PATH 很强大,利用它好,可以实现不错的 hack 技巧,但注意别让自己掉到坑里去了.

穷折腾,淘了台服务器当台式机用

此文献给同样爱穷折腾的同志们. 坑已经挖好,等着你们…

先讲一个悲伤的故事.
本来 双CPU + 32G内存 + DL180 G6 只要 1000 元的样子就可以.
由于本人没有服务器安装经验, 主板的CPU2的插座的针脚安装没放好,弯了,再手残挑断了针脚. 主板只可以用 CPU1 的插座,双路用不了.没办法,加320元换了一块主板(主板+机箱的准 系统也只要420块钱,原主板还要寄回去). 泪奔…

重要的事情说三遍. 慎入,慎入,慎入.

  1. 这价钱,不实用. 主机加内存加CPU差不多要1000,还没有买显卡和硬盘的.推荐买占美这种小主机,或自己组装台式主机.
  2. 机箱太大, 长 72 厘米, 宽 45 厘米. 差 30 厘米就 1 米了,真心没地方摆.不过可以改装安装到普通的台式机机箱里面.
  3. 默认的风扇太吵,刚开机和发廊的热吹风对着耳朵吹没区别.风扇虽然可以改装,但改装后电源的风扇还是有点吵,除非你决定换成普通的台式机电源.改装后带上耳机听歌就听不到.隔一面墙也听不到.如果放在睡房,睡房有其它人,请不要购买.
  4. CPU 耐热能力较差,像 L5630 最高只允许 63 度. 不过如果买 E 或 X 系列的 CPU 要好点.
  5. 南桥(IOH)温度太高,用自带风扇,室温20度 IOH TEMP 显示60多度. 自己在南桥加个风扇,就变 50 多度,不晓得夏天怎么样. ( X58 主板貌似这个问题貌似比较多 )
  6. 淘宝上面有全套改装好的,有兴趣的朋友可以入. 算上自己买机箱的钱,价格其它差不多了. https://item.taobao.com/item.htm?id=37302088648 淘宝标题: HP DIY服务器 24核 X5650 3D建模 渲染主机 图形工作站 游戏多开

购买清单总览

  1. CPU L5630 X2 - 84 元
  2. HP DL180 G6 X1 - 440 元 (准系统,只要主板,电源和机箱.无CPU,内存,硬盘)
  3. 硬盘架 X4 - 40 元
  4. 内存 8根 - 320 元
  5. 风扇 改装线+PWM风扇+普通3000转风扇 - 大概要60元
  6. usb 声卡 - 20 元

双CPU 8 核 16 线程 32G 内存 总价只要 934 元. 硬盘与显卡钱另计.
如果内存改成 24G ,只要 854 元.会砍价的话,砍到 800 应该可以的.

清单详情

淘宝标题方便商品过期后通过关键词还能找到相关商品.

CPU: L5630

淘宝标题: XEON志强L5630 2.13G 12M 40W CPU 正式版 取代E5520 L5520

单价 37 元, 数量 2 个.
此 CPU 为 4 核 8 线程,主频只有 2.13 GHz, 功耗 40W .
主频相对来说比较低,不适合用来玩游戏. 功耗只有 40W , 两个加起来 80W , 8 核 16 线程只有 80W 看起来还是不错.

另外可以上 E 或 X 系列的 CPU ,主频与耐热能力都有提升, 比如 E5620 X5650 . 当然 价格与功耗 都要高一倍以上.

所有的 1366 针 CPU 列表: https://en.wikipedia.org/wiki/Xeon#3600.2F5600-series_.22Gulftown.22_.26_.22Westmere-EP.22

淘宝上面还有 30 元的购买链接,貌似我之前搜索没有搜索到.估计被淘宝搜索排序给隐藏了.

服务器: HP DL180 G6

淘宝标题: 特价惠普HP DL180G6 2U服务器3.5寸8盘位HP 380G6 G7秒DELL R710

买的是准系统,没有 CPU 内存 硬盘. 有 主板 电源 一个散热器.
单价为 420 元,多去淘宝找找,应该还有便宜的.默认只有一个散热器,所以加 20 元再买了一个散热器.
硬盘托架 10 元一个,买了 4 个备用.
内存单根 4G, 40元一根,共买了8根. 本来只买了四根,后来发现每个 CPU 需要 3 根内存才能组成 3 通道. 共 32G 内存.
每边上4根内存,发现也可以三通道,用 AIDA32 的内存测试,一样可以把 CPU 的内存带宽跑满,跑到 25Gb/s .

网上关于 HP DL160 G6 的文章相对来说比较多,两个型号差不多

  • DL160 是 1U 的, DL180 是 2U 的. 2U 相对来说更厚些,更好放独立显卡.
  • DL180 比 DL160 支持更大的内存,好多 DL160 最大只支持 16G 内存. 而大部分 DL180 都支持 192G 内存, 可以在中关村网页看参数.

风扇改造

自带的风扇虽然有带温控,但一样很吵,特别是在装了独立显卡后,转速稳定在 4000 ,比一般台式机吵多了.开机那就更不要说.

基于 HP DL160 G6 的文章分析,风扇改造主要有三种方案.

1. 把6针的插座改成4针的,然后再买4针的PWM风扇,注意风扇大小与功率.

推荐此方案,换风扇就可以了.

技术文章: http://www.360doc.com/content/14/0318/13/73007_361564350.shtml

淘宝标题: HP DL160G6/DL180G6/SE316M1 静音改装 四线温控线 改装线
淘宝链接: https://item.taobao.com/item.htm?id=522213532817

2. 利用可调电阻来降速.

技术文章: http://tieba.baidu.com/p/2968626728

淘宝购买链接: https://item.taobao.com/item.htm?id=45394666862

卖家说了,最大只能降速50%,没试过,怕还是很吵.

3. 刷 BIOS 关闭风扇检测.

技术文章: http://tieba.baidu.com/p/3530406494

下载地址在15楼. 没试过,怕刷坏. 刷坏就是320.

这个只是关闭风扇检测,不是调速.所以也没有刷的必要.

我的风扇折腾之路

瞎折腾在风扇上面花了 100 多块.

第一次在这家买了个 50 的套餐,加邮费 60. https://item.taobao.com/item.htm?id=522213532817
到手后看老板只送了一个 4 线的风扇,三个 3 线的风扇.三线的风扇不是 6 厘米的,还放不进原来的风扇位置里面.装上压测 CPU 温度会超过40.
以为是老板小气,才配三个 3 线风扇.后来才知道是我太菜了.

参考老板送的 4 线风扇型号 台达AFB0612EH https://item.taobao.com/item.htm?id=39664158650,再买了4个,加邮费花了 31 块钱.
到手后才发现,所以的风扇接上转速都一样,都只要 1500 的转速左右,跟没装风扇一样, CPU 温度上 60 有望. 折腾了几个小时,发现只接风扇只接电源正负极速度就是全速转.全速转有 6800 转,参数写着噪音 46.5 dB,比原装的风扇还要吵.
终于知道卖线老板为什么送 3 个三线低转速的风扇了.因为那3个三线风扇只接了正负,所以全速转,但全速转的速度估计也只是 2000~3000 转,所以不吵.

为了完美,再买了 3 个 6cm 3000转 风扇, 包邮 25元. https://item.taobao.com/item.htm?id=43741478446
装上后效果可以,但是 IOH 温度还是有 60 度左右,估计到夏天上 80 度没问题.到时得换成 5000 转或 4000 转的风扇.

最终给你们的推荐方案,直接买第一家老板的套餐,然后再把风扇直接绑到 CPU 散热上面和 IOH 散热上面.

淘宝上面有两种改装线,有一种只能接两个风扇的,这种不要买,到时没办法为 IOH 接风扇.

USB 声卡

淘宝标题: 全新7.1USB声卡 高品质苹果外置独立声卡/电脑声卡/免驱WIN7 https://item.taobao.com/item.htm?id=21875420495

顺便在这家买了根显卡和sata供电线

淘宝标题: 做工很好 HP DL180se G6 显卡6P 8P SATA硬盘 电源供电线 转接线 https://item.taobao.com/item.htm?id=527137606595

声卡质量一般,用着用着,有时忽然变成噪音.然后要重插一下才可以.

linux 显卡如果带 hdmi,需要调整一个顺序. https://bbs.archlinux.org/viewtopic.php?id=171097

显卡

此主板是带两个 PCI-E X16 插口,不过通过PCI-E转换卡,转成了一个PCI-E X16, 两个PCI-E X8 插口.
PCI-E X16 插口肯定用来插显卡,自带显卡太差,连 1920x1080 的分辨率真都跑不起.
注意显卡最好不要还需要独立供电的,不然得买转接线.
显卡不要太大,我的小显卡都是拆了显卡固定条才安装上去的.

功耗

为了此文,给个准确的功耗数据,淘宝花了50元买了个功耗测试工具.

我接的显卡的 ati hd5450 入门显卡,功耗低.

接电源不开机 10W 左右.
平常使用 120w 左右波动. (加了阵列卡130w)
用鲁大师压测 145W 的样子.

机箱

网上说此主板可以放到普通机箱,本人测试过,拆掉硬盘架之类的,确实放的下.
参考文章 http://tieba.baidu.com/p/3790196594?pn=1

淘宝有机箱现货.
淘宝标题: 静音机箱 原装 DL160 G6 DIY 180G6 316M1 C1100主板支持长显卡 https://item.taobao.com/item.htm?id=521305177590
不过这个机箱需要另外买电源,用不了原装电源.不差钱的买.原装电源声音还是有点大.

本人没钱折腾了,所以没有折腾机箱了.

阵列卡

如果你需要接 SAS 硬盘,或组 RAID5, 你需要买 p410 阵列卡. 记得买一根 mini sas x4 的线. 跟老板说是 dl180 g6用的,他就知道了.

淘宝 阵列卡+电池+512M缓存+线 100包邮.

原装HP P410 6GB 阵列卡462919-001 013233-001 P410 阵列卡 https://item.taobao.com/item.htm?id=525780632164

看了下,包装上面有写着 RMA ,应该是 HP 的退换货件流出来的.

IOH 温度

x58 貌似比较多的主板 IOH 温度都有过高问题,所以需要接个风扇到 IOH 散热片上面.
IOH 散热片的位置位于CPU2与PCI接口的中间. 具体看图. 图在文尾.
有可能是这块主板的问题.到时有入手的朋友,可以告诉一下 IOH 的温度.

https://www.chiphell.com/thread-918499-1-1.html
http://game.ali213.net/thread-2970986-1-1.html

中间以为自己的也是散热片没接好的问题,然后把 IOH 的那个散热拆了,看到芯片旁边写着 IOH ,确认是 IOH 无误.
不小心把散热膏搞到芯片上面后,开不了机,又折腾了几个小时,最后用医生酒精清洗,才开得了机. 散热膏本身是绝缘的,不知道为什么会开不了机.

还碰到另外一个问题,就是用风扇的改装线,本来只要接4个,我接了6个,再换回4个.开机后BIOS检测到变动,貌似在改 BMC .然后再重启,出现 “bmc not responding” 错误,然后找资料,重刷了 BMC ROM 和 SYSTEM ROM 才解决. 怕了.

重置 IPMI 密码

通过 IPMI ,可以通过 http界面远程开关机 .

默认用户与密码是 admin admin

重置教程: http://pan.baidu.com/wap/link?uk=1396009279&shareid=4159928792&third=0

安装提示

  1. 盖子的背面有图,那里有标记 CPU1 和 CPU2 的位置. 前期只安装 CPU1 和插一根内存条.方便测试能否开机.
  2. 离风扇的近的那边的 CPU 与 内存是 1 . 内存不是按数字的顺序插,而是按字母的顺序插. A B C D E F 这样的顺序. 背面的图有说.
  3. CPU 安装请小心,不怕弄坏 CPU ,因为CPU没有针脚,怕搞坏CPU底座,要换主板. 可以参考此文 http://support.huawei.com/enterprise/KnowledgebaseReadAction.action?contentId=KB1000054278&idAbsPath=7919749
  4. 开机自检很久,差不多要1分钟,屏幕没显示时请耐心等待.
  5. 按f10进入bios设置.
  6. 默认优先从 USB 启动,所以做个 USB PE 启动盘,或刷个 Ubuntu 到 U 盘,可以先玩玩.

求打赏

在2月22日这个犯2的日子下了第一笔单,前前后后折腾了一个多月.累.

如果你觉得此坑挖的不错,准备入坑,可以打赏10元或20元小费到我的支付宝,谢谢. ciro9527ATgmail.com (AT换成@)

卖主板,CPU,内存

主板: 梅捷SY-N7HM3-GR
CPU: AMD X2 240
内存: AMD专用内存条两根4G, 共8G. (稳定,没有蓝屏死机过).

180 包邮. 长沙地址自提送机箱加电源,接上显卡和硬盘就能用.

https://2.taobao.com/item.htm?id=528249630350&grade=4.0

装2B图

装B图

IOH 风扇安装位置

IOH 风扇安装位置

开机进入系统后不操作时功耗

开机进入系统后不操作时功耗

打开 CRHOME 功耗

打开 CRHOME 功耗

持续更新地址: https://blog.mangege.com/tech/2016/03/14/1.html

撸了个Win平板点击按屏翻页的小工具

试用了十几个win store的pdf应用,都没办法点击按屏翻页.
只能先把pdf软件设置成按页查看,然后才能点击翻页.

但如果屏幕少于10寸,加上pdf的页边空白,那样看字会好小.

大部分 pdf 软件都支持按 page down 键按屏分页. 包括win自带的阅读器.
但是我们必须得用桌面应用,而不是用store里面的应用.因为 autohotkey 无法热键绑定到 store 里面的应用.

安装 adobe reader, 再运行此脚本.
双击开启按屏分页,再双击关闭按屏分页.
支持放大pdf再按屏分页,这样就可以隐藏页边空白.

脚本: https://gist.github.com/mangege/d28f03634ba6d2e1abe5

Spree 扩展机制分析

参考资料

扩展的分类

  • 类的扩展,主要是对 Model 与 Controller 进行修改. 其它像 Concern 与 Helper 都从属于 Model 与 Controller,一般直接改 Model 与 Controller 即可.
  • 视图的扩展,主要是对 Html 视图进行修改. JS 与 CSS 因为可以通过代码加载顺序来重写现有功能.

类的扩展

类的扩展的实现主要是基于 Ruby 的 Open classes 特性实现.

创建一个测试项目,请先参考 https://github.com/spree/spree 建立一个 Rails Project .
图省事,就不用 spree extension 命令建立一个 Rails engine ,而直接在 Rails Project 写代码测试.

示例一: 访问首页时在控制台打印文字

添加 app/controllers/spree/home_controller_decorator.rb 文件,文件内容如下:

module Spree
  HomeController.class_eval do
    alias_method :old_index, :index
    def index
      puts "#{'#'*100} index test"
      old_index
    end
  end
end

alias_method 是 Rails 的方法,用于重命名现有的方法并删除,方便重写方法时再调用老的方法.

Open classes 除了可以用 class_eval 这样来实现,还可以直接用 class A; end 这样的类定义语法来实现同样的功能.
之所以用 class_eval ,有两个个人能想到的优点:

  1. 用 class_eval 这种形式,肯定会先把原来的 class 给加载, 而用类定义语法就不一定了.
  2. 类定义语法,再次打开类,还需要记得原来的 class 的父类,如果不同的话,到时会报 superclass mismatch for class 错误.

文件名结尾一定要以 decorator 结尾,这样才能保证在开发模式时,每次自动请求会自动重新加载此文件.

decorator 分析

查看 Spree 源码的 core/lib/spree/core/engine.rb 文件,可以看到这样一段代码:

  config.to_prepare do
    # Load application's model / class decorators
    Dir.glob(File.join(File.dirname(__FILE__), '../../../app/**/*_decorator*.rb')) do |c|
      Rails.configuration.cache_classes ? require(c) : load(c)
    end
  end

to_prepare 为 Rails 的方法,此处用来加载 decorator 文件.
glob 用来查找所有包含 _decorator 的文件.
Rails.configuration.cache_classes 判断是否开启类缓存, 开启的话,用require加载文件,可以防止重复加载.否则用load方法,这样能保证每次请求,decorator的代码都是最新的.

to_prepare 分析

在项目里的 config/application.rb 文件增加以下内容:

config.to_prepare do
  puts "#{'$'*100} to_prepare test"
end

重启 rails server, 可以看到在启动后,就执行了添加的回调. 但再次访问不会执行回调. 随便修改一个 controller 文件,可以看到回调再次执行了.
基于 to_prepare 方法,这样就可以保证被修改的类不会被漏加载.

视图的扩展

视图的扩展有两种实现方法

1. 基于 Rails view path的加载顺序实现

添加 app/views/spree/home/index.html 文件,内容随便写点,比如 hello

再次访问首页,可以看到首页的内容变成 hello 去了.

View Paths 这一章的文档刚好没有,所以个人简单的介绍一下.

在rails console运行 ActionController::Base.view_paths.each{|a| puts a.to_path}; nil , 可以看到所有视图目录, Rails 是在这些目录下一个一个找,找到了就停止查找. 可以看到, Rails Proejct 的目录是在最前面的.

这种方式会替换此视图,没办法像 Deface 可以根据 DOM 查找添加内容到指定位置,或删除指定节点.

删除 app/views/spree/home/index.html 文件,方便再测试.

2. 基于 Deface 实现

示例在首页的侧边添加一行 Hello world

在 Rails 项目里新建 app/overrides/add_hello_to_home.rb 文件,文件内容如下:

Deface::Override.new(
  :virtual_path => 'spree/home/index',
  :name => 'add_hello_to_home',
  :insert_after => "erb[silent]:contains('sidebar')",
  :text => "<p><%= 'hello world' * 10 %></p>"
)

之后访问首页,可以看到侧边顶部增加一行hello world.

执行 rake deface:precompile 命令,可以看到生成了 app/compiled_views/spree/home/index.html.erb 文件内容,内容如下:

<% content_for :sidebar do %><p><%= 'hello world' * 10 %></p>
  <div data-hook="homepage_sidebar_navigation">
    <%= render :partial => 'spree/shared/taxonomies' %>
  </div>
<% end %>

<div data-hook="homepage_products">
  <% cache(cache_key_for_products) do %>
    <%= render :partial => 'spree/shared/products', :locals => { :products => @products } %>
  <% end %>
</div>

而原始文件 frontend/app/views/spree/home/index.html.erb 内容如下:

<% content_for :sidebar do %>
  <div data-hook="homepage_sidebar_navigation">
    <%= render :partial => 'spree/shared/taxonomies' %>
  </div>
<% end %>

<div data-hook="homepage_products">
  <% cache(cache_key_for_products) do %>
    <%= render :partial => 'spree/shared/products', :locals => { :products => @products } %>
  <% end %>
</div>

重启 rails console,再运行 ActionController::Base.view_paths.each{|a| puts a.to_path}; nil 语句,可以看到, app/compiled_views 这个目录的顺序是在 app/views 前面,排在第一位,所以最终还是靠 view paths来实现的.

deface 的作用是用来修改 erb 文件,但它解决了 erb 不能通过 dom 树来查找的问题.

分析 deface 的源码发现, 在 lib/deface/parser.rb 此文件,可以知道 deface 只是简单的把 <%= %> <% %> 替换成 <erb loud> <erb silent> </erb> 这样的非标准的html标签,再通过 Nokogiri 解析,执行 deface override代码里的替换,替换完后再把erb标签替换回来.

结尾

示例项目源码: https://github.com/mangege/spree_hack_example

为类增加代码很简单,但删除就很麻烦.比如从 Model 移除一个属性的 validate ,这个时候需要分析Rails的validate的实现,再写hack代码.

单元测试非常重要,因为没有单元测试,你没有办法保证你的 hack 代码在下个版本的 spree 和 rails 还是能正常运行.

新版ThinkPad USB指点杆键盘linux配置

喜欢 ThinkPad 的指点杆键盘,移动光标时手不需要离开键盘区.

在淘宝上面淘一个 0B47190 的国行指点杆键盘. 接上电脑,在 archlinux 上面,上下滚动能正常使用.
但有点小问题,按中键的时候,会先执行中键的功能,比如在终端上会粘贴剪切版的内容.

参考 https://wiki.archlinux.org/index.php/TrackPoint 的配置,执行 ~/.xinitrc 文件的内容,然后中键滚动都不能用了.

折腾模式开启了,主要参考了以下资料.

  1. http://www.x.org/archive/X11R7.7/doc/man/man5/xorg.conf.5.xhtml#heading9
  2. http://www.x.org/archive/X11R7.5/doc/man/man4/evdev.4.html
  3. https://wiki.ubuntu.com/X/Config/Input

首先用 xinput list 列出输入设备,查找设备的ID.指点杆设备是在 “Virtual core pointer” 节点下,另外个同名的设备为键盘.

$ xinput list
⎡ Virtual core pointer                      id=2015[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4[slave  pointer  (2)]
⎜   ↳ Lenovo ThinkPad Compact USB Keyboard with TrackPointid=9[slave  pointer  (2)]
⎣ Virtual core keyboard                     id=3[master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5[slave  keyboard (3)]
    ↳ Power Button                              id=6[slave  keyboard (3)]
    ↳ Power Button                              id=7[slave  keyboard (3)]
    ↳ Lenovo ThinkPad Compact USB Keyboard with TrackPointidid=8[slave  keyboard (3)]

再用 xinput test 9 测试键值,命令中的9为你的测试的输入设备的ID. 测试发现,按下中键会打印出 “button press 2”,在不释放中键的同时触摸指点杆,提示 “button press 4” 之类的.
接上一个普通的usb鼠标,再测试,发现滚动的键值都一样. 猜测键值: 1=左键, 2=中键, 3=右键, 4 5 6 7对应着上下左右滚动.
因手边没有ThinkPad电脑,没办法测试上文提到的 .xinitrc 配置的开启 Evdev Wheel Emulation 选项后 xinput-test 打印值的差别.
个人估计,新版的thinkpad键盘直接是硬件上就直接兼容标准的鼠标键值了,而不再需要配置 Wheel Emulation .

所有,解决方案根本不需要管滚动这一块,只需要处理中键粘贴的问题.简单粗爆的方法,直接禁用中键.

方式一是在 .xinitrc 里添加以下行命令.

xinput set-button-map "Lenovo ThinkPad Compact USB Keyboard with TrackPoint" 1 0 3 4 5 6 7 8 9 10 11 12 13

“Lenovo ThinkPad Compact USB Keyboard with TrackPoint” 这个值是通过xinput获取到的, 后面的数值是通过 xinput get-button-map 9获取来的.
设置时,把2的值置为0,这样就禁用掉中键的.

4 5为上下,如果我们把4 5的键值位置对换一下,应该可以实现 Mac 的滚动习惯的.

方式二是通过 xorg configuration 实现,创建一个 /etc/X11/xorg.conf.d/20-thinkpad.conf 文件,内容如下:

Section "InputClass"
    Identifier  "Trackpoint"
    MatchUSBID          "17ef:6047"
    MatchIsPointer      "true"
    Option              "ButtonMapping"         "1 0 3 4 5 6 7 8 9 10 11 12 13"
EndSection

查看 xorg conf 文档,觉得 MatchUSBID 更适合,而不是示例给的 MatchProduct 指令,通过 lsusb 命令查找设备的id.
查看 man evdev 文档,配置 InvertX 选项,应该也可以实现 Mac 的滚动习惯.

xorg conf 还是很强大,可惜不了解 Linux 系统编程.得加油!!!

python调用saltstack的几种方式

saltstack本身是用python写的,用python调用saltstack相对来说比较简单.

个人想到的调用方式有下:

1. Python client API

http://docs.saltstack.com/en/latest/ref/clients/#salt.wheel.WheelClient.cmd

优点:

  1. 最简单,只要机器安装了saltstack,直接在python代码里 import salt 即可.

缺点:

  1. 只有python语言才能这样使用.
  2. 必须得与salt master部署在同一台机器.
  3. saltstack任务执行时,某些处理是在调用方进程里执行,这样意味调用方的必须与salt master同用户,否则到时会没有权限往 /var/cache/salt/master 目录写缓存文件. 比如salt master是root用户运行,那么django网站调用salt时也必须得也root用户运行.

2. salt api

https://salt-api.readthedocs.org/en/latest/

优点:

  1. 以 http rest api形式提供访问,这样什么语言都可以调用.
  2. 调用方可以不与salt master在同一机器.
  3. 调用方完全可用普通用户运行.

缺点:

  1. 需要自己对rest api做一次封装.
  2. 调用 salt.modules.cp.push 时,文件存放在 salt master上面.这个时候需要拿到文件必须得走NFS或自定义接口.

3. salt command

直接在程序里调用 salt 命令来执行任务

优点:

  1. 简单粗暴

缺点:

  1. 需要自己解决命令执行结果,出错处理太难.

Linux使用ffmpeg直播推流

各直播网站直播教程都有提到OBS(Open Broadcaster Software),但在archlinux编译成功,运行却报错.
后来了解到ffmpeg可以推流,花了一两天简单的了解ffmpeg的命令参数.并成功在斗鱼上面直播.

主要参考 ffmpeg 的 wiki 的 Encoding for streaming sites

斗鱼的rtmp推流地址是 rtmp地址 加 / 加 直播码.
示例: rtmp://send3.douyutv.com/live/209282rr9tq83W9I?wsSecret=6d7cb31146e722d561e55eb75f9b6e6f&wsTime=54e051be.
注意此直播码每次关闭直播后会变动.

关于码率

请参考此文章 斗鱼TV游戏直播教程-OBS直播软件篇[推荐]

1Mbps左右的请设置最大码率为500kbps,压缩分辨率为720x480或与480接近。
2Mbps左右的请设置最大码率为1500kbps,压缩分辨率为1280x720或与720接近。
低于0.5Mbps的,还是去看直播吧。

对应的参数为 maxrate 与 bufsize, bufsize 斗鱼是推荐是 maxrate 一样.

ffmpeg 示例

捕获桌面,麦克风,摄像头命令参数示例:

$ ffmpeg -f x11grab -video_size 1680x1050 -framerate 30 -i :0.0 \
-f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
-f alsa -ac 2 -i hw:0,0 -filter_complex \
"[0:v]scale=1024:-1,setpts=PTS-STARTPTS[bg]; \
 [1:v]scale=120:-1,setpts=PTS-STARTPTS[fg]; \
 [bg][fg]overlay=W-w-10:10,format=yuv420p[out]"
-map "[out]" -map 2:a -vcodec libx264 -preset veryfast \
-maxrate 3000k -bufsize 4000k -acodec libmp3lame -ar 44100 -b:a 128k \
-f flv rtmp://send3.douyutv.com/live/209282rr9tq83W9I?wsSecret=6d7cb31146e722d561e55eb75f9b6e6f&wsTime=54e051be

循环播放文件示例,使用的是 concat 特性.

ffmpeg -re -f concat -i playlist.txt \
-vcodec libx264 -preset veryfast -maxrate 500k -bufsize 500k \
-vf "format=yuv420p:scale=720:-1" -g 48 -acodec libmp3lame -b:a 96k -ar 44100 \
-f flv "rtmp://send3.douyutv.com/live/209282rezHd16aNm?wsSecret=f759db6daa4137c184e2f16125d8af5d&wsTime=54dd5819"

视频加文字示例,使用的是 drawtext 特性.

ffmpeg -re -f concat -i playlist.txt \
-vcodec libx264 -preset veryfast -maxrate 500k -bufsize 500k \
-vf "format=yuv420p:scale=720:-1" -g 48 -acodec libmp3lame -b:a 96k -ar 44100 \
-filter:v "drawtext=fontsize=12:fontcolor=red:fontfile=/usr/share/fonts/TTF/DejaVuSans.ttf:text='CodeMonkeys %{localtime\:%T}':y=17:x=900" \
-f flv "rtmp://send3.douyutv.com/live/209282rezHd16aNm?wsSecret=f759db6daa4137c184e2f16125d8af5d&wsTime=54dd5819"

大部分功能ffmpeg wiki都有示例,比如配置摄像头,配置捕获桌面的,请记住 wiki 地址 https://trac.ffmpeg.org/wiki

另外 ffmpeg 的参数排列你要看懂.

usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

ffmpeg 通用选项 输入文件选项 输入文件 很多的输入文件 输出文件选项 输出文件 很多的输出文件
也就是说,可以有多个输入,也可以有多个输出.这样可以实现推流到网站时同时本地保存一份.

关于在linux服务器播放视频.

安装可以直接安装静态编译包,解压后就可以运行了, 而且一般比较新. http://johnvansickle.com/ffmpeg/

测试过在阿里云的最低配置,码率设置为500k,差不多刚好够播放.
通过ifstat命令测试,2M带宽播放码率1500k也够了,就实时转码CPU不够用.
请提前把文件转换成flv格式,这样应该就不卡了.

关于在斗鱼上面播放视频

貌似大部分有版权问题的视频都不能放,但不清楚别人为什么能放.

LG VS840 VS920可精简应用列表

本文是基于vs920 v9系统写的,理论上vs840 v9也可以用.

首先你得安装adb,通过adb shell连接上手机后,运行下面命令

pm list packages -f -s

列表系统所有的程序. 运行结果请看 附录一 .

把附录一的结果保存为一个普通文件,保存到linux电脑的/tmp/目录,之后再运行下面命令过滤出可以删除的应用.

cat v9_list.txt | grep -v com.android | grep -v com.lge | grep -v ipsec | grep -v com.google | grep -v com.qualcomm | grep -v framework | grep -v com.adobe.flashplayer | grep -v com.broadcom.bt.app.system | grep -v com.innopath

运行结果请看附录二,此命令主要保留Google与LG厂商开发的应用.

重新挂载 system 目录为可写

mount -o remount,rw /system

之后就是执行rm 与 pm uninstall 命令了

rm /system/app/Aetherpal.apk
rm /system/app/Kindle.apk
rm /system/app/NFSHP.apk
rm /system/app/ScoreCenter.apk
rm /system/app/BaSyncService.apk
rm /system/app/LGolf2.apk
rm /vendor/app/PolarisOffice.apk
rm /system/app/NFL.apk
rm /system/app/SSO_P3.apk
rm /system/app/SmartMovieHD.apk
rm /system/app/Netflix.apk
rm /system/app/Slacker.apk
rm /system/app/Swype.apk
rm /system/app/TuneWiki.apk
rm /system/app/BUAPLUS.apk
rm /system/app/VideoCallingPortal.apk
rm /system/app/appdirectedsmspermission.apk
rm /system/app/qospermission.apk
rm /system/app/securesettingspermission.apk
rm /system/app/ssopermission.apk
rm /system/app/vzwapnpermission.apk
rm /system/app/SecureSettingsService.apk
rm /system/app/VZNavigator.apk
rm /system/app/VZWAPNService.apk
rm /system/app/VCastTones.apk
rm /system/app/MyVerizon.apk
rm /system/app/VzwSMS.apk

pm uninstall com.Aetherpal.Device
pm uninstall com.amazon.kindle
pm uninstall com.ea.nfshp
pm uninstall com.espn.score_center
pm uninstall com.fusionone.android.sync.service
pm uninstall com.gameloft.android.Verizon.GloftLG2P
pm uninstall com.infraware.polarisoffice
pm uninstall com.mobitv.client.nfl2010
pm uninstall com.motricity.verizon.ssodownloadable
pm uninstall com.muvee.studio
pm uninstall com.netflix.mediaclient
pm uninstall com.slacker.radio
pm uninstall com.swype.android.inputmethod
pm uninstall com.tunewiki.lyricplayer.android
pm uninstall com.vcast.mediamanager
pm uninstall com.verizon.android.videocallingportal
pm uninstall com.verizon.permissions.appdirectedsms
pm uninstall com.verizon.permissions.qos
pm uninstall com.verizon.permissions.securesettings
pm uninstall com.verizon.permissions.sso
pm uninstall com.verizon.permissions.vzwappapn
pm uninstall com.verizon.settingsservice
pm uninstall com.vznavigator.VS9204G
pm uninstall com.vzw.apnservice
pm uninstall com.vzw.hs.android.modlite
pm uninstall com.vzw.hss.myverizon
pm uninstall com.vzw.sms

不喜欢Google的应用,可以直接用Android的应用程序管理,把Google的应用都停用掉,本人亲测,都可以停用.
之所以选择停用,是网上说删除掉Google Play电影会开不了机.

附录一

package:/system/framework/framework-res.apk=android
package:/system/app/Aetherpal.apk=com.Aetherpal.Device
package:/system/app/oem_install_flash_player_ics.apk=com.adobe.flashplayer
package:/system/app/Kindle.apk=com.amazon.kindle
package:/system/app/LGVZWSetupWizard.apk=com.android.LGSetupWizard
package:/system/app/BackupRestoreConfirmation.apk=com.android.backupconfirm
package:/system/app/Bluetooth.apk=com.android.bluetooth
package:/system/app/LGBrowser.apk=com.android.browser
package:/system/app/LGCalculator.apk=com.android.calculator2
package:/system/app/LGCalendar.apk=com.android.calendar
package:/system/app/CertInstaller.apk=com.android.certinstaller
package:/system/app/LGContacts3.apk=com.android.contacts
package:/system/app/DefaultContainerService.apk=com.android.defcontainer
package:/system/app/FaceLock.apk=com.android.facelock
package:/system/app/GalleryLG2.apk=com.android.gallery3d
package:/system/app/HTMLViewer.apk=com.android.htmlviewer
package:/system/app/KeyChain.apk=com.android.keychain
package:/system/app/NativeMagicSmokeWallpapers.apk=com.android.magicsmoke
package:/system/app/LGUSMms.apk=com.android.mms
package:/system/app/MusicFX.apk=com.android.musicfx
package:/system/app/PackageInstaller.apk=com.android.packageinstaller
package:/system/app/LGPhone.apk=com.android.phone
package:/system/app/ApplicationsProvider.apk=com.android.providers.applications
package:/system/app/LGCalendarProvider.apk=com.android.providers.calendar
package:/system/app/LGContactsProvider3.apk=com.android.providers.contacts
package:/system/app/LGDownloadProvider.apk=com.android.providers.downloads
package:/system/app/LGDownloadProviderUi.apk=com.android.providers.downloads.ui
package:/system/app/DrmProvider.apk=com.android.providers.drm
package:/system/app/MediaProvider.apk=com.android.providers.media
package:/system/app/LGSettingsProvider.apk=com.android.providers.settings
package:/system/app/LGUSTelephonyProvider.apk=com.android.providers.telephony
package:/system/app/UserDictionaryProvider.apk=com.android.providers.userdictionary
package:/system/app/LGSettings.apk=com.android.settings
package:/system/app/SharedStorageBackup.apk=com.android.sharedstoragebackup
package:/system/app/WAPPushManager.apk=com.android.smspush
package:/system/app/Stk.apk=com.android.stk
package:/system/app/SystemUI.apk=com.android.systemui
package:/system/app/Phonesky.apk=com.android.vending
package:/system/app/VoiceDialer_ics.apk=com.android.voicedialer
package:/system/app/VpnDialogs.apk=com.android.vpndialogs
package:/vendor/app/NativeLiveWallpapers2.apk=com.android.wallpaper
package:/system/app/NativeLiveWallpapersPicker.apk=com.android.wallpaper.livepicker
package:/system/app/BluetoothServices.apk=com.broadcom.bt.app.system
package:/system/app/NFSHP.apk=com.ea.nfshp
package:/system/app/ScoreCenter.apk=com.espn.score_center
package:/system/app/BaSyncService.apk=com.fusionone.android.sync.service
package:/system/app/LGolf2.apk=com.gameloft.android.Verizon.GloftLG2P
package:/system/app/Books.apk=com.google.android.apps.books
package:/system/app/Magazines.apk=com.google.android.apps.magazines
package:/system/app/GMS_Maps.apk=com.google.android.apps.maps
package:/system/app/PlusOne.apk=com.google.android.apps.plus
package:/system/app/MediaUploader.apk=com.google.android.apps.uploader
package:/system/app/GoogleBackupTransport.apk=com.google.android.backup
package:/system/app/GoogleFeedback.apk=com.google.android.feedback
package:/system/app/Gmail2.apk=com.google.android.gm
package:/system/app/GmsCore.apk=com.google.android.gms
package:/system/app/GoogleQuickSearchBox.apk=com.google.android.googlequicksearchbox
package:/system/app/GoogleServicesFramework.apk=com.google.android.gsf
package:/system/app/GoogleLoginService.apk=com.google.android.gsf.login
package:/system/app/NetworkLocation.apk=com.google.android.location
package:/system/app/talkback.apk=com.google.android.marvin.talkback
package:/system/app/Music2.apk=com.google.android.music
package:/system/app/GooglePartnerSetup.apk=com.google.android.partnersetup
package:/system/app/SetupWizard.apk=com.google.android.setupwizard
package:/system/app/Street.apk=com.google.android.street
package:/system/app/GoogleCalendarSyncAdapter.apk=com.google.android.syncadapters.calendar
package:/system/app/GoogleContactsSyncAdapter.apk=com.google.android.syncadapters.contacts
package:/system/app/Hangouts.apk=com.google.android.talk
package:/system/app/GoogleTTS.apk=com.google.android.tts
package:/system/app/Videos.apk=com.google.android.videos
package:/system/app/VoiceSearch.apk=com.google.android.voicesearch
package:/system/app/YouTube.apk=com.google.android.youtube
package:/vendor/app/PolarisOffice.apk=com.infraware.polarisoffice
package:/system/app/MobileUpdateClient.apk=com.innopath.activecare
package:/system/app/SDMPlugin.apk=com.innopath.activecare.dev.oem
package:/system/app/VpnClient.apk=com.ipsec.vpnclient
package:/system/app/LGVZWAppSetupWizard.apk=com.lge.AppSetupWizard
package:/system/app/LgTestMenu.apk=com.lge.LgHiddenMenu
package:/system/app/VerizonHiddenMenu.apk=com.lge.VerizonHiddenMenu
package:/system/app/RichNote_VZW.apk=com.lge.app.richnote
package:/system/app/BluetoothControllerWidget.apk=com.lge.appwidget.settings.bluetoothcontroller
package:/system/app/CameraApp.apk=com.lge.camera
package:/system/app/CameraTestApp.apk=com.lge.cameratest
package:/system/app/CarHome.apk=com.lge.carhome
package:/system/app/NightScapeCW.apk=com.lge.chargingwallpaper.nightscape
package:/system/app/ChargingWallpaperPicker.apk=com.lge.chargingwallpaper.picker
package:/system/app/RisingTideCW_RS.apk=com.lge.chargingwallpaper.risingtidecw
package:/system/app/LGAlarmClock.apk=com.lge.clock
package:/system/app/LGDefaultAccount.apk=com.lge.defaultaccount
package:/system/app/DeskHome.apk=com.lge.deskhome
package:/system/app/LGEmail_vzw.apk=com.lge.email
package:/system/app/HelpCenter.apk=com.lge.helpcenter
package:/system/app/HotspotProvision.apk=com.lge.hotspotprovision
package:/system/app/LGEIME.apk=com.lge.ime
package:/system/app/ImsProvider.apk=com.lge.ims.provider
package:/system/framework/lge-res.apk=com.lge.internal
package:/system/app/InTouchWidget.apk=com.lge.intouch
package:/system/app/IOTTestMenu.apk=com.lge.iot_hidden_menu
package:/system/app/LGHome3.apk=com.lge.launcher2
package:/system/app/LGDrm.apk=com.lge.lgdrm.permission
package:/system/app/LockScreen.apk=com.lge.lockscreen
package:/system/app/LockScreenSettings.apk=com.lge.lockscreensettings
package:/system/app/MLT.apk=com.lge.mlt
package:/system/app/MobileHotspot.apk=com.lge.mobilehotspot.ui
package:/system/app/MusicPlayer.apk=com.lge.music
package:/system/app/PhoneTestMode.apk=com.lge.phonetestmode
package:/system/app/PouchLockScreen.apk=com.lge.pouchlockscreen
package:/system/app/CompatibilityMode.apk=com.lge.settings.compatmode
package:/system/app/com.lge.shutdownmonitor.apk=com.lge.shutdownmonitor
package:/system/app/CalendarWidget.apk=com.lge.sizechangable.calendar
package:/system/app/EmailWidget.apk=com.lge.sizechangable.email
package:/system/app/FavoriteContactsWidget.apk=com.lge.sizechangable.favoritecontacts
package:/system/app/MemoWidget.apk=com.lge.sizechangable.memo
package:/system/app/MessageWidget.apk=com.lge.sizechangable.message
package:/system/app/MusicWidget.apk=com.lge.sizechangable.musicwidget.widget
package:/system/app/PhotoAlbumWidget.apk=com.lge.sizechangable.photoalbum
package:/system/app/PhotoFrameWidget.apk=com.lge.sizechangable.photoframe
package:/system/app/WeatherMultiCPbin.apk=com.lge.sizechangable.weather
package:/system/app/WeatherThemebin.apk=com.lge.sizechangable.weather.theme.optimus
package:/system/app/LGWorldClockWidget.apk=com.lge.sizechangable.worldclock
package:/system/app/SmartShare.apk=com.lge.smartshare
package:/system/app/SNC.apk=com.lge.snc
package:/system/app/StreamingPlayer.apk=com.lge.streamingplayer
package:/system/app/LGSystemServer.apk=com.lge.systemservice
package:/system/app/androidUTSManager.apk=com.lge.uts
package:/system/app/AnalogClockWidget.apk=com.lge.variousstyle.anlaogclock
package:/system/app/DigitalClockWidget.apk=com.lge.variousstyle.digitalclock
package:/system/app/VideoPlayer.apk=com.lge.videoplayer
package:/system/app/VoiceRecorder.apk=com.lge.voicerecorder
package:/system/app/VVM.apk=com.lge.vvm
package:/system/app/BaSyncClient.apk=com.lge.vzw.bua
package:/system/app/NFL.apk=com.mobitv.client.nfl2010
package:/system/app/SSO_P3.apk=com.motricity.verizon.ssodownloadable
package:/system/app/SmartMovieHD.apk=com.muvee.studio
package:/system/app/Netflix.apk=com.netflix.mediaclient
package:/system/app/PrivInit.apk=com.qualcomm.privinit
package:/system/app/Wiper.apk=com.qualcomm.wiper
package:/system/app/Slacker.apk=com.slacker.radio
package:/system/app/Swype.apk=com.swype.android.inputmethod
package:/system/app/TuneWiki.apk=com.tunewiki.lyricplayer.android
package:/system/app/BUAPLUS.apk=com.vcast.mediamanager
package:/system/app/VideoCallingPortal.apk=com.verizon.android.videocallingportal
package:/system/app/appdirectedsmspermission.apk=com.verizon.permissions.appdirectedsms
package:/system/app/qospermission.apk=com.verizon.permissions.qos
package:/system/app/securesettingspermission.apk=com.verizon.permissions.securesettings
package:/system/app/ssopermission.apk=com.verizon.permissions.sso
package:/system/app/vzwapnpermission.apk=com.verizon.permissions.vzwappapn
package:/system/app/SecureSettingsService.apk=com.verizon.settingsservice
package:/system/app/VZNavigator.apk=com.vznavigator.VS9204G
package:/system/app/VZWAPNService.apk=com.vzw.apnservice
package:/system/app/VCastTones.apk=com.vzw.hs.android.modlite
package:/system/app/MyVerizon.apk=com.vzw.hss.myverizon
package:/system/app/VzwSMS.apk=com.vzw.sms

附录二

package:/system/app/Aetherpal.apk=com.Aetherpal.Device
package:/system/app/Kindle.apk=com.amazon.kindle
package:/system/app/NFSHP.apk=com.ea.nfshp
package:/system/app/ScoreCenter.apk=com.espn.score_center
package:/system/app/BaSyncService.apk=com.fusionone.android.sync.service
package:/system/app/LGolf2.apk=com.gameloft.android.Verizon.GloftLG2P
package:/vendor/app/PolarisOffice.apk=com.infraware.polarisoffice
package:/system/app/NFL.apk=com.mobitv.client.nfl2010
package:/system/app/SSO_P3.apk=com.motricity.verizon.ssodownloadable
package:/system/app/SmartMovieHD.apk=com.muvee.studio
package:/system/app/Netflix.apk=com.netflix.mediaclient
package:/system/app/Slacker.apk=com.slacker.radio
package:/system/app/Swype.apk=com.swype.android.inputmethod
package:/system/app/TuneWiki.apk=com.tunewiki.lyricplayer.android
package:/system/app/BUAPLUS.apk=com.vcast.mediamanager
package:/system/app/VideoCallingPortal.apk=com.verizon.android.videocallingportal
package:/system/app/appdirectedsmspermission.apk=com.verizon.permissions.appdirectedsms
package:/system/app/qospermission.apk=com.verizon.permissions.qos
package:/system/app/securesettingspermission.apk=com.verizon.permissions.securesettings
package:/system/app/ssopermission.apk=com.verizon.permissions.sso
package:/system/app/vzwapnpermission.apk=com.verizon.permissions.vzwappapn
package:/system/app/SecureSettingsService.apk=com.verizon.settingsservice
package:/system/app/VZNavigator.apk=com.vznavigator.VS9204G
package:/system/app/VZWAPNService.apk=com.vzw.apnservice
package:/system/app/VCastTones.apk=com.vzw.hs.android.modlite
package:/system/app/MyVerizon.apk=com.vzw.hss.myverizon
package:/system/app/VzwSMS.apk=com.vzw.sms

LG VS840系统修改小工具 XposedLucidMod

废话

买两百从淘宝买了个LG VS840电信手机来玩,这手机性价比不错,双核,1G内存,8G存储,IPS硬屏.
有点郁闷的是原生系统默认是连接不上国内的电信网络打电话,需要修改设置里的选项才行.而此选项却隐藏起来,需要修改LGSettings.apk文件才能使用.

网上有修改好的LGSettings.apk文件,不过都是rom v8以前的版本,v9无法使用.
个人不喜欢替换原生系统的文件,用过一个不错的权限管理软件xprivacy,从而了解到xposed这个强大的rom修改框架,此框架修改rom无需要修改apk文件,大爱.

XposedLucidMod功能列表

  • 添加系统选择到设置
  • 从设置里删除Backup Assistant Plus
  • 从帐号与同步里删除VERIZON帐户选项
  • 删除状态栏的三角形漫游图标
  • 删除定位的十字架图标

效果图请看 http://pan.baidu.com/s/1sjzyceL

安装教程

XposedLucidMod源码

https://github.com/mangege/XposedLucidMod

在Linux用VirtualBox跑<自己动手写操作系统>示例一

在看于渊的<自己动手写操作系统>,第一章的示例用到软驱.
在这个年代,找到带软驱的计算机还真不容易,还好有虚拟机.

VirtualBox默认支持软驱镜像文件启动,难点在于在Linux环境创建软驱镜像并且把boot.bin写到镜像文件里.

本文基于archlinux环境操作,需要用到dd losetup mkfs.vfat等命令.
mkfs.vfat需要安装dosfstools这个包.

1 首先创建镜像文件

sudo dd if=/dev/zero of=/tmp/floppy.img bs=1k count=1440

2 格式化镜像文件

sudo mkfs.vfat /tmp/floppy.img

3 安装设备

sudo losetup losetup /dev/loop7 /tmp/floppy.img

4 复制启动文件

sudo dd if=boot.bin of=/dev/loop7 bs=512 count=1

5 删除设备

losetup -d /dev/loop7

6 设置VirtualBox的Floppy为”/tmp/floppy.img”文件

设置 -> 存储 -> 选择一个虚拟软盘

效果图
LinuxVBoxFloppy