<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Farseerfc的小窝 - arch</title><link href="//farseerfc.me/zhs/" rel="alternate"></link><link href="//farseerfc.me/feeds/tag-arch.atom.xml" rel="self"></link><id>//farseerfc.me/zhs/</id><updated>2016-07-31T03:52:00+09:00</updated><entry><title>PacVis: 可视化 pacman 本地数据库</title><link href="//farseerfc.me/zhs/pacvis.html" rel="alternate"></link><published>2016-07-31T03:52:00+09:00</published><updated>2016-07-31T03:52:00+09:00</updated><author><name>farseerfc</name></author><id>tag:farseerfc.me,2016-07-31:/zhs/pacvis.html</id><summary type="html">
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
PacVis&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="Demo of PacVis" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-first.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="pacvis"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id11"&gt;我为什么要做 PacVis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我喜欢 Arch Linux ，大概是因为唯有 Arch Linux 能给我对整个系统「了如指掌」的感觉。
在 Arch Linux 里我能清楚地知道我安装的每一个包，能知道系统里任何一个文件是来自哪个包，
以及我为什么要装它。或许对 Debian/Fedora/openSUSE 足够熟悉了之后也能做到这两点，
不过他们的细致打包的结果通常是包的数量比 Arch 要多个 3 到 10 倍，并且打包的细节也比 Arch
Linux 简单的 PKGBUILD 要复杂一个数量级。&lt;/p&gt;
&lt;p&gt;每一个装过 Arch Linux 的人大概都知道，装了 Arch Linux 之后得到的系统非常朴素，按照
ArchWiki 上的流程一路走下来的话，最关键的一条命令就是 &lt;code class="code"&gt;
pacstrap /​mnt …&lt;/code&gt;&lt;/p&gt;&lt;/div&gt;</summary><content type="html">
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
PacVis&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="Demo of PacVis" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-first.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="pacvis"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id11"&gt;我为什么要做 PacVis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我喜欢 Arch Linux ，大概是因为唯有 Arch Linux 能给我对整个系统「了如指掌」的感觉。
在 Arch Linux 里我能清楚地知道我安装的每一个包，能知道系统里任何一个文件是来自哪个包，
以及我为什么要装它。或许对 Debian/Fedora/openSUSE 足够熟悉了之后也能做到这两点，
不过他们的细致打包的结果通常是包的数量比 Arch 要多个 3 到 10 倍，并且打包的细节也比 Arch
Linux 简单的 PKGBUILD 要复杂一个数量级。&lt;/p&gt;
&lt;p&gt;每一个装过 Arch Linux 的人大概都知道，装了 Arch Linux 之后得到的系统非常朴素，按照
ArchWiki 上的流程一路走下来的话，最关键的一条命令就是 &lt;code class="code"&gt;
pacstrap /​mnt base&lt;/code&gt;
 ，
它在 &lt;code class="code"&gt;
/​mnt&lt;/code&gt;
 里作为根调用 &lt;code class="code"&gt;
pacman -S base&lt;/code&gt;
 装上了整个 base 组，
然后就没有然后了。这个系统一开始空无一物，你需要的任何东西都是后来一点点用
&lt;code class="code"&gt;
pacman&lt;/code&gt;
 手动装出来的，没有累赘，按你所需。&lt;/p&gt;
&lt;p&gt;然而时间长了，系统中难免会有一些包，是你装过用过然后忘记了，
然后这些包就堆在系统的角落里，就像家里陈年的老家具，占着地，落着灰。虽然
&lt;code class="code"&gt;
pacman -Qtd&lt;/code&gt;
 能方便地帮你找出所有
&lt;strong&gt;曾经作为依赖被装进来，而现在不被任何包依赖&lt;/strong&gt; 的包，但是对于那些你手动指定的包，
它就无能为力了。&lt;/p&gt;
&lt;p&gt;于是我就一直在找一个工具能帮我梳理系统中包的关系，方便我：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;找出那些曾经用过而现在不需要的包&lt;/li&gt;
&lt;li&gt;找出那些体积大而且占地方的包&lt;/li&gt;
&lt;li&gt;厘清系统中安装了的包之间的关系&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="figure"&gt;
&lt;img alt="Android System Architecture" class="img-responsive" src="//farseerfc.me/zhs/images/Android-System-Architecture.jpg"/&gt;
&lt;p class="caption"&gt;&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Android_(operating_system)"&gt;Android 系统架构&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;关于最后一点「厘清包的关系」，我曾经看到过
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Architecture_of_OS_X"&gt;macOS 系统架构图&lt;/a&gt;
和 Android 的系统架构图，对其中的层次化架构印象深刻，之后就一直在想，是否能画出现代
Linux 桌面系统上类似的架构图呢？又或者 Linux 桌面系统是否会展现完全不同的样貌？
从维基百科或者别的渠道能找到 Linux 内核、或者 Linux 图形栈，
或者某个桌面环境的架构，但是没有找到覆盖一整个发行版的样貌的。
于是我便想，能不能从包的依赖关系中自动生成这样一张图呢。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id1"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id12"&gt;PacVis的老前辈们&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在开始写 PacVis 之前，我试过一些类似的工具，他们都或多或少能解决一部分我的需要，
又在某些方面有所不足。这些工具成为了 PacVis 的雏形，启发了 PacVis
应该做成什么样子。&lt;/p&gt;
&lt;div class="section" id="pactree"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id13"&gt;pactree&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;pactree 曾经是一个
&lt;a class="reference external" href="https://bbs.archlinux.org/viewtopic.php?id=51795"&gt;独立的项目&lt;/a&gt; ，现在则是
&lt;a class="reference external" href="https://www.archlinux.org/pacman/pactree.8.html"&gt;pacman 的一部分&lt;/a&gt; 了。
从手册页可以看出， pactree 的输出是由某个包开始的依赖树。
加上 &lt;code class="code"&gt;
--graph&lt;/code&gt;
 参数之后 pactree 还能输出
&lt;a class="reference external" href="http://www.graphviz.org/"&gt;dot&lt;/a&gt; 格式的矢量图描述，然后可以用 dot 画出依赖图：&lt;/p&gt;
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
&lt;code class="code"&gt;
pactree pacvis-git -d3 --graph | dot -Tpng &amp;gt;pacvis-pactree.png&lt;/code&gt;
&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="pactree --graph" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-pactree.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt; pactree pacvis-git -d3&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;pacvis-git&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;├─python-tornado&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│ └─python&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─expat&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─bzip2&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─gdbm&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─openssl&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─libffi&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   └─zlib&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;├─pyalpm&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│ ├─python&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│ └─pacman&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─bash&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─glibc&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─libarchive&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─curl&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─gpgme&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   ├─pacman-mirrorlist&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;│   └─archlinux-keyring&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;└─python-setuptools&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;  └─python-packaging&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;    ├─python-pyparsing&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;    └─python-six&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="gp"&gt; $&lt;/span&gt; pactree pacvis-git -d3 --graph &lt;span class="p"&gt;|&lt;/span&gt; dot -Tpng &amp;gt;pacvis-pactree.png&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;从画出的图可以看出，因为有共用的依赖，所以从一个包开始的依赖关系已经不再是一棵
&lt;a class="reference external" href="https://zh.wikipedia.org/wiki/%E6%A8%B9%E7%8B%80%E7%B5%90%E6%A7%8B"&gt;图论意义上的树(Tree)&lt;/a&gt;
了。最初尝试做 PacVis 的早期实现的时候，就是试图用 bash/python 脚本解析 pactree 和
pacman 的输出，在 pactree 的基础上把整个系统中所有安装的包全都包含到一张图里。
当然后来画出的结果并不那么理想，首先由于图非常巨大，导致 dot
的自动布局要耗费数小时，最后画出的图也过于巨大基本上没法看。&lt;/p&gt;
&lt;p&gt;然而不得不说没有 pactree 就不会有 PacVis ，甚至 pacman 被分离出 alpm
库也和 pactree 用 C 重写的过程有很大关系，而 PacVis 用来查询 pacman 数据库的库
pyalpm 正是 alpm 的 Python 绑定。因为 pactree 的需要而增加出的 alpm 库奠定了 PacVis
实现的基石。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pacgraph"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id14"&gt;pacgraph&lt;/a&gt;&lt;/h3&gt;
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
pacgraph 的输出&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="pacgraph" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-pacgraph.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a class="reference external" href="http://kmkeen.com/pacgraph/index.html"&gt;pacgraph&lt;/a&gt; 是一位 Arch Linux 的
Trusted User &lt;a class="reference external" href="http://kmkeen.com/"&gt;keenerd&lt;/a&gt; 写的程序，和
PacVis 一样也是用 Python 实现的。
比起 pactree ， pacgraph 明显更接近我的需求，它默认绘制整个系统的所有安装包，
并且用聪明的布局算法解决了 dot 布局的性能问题。&lt;/p&gt;
&lt;p&gt;pacgraph 的输出是一个富有艺术感的依赖图，图中用不同的字体大小表示出了每个包占用
的磁盘空间。通过观察 pacgraph 的输出，我们可以清楚地把握系统全局的样貌，
比如一眼看出这是个桌面系统还是个服务器系统，并且可以很容易地发现那些占用磁盘空间
巨大的包，考虑清理这些包以节约空间。&lt;/p&gt;
&lt;p&gt;更棒的是 pacgraph 还提供了一个交互性的 GUI 叫做 pacgraph-tk ，显然通过 tk 实现。
用这个 GUI 可以缩放观察整幅图的细节，或者选中某个包观察它和别的包的依赖关系。&lt;/p&gt;
&lt;p&gt;pacgraph 还支持通过参数指定只绘制个别包的依赖关系，就像 pactree 那样。&lt;/p&gt;
&lt;p&gt;不过 pacgraph 也不是完全满足我的需要。如我前面说过，我希望绘制出的图能反应
&lt;strong&gt;这个发行版的架构面貌&lt;/strong&gt; ，而 pacgraph 似乎并不区别「该包依赖的包」和「依赖该包的包」
这两种截然相反的依赖关系。换句话说 pacgraph 画出的是一张无向图，
而我更想要一张有向图，或者说是 &lt;strong&gt;有层次结构的依赖关系图&lt;/strong&gt; 。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id15"&gt;于是就有了 PacVis&lt;/a&gt;&lt;/h2&gt;
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
PacVis 刚打开的样子&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="PacVis on startup" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-second.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;总结了老前辈们的优势与不足，我便开始利用空余时间做我心目中的 PacVis 。
前后断断续续写了两个月，又分为两个阶段，第一阶段做了基本的功能和雏形，
第二阶段套用上 &lt;a class="reference external" href="https://getmdl.io/"&gt;https://getmdl.io/&lt;/a&gt; 的模板，总算有了能拿得出手给别人看的样子。&lt;/p&gt;
&lt;p&gt;于是乎前两天在 AUR 上给 pacvis 打了个
&lt;a class="reference external" href="https://aur.archlinux.org/packages/pacvis-git/"&gt;pacvis-git&lt;/a&gt;
包，现在想在本地跑 pacvis 应该很方便了，用任何你熟悉的 aurhelper
就可以安装，也可以直接从 aur 下载 PKGBUILD 打包：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;~$ git clone aur@aur.archlinux.org:pacvis-git.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;~$ cd pacvis-git&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;~/pacvis-git$ makepkg -si&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;~/pacvis-git$ pacvis&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;Start PacVis at http://localhost:8888/&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;按照提示说的，接下来打开浏览器访问 &lt;a class="reference external" href="http://localhost:8888/"&gt;http://localhost:8888/&lt;/a&gt; 就能看到 PacVis
的样子了。仅仅作为尝试也可以直接打开跑在我的服务器上的 demo:
&lt;a class="reference external" href="https://pacvis.farseerfc.me/"&gt;https://pacvis.farseerfc.me/&lt;/a&gt; ，这个作为最小安装的服务器载入速度大概比普通的桌面系统快一点。&lt;/p&gt;
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
在 Windows msys2 跑 PacVis&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="PacVis on Windows msys2" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-msys2.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;另外补充一下，因为 PacVis 只依赖 pyalpm 和 tornado ，所以在别的基于 pacman
的系统上跑它应该也没有任何问题，包括
&lt;a class="reference external" href="https://msys2.github.io/"&gt;Windows 上的 msys2&lt;/a&gt; 里（尽管在 msys2 上编译
tornado 的包可能要花些功夫）。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id16"&gt;PacVis 的图例和用法&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;操作上 PacVis 仿照地图程序比如 Google Maps 的用法，可以用滚轮或者触摸屏的手势
缩放、拖拽，右上角有个侧边栏，不需要的话可以点叉隐藏掉，右下角有缩放的按钮和
回到全局视图的按钮，用起来应该还算直观。&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="PacVis showing pacvis-git" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-pacvis-git.png"/&gt;
&lt;p class="caption"&gt;pacvis-git 包的依赖&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;先解释图形本身，整张图由很多小圆圈的节点，以及节点之间的箭头组成。
一个圆圈就代表一个软件包，而一条箭头代表一个依赖关系。缩放到细节的话，
能看到每个小圆圈的下方标注了这个软件包的名字，鼠标悬浮在圆圈上也会显示相应信息。
还可以点开软件包，在右侧的边栏里会有更详细的信息。&lt;/p&gt;
&lt;p&gt;比如图例中显示了 pacvis-git 自己的依赖，它依赖 pyalpm, python-tornado 和
python-setuptools ，其中 pyalpm 又依赖 pacman 。图中用
&lt;span class="label label-primary"&gt;紫色&lt;/span&gt; 表示手动安装的包，
&lt;span class="label label-warning"&gt;橙色&lt;/span&gt; 表示被作为依赖安装的包，
箭头的颜色也随着包的颜色改变。&lt;/p&gt;
&lt;p&gt;值得注意的是图中大多数箭头都是由下往上指的，这是因为 PacVis 按照包的依赖关系做
了拓扑排序，并且给每个包赋予了一个拓扑层级。比如 pacvis-git 位于 39
层，那么它依赖的 pyalpm 就位于 38 层，而 pyalpm 依赖的 pacman 就位于 37
层。根据层级关系排列包是 PacVis 于 pacgraph 之间最大的不同之处。&lt;/p&gt;
&lt;p&gt;除了手动缩放， PacVis 还提供了搜索框，根据包名快速定位你感兴趣的包。
以及在右侧边栏中的 Dep 和 Req-By 等页中，包的依赖关系也是做成了按钮的形式，
可以由此探索包和包之间的关联。&lt;/p&gt;
&lt;p&gt;最后稍微解释一下两个和实现相关的参数：&lt;/p&gt;
&lt;div class="label label-info"&gt;
Max Level&lt;/div&gt;
&lt;p&gt;这是限制 PacVis 载入的最大拓扑层。系统包非常多的时候 PacVis
的布局算法会显得很慢，限制层数有助于加快载入，特别是在调试 PacVis 的时候比较有用。&lt;/p&gt;
&lt;div class="label label-info"&gt;
Max Required-By&lt;/div&gt;
&lt;p&gt;这是限制 PacVis 绘制的最大被依赖关系。稍微把玩一下 PacVis 就会发现系统内绝大多数
的包都直接依赖了 glibc 或者 gcc-libs 等个别的几个包，而要绘制这些依赖的话会导致
渲染出的图中有大量长直的依赖线，不便观察。于是可以通过限制这个值，使得 PacVis
不绘制被依赖太多的包的依赖关系，有助于让渲染出的图更易观察。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id17"&gt;从 PacVis 能了解到的一些事实&lt;/a&gt;&lt;/h2&gt;
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
一个 KDE 桌面的 PacVis 结果全图， &lt;a class="reference external" href="//farseerfc.me/zhs/images/pacvis-16384.png"&gt;放大（17M）&lt;/a&gt;&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="A normal KDE desktop in PacVis" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-4096-anno.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;稍微玩一下 PacVis 就能发现不少有趣现象，上述「绝大多数包依赖 glibc 」就是一例。
除此之外还有不少值得玩味的地方。&lt;/p&gt;
&lt;div class="section" id="id7"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id18"&gt;依赖层次&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;系统中安装的包被明显地分成了这样几个层次：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;glibc 等 C 库&lt;/li&gt;
&lt;li&gt;Bash/Perl/Python 等脚本语言&lt;/li&gt;
&lt;li&gt;coreutils/gcc/binutils 等核心工具&lt;/li&gt;
&lt;li&gt;pacman / systemd 等较大的系统工具&lt;/li&gt;
&lt;li&gt;gtk{2,3}/qt{4,5} 等 GUI toolkit&lt;/li&gt;
&lt;li&gt;chromium 等 GUI 应用&lt;/li&gt;
&lt;li&gt;Plasma/Gnome 等桌面环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大体上符合直观的感受，不过细节上有很多有意思的地方，比如 zsh 因为 gdbm
间接依赖了 bash，这也说明我们不可能在系统中用 zsh 完全替代掉 bash。
再比如 python （在 Arch Linux 中是 python3）和 python2 和 pypy
几乎在同一个拓扑层级。&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="zsh depends on bash because of gdbm" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-zsh-bash.png" style="width: 45%;"/&gt;
&lt;p class="caption"&gt;zsh 因为 gdbm 间接依赖了 bash&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;不过偶尔显示的依赖层级不太符合直观，比如 qt5-base &amp;lt; qt4 &amp;lt; gtk2 &amp;lt; gtk3 。
qt5 因为被拆成了数个包所以比 qt4 更低级这可以理解，而 gtk 系比 qt
系更高级这一点是很多人（包括我）没有预料到的吧。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id8"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id19"&gt;循环依赖&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;有些包的依赖关系形成了循环依赖，一个例子是 freetype2 和 harfbuzz，freetype2
是绘制字体的库，harfbuzz 是解析 OpenType 字形的库，两者对对方互相依赖。
另一个例子是 KDE 的 kio 和 kinit，前者提供类似 FUSE 的资源访问抽象层，
后者初始化 KDE 桌面环境。&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="freetype2 harfbuzz" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-freetype2-harfbuzz.png" style="width: 45%;"/&gt;
&lt;p class="caption"&gt;freetype2 和 harfbuzz 之间的循环依赖&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;因为这些循环依赖的存在，使得 PacVis 在实现时不能直接拓扑排序，我采用环探测
算法找出有向图中所有的环，并且打破这些环，然后再使用拓扑排序。
因此我在图中用红色的箭头表示这些会导致环的依赖关系。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id9"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id20"&gt;有些包没有依赖关系&lt;/a&gt;&lt;/h3&gt;
&lt;div class="figure"&gt;
&lt;img alt="PacVis Level 0" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-level0.png" style="width: 45%;"/&gt;
&lt;p class="caption"&gt;man-pages 和 licenses 没有依赖关系&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;有些包既不被别的包依赖，也不依赖别的包，而是孤立在整张图中，比如
man-pages 和 licenses 。这些包在图中位于最顶端，拓扑层级是 0 ，我用
&lt;span class="label label-info"&gt;蓝色&lt;/span&gt; 正方形特别绘制它们。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="linux"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id21"&gt;只看依赖关系的话 Linux 内核完全不重要&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;所有用户空间的程序都依赖着 glibc ，而 glibc 则从定义良好的 syscall 调用内核。
因此理所当然地，如果只看用户空间的话， glibc 和别的 GNU 组件是整个 GNU/Linux
发行版的中心，而 Linux 则是位于依赖层次中很深的位置，甚至在我的 demo 服务器上
Linux 位于整个图中的最底端，因为它的安装脚本依赖 mkinitcpio
而后者依赖了系统中的众多组件。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pacman-qtd"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id22"&gt;pacman -Qtd 不能找到带有循环依赖的孤儿包&lt;/a&gt;&lt;/h3&gt;
&lt;div class="figure"&gt;
&lt;img alt="pacman -Qtd cannot find packages with circle dependency" class="img-responsive" src="//farseerfc.me/zhs/images/pacvis-circledeps-Qtd.png" style="width: 45%;"/&gt;
&lt;p class="caption"&gt;msys2 中带有循环依赖的孤儿包&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;这是我在 msys2 上测试 PacVis 的时候发现的，我看到在渲染的图中有一片群岛，
没有连上任何手动安装的包。这种情况很不正常，因为我一直在我的所有系统中跑
&lt;code class="code"&gt;
pacman -Qtd&lt;/code&gt;
 找出孤儿包并删掉他们。放大之后我发现这些包中有一条循环依赖，
这说明 &lt;code class="code"&gt;
pacman -Qtd&lt;/code&gt;
 不能像语言的垃圾回收机制那样找出有循环依赖的孤儿包。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id10"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id23"&gt;PacVis 的未来&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;目前的 PacVis 基本上是我最初开始做的时候设想的样子，随着开发逐渐又增加了不少功能。
一些是迫于布局算法的性能而增加的（比如限制层数）。&lt;/p&gt;
&lt;p&gt;今后准备再加入以下这些特性：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;更合理的 optdeps 处理。目前只是把 optdeps 关系在图上画出来了。&lt;/li&gt;
&lt;li&gt;更合理的 &lt;strong&gt;依赖关系抉择&lt;/strong&gt; 。有时候包的依赖关系并不是直接根据包名，而是
&lt;code class="code"&gt;
provides&lt;/code&gt;
 由一个包提供另一个包的依赖。目前 PacVis 用 alpm
提供的方式抉择这种依赖，于是这种关系并没有记录在图上。&lt;/li&gt;
&lt;li&gt;目前的层级关系没有考虑包所在的仓库 (core/extra/community/...) 或者包所属的组。
加入这些关系能更清晰地表达依赖层次。&lt;/li&gt;
&lt;li&gt;目前没有办法只显示一部分包的关系。以后准备加入像 pactree/pacgraph 一样显示部分包。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果你希望 PacVis 出现某些有趣的用法和功能，也
&lt;a class="reference external" href="https://github.com/farseerfc/pacvis/issues"&gt;请给我提 issue&lt;/a&gt; 。&lt;/p&gt;
&lt;/div&gt;
</content><category term="tech"></category><category term="python"></category><category term="pacvis"></category><category term="pacman"></category><category term="arch"></category><category term="linux"></category><category term="pacgraph"></category></entry><entry><title>archlinux 上用 chrome 实现 透明计算 远程登录</title><link href="//farseerfc.me/zhs/arch-chrome-remote-desktop.html" rel="alternate"></link><published>2015-02-13T20:39:00+09:00</published><updated>2015-02-13T20:39:00+09:00</updated><author><name>farseerfc</name></author><id>tag:farseerfc.me,2015-02-13:/zhs/arch-chrome-remote-desktop.html</id><summary type="html">
&lt;p&gt;&lt;a class="reference external" href="http://news.sciencenet.cn/htmlnews/2015/1/311393.shtm"&gt;透明计算&lt;/a&gt;
具体是什么，因为他们没有公开技术细节所以我并不知道，只是看
&lt;a class="reference external" href="http://v.qq.com/page/h/v/q/h0145ebh1vq.html"&gt;公开出来的演示视频&lt;/a&gt;
，感觉似乎只要能从手机上远程登录系统桌面，就能算是透明计算了。
如果透明计算真是这个意思，那么我似乎已经用着这个技术很多年了嘛。&lt;/p&gt;
&lt;p&gt;Xorg 上常用的远程桌面工具有很多，基于 VNC 协议的、基于NX的和基于 RDP 协议的都能找到，
直接 ssh X forwarding 效果也不错。只是这些方案的一个 &lt;strong&gt;不太易用&lt;/strong&gt; 的地方在于，需要
通过 ip 访问到远程的电脑，所以在跨越 NAT 之类的情况下不太容易使用。&lt;/p&gt;
&lt;p&gt;于是今天介绍一个使用方便设置也简单的方法： 通过 chrome-remote-desktop 在 archlinux
上使用远程桌面。这个方案的优势在于，借助 Google 的云端服务器（内部貌似是XMPP协议下的握手）
方便地实现了 NAT 穿透，无论什么网络环境基本都能使用。当然，要支持远程登录，
位于远端的登录的计算机必须一直开着 …&lt;/p&gt;</summary><content type="html">
&lt;p&gt;&lt;a class="reference external" href="http://news.sciencenet.cn/htmlnews/2015/1/311393.shtm"&gt;透明计算&lt;/a&gt;
具体是什么，因为他们没有公开技术细节所以我并不知道，只是看
&lt;a class="reference external" href="http://v.qq.com/page/h/v/q/h0145ebh1vq.html"&gt;公开出来的演示视频&lt;/a&gt;
，感觉似乎只要能从手机上远程登录系统桌面，就能算是透明计算了。
如果透明计算真是这个意思，那么我似乎已经用着这个技术很多年了嘛。&lt;/p&gt;
&lt;p&gt;Xorg 上常用的远程桌面工具有很多，基于 VNC 协议的、基于NX的和基于 RDP 协议的都能找到，
直接 ssh X forwarding 效果也不错。只是这些方案的一个 &lt;strong&gt;不太易用&lt;/strong&gt; 的地方在于，需要
通过 ip 访问到远程的电脑，所以在跨越 NAT 之类的情况下不太容易使用。&lt;/p&gt;
&lt;p&gt;于是今天介绍一个使用方便设置也简单的方法： 通过 chrome-remote-desktop 在 archlinux
上使用远程桌面。这个方案的优势在于，借助 Google 的云端服务器（内部貌似是XMPP协议下的握手）
方便地实现了 NAT 穿透，无论什么网络环境基本都能使用。当然，要支持远程登录，
位于远端的登录的计算机必须一直开着 Chrome Remote Desktop 的后台服务。&lt;/p&gt;
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
Chrome Remote Desktop 插件&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="Chrome Remote Desktop 插件" class="img-responsive" src="//farseerfc.me/zhs/images/chrome-remote-desktop-plugin.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="chrome-remote-desktop"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id5"&gt;Chrome Remote Desktop 的客户端&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;虽然可能有很多人不知道，不过 Chrome 内包括远程桌面的功能很久了。只是这个功能的界面默认
没有提供界面，要使用它需要安装 Google 官方出品的
&lt;a class="reference external" href="https://chrome.google.com/webstore/detail/chrome-remote-desktop/gbchcmhmhahfdphkhkmpfmihenigjmpp"&gt;remote-desktop 插件&lt;/a&gt; 。
装好之后远程桌面的客户端就准备好，可以用来远程访问别的计算机桌面了（无论是 Windows/OS X
还是 Linux 都支持）。并且不光可以自己远程访问自己账户的桌面，还可以远程协助朋友的桌面。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="archlinux"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id6"&gt;Archlinux 上设置远程登录的服务器&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;有了客户端之后还要设置一下才能让桌面作为远程登录的服务器。Windows 和 OS X 上 Chrome
会自动下载需要的安装包，无脑下一步就能装好了。Linux上由于发行版众多，桌面配置各异，
所以需要一点手动配置。官方的设置步骤记载在 &lt;a class="reference external" href="https://support.google.com/chrome/answer/1649523"&gt;这里&lt;/a&gt;
其中给出了 debian 用的二进制包和 Ubuntu 12.10 上的设置方式，以下设置是参考官方步骤。&lt;/p&gt;
&lt;p&gt;首先要安装 chrome-remote-desktop 这个包，这个包实际上对应了 Windows/OS X 上用安装程序
安装的 Remote Desktop Host Controller。 archlinux 上开启了
&lt;a class="reference external" href="https://github.com/archlinuxcn/repo"&gt;[archlinuxcn]&lt;/a&gt;
仓库的话，可以直接安装打好的包。或者可以从
&lt;a class="reference external" href="https://aur.archlinux.org/packages/chrome-remote-desktop/"&gt;AUR&lt;/a&gt; 装。&lt;/p&gt;
&lt;pre&gt;&lt;span class="code-line"&gt;$ pacman -Ss chrome-remote-desktop&lt;br/&gt;&lt;span style="color:purple;font-weight:bold;"&gt;archlinuxcn/&lt;/span&gt;&lt;span style="font-weight:bold;"&gt;chrome-remote-desktop &lt;/span&gt;&lt;span style="color:green;font-weight:bold;"&gt;40.0.2214.44-1&lt;/span&gt;&lt;br/&gt;Allows you to securely access your computer over the Internet through Chrome.&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;装好之后从会说这么一段话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;groupadd：无效的组 ID “chrome-remote-desktop”&lt;/p&gt;
&lt;p&gt;Please create ~/.config/chrome-remote-desktop folder manually, if it doesn't exist, or else you can't use CRD.
The needed files are created by the Chrome app, inside the chrome-remote-desktop folder, after Enabling Remote Connections.
To {enable,start} the service use systemctl --user {enable,start} chrome-remote-desktop&lt;/p&gt;
&lt;p&gt;You may need to create a ~/.chrome-remote-desktop-session file with commands to start your session&lt;/p&gt;
&lt;p&gt;Go to &lt;a class="reference external" href="https://support.google.com/chrome/answer/1649523"&gt;https://support.google.com/chrome/answer/1649523&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;那句报错是 AUR 里打的包还没跟上上游 Google 的更改导致的错误，
首先我们需要把远程登录的用户添加入 chrome-remote-desktop 这个用户组里。
新版本的 chrome remote desktop 提供了一个命令做这个事情，所以执行以下命令就可以了：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt; /opt/google/chrome-remote-desktop/chrome-remote-desktop --add-user&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;然后我们需要手动创建 &lt;code class="code"&gt;
~/​.config/​chrome-remote-desktop&lt;/code&gt;
 这个文件夹，内容是空的
就好了，随后 chrome 会往这里面放 &lt;code class="code"&gt;
host#.json&lt;/code&gt;
 文件用于身份验证。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt; mkdir ~/.config/chrome-remote-desktop&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;然后我们要创建一个 shell 脚本 &lt;code class="code"&gt;
~/​.chrome-remote-desktop-session&lt;/code&gt;
 ，这是远程
登录时的 .xinitrc ，内容么就是启动你想在远程登录时用的桌面环境。
这里可以指定一个和你正在登录的 WM/DE 不同的桌面，比如我启动 xfce4：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt; cat ~/.chrome-remote-desktop-session&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="gp"&gt;#&lt;/span&gt;!/bin/bash&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;startxfce4&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; chmod &lt;span class="m"&gt;755&lt;/span&gt; .chrome-remote-desktop-session&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;接下来需要从 Chrome 的插件里启用远程桌面。打开 Chrome 的 Remote Desktop 插件，这时
应该可以看到一个「启用远程链接」的按钮。&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Chrome Remote Desktop 插件中「启用远程链接」的按钮" class="img-responsive" src="//farseerfc.me/zhs/images/chrome-remote-desktop-enable-button.png"/&gt;
&lt;p class="caption"&gt;Chrome Remote Desktop 插件中「启用远程链接」的按钮&lt;/p&gt;
&lt;/div&gt;
&lt;div class="alert alert-warning compound"&gt;
&lt;p&gt;在撰写本文的时候， Archlinux 官方源里的 chromium 的版本和 aur/google-chrome
的版本尚且还是 40.0.2214.111 ，而 Chrome Web Store 中提供的 Chrome Remote
Desktop 的插件的版本是 41.0.2272.41 。虽然通常并不要求两者版本一致，不过貌似最近
Chrome 内部的 Remoting 功能更改了 API 导致可能出问题。如果你找不到
「启用远程链接」的按钮，请尝试一下新版本的 Chrome 比如 google-chrome-dev 。
在这一步启用之后，老版本的 chrome 应该也就能使用远程桌面了。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="alert alert-warning compound"&gt;
&lt;p&gt;在32位的 Linux 版本上，最近更新的 Chrome Remote Desktop 插件可能无法正确识别 Host
的版本，具体 &lt;a class="alert-link reference external" href="https://code.google.com/p/chromium/issues/detail?id=332930"&gt;参考这个 bug&lt;/a&gt; 。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;点击「启用远程链接」，设定一个 PIN 密码（不需要很复杂，这里首先有 Google 帐号验证保证只有
你才能访问），然后就能看到这套电脑的 hostname 出现在「我的电脑」列表里。&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="启用远程链接之后的样子" class="img-responsive" src="//farseerfc.me/zhs/images/chrome-remote-desktop-after-enabled.png"/&gt;
&lt;p class="caption"&gt;启用远程链接之后的样子&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;同时，启用了远程链接之后，可以在刚刚创建的 ~/.config/chrome-remote-desktop
文件夹中找到记录了验证信息的文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt; ls .config/chrome-remote-desktop&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="go"&gt;chrome-profile  host#8cfe7ecfd6bb17955c1ea22f77d0d800.json  pulseaudio#8cfe7ecfd6&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;然后就可以启动对应的 systemd 用户服务了，如果想自动启动服务要记得 &lt;code class="code"&gt;
systemctl --user enable&lt;/code&gt;
 ：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt; systemctl --user start chrome-remote-desktop.service&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;如果上面的设置一切正常，就可以看到 chrome-remote-desktop 启动了另外一个 Xorg 执行你
刚刚指定的桌面环境：&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="htop 中看到的 chrome-remote-desktop 启动的另外一个 Xorg" class="img-responsive" src="//farseerfc.me/zhs/images/chrome-remote-desktop-htop.png"/&gt;
&lt;p class="caption"&gt;htop 中看到的 chrome-remote-desktop 启动的另外一个 Xorg&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;然后就可以试着通过 Remote Desktop 插件登录到这个新开的 Xorg 了：&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="「远程」登录到新的 XFCE4" class="img-responsive" src="//farseerfc.me/zhs/images/chrome-remote-desktop-xfce4.png"/&gt;
&lt;p class="caption"&gt;「远程」登录到新的 XFCE4&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="linux-chrome-windows-os-x"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id7"&gt;Linux 版本的 Chrome远程桌面 和 Windows/ OS X 上的区别&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;通过上面的设置步骤也可以看出，Linux版本的远程桌面会在后台开一个独立的 X 会话，而不能
复用现在已有的 X 会话。对远程登录的用法而言这还能接受，对远程协助的功能而言有点问题，
因为正在使用的人不能观察协助者做了什么，协助者也不能继续请求协助的人的操作。&lt;/p&gt;
&lt;p&gt;当然目前 Chrome 远程桌面的 Linux Host Controller 还只是 beta 版本，官方只测试支持
Ubuntu 12.04 和 12.10 （14.04之后似乎有
&lt;a class="reference external" href="https://code.google.com/p/chromium/issues/detail?id=366432"&gt;Bug&lt;/a&gt;
），所以不能要求太多。希望以后能改善吧。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="bonus"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id8"&gt;Bonus： 手机远程登录&lt;/a&gt;&lt;/h2&gt;
&lt;div class="panel panel-default"&gt;
&lt;div class="panel-heading"&gt;
手机上的 Chrome 远程桌面 App&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;img alt="手机上的 Chrome 远程桌面 App" class="img-responsive" src="//farseerfc.me/zhs/images/chrome-remote-desktop-android.png"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;通过上面的设置就可以从任何一个 Chrome 远程桌面客户端登录刚刚设置的这台电脑了。
因为 Chrome 在三大桌面系统 Windows / OS X / Linux 上都有，所以应该能覆盖大多数桌面
系统了。&lt;/p&gt;
&lt;p&gt;除了桌面的 Chrome 之外还有一个客户端是 Android 上的
&lt;a class="reference external" href="https://play.google.com/store/apps/details?id=com.google.chromeremotedesktop"&gt;Chrome 远程桌面 App&lt;/a&gt; 经过上面的设置之后，从这个 App 也能看到并登录：&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="手机远程登录" class="img-responsive" src="//farseerfc.me/zhs/images/chrome-remote-desktop-android-logined.png"/&gt;
&lt;p class="caption"&gt;手机远程登录&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;好啦，开始享受国家自然科学一等奖的透明计算技术吧！&lt;/p&gt;
&lt;/div&gt;
</content><category term="tech"></category><category term="linux"></category><category term="archlinux"></category><category term="arch"></category><category term="chrome"></category><category term="remote"></category><category term="desktop"></category></entry></feed>