Blog

  • ABC 新闻举报人透露哈里斯提前收到辩论问题,现已死于车祸

    Breaking: The ABC News whistleblower whorevealed Kamala Harris was given the debatequestions in advance has DlED in an auto accident
    The crash happened early on the morning ofSeptember 13 outside Bethesda #Maryland

    突发消息:ABC新闻举报人揭露卡马拉·哈里斯提前收到辩论问题,现已在车祸中丧生事故于9月13 日凌晨发生在贝塞斯达郊外#Maryland


    据日本电视台报道,7日上午,一名52岁男性在东京都品川区的都营地下铁浅草线的中延车站跳轨身亡。经警方确认,死者为日本奥林匹克委员会(JOC)会计部部长森古靖。

    7日,日本奥组委会计部部长森古靖跳轨身亡。可能是因为日本奥运会腐败严重,而会计部部长背锅死了

    据警方透露,森古靖在遭地铁列车撞击后虽然很快被送往医院救治,但仍在2小时后不治身亡。


  • Eredis:Redis 与 Emacs 的完美邂逅!😇

    Eredis 是一个 Emacs Lisp 客户端,专门为 Redis 内存数据结构商店而生。它就像一封写给 Redis 和 Emacs 的情书,将这两个强大的工具完美地连接在一起。

    为什么选择 Eredis? 🤔

    想象一下,你正在调试应用程序,需要查看 Redis 数据库中的数据。如果能直接在 Emacs 中使用强大的功能来操作 Redis,那该多棒!Eredis 让这一切成为现实。

    Eredis 是你的 Redis 万能工具箱:

    • 调试: Eredis 让你可以使用熟悉的 Emacs 缓冲区来检查 Redis 数据,提供了一个丰富的环境,方便你进行分析和探索。
    • 监控: 借助 Eredis,你可以将 Emacs 打造成实时监控工具。想象一下,用 Org-mode 创建一个从 Redis 数据库中获取的键值对表格,然后用 Lively.el 定期更新它。
    • 数据处理: Eredis 允许你使用强大的 Emacs Lisp 函数对 Redis 数据进行迭代和归约。这为数据分析和操作打开了无限可能。
    • 脚本编写和测试: 充分利用 Emacs Lisp 的强大功能,为你的应用程序创建测试数据或模拟用户行为。

    入门非常简单: 💨

    1. 从 Melpa 安装 Eredis 或从 Github 克隆它。
    2. 使用 Docker 运行本地 Redis 实例。 Eredis 附带了方便的脚本,可以帮助你设置两个实例,一个在端口 6380 上,另一个在默认端口 6379 上。这样你就可以从 Emacs 连接到多个 Redis 服务器。

    连接到 Redis: 🔌

    每个 Redis 连接都会创建一个独立的 Emacs 进程。要建立连接,请使用 eredis-connect

    (require 'eredis)
    (setq rp (eredis-connect "localhost" 6379))
    (setq rp2 (eredis-connect "localhost" 6380))

    返回值是一个进程对象。你可以将此对象作为大多数 Eredis 命令的最后一个参数传递,指定要连接的 Redis 实例。如果你省略了进程参数,Eredis 会默认使用最后一个打开的连接。

    基本命令:

    假设你的应用程序将用户登录时间存储为 user:ID 格式的键,并将时间戳作为值。我们可以设置两个同时登录的用户,分别在两个实例中:

    (eredis-set "user:61" "1542084912" rp)
    (eredis-set "user:62" "1542084912" rp2)

    现在让我们检查数据是否存储正确:

    (eredis-get "user:61" rp)
    (eredis-get "user:62" rp2)

    每个 Redis 命令都会通过 process-send-string 发送到网络。然后,Redis 的响应会发送到与该进程关联的 Emacs 缓冲区。这让你可以查看与 Redis 的通信历史记录,对于调试非常有用。

    Lolwut? 🤪

    Redis 5 版本引入了一个有趣的新命令 LOLWUT。它会生成随机的盲文艺术!Eredis 支持此命令,你可以使用 eredis-lolwut 在 Emacs 缓冲区中显示艺术作品。

    多字节字符串处理: 🌎

    Eredis 可以优雅地处理多字节字符串。它会在多字节字符串和单字节字符串之间进行转换,以确保解析器能够正常工作,无论你使用何种编码。

    Org-mode 集成: 📝

    Eredis 与 Org-mode 无缝集成,让你可以轻松地在 Org 文件中管理 Redis 数据。你可以从 Redis 数据创建 Org 表格,并直接在表格中编辑值。Eredis 会将更改推送到 Redis。

    数据处理: 📊

    Eredis 提供了强大的函数,可以使用 SCAN 命令对 Redis 数据进行迭代和归约。这样你就可以执行复杂的数据处理任务,而不会给 Redis 服务器带来过大的负担。

    下一步计划: 🚀

    Eredis 不断发展,计划支持 stream.el 来实现惰性序列,增强 Org-mode 集成,并添加更多功能。

    Eredis 是 Emacs Lisp 强大灵活性的证明。它是一个工具,可以让你使用 Redis 的旅程更加顺畅、高效,甚至更有趣。

  • CL-REDIS:Redis 的 Common Lisp 冒险之旅 🗺️

    CL-REDIS 就像一个探险家,带着你深入 Redis 的世界,探索数据存储的奥秘。它是一个快速、可靠的 Common Lisp 客户端,让你可以轻松地与 Redis 服务器进行交互。想象一下,它就像一个经验丰富的向导,带着你穿越 Redis 的广阔领域,为你提供所有你需要探索和管理数据的工具。 🧭

    快速入门:准备出发 🥾

    在你开始你的 Redis 冒险之旅之前,你需要准备一些必需品。首先,确保你有一台正在运行的 Redis 服务器。然后,使用 ql:quickload 'cl-redis 加载 CL-REDIS 库。就像在你的背包里装满地图和指南针一样。

    接下来,你需要连接到 Redis 服务器。你可以使用 (redis:connect :host <host> :port <port>) 函数来建立连接。默认情况下,host127.0.0.1port6379。就像找到你探险的起点一样。

    现在,你可以使用 red 包中的 Redis 命令来与服务器进行交互了。例如,你可以使用 (red:ping) 命令测试连接。就像向你的向导打招呼一样。

    完成你的探险之后,你可以使用 (redis:disconnect) 函数断开连接。或者,你可以使用 with-connection 宏,它会自动为你打开和关闭连接。就像在你的探险结束后,回到你的出发点一样。

    可用命令:你的探险工具箱 🧰

    CL-REDIS 提供了大量的 Redis 命令,让你可以执行各种操作,包括:

    • 字符串操作: SETGETAPPENDINCRDECR 等。就像在你的探险中,记录你的发现和修改你的笔记一样。
    • 哈希操作: HSETHGETHDELHGETALL 等。就像在你的探险中,收集和整理各种信息一样。
    • 列表操作: LPUSHRPUSHLRANGELREM 等。就像在你的探险中,收集和整理各种信息一样。
    • 集合操作: SADDSMEMBERSSISMEMBERSREM 等。就像在你的探险中,收集和整理各种信息一样。
    • 排序集操作: ZADDZRANGEZSCOREZREM 等。就像在你的探险中,收集和整理各种信息一样。
    • 事务操作: MULTIEXECDISCARD 等。就像在你的探险中,执行一系列操作,并确保它们按顺序完成一样。
    • 发布订阅操作: PUBLISHSUBSCRIBEUNSUBSCRIBE 等。就像在你的探险中,与其他探险者进行交流一样。

    代码组织:你的探险地图 🗺️

    CL-REDIS 提供了两个包:REDISRED。所有功能都可以在 REDIS 包中使用。为了避免符号冲突,Redis 命令在这个包中定义时,会加上一个前缀(默认情况下为 red-,在编译时设置)。 RED 包是语法糖,它只是提供了没有前缀的 Redis 命令。因此,它不建议导入,以避免与 COMMON-LISP 包发生符号冲突。你只需要使用包限定的符号名称即可。例如,同一个 Redis 命令(例如 GET)可以调用为 RED-GET(如果你导入了 REDIS 包)或 RED:GET

    安装:准备你的装备 🎒

    CL-REDIS 可通过 quicklisp 获取。它依赖于以下几个库:

    调试和错误恢复:你的探险指南 🧭

    如果 *echo-p*T,所有客户端-服务器通信将被回显到 *echo-stream* 流中,默认情况下为 *standard-output*

    错误处理模仿了 Postmodern。特别是,当发生错误导致通信流中断时,会发出 redis-connection-error 类型的条件,提供一个 :reconnect 重启。如果选择它,整个 Redis 命令将被重新发送,如果重新连接尝试成功。此外,connect 检查是否已经建立了与 Redis 的连接,如果已经建立,则提供两个重启(:leave:replace)。

    当服务器响应错误回复(即以 - 开头的回复)时,会发出 redis-error-reply 类型的条件。

    还有一个高级的 with-persistent-connection 宏,它会尽力做到正确的事情™(即在连接断开后自动重新打开连接一次)。

    高级用法:你的探险技巧 🧗‍♀️

    发布订阅

    由于没有专门的命令通过发布订阅从 Redis 接收消息,你可以使用以下方法:

    (bt:make-thread (lambda ()
                      (with-connection ()
                        (red:subscribe "foo")
                        (loop :for msg := (expect :anything) :do
                          (print msg))))
                    "pubsub-listener")

    要发布消息,可以使用以下方法:

    (with-connection ()
      (red:publish "foo" "test"))

    管道

    为了提高性能,Redis 允许对命令进行管道化,并延迟接收结果,直到最后再批量处理。CL-REDIS 提供了 with-pipelining 宏来支持管道化。比较以下示例中的执行时间(使用管道和不使用管道):6.567 秒 vs. 2023.924 秒!

    (let ((names (let (acc)
                   (dotimes (i 1000 (nreverse acc))
                     (push (format nil "n~a" i) acc))))
          (vals  (let (big-acc)
                   (dotimes (i 1000 (nreverse big-acc))
                     (let (acc)
                       (dotimes (i (random 100))
                         (push (list (random 10) (format nil "n~a" i)) acc))
                       (push (nreverse acc) big-acc))))))
      (time (redis:with-connection ()
              (redis:with-pipelining
                (loop :for k :in names :for val :in vals :do
                  (dolist (v val)
                    (apply #'red:zadd k v)))
                (red:zunionstore "result" (length names) names)
                (red:zrange "result" 0 -1))))
    
      ;; Evaluation took:
      ;;  6.567 seconds of real time
      ;;  3.900243 seconds of total run time (3.200200 user, 0.700043 system)
    
      (time (redis:with-connection ()
              (loop :for k :in names :for val :in vals :do
                (dolist (v val)
                  (apply #'red:zadd k v)))
              (red:zunionstore "result" (length names) names)
              (red:zrange "result" 0 -1))))
    
      ;; Evaluation took:
      ;; 2023.924 seconds of real time
      ;; 3.560222 seconds of total run time (2.976186 user, 0.584036 system)

    请注意,with-pipelining 调用理论上可以嵌套,但结果只对最高级别的管道可用,所有嵌套的管道将返回 :PIPELINED。因此,在这种情况下会发出警告。

    内部机制:你的探险指南 🗺️

    通用函数 tellexpect 根据 规范 实现 Redis 协议。tell 指定了 Redis 请求的格式,expect 指定了响应的处理方式。实现 expect 上另一种方法的最佳方式通常是使用 def-expect-method,它会安排从套接字读取数据,并提供一个 reply 变量,该变量保存从服务器解码的回复数据,并删除了初始字符。例如:

    (def-expect-method :ok
      (assert (string= reply "OK"))
      reply)

    Redis 操作通过 def-cmd 定义为普通函数,只需要提供参数和返回类型。def-cmd 将所有定义的函数名称加上 *cmd-prefix* 前缀,默认情况下为 'red。(请注意,设置 *cmd-prefix* 将在编译时生效)。它还将它们从 REDIS 包导出,并从 RED 包导出,但不带前缀。

    下面是一个命令定义的示例:

    (def-cmd KEYS (pattern) :multi
      "Return all the keys matching the given pattern.")

    请参阅 commands.lisp 查看所有定义的命令。

    未实现的功能:你的探险计划 🗺️

    • 以下命令未实现,因为它们不打算在客户端使用:MONITORDEBUG OBJECTDEBUG SEGFAULT
    • Unix 域套接字支持 – 已计划
    • 一致性哈希 未内置。实际上,这种东西与该库的功能是正交的,可能应该在另一个库中实现。
    • 连接池也没有实现,因为在存在 with-persistent-connection 的情况下,它实际上并不那么需要。持久连接对于专用线程来说更简单、更高效,而且错误更少。但是,连接池还有其他用例,因此它可能会在将来的版本中实现。

    致谢:你的探险伙伴 🤝

    该库由 Vsevolod Dyomkin vseloved@gmail.com 开发和维护。

    在最初阶段,Alexandr Manzyuk manzyuk@googlemail.com 开发了连接处理代码,遵循了 Postmodern 中的实现。后来,它被部分重写,以适应更高级的连接处理策略,例如持久连接。

    许可证:你的探险指南 🧭

    MIT(有关详细信息,请参阅 LICENSE 文件)。

    https://github.com/vseloved/cl-redis/raw/refs/heads/master/README.md

  • Hunchentoot:你的 Common Lisp 网页服务器探险之旅 🗺️

    Hunchentoot 就像一把瑞士军刀,专为 Common Lisp 网页开发者打造。它既是网页服务器,也是构建动态网站的工具箱。想象一下,它就像森林里的一间舒适小屋,随时准备接待你的网页应用,并提供所有你需要构建熊熊烈火和美味数字内容的工具。 🏕️🔥

    下载和安装:快速去商店一趟 🛒

    在你开始构建你的网页杰作之前,你需要收集一些物资。Hunchentoot 依赖于几个其他 Common Lisp 库,比如可靠的 MD5 用于安全,CL-BASE64 用于编码,以及 RFC2388 用于处理网页协议。就像为你的网页服务器准备了一个储备充足的食品储藏室。

    别担心,你可以很容易地从互联网上获取所有这些库。如果你想尝试更刺激的体验,还可以尝试一下 Quicklisp,这是一个方便的工具,可以帮助你管理 Common Lisp 依赖项。就像为你的网页服务器配备了一个私人采购员! 📦

    运行 Hunchentoot:启动引擎 💨

    现在你已经拥有了所有食材,是时候启动引擎了。你可以用一行代码启动一个基本的 Hunchentoot 服务器:

    (hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 4242))

    这将在端口 4242 上启动一个监听服务器。然后,你可以在浏览器中输入 http://127.0.0.1:4242/ 来访问它。就像打开你舒适小屋的门,欢迎访客一样。 🚪

    构建你的网页应用:添加家具和装饰 🛋️

    默认情况下,Hunchentoot 会从其源代码树中的 www/ 目录提供文件。想象一下,这就像你的空旷小屋,准备让你用自己的网页内容装饰。你可以使用 ACCEPTOR-DOCUMENT-ROOTACCEPTOR-ERROR-TEMPLATE-DIRECTORY 设置来定制文档根目录和错误模板目录的位置。

    想要为你的网页应用添加一些交互元素吗?Hunchentoot 提供了一个易于使用的框架来创建处理程序。你可以使用 DEFINE-EASY-HANDLER 宏来定义处理程序,它允许你创建响应特定请求的函数。就像在你的小屋里添加一张舒适的沙发和一个熊熊燃烧的壁炉一样。 🛋️🔥

    以下是一个简单的处理程序示例,它向访客说“你好”:

    (hunchentoot:define-easy-handler (say-yo :uri "/yo") (name)
      (setf (hunchentoot:content-type*) "text/plain")
      (format nil "Hey~@[ ~A~]!" name))

    现在,如果你在浏览器中访问 http://127.0.0.1:4242/yo,你将看到“你好!”。如果你访问 http://127.0.0.1:4242/yo?name=Dude,你将看到“你好,Dude!”。就像用友好的“你好!”来迎接你的客人一样。 👋

    Hunchentoot 位于代理服务器之后:添加一个门廊 🚪

    如果你对将你的网页应用暴露在狂野的互联网中感到有点害羞,你可以把它隐藏在一个代理服务器之后。想象一下,这就像在你的小屋前添加一个门廊,提供一层保护和隐私。

    一种常用的方法是使用 Apache 的 mod_proxy 模块。你可以配置它,将请求隧道到在特定端口上运行的 Hunchentoot 服务器。就像有一个友好的邻居为你开门一样。

    接受者:你的网页服务器的守门人 👮‍♀️

    接受者是你的 Hunchentoot 网页服务器的守门人。它们负责监听传入连接和处理请求。想象一下,它们就像你小屋里的友善员工,欢迎访客并确保一切顺利运行。

    Hunchentoot 提供了几种类型的接受者,包括标准的 ACCEPTOR 和用于安全连接的 SSL-ACCEPTOR。你可以通过子类化 ACCEPTOR 类并专门化定义其行为的通用函数来定制接受者的行为。就像在你的小屋的运作方式中添加你自己的个人风格一样。

    会话:跟踪你的访客 👤

    会话允许你跟踪你的访客和他们在你的网页应用上的活动。想象一下,它们就像一本留言簿,你可以记录谁来过你的小屋以及他们做了什么。

    Hunchentoot 提供了自动会话处理的功能,既有使用 cookie 的,也有不使用 cookie 的。你可以通过专门化相应的通用函数来定制会话行为。就像在与你的客人互动的方式中添加个性化的风格一样。

    日志记录:记录事件 📝

    日志记录对于理解你的网页应用的性能和排查任何问题至关重要。想象一下,它就像记录你小屋所有活动的一本日记。

    Hunchentoot 提供了访问和消息的日志记录功能。你可以通过设置 ACCEPTOR-ACCESS-LOG-DESTINATIONACCEPTOR-MESSAGE-LOG-DESTINATION 设置来定制日志记录行为。就像拥有一本日记,你可以记录你小屋的所有重要事件一样。

    错误处理:处理意外的客人 🚨

    即使是构建最好的网页应用,也可能会遇到意想不到的问题。这就是错误处理的用武之地。想象一下,它就像有一个计划来处理可能出现在你小屋的意外客人。

    Hunchentoot 提供了可定制的错误处理机制,允许你优雅地捕获和处理错误。你可以定义错误模板,为你的访客提供信息丰富的消息。就像为你的网页服务器准备了一个储备充足的急救箱一样。

    第三方插件:扩展你的小屋 🏘️

    Hunchentoot 是一款流行的网页服务器,有许多第三方库和框架可以扩展其功能。想象一下,它们就像你小屋的附加部分,比如一个舒适的秋千或一个宽敞的客房。

    一些流行的插件包括 Clack,一个可以与 Hunchentoot 一起使用的网页服务器抽象层,以及 hunchentoot-cgi,它为 Hunchentoot 提供 CGI 处理程序。还有一些框架,比如 RESTASCavemanRadianceSnooze,它们与 Hunchentoot 兼容。就像有一群朋友可以帮助你建造和维护你的小屋一样。

    结论:Hunchentoot – 你的 Common Lisp 网页服务器探险之旅 🏕️

    Hunchentoot 是一款功能强大且用途广泛的网页服务器,它为在 Common Lisp 中构建动态网站提供了坚实的基础。它就像森林里的一间舒适小屋,随时准备让你根据自己的喜好进行定制和装饰。所以,拿起你的工具,收集你的物资,开始构建你自己的网页杰作吧!

    参考文献:

    • Hunchentoot – The Common Lisp web server formerly known as TBNL (https://edicl.github.io/hunchentoot/)
    • Quicklisp (https://www.quicklisp.org/)
    • Clack (https://github.com/clack/clack)
    • hunchentoot-cgi (https://github.com/cyrus-harmon/hunchentoot-cgi)
    • RESTAS (https://github.com/edicl/restas)
    • Caveman (https://github.com/edicl/caveman)
    • Radiance (https://github.com/edicl/radiance)
    • Snooze (https://github.com/edicl/snooze)
    • Weblocks (https://github.com/weblocks/weblocks)
  • 🌪️ A股高管离职潮:金融业的人事大洗牌

    在这个金秋九月,A股市场掀起了一股令人瞠目结舌的高管离职潮。就像是一场突如其来的台风,席卷了整个金融界,让人不禁感叹:这些高管们是不是觉得中秋节放假太短,干脆来个长假?

    🏦 银行业:大象也会跳舞?

    让我们先来看看银行业这个”大象”。要知道,银行向来给人一种稳如泰山的印象。可是,这次的离职潮,却让这头大象跳起了华尔兹。

    从8月1日开始,仿佛有人按下了某个神秘的按钮,各大银行的高管们纷纷提交了辞呈。常熟银行、江阴银行、浙商银行,甚至是中国银行,都未能幸免。这场离职潮,就像是一场精心设计的多米诺骨牌表演,一个接一个,让人目不暇接。

    更有趣的是,这股风潮不仅吹倒了高管们,连普通员工也被卷入其中。据统计,今年上半年,全国42家主流银行的员工总数减少了约6万人。这是怎么回事?难道是银行突然决定大家一起去度假?

    其实,背后的原因可能没那么美好。银行业正面临着前所未有的压力。虽然大部分银行的营收和利润还在增长,但速度明显放缓,净息差也在下降。这就像是一个胖子,虽然体重还在增加,但增速却慢了下来,让人不得不担心他的”健康状况”。

    💼 券商业:到年纪的”同龄人”们的集体告别派对?

    再来看看券商业,这个离职潮就像是一场精心策划的”退休派对”。从8月底到9月初,财通证券、华林证券、西南证券等多家券商的高管们纷纷宣布退休或因个人原因离职。

    有趣的是,这些离职的高管们年龄都非常相近,就像是一群”同龄人”约好了一起退休似的。这让人不禁想象,他们是不是在某个高尔夫球场上一边打球一边商量:”老兄,咱们干脆一起退休吧,反正都这把年纪了。”

    实际上,这个现象与我国证券业的发展历程密切相关。90年代,证券业刚刚起步,这些高管们大多是那时入行的。30年过去了,他们就像是一起参加了一场马拉松,现在终于到了终点线。

    🎭 其他行业:一场风险与责任的躲猫猫游戏?

    除了金融业,其他行业的高管离职也不少。有的是因为公司业绩不佳,有的是因为涉及风险,还有的可能只是想换个环境。

    这让人联想到小时候玩的躲猫猫游戏。有些高管似乎认为,只要自己躲起来(辞职),就能避开所有的责任和风险。但事实真的如此吗?

    监管部门显然不这么认为。他们明确表示,对于那些试图通过辞职来逃避责任的行为,将会一查到底。这就像是在告诉那些想玩躲猫猫的高管们:”别躲了,我们能看到你!”

    🔍 离职潮背后:市场的无形之手在作祟?

    那么,究竟是什么原因导致了这场离职潮呢?是单纯的巧合,还是有更深层次的原因?

    事实上,这场离职潮反映了当前市场环境的复杂性和严峻性。金融行业面临着前所未有的挑战,从监管政策的收紧到市场竞争的加剧,再到科技创新带来的冲击,都在推动着行业的变革。

    这就像是一场大型的”音乐椅”游戏。音乐停止时,每个人都在寻找自己的位置。有些人选择离开,有些人选择调整,而有些人则在寻找新的机会。

    🔮 未来展望:变革中的新机遇

    尽管眼下的离职潮看似令人担忧,但它也可能是行业变革和创新的前奏。就像是春天来临前的一场大扫除,为新的成长腾出空间。

    对于那些留下来的高管和即将上任的新血液来说,这无疑是一个充满挑战和机遇的时代。他们需要以新的视角和思维来应对市场的变化,推动企业的创新和发展。

    总的来说,这场离职潮虽然看似混乱,但可能正是市场自我调节和优化的过程。就像是大自然中的生态系统,通过不断的变化和适应,最终达到新的平衡。

    让我们拭目以待,看看这场离职潮过后,A股市场会呈现出怎样的新面貌。毕竟,在每一个挑战背后,都潜藏着新的机遇。

    📚 参考文献

    1. 蓝鲸财经. (2023). 上市公司财总异动:传音控股财总被留置,9天12位财总辞职.
    2. 央广网. (2023). 五大行高管今年频繁辞职分析人士称与限薪无关.
    3. 中国青年报. (2023). 透视A股公司董监高离职潮.
    4. 时代财经. (2023). 业绩承压,光伏行业再现”离职潮”,有高管年薪400万.
    5. 财联社. (2023). 一代人落幕,券商高管退休高峰年,效力20年,华西证券副总经理祖强到龄退休.

    🤔 资本市场“离职潮”:是“战略调整”还是“另谋高就”?

    近来,金融界高管的密集离职,引发了市场广泛关注。有人说,这是他们对中国金融体系的信心不足,有人说,这是他们对未来发展方向的重新思考。究竟是“战略调整”还是“另谋高就”?这场“离职潮”背后,究竟隐藏着怎样的考量?

    🕵️‍♂️ “转型升级”的信号?

    “面对日益增长的市场竞争和监管压力,他们或许正在寻求新的发展机遇。”“他们可能认为,目前的职位已经无法满足他们的职业发展目标,因此选择离开,去寻找更广阔的天地。”

    这些话语,如同市场上的风向标,指向了金融界高层对未来发展的思考。他们掌握着金融命脉,对市场最为敏感,能感知到最深层次的趋势变化。地方债务、房地产泡沫、影子银行、兑付危机……这些潜在的风险,如同暗流涌动,需要他们做出更深层的思考。

    🤔 “战略调整”的考量?

    “他们或许正在寻求新的发展方向,或许正在筹划更具挑战性的项目。”“他们可能认为,目前的机构已经无法提供他们所需要的资源和平台,因此选择离开,去寻找更具潜力的机会。”

    当一些高管选择离开,这或许意味着他们正在进行“战略调整”,或许正在寻找更具发展潜力的领域。他们或许正在寻求新的挑战,或许正在寻求更广阔的发展空间。

    “离职潮”的背后:是市场调整还是个人选择?

    这场“离职潮”背后,究竟是市场调整还是个人选择?这或许是一个无法简单回答的问题。但有一点是肯定的,这场“离职潮”反映了中国金融体系的不断变化和发展。

    1. 市场竞争:

    金融市场竞争日益激烈,金融机构之间的竞争也更加激烈。高管们或许正在寻求更具竞争力的平台,以实现更大的发展。

    2. 监管压力:

    金融监管日益严格,金融机构面临着更大的监管压力。高管们或许正在寻求更符合监管要求的职位,以更好地适应市场环境。

    3. 个人发展:

    高管们或许正在寻求更具挑战性的职位,以实现更大的职业发展。他们或许正在寻求更符合自身发展目标的平台,以实现更大的成就。

    4. 机遇与风险:

    金融市场充满机遇和风险,高管们或许正在寻求更具潜力的机会,以获得更大的回报。

    5. 战略调整:

    金融机构或许正在进行战略调整,高管们或许正在寻求更符合机构发展战略的职位。

    🕵️‍♂️ “离职潮”的启示:

    这场“离职潮”给中国金融体系敲响了警钟。中国金融体系需要进行深刻的反思,需要进行全面的改革,需要加强监管,需要防范风险,需要建立更加健全的制度体系。

    1. 加强监管:

    加强对金融机构的监管,防范金融风险,维护金融市场秩序。

    2. 改革制度:

    改革金融体系的制度设计,完善金融市场监管体系,建立更加健全的金融风险防控机制。

    3. 完善法制:

    完善金融法律法规,建立更加完善的金融法制体系,为金融市场发展提供法律保障。

    4. 提升透明度:

    提升金融市场透明度,公开金融机构的财务信息,提高金融市场的透明度和可信度。

    5. 增强信心:

    增强市场信心,稳定金融市场预期,维护金融市场稳定。

    这场“离职潮”或许只是一个过渡,但它也可能是一个警醒。中国金融体系需要进行深刻的反思,需要进行全面的改革,才能迎接未来的挑战。


  • 舞动的世界:复杂适应系统的韵律

    🎭 序幕:宇宙的节拍

    在这个浩瀚无垠的宇宙中,从微观粒子到宏观天体,从单细胞生物到复杂的人类社会,似乎都在遵循着某种神秘的节奏。这种节奏不是简单的重复,而是一种复杂而又有序的舞蹈。今天,让我们一起探索这支宇宙之舞的奥秘——复杂适应系统的发展循环。

    🎵 第一乐章:同步之美

    想象一下,你正站在一片萤火虫栖息的森林里。起初,这些小精灵们各自为政,忽明忽暗。但随着时间的推移,奇妙的事情发生了:它们开始同步闪烁,仿佛整片森林在呼吸。这就是同步的魔力。

    在复杂适应系统中,同步是一个关键的起点。它代表着系统中各个元素开始协调一致,产生共振。就像一群人不约而同地开始鼓掌,最终形成整齐的掌声一样。这种同步并非偶然,而是系统内部相互作用的结果。

    数学上,我们可以用库拉莫托模型来描述这种同步现象:

    $\frac{d\theta_i}{dt} = \omega_i + \frac{K}{N}\sum_{j=1}^N \sin(\theta_j – \theta_i)$

    其中,$\theta_i$ 表示第 i 个振荡器的相位,$\omega_i$ 是其自然频率,K 是耦合强度,N 是振荡器总数。

    🌋 第二乐章:涌现的惊喜

    当系统达到一定程度的同步时,奇妙的事情开始发生了。就像水温升高到100度时突然沸腾一样,系统可能会突然展现出全新的、意想不到的特性。这就是我们所说的”涌现”。

    想象一下蚁群。每一只蚂蚁都只遵循简单的规则,但当成千上万只蚂蚁一起工作时,它们能够建造复杂的蚁巢,形成高效的觅食网络,甚至”计算”出最短路径。这种集体智慧就是涌现的绝佳例子。

    在人类社会中,我们也能看到类似的现象。比如,当足够多的人开始使用某种新的通讯工具时,突然间,一个全新的社交网络就”涌现”出来了。

    涌现性可以用以下公式来概括:

    $E = f(C_1, C_2, …, C_n) \neq \sum_{i=1}^n f(C_i)$

    其中 E 表示涌现的特性,$C_i$ 表示系统的组成部分,f 是一个非线性函数。这个公式告诉我们,整体的行为不仅仅是各部分行为的简单相加。

    🚫 第三乐章:抑制的智慧

    然而,生活从不是一帆风顺的。当新特性涌现后,系统往往会经历一个抑制阶段。这听起来可能有点消极,但实际上,抑制是系统保持平衡和避免失控的关键机制。

    就像人体的免疫系统会抑制过度的炎症反应,或者生态系统中捕食者会抑制猎物种群的过度增长一样,抑制作用确保系统不会”乐极生悲”。

    在经济学中,我们经常可以看到这种现象。当某个行业突然繁荣时(比如加密货币),往往会引来大量投机和泡沫。然后,市场的自我调节机制(或监管机构)会开始发挥抑制作用,使之回归理性。

    抑制过程可以用以下微分方程来描述:

    $\frac{dX}{dt} = rX(1 – \frac{X}{K}) – H(X)$

    其中 X 是系统的某个变量,r 是增长率,K 是环境承载力,H(X) 是抑制函数。

    🔄 第四乐章:解同步的重生

    经过抑制阶段后,系统并不会简单地回到原点。相反,它会进入一个”解同步”阶段。这个阶段看似混乱,实则充满创新的可能性。

    想象一下交响乐团在演奏结束后的场景。乐手们不再整齐划一地演奏,而是各自调试乐器,尝试新的音符。这种”不和谐”正是为下一轮精彩演出做准备。

    在科技创新领域,我们经常可以看到这种现象。当一种技术范式达到顶峰后,行业可能会经历一段”混沌”期。但正是在这个时期,新的想法和方法会不断涌现,为下一次技术革命铺平道路。

    解同步可以用混沌理论中的著名方程——洛伦兹方程来描述:

    $\begin{cases}
    \frac{dx}{dt} = \sigma(y-x) \
    \frac{dy}{dt} = x(\rho-z) – y \
    \frac{dz}{dt} = xy – \beta z
    \end{cases}$

    这组方程展示了一个看似随机但实际上是确定性的系统,完美诠释了解同步阶段的特点。

    🌈 尾声:永不停息的圆舞曲

    就这样,复杂适应系统在同步、涌现、抑制和解同步之间不断循环,演绎着生命的华尔兹。这个过程不是简单的重复,而是螺旋式上升,每一次循环都带来新的高度和复杂性。

    从个人成长到公司发展,从科技进步到文明演化,我们都可以看到这个循环的影子。理解这个循环,不仅能帮助我们更好地认识世界,还能指导我们在生活和工作中做出更明智的决策。

    下次当你感到困惑或迷茫时,不妨想想你是否正处于这个循环的某个阶段。也许,你正在经历一个”解同步”的过程,为下一次的”同步”和”涌现”做准备呢?

    让我们以物理学家理查德·费曼的一句名言作为结束:

    “大自然的想象力远比人类丰富得多。”

    的确,在复杂适应系统的舞台上,大自然为我们上演了一场又一场精彩绝伦的演出。而我们,既是观众,也是演员。那么,准备好继续这场精彩的舞蹈了吗?

    参考文献

    1. Strogatz, S. H. (2003). Sync: The emerging science of spontaneous order. Hyperion.
    2. Holland, J. H. (2006). Studying complex adaptive systems. Journal of Systems Science and Complexity, 19(1), 1-8.
    3. Kauffman, S. A. (1993). The origins of order: Self-organization and selection in evolution. Oxford University Press.
    4. Mitchell, M. (2009). Complexity: A guided tour. Oxford University Press.
    5. Lorenz, E. N. (1963). Deterministic nonperiodic flow. Journal of the atmospheric sciences, 20(2), 130-141.
  • 踏入联邦宇宙:你的博客新家 🏡

    你拥有一个博客,一个美丽的小角落,在那里你分享你的想法、理念,甚至可能还有猫的照片。但你可能感觉有点…局促。你渴望更广泛的受众,更丰富的社区,一个让你的文字真正自由漫游的地方。

    别担心,我的朋友,联邦宇宙在等着你!

    想象一下,联邦宇宙是一个巨大的、相互连接的独立社交平台网络,它们都说着同一种语言:ActivityPub。这种神奇的语言可以让你的博客无缝地将更新广播到一个全新的读者世界,而无需离开你的 WordPress 仪表板。

    想象一下:你是一个热爱复古游戏的作家。你倾注了你的心血在你的博客上,分享着深刻的评论和怀旧的故事。你梦想着与其他复古游戏玩家建立联系,但你的博客感觉被困在它自己的小角落里。

    ActivityPub 来了!

    只需一个简单的插件,你的博客就变成了一个联邦个人资料,一个准备好与联邦宇宙中各种人群交往的数字大使。

    让我们来分解一下:

    • 你的博客变成了一个社交中心:你的网站,比如 example.com,变成了一个社交实体。你将在 @example.com@example.com 找到一个博客范围的个人资料,并且你博客上的每个作者都将获得他们自己的个人资料。Jane,你的驻场游戏专家,变成了 @jane@example.com
    • 关注我,关注我! 想象一下,你在 Mastodon(一个流行的联邦宇宙平台)上,偶然发现了一位复古游戏玩家,@pfefferle@mastodon.social。你点击“关注”,然后,砰!每当 @pfefferle 发布帖子时,它都会出现在你的信息流中。现在,想象一下:有人在 Mastodon 上找到了 Jane 的个人资料,@jane@example.com,并点击了“关注”。Jane 在 example.com 上写的每一篇博客文章都会神奇地出现在他们的 Mastodon 信息流中!
    • 声音的交响曲: 通过关注博客范围的个人资料,@example.com@example.com,你将收到来自所有作者的更新,你最喜欢的博客中令人愉快的各种声音。

    但等等,还有更多!

    • 选择的权利: 你可以选择连接到哪些平台,从 Mastodon 到 Pixelfed 到 Friendica,以及更多。
    • 达到新的高度: 你的博客文章现在可以触及超出你网站边界的大量受众。
    • 与你的读者互动: 直接在你的博客上从联邦宇宙用户那里接收评论和回复。

    准备好开始了吗?

    1. 安装 ActivityPub 插件: 只需点击一下!
    2. 配置你的设置: 根据你的喜好调整插件,确保你的博客的作者个人资料页面处于活动状态。
    3. 加入联邦宇宙: 在 Mastodon 等平台上创建一个个人资料,并关注你的博客的个人资料。
    4. 发布一篇新帖子: 看着你的博客帖子神奇地出现在你的联邦宇宙信息流中!

    记住: 你的帖子可能需要几分钟才能出现在你的联邦宇宙信息流中,因为消息是使用延迟的 cron 发送的。别担心,你的帖子会到达,就像你最喜欢的复古游戏中精心安排的存档点一样。

    所以,你在等什么? 加入联邦宇宙,扩大你的影响力,让你的博客的声音在相互连接的社区的广阔网络中回荡。

    博客的未来就在这里,它是联邦的!


    注意: 这只是一个起点。联邦宇宙中充满了无限的可能性,等待着你去探索。

    敬请期待更多联邦宇宙的冒险!

  • Quicklisp:你的 Common Lisp 库一站式商店

    🎉 Quicklisp:Common Lisp 的库管理器 🎉

    Quicklisp 就如同 Common Lisp 的终极包管理器,让你轻松下载、安装和加载库。想象一下,它是 Lisp 世界的“apt-get”或“pip”,但又多了一丝 Lisp 的魔法。

    🚀 Quicklisp:适用于所有 Lisp 的通用工具 🚀

    Quicklisp 与众多 Common Lisp 实现完美兼容,包括 ABCL、Allegro CL、Clasp、Clozure CL、CLISP、CMUCL、ECL、LispWorks、MKCL、SBCL 和 Scieneer CL。它就像你的 Lisp 项目的瑞士军刀,支持你在 Linux、Mac OS X 和 Windows 等不同平台上工作。

    📦 超过 1,500 个库触手可及 📦

    Quicklisp 为你提供了庞大的库生态系统,超过 1,500 个库随时待命,准备融入你的项目。这就像拥有一个装满工具的宝箱,每个工具都旨在解决特定问题或增强你的 Lisp 之旅。

    ✨ Quicklisp 入门:快速指南✨

    1. 下载并加载: 从 Quicklisp beta 网站下载 Quicklisp 文件(quicklisp.lisp)并将其加载到你的 Common Lisp 会话中。
    2. 验证完整性: 为了更安心,下载分离的 PGP 签名文件并将其与 Quicklisp 发布签名密钥进行验证。
    3. 安装 Quicklisp: 加载完成后,运行 (quicklisp-quickstart:install) 来安装 Quicklisp。这将下载并安装必要的文件,包括 ASDF,一个 Common Lisp 的包管理器。
    4. 开始使用 Quicklisp: 安装完成后,你可以使用 (ql:quickload "system-name") 加载库。例如,要加载 vecto 库,你可以使用 (ql:quickload "vecto")

    💡 Quicklisp 实战:真实世界示例 💡

    假设你正在使用 Common Lisp 构建一个 Web 应用程序。你需要一个库来处理 HTTP 请求。Quicklisp 闪亮登场!

    1. 找到合适的库: 使用 (ql:system-apropos "http") 搜索与 HTTP 相关的库。Quicklisp 将返回一个可用库列表。
    2. 加载库: 选择最符合你需求的库,并使用 (ql:quickload "library-name") 加载它。
    3. 开始编码: 现在你就可以使用库的函数和特性来构建你的 Web 应用程序了。

    🚀 超越基础:Quicklisp 高级功能 🚀

    • 卸载库: 使用 (ql:uninstall "system-name") 从系统中删除库。
    • 更新 Quicklisp: 使用 (ql:update-dist "quicklisp")(ql:update-client) 保持你的 Quicklisp 安装和库更新。
    • 查找依赖项: 使用 (ql:who-depends-on "system-name") 发现哪些库依赖于特定库。
    • SLIME 集成: Quicklisp 使得安装和配置 SLIME 变得轻而易举,SLIME 是 Emacs 的强大 Lisp 开发环境。

    🎉 Quicklisp:社区的共同努力 🎉

    Quicklisp 是 Common Lisp 社区协作精神的证明。它是 Zachary Beane 开发和维护的项目,并得到了众多个人的贡献。你可以加入 Quicklisp 讨论组邮件列表或访问 Freenode 上的 #quicklisp 频道,与其他 Quicklisp 用户交流。

    💻 Quicklisp:Common Lisp 开发的未来 💻

    Quicklisp 彻底改变了 Common Lisp 开发,使访问和使用库变得比以往更容易。随着 Common Lisp 生态系统的不断发展,Quicklisp 将在赋能开发人员构建创新且强大的应用程序方面发挥越来越重要的作用。

    参考资料:

  • 🤯 AMD锐龙9000:延迟大作战!

    AMD的CCD+IOD Chiplet设计,就像是一场精心策划的“芯片盛宴”,将多个芯片模块组合在一起,打造出强大的处理器。 然而,最近却传出了一些令人担忧的消息:锐龙9000系列处理器出现了核心之间延迟骤然加大的情况,最高可达200纳秒左右!这就好比一场盛宴,菜肴虽然美味,但上菜速度却慢得让人抓狂。

    究竟是什么原因导致了这种延迟的“灾难”? 经过一番调查,我们发现问题就出在AMD的微代码上。微代码就像是一套操作系统,它负责协调处理器内部各个模块之间的工作。而之前的微代码版本,似乎在处理核心之间的数据传输时,出现了“迷路”的情况,导致延迟大幅增加。

    好在,AMD及时发布了新的AGESA 1.2.0.1版微代码,并迅速得到主板厂商的支持。 这就好比一位经验丰富的“领航员”,及时修正了航线,让数据传输更加顺畅。

    实测结果显示,升级到1.2.0.1版微代码后,锐龙9000系列的核心间延迟从180纳秒降低到了75纳秒,降幅高达58%! 这就像是一场“延迟大作战”,最终以AMD的胜利告终。

    这次微代码升级,不仅解决了延迟问题,还提升了锐龙9000系列处理器的性能表现。 我们可以期待,AMD的“芯片盛宴”将更加精彩!

    参考文献:

    1. AMD官网
    2. 华硕官网
    3. CapframeX官网

  • CFFI 炼丹:用“点”化繁为简 🧙‍♂️

    引言

    CFFI,这个强大的工具,让我们在 Lisp 中调用 C 函数,如同驾驭风火轮,穿梭于两个世界。然而,使用 CFFI 的 API 编写 C 风格代码,有时却像是在泥潭中跋涉,因为你需要不断地传递类型信息,而 C 中的“点”运算符却拥有着神奇的类型推断能力,让我们可以轻松地访问结构体成员。

    为了让 CFFI 也能像 C 一样优雅,我们打造了 cffi-ops 这个炼丹炉,它将 CFFI 的繁琐操作,炼化为简洁的“点”操作,让你在 Lisp 中写 C 代码,如同行云流水般流畅。

    炼丹秘籍:规则与对比

    cffi-ops 的炼丹秘籍,就是将 C 中的“点”运算符,映射到 Lisp 中的宏定义,让 Lisp 代码的结构与 C 代码保持一致。

    C 语法cffi-ops 语法
    x->y.zx->y->z(-> x y z) (注意:xyz 必须与 defcstruct 中定义的符号相同)
    &x->y(& (-> x y))
    *x([] x)
    x[n]([] x n)
    &x[n]x + n(& ([] x n))
    x.y = z(setf (-> x y) z) 如果 z 是一个变量
    (csetf (-> x y) z) 如果 z 是一个 CFFI 指针
    A _a, *a = &_a(clet ((a (foreign-alloca '(:struct A)))) ...)
    A *a = malloc(sizeof(A))(clet ((a (cffi:foreign-alloc '(:struct A)))) ...)
    A _a = *b, *a = &_a(clet ((a ([] b))) ...)
    A *a = b(clet ((a b)) ...)

    炼丹炉的奥妙:CFFI 指针与 clet

    在 Lisp 中,我们无法直接操作 C 的复合类型,因此,绑定和赋值复合类型需要借助 clet (或 clet*) 和 csetf,它们作用于 CFFI 指针,实现对 C 数据的操控。

    炼丹师的助手:arrow-macros

    cffi-ops 的炼丹炉,是建立在 arrow-macros 的基础上,它提供了 -> 宏,让我们可以像在 C 中一样,轻松地访问结构体成员。因此,cffi-opsarrow-macros 相辅相成,让你在 Lisp 中编写 C 代码,更加得心应手。

    炼丹实例:向量加法

    让我们来看一个 C 代码的例子:

    #include <stdlib.h>
    #include <assert.h>
    
    typedef struct {
      float x;
      float y;
      float z;
    } Vector3;
    
    typedef struct {
      Vector3 v1;
      Vector3 v2;
      Vector3 v3;
    } Matrix3;
    
    void Vector3Add(Vector3 *output, const Vector3 *v1, const Vector3 *v2) {
      output->x = v1->x + v2->x;
      output->y = v1->y + v2->y;
      output->z = v1->z + v2->z;
    }
    
    int main(int argc, char *argv[]) {
      Matrix3 m1[3];
      m1[0].v1.x = 1.0;
      m1[0].v1.y = 2.0;
      m1[0].v1.z = 3.0;
      Matrix3 m2 = *m1;
      Vector3 *v1 = &m2.v1;
      Vector3 *v2 = malloc(sizeof(Vector3));
      ,*v2 = *v1;
      v2->x = 3.0;
      v2->z = 1.0;
      Vector3Add(v1, v1, v2);
      assert(v1->x == 4.0);
      assert(v1->y == 4.0);
      assert(v1->z == 4.0);
      free(v2);
      return 0;
    }

    使用 cffi-ops,我们可以将其改写为 Lisp 代码:

    (defpackage cffi-ops-example
      (:use #:cl #:cffi #:cffi-ops))
    
    (in-package #:cffi-ops-example)
    
    (defcstruct vector3
      (x :float)
      (y :float)
      (z :float))
    
    (defcstruct matrix3
      (v1 (:struct vector3))
      (v2 (:struct vector3))
      (v3 (:struct vector3)))
    
    (defun vector3-add (output v1 v2)
      (clocally
        (declare (ctype (:pointer (:struct vector3)) output v1 v2))
        (setf (-> output x) (+ (-> v1 x) (-> v2 x))
              (-> output y) (+ (-> v1 y) (-> v2 y))
              (-> output z) (+ (-> v1 z) (-> v2 z)))))
    
    (defun main ()
      (clet ((m1 (foreign-alloca '(:array (:struct matrix3) 3))))
        (setf (-> ([] m1 0) v1 x) 1.0
              (-> ([] m1 0) v1 y) 2.0
              (-> ([] m1 0) v1 z) 3.0)
        (clet* ((m2 ([] m1))
                (v1 (& (-> m2 v1)))
                (v2 (foreign-alloc '(:struct vector3))))
          (csetf ([] v2) ([] v1))
          (setf (-> v2 x) 3.0
                (-> v2 z) 1.0)
          (vector3-add v1 v1 v2)
          (assert (= (-> v1 x) 4.0))
          (assert (= (-> v1 y) 4.0))
          (assert (= (-> v1 z) 4.0))
          (foreign-free v2))))

    而没有使用 cffi-ops 的 Lisp 代码则更加冗长:

    (defpackage cffi-example
      (:use #:cl #:cffi))
    
    (in-package #:cffi-example)
    
    (defcstruct vector3
      (x :float)
      (y :float)
      (z :float))
    
    (defcstruct matrix3
      (v1 (:struct vector3))
      (v2 (:struct vector3))
      (v3 (:struct vector3)))
    
    (declaim (inline memcpy))
    (defcfun "memcpy" :void
      (dest :pointer)
      (src :pointer)
      (n :size))
    
    (defun vector3-add (output v1 v2)
      (with-foreign-slots (((xout x) (yout y) (zout z)) output (:struct vector3))
        (with-foreign-slots (((x1 x) (y1 y) (z1 z)) v1 (:struct vector3))
          (with-foreign-slots (((x2 x) (y2 y) (z2 z)) v2 (:struct vector3))
            (setf xout (+ x1 x2) yout (+ y1 y2) zout (+ z1 z2))))))
    
    (defun main ()
      (with-foreign-object (m1 '(:struct matrix3) 3)
        (with-foreign-slots ((x y z)
                             (foreign-slot-pointer
                              (mem-aptr m1 '(:struct matrix3) 0)
                              '(:struct matrix3) 'v1)
                             (:struct vector3))
          (setf x 1.0 y 2.0 z 3.0))
        (with-foreign-object (m2 '(:struct matrix3))
          (memcpy m2 m1 (foreign-type-size '(:struct matrix3)))
          (let ((v1 (foreign-slot-pointer m2 '(:struct matrix3) 'v1))
                (v2 (foreign-alloc '(:struct vector3))))
            (memcpy v2 v1 (foreign-type-size '(:struct vector3)))
            (with-foreign-slots ((x z) v2 (:struct vector3))
              (setf x 3.0 z 1.0))
            (vector3-add v1 v1 v2)
            (with-foreign-slots ((x y z) v1 (:struct vector3))
              (assert (= x 4.0))
              (assert (= y 4.0))
              (assert (= z 4.0)))
            (foreign-free v2)))))

    两种代码在 SBCL 上生成几乎相同的机器码,性能也十分接近。

    总结

    cffi-ops 为我们提供了一种简洁高效的方式,让我们在 Lisp 中编写 C 代码,如同在 C 中一样自然流畅。它将 CFFI 的复杂操作,炼化为简洁的“点”操作,让我们可以专注于代码的逻辑,而不用被繁琐的类型信息所困扰。

    参考文献

    1. cffi-ops
    2. arrow-macros
    3. CFFI