<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Pany's Blog]]></title><description><![CDATA[GEEK or not—that is the question:]]></description><link>http://blog.pany.pro/</link><image><url>http://blog.pany.pro/favicon.png</url><title>Pany&apos;s Blog</title><link>http://blog.pany.pro/</link></image><generator>Ghost 3.13</generator><lastBuildDate>Wed, 08 Oct 2025 10:16:30 GMT</lastBuildDate><atom:link href="http://blog.pany.pro/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Test new NTFS3 driver for Linux]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="background">Background</h2>
<p><a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=Linux-NTFS3-v22-Driver">New NTFS Driver Misses Out On Linux 5.12 But Revved A 22nd Time</a><br>
<a href="https://lore.kernel.org/lkml/20210301160102.2884774-1-almaz.alexandrovich@paragon-software.com/">NTFS read-write driver GPL implementation by Paragon Software</a></p>
<h2 id="getkernelsourcerpm">Get kernel source rpm</h2>
<p>Enable the rawhide repo.</p>
<pre><code>~]# dnf se rawhide
...
======================= Name &amp; Summary Matched: rawhide ========================
fedora-repos-rawhide.noarch : Rawhide repo definitions
fedora-repos-rawhide-modular.noarch : Rawhide modular repo definitions</code></pre>]]></description><link>http://blog.pany.pro/test-new-ntfs-driver-for-linux/</link><guid isPermaLink="false">60407563eba88f00015f7223</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Thu, 04 Mar 2021 05:52:55 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="background">Background</h2>
<p><a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=Linux-NTFS3-v22-Driver">New NTFS Driver Misses Out On Linux 5.12 But Revved A 22nd Time</a><br>
<a href="https://lore.kernel.org/lkml/20210301160102.2884774-1-almaz.alexandrovich@paragon-software.com/">NTFS read-write driver GPL implementation by Paragon Software</a></p>
<h2 id="getkernelsourcerpm">Get kernel source rpm</h2>
<p>Enable the rawhide repo.</p>
<pre><code>~]# dnf se rawhide
...
======================= Name &amp; Summary Matched: rawhide ========================
fedora-repos-rawhide.noarch : Rawhide repo definitions
fedora-repos-rawhide-modular.noarch : Rawhide modular repo definitions
rpmfusion-free-release-rawhide.noarch : RPM Fusion Rawhide free repo definitions

~]# dnf in fedora-repos-rawhide fedora-repos-rawhide-modular
~]# dnf repolist --all
repo id                                   repo name                     status
fedora                                    Fedora 33 - x86_64            enabled
...
rawhide                                   Fedora - Rawhide - Developmen disabled
rawhide-debuginfo                         Fedora - Rawhide - Debug      disabled
rawhide-modular                           Fedora - Modular Rawhide - De disabled
rawhide-modular-debuginfo                 Fedora - Modular Rawhide - De disabled
rawhide-modular-source                    Fedora - Modular Rawhide - So disabled
rawhide-source                            Fedora - Rawhide - Source     disabled
...

~]# dnf list --disablerepo=\* --enablerepo=rawhide-source kernel\*
...
Available Packages
kernel.src                5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.fc35 rawhide-source
kernel-headers.src        5.11.0-1.fc35                                 rawhide-source
kernel-srpm-macros.src    1.0-4.fc34                                    rawhide-source
kernel-tools.src          5.11.0-1.fc35                                 rawhide-source
kernelshark.src           1:1.2-3.fc34                                  rawhide-source
</code></pre>
<p>Download SRPM and install it.</p>
<pre><code>~]# dnf download --source --disablerepo=\* --enablerepo=rawhide-source kernel

~]# rpm -ivh kernel-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.fc35.src.rpm
warning: kernel-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.fc35.src.rpm: Header V4 RSA/SHA256 Signature, key ID 9867c58f: NOKEY
Updating / installing...
   1:kernel-5.12.0-0.rc0.20210225gitc0warning: user mockbuild does not exist - using root
...
</code></pre>
<p>Modify <code>kernel.spec</code>.</p>
<pre><code>~]# diff ~/rpmbuild/SPECS/kernel.spec kernel.spec
99c99
&lt;
---
&gt; %define buildid .ntfs3
762a763,772
&gt; Patch999901: 0001-ntfs3-01.patch
&gt; Patch999902: 0001-ntfs3-02.patch
&gt; Patch999903: 0001-ntfs3-03.patch
&gt; Patch999904: 0001-ntfs3-04.patch
&gt; Patch999905: 0001-ntfs3-05.patch
&gt; Patch999906: 0001-ntfs3-06.patch
&gt; Patch999907: 0001-ntfs3-07.patch
&gt; Patch999908: 0001-ntfs3-08.patch
&gt; Patch999909: 0001-ntfs3-09.patch
&gt; Patch999910: 0001-ntfs3-10.patch
1264a1275,1284
&gt; ApplyOptionalPatch 0001-ntfs3-01.patch
&gt; ApplyOptionalPatch 0001-ntfs3-02.patch
&gt; ApplyOptionalPatch 0001-ntfs3-03.patch
&gt; ApplyOptionalPatch 0001-ntfs3-04.patch
&gt; ApplyOptionalPatch 0001-ntfs3-05.patch
&gt; ApplyOptionalPatch 0001-ntfs3-06.patch
&gt; ApplyOptionalPatch 0001-ntfs3-07.patch
&gt; ApplyOptionalPatch 0001-ntfs3-08.patch
&gt; ApplyOptionalPatch 0001-ntfs3-09.patch
&gt; ApplyOptionalPatch 0001-ntfs3-10.patch
1304c1324
&lt; cp $RPM_SOURCE_DIR/kernel-*.config .
---
&gt; cp $RPM_SOURCE_DIR/kernel-x86_64*.config .
</code></pre>
<p>Modify <code>kernel-local</code>.</p>
<pre><code>~]# cat kernel-local
# This file is intentionally left empty in the stock kernel. Its a nicety
# added for those wanting to do custom rebuilds with altered config opts.
CONFIG_NTFS3_FS=m
# CONFIG_NTFS3_64BIT_CLUSTER is not set
# CONFIG_NTFS3_LZX_XPRESS is not set
# CONFIG_NTFS3_FS_POSIX_ACL is not set
</code></pre>
<p>Generate new SRPM.</p>
<pre><code>~]# cp *.patch kernel-local ~/rpmbuild/SOURCES/
~]# cp kernel.spec ~/rpmbuild/SPECS/

~]# rpmbuild -bs ~/rpmbuild/SPECS/kernel.spec
</code></pre>
<p>Build with copr and install it.</p>
<pre><code>~]# copr build kernel-macbook ~/rpmbuild/SRPMS/kernel-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.ntfs3.fc33.src.rpm

~]# dnf copr enable pany/kernel-macbook
~]# dnf up kernel
</code></pre>
<p>Or build with better perfomance server.</p>
<pre><code>~]# mock -r fedora-33-x86_64 --rebuild kernel-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.ntfs3.fc33.src.rpm
</code></pre>
<p>Or build with current fedora.</p>
<pre><code>~]# dnf in bison dwarves elfutils-devel gcc-c++ gcc-plugin-devel net-tools nss-tools perl-devel perl-generators pesign -y
~]# rpmbuild -bb ~/rpmbuild/SPECS/kernel.spec
</code></pre>
<p>Without copr, install the RPM.</p>
<pre><code>~]# dnf in ./kernel-{,core-,modules-}5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.ntfs3.fc33.x86_64.rpm
</code></pre>
<h2 id="tryntfs3driver">Try NTFS3 driver</h2>
<p>Reboot to new kernel.</p>
<pre><code>~]# modprobe ntfs3
~]# lsmod | grep ntfs3
ntfs3                 245760  1

~]# lsblk /dev/sdc
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sdc      8:32   0 931.5G  0 disk
├─sdc1   8:33   0    16M  0 part
└─sdc2   8:34   0 931.5G  0 part
~]# mount -t ntfs3 /dev/sdc2 /media/
~]# mount | grep sdc2
/dev/sdc2 on /media type ntfs3 (rw,relatime,nls=utf8)

~]# cp kernel-{,core-,modules-}5.12.* /media/
~]# ls /media/
'$RECYCLE.BIN'/
 kernel-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.fc35.src.rpm
 kernel-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.ntfs3.fc33.x86_64.rpm
 kernel-core-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.ntfs3.fc33.x86_64.rpm
 kernel-modules-5.12.0-0.rc0.20210225gitc03c21ba6f4e.160.ntfs3.fc33.x86_64.rpm
'System Volume Information'/
</code></pre>
<p>So far so good.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Libvirt Hooks 实现快照自动还原]]></title><description><![CDATA[<h2 id="-">背景</h2><p>对业务虚拟机的系统盘做一个快照，每次开机之前或关机之后自动还原快照，就可以避免 Windows 异常之后虚拟机无法修复的情况。</p><h2 id="--1">需求分析</h2><ul><li>加 <code>-snapshot</code> 参数<strong>做不到</strong>只对 vda 加快照</li><li>加了 <code>-snapshot</code> 参数的机器，如果要更新 vda 需要至少两次重启虚拟机（关机-&gt;解快照-&gt;开机-&gt;更新-&gt;关机-&gt;加快照-&gt;开机）</li><li>尝试单纯使用 libvirt hooks 来实现，发现其有两个限制：</li><li>libvirt hooks 不能回调 libvirt API，会<a href="https://www.libvirt.org/hooks.html#recursive" rel="nofollow">无限递归</a></li><li>不像 <a href="https://www.ovirt.org/develop/developer-guide/vdsm/hooks.html" rel="nofollow">VDSM hooks</a>，libvirt hooks</li></ul>]]></description><link>http://blog.pany.pro/libvirt-hooks-snapshot-auto-revert/</link><guid isPermaLink="false">604f26dfeba88f00015f7230</guid><category><![CDATA[libvirt]]></category><category><![CDATA[KVM]]></category><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Sun, 27 Sep 2020 09:21:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="-">背景</h2><p>对业务虚拟机的系统盘做一个快照，每次开机之前或关机之后自动还原快照，就可以避免 Windows 异常之后虚拟机无法修复的情况。</p><h2 id="--1">需求分析</h2><ul><li>加 <code>-snapshot</code> 参数<strong>做不到</strong>只对 vda 加快照</li><li>加了 <code>-snapshot</code> 参数的机器，如果要更新 vda 需要至少两次重启虚拟机（关机-&gt;解快照-&gt;开机-&gt;更新-&gt;关机-&gt;加快照-&gt;开机）</li><li>尝试单纯使用 libvirt hooks 来实现，发现其有两个限制：</li><li>libvirt hooks 不能回调 libvirt API，会<a href="https://www.libvirt.org/hooks.html#recursive" rel="nofollow">无限递归</a></li><li>不像 <a href="https://www.ovirt.org/develop/developer-guide/vdsm/hooks.html" rel="nofollow">VDSM hooks</a>，libvirt hooks 无法修改 <a href="https://www.redhat.com/archives/libvir-list/2014-April/msg00678.html" rel="nofollow">libvirt XML</a></li></ul><p>潜在的解决方案有<a href="http://just4coding.com/2017/11/25/qemu-hook/" rel="nofollow">几种</a>：</p><ul><li>对 qemu-kvm 进行包装（wrap）替换原生的程序</li><li>自行修改 libvirt 源代码，重新编译</li><li>使用外部配置文件进行控制是否加快照，使用 libvirt hooks 进行快照自动还原</li></ul><h2 id="--2">解决方案</h2><p>最终选择最后一种方案，简单有效。</p><ul><li>外部配置文件来控制是否加「快照自动还原」</li><li>libvirt hooks 来控制每次开机的时重置快照</li><li>如果要单次更新 vda，关机后做一次 commit</li><li>hook 需要命名为 /etc/libvirt/hooks/qemu，<a href="https://www.libvirt.org/hooks.html#qemu" rel="nofollow">因为 libvirt 6.5.0 之后才支持 /etc/libvirt/hooks/qemu.d/ 路径</a></li></ul><h2 id="--3">基本逻辑</h2><ul><li>假设虚拟机有两个虚拟磁盘设备 vda 和 vdb，现在需要令 vda 自动还原快照，vdb 不做快照</li><li>假设 vda 的虚拟磁盘文件为 os.img</li><li>虚拟机开机之前，将 os.img 重命名为 os.img.backing_file （如果该文件已存在，则不进行重命名）</li><li>以 os.img.backing_file 作为 backing_file 创建 os.img</li><li>虚拟机开机，会根据其 libvirt xml 文件查找其虚拟磁盘文件，即 os.img</li><li>虚拟机运行，增量内容写入到 os.img</li><li>虚拟机关机，查询外部配置文件，是否要做「单次提交」</li><li>如果需要，做「单次提交」并修改配置文件，将「单次提交」标记为否</li><li>「提交」的意思是将一个 os.img 中的内容写入到其 backing_file 中</li><li>将 os.img.backing_file 重命名回 os.img（完成对增量内容的覆盖）</li></ul><h2 id="--4">示例说明</h2><pre><code class="language-python">#!/usr/bin/env python3

import json
import logging
import shlex
import subprocess
import sys
import xml.etree.ElementTree as ET
from pathlib import Path


class Config:
    def __init__(self, configFile):
        self.configFile = configFile
        with open(self.configFile, "r") as f:
            self.config = json.load(f)
        self.disks = self.config["disks"]

    def report(self):
        """ Do a one-shot-commit, then change the config file. """
        with open(self.configFile, "w") as f:
            json.dump(self.config, f, indent=2)


def getHookDetails():
    raw_xml = "".join((sys.stdin.readlines()))
    logging.info(str(sys.argv))
    return raw_xml


def getFilePath(target, domXML):
    XML = ET.fromstring(domXML)
    pattern = f"./devices/disk/target[@dev='{target}']..[@device='disk']"
    disk = XML.find(pattern)
    diskXML = ET.tostring(disk).decode()
    target_path = disk.find("source").get("file")
    logging.debug(f"Disk XML Dump:\n{diskXML}")
    return target_path


class SnapshotAutoRevert:
    def __init__(self, domName, qcow2_file):
        """ Take qcow2 file path as argument, which will be auto reverted in every VM life cycle. """
        self.domName = domName
        self.qcow2_file = qcow2_file

    def renameToBackingFile(self):
        if not Path(f"{self.qcow2_file}.backing_file").is_file():
            Path(self.qcow2_file).rename(f"{self.qcow2_file}.backing_file")
            logging.info(f"{self.domName} Rename origin image to backing_file")

    def createSnapshot(self):
        logging.info(f"{self.domName} Create a snapshot based on origin image")
        cmd = (
            f"qemu-img create -f qcow2 {self.qcow2_file} "
            f"-b {self.qcow2_file}.backing_file -F qcow2"
        )
        args = shlex.split(cmd)
        with subprocess.Popen(args, stdout=subprocess.PIPE) as proc:
            logging.info(proc.stdout.read().decode())

    def commitSnapshot(self):
        logging.info(f"{self.domName} Commit the snapshot")
        cmd = f"qemu-img commit {self.qcow2_file}"
        args = shlex.split(cmd)
        with subprocess.Popen(args, stdout=subprocess.PIPE) as proc:
            logging.info(proc.stdout.read().decode())

    def revertSnapshot(self):
        Path(f"{self.qcow2_file}.backing_file").rename(self.qcow2_file)
        logging.info(f"{self.domName} Revert to origin image, delete snapshot")


def main():
    hookPath = Path(sys.argv[0])
    domName = sys.argv[1]
    domAction = sys.argv[2]
    configFile = Path.joinpath(hookPath.parent, "config", f"{domName}.json")
    if not configFile.exists():
        exit(0)
    vmConfig = Config(configFile)
    domXML = getHookDetails()
    logging.debug(f"Config before: {vmConfig.config}")

    index = -1
    reportFlag = False
    for disk in vmConfig.disks:
        index += 1
        logging.info(disk["target"])
        target_file = getFilePath(disk["target"], domXML)
        commitFlag = disk["one-shot-commit"]
        AutoRevert_target = SnapshotAutoRevert(domName, target_file)

        if domAction == "prepare":
            AutoRevert_target.renameToBackingFile()
            AutoRevert_target.createSnapshot()
        elif domAction == "release":
            if commitFlag:
                AutoRevert_target.commitSnapshot()
                vmConfig.config["disks"][index]["one-shot-commit"] = False
                reportFlag = True
            AutoRevert_target.revertSnapshot()

    if reportFlag:
        vmConfig.report()
        logging.debug(f"Config after: {vmConfig.config}")


if __name__ == "__main__":
    logging.basicConfig(
        filename="/var/log/libvirt/qemu/hooks.log",
        format="%(asctime)s %(message)s",
        level=logging.INFO,
    )

    main()</code></pre><p>hook 需要命名为 <code>/etc/libvirt/hooks/qemu</code>，因此在有快照的机器上查看该文件即可读取源代码。</p><p>配置文件位置 <code>/etc/libvirt/hooks/config/{vm_name}.json</code> （每个虚拟机使用各自的配置文件）。</p><pre><code>{
  "disks": [
    {
      "target": "vda",
      "one-shot-commit": true
    },
    {
      "target": "sdb",
      "one-shot-commit": false
    }
  ]
}</code></pre><p>该配置文件的含义是对 <code>{vm_name}</code> 这个虚拟机设置针对 vda 和 sdb 快照自动还原，当该虚拟机的此次生命周期结束之后，对其 vda 进行「单次提交」（维护操作），提交之后该配置文件会被更新为如下内容：</p><pre><code>{
  "disks": [
    {
      "target": "vda",
      "one-shot-commit": false
    },
    {
      "target": "sdb",
      "one-shot-commit": false
    }
  ]
}</code></pre><p>在一个典型的业务宿主机上，常见的配置文件如下所示：</p><pre><code>{
  "disks": [
    {
      "target": "vda",
      "one-shot-commit": false
    }
  ]
}</code></pre><p>意思就是「只针对 vda 做快照自动还原，正常工作，不做单次提交」，没有 vdb 或 sdb，就不会对这些虚拟磁盘做快照。</p><p>如果找不到虚拟机的配置文件，就不会对虚拟机做快照。</p><p>如果配置文件是非法的 json 格式，该虚拟机不会启动。</p><p>相关日志会输出到 <code>/var/log/libvirt/qemu/hooks.log</code>。</p><p>想查看一台虚拟机是否运行在「快照自动还原」模式下，可以在虚拟机运行过程中执行 <code>virsh dumpxml vm_name | grep backing_file</code> ，如果有结果，就代表该机器当前运行在「快照自动还原」模式下。此时，如果想使虚拟机中的更新内容固化下来，可以直接去修改其 hook 配置文件 <code>/etc/libvirt/hooks/config/{vm_name}.json</code>，将 <code>"one-shot-commit"</code> 改为 <code>true</code> 即可。虚拟机生命周期结束时，会由 hook 脚本来执行「单次提交」并自动将 <code>"one-shot-commit"</code> 改为 false</p>]]></content:encoded></item><item><title><![CDATA[searx]]></title><description><![CDATA[<p><a href="https://asciimoo.github.io/searx/">https://asciimoo.github.io/searx/</a></p><blockquote>Searx is a free internet metasearch engine which aggregates results from  more than 70 search services. Users are neither tracked nor profiled.  Additionally, searx can be used over Tor for online anonymity.</blockquote><p>Follow the <a href=" https://asciimoo.github.io/searx/dev/install/installation.html#installation">installation guide</a>, git clone the <a href="https://github.com/asciimoo/searx.git">repository</a> and use docker to build</p>]]></description><link>http://blog.pany.pro/searx/</link><guid isPermaLink="false">5c90b4fb954aa80001d0be3a</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Tue, 19 Mar 2019 14:49:09 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://asciimoo.github.io/searx/">https://asciimoo.github.io/searx/</a></p><blockquote>Searx is a free internet metasearch engine which aggregates results from  more than 70 search services. Users are neither tracked nor profiled.  Additionally, searx can be used over Tor for online anonymity.</blockquote><p>Follow the <a href=" https://asciimoo.github.io/searx/dev/install/installation.html#installation">installation guide</a>, git clone the <a href="https://github.com/asciimoo/searx.git">repository</a> and use docker to build and run searx.</p><p>2 tips:</p><ul><li>Change SELinux policy to allow searx to connect to Google</li></ul><pre><code>$ setsebool -P httpd_can_network_connect 1</code></pre><ul><li>Avoid nginx loop redirecting </li></ul><pre><code>server {
	#...
	location / {
		proxy_pass http://127.0.0.1:8888;
		#...
		proxy_redirect off;
	}
}</code></pre>]]></content:encoded></item><item><title><![CDATA[Meaning of the word Kubernetes]]></title><description><![CDATA[<p><a href="https://kubernetes.io">Kubernetes</a> is REALLY popular. But the pronunciation of this word did confuse me. After some searching work, I realized that it came from an Ancient Greek word: <a href="https://en.wiktionary.org/wiki/%CE%BA%CF%85%CE%B2%CE%B5%CF%81%CE%BD%CE%AE%CF%84%CE%B7%CF%82">κυβερνήτης</a>, which means "a captain, a steersman, a pilot, a navigator" – this is why its logo is a helm (meanwhile there's a Kubernetes</p>]]></description><link>http://blog.pany.pro/meaning-of-the-word-kubernetes/</link><guid isPermaLink="false">5c749e8c954aa80001d0bdf0</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Tue, 26 Feb 2019 02:36:01 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://kubernetes.io">Kubernetes</a> is REALLY popular. But the pronunciation of this word did confuse me. After some searching work, I realized that it came from an Ancient Greek word: <a href="https://en.wiktionary.org/wiki/%CE%BA%CF%85%CE%B2%CE%B5%CF%81%CE%BD%CE%AE%CF%84%CE%B7%CF%82">κυβερνήτης</a>, which means "a captain, a steersman, a pilot, a navigator" – this is why its logo is a helm (meanwhile there's a Kubernetes package manager called <a href="https://github.com/helm/helm">Helm</a>). And the pronunciation of the word <em>κυβερνήτης</em> was kubernḗtēs, so, Kubernetes.</p><p>BTW, there was a saying – <em>Φιλοσοφία Βίου Κυβερνήτης</em>, which means "Love of wisdom is the guide of life" or "Philosophy is the governor of one's life." The abbreviation <em><a href="https://en.wikipedia.org/wiki/Phi_Beta_Kappa">ΦΒΚ</a></em> also named the oldest academic honor society in US.</p>]]></content:encoded></item><item><title><![CDATA[WireGuard on a Raspberry Pi]]></title><description><![CDATA[<p>Installing <a href="https://www.wireguard.com/quickstart/">WireGuard</a> – a state-of-the-art VPN – on a Raspberry Pi 2B turns out to be troublesome.</p><p>It was smooth just at the beginning:</p><ul><li>Add debian unstable source</li></ul><pre><code># /etc/apt/sources.list.d/unstable.list

deb https://mirrors.ustc.edu.cn/debian/ unstable main</code></pre><ul><li>Configure apt preference</li></ul><pre><code># /etc/apt/preferences.d/limit-unstable</code></pre>]]></description><link>http://blog.pany.pro/wireguard-on-a-raspberry-pi/</link><guid isPermaLink="false">5c710de5954aa80001d0bd9f</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Sat, 23 Feb 2019 16:39:44 GMT</pubDate><content:encoded><![CDATA[<p>Installing <a href="https://www.wireguard.com/quickstart/">WireGuard</a> – a state-of-the-art VPN – on a Raspberry Pi 2B turns out to be troublesome.</p><p>It was smooth just at the beginning:</p><ul><li>Add debian unstable source</li></ul><pre><code># /etc/apt/sources.list.d/unstable.list

deb https://mirrors.ustc.edu.cn/debian/ unstable main</code></pre><ul><li>Configure apt preference</li></ul><pre><code># /etc/apt/preferences.d/limit-unstable

Package: *
Pin: release a=unstable
Pin-Priority: 90</code></pre><ul><li>Update Raspberry Pi kernel</li></ul><pre><code>sudo rpi-update</code></pre><ul><li>Install Linux Headers</li></ul><pre><code>sudo apt install raspberrypi-kernel-headers</code></pre><ul><li>Install WireGuard</li></ul><pre><code>sudo apt install wireguard</code></pre><ul><li>Clone WireGuard source code</li></ul><pre><code>git clone https://git.zx2c4.com/WireGuard</code></pre><p>But when I tried to run the client script:</p><pre><code>sudo WireGuard/contrib/examples/ncat-client-server/client.sh</code></pre><p>BOOM!!</p><pre><code>RTNETLINK answers: Operation not supported</code></pre><p>According to <a href="https://superuser.com/questions/232807/iproute2-not-functioning-rtnetlink-answers-operation-not-supported">StackExchange</a>, I need to <a href="https://www.raspberrypi.org/documentation/linux/kernel/building.md">compile the kernel</a> and <a href="https://www.raspberrypi.org/documentation/linux/kernel/">customize the configuration</a> to get iproute2 to work.</p><p>Sigh. Add it to the TO-DO list.</p>]]></content:encoded></item><item><title><![CDATA[村庙碑文]]></title><description><![CDATA[<h2 id="-">其一：觀音堂流芳百世碑</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="http://blog.pany.pro/content/images/2019/02/IMG_4874.JPG" class="kg-image"><figcaption>觀音堂流芳百世碑</figcaption></figure><p><em>为村中「奶奶庙」打扫，见此古碑，没想到其历史竟如此悠久。感叹之余，将正面碑文整理抄录如下：</em></p><h3 id="--1">重修觀音堂碑記</h3><p>蓋聞天地以生民為心，菩薩即以保民為念。第人心未能以輸其誠，致神功無由以顕其效也。本村舊有觀音堂一座，不知創自何時，至乾隆二十九年重修迄於今代。遠年湮风雨損壞，殊令人目覩而心傷矣。不禁合村人等各施貲財，且募化四方，復為重修之舉。故峻宇雕牆、丹楹刻桷為神靈謀，非為觀瞻計也。告竣之後，庶幾趨蹌得其所，拜跪有所憑。人心以將其誠，亦神功無不見其效焉。</p><p>邑庠生姚得勤撰文書丹。</p><p>會首：姚士銀、姚思節</p><p>理事：姚思誠、姚得儉、姚得江、姚清年、姚士宗</p><p>掌賬：姚得勤、姚思節、姚賀年、姚清年</p><p>買辦：姚得節、姚文心</p><p>總催：</p>]]></description><link>http://blog.pany.pro/stele/</link><guid isPermaLink="false">5c55aa4d1d1bfc00018b146d</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Sat, 02 Feb 2019 14:38:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="-">其一：觀音堂流芳百世碑</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="http://blog.pany.pro/content/images/2019/02/IMG_4874.JPG" class="kg-image"><figcaption>觀音堂流芳百世碑</figcaption></figure><p><em>为村中「奶奶庙」打扫，见此古碑，没想到其历史竟如此悠久。感叹之余，将正面碑文整理抄录如下：</em></p><h3 id="--1">重修觀音堂碑記</h3><p>蓋聞天地以生民為心，菩薩即以保民為念。第人心未能以輸其誠，致神功無由以顕其效也。本村舊有觀音堂一座，不知創自何時，至乾隆二十九年重修迄於今代。遠年湮风雨損壞，殊令人目覩而心傷矣。不禁合村人等各施貲財，且募化四方，復為重修之舉。故峻宇雕牆、丹楹刻桷為神靈謀，非為觀瞻計也。告竣之後，庶幾趨蹌得其所，拜跪有所憑。人心以將其誠，亦神功無不見其效焉。</p><p>邑庠生姚得勤撰文書丹。</p><p>會首：姚士銀、姚思節</p><p>理事：姚思誠、姚得儉、姚得江、姚清年、姚士宗</p><p>掌賬：姚得勤、姚思節、姚賀年、姚清年</p><p>買辦：姚得節、姚文心</p><p>總催：元春才</p><p>監工：姚思榮、姚士儉、元中美、姚思正、姚士經、元春榮、姚有財</p><p>大清光緒二十三年四月十八日立</p><h2 id="--2">其二：奶奶庙萬古流芳碑</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="http://blog.pany.pro/content/images/2019/02/IMG_4873-1.JPG" class="kg-image"><figcaption>奶奶庙萬古流芳碑</figcaption></figure><p><em>多年之后，庙宇重修，新立石碑，誊录如下：</em></p><h3 id="--3">重修奶奶庙碑記</h3><p>「南海菩萨庙」，普称「奶奶庙」。根据旧庙碑文記载及老人续传，「奶奶庙」含意隽永。清咸丰年间，医药落后，民遭瘟疫，伤亡甚大。阖众求菩萨聖予慈悲，当日得稳。众感大恩，於光绪三年重加修补彩画。一九四七年遭战火，庙宇被毁。一九六三年洪水袭击，片瓦不存，赤身移至此。国家照顾，重建家园，奶奶庙因条件限制，有恩难报。聖宇未得安所，众常怀记在心，时至必成。一九九六年，全村大众齐心合意，重建聖宇，集资备料。一九九七年秋后，聖殿竣工。二零一零年村里硬化街道，奶奶庙限于低洼，众议重建。随于二零一二年三月十八日起工，至四月十九日落成。</p><p>公元二零一二年农历七月初六立</p><p><em>依家父听闻，旧碑曾于一九六三年洪水中失落，约于二零一六年被另一村庄村民挖沙时发现，见上有元氏先人「元春才」名讳，打听至本村，方得以送还。故而新旧碑文中故事有所出入，亦情有可原。</em></p><p><em>区区墟里，虽无大传名志，藉此庙碑亦可使后人管窥白云苍狗。时过境迁，万物刍狗。「不问鬼神问苍生」，且读碑文所载先人拳拳之意，仍感心有戚戚焉。</em></p>]]></content:encoded></item><item><title><![CDATA[Install wubi_pinyin w/ RIME]]></title><description><![CDATA[<p>I. Install RIME for macOS (a.k.a. Squirrel)</p><pre><code>brew cask install squirrel</code></pre><p>Then <strong>reboot</strong> Mac.</p><p>II. Download RIME schema installation script</p><pre><code>git clone https://github.com/rime/plum.git
cd plum
bash rime-install wubi pinyin-simp</code></pre><p>III. Create custom configuration file</p><pre><code>vim ~/Library/Rime/default.custom.yaml</code></pre><p>Add content below:</p>]]></description><link>http://blog.pany.pro/install-wubi_pinyin-w-rime/</link><guid isPermaLink="false">5c3050101d1bfc00018b13f4</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Sat, 05 Jan 2019 08:33:51 GMT</pubDate><content:encoded><![CDATA[<p>I. Install RIME for macOS (a.k.a. Squirrel)</p><pre><code>brew cask install squirrel</code></pre><p>Then <strong>reboot</strong> Mac.</p><p>II. Download RIME schema installation script</p><pre><code>git clone https://github.com/rime/plum.git
cd plum
bash rime-install wubi pinyin-simp</code></pre><p>III. Create custom configuration file</p><pre><code>vim ~/Library/Rime/default.custom.yaml</code></pre><p>Add content below:</p><pre><code>patch:
  schema_list:
    - schema: wubi_pinyin
    - schema: luna_pinyin_simp</code></pre><p>Then create a <code>squirrel.custom.yaml</code> in the same direction:</p><pre><code>patch:
  style:
    color_scheme: mojave_dark
    horizontal: true</code></pre><p>IV. Import personal database (if you have that before)</p><pre><code>cp -r wubi86.userdb luna_pinyin.userdb ~/Library/Rime/</code></pre><p>V. Set Squirrel as default input method</p><p><code>System Preferences</code> - <code>Keyboard</code> - <code>Input Sources</code> </p><p>Switch to Squirrel, then <code>Deploy</code>.</p>]]></content:encoded></item><item><title><![CDATA[SSH tunnel]]></title><description><![CDATA[<p><em>source:</em> <a href="https://hackertarget.com/ssh-examples-tunnels/">https://hackertarget.com/ssh-examples-tunnels/</a></p><hr><h3 id="6-establish-a-vpn-over-ssh">6. Establish a VPN over SSH</h3><p>A common term amongst offensive security folks (pentesters / red  teams / etc), is to pivot into a network. Once you have a connection  established on one system that system becomes a gateway point for  further access to the network. This</p>]]></description><link>http://blog.pany.pro/ssh-tunnel/</link><guid isPermaLink="false">5c2f0f231d1bfc00018b13da</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Fri, 04 Jan 2019 07:53:53 GMT</pubDate><content:encoded><![CDATA[<p><em>source:</em> <a href="https://hackertarget.com/ssh-examples-tunnels/">https://hackertarget.com/ssh-examples-tunnels/</a></p><hr><h3 id="6-establish-a-vpn-over-ssh">6. Establish a VPN over SSH</h3><p>A common term amongst offensive security folks (pentesters / red  teams / etc), is to pivot into a network. Once you have a connection  established on one system that system becomes a gateway point for  further access to the network. This is known as pivoting and enables  lateral movement through the network.</p><p>We can use the SSH proxy for this and <strong>proxychains</strong>, however there are some limitations. For example we cannot use raw sockets, so <a href="https://hackertarget.com/nmap-online-port-scanner/">Nmap</a> <code>SYN</code> scans cannot be used to port scan the Internal network.</p><p>Using this more advanced VPN option we move the connectivity down to <strong>layer 3</strong>. We can then simply route traffic through the tunnel using standard network routing.</p><p>This technique uses <code>ssh</code>, <code>iptables</code>, <code>tun interfaces</code> and routing.</p><p>First we need these options set in the <code>sshd_config</code>. Since we are making interface changes on the remote system and the client system, we will <strong>need root privileges on both sides</strong>.</p><pre><code>PermitRootLogin yes
PermitTunnel yes</code></pre><p>Then we will establish our <code>ssh</code> connection using the parameter that requests <code>tun</code> devices be initialised.</p><pre><code>localhost:~# ssh -v -w any root@remoteserver</code></pre><p>Now you should have a <code>tun</code> device when you show interfaces (<code># ip a</code>). Next step is to add IP addresses to the tunnel interfaces.</p><p>SSH Client Side:</p><pre><code>localhost:~# ip addr add 10.10.10.2/32 peer 10.10.10.10 dev tun0 
localhost:~# ip tun0 up</code></pre><p>SSH Server Side:</p><pre><code>remoteserver:~# ip addr add 10.10.10.10/32 peer 10.10.10.2 dev tun0 remoteserver:~# ip tun0 up</code></pre><p>Now we should have a direct route to the other host (<code>route -n</code> and <code>ping 10.10.10.10</code>).</p><p>It is now possible to route any subnet through the other side host. </p><pre><code>localhost:~# route add -net 10.10.10.0 netmask 255.255.255.0 dev tun0</code></pre><p>On the remote side we need to enable <code>ip_forward</code> and <code>iptables</code>.</p><pre><code>remoteserver:~# echo 1 &gt; /proc/sys/net/ipv4/ip_forward 
remoteserver:~# iptables -t nat -A POSTROUTING -s 10.10.10.2 -o enp7s0 -j MASQUERADE</code></pre><p>Boom! <strong>Layer three VPN through an SSH tunnel</strong>. Now that's winning.</p><p>Any trouble, try <a href="https://hackertarget.com/tcpdump-examples/">tcpdump</a> and <code>ping</code> to see where its broken. Since we are playing at layer 3 our <code>icmp</code> packets should be jumping through that tunnel.</p><hr><h3 id="20-bouncing-through-jump-hosts-with-ssh-and-j">20. Bouncing through jump hosts with ssh and -J</h3><p>When network segmentation means you are jumping through multiple <code>ssh</code> hosts to get to a final destination network or host, this jump host shortcut might be just what you need.</p><pre><code>localhost:~$ ssh -J host1,host2,host3 user@host4.internal</code></pre><p>A key thing to understand here is that this is not the same as <code>ssh host1</code> then <code>user@host1:~$ ssh host2</code>, the <code>-J</code> jump parameter uses forwarding trickery so that the <strong>localhost</strong> is establishing the session with the next host in the chain. So our <strong>localhost</strong> is authenticating with <strong>host4</strong> in the above example; meaning our <strong>localhost keys</strong> are used and the session from <strong>localhost</strong> to <strong>host4</strong> is <strong>encrypted end to end</strong>.</p><p>To use this ability in the <code>ssh_config</code> use the <strong>ProxyJump</strong> configuration option. If you regularly have to jump through multiple hosts; use the config file and your alias to <code>host4</code> will save you a lot of time.</p><hr><h3 id="22-modify-port-forwarding-within-a-session-with-c">22. Modify Port Forwarding within a session with ~C</h3><p>And our final <code>ssh</code> example is for modifying port forwarding on the fly within an existing <code>ssh</code> session. Picture this example scenario. You are deep in a network;  perhaps you have jumped through half a dozen jump hosts and need a local  port on your workstation forwarded to Microsoft SMB on the old Windows  2003 system you spotted (ms08-67 anyone?).</p><p>After hitting <code>enter</code> try typing <code>~C</code> in your terminal. This a control escape sequence within the session that allows to make changes to the existing connection.</p><pre><code>localhost:~$ ~C 
ssh&gt; -h
Commands:
      -L[bind_address:]port:host:hostport    Request local forward
      -R[bind_address:]port:host:hostport    Request remote forward
      -D[bind_address:]port                  Request dynamic forward                   
      -KL[bind_address:]port                 Cancel local forward       
      -KR[bind_address:]port                 Cancel remote forward       
      -KD[bind_address:]port                 Cancel dynamic forward 
ssh&gt; -L 1445:remote-win2k3:445
Forwarding port.</code></pre><p>You can see here we have forwarded our local port 1445 to the <strong>Windows 2003</strong> host we found on the internal network. Now simply launch <code>msfconsole</code> and we are good to go (assuming you were planning on <strong>exploiting that host</strong>).</p>]]></content:encoded></item><item><title><![CDATA[Silverblue Note]]></title><description><![CDATA[<blockquote>Configuring Docker to use the cluster registry cache</blockquote><blockquote>Add the local cache registry running on the master to the docker options that get pulled into the systemd unit file.</blockquote><pre><code>[fedora@atomic01 ~]$ sudo vi /etc/sysconfig/docker
OPTIONS='--registry-mirror=http://192.168.122.10:5000 --selinux-enabled --log-driver=journald'</code></pre><p>cite: <a href="https://www.projectatomic.io/docs/gettingstarted/">https://www.</a></p>]]></description><link>http://blog.pany.pro/silverblue-note/</link><guid isPermaLink="false">5c2733df1d1bfc00018b13a3</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Sat, 29 Dec 2018 08:48:32 GMT</pubDate><content:encoded><![CDATA[<blockquote>Configuring Docker to use the cluster registry cache</blockquote><blockquote>Add the local cache registry running on the master to the docker options that get pulled into the systemd unit file.</blockquote><pre><code>[fedora@atomic01 ~]$ sudo vi /etc/sysconfig/docker
OPTIONS='--registry-mirror=http://192.168.122.10:5000 --selinux-enabled --log-driver=journald'</code></pre><p>cite: <a href="https://www.projectatomic.io/docs/gettingstarted/">https://www.projectatomic.io/docs/gettingstarted/</a></p><figure class="kg-card kg-image-card"><img src="http://blog.pany.pro/content/images/2019/01/IMG_4653.png" class="kg-image"></figure>]]></content:encoded></item><item><title><![CDATA[Product Microcopy]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>收集整理一些产品的小细节。</p>
<ul>
<li><a href="http://www.thedrum.com">http://www.thedrum.com</a></li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2017/10/ScreenShot.png" alt="LET'S GET CONNECTED"></p>
<p>Emoji 和提示语，第一次看有趣，点过之后置灰，或消失，提供关闭按钮，避免反感。</p>
<ul>
<li>豆瓣电影介绍「话题」新功能</li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2018/01/douban-topic.png" alt="douban-topic"></p>
<p>时下用遮盖的可能较多，用同一平面标注的较少。</p>
<ul>
<li>B 站的创新：长按点赞按钮 == 点赞 + 投币 + 收藏</li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2018/12/2018-12-25-15.44.52.jpg" alt="2018-12-25-15.44.52"></p>
<!--kg-card-end: markdown-->]]></description><link>http://blog.pany.pro/product-microcopy/</link><guid isPermaLink="false">5c2117307a280400018ce955</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Thu, 04 Jan 2018 04:35:57 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>收集整理一些产品的小细节。</p>
<ul>
<li><a href="http://www.thedrum.com">http://www.thedrum.com</a></li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2017/10/ScreenShot.png" alt="LET'S GET CONNECTED"></p>
<p>Emoji 和提示语，第一次看有趣，点过之后置灰，或消失，提供关闭按钮，避免反感。</p>
<ul>
<li>豆瓣电影介绍「话题」新功能</li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2018/01/douban-topic.png" alt="douban-topic"></p>
<p>时下用遮盖的可能较多，用同一平面标注的较少。</p>
<ul>
<li>B 站的创新：长按点赞按钮 == 点赞 + 投币 + 收藏</li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2018/12/2018-12-25-15.44.52.jpg" alt="2018-12-25-15.44.52"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Setup Ghost blog w/ Docker]]></title><description><![CDATA[<!--kg-card-begin: markdown--><ul>
<li>Export your content from <code>SETTINGS</code>-<code>Labs</code>-<code>Export your content</code></li>
<li>Backup your images folder</li>
<li>Install docker<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></li>
<li>Setup Docker<br>
<code>sudo usermod -aG docker $USER</code><br>
Log out then Re-login<br>
<code>sudo systemctl start docker</code><br>
<code>sudo systemctl enable docker</code><br>
<code>docker pull ghost</code></li>
<li>Run Docker<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup></li>
</ul>
<pre><code class="language-bash">docker run -d --name blog \
	--restart unless-stopped</code></pre>]]></description><link>http://blog.pany.pro/ghost-docker/</link><guid isPermaLink="false">5c2117307a280400018ce95d</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Thu, 28 Dec 2017 08:03:31 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><ul>
<li>Export your content from <code>SETTINGS</code>-<code>Labs</code>-<code>Export your content</code></li>
<li>Backup your images folder</li>
<li>Install docker<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></li>
<li>Setup Docker<br>
<code>sudo usermod -aG docker $USER</code><br>
Log out then Re-login<br>
<code>sudo systemctl start docker</code><br>
<code>sudo systemctl enable docker</code><br>
<code>docker pull ghost</code></li>
<li>Run Docker<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup></li>
</ul>
<pre><code class="language-bash">docker run -d --name blog \
	--restart unless-stopped \
	-p 80:2368 \
	-v /path/to/ghost/content/images:/var/lib/ghost/content/images \
	-v /path/to/ghost/content/data:/var/lib/ghost/content/data \
	-v /path/to/ghost/content/logs:/var/lib/ghost/content/logs \
	-v /path/to/ghost/content/themes:/var/lib/ghost/content/themes \
	-v /path/to/ghost/config.production.json:/var/lib/ghost/config.production.json \
	ghost
</code></pre>
<ul>
<li>Signin via <code>your-url.com/ghost</code></li>
<li>Inport your content</li>
<li>Unlock your account<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup></li>
</ul>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://docs.docker.com/engine/installation/">Docker installation</a> <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://www.ghostforbeginners.com/deploying-ghost-with-docker/">Deploying Ghost With Docker</a> <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://briankoopman.com/unlock-ghost-account/">Unlock Your Locked Ghost Account</a> <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Recognize subtitle from video]]></title><description><![CDATA[<!--kg-card-begin: markdown--><ol>
<li>Play the video w/ IINA<br>
While playing, press [s] to take screenshots.</li>
</ol>
<blockquote>
<p>TBD: Is there a better way?</p>
</blockquote>
<ol>
<li>Crop bulk screenshots w/ [Image Crop]<br>
Set &quot;Custom Crop&quot;, &quot;Pixels&quot; and &quot;Output&quot;.</li>
<li>Generate subtitle pdf file<br>
<code>ls &gt;&gt; subtitle.md</code> then <code>vim subtitle.md</code> add</li></ol>]]></description><link>http://blog.pany.pro/recognize-subtitle-from-video/</link><guid isPermaLink="false">5c2117307a280400018ce957</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Mon, 13 Nov 2017 16:49:18 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><ol>
<li>Play the video w/ IINA<br>
While playing, press [s] to take screenshots.</li>
</ol>
<blockquote>
<p>TBD: Is there a better way?</p>
</blockquote>
<ol>
<li>Crop bulk screenshots w/ [Image Crop]<br>
Set &quot;Custom Crop&quot;, &quot;Pixels&quot; and &quot;Output&quot;.</li>
<li>Generate subtitle pdf file<br>
<code>ls &gt;&gt; subtitle.md</code> then <code>vim subtitle.md</code> add <code>![]()</code>, generate pdf w/ [Typora]</li>
</ol>
<blockquote>
<p>TBD: Is there a tool to OCR bulk images?</p>
</blockquote>
<ol>
<li>Convert pdf to word w/ [PDF to Word Converter]</li>
</ol>
<h1 id="recap">Recap</h1>
<p>Need an AI way.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Download macOS High Sierre via CLI (Aria2)]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Apple's CDN sucks. Especially in China mainland.</p>
<p>So, if you couldn't successfully download macOS Installer from Mac App Store, follow these steps to download the Installer via CLI tool – <a href="https://github.com/aria2/aria2"><code>Aria2</code></a>.</p>
<ul>
<li>Download from Mac App Store.</li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2017/10/1.png" alt></p>
<p>Yeah, we still need Mac App Store in order to get the direct links. Before</p>]]></description><link>http://blog.pany.pro/download-macos-high-sierre-via-cli-aria2/</link><guid isPermaLink="false">5c2117307a280400018ce954</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Mon, 23 Oct 2017 10:10:13 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Apple's CDN sucks. Especially in China mainland.</p>
<p>So, if you couldn't successfully download macOS Installer from Mac App Store, follow these steps to download the Installer via CLI tool – <a href="https://github.com/aria2/aria2"><code>Aria2</code></a>.</p>
<ul>
<li>Download from Mac App Store.</li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2017/10/1.png" alt></p>
<p>Yeah, we still need Mac App Store in order to get the direct links. Before you wasting time downloading it, delete it from Launchpad.</p>
<p><img src="http://blog.pany.pro/content/images/2017/10/2.png" alt></p>
<ul>
<li>Check the <code>extraInfo</code> file at <code>/Library/Updates/***-*****/***-*****.English.extraInfo</code>.</li>
</ul>
<p><code>***-*****</code> means several numbers (maybe version code?), e.g.:</p>
<p><img src="http://blog.pany.pro/content/images/2017/10/3.png" alt></p>
<p>See the link above?</p>
<blockquote>
<p>(Pff... Seriously? Not even HTTPS?)</p>
</blockquote>
<pre><code>http://swcdn.apple.com/content/downloads/30/55/091-36857/e08asjpjpbflt33p43ufqmuv6b39x8pa10/InstallAssistantAuto.smd
</code></pre>
<p>There are 3 files you need to download: <code>RecoveryHDMetaDmg.pkg</code>, <code>InstallAssistantAuto.pkg</code>, and <code>InstallESDDmg.pkg</code>. Thus in this case, URLs will be:</p>
<pre><code>http://swcdn.apple.com/content/downloads/30/55/091-36857/e08asjpjpbflt33p43ufqmuv6b39x8pa10/RecoveryHDMetaDmg.pkg

http://swcdn.apple.com/content/downloads/30/55/091-36857/e08asjpjpbflt33p43ufqmuv6b39x8pa10/InstallAssistantAuto.pkg

http://swcdn.apple.com/content/downloads/30/55/091-36857/e08asjpjpbflt33p43ufqmuv6b39x8pa10/InstallESDDmg.pkg
</code></pre>
<p>Modify the URLs if you need, then download these 3 files via <code>Aria2</code>:</p>
<pre><code>aria2c -x8 &quot;URL&quot;
</code></pre>
<p>After successfully downloading them, copy them to the directory <code>/Library/Updates/***-*****/</code> ('Member the code numbers? Check above).</p>
<ul>
<li>Final step, open Mac App Store and click <code>Download</code> button again, wait a minute, Ta-da! You will get the <code>Install macOS High Sierra.app</code>!</li>
</ul>
<p><img src="http://blog.pany.pro/content/images/2017/10/4.png" alt></p>
<ul>
<li>One more thing...</li>
</ul>
<p>If you want to check the sha1sum hash, I'll recommend <a href="https://github.com/notpeter/apple-installer-checksums">https://github.com/notpeter/apple-installer-checksums</a>.</p>
<p><img src="http://blog.pany.pro/content/images/2017/10/5.png" alt></p>
<p>Good luck.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Grid systems]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>《平面设计中的网格系统》</p>
<p><em>Grid systems in graphic design</em></p>
<p><img src="http://blog.pany.pro/content/images/2017/10/IMG_2809.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2811.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2836.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2837.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2957.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2958.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2974.JPG" alt></p>
<!--kg-card-end: markdown-->]]></description><link>http://blog.pany.pro/grid-systems/</link><guid isPermaLink="false">5c2117307a280400018ce953</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Thu, 19 Oct 2017 07:48:30 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>《平面设计中的网格系统》</p>
<p><em>Grid systems in graphic design</em></p>
<p><img src="http://blog.pany.pro/content/images/2017/10/IMG_2809.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2811.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2836.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2837.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2957.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2958.jpg" alt><br>
<img src="http://blog.pany.pro/content/images/2017/10/IMG_2974.JPG" alt></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[西文字体]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><img src="http://blog.pany.pro/content/images/2017/09/IMG_2779.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2780.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2781.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2782.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2783.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2798.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2806.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2807.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2808.JPG" alt></p>
<!--kg-card-end: markdown-->]]></description><link>http://blog.pany.pro/xi-wen-zi-ti/</link><guid isPermaLink="false">5c2117307a280400018ce952</guid><dc:creator><![CDATA[Pany]]></dc:creator><pubDate>Fri, 01 Sep 2017 08:24:06 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><img src="http://blog.pany.pro/content/images/2017/09/IMG_2779.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2780.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2781.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2782.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2783.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2798.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2806.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2807.JPG" alt><br>
<img src="http://blog.pany.pro/content/images/2017/09/IMG_2808.JPG" alt></p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>