Bootstrap

【AI赋能工作流】一个程序员的自白:我如何利用大语言模型将工作效率提升500%—慢慢学AI137

结论先行

  • 熬夜学习 AI,脱发却依然摸不着门道?
    • 花了一周时间,AI 还是帮不了你写文案?
  • 有人用 AI 高效工作,他们的秘诀是什么?
    • 是 AI 真那么强,还是我们没找对方法?
  • 程序员的 AI 日记曝光:
    • 他用 AI 重塑了工作流程,我们却在纠结 AI 会不会骗人。
  • 看完这篇文章,你可能会恍然大悟:
    • 被忽视的 AI 能力,才是真正的效率杀手锏。
    • 想像高手一样驾驭 AI,不再为脱发烦恼?继续阅读!

原文地址 : How I Use AI
我如何使用“AI”
作者:Nicholas Carlini 2024-08-01

我并不认为“AI”模型 (人工智能模型) 这个词有多好,我甚至讨厌它。(我指的是:大语言模型)。我认为现在对它的宣传有点过火了。

它根本不是真正的 AI (人工智能)。但我希望,无论是否喜欢这个词的人,都能看到这篇文章。所以为了营销、SEO 和吸引眼球,我不得不使用它。

的确,任何新技术都会吸引投机者。许多公司喜欢宣称他们在“使用 AI (人工智能)”,就像他们之前说他们使用了“区块链”技术一样。(类似的情况我们已经见过 很多, 很多, 很多, 很多)。我们可能正处于一个泡沫之中。互联网曾在 2000 年经历泡沫破裂,但我们现在所使用的互联网应用,在过去可是科幻小说中的情节。

但我认为,我们最近取得的进步并非只是炒作。在过去的一年里,我每周都会花几个小时与各种大语言模型互动,它们解决我提出的各种难题的能力给我留下了深刻的印象。因此,我的编程速度至少提高了 50%,无论是在我的研究项目还是个人项目中。

我发现网上大多数讨论大语言模型的人,要么过于乐观,认为所有工作都将在三年内自动化;要么过于悲观,认为它们毫无用处。

所以在这篇文章中,我想尝试让讨论更务实一些。我不会预测未来,只想列举 50 个我(一名研究机器学习的程序员和研究科学家)与不同的大语言模型进行的对话,这些对话显著提升了我的研究能力,并帮助我完成各种编程项目。其中包括:

  • 使用我从未接触过的技术构建完整的网络应用。
  • 学习如何使用各种我之前不熟悉的框架。
  • 将许多程序转换为 C 语言或 Rust 语言,从而将性能提升 10 到 100 倍。
  • 精简大型代码库,从而大大简化项目。
  • 为我去年撰写的几乎每一篇研究论文编写初始实验代码。
  • 自动化几乎所有重复性任务或一次性脚本。
  • 几乎完全取代了网络搜索,在设置和配置新的软件包或项目时为我提供帮助。
  • 在调试错误信息时,大约 50% 的情况下取代了网络搜索。

如果要将这些例子归类,可以分为“帮助我学习”和“自动化繁琐的任务”。帮助我学习显然很重要,因为它让我能够做到以前觉得困难的事情;而自动化繁琐的任务(对我来说)同样重要,因为它让我能够专注于自己最擅长的领域,解决那些真正棘手的问题。

最重要的是,这些例子都是我如何利用大语言模型来帮助我的真实案例。它们的目的不是为了炫耀某些令人印象深刻的功能,而是源于我完成实际工作的需要。这意味着这些例子可能并不光鲜亮丽,但我每天的大部分工作也并不光鲜,而现在的大语言模型能够帮我自动完成几乎所有这些工作。

我希望通过这篇文章,用大量的例子来展示在过去的一年中,我如何利用大语言模型来提高我的工作效率。请记住,当你读完这些例子的时候,你看到的只是我使用大语言模型的案例中不到 2% 的部分。

所以,当你读到感到疲倦时——你很可能会——请随时使用左侧的导航菜单,这是我(或者说,一个大语言模型)专门为这篇文章创建的,因为它的内容实在是太长了。

细微差别

如果说互联网有什么事情做得不好,那就是把握细微差别。我不会说现在的大语言模型会统治世界,也不会谈论未来的模型能做什么或不能做什么。我只想讨论现在的模型是否对我有用。

你可能会想——怎么会有人专门写一篇文章来论证语言模型的实用性呢?这难道不是显而易见的吗?但似乎有很多人——无论是在学术界、软件工程领域还是媒体领域——都声称大语言模型毫无贡献,只是一时的炒作,几年后就会销声匿迹,对世界没有任何影响。我认为他们是错的,因为现在的大语言模型已经非常有用了。

但是我觉得有必要说明一下,因为还有另一群人持有相反的观点:他们认为现在的大语言模型可以取代所有的程序员,人们不应该学习编程,因为明年他们都会失业。我不会直接反驳他们的观点(这不是本文的重点),但我想明确表示,我并不是在支持他们的观点。

我也不会试图论证“为了目的可以不择手段”,说我们应该不顾大语言模型的负面影响(其中有很多)而去训练它们。

我完全理解,这些模型会带来负面影响,甚至是极其负面的影响。我指的是所有方面,从虚假信息到滥用,从监控到失业。(或者,如果你相信某些人的说法,甚至是人类灭绝?)我很快会专门写一篇文章来阐述我对大语言模型的负面影响的看法。链接会放在这里。但这与语言模型是否有用的问题是分开的——正如我所说,这正是我想在这里讨论的内容。

我进一步理解,你可能因为大语言模型容易产生幻觉、重复事实以及由于缺乏鲁棒性而可能出现的严重错误等局限性而不愿意使用它们—— 我可能比你更了解这些局限性。但这篇文章不会讨论这些,因为我认为即使存在这些缺陷,模型仍然是有用的。

我更进一步地理解,训练这些模型的伦理问题非常值得商榷。也许你反感它们未经授权就使用人们的数据进行训练(我可能比你更了解这一点)。或者,你可能会想到那些拿着微薄的工资来专门训练这些模型的人。我同意,这些都是问题。但这篇文章也不会讨论这些。

正如我已经反复强调的那样:我在这里只讨论一个问题,那就是这些模型,以它们现在的形式,是否有用。

我的一些背景

一般来说,我不是一个轻易相信事物的人。例如:尽管十年前经历了安全社区的加密炒作,但我完全避免写任何关于区块链的论文。我从未拥有过比特币。它们基本上没有任何用途——除了赌博和欺诈。日复一日,我对所有的说法都持怀疑态度。每当有人告诉我“新技术将改变世界”时,我的一般反应是漠不关心。

所以,当我告诉你,当我第一次听到有人告诉我,人工智能将非常有用,并将显著改变我处理日常工作的方式时,我的反应基本上是一样的,那就是:“眼见为实”。

除此之外,我还是一名安全研究员。近十年来,我的日常工作就是展示人工智能模型在面对任何未经训练的环境时是如何彻底失败的。我已经证明,稍微扰动机器学习模型的输入,使其产生极其错误的输出,这是微不足道的;或者大多数机器学习模型会记住其训练数据集中特定的例子,并在使用时重复它们。我完全理解这些系统的局限性。

然而,我在这里要说的是,我认为当前的大语言模型为我的工作效率提供了自互联网诞生以来最大的提升。老实说,今天,如果你让我在完成一项从我的工作中随机选择的编程任务时,可以选择使用互联网或使用最先进的语言模型,我可能会在超过一半的时间里选择语言模型。

我如何使用大型语言模型

我之所以强调“帮助我”,

是因为我的工作方式可能与你截然不同。以下是我在过去一年里与多个大型语言模型(LLM)交互时总结的一些使用案例,仅供参考。

你可能会觉得这些案例很奇怪或不实用,甚至与你的需求无关。我对此表示理解,毕竟每个人对 AI 工具的使用方式都不同。这些案例只是我个人的经验分享。

帮助我构建完整的应用程序

去年,我制作了一个测验,让人们测试自己对 GPT-4 解决任务能力的预测水平。这个测验非常受欢迎,获得了超过一千万次的页面浏览量。而且你知道吗?我几乎完全依靠 GPT-4 编写了这个应用程序的初始版本。整个过程是通过一系列的提问来完成的,我从询问应用程序的基本结构开始,逐步扩展功能。整个对话记录超过了 30,000 字,这极大地考验了(当时最先进的)原版 GPT-4 模型的能力。

{% hideToggle ChatGPT 对话记录 - 编写应用程序的初始版本 %}

{% timeline 编写应用程序的初始版本 %}

我计划使用 Flask 构建一个类似问答游戏的应用程序。每个页面将展示一个问题和一个预期的答案。用户可以通过滑动条来预测他们认为 GPT-4 以该预期答案作答的概率。每个页面都会有一个提交按钮。当用户点击提交后,页面会显示 GPT-4 是否成功回答了这个问题,并提供模型的实际答案作为参考。页面还会有一个“下一个问题”的按钮。

我需要以下页面:

- GET /home:介绍比赛内容并解释规则。提供一个链接以开始第一个问题,同时为用户创建一个会话变量。
- GET /question? Id=[uuid]:显示对应 [uuid] 的问题,页面内容如前述。
- POST /score:接收 POST 参数 id=[uuid]、session=[uuid] 和 guess=[0 到 1 之间的浮点数]。
    - 首先,将用户的预测值添加到该问题的所有预测列表中。
    - 接着,计算用户的对数损失,并返回结果。
    - 最后,告知用户其表现相对于其他人如何。

你需要设置以下全局变量:

- scores:一个字典,将问题 UUID 映射到一个预测列表,例如 {question 1: [.5, .1, .9]}。
- entries:一个字典,将用户 UUID 映射到包含问题 UUID 和预测值的字典,例如 {person 1: {question 1: .5, question 2: .8}}。
- questions:一个包含问题和答案对的元组列表,例如 [("1+1 等于多少?", "2")]。
- answers:一个由整数构成的列表,用于记录模型是否回答正确,例如 [0, 1, 0 ...]。

你可以首先使用 pip 安装 Flask 和其他必要的库,如果尚未安装这些库的话:

pip install flask numpy scikit-learn

现在,我们来使用 Flask 开发你的游戏:

from flask import Flask, request, session, redirect, url_for, render_template
from sklearn. Metrics import log_loss
from uuid import uuid 4
import numpy as np

App = Flask (__name__)
App. Config['SECRET_KEY'] = 'a very secret key'  # replace with your secret key

# Global variables
scores = {
   }  
entries = {
   }
questions = [("What is 1+1?", "2"), ("What is the capital of France?", "Paris")]
answers = [1, 0]  # Suppose for these questions GPT-4 got the first one right and the second one wrong

@app.Route ('/home', methods=['GET'])
def home ():
    session['id'] = str (uuid 4 ())
    return render_template ('home. Html')  # render a template that explains the game

@app.Route ('/question', methods=['GET'])
def question ():
    qid = request.Args.Get ('id', default=0, type=int)
    if 'id' in session:
        question, expected_answer = questions[qid]
        return render_template ('question. Html', question=question, expected_answer=expected_answer, id=qid)  
    else:
        return redirect (url_for ('home'))

@app.Route ('/score', methods=['POST'])
def score ():
    qid = request.Form.Get ('id', type=int)
    guess = request.Form.Get ('guess', type=float)
    user_id = session.Get ('id')

    if user_id and qid is not None and guess is not None:
        # Add to the list of all guesses for that question
        scores.setdefault(qid, []).append(guess)
        
        # Add to the person's guesses
        entries.setdefault(user_id, {
   })[qid] = guess

        # Compute the person's log loss
        user_log_loss = log_loss([answers[qid]], [guess], labels=[0, 1])

        # Compare with others
        other_scores = scores[qid]
        other_log_losses = log_loss([answers[qid]] \* len(other_scores), other_scores, labels=[0, 1])

        comparison = 'better' if user_log_loss < other_log_losses else 'worse'

        return render_template('score.html', user_log_loss=user_log_loss, comparison=comparison)
    else:
        return redirect(url_for('home'))

If __name__ == "__main__":
    App.Run (debug=True)

这段代码作为初始代码,实现了三个端点:/home/question/score,并管理全局变量来记录用户预测和计算对数损失得分。

不过,要让代码正常运行,你还需要创建用于渲染的模板文件,包括 home.htmlquestion.htmlscore.html。这些模板文件应该包含你的 HTML 代码,并预留出动态内容的占位符。

建议你阅读 Flask 文档中关于会话和模板的部分,以便更好地理解它们的使用。

需要注意的是,使用全局变量来存储信息适用于用户较少且应用运行时间较短的小型应用或快速原型。但如果是在生产环境或有更多用户的应用中,你可能需要使用数据库或其他数据存储系统来管理这些信息。

页面受限,

{% endtimeline %}

{% endhideToggle %}

如果你查看这段对话,你会发现各种类型的例子,从我用文字描述我想要的功能并要求模型提供完整实现的情况,到我请求具体更改的场景(如“能否将‘与平均分的比较’改为‘用 KDE 表示的百分位数’?”),再到我仅仅复制并粘贴错误信息,提出完全未指定的问题(如“绘图时:numpy. Linalg. LinAlgError: 奇异矩阵”),甚至还有一些我只是简单询问一次性问题的例子(如“如何用 JavaScript 添加一个内容从字符串加载的 iframe?”)。

总的来说,这能奏效是因为语言模型非常擅长解决那些已经被人们解决过的问题。事实上,这个测验的 99% 只是由一些基本的 HTML 和一个 python 网页服务器后端组成的,任何人都能轻松编写。这个测验之所以引人入胜,受到大家的喜爱,并不是因为背后的技术有多么先进,而是因为测验的内容本身有趣。因此,通过自动化处理所有重复性的工作,我可以很轻松地完成这个测验。

事实上,我非常有信心地说,如果没有语言模型的帮助,我可能根本不会去制作这个测验——因为我并不愿意花时间从头开始编写整个 Web 应用程序。要知道,我可是会编程的! 我相信,即使是现有的模型,也已经足够让绝大多数人通过简单的提问来解决他们以前从未能解决的复杂问题。

我还有一些类似的例子,我让模型为我编写了完整的应用程序,等它们上线时,我会明确说明这些应用程序是借助语言模型完成的。

作为新技术的导师

曾经我一直密切关注各种新框架的发展。但一个人的时间有限,由于工作原因,我主要专注于最新的研究进展,而不是 JavaScript 框架的最新动态。

这意味着,当我需要开展一个超出我研究领域的新项目时,通常有两个选择。首先,我可以使用已有的知识。虽然这些知识可能已经过时了十年或二十年,但对于小项目来说通常已经足够。或者,我可以尝试学习新的(通常更优越的)方法。

这时,语言模型就派上用场了。像 Docker、Flexbox 或 React 这样的框架或工具,虽然对我来说是新鲜的,但对其他许多人来说却非常熟悉。世界上可能有成千上万的人精通这些技术,而现有的语言模型也可以同样了解这些技术。

这意味着我不必去读那些假定读者有特定知识并想实现特定目标的静态教程。相反,我可以通过与语言模型互动,学习我完成任务所需的任何知识。
例如,今年早些时候,我在构建一个用于评估大语言模型的框架,并希望能够在受限环境中运行 LLM 生成的代码,以防止其意外删除我电脑上的文件或执行其他不必要的操作。Docker 是完成这一任务的理想工具,但我之前从未使用过它。

需要注意的是,这个项目的目标并不是为了使用 Docker。Docker 只是我实现目标所需的工具而已。我只需掌握 Docker 的 10% 核心知识,以确保我能够在最基本的操作下安全地使用它。

如果这是 90 年代,我可能需要买一本入门 Docker 的书籍,阅读前几章,然后翻阅找到我需要的部分,来了解如何实现我的需求。此后,情况有所好转;如果这是过去十年,我可能会在线搜索一些 Docker 教程,跟着步骤操作,然后查找出现的错误信息,看看是否有其他人遇到类似问题。

但如今,我只需请语言模型教我如何使用 Docker。 这就是我所做的。

{% hideToggle ChatGPT 对话记录 - 教我如何使用Docker %}

{% timeline 教我如何使用 Docker %}

首先,启动一个新的 Docker 虚拟机。接着,在 Python 中运行一个当前位于 /tmp/a.sh 的 Bash 脚本,以在新的环境中进行配置。最后,在 Docker 环境中执行 ls /tmp/ 命令来验证设置是否成功。

1. 启动新的 Docker 容器

我们将使用 Python 的 subprocess 模块来启动一个新的 Docker 容器。你可以根据需要选择一个合适的 Docker 镜像。以下是使用 ubuntu 镜像的示例。

import subprocess

# 第一步:启动新的 Docker 容器
container_name = "my_new_container"
image_name = "ubuntu"  # 将此处替换为你要使用的镜像名称

# 以分离模式运行一个新的容器
subprocess.run(["docker", "run", "-d", "--name", container_name, image_name, "sleep", "infinity"])

2. 将 Bash 脚本复制到 Docker 容器中

接下来,我们将主机上的 Bash 脚本 /tmp/a.sh 复制到 Docker 容器的 /tmp/ 目录中。

# 第二步:将脚本复制到 Docker 容器中
subprocess.run(["docker", "cp", "/tmp/a.sh", f"{
     container_name}:/tmp/a.sh"])

3. 在 Docker 容器中执行 Bash 脚本

现在,我们将在 Docker 容器中执行已复制的脚本,以设置环境。

# 第三步:在 Docker 容器中执行 Bash 脚本
subprocess.run(["docker", "exec", container_name, "bash", "/tmp/a.sh"])

4. 通过在 Docker 容器中列出 /tmp/ 目录来测试

最后,让我们通过在 Docker 容器中列出 /tmp/ 目录的内容来验证一切是否已正确设置。

# 第四步:在 Docker 容器中运行 'ls /tmp/' 以测试
subprocess.run(["docker", "exec", container_name, "ls", "/tmp/"])

5. 清理(可选)

如果你在测试后希望删除 Docker 容器,可以使用以下命令:

# 可选步骤:停止并删除 Docker 容器
subprocess.run(["docker", "stop", container_name])
subprocess.run(["docker", "rm", container_name])

总结

  • 该 Python 脚本启动一个新的 Docker 容器,将脚本复制到其中,执行该脚本,并通过列出 /tmp/ 目录来验证设置。
  • 这个过程假设系统上已安装并运行 Docker。
  • Docker 镜像和路径应根据你的具体使用场景进行调整。

页面受限,

{% endtimeline %}

{% endhideToggle %}

当我成功设置并运行 Docker 后,发现它在 Linux 上运行时存在一些权限问题。我希望能解决这些权限问题,于是请模型帮助我处理这些问题。

{% hideToggle ChatGPT 对话记录 - 如何解决 Linux 上运行时权限问题 %}

{% timeline 如何解决 Linux 上运行时权限问题 %}

我正在编写一个程序,该程序通过为每个测试启动一个 Docker 环境来运行一些测试用例,在环境中运行测试,然后删除该环境。

在我的 Mac 上,我可以直接运行 `do_test.py`,因为 Docker 不需要 root 权限。

但是在 Ubuntu 上,现在我必须使用 `sudo` 运行 `do_test.py`,因为创建新的 Docker 环境需要 `sudo`。我怎样才能设置不需要使用 `sudo` 来运行?

如果你想在 Ubuntu 上运行 Docker 命令时不使用 sudo,你需要将你的用户添加到 Docker 组中。Docker 组在 Docker 安装时自动创建。将用户添加到 Docker 组后,组内的用户就可以无须超级用户权限执行 Docker 命令。以下是实现这一设置的步骤:

  1. 将你的用户添加到 Docker 组

    打开终端,输入以下命令,将 your-username 替换为你当前的用户名:

    
    sudo usermod -aG docker your-username
    

    这条命令会将你的用户添加到 Docker 组。-aG 参数确保用户会被追加到指定组中。

  2. 应用组设置

    为了使组设置生效,你需要注销并重新登录。或者,你也可以通过运行以下命令立即应用新的组设置:

    newgrp docker
    

    这条命令会在当前会话中激活新的组设置,从而让你在不使用 sudo 的情况下执行 Docker 命令。

  3. 验证 Docker 命令是否可在无 sudo 情况下运行

    重新登录或执行 newgrp docker 之后,你可以通过运行以下命令验证 Docker 命令是否可在不使用 sudo 的情况下执行:

    Bash

    
    docker run hello-world
    

    这条命令会下载一个测试镜像并在容器中运行。如果运行成功,说明你的设置已正确生效。

重要注意事项

  • 安全性考虑:请注意,将用户添加到 Docker 组会授予该用户在 Docker 操作中的权限,相当于 root 用户的权限。这种设置在多用户系统中可能会带来安全隐患。请确保你理解这一更改的安全影响。

  • Docker 服务:确保你的系统上 Docker 服务正在运行。你可以使用 sudo systemctl start docker 启动 Docker 服务,并使用 sudo systemctl enable docker 设置其在启动时自动运行。

通过遵循这些步骤,你应该可以在 Ubuntu 上无需使用 sudo 就能运行 Docker 命令,从而简化在 Docker 环境中运行测试用例的过程。

页面受限,

{% endtimeline %}

{% endhideToggle %}

通过这个过程,我了解到了 Podman,于是请模型将我所有特定于 Docker 的代码转换为对应的 Podman 版本。

{% hideToggle ChatGPT 对话记录 - 所有特定于 Docker 的代码转换为对应的 Podman 版本 %}

{% timeline 对话记录 %}

From python spin up a podman container

To spin up a Podman container using Python, you would typically use the subprocess module to execute Podman commands from within a Python script. This approach allows you to programmatically manage containers, including starting them, from your Python code.

Here’s a basic example to demonstrate how you can use Python to start a Podman container:

  1. Ensure Podman is Installed: First, make sure Podman is installed on your system. You can check this by running podman --version from your terminal.

  2. Choose Your Container Image: Decide which container image you want to use. For this example, let’s use the alpine image, which is a minimal Docker image based on Alpine Linux. If you want to use a different image, replace alpine with the name of the image you wish to use.

  3. Write the Python Script: Use the subprocess.run function to call Podman commands.

Here’s a simple Python script that starts an Alpine container and runs the echo "Hello from Podman!" command inside it:

python

复制代码

import subprocess def start_podman_container(): # Define the Podman command to run a container command = ["podman", "run", "alpine", "echo", "Hello from Podman!"] # Execute the command result = subprocess.run(command, capture_output=True, text=True) # Check if the command was successful if result.returncode == 0: print("Container ran successfully.") print("Output:", result.stdout) else: print("Error running container.") print("Error:", result.stderr) # Run the function start_podman_container()

This script runs a container using the alpine image and executes a simple echo command inside it. The output of the command is captured and displayed by the Python script.

Important Notes:

  • Permissions: Running Podman might require superuser privileges, depending on your setup. However, one of the advantages of Podman is its ability to run containers as a non-root user. Ensure your environment is configured appropriately.
  • Python Environment: This script uses Python’s built-in subprocess module, which is included in the standard library and does not require any additional packages.
  • Podman Installation: This example assumes that Podman is already installed and configured on your system. If not, you will need to install Podman first.

Remember, this script is a basic example. Podman’s capabilities allow for much more complex container management, including building images, managing container networks, volumes, and more. For advanced scenarios, refer to the Podman documentation and the Python subprocess module documentation to tailor the script to your needs.

页面受限,

{% endtimeline %}

{% endhideToggle %}

And then when I wanted to figure out how to pass a host’s GPUs through in a docker container, I ask for that too.

{% hideToggle ChatGPT 对话记录 - 所有特定于 Docker 的代码转换为对应的 Podman 版本 %}

{% timeline 对话记录 %}

How do I pass nvidia gpus through to a docker instance?

你可以首先使用 pip 安装 Flask 和其他必要的库,如果尚未安装这些库的话:

pip install flask numpy scikit-learn

现在,我们来使用 Flask 开发你的游戏:

from flask import Flask, request, session, redirect, url_for, render_template
from sklearn. Metrics import log_loss
from uuid import uuid 4
import numpy as np

App = Flask (__name__)
App. Config['SECRET_KEY'] = 'a very secret key'  # replace with your secret key

# Global variables
scores = {
   }  
entries = {
   }
questions = [("What is 1+1?", "2"), ("What is the capital of France?", "Paris")]
answers = [1, 0]  # Suppose for these questions GPT-4 got the first one right and the second one wrong

@app.Route ('/home', methods=['GET'])
def home ():
    session['id'] = str (uuid 4 ())
    return render_template ('home. Html')  # render a template that explains the game

@app.Route ('/question', methods=['GET'])
def question ():
    qid = request.Args.Get ('id', default=0, type=int)
    if 'id' in session:
        question, expected_answer = questions[qid]
        return render_template ('question. Html', question=question, expected_answer=expected_answer, id=qid)  
    else:
        return redirect (url_for ('home'))

@app.Route ('/score', methods=['POST'])
def score ():
    qid = request.Form.Get ('id', type=int)
    guess = request.Form.Get ('guess', type=float)
    user_id = session.Get ('id')

    if user_id and qid is not None and guess is not None:
        # Add to the list of all guesses for that question
        scores.setdefault(qid, []).append(guess)
        
        # Add to the person's guesses
        entries.setdefault(user_id, {
   })[qid] = guess

        # Compute the person's log loss
        user_log_loss = log_loss([answers[qid]], [guess], labels=[0, 1])

        # Compare with others
        other_scores = scores[qid]
        other_log_losses = log_loss([answers[qid]] \* len(other_scores), other_scores, labels=[0, 1])

        comparison = 'better' if user_log_loss < other_log_losses else 'worse'

        return render_template('score.html', user_log_loss=user_log_loss, comparison=comparison)
    else:
        return redirect(url_for('home'))

If __name__ == "__main__":
    App.Run (debug=True)

这段代码作为初始代码,实现了三个端点:/home/question/score,并管理全局变量来记录用户预测和计算对数损失得分。

不过,要让代码正常运行,你还需要创建用于渲染的模板文件,包括 home.htmlquestion.htmlscore.html。这些模板文件应该包含你的 HTML 代码,并预留出动态内容的占位符。

建议你阅读 Flask 文档中关于会话和模板的部分,以便更好地理解它们的使用。

需要注意的是,使用全局变量来存储信息适用于用户较少且应用运行时间较短的小型应用或快速原型。但如果是在生产环境或有更多用户的应用中,你可能需要使用数据库或其他数据存储系统来管理这些信息。

页面受限,原始英文版本查看,中文版本查看

页面受限,

{% endtimeline %}

{% endhideToggle %}

如何开始新项目

年轻时,我的第一门编程语言是 Java。(这或许是个错误。)

甚至可以说整个 Java 语言都是个错误。但这另当别论。

我非常喜欢编程,但有一件事让我特别头疼,那就是面对新项目时那片空白的屏幕。尤其是在使用 Java 的时候!即便是编译一个简单的 hello world 程序,我也会困惑:“public static void main string args”究竟是什么意思?括号该放在哪里?哪些字母要大写?为什么这里用花括号而那里用方括号?

于是,我做了任何孩子都会做的事情——我请我父亲帮我完成。

二十年后的今天,我依然不喜欢用那些我不太熟悉的框架来启动新项目。光是处理模板代码就需要花费大量时间,而且我对自己在做什么也没有头绪。

举个例子,我最近想尝试写一些 CUDA 代码,来基准测试在 GPU 上运行的一种朴素贪婪搜索算法的性能,并与某个高效优化的 CPU 实现进行比较。

但问题是,我不会写 CUDA 程序。我会写 C 语言,也理解 GPU 的工作原理、内核的作用以及内存布局等方面的内容。但让我实际编写发送任务到 GPU 的代码?完全不知道从何入手。所以我就请模型为我写了一个 CUDA 程序的初步版本。它完美吗?当然不是!但这已经是一个不错的开始。而这正是我所需要的。

{% hideToggle ChatGPT 对话记录 - 请模型为我写了一个 CUDA 程序的初步版本 %}

{% timeline 对话记录 %}

编写一个简单的 CUDA 程序,该程序接受一个 32 位的命令行参数,并将其拆分为 8 个 4 位的独立命令。接着,对这些命令逐一调用 proc() 函数。

proc 函数将接收一组 4 位整数命令,并计算表达式
(a [op1] b) op2 (c [op3] d)

其中,a、op1、b、op2、c、op3、d 都是 4 位整数,操作符 op 由以下映射定义:
0: 加法(+)
1: 减法(-)
2: 乘法(*)
3: 除法(/)
4: 异或(^)

接下来,枚举所有可能的 32 位程序,并打印出计算结果最接近 1729 的那个程序。

下面是一段 CUDA 程序代码,它将一个 32 位的命令行参数拆分为 8 个 4 位的独立命令,并按照前面描述的方式进行处理。该程序会枚举所有可能的 32 位程序,并输出结果最接近 1729 的那个程序。

要运行此程序,你需要一台支持 CUDA 的 GPU 并安装好 CUDA 工具包。

#include <iostream>
#include <cuda_runtime.h>
#include <limits>

__device__ int proc(int command) {
    int a = (command >> 28) &amp; 0xF;
    int op1 = (command >> 24) &amp; 0xF;
    int b = (command >> 20) &amp; 0xF;
    int op2 = (command >> 16) &amp; 0xF;
    int c = (command >> 12) &amp; 0xF;
    int op3 = (command >> 8) &amp; 0xF;
    int d = (command >> 4) &amp; 0xF;

    int intermediate1, intermediate2, result;

    switch (op1) {
        case 0: intermediate1 = a + b; break;
        case 1: intermediate1 = a - b; break;
        case 2: intermediate1 = a * b; break;
        case 3: intermediate1 = (b != 0) ? a / b : 0; break;
        case 4: intermediate1 = a ^ b; break;
        default: intermediate1 = 0; break;
    }

    switch (op3) {
        case 0: intermediate2 = c + d; break;
        case 1: intermediate2 = c - d; break;
        case 2: intermediate2 = c * d; break;
        case 3: intermediate2 = (d != 0) ? c / d : 0; break;
        case 4: intermediate2 = c ^ d; break;
        default: intermediate2 = 0; break;
    }

    switch (op2) {
        case 0: result = intermediate1 + intermediate2; break;
        case 1: result = intermediate1 - intermediate2; break;
        case 2: result = intermediate1 * intermediate2; break;
        case 3: result = (intermediate2 != 0) ? intermediate1 / intermediate2 : 0; break;
        case 4: result = intermediate1 ^ intermediate2; break;
        default: result = 0; break;
    }

    return result;
}

__global__ void findClosest(int* closestCommand, int* closestValue, int target) {
    int idx = blockDim.x * blockIdx.x + threadIdx.x;
    int command = idx;
    int result = proc(command);

    int diff = abs(result - target);

    atomicMin(closestValue, diff);

    if (diff == *closestValue) {
        *closestCommand = command;
    }
}

int main(int argc, char** argv) {
    int target = 1729;
    int closestCommand = 0;
    int closestValue = std::numeric_limits<int>::max();

    int* d_closestCommand;
    int* d_closestValue;

    cudaMalloc((void**)&amp;d_closestCommand, sizeof(int));
    cudaMalloc((void**)&amp;d_closestValue, sizeof(int));

    cudaMemcpy(d_closestCommand, &amp;closestCommand, sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(d_closestValue, &amp;closestValue, sizeof(int), cudaMemcpyHostToDevice);

    int threadsPerBlock = 256;
    int numBlocks = (1 << 24) / threadsPerBlock;

    findClosest<<<numBlocks, threadsPerBlock>>>(d_closestCommand, d_closestValue, target);

    cudaMemcpy(&amp;closestCommand, d_closestCommand, sizeof(int), cudaMemcpyDeviceToHost);
    cudaMemcpy(&amp;closestValue, d_closestValue, sizeof(int), cudaMemcpyDeviceToHost);

    std::cout << "Closest command: " << closestCommand << std::endl;
    std::cout << "Closest value: " << (1729 - closestValue) << std::endl;

    cudaFree(d_closestCommand);
    cudaFree(d_closestValue);

    return 0;
}

本程序将执行以下步骤:

  1. 定义一个名为 proc 的函数,用来计算给定命令序列的结果。
  2. 启动 CUDA 内核,寻找一个能返回最接近 1729 的 32 位数值的程序。
  3. 输出最接近的命令及其对应的值。

请确保您的 CUDA 开发环境已经正确配置,这样才能顺利编译和运行程序。您可以使用 nvcc 进行编译:

nvcc -o cuda_program cuda_program.cu

And then run it:

./cuda_program

页面受限,

{% endtimeline %}

{% endhideToggle %}

你可能会发现,这里的代码有时会出错!但这对我来说完全可以接受。我并不追求一个完美的解决方案,我需要的只是一个起点,然后我可以从那里开始。如果未来的模型更强大,那当然非常了不起。但即便是现在的模型,已经对我有很大帮助了。

或者,换个话题,谈谈我在家里进行的另一个完全不同的个人项目。我正在使用 Raspberry Pi Pico W。这是我第一次使用它。我希望它能帮我实现一些功能,尤其是在网络方面。同样,我相信可以在网上找到一些好的教程,教我如何实现这些功能。但是你有没有注意到,最近的网络搜索结果通常前 5 个都是一些低质量的内容农场,里面充斥着从 2008 年更新过来的、为了 SEO 优化而更新却依然存在问题的代码。

因此,我选择让语言模型直接教我如何完成这些任务。我之前使用过微控制器,了解它们的大致工作原理,但从未使用过 Pico W。我需要的只是一个起点,帮我解决依赖项的问题,然后我可以自己摸索其余的部分。

对于新的微控制器,我总是先写一个 LED 闪烁程序作为“hello world”。这样可以测试我是否能成功编译并上传代码,确认所有引脚设置是否正确,并基本了解我在做什么。所以,让我们请模型生成一个 LED 闪烁程序。(这在互联网上找得到吗?几乎可以肯定是能找到的。但还得费劲去搜。)

{% hideToggle ChatGPT 对话记录 - 请模型生成一个 LED 闪烁程序 %}

{% timeline 对话记录 %}

编写一个用于 Raspberry Pi Pico W Zero 的 blink 示例代码,让引脚 26 上的 LED 闪烁,使用 MicroPython。

以下是一个简单的 Micropython 示例代码,能够让 Raspberry Pi Pico W Zero 的引脚 26 上的 LED 闪烁。该代码假设你已经在 Pico W 上刷入了 MicroPython。

from machine import Pin
import utime

# Setup pin 26 as output
led = Pin (26, Pin. OUT)

# Function to toggle the LED
def blink_led ():
    while True:
        led.Value (1)  # Turn LED on
        utime.Sleep (1)  # Sleep for 1 second
        led.Value (0)  # Turn LED off
        utime.Sleep (1)  # Sleep for 1 second

# Run the blink function
blink_led ()

该脚本将引脚 26 设置为输出引脚,然后连续不断地在开关状态之间每秒切换一次 LED。当你想要停止 LED 闪烁时,请中断脚本或重置你的开发板,因为它运行在一个无限循环中。

页面受限,

{% endtimeline %}
{% endhideToggle %}

一旦我将这段代码运行起来,接下来我就知道如何继续了。我知道 python 是如何工作的(或许你会觉得惊讶!)。因此,我可以直接从这里开始编辑代码,因为已经处理好了 Micro python 的特殊部分。

当我遇到需要特殊处理的问题时,我可以直接请模型帮助我解决。比如在这里,我继续请模型帮我写了一个连接 wifi 的脚本

{% hideToggle ChatGPT 对话记录 - 一个连接 wifi 的脚本 %}

{% timeline 对话记录 %}

Write me a simple script that connects a pico w to the wifi and sends an http request with python curl

你可以首先使用 pip 安装 Flask 和其他必要的库,如果尚未安装这些库的话:

pip install flask numpy scikit-learn

现在,我们来使用 Flask 开发你的游戏:

from flask import Flask, request, session, redirect, url_for, render_template
from sklearn. Metrics import log_loss
from uuid import uuid 4
import numpy as np

App = Flask (__name__)
App. Config['SECRET_KEY'] = 'a very secret key'  # replace with your secret key

# Global variables
scores = {
   }  
entries = {
   }
questions = [("What is 1+1?", "2"), ("What is the capital of France?", "Paris")]
answers = [1, 0]  # Suppose for these questions GPT-4 got the first one right and the second one wrong

@app.Route ('/home', methods=['GET'])
def home ():
    session['id'] = str (uuid 4 ())
    return render_template ('home. Html')  # render a template that explains the game

@app.Route ('/question', methods=['GET'])
def question ():
    qid = request.Args.Get ('id', default=0, type=int)
    if 'id' in session:
        question, expected_answer = questions[qid]
        return render_template ('question. Html', question=question, expected_answer=expected_answer, id=qid)  
    else:
        return redirect (url_for ('home'))

@app.Route ('/score', methods=['POST'])
def score ():
    qid = request.Form.Get ('id', type=int)
    guess = request.Form.Get ('guess', type=float)
    user_id = session.Get ('id')

    if user_id and qid is not None and guess is not None:
        # Add to the list of all guesses for that question
        scores.setdefault(qid, []).append(guess)
        
        # Add to the person's guesses
        entries.setdefault(user_id, {
   })[qid] = guess

        # Compute the person's log loss
        user_log_loss = log_loss([answers[qid]], [guess], labels=[0, 1])

        # Compare with others
        other_scores = scores[qid]
        other_log_losses = log_loss([answers[qid]] \* len(other_scores), other_scores, labels=[0, 1])

        comparison = 'better' if user_log_loss < other_log_losses else 'worse'

        return render_template('score.html', user_log_loss=user_log_loss, comparison=comparison)
    else:
        return redirect(url_for('home'))

If __name__ == "__main__":
    App.Run (debug=True)

这段代码作为初始代码,实现了三个端点:/home/question/score,并管理全局变量来记录用户预测和计算对数损失得分。

不过,要让代码正常运行,你还需要创建用于渲染的模板文件,包括 home.htmlquestion.htmlscore.html。这些模板文件应该包含你的 HTML 代码,并预留出动态内容的占位符。

建议你阅读 Flask 文档中关于会话和模板的部分,以便更好地理解它们的使用。

需要注意的是,使用全局变量来存储信息适用于用户较少且应用运行时间较短的小型应用或快速原型。但如果是在生产环境或有更多用户的应用中,你可能需要使用数据库或其他数据存储系统来管理这些信息。

页面受限,原始英文版本查看,中文版本查看

页面受限,

{% endtimeline %}

{% endhideToggle %}

然后,当我再次遇到困难,这次是需要连接到 MQTT 服务器时,我再次请模型帮助我解决

{% hideToggle ChatGPT 对话记录 - 连接到 MQTT 服务器 %}

{% timeline 对话记录 %}

为 Raspberry Pi Pico W Zero 配置 HTTP 请求的端口

要为 Raspberry Pi Pico W Zero 配置一个用于接收 HTTP 请求的端口,您需要按照以下步骤进行:

  1. 连接 Pico W Zero 到您的网络:

    • 确保您的 Pico W Zero 具备 WiFi 功能并已连接至本地网络。
  2. 设置 Pico W Zero 的 Web 服务器:

    • 您需要编写代码,让 Pico W Zero 能够处理 HTTP 请求。Micropython 是非常适合 Pico W Zero 这类微控制器的编程环境。
    • 如果还未安装 MicroPython,请先将其安装到您的 Pico W Zero 上。
    • 编写一个 Micropython 脚本以启动基础的 Web 服务器。以下是一个示例:
     import network
     import socket
     
     ssid = 'YOUR_SSID'
     password = 'YOUR_PASSWORD'
     
     station = network.WLAN(network.STA_IF)
     station.active(True)
     station.connect(ssid, password)
     
     while station.isconnected() == False:
       pass
     
     print('Connection successful')
     print(station.ifconfig())
     
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s.bind(('', 80))
     s.listen(5)
     
     while True:
       conn, addr = s.accept()
       print('Got a connection from %s' % str(addr))
       request = conn.recv(1024)
       print('Content = %s' % str(request))
       response = 'HTTP/1.1 200 OK\n\nHello World!'
       conn.send(response)
       conn.close()
  1. 在路由器上设置端口转发:

    • 如果您希望从外部网络访问 Pico W Zero,需要将外部端口转发到 Pico W Zero 的内部 IP 地址及端口。
    • 登录到路由器的管理界面,找到端口转发设置。
    • 创建一条规则,将外部端口(如 8080)转发到 Pico W Zero 的内部 IP 地址的 80 端口。
    • 确保您的 ISP 不会阻止您所使用的端口。
  2. 测试设置:

    • 在同一网络中的设备上访问 http://<Pico W IP 地址>/ 来测试服务器。
    • 从外部网络访问时,使用您的公共 IP 地址并添加转发的端口,例如 http://<公共 IP 地址>:8080/
  3. 安全性建议:

    • 在将设备直接暴露在互联网上时要格外小心。确保只开放必要的端口,并考虑使用防火墙或 VPN 增强安全性。

如果您需要更详细的指导,请告知我!

页面受限,

{% endtimeline %}
{% endhideToggle %}

我现在经常这样做。甚至这个部分开头的例子也不是虚构的——这是我在请教如何使用 Flexbox,因为我上次学习 HTML 布局方式时还在用 div 代替表格。

{% hideToggle ChatGPT 对话记录 - 请教如何使用 Flexbox %}

{% timeline 对话记录 %}

使用 Flexbox 实现一个页面布局,其中左侧有一个 ID 为 "a" 的元素,右侧有两个 ID 分别为 "b" 和 "c" 的元素

以下是如何使用 Flexbox 实现这一布局的示例:
HTML:

<div class="container">
  <div id="a">Element A</div>
  <div class="right">
    <div id="b">Element B</div>
    <div id="c">Element C</div>
  </div>
</div>

CSS:

.container {
   
  Display: flex;
  Justify-content: space-between;
  Align-items: center;
}

#a {
   
  Flex: 0 0 auto;
  Margin-right: 20 px;
}

.right {
   
  Display: flex;
  Justify-content: flex-end;
  Align-items: center;
}

#b , #c {
   
  Margin-left: 20 px;
}

以下是 CSS 代码的主要功能解释:

  • .container 元素设置为 display: flex,使其子元素能够使用 Flexbox 布局。
  • justify-content: space-between 用于在左侧和右侧元素之间留出空间。
  • align-items: center 用于将元素垂直居中。
  • #aflex: 0 0 auto 设置了它的宽度只占用所需的空间,并通过 margin-right 属性在 #a 和右侧元素之间创建间距。
  • 如果希望 #b#c 垂直堆叠,可以将它们放在一个 flex 容器内,并使用 flex-direction: column 实现堆叠。
Can you do this and keep the three divs for a, b, and c all siblings? That is, without the "right" div?

Sure, you can achieve the same layout without using the “right” container. Here’s an example:

HTML:

<div class="container">
  <div id="a">Element A</div>
  <div id="b">Element B</div>
  <div id="c">Element C</div>
</div>

CSS:

.container {
   
  Display: flex;
  Justify-content: space-between;
  Align-items: center;
}

#a {
   
  Flex: 0 0 auto;
  Margin-right: 20 px;
}

#b , #c {
   
  Flex: 0 0 auto;
}

Here’s a breakdown of what’s happening in the CSS:

  • The . Container element is set to display: flex so that its child elements can be positioned using flexbox.
  • The justify-content: space-between property is used to create space between the left and right elements.
  • The align-items: center property is used to vertically center the elements.
  • The flex: 0 0 auto property on #a, #b, and #c sets their flex basis to auto, which means they will take up only the necessary space.
  • The margin-right: 20 px property on #a creates a gap between #a and #b.
  • Since #b and #c are both siblings, they will automatically be positioned next to each other without the need for an additional container.
I want b and c to stack vertically please

Sure, to stack #b and #c vertically while keeping #a on the left, you can nest another flex container inside the main . Container. Here’s an example:

HTML:

<div class="container">
  <div id="a">Element A</div>
  <div class="right">
    <div id="b">Element B</div>
    <div id="c">Element C</div>
  </div>
</div>

CSS:

.container {
   
  Display: flex;
  Justify-content: space-between;
  Align-items: center;
}

#a {
   
  Flex: 0 0 auto;
  Margin-right: 20 px;
}

.right {
   
  Display: flex;
  Flex-direction: column;
}

#b , #c {
   
  Margin-top: 20 px;
}

Here’s a breakdown of what’s happening in the CSS:

  • The . Container element is set to display: flex so that its child elements can be positioned using flexbox.
  • The justify-content: space-between property is used to create space between the left and right elements.
  • The align-items: center property is used to vertically center the elements.
  • The flex: 0 0 auto property on #a sets its flex basis to auto, which means it will take up only the necessary space, and the margin-right property creates a gap between #a and the right elements.
  • The . Right element is set to display: flex and flex-direction: column to create a vertical stack of #b and #c.
  • The margin-top: 20 px property on #b and #c creates a gap between the stacked elements.
I want b and c to stack vertically without the other div.

Sure, you can achieve this by nesting another flex container inside the . Container element and then using the flex-direction: column property on the nested container to stack #b and #c vertically. Here’s an example:

HTML:

<div class="container">
  <div id="a">Element A</div>
  <div class="stacked">
    <div id="b">Element B</div>
    <div id="c">Element C</div>
  </div>
</div>

CSS:

.container {
   
  Display: flex;
  Justify-content: space-between;
  Align-items: center;
}

#a {
   
  Flex: 0 0 auto;
  Margin-right: 20 px;
}

.stacked {
   
  Display: flex;
  Flex-direction: column;
}

#b , #c {
   
  Flex: 0 0 auto;
  Margin-top: 20 px;
}

Here’s a breakdown of what’s happening in the CSS:

  • The . Container element is set to display: flex so that its child elements can be positioned using flexbox.
  • The justify-content: space-between property is used to create space between the left and right elements.
  • The align-items: center property is used to vertically center the elements.
  • The flex: 0 0 auto property on #a, #b, and #c sets their flex basis to auto, which means they will take up only the necessary space.
  • The margin-right: 20 px property on #a creates a gap between #a and the stacked elements.
  • The . Stacked element is set to display: flex and flex-direction: column to create a vertical stack of #b and #c.
  • The margin-top: 20 px property on #b and #c creates a gap between the stacked elements.

{% endtimeline %}
{% endhideToggle %}

简化代码

作为一名安全研究员,我经常面对这样一种情况:需要分析一个包含几千行代码的研究项目代码仓库,以便了解其工作原理,然后找出可攻击的点。听起来似乎不难,如果所有人都写干净的代码的话,确实如此,但事实并非如此。研究人员通常不会因为代码的整洁而受到激励,因此很多人只会发布那些能运行的代码,无论其质量如何。(我也不例外。)

虽然我不能分享任何与研究相关的例子,但可以分享一个我个人项目中的例子。有人说我对康威的生命游戏有着不健康的偏爱。最近,我在尝试通过 python 快速评估一些生命游戏的模式。有一个叫 golly 的 C++ 工具非常适合这个任务,但我并不想把我的 python 代码重写成 C++。

golly 有一个可以满足我需求的命令行工具——我只需要找到正确调用它的方法。第一步是从支持大约 50 个不同命令行选项的 C++ 代码中,只让它执行我需要的那个功能。所以我将 500 行的 C++ 代码输入到 LLM 中,请求生成一个更简洁的文件来完成同样的任务

结果非常完美。随后,我请求模型生成了一个围绕这段 C++ 代码的 python 包装器,也同样顺利完成。

{% hideToggle ChatGPT 对话记录 - 请求生成一个更简洁的文件来完成同样的任务 %}

{% timeline 对话记录 %}

Given this cpp file

// See docs/License.html for the copyright notice.

#include "qlifealgo.h"
#include "hlifealgo.h"
#include "generationsalgo.h"
#include "ltlalgo.h"
#include "jvnalgo.h"
#include "superalgo.h"
#include "ruleloaderalgo.h"
#include "readpattern.h"
#include "util.h"
#include "viewport.h"
#include "liferender.h"
#include "writepattern.h"
#include <stdlib.h>
#include <iostream>
#include <cstdio>
#include <string.h>
#include <cstdlib>

using namespace std ;

double start ;
int maxtime = 0 ;
double timestamp() {
   
   double now = gollySecondCount() ;
   double r = now - start ;
   if (start == 0)
      start = now ;
   else if (maxtime &amp;&amp; r > maxtime)
      exit(0) ;   
   return r ;
}

viewport viewport(1000, 1000) ;
lifealgo *imp = 0 ;

/*
 *   This is a "renderer" that is just stubs, for performance testing.
 */
class nullrender : public liferender {
   
public:
   nullrender() {
   }
   virtual ~nullrender() {
   }
   virtual void pixblit(int, int, int, int, unsigned char*, int) {
   }
   virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b,
                          unsigned char* dead_alpha, unsigned char* live_alpha) {
   
      static unsigned char dummy[256];
      *r = *g = *b = dummy;
      *dead_alpha = *live_alpha = 255;
   }
} ;
nullrender renderer ;

// the RuleLoader algo looks for .rule files in the user_rules directory
// then in the supplied_rules directory
char* user_rules = (char *)"";              // can be changed by -s or --search
char* supplied_rules = (char *)"Rules/";

int benchmark ; // show timing?
/*
 *   This lifeerrors is used to check rendering during a progress dialog.
 */
class progerrors : public lifeerrors {
   
public:
   progerrors() {
   }
   virtual void fatal(const char *s) {
    cout << "Fatal error: " << s << endl ; exit(10) ; }
   virtual void warning(const char *s) {
    cout << "Warning: " << s << endl ; }
   virtual void status(const char *s) {
    
      if (benchmark)
         cout << timestamp() << " " << s << endl ;
      else {
   
         timestamp() ;
         cout << s << endl ;
      }
   }
   virtual void beginprogress(const char *s) {
    abortprogress(0, s) ; }
   virtual bool abortprogress(double, const char *) ;
   virtual void endprogress() {
    abortprogress(1, "") ; }
   virtual const char* getuserrules() {
    return user_rules ; }
   virtual const char* getrulesdir() {
    return supplied_rules ; }
} ;
progerrors progerrors_instance ;

bool progerrors::abortprogress(double, const char *) {
   
   imp->draw(viewport, renderer) ;
   return 0 ;
}

/*
 *   This is our standard lifeerrors.
 */
class stderrors : public lifeerrors {
   
public:
   stderrors() {
   }
   virtual void fatal(const char *s) {
    cout << "Fatal error: " << s << endl ; exit(10) ; }
   virtual void warning(const char *s) {
    cout << "Warning: " << s << endl ; }
   virtual void status(const char *s) {
   
      if (benchmark)
         cout << timestamp() << " " << s << endl ;
      else {
   
         timestamp() ;
         cout << s << endl ;
      }
   }
   virtual void beginprogress(const char *) {
   }
   virtual bool abortprogress(double, const char *) {
    return 0 ; }
   virtual void endprogress() {
   }
   virtual const char* getuserrules() {
    return user_rules ; }
   virtual const char* getrulesdir() {
    return supplied_rules ; }
} ;
stderrors stderrors_instance ;

char *filename ;
;