Giter VIP home page Giter VIP logo

blog's People

Contributors

tsunhua avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

blog's Issues

SSH 登录须知

SSH 背景

  • 解决的问题:明文登录信息暴露问题。

  • 历史:

    1. 1995 年,芬兰赫尔辛基理工大学的 Tatu Ylonen 发现自己学校存在嗅探密码的网络攻击,于是开发了 SSH (Secure Shell)通信安全协议,用于加密登录,并随后以免费软件形式发布,并创办 SSH 通信安全公司来继续开发和销售SSH。
    2. 截至2005年,OpenSSH 是唯一一种最流行的SSH实现,而且成为了大量操作系统的默认组件。

SSH 原理

核心:非对称加密

整个过程是这样的:

  1. 远程主机收到用户的登录请求,把自己的公钥发给用户。
  2. 用户使用这个公钥,将登录密码加密后,发送回来。
  3. 远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。

口令登录

用户使用 ssh user@host 登录远程主机时,系统会提示远程主机的公钥指纹,当用户确认接收该公钥指纹时,会保存到 $HOME/.ssh/known_hosts 中,下次登录时会跳过。

公钥指纹:公钥长度较长(这里采用RSA算法,长达1024位),很难比对,所以对其进行MD5计算,将它变成一个128位的指纹。上例中是 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d,再进行比较。

公钥登录

所谓"公钥登录",原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

用户将自己的公钥储存在远程主机的具体过程如下:

  1. 使用 ssh-keygen 在本地目录 $HOME/.ssh/ 生成公钥 id_rsa.pub 和密钥 id_rsa

  2. 使用 ssh-copy-id user@host 将公钥上传至远程主机 host 中,实现细节是:

    $ ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub

SSH CONFIG FILE

可以通过配置文件快速进行 ssh 登录,配置文件有两种:

  1. 用户配置文件 ~/.ssh/config
  2. 系统配置文件 /etc/ssh/ssh_config)

可配置项有:

  • Host,配置标识,使用 ssh [Host] 进行快速登录;
  • HostName,服务器所在地址,可以是域名或 IP;
  • User,进行 ssh 登录的用户名;
  • Port,指定服务器端口;
  • IdentityFile,指定私钥文件的位置。

如在 ~/.ssh/config文件中按如下配置,则可以通过 ssh xx-server 进行快速 ssh 登录。

Host xx-server
    HostName ssh.xx-server.com
    User xx_user
    Port 2200
    IdentityFile ~/.ssh/local_id_rsa

名词解释

名词 含义
X.509 一种通用的证书格式,包含证书持有人的公钥,加密算法等信息
pkcs1 ~ pkcs12 公钥加密(非对称加密)的一种标准,一般存储为 *.pN*.p12 是包含证书和密钥的封装格式
*.der 证书的二进制存储格式(不常用)
*.pem 证书或密钥的 Base64 文本存储格式,可以单独存放证书或密钥,也可以同时存放
*.key 单独存放的 pem 格式的密钥,一般保存为 *.key
*.cer *.crt 两个指的都是证书,Linux 下叫 crt,Windows 下叫 cer;存储格式可以是 pem 也可以是 der
*.pfx 微软 IIS 的实现
*.jks Java Keytool 实现的证书格式

参考

《日語自遊行の最和味》第三課 七夕

對話

健さん、香港 にも 七夕祭りがありますが。
牽牛 と織女 が 一年に一度 天の川 で デイトを する。
ごの話 は ありますが。
子ども たち は 短冊に 願い事 を 書きます。
そして、笹の葉 に その短冊 を 飾ります。
いいですね。
私は 「日本語 が 上手に なります ように。」と書きたいです。
私 は 「すてきな 出会い が ありますように。」と書きたいです。
桜:阿健,香港也有七夕節嗎?
健:我們有牛郎和織女一年一度在銀河相會的傳說。
桜:(在日本) 小孩子們把願望寫在小紙條上,然後裝飾在幼竹葉上。
健:這個很不錯。我想寫「希望我的日文更加進步」。
桜:我想寫「希望能遇到我的白馬王子」。

附錄

  1. 日語自遊行の最和味

閩南語拼音方案

閩語拼音方案種種

名稱 簡稱 特征 發佈情況
白话字 POL 白话字是历史最为悠久的拉丁化方案,因此广泛流通于全球各地的闽南语流通地区。 17世紀文獻中,如英國人與鄭氏王朝通商的商館紀錄中,便存在以羅馬字母拼寫閩南語語音的「白話字」雛型。1850年,教會正式推行白話文。
臺灣語言音標方案 TLPA 內含臺灣閩南語音標系統、臺灣客家語音標系統、臺灣原住民語音標系統等三套系統。 台灣語文學會於1991年期間針對臺灣語言所制定的音標系統。
台灣闽南语罗马字拼音方案 TL 与白话字的相容性良好,可以视为白话字的增补或发展上的分支。在**,使用白话字的社群有较高的意愿使用台罗拼音,同时,在官方地位方面台罗拼音方案取代了TLPA。 2006年10月14日,台灣教育部正式發佈。
台語通用拼音方案 DT 與漢語拼音相容。目的在於統一華語、客語和閩語的拼音系統。 暫無相關資訊
闽南方言拼音方案 BP 與漢語拼音相容,并參考《汇集雅俗通十五音》,基於廈門口音。 另称“《普闽典》方案”来自于1982年10月厦门大学主编的《普通话闽南方言词典》一书。

臺羅系統和通用拼音之爭

臺羅系統和通用拼音最大的爭執在於國際上普遍使用的濁音符號 b, d , g 要標示濁音,還是不送氣清音的問題。這個爭執,如果要考慮音標符號的普遍性,就變成可以討論的問題。 世界上沒有濁音的語言不多,世界上沒有濁音卻有送氣音的語言很少,華語正好是這種罕見的語言。世界上大部分的語言都是清濁音二元對立,華語沒有濁音卻有送氣音,一樣是二元對立,因此漢語拼音就把濁音符號 b, d, g 用來標示不送氣清音,而把清音符號用來標示送氣清音,這在中國本位立場雖然可行,卻違背了世界通用拼音的習慣。在中國境內,不但是北京話,即連其他有濁音的漢語也都遵從這個系統而修補,但這種系統只能在中國通行,可以說是中國通用拼音系統(簡稱C系統),和世界通用的拼音系統(簡稱W系統)是不相容的。這一點從下表即可了解。

— 引自《臺語拼音論戰簡史》

在台通拼音方案中,任一音节若用某个在台罗拼音已经采用的拼写法,则此音节在台通拼音中之拼写法亦相同、或有一等式符号与之对应。意即台通拼音与台罗拼音在拼音的结构上具有完全的相容性。

— 引自《臺語通用拼音-維基百科》

台灣闽南语罗马字拼音方案

閩南語的音節結構

閩南語是漢語的一種,因此音節結構也一樣可以區分為五個音位成分:聲母、韻頭(介音)、韻腹、韻尾、聲調。韻頭、韻腹、韻尾又合稱為韻母。閩南語有變調,而台羅方案和白話字一樣,都只標示本調,且採用變音符號來標示聲調,稱為調號或調符。

聲母

台灣閩南語的聲母有十八個音位,其中「零聲母」並非沒有聲母,而是喉塞音,漢字是TLPA方案所建議的,除了「毛、耐、雅」之外,大多為傳統十五音。零聲母「英」不標。

台灣閩南語的塞音及塞擦音,分成了清送氣音、清不送氣音、鼻濁音三重對立。這也是通用拼音與臺羅拼音爭論的源頭。

韻母

聲調

閩語有八音,普通腔沒有第六音(陽上音)。

傳統調類 陰平 陰上 陰去 陰入 陽平 陽上 陽去 陽入
台羅 a á à ah â ǎ ā a̍h
例字
IPA調符(以高雄腔為主) ˦˦ ˥˧ ˨˩ ˧˨ ˨˦ ˧˧(鹿港腔 ˧˧ ˦

其脫胎自 IPA 中聲調,并合二調符為一符,基本符合聲調的走向。第四調和第八調另加 hk 表示入音。

調號標識

當一個音節有多個字母時,調號應該標示在響度(sonority)最大的字母上面(通常在韻腹)。由規則可以判定確切的字母:

  1. 響度優先順序: a > oo > e = o > i = u〈低元音 > 高元音 > 無擦通音 > 擦音 > 塞音〉
  2. iu 及 ui ,調號都標在後一個字母,因為前一個字母是介音。
  3. m 作韻腹時標於 m 上。
  4. 雙字母 oo 及 ng,標於前一個字母。
  5. 三字母 ere,標於最後的 e。

參考

《海街日记》观后

海街diary

导演: 是枝裕和
编剧: 是枝裕和 / 吉田秋生
主演: 绫濑遥 / 长泽雅美 / 夏帆 / 广濑铃 / 大竹忍 / 更多...
类型: 剧情 / 家庭
官方网站: umimachi.gaga.ne.jp
制片国家/地区: 日本
语言: 日语
上映日期: 2015-05-14(戛纳电影节) / 2015-06-13(日本)
片长: 127分钟
又名: 海街女孩日记(港) / Kamakura Diary / Umimachi Diary / Our Little Sister
IMDb链接: tt3756788

观后感

大家都懂得宽恕了,怨恨终究没有湮灭亲情。

古都镰仓,有一家,唤香田氏。父亲与情人奔走,母亲亦离去,留下三女,幸、加乃、千佳,与外婆看管。外婆去逝后,三女相依为命,共同居住在父母留下的老宅中。老宅有庭院,有花草,还有 55 年历史的梅树,虽然没有父母,也自有一片温馨。

一日,传来父亲逝世的噩耗。姐妹们几分犹豫,但还是决定去参加父亲的葬礼。一下电车,就听到一个女中学生在挥手打招呼,询问后才知道是同父异母的妹妹浅野玲。玲不爱说话,似乎内心承担着许许多多她这个年纪不该承担的东西。是的,这些年是她在一直照顾着父亲,而生母已逝,继母无爱。三个姐姐临走时,玲赶了上来,拿出了父亲放在桌上一个信封,拆开看原是三个姐姐小时候的照片,小时候的一切历历在目。上电车时,幸姐看着孤独无依的玲说:来老家吧,我们一起生活。

随后,玲怀着对未来生活的憧憬,进入了这 “女生宿舍” 开始了四姐妹的生活。她们一起聊天,一起做饭,一起制作梅酒,一起去沙滩,一起去海猫食堂,一起穿和服放烟花。玲还加入了学校的足球队,成为了队中的宠儿,并认识了好朋友风太,跟他一起骑自行车穿越樱花隧道。

在与玲的相处过程中,姐妹们与父亲和解了,一致觉得父亲还是温柔的,至少还给她们留下这么个可爱的妹妹。

而与母亲的和解是在参加外婆的七回忌(死亡六周年追悼会)后,母女争吵的第二天,母亲送来了原本应该是前一天给与三个女儿还有玲的礼物,并打算去看看外婆的墓地后离去。幸顿了下,立即醒过神来,跟母亲一起去拜祭外婆,在回来路上母亲谈及女儿们还在酿梅酒,幸跑回家取出外婆酿的和四姐妹新酿的梅酒各一瓶,赶在母亲走之前作为礼物。此间的浓浓亲情,化解了漫漫怨恨。

IDEA 小记

1. 查看某个类的 javadoc 的快捷键?

在该类旁边敲击 ctrl + j

日本的喪葬法事

日本的喪葬法事真正體現了吾國以前對待逝者「慎終追遠」的**。日本的法事莊重、肅穆、感恩、哀有度,對逝者有充分的尊重,對與會者是一場心靈的洗禮。以下內容翻譯自 法要に関する基礎知識 ,如有不當,懇請指正。

法事種類 逝後時期 補充
付け七日(つけなのか) 第 1 天 是喪葬儀式當日合起還骨修行進行頭七。
初七日(しょなのか) 第 7 天 しょしちなのか・初願忌(しょがんき)。多數情況下在還骨修行法事和遺體告別儀式中合併舉行。
二七日(ふたなのか) 第 14 天 にしちにち・以芳忌(いほうき)。
三七日(みなのか) 第 21 天 さんしちにち・洒水忌(しゃすいき)。
四七日(よなのか) 第 28 天 ししちにち・阿経忌(あぎょうき)。
初月忌(しょがっき) 月命日 死後第一個月的忌辰法事。
五七日(いつなのか) 第 35 天 ごしちにち・三十五日(ごしちにち)・小練忌(しょうれんき)。大部分情況下被省略了。有的地方進行除服儀式。
六七日(むなのか) 第 42 天 ろくしちにち・檀弘忌(だんこうき)。
七七日(なななのか) 第 49 天 しちしちにち・四十九日(しじゅうくにち)・忌明け・満中陰・尽七日・大練忌(だいれんき)。這是在到一周年忌辰为止的法事中最重要的。叫齊朋友,親属,讓僧侣增誦佛經�,供養之后聚餐。常常也舉行納骨法事,除服送奠仪回禮。
百か日(ひゃっかにち)百ヶ日 第 100 天 出苦忌(しゅっくき),也叫卒哭忌(そつこくき)。故人成為新亡靈的法事。
一周忌 満 1 年 一般来说,它被称为「喪中」。打电话给朋友、亲戚、僧侣們,供養后聚餐。
三回忌 満 2 年 同上
七回忌 第 6 年 逝者的家庭、親戚來完成。七回忌 後規模逐漸縮小。
十三回忌 第 12 年 通常只由逝者的家庭来完成。
十七回忌 第 16 年 同上
二十三回忌 第 22 年 同上
二十七回忌 第 26 年 同上
三十三回忌 第 32 年 同上
五十回忌 第 49 年 同上。之後每 50 年可以有百回遠忌(第 99 年)、百五十回遠忌(第 149 年),但通常到此為止了。

《日語自遊行の最和味》第二課 梅雨季節結束

對話

今日 は いい お天気 ですね。
そろそろ 梅雨明け ですが。
ええ、そろそろ ですね。
今、日本中、梅雨 です が。
ええ、梅雨明けの時期は 違いますが。
そうですが。
ああ、北海道 へ 行きたい です。
桜:今天天氣不錯喲。
健:梅雨季節該結束了吧?
桜:嗯,差不多了吧。
健:現在整個日本都是梅雨天氣嗎?
桜:是的,而且梅雨季節結束的時間(各地)也不同,除了北海道是沒有梅雨季節的。
健:這樣啊,好想去北海道。

附錄

  1. 日語自遊行の最和味
  2. 《日語自遊行の最和味》第二課 梅雨季節結束.pdf

MVP 架构下解决 RxJava 自动解绑问题

背景

MVP 模式下使用 RxJava 处理网络访问的回调,当数据返回时 Presenter 调用绑定的 View 的方法。

定义 BasePresenter 如下:

public class BasePresenter<T extends MvpView> implements Presenter<T> {

  private T mMvpView;

  @Override
  public void attachView(T mvpView) {
    mMvpView = mvpView;
  }

  @Override
  public void detachView() {
    mMvpView = null;
  }

  public boolean isViewAttached() {
    return mMvpView != null;
  }

  public T getMvpView() {
    return mMvpView;
  }
}

定义 MvpView 如下:

public interface MvpView {
}

举一个具体的实现,有记录页为 RecordActivity,定义如下:

public class RecordRecordActivity extends BaseActivity
    implements RecordMvpView {
      @Inject
  	  RecordPresenter presenter;
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          //...
          presenter.attachView(this);
          //...
          onRefresh();
      }
      
      public void onRefresh(){
          presenter.queryReocrd();
	  }
      
      @Override
      protected void onDestroy() {
        presenter.detachView();
        super.onDestroy();
      }
        @Override
      public void showRecord(List<RecordResponse> data) {
        //...
      }
}

RecordMvpView 定义如下:

public interface RecordMvpView extends MvpView {
	void showRecord(List<RecordResponse> data);
}

RecordPresenter 的定义如下:

public class RecordPresenter extends BasePresenter<RecordMvpView> {

  private DataManager dataManager;
  private Disposable disposable;

  @Inject
  public RecordPresenter(DataManager dataManager) {
    this.dataManager = dataManager;
  }

  public void queryRecord(int page, int count) {
    RxUtil.dispose(disposable);
    dataManager.queryRecord(page, count)
               .subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread())
               .subscribe(new SingleObserver<List<RecordResponse>>() {
                 @Override
                 public void onSubscribe(Disposable d) {
                   disposable = d;
                 }

                 @Override
                 public void onSuccess(List<RecordResponse> resp) {
                   getMvpView().showRecord(resp);
                 }

                 @Override
                 public void onError(Throwable e) {
                   Timber.e(e);
                   getMvpView().showRecord(null);
                 }
               });
  }
}

以上实现具有一个重大问题,当 Activity 处于 destroy 状态时调用 onRefresh 方法去加载数据,会导致 Presenter 中处理数据返回后调用 getMvpView 方法返回 null,从而导致 NPE。抑或,在 create 状态请求的数据在未返回前 Activity 就进入了 destroy 状态从而导致 NPE。

解决方案

(1)最简单的也是最复杂的解决方案

在调用 getMvpView 前进行判空,即:

if(isViewAttached()){
  getMvpView().showRecord(resp);
}

是不是很简单?是的,看起来简单,其实是最复杂的,应该它需要在每个回调的地方小心翼翼地包上这层判断,工作量大还容易出错,代码也不好看。更关键的是,它到底是执行了,并没有在 View 销毁后立即停止订阅

(2)使用第三方库 RxLifecycle 或 AutoDispose

这两个都是较出名的用于解决 RxJava 与Android 生命周期问题的第三方库。可以自行 Github 一下。

RxLifecycle

This library allows one to automatically complete sequences based on a second lifecycle stream.

This capability is useful in Android, where incomplete subscriptions can cause memory leaks.

该库允许在接收到第二个生命周期流时自动结束订阅。

此种能力对于解决因未完成的订阅导致的Android 内存泄漏问题很有用。

RxLifecycle 的局限性:

  1. 需要继承自 RxActivity 或 RxFragment 等;

  2. 其核心步骤需要 RxActivity 或 RxFragment 的引用。

    .compose(this.<T>bindUntilEvent(ActivityEvent.PAUSE))

AutoDispose

AutoDispose is an RxJava 2 tool for automatically binding the execution of RxJava 2 streams to a provided scope via disposal/cancellation.

AutoDispose 是 RxJava2 中的一款工具,能通过解绑或取消操作,使得 RxJava2 流执行到在给定的域中为止。

其受 RxLifecycle 启发。

优势:

  1. 将生命周期相关的从 Activity 或 Fragment 中分离出来,独立成 LifecycleOwner,可扩展。

(3)结合项目情况自定义解决方案

RxLifecycle 的原理是:

  1. BehaviorSubject 在订阅后会发送前一个数据值;
  2. ObservableTransformer、SingleTransformer 等等可以对整个流进行操作;
  3. takeUntil 操作符可以在第二个被观察者发送事件时自动停止订阅。

结合 MVP 架构和 RxLifecycle 的原理,我的解决方案是:

  1. 使用 BehaviorSubject 发送 View 的绑定情况;
  2. 在所有跟 View 相关的流中使用 compose 操作符,compose 一个自定义的 LifecycleTransformer 操作整个流,使用 takeUntil 操作符在观察到 BehaviorSubject 发送解绑消息后使用停止订阅。

具体代码实现如下:

BasePresenter 修改为:

public class BasePresenter<T extends MvpView> implements Presenter<T> {

  private T mMvpView;
  private CompositeDisposable compositeDisposable = new CompositeDisposable();
  private BehaviorSubject<Boolean> behaviorSubject = BehaviorSubject.createDefault(false);

  @Override
  public void attachView(T mvpView) {
    mMvpView = mvpView;
    behaviorSubject.subscribe();
    behaviorSubject.onNext(true); // TRUE 表示 View 绑定了
  }

  @Override
  public void detachView() {
    mMvpView = null;
    behaviorSubject.onNext(false); // FALSE 表示 View 解绑了
    compositeDisposable.clear();
  }

  public void addDisposable(Disposable... disposables) {
    for (Disposable d : disposables) {
      compositeDisposable.add(d);
    }
  }

  protected void deleteDispoable(Disposable disposable) {
    compositeDisposable.delete(disposable);
  }

  protected <R> LifecycleTransformer<R> bindLifeCycle() {
    return new LifecycleTransformer<>(behaviorSubject, this);
  }

  public boolean isViewAttached() {
    return mMvpView != null;
  }

  public T getMvpView() {
    return mMvpView;
  }
}

其中 LifecycleTransformer 定义为:

public final class LifecycleTransformer<T>
    implements ObservableTransformer<T, T>, SingleTransformer<T, T>, MaybeTransformer<T, T>, CompletableTransformer {
  private final Observable<Boolean> observable;
  private BasePresenter presenter;

  public LifecycleTransformer(Observable<Boolean> observable, BasePresenter presenter) {
    this.observable = observable;
    this.presenter = presenter;
  }

  @Override
  public ObservableSource<T> apply(Observable<T> upstream) {
    return upstream.takeUntil(getFilterFalseObservable()) //当收到 View 解绑消息时自动解除订阅
                   .subscribeOn(Schedulers.io())
                   .observeOn(AndroidSchedulers.mainThread())
                   .doOnSubscribe(disposable -> {
                     if (!presenter.isViewAttached()) { // 当订阅时,若 View 解绑则自动解除订阅
                       Timber.v("dispose");
                       disposable.dispose();
                       return;
                     }
                     presenter.addDisposable(disposable);
                   });
  }

  @Override
  public SingleSource<T> apply(Single<T> upstream) {
    return upstream.takeUntil(getFilterFalseObservable().firstOrError())
                   .subscribeOn(Schedulers.io())
                   .observeOn(AndroidSchedulers.mainThread())
                   .doOnSubscribe(disposable -> {
                     if (!presenter.isViewAttached()) {
                       Timber.v("dispose");
                       disposable.dispose();
                       return;
                     }
                     presenter.addDisposable(disposable);
                   });

  }

  @Override
  public CompletableSource apply(Completable upstream) {
    return Completable.ambArray(upstream,
                                getFilterFalseObservable().flatMapCompletable(CANCEL_COMPLETABLE))
                      .subscribeOn(Schedulers.io())
                      .observeOn(AndroidSchedulers.mainThread())
                      .doOnSubscribe(disposable -> {
                        if (!presenter.isViewAttached()) {
                          Timber.v("dispose");
                          disposable.dispose();
                          return;
                        }
                        presenter.addDisposable(disposable);
                      });
  }

  @Override
  public MaybeSource<T> apply(Maybe<T> upstream) {
    return upstream.takeUntil(getFilterFalseObservable().firstElement())
                   .subscribeOn(Schedulers.io())
                   .observeOn(AndroidSchedulers.mainThread())
                   .doOnSubscribe(disposable -> {
                     if (!presenter.isViewAttached()) {
                       Timber.v("dispose");
                       disposable.dispose();
                       return;
                     }
                     presenter.addDisposable(disposable);
                   });

  }

  private Observable<Boolean> getFilterFalseObservable() {
    return observable.filter(aBoolean -> !aBoolean);
  }

  private static final Function<Object, Completable> CANCEL_COMPLETABLE =
      ignore -> Completable.error(new CancellationException());

}

这样原先的 RecordPresenter 就可以修改为:

public class RecordPresenter extends BasePresenter<RecordMvpView> {

  private DataManager dataManager;

  @Inject
  public RecordPresenter(DataManager dataManager) {
    this.dataManager = dataManager;
  }

  public void queryRecord(int page, int count) {
    dataManager.queryRecord(page, count)
               .compose(bindLifeCycle()) // 关键代码
               .subscribe(new LifecycleSingleObserver<List<RecordResponse>>() {
                 @Override
                 public void onSuccess(List<RecordResponse> resp) {
                   Timber.i("onSuccess --------------");
                   getMvpView().showRecord(resp);
                 }

                 @Override
                 public void onError(Throwable e) {
                   Timber.i(e, "onError --------------");
                   getMvpView().showRecord(null);
                 }
               });
  }
}

其中 LifecycleSingleObserver 是为了简化 SingleObserver 引入的,定义如下:

public abstract class LifecycleSingleObserver<T> implements SingleObserver<T> {
  @Override
  public void onSubscribe(Disposable d) {
  }
}

至此,关于订阅的绑定及生命周期的问题已经在基类进行解决,具体使用时的代码大大简化(至少少了 5 行代码),只需加上一句 .compose(bindLifeCycle()) 即可。

Git 实战记录

提交当前分支的更改到远程的同名分支

$ git push origin HEAD

删除远程分支

$ git push origin :dev-sth
# 相当于
$ git push origin --delete dev-sth

撤销 git commit 但未 git push 的修改

#找到想要撤销的 commit id
$ git log
#撤销,但不对代码修改进行撤销,还可以再次 commit
$ git reset <commit id> 
#撤销并忽略该次 commit 的代码修改
$ git reset --hard <commit id>

伊呂波歌

いろは歌

朗讀 📣

漢字與假名 發音 漢譯
色は匂へど Iro wa nioedo (花的)颜色与芳香
散りぬるを Chirinuru o (最终)会消散,
我が世誰ぞ Wa ga yo dare zo 我们这个世上谁
常ならん Tsune naran 都不能常驻不变;
有為の奥山 Ui no okuyama 有为的深山
今日越えて Kyō koete 在今天越过,
浅き夢見じ Asaki yume miji 不做肤浅的梦,
酔ひもせず Yoi mo sezu 也不再沉醉。

參考

  1. 伊呂波歌
  2. 【日语阅读】一緒に読みましょう! 第14期 伊呂波歌

从序列化到 GSON 排错记录

写在前面

序列化、反序列化和持久化

序列化的目的在于对象中携带的数据之传输(进程间通信、客户端 - 服务器通信等),反序列化的目的在于将传输过来的数据重组成对象进行调用,持久化的目的在于将对象中携带的数据持久化保存在文件或数据库中,序列化和持久化的区别就在于此。

序列化的媒介有:对象输入输出流、JSON 字符串,以及 Android 独有的 Parcel。下面简述这几种方式。

第一种:对象输入输出流

// Dog
public class Dog implements java.io.Serializable{
   public String name;
}
// 序列化
FileOutputStream fos = new FileOutputStream("adog.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
Dog dog = new Dog();
dog.name = "aDog";
oos.writeObject(dog);
oos.close();

// 反序列化
FileInputStream fis = new FileInputStream("adog.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);
Dog dog = (Dog) ois.readObject();
ois.close();

第二种:JSON 字符串

以广为使用的 GSON 库为例,GSON 是一个很常用的序列化和反序列化对象的 JSON 库。其最简单的使用方式是:

// Cat
public class Cat {
   public String name;
}

Gson gson = new Gson();

// 序列化对象
Cat cat = new Cat();
cat.name = "aCat";
String catStr = gson.toJson(cat);

// 反序列化对象
Cat cat = gson.fromJson(catStr, Cat.Class);

第三种:Parcel

Android 中的 Parcel,官方的文档中表明是为了提高 IPC 效率而生的,不建议进行持久化,因为一旦类的成员变量发生改变,旧的数据将不再可读。Parcel 对象存在于一段多进程共享的内存中,没有进行文件的读写操作,高效是显而易见的。

// Hawk
import android.os.Parcel;
import android.os.Parcelable;

public class Hawk implements Parcelable {
  public String name;

  protected Hawk(Parcel in) {
    // 反序列化
    name = in.readString();
  }

  public static final Creator<Hawk> CREATOR = new Creator<Hawk>() {
    @Override
    public Hawk createFromParcel(Parcel in) {
      return new Hawk(in);
    }

    @Override
    public Hawk[] newArray(int size) {
      return new Hawk[size];
    }
  };

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    // 序列化
    dest.writeString(name);
  }
}

Github 上提供了一种方式将 Parcelable 对象字节化和反字节化,以便进行持久化,摘取如下:

public class ParcelableUtil {
    public static byte[] marshall(Parcelable parceable) {
        Parcel parcel = Parcel.obtain();
        parceable.writeToParcel(parcel, 0);
        byte[] bytes = parcel.marshall();
        parcel.recycle(); // not sure if needed or a good idea
        return bytes;
    }

    public static <T extends Parcelable> T unmarshall(byte[] bytes, Parcelable.Creator<T> creator) {
        Parcel parcel = unmarshall(bytes);
        return creator.createFromParcel(parcel);
    }

    public static Parcel unmarshall(byte[] bytes) {
        Parcel parcel = Parcel.obtain();
        parcel.unmarshall(bytes, 0, bytes.length);
        parcel.setDataPosition(0); // this is extremely important!
        return parcel;
    }
}

对象是千奇百怪的,导致我们序列化和反序列化的时候可能会出现一些不可思议的错误信息。下面就我遇到的一些情况为例,书写排错的血泪史。

1. AssertionError:Impossible

背景

在对某广告 SDK 的 Ad 对象进行序列化时出现该错误,瞬间惊呆了,序列化一个实现了简单的对象怎么不可能了?

关于字体的一些小知识

Atypl

ATypI 或 Association Typographique Internationale (国际排印协会)是一家致力于排版和类型设计的国际非营利组织。该协会的主要活动是每年秋季会议,每年在不同的全球城市举行。第62届年会于2018年9月11至15日在比利时安特卫普举办,主题为 “Type Legacies”(字体遗产)。

字体类型(数字化字体,Digital Font)

  • 点阵字体(Bitmap Font)通过点阵表现字形,其本质上只是一组图片。每一种字体变体都包括一组完整的字符,一个字符占一张图片。假设总字符数量为3,即包括三个字符,提供粗体和斜体的组合(即无、粗体、斜体、粗斜体四种变体),该字体总共有12张图片。
  • 轮廓字体(outline font),又称描边字体。这类字体使用贝兹曲线描述轮廓,可以通过简单的数学变形放大或缩小。但是很小的字体经常需要额外的信息(hints)指导笔画取舍进行润算,不然容易漆黑一团。
    • PostScript,由Adobe公司为专业数字排版开发。它使用PostScript,字形以3次贝兹曲线描述。
    • OpentType,是一种最初由苹果计算机公司开发的字体技术。
    • TrueType,为了实现Windows和Macintosh系统兼容,而产生的一种新字体格式。
  • 笔画字体(Stroke-based font),字形的轮廓由分离的笔画顶点和笔画外形(profile)定义。它优于轮廓字体之处在于:减少了定义字形的顶点数,允许同一组顶点生成不同的字体(不同的粗细,不同大小或不同衬线规则)所以节省大小。
    • METAFONT,美国计算机科学家高德纳(Donald Knuth)于1977年着手字体制作软件,并于1979年发布的第一个版本METAFONT。与TrueType类似,它是一种数学上的字体描述系统,只是描述字符使用圆点(circular pen)。这意味着由METAFONT产生的字形,没有锐利的点(sharp points),即笔尖大小是有限的。

带喇叭口的黑体

在设计横画起笔、收笔处向上下微微扩张,形成喇叭口的黑体。

--摘自 有喇叭口的黑一体_蓬间雀_新浪博客

这种装饰源于早些时候的铅字印刷的铅字,由于当时技术的限制,笔画的端口会收缩,为了解决这个问题,当时设计铅字的工作人员就把黑体设计成喇叭口的。

-- 摘自 黑体 -百度百科

Variable Font

2016 年 9 月在华沙召开的第 60 届 ATypI 年会上,Adobe, Apple, Google, Microsoft 4大巨头联合宣布了Variable Font 的字体规格- OpenType v1.8 。

字体分类(按 末端是否有修饰)

  • 衬线字体(Serif),衬线指的是字形笔画末端的装饰细节部分。
  • 无衬线字体(Sans-Serif),与衬线字体相反,完全抛弃装饰衬线,只剩下主干,造型简明有力,更具现代感,起源也很晚。适用于标题、广告,瞬间的识别性高。

字体分类(按字符宽度)

  • 等宽字体(Monospaced Font),指字符宽度相同的计算机字体。
  • 比例字体(Proportional Font),与等宽字体相反,字符宽度不尽相同的计算机字体。

参考

使用 RxJava 进行嵌套串行网络请求的一种方法

需求

有这样一个列表数据,它包含了商店+订单的信息,获取订单列表时,订单实体中会包含商店的 ID,而列表显示时需要商店的名称和 logo,这时候就需要进行嵌套串行网络请求了。

关键词

flatMap缓存RetrofitRxJava

动手

(1)使用 Retrofit 定义网络接口

// RemoteService.java
// 请求订单信息
@POST("/order/v1/order_history")
Single<List<OrderResponse>> queryOrderList(@Body FetchOrderHistoryRequest request);
// 请求商店信息
@POST("/store/v1/store_query")
Single<StoreResponse> queryStore(@Body StoreQueryRequest request);

(2)使用 DataManager 管理数据

// DataManager.java
// 请求订单信息
public Single<List<OrderResponse>> queryOrderList(String status) {
    FetchOrderHistoryRequest request = new FetchOrderHistoryRequest();
    request.setStatus(status);
    return mRemoteService.queryOrderList(request);
}

// 请求商店信息,并缓存 5min,如果不作缓存可能导致多次重复请求同一数据
public static final int DEFAULT_CACHE_TIME_MILLIS = 5 * 60 * 1000; // 5min

public Single<StoreResponse> queryStore(String storeId) {
    String storeKey = PrefConstant.getStoreKey(storeId);
    String storeJson = mMemberPref.getString(storeKey, null);
    Single<StoreResponse> storeSingle;
    if (!TextUtils.isEmpty(storeJson)) {
        storeSingle = Single.just(Json.fromJson(storeJson, StoreResponse.class));
    } else {
        StoreQueryRequest request = new StoreQueryRequest();
        request.setId(storeId);
        storeSingle = mRemoteService.queryStore(request)
            .doOnSuccess(storeResponse -> mMemberPref.put(storeKey,
                                                          Json.toJson(
                                                              storeResponse),
                                                          DEFAULT_CACHE_TIME_MILLIS));
    }
    return storeSingle;
}

注:

  1. mMemberPref 是我写的一个使用 SharedPreferences 进行数据缓存的类,详情查看 Pref.java

(3)多次FlatMap

dataManager.queryOrderList(status)
           .flatMapObservable((Function<List<OrderResponse>, ObservableSource<OrderResponse>>) Observable::fromIterable)
           .flatMap((Function<OrderResponse, ObservableSource<OrderHolder>>) orderResponse -> {
             OrderHolder orderHolder = new OrderHolder();
             orderHolder.setOrder(orderResponse);
             return dataManager.queryStore(orderResponse.getStoreId())
                               .flatMapObservable((Function<StoreResponse, ObservableSource<OrderHolder>>) storeResponse -> {
                                 orderHolder.setStore(storeResponse);
                                 return Observable.just(orderHolder);
                               });
           })
           .toList()
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeOn(Schedulers.io())
           .subscribe(new SingleObserver<List<OrderHolder>>() {
             @Override
             public void onSubscribe(Disposable d) {
               disposable = d;
             }

             @Override
             public void onSuccess(List<OrderHolder> orderHolders) {
               if (orderHolders != null && !orderHolders.isEmpty()) {
                 getMvpView().showOrderList(orderHolders);
               } else {
                 getMvpView().showEmpty();
               }
             }

             @Override
             public void onError(Throwable e) {
               Timber.e(e);
               getMvpView().showError();
             }
           });
  }

说明:

  1. 第一次 flatMapObservable ,将 List<OrderResponse> 转为 ObservableSource<OrderResponse>
  2. 第二次 flatMap,将 OrderResponse 转为 ObservableSource<OrderHolder>
  3. 第三次 flatMapObservable ,将 StoreResponse 合并到 OrderHolder,再转为ObservableSource<OrderHolder>

S3 Select 实践 — 确定用户国家地区

背景

后台基本使用 Amazon 的全家桶(EC2、DynamoDB、S3、Step Fuction 等等)构建。现在需要根据访问者的 IP 确定访问者的国家或地区。

已知:

  1. 访问者 IP

  2. 一个 ipdata.csv 文件,已放置在 S3 的桶 ow-public-us 中,格式如下

    ip_from ip_to country_code country_name
    0 16777215 - -
    16777216 16777471 AU Australia
    16777472 16778239 CN China

流程

1. 引入 S3 Select

compile "com.amazonaws:aws-java-sdk-s3:1.11.379"

2. 构建 AmazonS3 对象

public AmazonS3 createAmazonS3(){
    final AwsSupport awsSupport = new AwsSupport();
    ClientConfiguration clientConfiguration = new ClientConfiguration();
    clientConfiguration.setSocketTimeout((int) TimeUnit.SECONDS.toMillis(70));
    AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard()
                                                            .withCredentials(awsSupport.getCredentials())
                                                            .withClientConfiguration(
                                                                clientConfiguration);
    // ). region
    final Region region = awsSupport.getCurrentRegion();
    if (region != null) {
        builder.withRegion(region.getName());
    }
    return builder.build();
}

3. 构建 SelectObjectContentRequest 对象

本文中输入的为 CSV 无压缩数据,输出为 Json 类型数据。

public static SelectObjectContentRequest createBaseCSVRequest(String bucket,
                                                                String key,
                                                                String query) {
    SelectObjectContentRequest request = new SelectObjectContentRequest();
    request.setBucketName(bucket);
    request.setKey(key);
    request.setExpression(query);
    request.setExpressionType(ExpressionType.SQL);

    InputSerialization inputSerialization = new InputSerialization();
    inputSerialization.setCsv(new CSVInput());
    inputSerialization.setCompressionType(CompressionType.NONE);
    request.setInputSerialization(inputSerialization);

    OutputSerialization outputSerialization = new OutputSerialization();
    outputSerialization.setJson(new JSONOutput());
    request.setOutputSerialization(outputSerialization);
    return request;
}

4. 转化 IP 为 IP LONG

将 IP 字符串 转为 long 型数值,方便进行 IP 国家地区定位。

public static long ip2Long(String ipAddress) {
    if (Strings.isNullOrEmpty(ipAddress)) {
        return 0L;
    }
    long result = 0;
    String[] ipAddressInArray = ipAddress.split("\\.");

    for (int i = 3; i >= 0; i--) {
        long ip = Long.parseLong(ipAddressInArray[3 - i]);
        // left shifting 24,16,8,0 and bitwise OR
        // 1. 192 << 24
        // 1. 168 << 16
        // 1. 1 << 8
        // 1. 2 << 0
        result |= ip << (i * 8);
    }
    return result;
}

5. 请求并获取国家地区信息

// _1 代表第一列 ip_from
// _2 代表第二列 ip_to
// _3 代表第三列 country_code
// 注意: SQL 中的变量需要用单引号括起来
SelectObjectContentResult selectObjectContentResult =
    createAmazonS3().selectObjectContent(createBaseCSVRequest("ow-public-us",
                                                                    "ipdata.csv",
                                                                    "SELECT s.\'country_code\' FROM S3Object s WHERE s._1<=\'" +
                                                                    ipLong +
                                                                    "\' AND s._2>=\'" +
                                                                    ipLong + "\' LIMIT 1"));
selectObjectContentResult.getPayload()
                            .getRecordsInputStream(new SelectObjectContentEventVisitor() {
                            @Override
                            public void visit(SelectObjectContentEvent.RecordsEvent event) {
                                try {
                                String content =
                                    new String(event.getPayload().array(), "utf-8");
                                LOGGER.debug("Country is --> {}", content);
                                JsonObject object = Json.fromJson(content, JsonObject.class);
                                String country = object.get("_3").getAsString();
                                } catch (UnsupportedEncodingException e) {
                                e.printStackTrace();
                                }
                            }
                            });

预警

在编辑 S3 Select 的 SQL 语句时,使用下列形式是不支持的:

// 出错:AmazonS3Exception: The column index at line 1, column 8 is invalid. Please check the service documentation and try again. (Service: Amazon S3; Status Code: 400; Error Code: InvalidColumnIndex;
String sql = "SELECT s.\"country_code\" FROM S3Object s WHERE s._1<=\'" + ipLong +"\' AND s._2>=\'" + ipLong + "\' LIMIT 1";

// 出错:AmazonS3Exception: Invalid Path component, expecting either an IDENTIFIER or STAR, got: LITERAL,at line 1, column 10. (Service: Amazon S3; Status Code: 400; Error Code: ParseInvalidPathComponent;
String sql = "SELECT s.\'country_code\' FROM S3Object s WHERE s._1<=\'" + ipLong +"\' AND s._2>=\'" + ipLong + "\' LIMIT 1";

// 出错:AmazonS3Exception: The column index at line 1, column 8 is invalid. Please check the service documentation and try again. (Service: Amazon S3; Status Code: 400; Error Code: InvalidColumnIndex;
String sql = "SELECT s.country_code FROM S3Object s WHERE s._1<=\'" + ipLong +"\' AND s._2>=\'" + ipLong + "\' LIMIT 1";

但是第一种写法在 Python 库 boto3 中是支持的,可以参见 参考2

参考

  1. 使用 适用于 Java 的开发工具包 从对象中选择内容 - Amazon
  2. S3 Select — new revolution “at rest” - Medium

《古代漢語》上一·文選

本文選自《左傳》,《左傳》是一部編年體+經傳體,以魯國歷代君王為時間線,記錄當時的人和事。有觀點認為《左傳》是以《春秋》為藍本的,也有人不以為然。

一、鄭伯克段于鄢

概述

鄭伯莊公和共叔段,一兄一弟,其母姜氏偏愛共叔段。及莊公立,莊公放任姜氏和共叔段在京這個地方高筑墻并侵吞邊境地區,等到預謀與姜氏裡應外合襲擊鄭時才發兵攻打共叔段,將其趕出了京、鄢地區,將姜氏軟禁于穎,發誓永不相見。後後悔,經潁考叔出謀,闕地及泉,使母子如初。

原文

初,鄭武公娶于申,曰武姜,生莊公及共叔段。莊公寤生,驚姜氏,故名曰「寤生」,遂惡之。愛共叔段,欲立之。亟請于武公,公弗許。及莊公即位,為之請制。公曰:「制,巖邑也,虢叔死焉,佗邑唯命。」請京,使居之,謂之京城大叔。祭仲曰:「都城過百雉,國之害也。先王之制,大都不過參國之一,中五之一,小九之一。今京不度,非制也,君將不堪。」公曰:「姜氏欲之,焉辟害?」對曰:「姜氏何厭之有?不如早為之所,無使滋蔓!蔓,難圖也。蔓草猶不可除,況君之寵弟乎?」公曰:「多行不義,必自斃,子姑待之。」

寤
--> 《註》遌生也。遌,逆也。杜預曰:寤寐而莊公生。《風俗通》凡兒墮地,能開目視者,謂之寤生。
亟 
-->jí《說文》从人从口从又从二。二,天地也。《徐鍇曰》承天之時,因地之利,口謀之,手執之,時不可失,疾之意也。
-->qì 屡次。
雉
--> 《註》方丈曰堵,三堵曰雉。一雉之牆,長三丈,高一丈。
--> 《維基百科》周 1丈=10尺, 1尺=10寸, 1寸=10分(前期:1尺=19.7厘米;後期:1尺=24.63厘米)

既而大叔命西鄙、北鄙貳於己。公子呂曰:「國不堪貳,君將若之何?欲與大叔,臣請事之;若弗與,則請除之。無生民心。」公曰:「無庸,將自及。」大叔又收貳以為己邑,至于廩延。子封曰:「可矣,厚將得眾。」公曰:「不義不暱,厚將崩。」大叔完聚,繕甲兵,具卒乘,將襲鄭,夫人將啟之。公聞其期,曰:「可矣!」命子封帥車二百乘以伐京。京叛大叔段,段入于鄢,公伐諸鄢。五月辛丑,大叔出奔共。

鄙
--> bǐ《註》鄙,鄭邊邑。
貳
--> 《註》貳,兩屬也。
暱
--> nì《說文》日近也。《類篇》親也。《傳》暱,近也。

書曰:「鄭伯克段于鄢。」段不弟,故不言弟;如二君,故曰克;稱鄭伯,譏失教也:謂之鄭志。不言出奔,難之也。

遂寘姜氏于城穎,而誓之曰:「不及黃泉,無相見也。」既而悔之。

寘
--> zhì《說文》置也。

潁考叔為潁谷封人,聞之,有獻於公,公賜之食,食舍肉。公問之,對曰:「小人有母,皆嘗小人之食矣,未嘗君之羹,請以遺之。」公曰:「爾有母遺,繄我獨無!」潁考叔曰:「敢問何謂也?」公語之故,且告之悔。對曰:「君何患焉?若闕地及泉,隧而相見,其誰曰不然?」公從之。公入而賦:「大隧之中,其樂也融融!」姜出而賦:「大隧之外,其樂也洩洩!」遂為母子如初。

遺
--> wèi《康熙字典》投贈也,餽也。
繄
--> yī《註》繄,語助辭。
闕
--> jué《註》闕,穿也。
--> què《說文》門觀也。《廣韻》闕在門兩旁,**闕然爲道也。《正韻》宮門雙闕也。《韻會》爲二臺于門外,作樓觀於上,上員下方,以其縣法謂之象魏。象,治象也。魏者,言其狀魏魏然高大也,使民觀之,因爲之觀,兩觀雙植,中不爲門。又宮門、寢門、冢門皆曰闕。《古今注》闕,觀也。古每門樹兩觀於其前,所以標表宮門也。其上可居,登之則可遠觀,故謂之觀。人臣將至此,則思其所闕,故謂之闕。

君子曰:「潁考叔,純孝也,愛其母,施及莊公。《詩》曰『孝子不匱,永錫爾類。』其是之謂乎!」

施
--> yì《箋》施,猶易也,延也。

二、齊桓公伐楚

概述

四年春,王正月。公會齊侯、宋公、陳侯、衛侯、鄭伯、許男、曹伯侵蔡。蔡潰,遂伐楚,次于陘。

夏。許男新臣卒。楚屈完來盟于師,盟于召陵。齊人執陳轅濤塗。

原文

四年春。齊侯以諸侯之師侵蔡。蔡潰,遂伐楚。楚子使與師言曰:「君處北海,寡人處南海,唯是風馬牛不相及也。不虞君之涉吾地也,何故?」管仲對曰:「昔召康公命我先君大公曰:『五侯九伯,女實征之,以夾輔周室。』賜我先君履,東至于海,西至於河,南至於穆陵,北至於無棣。爾貢包茅不入,王祭不共,無以縮酒,寡人是徵。昭王南征而不復,寡人是問。」對曰:「貢之不入,寡君之罪也,敢不共給。昭王之不復,君其問諸水濱。」師進,次於陘。

風
--> 賈逵云:風,放也。牝牡相誘謂之風。然則馬牛風佚,因牝牡相逐而遂至放佚遠去也。
虞
--> yú 度也。
履
--> 《註》謂所踐履之界也。
共
--> 《說文》周禮、尚書供給供奉字皆借共字爲之。
包茅
--> 成束捆綁的菁茅草。古代祭祀時,用來濾酒去滓,為春秋時楚國的貢物。
徵
--> 問也。

夏。楚子使屈完如師。師退,次於召陵。齊侯陳諸侯之師,與屈完乘而觀之。齊侯曰:「豈不穀是為?先君之好是繼,與不穀同好如何?」對曰:「君惠徼福於敝邑之社稷,辱收寡君,寡君之願也。」齊侯曰:「以此眾戰,誰能禦之?以此攻城,何城不克?」對曰:「君若以德綏諸侯,誰敢不服?君若以力,楚國方城以為城,漢水以為池。雖眾,無所用之。」屈完及諸侯盟。

不穀
-->《爾雅·釋詁》穀,善也。《禮·曲禮》自稱曰不穀。《註》謙稱。
徼
--> jiǎo《玉篇》要也,求也。
社稷
--> 本指土神和穀神。後指國家。
綏
--> suí《說文》車中把也。《註》徐鍇曰:禮升車必正立執綏,所以安也。

三、宮之奇諫假道

概述

晉侯想要再次借道虞國攻打虢國,宮之奇上諫奏明虞虢脣齒相依的利害關係,虞公不聽,答應了晉國的要求,宮之奇帶領族人遠走他鄉。後,晉滅虢并襲擊了虞國。

原文

晉侯復假道於虞以伐虢,宮之奇諫曰:「虢,虞之表也。虢亡,虞必從之。晉不可啟,寇不可翫。一之謂甚,其可再乎?諺所謂『輔車相依,脣亡齒寒』者,其虞虢之謂也!」公曰:「晉,吾宗也。豈害我哉?」對曰:「大伯、虞仲,大王之昭也。大伯不從,是以不嗣。虢仲、虢叔,王季之穆也,為文王卿士,勳在王室,藏於盟府。將虢是滅,何愛於虞?且虞能親於桓莊乎?其愛之也,桓莊之族何罪,而以為戮,不唯偪乎?親以寵偪,猶尚害之,況以國乎?」公曰:「吾享祀豐絜,神必據我。」對曰:「臣聞之,鬼神非人實親,惟德是依。故《周書》曰:『皇天無親,惟德是輔。』又曰:『黍稷非馨,明德惟馨。』又曰:『民不易物,惟德緊物。』如是,則非德,民不和,神不享矣。神所馮依,將在德矣。若晉取虞,而明德以薦馨香,神其吐之乎?」弗聽,許晉使。宮之奇以其族行,曰:「虞不臘矣,在此行也,晉不更舉矣。」

表
--> 外也。
啟
--> 《說文》開也。
翫
--> wán 轻慢;轻视。
昭穆
--> 宗廟的輩次排列。古代宗廟制度,天子七廟,諸侯五廟,大夫三廟。以天子而言,太祖廟居中;二、四、六世居左,稱為「昭」;三、五、七世居右,稱為「穆」。
桓莊
--> 桓叔與莊伯,這裡指桓莊之族。莊伯是桓叔之子,桓叔是獻公的曾祖,莊伯是獻公的祖父。晉獻公曾盡殺桓叔、莊伯的後代。
偪
-->《集韻》與逼同。 
絜
--> 同潔,乾淨。
薦
--> jiàn《韻會》進也。《穀梁傳註》無牲而祭曰薦。
臘
--> 《註》此周禮所謂蜡祭也。
更
--> gèng 《增韻》再也。
舉
--> 起也。

冬,十二月,丙子朔。晉滅虢,虢公醜奔京師。師還,館于虞,遂襲虞,滅之。

京師
--> 國都。
館
--> 《說文》客舍也。這裏用如動詞,等於說住賓館。

四、燭之武退秦師

概述

晉秦大軍壓境,出兵的理由是:當時晉文公重耳流亡的時候鄭國對他無禮。鄭伯派出燭之武去函陵說服秦伯退兵,理由是:這是一場長途戰,對於秦國沒有任何好處,反而會擴張晉國的版圖,威脅秦國的安全;而且晉侯是一個不守信譽且貪得無厭的人,不能與謀。秦伯聽完大悅,與鄭國結盟,并退兵。晉侯聽聞秦國退兵后也退了。

原文

晉侯、秦伯圍鄭,以其無禮於晉,且貳於楚也。晉軍函陵,秦軍汜南。佚之狐言於鄭伯曰:「國危矣!若使燭之武見秦君,師必退。」公從之。辭曰:「臣之壯也,猶不如人。今老矣,無能為也已!」公曰:「吾不能早用子,今急而求子,是寡人之過也。然鄭亡,子亦有不利焉。」許之。夜縋而出,見秦伯,曰:「秦、晉圍鄭,鄭既知亡矣。若亡鄭而有益於君,敢以煩執事。越國以鄙遠,君知其難也,焉用亡鄭以倍鄰?鄰之厚,君之薄也。若舍鄭以為東道主,行李之往來,共其乏困,君亦無所害。且君嘗為晉君賜矣,許君焦、瑕,朝濟而夕設版焉,君之所知也。夫晉,何厭之有?既東封鄭,又欲肆其西封,若不闕秦,將焉取之?闕秦以利晉,唯君圖之。」秦伯說,與鄭人盟。使杞子、逢孫、楊孫戍之,乃還。子犯謂擊之,公曰:「不可。微夫人力不及此。因人之力而敝之,不仁。失其所與,不知。以亂易整,不武。吾其還也。」亦去之。

軍
--> 用如動詞,屯兵。
汜
--> fán,水名,指東氾,今已湮,故道在今河南中牟縣南。
縋
--> 《說文》以繩有所懸也。《註》縋,縣城而下。
舍
--> 捨棄,不取(不滅掉)
東道主
--> 東路上的主人,因鄭國在秦國東面,所以稱為「東道主」,後借以泛稱接待或宴請賓客的主人。
肆
--> 伸展。

五、蹇叔哭師

概述

僖公三十二年東,晉文公重耳去世。掌管卜筮的卜偃聽聞秦國密謀,借文公之口,散佈消息說:秦軍將要過境去攻打鄭國,攻打他必勝。同時,在燭之武退秦后戍守鄭國邊境的杞子托使者告訴秦伯:派兵過來,唾手可得。秦穆公問了下蹇叔的意見,蹇叔不同意興師動眾攻打大老遠的鄭國。秦穆公不樂意,執意出師。蹇叔哭送軍中的兒子,并預言晉軍會在殽進行防禦,讓兒子一定要死在北陵,好收骨頭。

原文

冬,晉文公卒。庚辰,將殯于曲沃,出絳,柩有聲如牛,卜偃使大夫拜曰,君命大事,將有西師過軼我,擊之必大捷焉。

殯
--> 停柩待葬。
絳
--> 晉國國都,在今山西翼城縣東南。
軼
--> 後車超過前車。

杞子自鄭使告于秦曰,鄭人使我掌其北門之管,若潛師以來,國可得也,穆公訪諸蹇叔。蹇叔曰,勞師以襲遠,非所聞也。師勞力竭,遠主備之,無乃不可乎,師之所為,鄭必知之,勤而無所,必有悖心,且行千里,其誰不知,公辭焉,召孟明,西乞,白乙,使出師於東門之外,蹇叔哭之曰,孟子,吾見師之出,而不見其入也,公使謂之曰,爾何知,中壽,爾墓之木拱矣。蹇叔之子與師。哭而送之曰,晉人禦師必於殽,殽有二陵焉,其南陵,夏后皋之墓也,其北陵,文王之所辟風雨也,必死是間,余收爾骨焉,秦師遂東。

潛
--> 隱藏在水面下,指偷偷行動。
中壽
--> 約指活到六七十歲。
拱
--> 兩手合抱。
殽
--> 通崤,山名,在今河南洛寧縣西北,地勢極險。
陵
--> 大山。淆有二山,稱為東陵西陵,相距三十五里。下文南陵即西陵,北陵即
東陵。
東
--> 用如動詞(名詞活用為動詞),向東進發。

六、晉靈公不君

概述

晉靈公不行君道,收老百姓大批賦稅大興土木,商議國事時卻在臺上玩彈弓,彈人。有一次宰夫熊掌沒烹熟,被靈公下令宰殺了,還讓一婦人載著他經過朝廷。趙盾和士季看到這種情況,先後多次進諫。晉靈公不但不知悔改,還想殺掉進諫的大臣。派殺手一大早地去刺殺趙盾,然殺手感于趙盾的恭敬,撞槐樹自殺了。晉靈公又在酒宴上想把趙盾灌醉,然後趁機消滅他,提彌明挺身而出,為趙盾犧牲了,趙盾逃了。不久,趙穿在桃園刺殺了靈公。

原文

晉靈公不君,厚斂以彫牆,從臺上彈人,而觀其辟丸也,宰夫胹熊蹯不熟,殺之,寘諸畚,使婦人載以過朝,趙盾,士季,見其手,問其故,而患之,將諫,士季曰,諫而不入,則莫之繼也,會請先,不入,則子繼之,三進及溜,而後視之,曰,吾知所過矣,將改之。稽首而對曰,人誰無過,過而能改,善莫大焉。《詩》曰:『靡不有初,鮮克有終』,夫如是,則能補過者鮮矣。君能有終,則社稷之固也,豈惟群臣賴之,又曰,袞職有闕,惟仲山甫補之,能補過也。君能補過,袞不廢矣。

彫
--> diāo 画也。——《广雅》
辟
--> 躲避。
胹
--> ér 疏:“过熟曰胹。”
蹯
--> fán《說文》作番,獸足也。
溜
--> liù《正義》溜,謂簷下水滴之處。
袞
--> gǔn 天子服也。

猶不改,宣子驟諫,公患之,使鉏麑賊之,晨往,寢門闢矣,盛服將朝,尚早,坐而假寐,麑退,歎而言曰,不忘恭敬,民之主也,賊民之主,不忠,棄君之命,不信,有一於此,不如死也,觸槐而死。

賊
--> 《註》賊,傷害也。《傳》殺人曰賊。
闢
--> 《說文》闢,開也。

秋,九月,晉侯飲趙盾酒,伏甲將攻之,其右提彌明知之,趨登曰,臣侍君宴,過三爵,非禮也,遂扶以下,公嗾夫獒焉,明搏而殺之,盾曰,棄人用犬,雖猛何為,鬥且出,提彌明死之。

飲
--> yìn 使...喝。
嗾
--> sǒu,喚狗的聲音,用如動詞,嗾使。

初,宣子田於首山,舍于翳桑,見靈輒餓,問其病,曰,不食三日矣,食之,舍其半,問之。曰:宦三年矣,未知母之存否。今近焉,請以遺之,使盡之,而為之簞食與肉,寘諸橐以與之,既而與為公介,倒戟以禦公徒,而免之,問何故,對曰,翳桑之餓人也。問其名居,不告而退,遂自亡也。

田
--> 同“畋”,打獵。
遺
--> wèi 給。
簞
--> dān 盛飯用的竹筐。
食
--> sì 飯。
橐
--> tuó 口袋。

乙丑,趙穿攻靈公於桃園。宣子未出山而復。大史書曰:趙盾弒其君,以示於朝。宣子曰:不然。對曰,子為正卿。亡不越竟,反不討賊,非子而誰。宣子曰:嗚呼,我之懷矣,自詒伊慼,其我之謂矣。

孔子曰:董狐,古之良史也。書法不隱,趙宣子,古之良大夫也,為法受惡,惜也,越竟乃免。

七、齊晉鞌之戰

背景

戰事因齊國而起,齊國首先**魯國的北部邊境,圍困了龍地,而寵臣盧蒲就魁攻城不入被龍地人俘虜,齊頃公提出條件跟魯國結盟并再不入侵,魯國不接受并殺了盧蒲就魁。齊頃公憤而親自擊鼓,三天內攻破了龍地,并繼續南侵到巢丘。這時衛國也派兵出征齊國,在新築潰敗,於是去晉國請救兵,然後就有下面的齊晉鞌之戰了。

原文

癸酉,師陳于鞌,邴夏御齊侯,逢丑父為右,晉解張御郤克,鄭丘緩為右,齊侯曰,余姑翦滅此而朝食,不介馬而馳之。郤克傷於矢。流血及屨,未絕鼓音。曰:余病矣。張侯曰:自始合,而矢貫余手及肘,余折以御,左輪朱殷,豈敢言病,吾子忍之。緩曰,自始合,苟有險,余必下推車,子豈識之,然子病矣,張侯曰,師之耳目,在吾旗鼓,進退從之,此車,一人殿之,可以集事,若之何其以病,敗君之大事也,擐甲執兵,固即死也,病未及死,吾子勉之,左并轡,右援桴而鼓,馬逸不能止,師從之。齊師敗績,逐之,三周華不注。

陳
--> 擺開陣勢。
御
--> 《說文》御,使馬也。
翦滅
--> 剪除消滅。
介
--> 象形。甲骨文字形,象人身上穿着铠甲形。中间是人,两边的四点象联在一起的铠甲片。本义:铠甲。這裡是用如動詞,表示給馬上甲。
病
-->《說文》疾加也。《玉篇》疾甚也。
殿
--> 《广雅》殿,后也。這裡用如動詞,表示殿后。
擐
--> huàn 穿
桴 
--> fú 鼓槌。
華不注
--> 華不注,山名,在今濟南東北。

韓厥夢子輿謂己曰,旦辟左右,故中御而從齊侯,邴夏曰,射其御者,君子也,公曰,謂之君子而射之,非禮也,射其左,越于車下,射其右,斃于車中,綦毋張喪車,從韓厥曰,請寓乘,從左右,皆肘之,使立於後,韓厥俛定其右。

子輿
--> 韓厥之父。
從
--> 追趕。
俛
--> 《註》師古曰:俛卽俯。

逢丑父與公易位,將及華泉,驂絓於木而止。丑父寢於轏中,蛇出於其下,以肱擊之,傷而匿之,故不能推車而及。韓厥執縶馬前,再拜稽首,奉觴加璧以進,曰,寡君使群臣為魯衛請,曰,無令輿師,陷入君地,下臣不幸,屬當戎行,無所逃隱,且懼奔辟,而忝兩君,臣辱戎士,敢告不敏,攝官承乏,丑父使公下如華泉取飲,鄭周父御佐車,宛茷為右,載齊侯以免,韓厥獻丑父,郤獻子將戮之,呼曰,自今無有代其君任患者,有一於此,將為戮乎,郤子曰,人不難以死免其君,我戮之不祥,赦之以勸事君者,乃免之。

驂
--> cān 《说文》骖,驾三马也。
絓
--> guà 同“掛”。《广雅》絓,悬也。
轏
--> zhàn 古代用竹木条做成的车。
縶
--> zhí 本義為系绊马足。這裡指拴住马足的绳索。
輿
--> 《广雅》舆,多也。這裡用如動詞,表示增加。

八、楚歸晉知罃

背景

宣公十二年(公元前 597 年)晉楚邲(地名,在今河南鄭州市東)之戰時,晉知罃被俘,晉卻擒獲了穀臣,射死了襄老,把屍首運回晉國。現在晉要用穀臣和襄老的屍體換回知罃。

概述

楚共王送歸知罃路上,詢問了知罃是埋怨他還是感激他。而知罃答之:我被抓是因為自己無才,王不把我在祭祀中作為犧牲已經待我很好了,我不埋怨;然而我也不感激您,因為這是國與國之間的交換,與我個人沒太大關係。如果一定要我報答的話,我會竭力致死盡忠于吾國來報答。楚共王意思到晉國人的忠,不可與爭,厚待并釋放了知罃。

原文

晉人歸楚公子穀臣,與連尹襄老之尸于楚,以求知罃,於是荀首佐中軍矣,故楚人許之,王送知罃,曰,子其怨我乎,對曰,二國治戎,臣不才,不勝其任,以為俘馘,執事不以釁鼓,使歸即戮,君之惠也,臣實不才,又誰敢怨,王曰,然則德我乎,對曰,二國圖其社稷,而求紓其民,各懲其忿,以相宥也,兩釋纍囚,以成其好,二國有好,臣不與及,其誰敢德,王曰,子歸何以報我,對曰,臣不任受怨,君亦不任受德,無怨無德,不知所報,王曰,雖然,必告不穀,對曰,以君之靈,纍臣得歸骨於晉,寡君之以為戮,死且不朽,若從君之惠而免之,以賜君之外臣首,首其請於寡君,而以戮於宗,亦死且不朽,若不獲命,而使嗣宗職,次及於事,而帥偏師以脩封疆,雖遇執事,其弗敢違,其竭力致死,無有二心,以盡臣禮,所以報也,王曰,晉未可與爭,重為之禮而歸之。

佐
--> 輔佐。
--> 本字為“左”,為方位詞,後金文在此基础上再加“工”(巧具、事工)另造“佐”,表示呼求神赐巧具,助事成功。(來自:象形字典)
馘
--> guó《註》軍法,獲而不服,則殺而獻其左耳。
釁
--> xìn 《說文》血祭也。象祭竈也。《廣韻》牲血塗器祭也。《禮·月令》孟冬之月,命大史釁龜筴。《疏》謂殺牲以血塗釁其龜及筴。
懲
--> 克制;制止。
宥
--> yòu《說文》寬也。
纍
--> léi《說文》一曰大索也。《廣韻》係也。亦作縲。《左傳·僖三十三年》不以纍臣釁鼓。《註》纍,囚繫也。
嗣
--> 《玉篇》嗣,續也,繼也。
偏師
--> 副帥副將所屬的軍隊,這裏是客氣的說法。
封
--> 《說文》爵諸侯之土也。从之从土从寸。《徐曰》各之其土也,寸守其法度也。本作封,隸作封,从圭所執也。

九、祁奚薦賢

概述

祁奚是晉國的中軍尉,向晉悼公告老還鄉。晉侯問繼承者,祁奚舉薦了他的死對頭解狐。不料解狐死了,就舉薦了自己的兒子祁午。這時候副中軍尉羊舌職死了,晉侯問繼承者,祁奚舉薦了羊舌職的兒子赤(字伯華)。祁奚同學無偏無黨的精神值得我們好好學習。

原文

祁奚請老,晉侯問嗣焉,稱解狐,其讎也,將立之而卒,又問焉。對曰,午也可。於是羊舌職死矣,晉侯曰,孰可以代之。對曰,赤也可,於是使祁午為中軍尉,羊舌赤佐之,君子謂祁奚於是能舉善矣。稱其讎,不為諂,立其子,不為比,舉其偏,不為黨。商書曰,無偏無黨,王道蕩蕩,其祁奚之謂矣,解狐得舉,祁午得位,伯華得官,建一官而三物成,能舉善也,夫唯善,故能舉其類,詩云,惟其有之,是以似之,祁奚有焉。

讎
--> chóu《玉篇》對也。又《韻會》仇也。
於是
--> 當這時候。
比
--> bì《康熙字典》又偏也,黨也。《論語》君子周而不比。

十、子產不毀鄉校

概述

鄭國的兩個大夫在鄉校遊覽,談論政事。然明建議把鄉校都拆了,子產不同意,說:老百姓在這談論政事,好的政策我就施行,不好的及時改正,就好比我的老師。況且我們應該行忠善來化解民怨,而不是作威作福來防止民怨。就像治水一樣,你一昧地堵,總有一天會潰堤釀成大災,還不如開個小口,疏導民怨。這就叫「防民之口,甚于防川」。

原文

鄭人游于鄉校,以論執政,然明謂子產曰,毀鄉校何如,子產曰,何為,夫人朝夕退而游焉,以議執政之善否,其所善者,吾則行之,其所惡者,吾則改之,是吾師也,若之何毀之,我聞忠善以損怨,不聞作威以防怨,豈不遽止,然猶防川,大決所犯,傷人必多,吾不克救也,不如小決,使道不如,吾聞而藥之也,然明曰,蔑也今而後知吾子之信可事也,小人實不才,若果行此,其鄭國實賴之,豈唯二三臣,仲尼聞是語也,曰,以是觀之,人謂子產不仁,吾不信也。

子產
--> 鄭大夫,名公孫僑(子產是字),春秋時有名的政治家。執政二十餘年,使處在晉楚雙重壓迫 之下的弱小鄭國獲得安定,並受到各國尊重。
鄉校
--> 鄉間的公共場所。既是學校,又是鄉人聚會議事的地方。
執政
--> 指掌握政權的人。
然明
--> 鄭大夫,姓鬷(zōng),名蔑,字然明。
遽
--> jù 《玉篇》急也,疾也,卒也。
決
--> 《康熙字典》又行流也。又開也。

讀懂漢字偏旁部首

一劃

gǔn 《說文》上下通也。
jué 《說文》鉤逆者謂之亅。
丿 piě 《說文》右戾也。象左引之形。《註》戾,曲也。
同“乙”。
《說文》惟初大始,道立於一。造分天地,化成萬物。《廣韻》數之始也,物之極也。
《說文》象春艸木冤曲而出,陰气尚彊,其出乙乙也。與丨同意。乙承甲,象人頸。
háo 同“毫”。《說文》玄鳥也。齊魯謂之乚。取其鳴自呼。象形。凡乚之屬皆从乚。鳦,乙或从鳥。《註》鳦,燕子。
zhǔ 《說文》有所絕止,丶而識之也。

二劃

《說文》別也。象分別相背之形。
bāo 《說文》裹也。象人曲形,有所包裹。
《說文》相與比敘也。从反人。匕,亦所以用比取飯,一名柶。《註》柶,古代舀取食物的礼器,像勺子,多用角做成。
bīng 古同“冰”。
《說文》灼剝龜也。象炙龜之形。一曰象龜兆之縱橫也。一說是樹杈或神杖。
hàn 《說文》山石之厓巖,人可居。
dāo 《說文》兵也。
dāo 同“刀”。
ér 同“兒”。《說文》从儿,象小兒頭囟未合。
èr 《說文》地之數也。
fāng 《說文》受物之器。
同“阜”,《說文》山無石者。《釋名》土山曰阜,言高厚也。
同“八”
《說文》踞几也。《註》古人坐而凭几。
jié 《說文》瑞信也。守國者用玉卪,守都鄙者用角卪...
jiōng 《說文》邑外謂之郊,郊外謂之野,野外謂之林,林外謂之冂。象遠界也。
《說文》筋也。象人筋之形。
《說文》覆也。从一下垂也。《註》今俗作冪。
qiǎn 《說文》張口也。
rén 《說文》天地之性最貴者也。此籒文。象臂脛之形。
rén 同“人”
《說文》内也。象从上俱下也。《註》上下者、外中之象。
shí 《說文》數之具也。一爲東西,丨爲南北,則四方**備矣。
《說文》姦衺也。韓非曰:“蒼頡作字,自營爲厶。”《象形字典—夜遊人》私:先有厶,也是私有的意思,这个字很直接形象,像人的臂弯,向自己怀中搂,那点像手里拿的东西,也就是把别人的东西拿到手并向自己的怀里搂据为已有。后来加“禾”,是将人们活命的稻谷搂在怀里据为已有。
tóu 《字彙》徒鉤切,音頭。義闕。
《說文》衺徯,有所俠藏也。
yán 同“言”。《說文》直言曰言,論難曰語。
yǐn 《說文》長行也。
yòu 《說文註》手也。象形。此卽今之右字。

日語五十音考

歷史

  • 公元 5 世紀,正值中國東晉時期(317~420),日本古墳時代(300~600),僧侶們東渡日本,漢字傳播到了日本。
  • 公元 8 世紀,正值中國唐朝(618~907),《萬葉集》依據漢字草書,造出萬葉假名,表漢字之音,為女性所用。明治時代,日本政府根據萬葉假名確定出現今使用的平假名。
  • 平安時代(794~1185)初,也就是公元 8 世紀末,為了訓讀漢字,發明了片假名。初始時,一音可以對應多個片假名。到明治時代,日本政府確定了一音一片的對應規則。

「訓讀」與「音讀」

  • 「訓讀」:借用漢字的形意,而用日本原有語音。如:秋(あき)

  • 「音讀」:模仿漢字之音。如:新年 (しんねん )

結論:

  • 當時傳入日本的是中古漢語(魏晋南北朝、隋、唐、宋),音韻體系跟如今的普通話、閩南語、吳語、粵語、客家話都有差別。中古漢語的音韻可以通過研究《切韻》和《廣韻》略知一二。
  • 平假名先於片假名。平假名的研究重點在於表音;片假名的研究重點在於表意。

選用同一漢字作為參照的平假名和片假名

序號 平假名 片假名 漢字
1
2 オ(疑是對平假名的簡化)
3
4 幾(一說為機)
5
6
7
8
9 曾(或其異體字「曽」)
10
11
12
13
14
15
16 祢(mí)
17
18
19
20 ヘ(就是平假名)
21
22
23
24
25
26
27
28
29
30 り(疑是從片假名來)
31
32
33 ヮ(疑是對平假名的簡化)

結論:

  • 現代日語有 45 音,其中 33 音的平假名和片假名來自同一漢字,佔比 73.33%。
  • 七成以上片假名來自對原有平假名來源的漢字的楷書結構的抽取。

發音近似閩南語的平假名

序號 平假名 羅馬拼音 漢字 閩南語羅馬拼音
1 a an
2 i í
3 u ú
4 ka ka
5 ki
6 ku
7 ke
8 se
9 bi
10 bo
11 mi
12 mo moo
13 ya
14 yu
15 ri

結論:

  • 現代日語有 45 音,其中有 15 音近似閩南語發音,佔比 1/3。
  • 傳入日本的漢語為中古漢語,而現代日語中仍保留了大量中古發音,且與現代閩南語有 1/3 近似的事實,說明了現代閩南語較好地保留了許多中古漢語的發音。

附錄

  1. 平假名-草書漢字對應表

    平假名-草書漢字對應表

  2. 片假名-楷書漢字對應表

    片假名-楷書漢字對應表

閩南語俚語小記

序號 俚語 拼音 含義
1 爱 媠 毋惊 流 鼻水 Ài-suí m̄ kiann lâu phīnn-tsuí. (女孩子)爱漂亮、就算天冷也不怕穿得少。
2 嚴官府出厚賊;嚴爸母出阿里不達 Giâm kuann-hú tshut kāu tsha̍t; giâm pē-bú tshut a-lí-put-ta̍t. 嚴格的官府反而出現很多小偷;父母太嚴格,小孩越是不成材。「阿里不達」源自被谭崔密教仿冒為男女雜交的普贤王如来(Adi-Buddha)。
3 一人煩惱一樣,無人煩惱親像 Tsi̍t lâng huân-ló tsi̍t iūnn, bô-lâng huân-ló tshin-tshiūnn. 意謂家家有本難唸的經。
4 一代親,二代表,三代毋捌了了 It tāi tshin, jī tāi piáu, sann tāi m̄ bat liáu-liáu. 姻親間的往來,一代比一代疏遠。
5 六月芥菜假有心 La̍k-gue̍h kuà-tshài ké ū sim. 形容人擅於表面功夫,裝出一副古熱心腸的樣子。
6 刣雞教猴 Thâi ke kà kâu. 罰小儆大。
7 會生得囝身,袂生得囝心 Ē senn tit kiánn sin, bē senn tit kiánn sim. 用來說明,雖然兒女是父母所生,但也有自己的意志,父母不能左右的。
8 翁親某親,老婆仔拋捙輪 Ang tshin bóo tshin, lāu-pô-á pha-tshia-lin. 夫妻二人置年邁雙親於不顧之意。
9 耳仔生兩葉,家己看袂著。 Hīnn-á senn nn̄g hio̍h, ka-kī khuànn bē tio̍h. 耳朵有兩片,自己看不見。比喻人看不到自己的缺點。
10 食雞,會起家;食鰇魚,生囡仔好育飼。 Tsia̍h ke, ē khí-ke; tsia̍h jiû-hî, senn gín-á hó io-tshī. 吃雞,會起家,吃魷魚,生孩子好養。借諧音的吉祥話,說出心中的願望。
11 飼鳥鼠,咬布袋。 Tshī niáu-tshí, kā pòo-tē. 養老鼠,咬布袋。比喻養虎為患。
12 豬頭皮炸無油。 Ti-thâu-phuê tsuànn bô iû. 揶揄人少吹牛了。

參考:

一念廢立,貴在自律

我惶恐,一方面是出於內心的空虛,另一方面是出於經濟的匱乏。

經濟的匱乏可以通過辛勤工作獲得,而內心空虛就沒那麼簡單了。一個重要原因是單身如此之久,缺乏靈魂伴侶,但更遺憾的是,一直以來盤在心中的文化缺失感。文化缺失得學,而語言文字是文化的重要載體,自然得從語言文字入手。漢語言文字、英語、日語都學,都難以堅持,熱度一般不超過兩周。可惡!

行路是如此艱難,一方面要堅持幾無正向反饋的學習,一方面還要擺脫一些浪費時間的沉迷。現在,要廢掉自己從未如此簡單,遊戲隨手可玩,美劇隨時可看,資訊如此繁多瑣碎,AV(Adult Video)也充盈網路,足以讓我在其中沉迷忘返。一念懶惰,堅持了一兩周的學習就又廢了,文化的缺失沒能得到有效的解決,舊的慣性迴路卻又開始了。該如何去舊迎新,有效解決內心的文化空虛呢?

  1. 自律,長久的堅持少不了自律的精神和行為;
  2. 打破舊的迴路后要建立持久的正向反饋迴路才行,不然舊的迴路又陰魂不散、死而復生;
  3. 要有全盤的計劃和詳細到每一天的安排;
  4. 要每天自我檢查完成情況,及時調整安排。

準備好了嗎?前方的荊棘路在等著你,這次可得握好砍刀(自律),看好指南針(計劃),為每一次小勝自我鼓舞(正向反饋),不斷回頭看看自己走了多遠以及前方還有多遠(自我檢查),從而堅持到最後,否則又得衣衫襤褸灰頭土臉地原路返回了。

解决 Android 中出现依赖多个版本支持库的问题

在 app 的 build.gradle 中引入依赖时发现如下错误:

All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 27.1.1, 26.1.0. Examples include com.android.support:animated-vector-drawable:27.1.1 and com.android.support:support-media-compat:26.1.0 less... (⌘F1) 
There are some combinations of libraries, or tools and libraries, that are incompatible, or can lead to bugs. One such incompatibility is compiling with a version of the Android support libraries that is not the latest version (or in particular, a version lower than your targetSdkVersion).

简单的说就是引入了两种版本的 Android Support Library,这种情形该如何处理呢?

  1. 统一管理支持包的版本号;
  2. 剔除第三方库中包含的支持包,并引入版本一致的支持包。

具体如下:

ext.versions = [
  play_services: '15.0.1',
  // 统一管理支持包的版本号
  suport_library: '27.1.1',
]

dependencies {
  implementation("com.google.android.gms:play-services-gcm:${versions.play_services}") {
    // 剔除 play service 中包含的 v4 支持包
    exclude group: 'com.android.support', module: 'support-v4'
  }
  // 引入版本一致的 v4 支持包
  implementation "com.android.support:support-v4:${versions.suport_library}"
  implementation "com.android.support:appcompat-v7:${versions.suport_library}"
  implementation "com.android.support:recyclerview-v7:${versions.suport_library}"
  implementation "com.android.support:cardview-v7:${versions.suport_library}"
  implementation "com.android.support:support-annotations:${versions.suport_library}"
}

通常在我们引入了众多依赖的情况下,我们并不知道引入哪个依赖重复引入了支持库,有没有工具可以帮我们分析呢?

答案是肯定的,gradle 命令中有一条可以做到这点,那就是 gradle dependencies ,它可以将依赖和依赖的依赖罗列出来。也可以通过 Android Studio 右侧工具栏的 Gradle --> help--> dependencies 启动依赖分析。以上面的依赖为例,执行结果如下:

+--- com.google.android.gms:play-services-gcm:15.0.1
|    +--- com.google.android.gms:play-services-base:[15.0.1,16.0.0) -> 15.0.1
|    |    +--- com.google.android.gms:play-services-basement:[15.0.1] -> 15.0.1
|    |    |    \--- com.android.support:support-v4:26.1.0 -> 27.1.1
|    |    |         +--- com.android.support:support-compat:27.1.1
|    |    |         |    +--- com.android.support:support-annotations:27.1.1
|    |    |         |    \--- android.arch.lifecycle:runtime:1.1.0
|    |    |         |         +--- android.arch.lifecycle:common:1.1.0
|    |    |         |         \--- android.arch.core:common:1.1.0
|    |    |         +--- com.android.support:support-media-compat:27.1.1
|    |    |         |    +--- com.android.support:support-annotations:27.1.1
|    |    |         |    \--- com.android.support:support-compat:27.1.1 (*)
|    |    |         +--- com.android.support:support-core-utils:27.1.1
|    |    |         |    +--- com.android.support:support-annotations:27.1.1
|    |    |         |    \--- com.android.support:support-compat:27.1.1 (*)
|    |    |         +--- com.android.support:support-core-ui:27.1.1
|    |    |         |    +--- com.android.support:support-annotations:27.1.1
|    |    |         |    +--- com.android.support:support-compat:27.1.1 (*)
|    |    |         |    \--- com.android.support:support-core-utils:27.1.1 (*)
|    |    |         \--- com.android.support:support-fragment:27.1.1
|    |    |              +--- com.android.support:support-compat:27.1.1 (*)
|    |    |              +--- com.android.support:support-core-ui:27.1.1 (*)
|    |    |              +--- com.android.support:support-core-utils:27.1.1 (*)
|    |    |              +--- com.android.support:support-annotations:27.1.1
|    |    |              +--- android.arch.lifecycle:livedata-core:1.1.0
|    |    |              |    +--- android.arch.lifecycle:common:1.1.0
|    |    |              |    +--- android.arch.core:common:1.1.0
|    |    |              |    \--- android.arch.core:runtime:1.1.0
|    |    |              |         \--- android.arch.core:common:1.1.0
|    |    |              \--- android.arch.lifecycle:viewmodel:1.1.0
|    |    \--- com.google.android.gms:play-services-tasks:[15.0.1] -> 15.0.1
|    |         \--- com.google.android.gms:play-services-basement:[15.0.1] -> 15.0.1 (*)
|    +--- com.google.android.gms:play-services-basement:[15.0.1,16.0.0) -> 15.0.1 (*)
|    +--- com.google.android.gms:play-services-iid:[15.0.1] -> 15.0.1
|    |    +--- com.google.android.gms:play-services-base:[15.0.1,16.0.0) -> 15.0.1 (*)
|    |    +--- com.google.android.gms:play-services-basement:[15.0.1,16.0.0) -> 15.0.1 (*)
|    |    +--- com.google.android.gms:play-services-stats:[15.0.1,16.0.0) -> 15.0.1
|    |    |    \--- com.google.android.gms:play-services-basement:[15.0.1] -> 15.0.1 (*)
|    |    \--- com.google.android.gms:play-services-tasks:[15.0.1,16.0.0) -> 15.0.1 (*)
|    \--- com.google.android.gms:play-services-stats:[15.0.1,16.0.0) -> 15.0.1 (*)
+--- com.android.support:support-v4:27.1.1 (*)
+--- com.android.support:appcompat-v7:27.1.1
|    +--- com.android.support:support-annotations:27.1.1
|    +--- com.android.support:support-core-utils:27.1.1 (*)
|    +--- com.android.support:support-fragment:27.1.1 (*)
|    +--- com.android.support:support-vector-drawable:27.1.1
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    \--- com.android.support:support-compat:27.1.1 (*)
|    \--- com.android.support:animated-vector-drawable:27.1.1
|         +--- com.android.support:support-vector-drawable:27.1.1 (*)
|         \--- com.android.support:support-core-ui:27.1.1 (*)
+--- com.android.support:recyclerview-v7:27.1.1
|    +--- com.android.support:support-annotations:27.1.1
|    +--- com.android.support:support-compat:27.1.1 (*)
|    \--- com.android.support:support-core-ui:27.1.1 (*)
+--- com.android.support:cardview-v7:27.1.1
|    \--- com.android.support:support-annotations:27

Mac 上的那些*操作

本帖记录个人在使用 Mac 操作系统上的一些*操作,不断更新,以飨读者。

1. 快速移动网页到顶部或底部

用双指上下划触摸板吗?NO,我们有更*的操作:

command + ↑ 回到顶部

command + ↓ 滚到底部

另外,

fn + ↑ 上滚一页

fn + ↓ 下滚一页

fn + ← Home,回到顶部

fn + → End,滚到底部

2. Dock 中只显示打开的应用

Mac 用着用着 Dock 上显示了一堆的图标,看着无法集中注意力,这时候可以打开 Terminal 输入:

defaults write com.apple.dock static-only -boolean true; killall Dock

回车就可以让 Dock 只显示打开的应用了,世界一下子清爽了。

PS,如果想恢复原样,可以执行:

defaults delete com.apple.dock static-only; killall Dock

3. 粘贴文字时不要带样式

有时候从网上看到不错的文字想要粘贴到 Word、Evernote 或者文字编辑应用上,但使用 command + v 会连文字样式都带过来,这时候就要使用*一点的操作了,那就是:

command + shift + v

4. 输入英文时首字母不要自动大写

当你在文字编辑软件上写英文时,Mac 会很贴心地识别首字母并自动大写。但常常让我觉得画蛇添足,明明我不想大写,特别是在博客中或写或改一些代码或脚本时更觉得是捣乱。这时候,我找到了一个禁止自动首字母自动大写的方法:

系统偏好设置 —> 键盘 —> 文本 —> 去除勾选【自动大写字词的首字母】

5. 我要剪切或移动文件

Mac 中,复制的快捷键是 command + c,粘贴的快捷键是 command + v ,但是剪切的快捷键可不是 command + x ,如果要移动文件,你是不是还在进行 粘贴完再删除 的复杂操作?

NO,其实移动文件可以复制后使用快捷键 command + option + v 实现,快去试试吧。

6. 快速转换中文简繁体

确保简繁体转换服务已经开启,路径如下:

系统偏好设置 —> 键盘 —> 快捷键 —> 服务 —> 将文字转换为繁体中文 / 将文字转换为简体中文

选中需要进行简繁对换的文字,按:

  • control + shift + command + c 将文字转为繁体中文
  • control + option + shift + command + c 将文字转为简体中文

Linux 命令总结

SET 命令

用途:

可以设置 shell 的执行方式,不带参数时输出环境变量。

> set [+-abCdefhHklmnpPtuvx]

注:

1. [-] 表示设置参数
2. [+] 表示取消设置参数

示例:

> tmp="nice day"
> $tmp
nice day
> set | grep tmp
tmp="nice day"
> unset tmp
> $tmp

SSH 命令

用途:

连接远程计算机。

> ssh  -p <port> <user>@<hostname> <remote cmd>

注:

  1. [-p] 指定端口号,默认为 22
  2. [remote cmd] 远程执行命令并显示到本地继续工作

配置 [.ssh] 在 [~/.ssh/config] 中,

Host <myhost>
User <username>
HostName <ip>
IdentityFile ~/env/<username>.id_rsa

可快速进行ssh连接,ssh myhost

进程管理命令

前后台切换命令 bg、fg

> fg <task id>
> bg <task id>

注:

  1. 当使用这两个任务时,如果提示 no job control in this shell ,可以使用 set -m 命令开启。
  2. 当一个任务进程在执行过程中想要暂时挂起,可以使用 ctrl + Z ,若要终止,进入 suspended 状态,使用 ctrl + C ,进入terminated 状态。
  3. 挂起的任务可以通过 fg 重新调到前台运行,或者通过 bg 调到后台运行。
  4. 若要终止挂起的任务,可以使用 kill <pid>

& 字符的作用

用途:

放在启动参数后面表示设置此进程为后台进程,这是称之为 job。通过 jobs

命令可以查看当前有多少后台运行的命令。

示例:

> ./run.sh &
> jobs -l

注:

  1. [-l] 显示pid。

nohup

当用户关闭窗口时,终端会受到HUP(hungup)信号,从而关闭其所有子进程。

若要让命令不被终止,有两种处理方式:

  1. 让进程忽略HUP信号, nohup 之所为
  2. 让进程运行在新的会话中,setsid(<cmd> &)之所为

示例:

> nohup ping www.ibm.com &
> setsid ping www.ibm.com
> (ping www.ibm.com &)
> ps -ef | grep www.ibm.com

如果事前没有使用前面的方式保住进程,那么可以使用如下流程进行补救:

  1. ctrl+Z 挂起进程,使用 jobs -l 获取进程号;
  2. 使用 bg <pid> 将其放入后台运行;
  3. 再使用 disown <pid> ,可以避免 HUP 信号的影响。

文件管理命令

tail 查看文件末尾

> tail [-n <line numbers>] [-f] <file>

注:

  1. [-n] 可以指定显示的日志行数,不指定默认为 10 行
  2. [-f] 可以监视文件的增长,简缩的命令为 tailf
  3. 与之相对应的显示前面几条日志的命令为 head

cat 一次显示文件内容

> cat [-ns] <file>...

注:

  1. [-n] 可以显示行号
  2. [-s] 可以合并连续的空行为一
  3. 与之相对的命令为 tac 可以从尾到头显示文件内容(Mac 好像不支持)

示例:

# 一次显示整个文件
cat <file1> <file2>
# 创建新文件
cat > <file>
# 将多个文件合并为一个文件
cat <file1> <file2> > <file> 

more 逐页显示文件内容

> more [-s] [-<line numbers>] [+<line numbers>] <file>

注:

  1. [-s] 可以合并连续的空行为一
  2. [-n] 可以定义每次上滚 n 行
  3. [+n] 可以指定从第 n 行开始显示
  4. ctrl +F 向上滚动一屏,空格键 向下滚动一屏
  5. = 显示当前显示的行数范围及文件名称

示例:

# 从第 100 行开始显示 debug.log, 每次滚动 10 行,合并空行为一
> more -s -10 +100 debug.log

less 分页显示文件内容

more 强大的真正意义上的分页查看文件命令,more 一次会加载整个文件,而 less 是逐页加载。less 还支持向上翻页和搜索。

> less [-gimNsS] [-x <numbers>] <file>

注:

  1. [-g] 高亮先前的搜索结果
  2. [-i] 搜索时忽略大小写
  3. [-m] 显示已显示内容的百分比
  4. [-N] 显示行号
  5. [-s] 合并显示连续的空行为一
  6. [-S] 行过长时舍弃超出部分
  7. [-x 4] 设置tab 为规定的数量的空格
  8. / 向上查找
  9. ? 向下查找
  10. n 正向重复查找
  11. N 反向重复查找
  12. b 向后翻一页
  13. d 向后翻半页
  14. y 向前翻一页
  15. u 向前翻半页
  16. q 退出

示例:

# 查找历史命令中包含run的命令
> history | less
/run
# 假设找到要运行的命令序号为 100,按 q 退出,再按如下重新执行
> !100

grep 查找文件内容

grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)

> grep <option> <file>...
  1. [-A num] 显示匹配行后面 num 行
  2. [-B num] 显示匹配行前面 num 行
  3. [-C num] 显示匹配行前后各 num 行
  4. [--color=auto] 匹配结果自动配色
  5. [-m num] 当匹配了 num 行后不再继续查找
  6. [-n] 显示匹配行所在行号
  7. [-v] 输出未匹配的行

示例:

# 查询日志文件中包含 keyword 但不含 keywords 的行,最多输出 10 行匹配,且显示匹配行前后 2 行
> grep -C 2 -n -m 10 keyword *.log | grep -v keywords

alias 添加别名

树状查看文件:

# 注意:这种方式会列出所有文件,建议使用 brew instal tree. 因为可以使用 `tree -L [depth]`自定义深度
> alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"
> source ~/.zshrc

取消别名:

> unalias tree

ctrl 移动光标

Windows 快捷键 Mac 快捷键 功能
ctrl + 左右键 option + 左右键 在单词之间跳转
ctrl + a 同左 跳到本行的行首
ctrl + e 同左 跳到页尾
ctrl + u 同左 删除当前光标前面的文字
ctrl + k 同左 删除当前光标后面的文字
ctrl + w、ctrl + d 同左 对于当前的单词进行删除操作,w删除光标前面的单词的字符,d则删除后面的字符
ctrl + y 同左 恢复删除的文字
ctrl + l 同左 清屏

同步一台服务器中的文件到另一台

基本思路:拷贝文件到本地,然后覆盖另一台上的同名文件。命令如下,其中 server-a 以及 server-b 是定义在文件 ~/.ssh/config 中的 HOST

ssh server-a "cat ~/test.txt" > ~/Desktop/test.txt;scp ~/Desktop/run.sh server-b:~/test.txt

日语一周七天的记忆方法

速记

汉语 日语 英语 来源
星期日 日曜日 Sunday Sun Day(太阳之日)
星期一 月曜日 MonDay Moon Day(月亮之日)
星期二 火曜日 Tuesday Tiu's Day( Tiu 是日耳曼战争之神,代替古罗马中的战神 Mars,**命名为火星)
星期三 水曜日 Wednesday Woden's Day( Woden 是日耳曼神话中的至高神,代替古罗马中的 信使 Mercury ,**命名为水星)
星期四 木曜日 ThursDay Thor's Day( Thor 是北欧雷神,代替古罗马中的爱神 Jupiter,**命名为木星)
星期五 金曜日 FriDay Freya’s Day... Or Frigg’s Day( Freya 和 Frigg 都是北欧女神,代替古罗马中的女神 Venus,**命名为金星)
星期六 土曜日 Saturday Saturn's Day( Saturn 是古罗马中的农神)

Week

古巴比伦人首先使用 7 日为一周的时间单位,后来犹太人把它传到古埃及,又由古埃及传到罗马,公元3世纪以后,就广泛地传播到欧洲各国。唐朝时期在西域和**的交流中传入了中土获得发展,再传入朝鲜半岛,日本。

七曜

杨士勋(唐)疏:“ 谓之七曜者,日月五星皆照天下,故谓之曜。” 一个曜日就是日月五星轮流照耀世界的一天。日本曜日的说法就是从**传入的。

星期

“星期”原是指牛郎星和织女星相会之期,现代意义的“星期”是个旧词新义词。光绪三十一年(1905年)由袁嘉谷所定用“星期”代替“曜日”,到了民国以后星期被广泛使用。

礼拜

到了19世纪20年代,有人将汉语中的“礼拜”一词用作英语 week 的对应词了,如1828年马礼逊《广东省土话字汇》:“WEEK ,a ,一个礼拜。”“礼拜”原为动词,指宗教徒向所信奉的神行礼。由于基督教、伊斯兰教是一星期做一次礼拜,故此词慢慢引申用来指 week 了。

日本还有一个表示 week 的“周”字,而且这个词还传到了**。如1901年《清议报》七十八册《马塞多尼亚》:“前在欧洲定造水雷艇六只。目下有二只,业已竣工,数周间(即数礼拜)必到。”

参考

《日語自遊行の最和味》第一課 秋葉原

對話

桜:秋葉原 は 日本最大 の 電気街です。 でも、今 は 「オタク」で 有名です。

秋葉原是日本最大的電器街。但是,現在卻以[御宅族]出名。

健:そです よね。 秋葉原 は 若い人 の 新しい 観光名所 です よね。

說的正是啊。秋葉原是年輕人的新觀光勝地哦。

桜:香港 でわ 「電車男」で 有名 です。

在香港,(御宅族)以[電車男]聞名。

健:若い 観光客 は お寺 や 神社 へ 行きません ね。

年輕一輩的遊客是不會到寺廟呀、神社呀這些地方去的。

桜:アキバグッズ を 買い、 コスペレ を 見、 メイドカフェ へ 行く...。

(他們)買秋葉原紀念品,看 cosplay,去俏女僕咖啡店。

健:本当 ですよね。

你說的一點都沒錯啊。

附錄

  1. 日語自遊行の最和味
  2. 《日語自遊行の最和味》第一課 秋葉原.pdf

Axure 使用小记

使用第三方组件库

(1)下载第三方组件库

Refs.cn 原型设计元件库,基于Axure RP 8,支持 Android、Apple、Windows、微信,移动、桌面平台的应用和网站原型设计。 http://refs.cn/rplibs

(2)导入第三方组件库

打开 Axure,点击右侧的 Libraries 面板的菜单按钮,在弹框中选择 Load Library... 然后选择下载的 .rplib 格式的文件,确定即可。

《日語自遊行の最和味》第四課 名古屋相撲大會

詞彙

大 相撲 おお ずもう 日本相撲協會主辦的職業相撲比賽。分析:「おお」是對漢字「大」或「太」的訓讀,「すもう」是對漢字「相撲」或「角力」的訓讀。
場所 ばしょ (專指相撲的)會場;(專指相撲的)會期;地點。「ばしょ」是中文「場所」的音讀。
力士 りきし 相撲選手。「りきし」是對漢字「力士」的音讀。
体重 たいじゅう 體重。「たいじゅう」是對漢字「體重」的音讀。
大きい 高大;大氣的,大度的;誇大的;數量多的。
どのぐらい 大約多少。「どの」或「何の」,表示詢問大致的數量。「くらい」在這裡是副詞助詞,表示「大約」。

汉语音韵中的四声八调及平仄

四声八调

国语拼音中的四声为:一声、二声、三声、四声,其正式学名分别为:阴平、阳平、上声、去声。其 IPA 调值(根据五度分音法确定的相对调值)如下:

声调 IPA 调值 记号
阴平 55 ¯
阳平 35 ˊ
上声 214 ˇ
去声 51 ˋ

在古代汉语中四声八调的说法。“四声” 源自唐宋时期中古汉语的 “平上去入” 四个声调。在发展过程中经历了以下的流变:

平分阴阳

在元代受声母发音方法中的清浊从每一声中分出阴阳二调(清者为阴,浊者为阳),构成 “阴平”、“阳平”、“阴上”、“阳上”、“阴去”、“阳去”、“阴去”、“阳去”、“阴入”、“阳入” 共八个调。

如今,官话北京话只有平声分阴阳,而吴语和闽南语只有上声不分阴阳。

浊上归去

指声母为全浊的上声字改读去声(而次浊上字声调和清上字相同)。次浊和全浊的关键在于声带震动的程度,笔者母语福佬话中刚好与中古音相符。

汉字 中古音 汉语拼音 闽南语台罗拼音 吴语拼音(苏州闲话)
清上 dǎo tau5
全浊上 dào dau6
次浊上 lǎo láu lau6

入派三声

官话及大多数方言中入声消失了,并归入了其他三声,而在南方的方言(包括粤语、闽南语、客语和吴语等)中仍然包含着入声。比如 “屋” 在在粤语、闽南语、客语和吴语都是入声,而在国语中是平声。

平仄

中古汉语中,“平仄” 是指 平声为 “平”,其他三声为 “仄”。之后随着音韵的流变,原本诗词中的 “仄” 声变得难以判断。但是根据流变规律可以得出一个简易的判别方法:如果国语中为非平声,那么就是 “仄”;如果国语中为平声,而南方方言中为入声,那么就是 “仄”,否则为 “平”。

参考

《古代漢語》上一·常用字

甲骨文 金文 篆書
言-oracle-j04903 言-bronze-b02975 言-seal-s01648
言-oracle-j04918 言-bronze-b03192
言,甲骨文是指事字,字形在舌的舌尖位置加一短横指事符号,表示舌头发出的动作。造字本义:动词,鼓舌说话。  --《象形字典》有刪減

頭腦風暴:言的甲骨文好似一把小刀刺進胸膛,然後噴濺出血液來,所以可以解釋成直話直說就像一針見血,常常令人不舒服。

  • 《說文》直言曰言,論難曰語。
  • 又辭章也。《書·洪範》五事,一曰貌,二曰言。
  • 又一句爲一言。《論語》一言以蔽之。
  • 又一字爲一言。《戰國策》臣請三言而已矣,曰海大魚。
  • 又猶議也。《屈原·離騷》初旣與余成言兮,後悔遁而有他。
  • 又號令也。《周語》有不祀則修言。
  • 又助語辭。《易·師卦》田有禽利執言。《註》語辭也。
  • 又《爾雅·釋詁》言,我也。《詩·周南》言告師氏。《傳》言,我也。師,女師也。
  • 又《博雅》問也。《周禮·春官》冢人:及葬,言鸞車象人。《註》言問其不如法度者。

甲骨文 金文 篆書
--
--
五,既是声旁也是形旁,表示数量多。语,金文(言,说)(两个“五”,数量极多),表示说很多话。造字本义:演说,谈论,议论。篆文加“口”。  --《象形字典》有刪減

頭腦風暴:語的金文左言右兩五,表示說了很多話或者很多人在說話,說了很多話就叫「敘」,很多人在說話就是「論」。

上聲 (yǔ)

  • 《說文》論也。

  • 《疏》直言曰言,謂一人自言。答難曰語,謂二人相對。

  • 《釋名》敘也。敘己所欲說也。《易·頤卦》君子以愼言語,節飮食。

去聲 (yù)

  • 《廣韻》告也。《增韻》以言告人也。《左傳·隱元年》公語之故。

「謂」字由左「言」右「胃」構成,「言」字上面說了,下面研究下「胃」的字形演變,如下:

甲骨文 金文 篆書
--
--
金文是会义字,上面(像“米袋”)下面(月,即“肉”),强调“米袋”为身体的器官。 --《象形字典》有刪減
  • 《說文》胃,榖府也。也就是消化穀物的器官。

「謂」字的字形演變如下:

甲骨文 金文 篆書
--

頭腦風暴:這應該是一個指事詞,告訴族人肚子餓了,引為「訴說」之意。溫飽問題是大問題,所以「有所謂」,不值得一提的問題那就是「無所謂」了。

  • 《說文》謂,報也。
  • 《廣韻》告也,言也。
  • 又《韻會》事有可稱曰有謂,失於事宜不可名言曰無謂。《莊子·齊物論》今我則有謂矣,而未知吾所謂之,其果有謂乎,其果無謂乎。
  • 又《正韻》非與之言而稱其人亦曰謂,《論語》子謂子賤,子謂子產,是也。
  • 又《爾雅·釋詁》勤也。《詩·小雅》心乎愛矣,遐不謂矣。(謂在這裡應為告也。)

先看看「方」,其字形演變如下:

甲骨文 金文 篆書
“方”是“放”、“旁”的本字。方,甲骨文(剔发刺字的犯人)(锁颈的枷械),表示被披枷流放的罪人。造字本义:动词,将罪犯剔发刺字,流放边疆。当“方”的“流放犯人”本义消失后,篆文再加“凡”(方形木枷)另造“旁”代替;或加“攴”(打击)另造“放”代替,表示刑罚驱逐。 --《象形字典》有刪減

頭腦風暴:「方」所帶的枷為矩形,所以「方」有了矩形之引申;「方」是被發配到邊疆,所以「方」有了地方、邊邑之引申。

甲骨文 金文 篆書
--
方,既是声旁也是形旁,表示边邑。访,篆文(言,问候、交流)(方,边邑、异域),造字本义:**派人到异域他邦问候、交流方略。 --《象形字典》

頭腦風暴:金文「訪」很像一個人低頭伸手謙虛地詢問,而篆書「訪」很像一個人抬頭招手向人打招呼。「訪」的本義應該就是去問,後面才引申出拜訪之意。

  • 《說文》汎謀曰訪。《註》汎,泛也。
  • 《傳》謂就而問之也。
  • 又議也。《楚語》敎之令,使訪物官。
  • 又《增韻》及也,見也。
  • 又方也。《前漢·高五王傳》訪以呂氏,故幾亂天下。《註》訪,猶方也。《字彙補》與昉義同。

先來看「青」字的演變,如下:

甲骨文 金文 篆書
--
井,既是声旁也是形旁,表示矿坑。青,甲骨文(屮,生,出现、出产)(井,矿坑),表示某种产自矿井的东西。古人将这种矿石研磨成粉末,作为重要颜料。 造字本义:名词,从矿井采掘的苔色矿石。 --《象形字典》有刪減
  • 《說文》:“青,東方色也。木生火,从生丹,丹青之信言象然。𡗡,古文青。《註》大為成年人,屮為成長,成長為成年人的階段就是青年人。
  • 《釋名》靑,生也。象物之生時色也。
  • 又《韻會》竹皮曰靑。《後漢·吳祐傳》殺靑簡以寫經書。《註》以火炙簡令汗取其靑,易書復不蠹,謂之殺靑。
甲骨文 金文 篆書
--
青,既是声旁也是形旁,是“倩”的省略,表示漂亮、美丽。请,金文(言,说)(倩,漂亮),造字本义:说漂亮话赞美对方,以期对方接受邀聘。 --《象形字典》有刪減

頭腦風暴:「青」在此處應該麗人的意思,「言」「青」表示向麗人說話。見麗人會說什麼話呢?豈非美言?

  • 《說文》謁也。
  • 《玉篇》乞也,問也。《前漢·張湯傳》造請諸公,不避寒暑。
  • 又《正韻》漢制,春曰朝,秋曰請,如古諸侯聘禮也。《史記·吳王濞傳》使人爲秋請。《前漢·宣帝紀》時會朝請。

召(𥃝)

字形演變如下:

甲骨文 金文 篆書
“召”是“招”的本字。刀,既是声旁也是形旁,疑是“匕”即“匙”的误写。召,甲骨文(双手)(匕,酒匙)(酉,酒坛),表示主人手持酒匕为客人打酒。有的甲骨文用“口”(盛器)代替“酉”;再加,像主宾双方相对坐在席子上。简体甲骨文省去双手和主客对坐的形象,并将酒匙“匕”写成“刀”。造字本义:打酒添食,招待客人。 --《象形字典》有刪減

頭腦風暴:客人來訪,雙手搬出酒肉相待。從上至下依次為「人」、「雙手」、「酒缸」、「藏酒缸之處」。

  • 《王逸》曰以手曰招,以言曰召。
  • 又姓。《廣韻》召公之後。《前漢·循吏傳》召信臣,九江壽春人。《氏族博考》春秋召與邵一氏,後分爲二,汝南安陽之族皆从邵。

Vim 小记

1. Vim 剪贴板如何与系统剪贴板交互?

“+y 把选中内容拷贝到”+号剪贴板,即系统剪贴板。

“+p 把系统剪贴板的内容粘贴到vim。

Vim 中的剪贴板历史可以使用 :reg 进行罗列,并配合以上操作进行粘贴。

2. 如何连接两行文字?

在 Vim 中你可以把两行连起来这意味着删除两行间的换行符。"J" 命令用于完成这个
功能。
以下面两行为例:

A young intelligent
turtle

把光标移到第一行,然后按 "J":

A young intelligent turtle

3. 如何进行列块选择?

使用 Ctrl + v 进入列块选择模式。

4. 如何快速查找和替换?

快速进行查找可以在命令模式下,使用 /{regex},Vim 中的正则有点特殊(详细规则可以阅读文末附件,最明显的就是括号也需要转义),举个例子,有文字材料如下:

java.lang.NullPointerException
...
java.lang.ClassNotFoundException

要求查找到所有 Exception,那么可以使用

/\.\a*Exception

再配合 n 继续查找。

5. 如何进行重做?

使用 Ctrl + r 进行重做。

6. 如何记录和回放我的可重复性操作?

要点:使用 q{register} 和 @{register}

"." 命令重复前一个修改操作。但如果你需要作一些更复杂的操作它就不行了。这时,记
录命令就变得很有效。这需要三个步骤:

  1. "q{register}" 命令启动一次击键记录,结果保存到 {register} 指定的寄存器中。
    寄存器名可以用 a 到 z 中任一个字母表示。

  2. 输入你的命令。

  3. 键入 q (后面不用跟任何字符) 命令结束记录。

现在,你可以用 "@{register}" 命令执行这个宏。
现在看看你可以怎么用这些命令。假设你有如下文件名列表:

stdio.h
fcntl.h
unistd.h
stdlib.h

而你想把它变成这样:

include "stdio.h"
include "fcntl.h"
include "unistd.h"
include "stdlib.h"

先移动到第一行,接着执行如下命令:

qa 启动记录,并使用寄存器 a
^ 移到行首
i#include " 在行首输入 #include "
$ 移到行末
a" 在行末加上双引号 (")
j 移到下一行
q 结束记录

现在,你已经完成一次复杂的修改了。你可以通过重复三次 "@A" 完成余下的修改。
"@A" 命令可以通过计数前缀修饰,使操作重复指定的次数。在本例中,你可以输入:

3@a

附录

Vim 用户使用手册

Android 使用 DiffUtil 处理 RecyclerView 数据更新问题

背景

  1. RecyclerView.Adapter#notifyDataSetChanged() 会每次刷新整个布局;
  2. 每次手动调用 RecyclerView.Adapter#notifyItemXx 系列方法很麻烦;
  3. 需要在新增的项目中跟旧的列表项重复时,只更新内容,而不是插入重复项。

DiffUtil

DiffUtil 就是为了简化 RecyclerVeiw 更新数据操作而生。其关键类和方法如下:

方法 描述
DiffUtil public static DiffResult calculateDiff(Callback cb) 根据 Callback 提供的数据分析出新旧数据列表的差异,返回 DiffResult
DiffUtil.Callback public abstract int getOldListSize() 返回旧数据的数量
public abstract int getNewListSize() 返回新数据的数量
public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition) 决定两个数据项是否是同一个
public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition) (当两个数据项是同一个时,)决定两个数据项的内容是否同样,或者说是否需要进行更新
DiffUtil.DiffResult public void dispatchUpdatesTo(final RecyclerView.Adapter adapter) 将差异信息更新到 RecyclerView.Adapter 中

步骤

  1. 创建一个类实现 DiffUtil.Callback
  2. 当新数据到来时,实例化自定义的 callback,传入新旧数据;
  3. 在子线程调用 DiffUtil#calculateDiff 计算差异;
  4. 将差异结果 DiffResult 更新到 RecyclerView.Adapter 中。

更多

  • 使用 android.support.v7.recyclerview.extensions.ListAdapterandroid.support.v7.recyclerview.extensions.AsyncListDiffer

Genesis 1 @Old Testament

  1. In the beginning God created the heaven and the earth.

    起 初   神 創 造 天 地 。

  2. And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.

    地 是 空 虛 混 沌 . 淵 面 黑 暗 .   神 的 靈 運 行 在 水 面 上 。

    void
    -> a large empty space
    
  3. And God said, Let there be light: and there was light.

    神 說 、 要 有 光 、 就 有 了 光 。

  4. And God saw the light, that it was good: and God divided the light from the darkness.

    神 看 光 是 好 的 、 就 把 光 暗 分 開 了 。

  5. And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.

    神 稱 光 為 晝 、 稱 暗 為 夜 . 有 晚 上 、 有 早 晨 、 這 是 頭 一 日 。

  6. And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.

    神 說 、 諸 水 之 間 要 有 空 氣 、 將 水 分 為 上 下 。

    firmament
    -> the sky or heaven
    midst
    -> middle
    
  7. And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.

    神 就 造 出 空 氣 、 將 空 氣 以 下 的 水 、 空 氣 以 上 的 水 分 開 了 . 事 就 這 樣 成 了 。

  8. And God called the firmament Heaven. And the evening and the morning were the second day.

    神 稱 空 氣 為 天 . 有 晚 上 、 有 早 晨 、 是 第 二 日 。

  9. And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.

    神 說 、 天 下 的 水 要 聚 在 一 處 、 使 旱 地 露 出 來 . 事 就 這 樣 成 了 。

  10. And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.

    神 稱 旱 地 為 地 、 稱 水 的 聚 處 為 海 .   神 看 著 是 好 的 。

  11. And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.

    神 說 、 地 要 發 生 青 草 、 和 結 種 子 的 菜 蔬 、 並 結 果 子 的 樹 木 、 各 從 其 類 、 果 子 都 包 著 核 . 事 就 這 樣 成 了 。

    forth
    -> [only after verb]formal going out from a place or point, and moving forwards or outwards.
    herb
    -> a small plant that is used to improve the taste of food, or to make medicine.
    yield
    -> [transitive] to produce crops, profits etc.
    -> [transitive] to produce a result, answer, or piece of information.
    
  12. And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.

    於 是 地 發 生 了 青 草 、 和 結 種 子 的 菜 蔬 、 各 從 其 類 、 並 結 果 子 的 樹 木 、 各 從 其 類 、 果 子 都 包 著 核 。   神 看 著 是 好 的 .

  13. And the evening and the morning were the third day.

    有 晚 上 、 有 早 晨 、 是 第 三 日 。

  14. And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:

    神 說 、 天 上 要 有 光 體 、 可 以 分 晝 夜 、 作 記 號 、 定 節 令 、 日 子 、 年 歲 .

    sign
    -> [countable] (also star sign) a group of stars, representing one of 12 parts of the year, that some people believe influences your behaviour and your life
    
  15. And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.

    並 要 發 光 在 天 空 、 普 照 在 地 上 . 事 就 這 樣 成 了 。

  16. And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.

    於 是   神 造 了 兩 個 大 光 、 大 的 管 晝 、 小 的 管 夜 . 又 造 眾 星 。

    lesser
    --> [formal] not as large, as important, or as much as something else 
    
  17. And God set them in the firmament of the heaven to give light upon the earth,

    就 把 這 些 光 擺 列 在 天 空 、 普 照 在 地 上 、

  18. And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.

    管 理 晝 夜 、 分 別 明 暗 .   神 看 著 是 好 的 .

  19. And the evening and the morning were the fourth day.

    有 晚 上 、 有 早 晨 、 是 第 四 日 。

  20. And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.

    神 說 、 水 要 多 多 滋 生 有 生 命 的 物 . 要 有 雀 鳥 飛 在 地 面 以 上 、 天 空 之 中 。

    abundantly
    -> in large quantities.
    hath
    -> has
    fowl
    -> any bird
    
  21. And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.

    神 就 造 出 大 魚 、 和 水 中 所 滋 生 各 樣 有 生 命 的 動 物 、 各 從 其 類 . 又 造 出 各 樣 飛 鳥 、 各 從 其 類 .   神 看 著 是 好 的 。

    whale
    -> a very large animal that lives in the sea and looks like a fish, but is actually a mammal.
    moveth
    -> moving creature.
    wingled
    -> having wings.
    
  22. And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.

    神 就 賜 福 給 這 一 切 、 說 、 滋 生 繁 多 、 充 滿 海 中 的 水 . 雀 鳥 也 要 多 生 在 地 上 。

    fruitful
    -> producing good results.
    multiply
    -> [intransitive and transitive] to increase by a large.
    
  23. And the evening and the morning were the fifth day.

    有 晚 上 、 有 早 晨 、 是 第 五 日 。

  24. And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.

    神 說 、 地 要 生 出 活 物 來 、 各 從 其 類 . 牲 畜 、 昆 蟲 、 野 獸 、 各 從 其 類 . 事 就 這 樣 成 了 。

    cattle
    -> cows and bulls kept on a farm for their meat or milk.
    creep
    ->  if something such as an insect, small animal, or car creeps, it moves slowly and quietly.
    
  25. And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.

    於 是   神 造 出 野 獸 、 各 從 其 類 . 牲 畜 、 各 從 其 類 . 地 上 一 切 昆 蟲 、 各 從 其 類 .   神 看 著 是 好 的 。

  26. And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.

神 說 、 我 們 要 照 著 我 們 的 形 像 、 按 著 我 們 的 樣 式 造 人 、 使 他 們 管 理 海 裡 的 魚 、 空 中 的 鳥 、 地 上 的 牲 畜 、 和 全 地 、 並 地 上 所 爬 的 一 切 昆 蟲 。

```
dominion
-> the power or right to rule people or control something.
```
  1. So God created man in his own image, in the image of God created he him; male and female created he them.

    神 就 照 著 自 己 的 形 像 造 人 、 乃 是 照 著 他 的 形 像 造 男 造 女 。

  2. And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.

    神 就 賜 福 給 他 們 、 又 對 他 們 說 、 要 生 養 眾 多 、 遍 滿 地 面 、 治 理 這 地 . 也 要 管 理 海 裡 的 魚 、 空 中 的 鳥 . 和 地 上 各 樣 行 動 的 活 物 。

    replenish
    -> to put new supplies into something, or to fill something again.
    subdue
    -> to defeat or control a person or group, especially using force.
    
  3. And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.

    神 說 、 看 哪 、 我 將 遍 地 上 一 切 結 種 子 的 菜 蔬 、 和 一 切 樹 上 所 結 有 核 的 果 子 、 全 賜 給 你 們 作 食 物 。

  4. And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.

    至 於 地 上 的 走 獸 、 和 空 中 的 飛 鳥 、 並 各 樣 爬 在 地 上 有 生 命 的 物 、 我 將 青 草 賜 給 他 們 作 食 物 . 事 就 這 樣 成 了 。

    wherein
    -> in which place or part.
    
  5. And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.

    神 看 著 一 切 所 造 的 都 甚 好 . 有 晚 上 、 有 早 晨 、 是 第 六 日 。

    behold
    -> to see or to look at something – sometimes used humorously.
    

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.