Archive of

网友语录 - 第12期

这里记录每周值得分享的网友文字,我的网摘和书摘。一般在周六发布。

愚兄 人很多懊恼来自于对他人的“怒其不争”,也就是特喜欢当爹育人。很多时候对方根本不想也无法被教育,要欣喜于这世界有花,也接纳这世界有蛆。(世间万物,各有各的活法)


书摘 《暮色将尽》

我还从没认真地使用过自己的双手,当然绣花除外,这个我很在行。想象一下,如果能用自己的双手做个书架,那该多么有益,又多么令人开心啊!我真的为此感到遗憾。

因此,总的来说,我这一生,一共有两件最主要的憾事:内心深处有一个冷酷的点,以及懒惰(缺乏行动力其实也不乏胆怯的因素,但我觉得懒惰比胆怯的比重大些)。这两件憾事真实存在,但并没有怎么太折磨我,我也没觉得该常常反思。止于此就行了吧,因天天看着不好的一面是相当无聊的事。我不觉得挖掘过去的内疚对老年人有什么意义,历史已经无法改变了。

......

看看她说的话,她说她到现在依然记得在集中营里唯一善良的纳粹邻居,在以色列感受到的令人心灵颤料的自由,以及她如何热爱英国、热爱英国人,更重要的是,她到现在依然嗜好钢琴演奏,每天都弹三小时。她曾说过,“工作是人类最棒的发明••••它让你感到快乐,因你在做事情”,她和玛丽•路易斯•莫泰希茨基一样令人惊异,而她是天生就有创造力的典型。她沉醉于生活的美妙之中,并非由于宗教的激发,“开始是这样的,我们生来就有好的一面,也有坏的一面,每个人,每一个人都是这样的。然后你会遇到激发你内心好或坏的不同境遇,我相信,这就是为什么人们要发明宗教的原因”,因此她很尊重宗教里饱含的希望,尽管她的内心未必需要宗教的支持。她身上有一种不同寻常的好运,天生就具备强有力地朝向乐观主义的本性,不论经历了怎样的际遇,她依然会这样说:“生命是美丽的,如此美丽。而一个人越老,就越能察觉到这一点。当你老了,你思考,你记忆,你关切,你明了。你因为一切而深怀感激,为一切。”她还说:“我了解所有事情坏的一面,但我只看好的一面。”

.....

我是在狗的陪伴下长大的,所以不太理解为什么有些人不喜欢狗。这种动物被人类驯养的历史很久了,与人生活在一起似乎天经地义,如虎入丛林一般自然。它们已成为人类能透彻了解其情感的唯一动物种群。它们的情感与人类何其相似,只是看起来形式简单些罢了。当一只狗焦虑、愤怒、饥饿、迷惑、快乐或充满爱意时,它将这些情绪以最纯洁的形式呈现出来,我们也能感受得到,只不过人类的这些情感早被日益增长的复杂人性扭曲变形了。狗和人类因此在简单却深刻的层面彼此相通,我多想再养一只黑色绒脸小哈巴狗,重新体验这一切啊

......

我们非常清楚生命是依照生物规律而不是个体规律运作的,个体出生、长大、生儿育女、凋零死亡让位给后来者。不管人类做着怎样的白日梦,也无法幸免这样的命运。当然,我们想要尽力延长凋零过程,以至于有时候凋零甚至比成长所经历的时间还长,因此,在这一过程中会遭遇什么,如何能尽力过好这一凋零的时光,确实值得深思。现在有这么多关于保持青春的书,还有更多有关生儿育女详尽的、实验性的经验分享,但有关凋零的记录却不多见。而我,正行走在这一凋零的路程当中,我的神经刚刚经历了小狗事件和树蕨事件,倍感痛楚,于是我问自己:“为什么我不来记录?”因此,我写了这本书。

......

不信神说明什么?缺乏想象力,还是缺乏勇气?或仅是一种遗传所赋予的性情模式?前两种情况在有神论或无神论的群体中均能发现,第三种情况只不过用家族史将这个问题回避过去罢了。虔诚但文化不高的人常觉得我的这种辩解是一种放肆,是淘气任性、拒绝自我节制的行为,但实际上不管信不信神,人们一样能勤勉地履行外界赋予我们的制约和责任,并和他人一起分享这个世界。对无神论者而言,答案可能很简单,尽管说起来有点令人难为情:他不信,只是因为他觉得自己比信神的兄弟聪明智慧。不过他那信神的兄弟从相反的角度,势必也是同样的想法,那么谁可以做中间调停人?我想我们必须接受这个事实,即关于这个问题,世界上存在着两种人。


西瓦 “家居生活的舒适与整洁无关。若非如此,则每个人都可能住在室内设计与建筑杂志刊出的那些不具生气、全无人味的房屋中。这些整理得毫无瑕疵的房间所欠缺的,或者说摄制这些房间的摄影师所刻意去除的,是经人住用的一切证据。”《家的设计史》


CarrieZ 日子循环往复,但爱历久弥新。


“如果你在思考时没有将其写下来,那么你只是以为自己在思考。”( » Paul Graham)


闽南大翠花 所有可有可无的东西,一律可无。


“能长期稳定维持下去的关系不是靠很强烈的爱,很大量的付出,而是很少的攻击,很少的对抗,很少的强人所难,很多的接纳和允许。爱是如你所是,而非如我所愿。”适用于任何关系。


书摘 《人类文明史》

还有一些人走向了河湖海洋,以水中捕食为生。这种生活方式未必形成得更晚,因为船的出现比人类更早,我们的祖先在尚未完全进化成人类时就造出了最早的船。所以,人类在诞生之初应该就已经明白,只要地理条件允许,捕鱼、耕种和放牧一样,都能够维持生存。

(船出现的比智人更早,这是我以前不知道的)

......

尼罗河下游水阔流深,波澜不兴地一路向北流去。在这平静的水面上,终年吹着向南的微风。人们在河上行船,撑上帆就随风向南,收起帆则顺流向北。这样的条件让人们能沿着河流分散而居,而不用聚集在一个个孤立的城镇。在不断交流互动中,人们形成了相同的文化,或者可以说,整个流域形成了一个巨大的社会星群。

......

底格里斯—幼发拉底河在尼罗河三角洲正东大约1 350英里处流入波斯湾。这两条河流发源于土耳其的群山中,相隔平均50英里,近乎平行地一路向南流去,流过今天的伊拉克地区,一直到快入海处才汇流合一。两河流域没有尼罗河那样的大瀑布群分开上游和下游,有些河段可以行船,有些不能。河上风向多变,下游还有很多沼泽地。所以美索不达米亚平原没有形成全流域连绵单一的文化,而是出现了很多散落的村庄群,各有各的祭祠神庙和信奉体系。

这个地区没有人能赖以庇护的地理屏障。大河滋养了农耕,且当地的环境同样适合游牧,所以农民必须时刻提防可能从任何方向入侵的劫掠者。没有地理屏障,村庄里的人就自己修筑卫墙,于是美索不达米亚平原上就出现了不一样的景观,形成了很多有卫墙的城池,进而发展成了善战的小型城邦:乌鲁克、阿卡德、拉伽什、基什……每个城邦都有自己训练有素的军队。

古埃及人发现,一旦培育出了修筑工程的劳动人口就必须让他们有活儿可干。而美索不达米亚人则发现,一旦有了军队就要不停征战,否则无仗可打的军队会产生内讧。于是,这里的统治者们不是在抵御外敌入侵,就是在沿着河流向上下游征讨邻邦。古埃及人修建了金字塔,美索不达米亚人则建立了王朝。战胜的首领统治若干城邦,得以拥有和调动更多资源,由于城邦需要更强大的军队来保卫,反过来又挑起了更多战事。大约四千三百年前,基什城邦的王——阿卡德的萨尔贡(Sargon of Akkad)征服了美索不达米亚地区大部分的城邦,建立了世界历史上第一个王朝帝国。


有人说苦难会让人变得高风亮节,其实不然。有时幸福的生活才会让人的情操变得高尚,苦难在大多数情况下,只会让人变得心胸狭窄,苦大仇深。-- 毛姆

世界上最无耻、最阴险、最歹毒的赞美,就是用底层人的艰辛和苦难,当作励志故事去愚弄底层人。-- 王朔


Sam Tsai 「這應該很簡單,不會花你太多時間吧?」—尋求協助時,不管多熟的朋友,都不要說這種話。當你遇到自己解決不了的事,多數情況下,你並沒有評估難易度的資格。貿然說出這樣的話,對雙方都不利。想想看,如果對方最後沒能幫上忙,這個台階要怎麼下?再說,我的時間值多少,也不是你能評斷的。


我写 SQLite 的时候,从来没人教过我 B 树的知识。我需要自己实现 B 树,我就从书架取下高德纳的《计算机编程艺术》,找到了 B 树的章节。他描述了算法,我就照着实现。

有趣的是,高德纳详细介绍了搜索 B 树和插入 B 树的算法,没有提供从 B 树删除数据的算法,这是放在本章末尾的练习。所以我在实现自己的 B 树之前,还必须先做完该章的练习。谢谢高德纳,我真的很感激。

-- 理查德·希普《SQLite 不为人知的故事》(英文)https://corecursive.com/066-sqlite-with-richard-hipp/


书摘《租界生活-一个英国人在天津的童年》

到了秋天,蝗虫又来了。它们在人们头顶上空云集,犹如沙尘暴一样遮天蔽日,然后又像雨一样落下来。我们都赶忙关窗闭户。非常害怕蝗虫的妈妈简直发了疯,“你瞧见了吧,”她叫喊着,声音变成了紧张的尖叫,“我跟你们说过!我早就知道它们要来!它们总是在早灾过后来的!“那天晚上她教的钢琴课就像一场风暴,“不,不,不!”她冲着她的学生吼道,“我说的是升B调,再弹一遍。”

整整一个晚上,不断飞来的蝗虫不停地敲打在玻璃窗上,发出沉闷的砰砰声。第二天早上,花园里到处都是蝗虫。这些大约两英寸长、呈灰褐色的蝗虫一只压一只地蠕动着,争先恐后地奔向有草的地方,气势凶恶而又悄然无声。

那棵雨伞树也早就光秃秃的了,就像到了冬天。越来越多的蝗虫从空中落下来,它们的翅膀发出呼呼的声音。贫穷的中国人从地沟边儿一堆一堆地弄来,拿到家里炒熟了吃。宋哥哥用油炸了一些,弄得厨房里臭味儿熏天。我勇敢地吃了一只,弄得我嘴里好长时间都有那股令人恶心的酸味儿。

在两天的时间里,蝗虫吞噬了维多利亚花园里的每一朵花和每一片草叶。花园警卫老王喜欢蝗虫,他还会拿来坐在长発上生着吃,那个样子真是令人毛骨悚然,他掐掉蝗虫的头和翅膀,将还活着的蝗虫扔进嘴里。他拿了一只蝗虫给我吃,我吓得赶紧跑开了,他却在我身后发出一阵狂笑。

......

一个女人从货舱里走出来。她看上去与一姐很像,只是年轻些。

在她身后跟着一群孩子,两个男孩儿,六个女孩儿。“欢迎,欢迎!”她一边说着,一边扶着我们上了船。她让我坐在船尾的一卷铺盖上。一位老渔民正蹲在船尾处的一个炭火盆旁,在他旁边,有两口铁锅、一个盛粮食的大筐和一把扫帚。

这个老人姓程。他朝我笑了笑,说:“你得吃点儿东西,你累了。”我们吃的是白菜和煮高粱米,喝的是茶。吃饭时大家都没怎么说话。 那几个孩子非常腼腆,藏在母亲身后盯着我看。那种很粗的黄色的高粱米味道很苦,我勉强吃了一碗。我当时在想,要是我也住在运河的船上,我就得习惯吃这种东西。“疯子”麦克说高是北方的穷人能吃到的唯一的东西,想一想真是如此。他们从高粱中得到食物、酒、盖屋顶的材料、地上铺的席子、筐、笤帚以及很多别的东西。

过了一会儿,我转过身对程说:“我们看见了一条蛇。”他大笑道:“这里有很多蛇,看!”他说着,手指向一边,就见一条蛇,只有暗绿色的头露出水面,在运河中间游了过去,身后留下箭状的波纹。

“蛇很坏,是不是?”我问程。 他大笑着,拍着大腿说道:“不,它们不坏。蛇能做药,还能吃。”“可在我爸爸的家乡爱尔兰,人们都说蛇很坏。有个圣徒,他是 爱尔兰的英雄,把所有的蛇都赶到了海里。”

程摇了摇头,没说什么。


SpringField 专制是政治上的一种极端主义,西方从文艺复兴以来逐渐走向更加开放文明,其基础就是解放人性。大白话就是给人更多的自由,鼓励反思质疑权威。而东方的儒家还是让人服从听话为基础,哪怕某个时刻稍微松绑还是禁锢于特定的框架之内。所以难以突破固定僵化思维的还是会drawn to具有独裁专制特质的一切。


安迪斯晨风 (关于过年)“生活在银河系第三旋臂一颗普通恒星光焰辐射范围内的细小生命,正在欢庆它们居住的行星完成了一次公转。” // 这么说出来别有一番不是滋味

Migrated your moments from HappyFeed to HappyNotes

First, get your moments data

(function () {
  const MAX_WAIT_TIME = 50000; // If the button is always not there, we wait at most 50 seconds.
  const CHECK_INTERVAL = 1000; // If the button is not there, we do the same check after 1 scond
  const buttonSelector = '#__next > main > div > div.MomentHistory_moment-history__inner__a9etG > button';

  // Initially finding the button
  const button = document.querySelector(buttonSelector);
  if (button) {
    button.click();
    console.log('Found the button and clicked');
  } else {
    console.log('No Load button at all');
    return
  }

  // 当前已等待的时间
  let elapsedTime = 0;

  // 定时器开始循环查找,立即获得 intervalId
  const intervalId = setInterval(() => {
    elapsedTime += CHECK_INTERVAL;

    // Searching the Load button
    const retryButton = document.querySelector(buttonSelector);
    if (retryButton) {
      retryButton.click();
      elapsedTime = 0
      console.log('Found the button and clicked');
    } else {
      console.log('Could not find the button, continue searching...');
    }

    // If we could no longer find the button in MAX_WAIT_TIME, we know the work has been done.
    if (elapsedTime >= MAX_WAIT_TIME) {
      console.error('Could not find the button any more, stopping....');
      clearInterval(intervalId); // Stop the interval
    }
  }, CHECK_INTERVAL); // check if we can find the button every second
})()

Second, extract the data into a JSON object from the long page we get by clicking the Load button again and again by the script above

const diaryEntries = [];
const listItems = document.querySelectorAll('.MomentListItem_moment-list__item__d5UJL');

// Helper function:Convert date into yyyy-MM-dd format
function formatDate(dateString) {
    const months = {
        January: "01", February: "02", March: "03", April: "04", May: "05", June: "06",
        July: "07", August: "08", September: "09", October: "10", November: "11", December: "12"
    };
    const [month, day, year] = dateString.split(" ");
    return `${year}-${months[month]}-${day.padStart(2, '0')}`;
}

listItems.forEach(item => {
    const dateElement = item.querySelector('.MomentListItem_moment-item__date__XfMA8');
    const contentElement = item.querySelector('.MomentListItem_moment-item__text__F5V2C > p');
    const photoElement = item.querySelector('.MomentImage_root__uLWy7 img');
    const videoElement = item.querySelector('.MomentListItem_moment-item__video__16FUa video');

    const entry = {
        pdate: dateElement ? formatDate(dateElement.textContent.replace('Posted ', '').trim()) : null,
        content: contentElement ? contentElement.textContent.trim() : '',
        photo: ''
    };

    if (photoElement) {
        entry.photo = photoElement.getAttribute('src');
    } else if (videoElement) {
        const thumbnail = videoElement.getAttribute('poster');
        entry.photo = thumbnail ? thumbnail.trim() : '';
    }

    diaryEntries.push(entry);
    diaryEntries.reverse(); // make sure the old data is at the beginning
});

Third, send the moments data to HappyNotes by the following script

// Your personal token
const token = "eyJh...";

// API endpoint
const apiUrl = "https://happynotes-api.shukebeta.com/note/post";

// Function to send a note
async function sendNote(note) {
    const contentWithPhoto = note.photo 
        ? `${note.content}\n\n ![image](${note.photo})`
        : note.content;

    const payload = {
        isprivate: true,
        isMarkdown: true,
        publishDateTime: note.pdate,
        timezoneId: "Pacific/Auckland",
        content: contentWithPhoto
    };

    try {
        const response = await fetch(apiUrl, {
            method: "POST",
            headers: {
                Authorization: `Bearer ${token}`,
                "Content-Type": "application/json"
            },
            body: JSON.stringify(payload)
        });

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        console.log(`Note sent successfully: ${await response.text()}`);
    } catch (error) {
        console.error(`Error sending note: ${error.message}`);
    }
}

// Send notes one by one
(async () => {
    var date = ''
    var minutes = '00'
    for (const note of diaryEntries) {
        if (note.pdate != date) {
           date = note.pdate
           minutes = '00'
        } else {
           minutes = (+minutes + 10) + ''
        }
        note.pdate += ` 20:${minutes}:00`
        await sendNote(note);
    }
})();

You need to get the token by manually login. Don't share the token to anyone else! Anyone who gets the token can access your account and data. Follow the following steps to get your personal token.

Open the DevTools on Chrome or Firefox, then do a fresh login.

image

Solving AutoMapper Errors When Mapping Fields That Don't Exist in the Target Class

When working with AutoMapper, you may encounter errors when trying to map properties from a source object to a target object, especially if the source contains properties that don't exist in the target. This is a common pitfall, but it’s easy to resolve once you understand the root cause.

The Issue:

Consider the scenario where we have a PostNoteRequest class containing two new fields: PublishDateTime and TimezoneId. These fields are necessary for calculating the CreatedAt property of the target Note class, but the Note class doesn’t have PublishDateTime or TimezoneId at all.

Here’s a typical AutoMapper mapping that results in an error:

CreateMap<PostNoteRequest, Note>()
    .ForMember(m => m.CreatedAt, _ => _.MapFrom((src,dst) =>
    {
        // Logic to calculate CreatedAt based on PublishDateTime and TimezoneId
    }));

Even though we're calculating CreatedAt based on the source properties, AutoMapper will try to map PublishDateTime and TimezoneId directly from the source to the target, resulting in an error like this:

Error mapping types.
Mapping types:
PostNoteRequest -> Note
HappyNotes.Models.PostNoteRequest -> HappyNotes.Entities.Note

The issue arises because AutoMapper expects all properties mentioned in the MapFrom expression to exist in both the source and target objects.

The Cause:

AutoMapper doesn't know how to handle fields (PublishDateTime and TimezoneId) that don’t exist in the target class (Note). The moment we reference these fields directly in the delegate passed to MapFrom, AutoMapper assumes they need to be mapped.

The Solution:

To solve this, we have two main approaches:

1. Use a Custom Value Resolver

A custom value resolver allows us to decouple the logic of calculating CreatedAt from the mapping process. It ensures that we don't reference non-existent fields in the target object.

public class CreatedAtResolver : IValueResolver<PostNoteRequest, Note, long>
{
    public long Resolve(PostNoteRequest source, Note destination, long member, ResolutionContext context)
    {
        if (!string.IsNullOrWhiteSpace(source.PublishDateTime) && !string.IsNullOrWhiteSpace(source.TimezoneId))
        {
            return DateTime.UtcNow.ToUnixTimeSeconds();
        }
        
        var dateStr = source.PublishDateTime;
        if (dateStr.Length == 10) dateStr += " 20:00:00";

        DateTime date = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
        TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(source.TimezoneId);

        return TimeZoneInfo.ConvertTime(new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Unspecified), timeZone).ToUnixTimeSeconds();
    }
}

// In your mapping configuration
CreateMap<PostNoteRequest, Note>()
    .ForMember(m => m.CreatedAt, opt => opt.MapFrom<CreatedAtResolver>());

This approach encapsulates the logic for CreatedAt calculation in a resolver, which avoids directly referencing PublishDateTime or TimezoneId in the target object.

2. Use ConstructUsing for Manual Construction

Another way to handle this is by manually constructing the target object in the ConstructUsing method, ensuring CreatedAt is set correctly without relying on AutoMapper’s default property mapping behavior.

CreateMap<PostNoteRequest, Note>()
    .ForMember(m => m.CreatedAt, opt => opt.MapFrom((src, dst) =>
    {
        var dateStr = src.PublishDateTime;
        if (dateStr.Length == 10) dateStr += " 20:00:00";
        
        DateTime date = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
        TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(src.TimezoneId);
        
        return TimeZoneInfo.ConvertTime(new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Unspecified), timeZone).ToUnixTimeSeconds();
    }))
    .AfterMap((src, dst) =>
    {
        dst.Tags = string.Join(" ", dst.TagList);
        dst.Content = dst.IsLong ? src.Content.GetShort() : src.Content;
    });

This method allows you to explicitly handle the CreatedAt logic while avoiding AutoMapper’s attempt to map non-existent properties from the source object.

Conclusion:

AutoMapper is a powerful tool, but it expects the properties referenced in its mapping expressions to exist in both the source and target objects. When you need to perform custom logic (like calculating CreatedAt based on other properties), using custom value resolvers or manual construction can help you avoid errors and maintain clear and maintainable code.

By understanding how AutoMapper expects the mapping to work, you can prevent issues related to missing properties and ensure your mappings are both efficient and correct.

书摘: 人间相亲故事

2024-06-14 18:05:45 毕业后的恋爱里,女友有次幽怨地说,她期待的是回家时有一盏为她亮着的灯。于是,他毅然放弃了深圳的稳定工作来到广州,从零开始打拼。但爱情的甜蜜期很快过去,女友开始天天计算着工资和房价,

2024-06-13 15:37:39 他曾经奋不顾身的浪漫变成了鲁莽、冲动和毫无计划…… 注: 怎么说呢,这话又对又不对。这话有理,但谁说都不违和,可从那个人嘴里说出来就好没理。

2024-06-13 15:39:37 他原本“希望与对方有话题可以聊,价值观至少要匹配”,但一年下来却发现,“很难找到能好好说话的人”。

2024-06-13 20:09:38 小林是他的初恋女友,也是他的情感启蒙老师。29岁的陆昱辰,像新生儿颤巍巍地迈出了第一步——跨进了一个没有爸妈、只有他和小林的平行空间。他们一起度过了将近一年的时光,逛遍了彼此都很熟悉的北京、看遍了新上线的电影,还去丽江等地旅行。他们也吵架,又和好。他们谈论朋友,讨论工作,唯独不谈论未来。

2024-06-14 08:35:31 我远远地看着,看东子和一个刚刚认识两天的姑娘结婚。我远远地看着,看东子和一个刚刚认识两天的姑娘结婚。

2024-06-14 08:43:00 我远远地看着。看东子和一个刚刚认识两天的姑娘,并排站在装饰得极浪漫温馨的礼台中央,表白、宣誓、拥抱、互换婚戒,相视而立,亲友哄笑着把两个人的脸颊贴在一起,他们也各自捆绑住了彼此始料未及的今生。

书摘:毛澤東私人醫生回憶錄

2024-01-14 17:00:37
帝王權勢讓帝王享有最大的奢侈──生活簡單。毛大部分的時間要不在床上,要不在私人游泳池旁休憩。

2024-01-14 17:05:31
毛告訴李醫生,美國對中國的企圖一向具有正面意義。

2024-01-14 17:11:36
毛發展的理想失敗了。但在這個他所毀滅的國家中,他握有絕對權力。

2024-01-14 17:17:13
此書給我們另一種教訓。它描述過度膨脹的權力,如何驅策其擁有者進入一種黑暗的深淵:在深淵中,偉大的夢想只能導致滔天罪行。

2024-01-14 18:20:00
雪泥鴻爪

2024-01-14 18:21:33
一九八九年三月,我點檢行篋,取出了舊記和帶來的全部資料,開始了寫作生活。這一方面是對嫻的永久的紀念。另一方面,身在美國,就可以將這些年的所見所聞,秉筆直書,無需避諱,加以發表。如果讀過這本書以後,讀者能夠更加珍惜自己的理想和所嚮往的幸福的生活,那將是我和嫻多年來的最大願望。

2024-01-14 18:25:33
對蔣介石,雖然終生為敵,但並不持完全否定的態度。他認為蔣有強烈的民族自尊心,不俯首貼耳聽命於美國。

2024-01-14 18:29:26
寮國領袖凱山的合照

…more