Transcription
你的爱。 >> 嘿,怎么了,Papa Fam?我是你们的 Sunny,我们又回来了,带来一个全新的系列,《Vibe Code with me the right way》,第一集。这是直播。别担心,之后频道上也会有。但整个系列都致力于向你介绍人工智能,掌握人工智能,它将由你来塑造。所以,如果你在观看时喜欢这些内容,请留下评论,在直播聊天中告诉我。今天我们将深入到一个完整的构建,而且它完全适合初学者。这将会让你大吃一惊。现在是进入编程领域最容易的时代。所以,让我们开始吧,进入《Vibe Code with me the right way》第一集,Indeed 克隆版。欢迎来到频道,各位。我是你们的 Sunny,我们即将在这个频道做一件大事。我觉得我们现在将进入这个领域的一个全新时代,我将在这个频道引领它。各位,请在三、二、一中向演示打个招呼。让我们来看看。砰。嘿,来了。我喜欢这个。我们有 Omshex。我爱你,Sunny,来自尼日利亚。我非常感谢你,伙计。那种积极的能量,各位,我们这里有,这太不可思议了,对吧?当我告诉你,就像疯狂的魔法一样,我看到了你,伙计。我看到了你。对。当我告诉你们,这个构建是令人难以置信的庞大,但今天比以往任何时候都更容易构建它。相信我,这将为许多许多人打开大门,对吧?所以,我们有了,一个 Indeed 克隆版。现在,不要担心克隆本身。我想向你们展示,克隆本身在某种程度上是一个技术演示,对吧?我想向你们展示并提供你们需要的所有工具,以便构建任何你们想要的东西。对。所以,这将是一个小应用演示,然后这将是我们的起始测试项目。请记住,我已经给了你们所有这些代码。如果你现在进入描述中的链接,那里有一个表格。你填写它,我将免费发送给你访问整个代码库的权限。看,Vibe Code the right way 第一集 Indeed 克隆版。好了,你们可以自己看看,对吧?我们将它命名为 Jobly。正如你们所见,我们可以找到工作。它还有一个面向雇主的管理面板。这一切都归功于今天令人惊叹的赞助商 Clerk。稍后会详细介绍。对。所以,让我们现在就开始吧。所以,让我们做一个快速的技术演示。所以,显然 Indeed 是一个非常受欢迎的应用,对吧?所以,如果我们点击浏览工作,我们可以自己去寻找。我们可以看到所有,你知道的,那里有哪些不同的工作机会,对吧?而且,当我这样做的时候,请告诉我你在哪里观看。我希望聊天今天能火爆起来,因为我想要很多不同种类的,这将是一个我今天想要做的完全不同的主题,并稍微改变一下,对吧?所以,让我们申请其中一份工作。正如你所看到的,它说立即申请,你的个人资料将被共享。看看这个。它已经有一个完整的个人资料了。我的意思是,它怎么会得到那个?对吧?三行,两个条目。嗯,我们这里有一个完整的后端系统。所以,让我们去编辑我的个人资料。你可以看到,我将向你们展示如何做到这一切。所以,看,你可以拥有你的全部详细信息。你可以拥有,就像一个 LinkedIn 式的方法,对吧?所以,我们有高级前端、全栈开发人员、初级,然后你有你的教育、认证、一目了然的技能。你还可以进行拖放文件上传。所有这些都将被,你知道的,介绍。嘿,我们有澳大利亚、马其顿、印度。伙计们,欢迎来到直播。继续告诉我你们来自哪里。我们也有斯里兰卡。伙计们,怎么了?直播已经达到 100 人了。太棒了。这就是我说的。狠狠地按赞。狠狠地按赞。我们还有一些额外的东西。所以,如果我们现在去工作面板,我们有完整的搜索功能。所以,你进去,就像输入客户搜索一样,例如,客户成功管理。假设我想保存这个。我们有保存功能,所有的一切。甚至还有一个完整的通知系统,对吧?所以,完整的通知面板。我们可以访问我们所需的一切。当然,我们还可以访问 Clerk 令人惊叹的方面。对。现在,我更进一步了。现在,这些工作不是凭空出现的。好的?假设你是一名招聘人员。在这种情况下,我不仅仅构建了一个 B2C 应用,也就是我刚才演示的。不,不,不。我们做得更远了,伙计们。我们构建了一个 B2B 多租户混合应用。是的,我把所有这些都说了一句话。如果你不明白这些是什么,别担心。我今天会解释一切,这样你就能理解这些术语,并能在这个领域继续前进。对。所以,让我们点击“面向雇主”标签。好的?现在你可以在这里看到我有一个公司仪表板。我们有一个完整的计费方面。所以,在这种情况下,你实际上可以有一个完整的计费计划。现在我们使用的是增长计划。我将向你展示如何做到这一切。现在你可能听说过基于角色的权限访问。如果你以前做过任何编程,你没有担心过,我将向你解释一切。但它的工作方式通常是,你有公司。这些公司可以是任何人。可以是 Oracle、Microsoft,随便什么。它们可以是小公司,大公司。没关系。但实际上,它们有一个账户,然后人们可以登录到该账户,这就是所谓的 B2B 组织,对吧?所以我将向你们展示一个组织示例,我们可以在我们的应用中创建几个组织。我将向你们展示如何做到这一点,如何拥有多个席位并设置限制,以及如何完成所有这些事情,比如邀请流程,所有这些好的东西,对吧?所以,让我们暂时看一下我们的仪表板,假设我将邀请,嗯,假设我将邀请 Jay,对吧?所以,我暂时不会透露 Jay 的信息。我将把他的电子邮件输入到这里,Gmail。然后我们来做 RO。我将向下滚动一点,这样你就可以隐藏它,否则他会杀了我的。如果我们现在点击 RO,我们有成员、管理员和招聘人员。对。所以,在这种情况下,成员只是一个可以查看事物的成员。我们有管理员,他们可以做任何事情。然后我们有招聘人员,他们可以做创建职位空缺之类的事情。对。哦,Jay 说没关系,伙计们。所以,你们,你知道的?我将显示他的电子邮件。就是这样。给你。谢谢你,Jay。好的。所以,让我们首先给 Jay,嗯,假设成员访问权限,对吧?所以,如果我们现在点击发送邀请,那将发送一个邀请给 Jay。现在,我们可以从这里做到。我们也可以从,如果我们去我们的管理组织面板。我们现在可以看到有一个待处理的 Jay 的邀请。看,作为一个成员角色,现在这些成员、招聘人员、管理员,所有这些好的东西都有访问限制。所以,假设这个用户是管理员。好的?所以,他们能够做任何事情。他们可以管理计费。他们可以创建工作申请。所以,在这种情况下,我们可以看到这家公司列出的所有不同的工作,哪些已经关闭。我们甚至可以点击申请本身,看看里面的申请人是谁。当我告诉你们,这是一个完整的构建时,这是令人难以置信的。而且,做到这一点从未如此容易。我们为最高计划提供了高级过滤功能。我们还可以创建一个新的职位空缺,就像这样。甚至在第一个被接受的申请人之后自动关闭。对。所以,你们可以自己看看。这太不可思议了。这是一个巨大的应用,我完全免费地提供给你们。对。所以,你们可以自己看看。如果我们去查看申请,假设,例如,我将查看我们所有开放的职位。好的?所以,在这种情况下,我们有几个不同的职位,比如后端工程师。我可以看到很多人申请了这个职位。在这种情况下,我们已经接受了两个人,对吧?我们已经接受了两个人。你可以看到我们如何将他们移至待审、拒绝候选人等等。如果有人撤回他们的申请,我们可以做到所有这些。今天,在这个构建中,所有这些都将被涵盖,对吧?但我们正在做一些与往常截然不同的事情,对吧?通常我会手动完成,一行一行地编码。我将向你们展示这个领域真正的现实是如何发展的。我们将有效地,当我说的 Vibe Coding 时,我将向你们展示理解 Vibe Coding 是什么意思的正确方法。好的?我们不会做那种你做错了,你不明白发生了什么的那种 Vibe Coding。我将解释一切。当你进行人工智能辅助编码时,你将知道所有你应该知道的事情。好的?它将使你成为一个绝对的怪物。我向你保证,对吧?所以,在这种情况下,我们也有针对不同用户的通知。但我又想向你们展示一件事,限制方面。所以,如果我们现在去雇主面板,我相信这个成员是一名招聘人员。所以,你看他们为什么不能管理计费方面的事情,对吧?但他们可以创建一个新的职位,对吧?所以,在这种情况下,如果我限制该用户,让我们去,我正在切换不同的用户成员身份。所以,这个用户,我将把他的状态改为成员。好的?现在,如果我回到这里,现在他是一名成员。啊,你看,我们突然只能看到职位。我们不能创建新的职位空缺。所以,这具有完整的基于角色的访问控制。好的?现在,你可能会想,好吧,我们到底要怎么做这一切,对吧?嗯,感谢 Clerk 的各位。这实际上非常容易,对吧?所以,我将向你们展示 Clerk 的各位。前往 clerk.com,自己看看。而且,是的,这个视频是有赞助的。它帮助我免费做这些事情。所以,这就是事情的真相。但我向你保证,我永远不会使用其他不同的服务来做这类事情。它使得构建 B2C、B2B 应用、身份验证、计费、整个流程变得如此容易,对吧?所以,如果我们向下滚动,你可以看到所有开箱即用的身份验证方法都为我们处理好了。我指的是多因素认证、短信、一次性密码,所有这些东西。在 Clerk 中就是这么简单。我们有多租户。你知道,如果你不知道什么是多租户,就像我之前解释的那样,当你拥有组织时,这些是拥有多个席位的大公司,你知道,就像你将要构建的真正的企业级的东西。这实际上就是我们在这里拥有的多租户,对吧?所以,从头开始构建它是一件非常疯狂的事情。所以,Clerk 的各位让它变得如此容易。我们今天还将包含所有付款流程。最棒的是,你不需要做一个 Stripe 的 webhook。所以,我们今天将要涵盖的内容真是太疯狂了。我们当然会使用人工智能编码,因为这是一个 Vibe Coding 教程。所以,我将向你们展示我所知道的一切以及我如何在当今世界工作。所以,在这种情况下,如果我们简单地输入 Clerk with AI,我希望你们习惯于跟着我一起,以一种非常,你知道的,这将是一种更像是坐在一起的方法。所以,如果我们点击使用 Clerk with AI,这就是我们将要深入研究的。Clerk 技能和 MCP 服务器。我将解释什么是技能,什么是 MCP 服务器,它们如何有效地拨打你的光标,你知道的,无论你使用的是什么,IDE、Claude Code、Cursor,无论是什么。但这将是一个很棒的教程。好的,所以让我们开始分解。我想打开一个画板,这样我们就可以开始画图,并确保如果你想在我和你交谈、解释事情的时候访问代码,我希望你去填写那个表格,然后我会发送给你所有你需要知道的东西,对吧?而且,请记住这是一个系列。所以,根据你们给我的每一个反馈,无论是直播聊天,还是评论,无论是什么,每一集都将基于此。所以,这完全取决于你们在这个频道上想要什么。你们现在拥有创作自由来告诉我。我将把这个系列朝着这个方向转移,完全围绕着人工智能领域,因为这就是我们前进的方向。好的?所以,填写这个,获取代码访问权限,然后跟着我。好的?所以,在这种情况下,我通常会谈论技术栈,对吧?我将做一个非常简短的技术栈介绍,因为我想让你们理解不同的高级基本原理。好的,你知道吗?事实上,让我们改变一下。我们将说你需要知道什么。好的,这是,我之所以要这样教,是因为这实际上就是我在我的辅导课程中教的方式,对吧?所以,你可以随时查看所有这些。这些都在下面的描述中。但我将向你们展示我如何有效地教学,我们将简单地采用这种方法。所以,让我们现在就开始吧。哦,是的,Jayce 实际上给我发了一封电子邮件,好的,那太好了。我们稍后可以展示。是的。所以,在这种情况下,我们当然是用 Nex.js 构建的。好的?所以,当你进行 Vibe Coding 时,你的 Vibe Coding 平台,你知道,理解基本原理非常重要。是的,人工智能可以为我们编码,但你需要知道你在做什么。这就像说,让我们假设人工智能可以,你知道的,它有真实的双手,它可以在现实世界中做事情。就像,去建造一座房子。好的?用什么?我们是说用稻草吗?我们是说用砖块,还是用什么来建造房子?软件也是如此,对吧?任何东西都是如此。无论你用人工智能做什么,无论是自动化,无论是任何东西,你都需要知道你将在其下构建的内容的基本原理。所以,NextJS 16 是我们在网络领域所做的。它性能优越,速度快,可扩展,我用它做了大量的生产应用。在我看来,它是王者。好的?在这之下是 React。好的?所以,当我们让人工智能为我们编码时,这就是它将要编码的库,也是它将要编码的框架。好的?我们引导它。我们开始朝着这个方向引导它,对吧?所以,在这种情况下,我们有了这两个。当我们进行样式设计时,我们有一个叫做 Tailwind CSS 的东西。现在,通常以前的工作方式是,你会去手动编写所有东西,对吧?但不要误会,Tailwind CSS 使它容易了很多。但后来出现了 Shad Cenne,对吧?Shaden 是一个非常非常好的,非常有主见的库。所以,在这种情况下,如果我们在这里说 Shaden,去组件这里。伙计们,你们好。我看到你们在聊天中。Nicola,我看到你们了。Son of code。我非常感谢你。你太棒了,伙计。我喜欢你在聊天中的能量。对。所以,在这种情况下,你可以在这里看到我们设计系统的基础。也向这些伙计们致敬,因为他们目前正在经历一些事情,而且他们非常棒。他们有一个很棒的社区支持他们,他们是真正的人工智能优先的。所以,他们有 MCP 服务器,你可以利用和使用。我们今天将做所有这些。对。所以,在这种情况下,回到黑板,你需要知道什么。所以,让我们快速浏览一下。我们有 Clerk 的方面,Clerk 将处理我们的身份验证和计费。好的?所以,有效地,我们拥有了一切。拼图的最后一块是数据库。现在,我们今天将使用 Convex,但这是我今天想说的重点,好的?如果你想,你可以完全替换掉。绝对没问题。我展示的是我们今天使用的,但如果你喜欢某个数据库,绝对没问题。我展示 Clerk 的唯一原因有两个,一是我是 Clerk 的合作伙伴,我爱他们,因为他们非常棒。我与这个品牌一起成长。他们从一开始就非常棒,他们以最好的方式处理事情。而且,顺便说一句,他们的价格与 Stripe 完全相同。所以,如果你认为,我要去 Stripe 构建一切并省钱,伙计们。价格与 Stripe 完全相同。所以,在我看来,你会疯狂地不这样做,而且它为你节省了大量工作。你应该构建令人惊叹的应用,而不是专注于重建其中的一部分。对。所以,我们这里有一个很棒的问题。Nicola 说,“嘿,有可能做一个关于从初级到中级,中级到高级架构,CI 部署,拥有项目的旅程的直播视频吗?”你知道吗?我确实在我们的课程和社区中谈论过这些。现在,我们正在启动一个新社区。所以,我建议的是,如果你想了解这些高级知识,请务必免费获取代码,你将进入我们的电子邮件列表,然后我将向你发送今天的构建代码,这真是太棒了,然后确保你留意你的收件箱,因为我们非常接近在社区中做到你刚才所说的,在那里我们可以扩展它,我们可以以它应有的质量来做到这一点,而且我们倾向于在 Zoom 会议中做到。好的,那么现在你需要了解人工智能方面的什么呢?对吧?通常之前是手动编码,对吧?所以,之前我们做了大量的体力劳动,好的?我听到了你们频道上的反馈,Sunny,人们不再这样编码了。Sunny,你还这样编码吗?事实是,伙计们,现实是,不,它正朝着自动化编码的方向发展。所以,这是否意味着工作正在被取代?不,绝对不是。事实上,它只是改变了我们应该思考的方式。另外,欢迎来到 Papa Social,Mobile Heat。我非常感谢你。对。我们将使用什么平台进行 Vibe?是的。我现在就去。好的?所以,我们以前是手动编码,我们做了很多这样的事情。现在,和以前一样的是什么,对吧?所以,我们将说,让我们称之为人工智能之后。好的?所以,之前,然后是人工智能之后。好的?所以,这是之前的那条线,以及之后的那条线。所以,现在仍然相同的是架构。好的?是的,我们可以和人工智能谈论如何使用它,对吧?或者如何构建我们的平台,但你仍然需要了解你的架构。你仍然需要知道如何正确地构建某样东西。好的?因为你可以让人工智能为你构建,你知道的,一个 WhatsApp 应用,它可以在一千万种不同的方式中构建它。好的?架构,底层技术以及基本原理。为什么这在大多数时候很重要?我真的想引起大家注意这一点,因为有很多人现在正在使用人工智能编码平台,认为仅仅因为你构建了一个前端,它就是一个生产应用。伙计们,我向你们保证。现实是,当你获得更多客户,获得更多数据库使用量,获得更多 API 调用,在你的应用中最简单层面发生很多事情时,问题就会出现。所以,当你只是测试你的应用,或者向你的妈妈或朋友展示时,你不会有问题,但当你进入生产环境时,你就会被那些会使你的应用充满 bug 的东西搞砸。好的?所以,你需要了解基本原理。那意味着什么?就是当人工智能编写我们的代码时,我们应该问人工智能什么?也许我们甚至不审查自己的代码。也许我们让人工智能去做。我今天将向你们展示我所有的技巧,但你首先需要知道要寻找什么。就像,如果人工智能 somehow 构建了一座房子,如果,让我们说它可以做到。如果它建造了一座房子,你基本上可以这样说,“好吧,如果你知道你在做什么,好的,我想让你去挑出所有这些小缝隙。也许墙上有洞,或者这个那个。”但假设我一生都没有建造过房子,我看到一个草房子出来了。伙计们,那个人会很兴奋。他一生都没有建造过房子。这不,你明白我的意思吗?你必须知道你在做什么。否则,你只会对最基本的东西感到印象深刻。不要做那个傻瓜。了解你在做什么,然后你就可以真正地把它分层,它会非常强大。好的,现在我们来谈谈工具。所以,你有很多 IDE,对吧?让我们简单地称它们为 AI IDE。我们可以使用 Cursor,这是我们将要使用的,它是一个很棒的 IDE,对吧?而且,不,我们没有得到 Cursor 的赞助,好的?你可以使用 VS Code 和 GitHub Copilot。你可以使用 Claude Code,对吧?你甚至可以使用,有很多平台。有 Kira。有几个,对吧?但在这种情况下,我们将进入 Cursor。现在,我唯一的反馈是,你还有 Wind 和 Kuro 之类的东西。所以,只是把它们放在这里。Windsurf,Curo,还有一些其他区域。对。现在,有了这些,很多都是 IDE。它们有一个,你知道的,一个 UI,你可以与之合作,但 Claude Code 是很多人都在使用的唯一一个,而且它确实很好。但是 Claude Code 有一个问题。哦,还有反重力。我把它记下来。抱歉,伙计们。好东西。这就是为什么聊天很重要,对吧?我们需要社区像这样火爆起来,对吧?Claude Code 是我今天想提到的。今天,因为你们很多人都在使用它。但是 Claude Code 的问题是,如果你不了解你的基本原理,或者不知道你在做什么,就很难直观地理解那个代码库里到底发生了什么。这是我与许多,你知道的,我们现在正在教的学生遇到的问题,他们正在使用人工智能,他们正在快速前进,但他们只是在我们称之为人工智能方面的“AI 垃圾”。而“AI 垃圾”的问题在于它会导致早期原则、架构和你的基本原理失效。而你不需要那样发生,对吧?因为你不想因此而头疼,我向你保证。所以,在这种情况下,一旦你擅长理解这些东西,当然你可以使用 Claude Code,但不要犯跳过视觉 IDE 的错误,因为你可以有六个 Claude Code 终端,我有时会使用并行终端,但我可以向你保证,我正在检查每一个。所以,请确保你今天跟着我,理解我做的每一个小细节,并且请,请提问,我的目标是让这个社区以另一种方式复兴,Papa Fam 在人工智能领域全员回归,我希望你们尽可能多地提问。如果需要,我真的会在这里坐几个小时回答你们的问题。所以,我只要求你们狠狠地按赞,我们已经在直播平台上有 200 人了。这真是太棒了。说实话,欢迎回来,各位。好的,所以让我们开始吧。好的,现在我想首先向你们展示,让我们深入研究一下,并告诉我,你们现在喜欢这种内容吗?对吧?如果喜欢,就像我说的,狠狠地按赞。好的,所以告诉我。你们更喜欢视觉讲解,还是想深入研究?但是人工智能有很多相关的东西。好的?所以,在这种情况下,让我们把它放在这里。好的?所以,人工智能的核心是模型。好的,请原谅我可爱的画。好的,人工智能的核心是模型。好的,人工智能的核心是 LLM。现在,这就是你所知道的 ChatGPT。所以,例如,它可以是 GPT 53 Codeex,对吧?这些是你的 LLM,对吧?你有 GPT 53 Codeex。你有像 Claude、Opus 46、Sonet 46、Haiku 这样的模型,所有这些模型。你有 Minimax、Kimi 2.5,所有这些东西。好的?你现在需要了解的主要事情是,首先,你的预算是多少,对吧?你的预算是多少?这是主要的事情,你知道的,如果你能负担得起使用 Claude Opus 4.6,在我看来,它是与 53 Codeex 并列的王者。它们都有各自的优缺点。我认为 53 Codeex 的成本效益更高,但如果你有能力,Opus 4.6 仍然是这个领域的王者。然后,当然,你还有 Gemini 之类的东西,你知道的,你可以去玩很多东西。好的?但重点是,总有一个适合你,取决于你的预算。只要明白,每一个都更贵,因为它们可能更强大。而且每个都有不同的模型。所以,让我们以这两个为例。好的?现在,当你使用 LLM 时,也有很多种使用 LLM 的方法,对吧?你有不同的东西。你有推理,对吧?你可以打开或关闭推理。什么是推理?对吧?推理是你问人工智能一个问题。它会思考吗?对吧?它有那个思考提示吗?你知道的,它在思考,有什么事情正在发生,或者什么事情没有发生。这就是所谓的推理。好的?现在,有了很多新的模型,你还有一个努力的程度。好的?现在,努力的程度可以是低、中、高、极高等等。就像每个都有自己的术语。但重点是,你知道的,有时你可能会听到“人工智能太贵了”。“我的天哪,我用完了所有的 token。”是的。因为你可能默认开启了推理,而且是极高的,然后下一件事就是你的 AI 工作了几个小时,花费了你可能没有预料到的钱。所以,你看,你需要了解你在使用什么,你在做什么任务,以及像 Open Claude 这样的事情,你可以有不同的方式来拥有不同的代理,不同的模型,然后它可以使事情变得更具成本效益。是的,我现在正在充分利用 Open Claude。我有大约 10 个代理在为我做疯狂的事情。所以,如果你想了解这一点,请订阅并点赞。好的?所以,这是目前 LLM 的基础。现在,我们有一些非常酷的重要原则,我想让你们理解。好的?第一个是上下文窗口。好的,上下文窗口。什么是上下文窗口?对吧?当我们与人工智能交谈时,这个上下文窗口,让我们假设,例如,很多通常有大约 20 万个 token 的上下文窗口,对吧?然后 Opus 46,我认为 53,我不确定 53 是否已经有了,但 46 可以达到,例如,一百万个 token。好的?所以,上下文窗口基本上是,如果我现在和你聊天,假设你是人工智能,我是人类。好的?我们现在正在聊天,我一直在和你谈论事情。我们将建立一些东西,对吧?就像正在发生的是,你的上下文窗口正在被所有这些信息慢慢填满,而不仅仅是聊天。还有其他一些事情。可能是工具。可能是它在网上进行的各种调用,以及所有这些东西,对吧?所以,当你填满那个上下文窗口时,你需要明白,有时如果你超过了限制,假设我达到了 20 万的上下文窗口限制,那么它会尝试,它会尝试总结,因为它需要重置它的上下文窗口,而且对很多人来说更糟糕的是,现在你有了一百万个 token,这可能意味着,“我的天哪,我们有更多的上下文窗口,这是一件好事,对吧?”但问题是,一旦你超过了 20 万 token,我保证 95% 的人都没有意识到他们已经达到了 20 万 token。他们只是继续聊天。你应该做的是重置你的上下文窗口,然后聊天,因为在 20 万到一百万之间发生的是,你的 API 成本每次请求都会翻倍,而且请求越来越大,这就是为什么你像疯了一样烧钱。所以,你看,有一些方法你需要了解,这就是现在的问题。没有人谈论这个,而这个社区将解决这个问题,你们将成为这些东西的大师。我向你保证。好的?所以,我们有上下文窗口。好的?所以,这将是第一个原则,我们今天也将涵盖所有这些内容。接下来是,当你通常有一个叫做规则文件的东西时,这基本上是人工智能的规则。现在,很多人会知道这是什么。所以,这就像,你知道的,做这个,不要做那个,你给你的 AI 一些规则,把它想象成,我们将把我们的 AI 命名为,例如,在这个例子中是 Henry,对吧?所以,Henry 是我们的 AI。现在,我们告诉 Henry 不要以某种方式编写代码。不要,我喜欢我的代码以这种方式编写,这种方式,这种方式。那就是,你知道的,我们可以把它放进一个规则文件中。现在,不同的 IDE 有不同的方法来做。Claude Code 有一个 claw.md 文件,你知道的,Cursor 有一个 agent.md 文件等等。问题是,过去发生的是,规则文件变得越来越大。所以,你进行的每一次新对话,在开始之前,就已经有了很大的上下文,因为每一次它都会加载这个巨大的规则文件。想想看。每次我们与人工智能交谈时,我们不一定需要它拥有我们告诉它的一切。例如,我的 AI 可以是营销、编码、视频编辑等方面的专家。当我谈论编码时,我不需要它是视频编辑专家。这太傻了。所以,他们想出了一些东西。他们想出了技能。技能很棒。基本上,技能就像被包装起来的规则,对吧?所以,简单来说,我将用简单的术语来解释。把它想象成被包装起来的规则,但它们只会在需要时被调用。是的,它们只会在需要时被调用。为什么这很重要?因为技能,因为它们是被包装起来的规则,只会在需要时被调用,它们不会让你的上下文窗口膨胀。所以,现在你解决了问题。现在,你的代理的上下文窗口中可以有几件事情,但它只会去调用那个技能,当它需要的时候。好的?这是第一件事。所以,技能在这个领域绝对是改变游戏规则的。然后,例如,我们开始得到 MCP 之类的东西,这实际上是在那之前,而 MCP 基本上是,例如,当我们编码时,你知道的,我们倾向于使用 API。现在,假设世界上有很多公司。有亚马逊,有 Stripe,有 Convex,有太多公司了,我们使用这些。这些叫做第三方,对吧?我们经常做的事情是,我们用我们的代码与一家公司交谈。我们使用一种叫做 API 的东西,API 基本上是我们和公司之间的层,对吧?我们通过 API 进行通信。人工智能可以做到这一点,但存在理解问题,对吧?它知道它可以发送哪些函数?它是否使用了正确的请求?事物可能会更新等等。所以,为了解决这个问题,Claude 提出了一些东西。我认为是 Anthropic 提出的,它基本上叫做模型上下文协议。基本上,这是一个标准,每个人都以 MCP 服务器的方式构建服务器。而这基本上是,你有一家公司,他们拥有后端的所有工具。所以,这是如何创建一个 Stripe 付款。这是如何检查 Stripe 会员资格。这是如何取消用户。然后他们将其包装在 MCP 服务器中。然后他们将其暴露给网络,对吧?现在,你的代理可以做到,你的代理可以说道,“嘿,我看到了那里的 Stripe MCP 服务器。我将连接到它。”突然间,我得到了 Stripe 的所有工具。而且这些也可以是经过身份验证的工具,对吧?所以,它现在可以为我的业务创建用户。它可以代表我的业务向用户收费等等。所以,这太棒了。好的?所以,使用 MTP 服务器是一件非常非常强大的事情。所以,现在我们有了这些技能,这些 MCP 服务器,这就是让我们的代理在他们所做的事情上变得非常聪明的基础。好的?所以,让我们称之为第三方工具。好的?让我们称之为第三方工具。这是获取第三方工具的一种方式。好的?现在,很多地方现在都在做的是,他们将技能、MCPs 以及有效地规则包装成叫做插件的东西。所以,你可能最近在你的 IDE 上看到过插件。所以,现在你可以做的是,你只需安装一个插件,你就会自动获得一堆技能和一堆 MCP 服务器的东西,并自动拉入你的 IDE。所以,这就是人工智能领域的发展方向,而且它发展得很快,伙计们。它发展得非常快。这就是为什么我想创建这样一个平台,在那里你可以收听每一集,然后弄清楚,好吧,我现在在人工智能领域的哪个位置?而且,就像我之前说的,我们有一个完整的社区,在那里我们教你如何做所有这些代理的东西。你所要做的就是成为其中的一员,就是注册并获取今天的代码,对吧?所以,你免费输入你的名字、电子邮件,提交它,我将免费给你代码,然后你就在那个新社区的等待名单上。它很快就会推出。所以,如果你还没有这样做,现在就去做。然后,让我们开始今天的构建。现在,我首先想告诉你的是,今天的一切都是完全免费的,因为我们有像 Clerk 这样的了不起的赞助商。好的?所以,他们是一家了不起的公司。我们与他们合作,因为我们相信他们。我不会把任何我不相信的东西放在你们面前。所以,我只要求的是,通过这个教程,请,请,请去使用描述中的那个链接,它将带你到这个页面。这只是让 Clerk 了解你来自 Papa Fam。这使我能够免费制作这些视频。好的?所以,我们现在就来做。我点击了描述中的链接,然后我点击了注册方法。所以,我现在要创建我的 Clerk 账户。这将为我们的身份验证、计费等所有这些东西提供动力。好的?所以,我已经有一个账户了。所以,我将使用我的个人账户。让我们登录。而且,请告诉我,你们喜欢视觉解释吗?就像,你们喜欢我教人工智能吗?我真的,真的告诉你,这将是我希望你们深度参与的事情。好的?所以,接下来,我们将创建一个应用程序。所以,我们将这个命名为 Jobly 网站。我们就叫它 Jobly Job Site。好的?然后,我们将,你知道的,你可以启用任何你想要的身份验证方法。这就是我喜欢 Clerk 的地方。做起来非常简单。让我们创建一个应用程序。好的?现在,下一步是我们需要设置我们的应用。好的?现在,有很多方法可以做到这一点。我们可以使用 create next app,这是一个模板化的 CLI 命令。我们可以使用 Convex 的 CLI 命令。有很多不同的方法。我们甚至可以告诉人工智能从头开始做。如果我们要使用 Convex 和 Clerk,我最喜欢的方式是以下方式。好的?所以,我喜欢去 Convex。Comx 是一个很棒的数据库网站。所以,在这种情况下,它基本上,嗯,它不仅仅是一个数据库。他们做很多事情,但我会告诉你。所以,去数据,Comx,我也在描述中包含了一个链接。它帮助我获得更多的资源,这样我就可以继续为你们制作这些东西。去,嗯,我们实际上想去 Convex 的主页。所以,去 Convex,只需输入 convex reach convex.dev。现在,这是我们要去文档,入门,然后我们要点击 Next.js。而且,看看这个,看看使用 Convex Chef 启动应用程序的提示。所以,你甚至可以查看这些东西。所以,再次,通常像这些内置的。所以,我们点击 Next.js。现在,让我们来做以下事情。如果你已经创建了一个应用,但在这种情况下,我们只是使用它。好的?MPM create convex at latest。好的?现在,简单的方法是,让我们回到我们的代码。我将使用 Warp 终端。我真的很喜欢 Warp 终端。它对我们来说非常棒。嗯,让我们在我的文档中做。所以,让我们做文档,构建,然后我将做 mpm create convex at latest。好的?现在,再次,你可以使用 pmppm dlx 之类的东西。我今天只是简单地使用 npm create comx at latest。对。所以,它将要求我输入一个名字。我们就叫它 Jobly Job YouTube App。好的?可爱的名字。对。让我们做 Next App Router。然后看看这里。选择用户身份验证。我们正在使用 Clerk。所以,它已经为我们设置了整个基础。对。所以,Clerk。就这样,设置起来非常简单。另外,请告诉我,音乐是不是有点刺耳,还是你想让我放点更舒缓的音乐?我们来放点低保真音乐。让我们放点低保真音乐。低保真音乐,低保真节拍精选,内向电台。我喜欢这个。好的,好了。现在我们可以一起 Vibe 了。一起进入。开始一起编码。对。Nico 说,“Sunny,最后一个问题。我过去一年一直在使用 Cursor,在构建了一个 hook 组件后,我让它重构为 SRP 模块架构,原子设计,以及现代 React 实践。这是个好方法吗?”嗯,不是个坏方法。嗯,我将向你展示一种更好的方法。好的?所以,请继续关注。我将向你展示如何做到这一点。对。让我们进入应用。你看它已经创建好了。所以,我们现在要做的是,我已经安装了 Cursor。所以,我将输入 cursor dot。好的?现在,对于任何不了解 Cursor 的人来说,它就是一个编码 IDE。好的?再次,我不是 Cursor 的赞助商。它只是一个很棒的平台。它没有显示出来,但总之,它基本上就是一个,它是一个人工智能辅助的集成开发环境。基本上,它最初是一个 VS Code 的包装器,然后它变得非常非常大。好的?所以,在这种情况下,关闭我的 Warp。打开这个。我将稍微准备一下我的环境,这样我们就可以很好地编码。好的?所以,有几件事你需要知道。Command I 打开代理选项卡。Command B 打开侧边选项卡。Command J 打开终端。好的?所以,一些快捷键。现在,通常如果我查看代码,例如,假设我就在这里,对吧?我在这里编码。这个视图是一个视图,对吧?这就是我称之为我的活动编辑器视图。好的?但我想让你们熟悉的是,Cursor 有两个视图。好的?我通常在这两者之间切换。所以,我将按 Command E,然后进入代理视图。你看它如何翻转,对吧?所以,现在如果我做 Command B,你看它现在在另一边了。然后如果你去这里,你可以有多个代理会话。好的?所以,这真的很酷,因为现在如果我想,如果我在我的代理流程中,并且我正在谈论,让它编码,我可以这样做。如果我现在做 Command E,我觉得我回到了我的手动检查东西的方法。所以,你实际上可以有两个不同的视图。如果你忘了命令是什么,你只需去这里,看,切换到代理布局,然后你可以回到常规布局,或者,你知道的,Command D。对。所以,一些快捷键可以让你快速上手。现在,我们要做下一步是安装我之前提到的那些东西。好的?所以,我们将输入 Clerk with AI。好的?使用 Clerk with AI,对吧?嗯,让我们在这里做。所以,他们有。
一系列的技能。可安装的包,为 AI 编码代理提供关于 Clerk 的专业知识。安装后,代理可以帮助添加身份验证、管理组织、同步用户等。现在,您可以自己完成这些。您甚至可以像这样在每个 IDE 中打开它。好的。但在此案例中,我们将一起手动完成。可以吗?所以,我们将回到这里。我们将执行 Command J,然后粘贴这个。对。我只想检查一下。不知何故,我的还没有执行 get init。所以我现在就去做。嗯,您不必担心。您的通常应该会这样做。所以我将执行 Command I Command B。然后我将粘贴这个 MPX skills add clerk skills。对。另外,各位,我们现在有超过 200 人在观看,遍布各个平台。我感谢大家。我只想说声谢谢。如果您喜欢这些内容,并且喜欢我们正在转向的 AI 领域,请帮我一个忙,狠狠地按下那个点赞按钮。Jay,请随时更新点赞数。呃,这有助于这个频道的大量增长。对,我们将点击“确定”继续。正如您所见,现在这就是我们被问到的。请选择要安装的技能。所以,我将向下滚动。空格键,空格键,空格键。我将安装所有这些,对吗?您可以看到,看,这是今天有趣的一个。Clerk orgs Clerk organizations for B2B SAS 创建多租户应用程序。对?所以,我们现在就按 Enter 键。您可以看到我的编码环境中有很多东西。但向下滚动,我想去光标。所以我们有 claw code client command,光标在哪里?我想我已经安装了它,然后是 universal uh 始终包含。啊,好的。所以这些总是包含在内的。是的。所以,在这种情况下,我们只需按 Enter。我们想做,如果您想跨平台使用,您可以选择全局。所以我建议您选择全局。呃,今天我将选择项目,只是为了向您展示它们在我们的项目中创建了什么。所以我将点击项目,然后我将执行 sim link。这就是您复制它的地方,而且在空间中效率不高。所以 sim link 意味着您只需复制,将其放在一个位置,然后就像复制它的链接到其他地方一样。对。所以 sim link,然后我们继续安装,您可以看到它们实际上也执行提示注入扫描。所以,在这种情况下,它是一个非常安全的安装完成。现在它完成了。如果我们回到这里,我们现在可以看到在光标文件夹中,您可以看到我们有这个光标规则文件,但在代理中也是如此,这是关键。所以技能和呃,所以他们已经添加了一个 convex 规则文件。所以在这个入门模板中,这是一个关于如何使用 convex 的规则文件。正如您在规则文件中看到的,它们通常是 MDC 文件。它说适用于特定文件。所以这将适用于所有包含这些内容的文件。现在您也可以智能地应用,我可以只在使用 convex 内容时应用。但它也非常聪明。知道由于描述,AI 知道,好吧,我可能应该在我们使用 convex 时应用它,您知道,构建一个 convex 项目或数据库模式内容或查询或突变或什么。好的。现在,如果我们查看 clerk 技能,让我们现在查看 clerk,我们可以看到 clerk MD。所以,看,clerk 身份验证路由器,所有这些内容。正是如此。基本上,它正在教我们的代理确切地知道这些是什么。所以,在这种情况下,看,clerk uh 设置。如果我们转到 skill.md,这个文件会教您的代理如何完美地进行设置,以及如何操作,做什么,不做什么,示例,说明等等。所以,这是很多人忽略的地方,这就是为什么您会得到一个 AI 插槽。所以,您看,我们花了 2 秒钟就完成了,对吗?所以,我们将关闭这些。我们已经有很多很棒的光标。呃,我们有 convex 技能,我们有,嗯,代理技能。下一步是安装一个 Clerk MCP 服务器,对吗?所以,让我们点击连接到 Clerk 的 MCP 服务器。向下滚动,根据您所在的平台,他们有不同的说明,但它们基本上都相同。我们只需在此处点击添加到光标。光标是最简单的。打开光标。就这样了,各位,我可以看到,看,clerk。我们有 mtp.clark.com/mptp,对吧?我们点击安装。现在您可以看到我有一个 clerk。现在我有很多 MTP。所以我将禁用几个我们不需要的。是的,我经常使用 OpenClaw。正如您所见,还记得我告诉过您的那些工具吗?所以,在这种情况下,我们可以点击这个。看,我们得到了一些对我们有用的代码片段。我们还得到了一堆工具调用,对吧?所以看,用户按钮,组件,这些都是它可以使用的不同工具调用。在这种情况下,嗯,即使在这里,我们也有大约 12 个不同的工具调用。这太棒了,因为现在当我们与我们的代理交谈时,它实际上可以进入我们的 convex 数据库并找出用户在哪里,convex 数据库中发生了什么,如果您从未用过这些东西,那将是改变游戏规则的。好的。现在,如果我们在这里查看插件,这就是我之前所说的。看,用技能、规则、代理、钩子和 MCP 扩展光标。顺便说一句,我没有提到钩子,但钩子基本上是给您一个单行指令。它们基本上允许您在特定点运行自定义脚本。所以,钩子将在代理执行之前或之后运行。您可以修改行为。例如,假设一个代理完成了一些工作,每次完成工作后,我都希望它格式化文件。我们可以在其末尾添加一个 lint 或 format 钩子。所以它会继续确保它这样做。所以像这样的几件事非常有用。好的。所以,让我们回到插件。现在您可以安装任何您想要的。对。所以,在这种情况下,我推荐大家做的几个。如果我们在这里底部查看市场。您可以看到我已经安装了 Slack、Figma、Linear、Bell、Stripe、Notion,等等,对吧?啊,他们做到了。是的,我昨天刚告诉 Clerk,您需要添加一个。各位,看,它就在那里。所以,您甚至不必做我之前做的步骤,顺便说一句。您可以来这里,点击添加到光标,他们做到了。太棒了。所以我昨天刚发了消息,他们就做到了。不错。所以我自己添加。我实际上将全局添加。不错。所以,现在我们有了我之前展示的所有技能以及 MCP。太棒了。对。然后如果我们回到我们的 um 光标设置。然后我想回到市场向您展示更多。所以,我们有了那个。我还希望您获得 convex 的那个。所以,我们已经有了这个,convex,对吧?您可以看到子代理。它还为我们提供了一些子代理规则,这真的很酷,对吧?所以,这基本上就像一个审阅者,一个顾问,如果我们做得正确的话。看,这里面有很多东西,各位,有一个钩子,一个 MTP,19 条规则,两个子代理,七个技能。好的,所以这真的在为我们的代理充能,对吧?所以,我们有了那个。我们安装了 clerk 的那个。太棒了。所以,我们基本上准备好了。我们有了我们需要的两个。我推荐您尝试的其他一些是下面的代理编排和所有插件。所以持续学习非常酷。您可以自己查看。基本上,它只是通过观察您所做的来帮助它学习您的偏好,并对其进行迭代。团队工具包是一个很酷的东西。您可以自己查看,还有一些,还有一些像并行,对吧?所以并行很棒,因为它进行网络搜索内容提取。它基本上允许事物并行执行,比如不同的 um AI 代理。好的。现在,在我们深入编码之前,我想提一下,是的,我使用的是 Cursor Ultra 计划。现在,我每月为 Cursor Ultra 计划支付 200 美元,对吧?顺便说一句,您不必这样做。好的。所以我将公开展示我如何做。所以,在这种情况下,光标设置。我只是想双重检查一下我的卡是否在这里。所以,如果我在这里,您看不到。是的,没关系。只是需要检查一下。好的。所以,您可以看到我处于 Ultra 计划。您不必每月支付 200 美元,各位。请记住,您不必每月支付 200 美元。您可以支付最适合您的任何计划。好的?您还可以提供自己的 API 密钥。但我建议您在花费 API 密钥之前。不要这样做。要么加入 Claude codes 的 max 计划,要么如果您使用的是 Cursor,就加入 Cursor 的计划,因为通常情况下,与直接 API 密钥相比,您使用计划可以获得更好的使用限制。直接 API 密钥比计划贵得多。好的。这就是他们制定计划的原因。好的。现在,我还想让您注意一下 Ultra 200 美元计划。顺便说一句,它的价格非常便宜,物有所值。对。您可以看到自动和作曲家,我几乎不使用它,而且我大部分时间都使用我的 Opus 4.6,这就是为什么我在这里用完了我的配额。好的。然后按需是如果它超出范围,我可以设置一个限制说,“是的,我愿意在之后花费 XYZ 金额。”好的?但我想让您这样思考,这更多的是一种情况,是的,我们正在使用 AI。AI 不是免费的。当然,您也可以使用 Gemini 密钥,如果您愿意的话。如果您在这里,您也可以输入自己的密钥。所以,我认为是 um 计划和使用。有一种方法可以做到。您可以随意自己查看,但有一种方法可以做到,可以输入您自己的密钥。这里的 API 密钥。所以,您可以去并实际提供您自己的 API 密钥,例如 Google 的 Gemini 密钥、Azure、Bedrock,您知道,所有这些好东西。好的?它会去使用它。啊,这就是为什么它不使用我的。哦,该死。好的。哦,不,它没有。不。是的,没关系。好的。所以,让我们开始进行我们的 vibe 编码。对。所以,在这种情况下,现在,我想做的是,我将在屏幕上向您展示演示。我们将来回切换。所以,例如,这是我们要构建的应用程序。我把应用程序关掉了。这是一个很好的开始。让我们重新启动应用程序。所以我将在我的另一台机器上重新启动它。但在我这样做之前,我想有 P uh PMP dev。也一样,好的。现在我们使用的是 package lock。这意味着我们使用 MPM 进行依赖管理。我想使用 pmppm。所以我将执行 pmppmi,然后它将实际安装一个 uh pmppm lock。它只是对安装的模块大小更好一点,这就是为什么您会遇到错误。它们很快就会消失。然后我们可以执行 pmppm dev。好的。现在,此时,如果其中任何内容让您感到困惑,就像我说的,请注册代码库。我很快就会给您一个社区邀请,然后我们就可以开始进行。现在,当我们执行 PMP deb 时,它会启动两件事。如果我们查看 package,uh Jason,嘿,您看到了我可爱的女朋友。好了,Tatiana。她说,“来自迪拜的问候。”所以,在这种情况下,我们有 dev dev front end,dev back end。所以,如果我执行 pmpp dev,您可以看到它并行运行两件事。dev front end 和 dev back end,对吧?所以,这正在做的是,它启动了 convex 的后端以及 next 的前端。但现在,Convex,当您第一次加载它时,它会要求您登录,我已经登录了。然后我们可以创建一个新项目。所以我将在这里为我的团队创建一个新项目。我将称之为 Jobly job YouTube app。我们将进行云部署。我可以选择一个区域。我将选择美国。现在,好的,我有一个。我实际上用完了最后一个项目。所以,在这种情况下,它去添加了两个环境变量。然后它还启动了 convex 仪表板。好的。所以,现在您可以看到应用程序也启动了。所以,在一个终端中,我运行着 convex,并且我的应用程序也在运行。好的。正如您所见,它说配置您的应用程序,临时 API 密钥已启用,因此您可以立即开始,因为请记住,我们创建了 Clerk 帐户,但我们没有添加密钥。好的。所以,现在我想让您做的是,进入您的环境变量文件。您需要知道的一件事是什么是公共的,什么是允许的。对。所以,在这种情况下,我将使其更简单。这些都称为 convex 密钥。好的。所以,这些都是我们的 convex 密钥。让我隐藏这些,以便您轻松查看。我们在这里有 convex 密钥。我们还需要我们的 clerk 密钥。密钥是我们如何与我们之前谈过的 API 进行通信的方式。好的。所以,现在在 Clerk 中,让我们回到 Clerk。请记住,我们注册并设置了我们的第一个帐户,这很棒。我希望您做的第一步是,看,他们甚至还有快速入门指南,但我们已经使用了 Convex 的快速入门设置。向下滚动,获取您的密钥。现在,我的密钥是私有的,对吧?我将与您分享,因为显然我将隐藏我将擦除这些密钥。您永远不应该分享您的密钥,对吧?第一条规则。好的。所以,在这种情况下,我们有 clerk secret key,对吧?它确实写着 test secret key SK 和 PK 通常表示私钥。好的。另外,您会注意到它没有写 next public。Next public 意味着它将在应用程序和客户端内容中加载。当它没有 next public 时,意味着它只在服务器内容中呈现。如果这没有意义,请不要担心。稍后它会变得有意义。好的。所以,现在我们想做的是,我们已经设置好了我们的应用程序。让我们运行它,以便我们可以看到侧面的应用程序。好的。现在您可以使用 Convex 内置的浏览器,但我喜欢在旁边运行一些东西。对我来说更方便。然后我将创建一个新的东西,locos 3000。让我们进入应用程序。好的。所以,现在您可以看到,看,我已经可以登录演示了。所以,请记住,ComX 入门工具包给了我们一个演示点。所以,让我们测试一下。让我们点击登录。我可以继续使用 Google。让我们登录我的一个帐户。就这样了,我们可以看到,是的,继续。如果我们在这里,如果我转到用户,我们应该会看到一个用户现在被创建了。所以,稍后,我们应该会看到。哦,填一下。填入缺失的详细信息。用户名,我们称之为 Sunny Sanger。继续。现在我们刷新,应该会看到一个用户。所以,D。让我们等一下。我们看到用户 Sunonny Sanger。用户名 Sunny Sanger。就这样了。我们甚至可以看到我处于活动状态。Click 有这个非常好的用户活动功能。砰,就这样了。对。所以,现在我的用户在那里了。我有一个用户配置文件按钮。所以,这太棒了。身份验证已经设置好了,并且设置账单也将非常简单。对。所以,如果您来晚了,请不要担心。我说我看到有人写道,什么时候开始的?没关系。这将在之后可用,并且我们将尽快对其进行时间戳。实际上,在一天之内也会进行时间戳。好的。所以,现在是时候快速喝水休息一下了。我看到你了,Jay。所以,现在我们将要做的是,请告诉我。顺便说一句,我认为每个人都已连接,因为我们有 200 多人正在观看,遍布各个平台,这太疯狂了。也请狠狠地按下那个点赞按钮。对。所以,呃,Jordan 说 Clerk 和 Comx 很棒。我在我构建的 SAS 中经常使用它们,伙计。100%。它们是王者。我现在告诉您,那就是 SAS 构建的秘籍。所以,让我们开始 vibe 编码,对吧?所以,当您开始 vibe 编码时,有几件事。好的,有几件事我想让您注意。请记住,这是我们进入的第一个默认视图。Command E。让我们进入我们的代理视图。所以,Command E 将我们带到另一个视图。现在,在这里,我们可以开始描述我们想要什么。好的。我现在做了一些事情。所以在我的另一个应用程序中,我创建了一个名为 live.md 的文件。它的作用基本上就像一个用户故事设置。好的。所以,如果您曾经做过任何形式的软件开发,对吧?您会知道,通常您会有一个称为,让我隐藏一些东西。抱歉,各位,现在很难看清楚。是的。所以,您会知道,通常您会有一个称为用户故事的东西。现在,用户故事是,作为一个用户,我应该能够登录。作为一个用户,我应该能够,您知道,申请一份工作。作为一个用户,我应该能够拥有,您知道,我自己的个人资料等等,对吧?所以,这通常就是我们所说的用户故事。所以,在这种情况下,我创建了一个示例,就像,您知道,如果我们有几个用户故事。所以,故事一,登陆页面,对吧?所以,搭建项目等等。第二阶段,身份验证,对吧?第三阶段,数据库和后端等等。就像所有这些内容,Webhook 同步。我们实际上将同步 Clerk 和 Convex 的 Webhook。所以,这与我们之前所做的有所不同。然后我们有组织和账单,以及我们如何设置不同的角色等等。我也会将此推送到实际的 um git。好的。所以,这里也有很多东西,以及一些共享组件之类的东西。但再次,这只是一个指南,对吧?假设我们现在还没有这个,但我只是想向您展示,通常情况下,您可能会这样工作。好的。所以,在这种情况下,现在,我将关闭它,让我们开始构建。所以,我们的应用程序现在看起来是这样的。我们需要它看起来更像另一个。我将要做的是,我将在这里启动它。我将在另一台应用程序的一侧进行演示。这样我们就可以同时访问两者,并且我们可以来回查看演示与实时应用程序。好的。所以,这应该很快就会在 301 上加载。好的。另外,我还想向您展示,我稍后会向您展示 comx。没关系。所以 30 和 1。好的。所以,这里我们。哦,不。好的,那是我的 um 社区。顺便说一句,欢迎您加入。前往 universityofcode.com。哦。哦,不。我遇到了这个奇怪的烦人情况,如果我这样做。是的,就是这样。所以,这里是最终的应用程序。好的。所以,我们需要从这个模板变成那样。好的。所以,再次,它不会完全相同。请记住,如果您想复制,我为您提供了最终构建的代码。再次,我们与 Jobly 或 Indeed 或任何类似的公司没有任何关系。这纯粹是教育性的。我只是想不到一个名字。所以,在这种情况下,呃,这个,您可以访问代码,但我们的代码看起来会不同,因为我们将对其进行 vibe 编码,对吧?所以,第一件事,Command I。现在,我们需要制定我们的第一个计划。对。现在,我想让您做的是,我将与您一起 vibe。字面意思,如果我不断解释每一个部分,基本上我想做的是,您告诉我我是否进展太快。好的。所以,我将要做的是,我将提交所有这些更改。首先,我将执行一个默认的提交消息。这也不是最佳实践,对吧?顺便说一句,FYI,我只是在进行演示。我想摆脱所有这些东西。所以,呃,提交意味着我们现在有一个干净的分支,对吧?所以我将其推送到我们的分支进行 git 控制。我今天不会过多地涵盖 git 控制。但我喜欢这样是因为现在当我们 vibe 编码时,我可以确切地看到每一步的变化。所以,第一步,我想做的是,让我们构建一些类似登陆页面的东西。好的。所以我现在要用我的 AI 制定一个巨大的计划。好的。所以,我们在代理模式下。所以,我将要做的是,我将从这个代理模式切换到计划模式。我也可以通过按 Shift 和 Tab 来做到这一点。对。嘿,Tatiana 已经开始赠送给大家了。好了,我们有圣诞老人来了。好的。感谢 Tatiana。您现在是 pub fam 的一部分,对吧?或者说是那个更高级别的,我猜,对吧?在计划模式下,这要好得多,因为您不会花费那么多令牌,并且您将获得一个更好的计划草稿。您总是想从计划模式开始。另外,我在这里处于 max 模式,Opus 46,这就是为什么我有一个非常聪明的模型。我不在乎为此付费。但如果您担心支出,只需从自动模式开始,各位。它将字面意思地完成。它会更简单。好的。所以,它也会更便宜。但请知道结果会不同,因为 Opus 显然是更聪明的模型。好的。所以,在这种情况下,我可以输入这里,或者我喜欢使用一个叫做 Super Whisper 的东西。好的。我的一个朋友建造了这个。如果您想去获取它,可以使用 Sunny 25,但基本上您安装了这个,然后您就可以说话了,它基本上就像一个转录层,可以放入机器或计算机中。所以,在这种情况下,我将要和它说话。所以,让我们稍微调低音量。我将进入并说我正在构建一个类似 Indeed 的招聘网站,对吧?我需要构建一个登陆页面。我还需要一个 B2C 应用程序,所以任何人都可以申请工作。我还希望雇主能够登录并拥有组织内的不同成员。所以,我们将使用 Clerk 的账单组织功能,他们应该能够创建职位发布。我们使用 Clerk 和 Convex 作为技术栈。呃,帮我计划一下。所以,非常非常简单。我可以这样说。好的。现在,在这种情况下,她将转录它。所以,在您看到的这个中,我正在构建一个类似 Indeed 的招聘网站。我需要构建一个登陆页面。我还需要一个 B2C 应用程序。所以,在这种情况下,或者 um 这是一个 B2C 应用程序。让我们说它是一个 B2C 应用程序。呃,所以任何人都可以申请工作。我希望雇主能够登录,拥有组织内的不同成员。我们将使用 Clerk 的账单组织功能,并且他们应该能够创建职位发布。我们使用 Clerk 和 Convex 作为技术栈,帮我计划一下。现在,我通常在这里做几件事。我将继续说,请确保使用 Clerk 账单,并确保使用 Clerk B2B 组织功能。对于 Clerk 账单。我想确保您遵循官方文档。对。所以我发现这些通常是我发现非常有帮助的事情。是的。现在,我不是说我们安装了 Clerk MTP,但我仍然认为通过做一些简单的事情,我们可以获得更好的结果。我只是去 Clerk 账单,我可以看到,例如,这里的 Clerk 账单,然后我可以看到 B2B 身份验证。所以,我可以选择其中一个,或者我喜欢做的是实际去文档本身。所以,账单管理,Clerk Docs。所以我抓住这个,然后我将粘贴进去。好的。所以,现在我给了它更多的上下文。请记住,我们安装了一堆技能,但如果您想明确告诉它使用某个技能,您就输入斜杠。您可以看到我安装了一堆技能,对吧?所以,如果我输入 clerk,您现在可以看到我有了 clerk next.js 技能等等。对。所以在点击 um um 确定之前,我想向大家介绍 skills.sh。所以,VEL 创建了这个平台。呃,如果您不知道,您应该知道,因为您可以将其与许多不同的东西一起使用,对吧?所以,在这里,我想向您介绍一件事是,一,您应该非常非常小心您安装的东西,因为有些东西可能包含隐藏的注入攻击。所以,如果您现在点击它,他们已经添加了这个安全审计功能在右侧。请务必检查一下。好的。但我想推荐您拥有的几个是 React Vel React 最佳实践。这太棒了。就像,它对于在 X.js 页面上编写新的 React 组件来说真的很好。基本上,它将教您的 um 代理确切地知道该怎么做,正确地做。所以,例如,我们可以复制它,回到终端。是的,我可以创建另一个终端。所以我在这里有我的第二个终端,我可以像这样粘贴进去。对。所以我可以粘贴进去,这将把它安装到机器上。所以,您看到它如何弹出,与我们之前的情况类似。现在它可以说您想安装哪个。它默认安装在光标上。所以,我们将只点击 Enter,然后我们将将其安装到我们的项目中。Sim link 继续安装。是的。对。您可以看到它已经安装了技能。好的。所以,现在我的代理拥有了这个技能。React Versel 的最佳实践。Web 设计指南是另一个好东西。Versel Composition Patterns 也非常棒。这对于例如状态管理非常有用,当您在应用程序中拥有非常高的状态时。如何正确地做,以 React 的方式。所以,这与那个很方便。所以我已经安装了其中很多,顺便说一句。所以,我不需要一直这样做。嗯,但在这种情况下,您可以做这些,还有 Web 设计指南,前端设计,非常非常好的。如果您正在进行任何原生开发,那么对于 expo 来说,这是一个很棒的选择。好的。所以,像这样的几件事。再次,您可以看到这里的安装非常大,对吧?即使是 find skills um 本身,这个技能也有助于您从开放代理技能生态系统中发现和安装技能。所以,在这种情况下,您甚至可以要求它找到与您正在做的事情相关的技能。另外,reotion 最佳实践也很棒。基本上,您可以让代理制作视频,对吧?这真的很酷。好的。所以,此时,让我们进入计划模式。所以,Command J。我们已经有了计划,它正在运行。我们将点击计划。现在,让它做它的事情。我将字面意思地对整个事情进行 vibe 编码。所以,请记住,这是新的。好的。我从来没有在直播中做过这个。我不知道会发生什么,因为我无法真正预测它到底会做什么。所以,这将是一个有趣的构建,并且我知道我正在为你们这样做。呃,所以,是的,我唯一的要求就是您用力按下点赞按钮。嗯,所以,呃,Dion 说,“技能就像一个带有说明的 MD 文件吗?”正是如此。是的,它是一个带有说明的 MD 文件。所以,如果我们将其弹出到这里,您可以看到它已经开始启动了。子代理正在做事情。在解释技能部分之前,我想提一下,如果我们现在点击它,您可以看到顶部,我喜欢 Cursor 的一点是,您可以看到 Composer One。现在,Composer One 是 Cursor 的一个模型。它很棒的原因是它非常快,它非常快,而且它在编码任务方面做得相当不错。我不会说它接近 Opus,但我们不需要达到 Opus 级别。例如,当我们扫描文件树时。所以,例如,当我们执行计划时,第一步需要做的是理解代码库。它需要知道在哪里,我的起点在哪里。所以,看,探索代码库,收集关键文件和结构。它没有使用 Opus。它使用的是 um composer one,这很好,因为我们不希望它在发现部分消耗 Opus 积分。我们希望在实际编码时使用 Opus 积分。好的。所以,在这种情况下,您可以看到所有这些小子调用或您知道的 um 子代理调用,这些都是子代理,它们正在使用一个更便宜的模型,这就是我们想要的,对吧?所以,它可以更快地完成,它可以做得更好,等等。好的。现在,我们之前有一个关于技能的问题。是的。所以,一个技能基本上就是一个 skill.md 文件,它解释了。所以,它说名称描述,而这个描述将使 AI 理解我应该拉进来还是不拉进来。好的。所以,在这种情况下,如果我们向下滚动到这里,看,Versel 的 React 最佳实践,何时应用,在编写新的 React 组件、实现数据获取客户端或服务器端时,请参考这些指南。顺便说一句,你们大多数人都需要这个,因为严酷的现实是,很多学生不理解客户端和服务器之间的区别。我明白。这可能令人困惑。但如果您发现这是一个薄弱点,我强烈建议您安装这个技能,因为它将帮助您避免很多您可能会遇到的问题。对。审查代码中的性能问题,重构现有代码,优化捆绑包大小,等等。所以,所有这些内容现在 um 现在您可以理解我不是在进行 um 您知道的基本教程,向您展示如何做某事,而是试图向您展示如何正确地做到这一点。对。技能文件内容检索。所以,现在它将基本上,您看到第一步是它探索了整个代码库。第二步是它进入了我们的技能,并查看了我们有哪些技能。对。所以,现在如果我们一直滚动到这里,看,并行读取所有四个技能,它探索了,它发现了 clerk 技能,它发现了 clerk organization 技能,它发现了更多,所以它发现了 um 例如,不同的或 um organization rows 等等。默认情况下,所有新成员都会被分配一个行,它理解 um 行级访问以及所有这些好东西,它还读取了 clerk webhooks,非常棒,对吧?现在,现在它开始创建一个叫做计划的东西。现在,这个计划非常非常重要,各位。好的。所以,我们的工作方式是,我们通常从计划模式开始。好的。然后我们继续,我们开始创建计划。现在,我喜欢这里的是,您可以看到它已经开始制作图表和其他一些东西。这个项目是下一个 16 应用程序,Clerk 已部分配置,Convex 已连接,但使用了示例模式或配置。是的,Clerk Provider 被注释掉了。我们需要正确设置。然后它开始设置。所以,您可以看到我们需要用户、组织、工作、申请等等。然后我们需要同步 Clerk Webhooks,对吧?所以,在 Convex 中创建一个 HTTP 端点来接收 Clerk Webhooks 以将用户和组织同步到 Convex。对。当然,这将与我构建的应用程序不同。它只是会,因为显然我我真的可以是不同的计划。我不想复制另一个应用程序,因为那对你们来说就不真实了。我想从头开始向你们展示如何自己做。Yo,发生了什么,Desire?我记得你,伙计。怎么样?他说,“很高兴回来。”怎么样,伙计?我们有一些 OG 回来了。启用 Clerk 账单,启用组织,所有这些东西。还有门控。这是 Clerk 账单使门控如此容易的正确方法,各位。因为在这里,我们可以通过说他们是否拥有其计划中的职位发布功能来在服务器端进行门控,或者通过使用 protect 块在客户端进行门控,对吧?所以,非常非常简单的事情,很棒的 Convex 后端函数,一堆东西。但您可以看到计划是如何完成的,这个计划完成得相当快,对吧?它允许我们以一种受控的方式进行。现在您可以看到我的工作有很多阶段性工作,对吧?所以我总是建议,当您与 AI 合作或与任何客户或任何东西合作时,请务必说将其分解为阶段。您将看到我今天为什么要这样做。好的。所以,我们将进入第一阶段,对吧?所以我将说 um 就像,让我们假设我对这个满意。如果我愿意,我也可以对其进行更改。呃,但让我们说,让我们进入第一阶段。好的。所以,说只执行第一阶段。好的。现在我们点击执行。好的。现在它将要做的是,它现在处于计划模式。但通常情况下,如果您点击构建,它将开始做所有事情。好的。但用户希望我执行计划模式。我再说一遍。所以,它开始处理待办事项。您通常要做的是,此时将其切换到代理模式。所以我刚刚做了 Command Tab,现在我们在代理模式下。所以,现在我可以开始构建了。我已经给了它权限来构建。好的。所以,看。所以,它然后创建了一些待办事项。所以,完成 Clerk Convex 管理,取消注释或配置并设置 Clerk JWT 令牌。这是我希望您做的。好的。所以,当它在工作时,我们可以点击它,我们可以确切地看到它在做什么。但您在这里看到它说,现在将 Clerk JWT 签发域添加到环境。到 environment.local。所以,我们这里有,看,别担心它开始运行了。我将向您展示我们将要做什么。对。它开始编码了。我正在使用 Opus。我想让您也注意一下这里。所以,您还记得上下文窗口吗?看,我们已经有 74,000 个令牌了。您需要开始感受和理解令牌的真正含义。在我看来,唯一的方法就是使用它。就是用它。是的,您可能会偶尔花点钱。别担心,就是用它,相信我,别去派对或喝酒什么的,一周我向您保证,您就能负担得起 AI,就像您做的任何事情一样,削减一些东西,然后将其用于 AI,这将是您一生中最好的投资。非常非常简单就能赢得这一点,对吧?所以,Clerk JWT 签发域,所以,在这种情况下,请记住这里的文档已经有了 um 如何设置它。所以,我想让您做的是,当它运行时,让我们去 Clerk um Convex,抱歉,去 Convex,我们将进入 jobly job YouTube。疯狂的名字。进入设置,我们需要在这里设置环境变量。现在,您可能想知道,好吧,Sunny,它实际上不在 environment local 文件中吗?就像,我们不应该在我们的 environment local 中这样做吗?嗯,您可以将其放在这里作为参考,但它实际上不会从中提取。它实际上将从您的 Convex 中提取,因为 Convex 通常以略微不同的方式工作。就像当我们在那里有环境变量时,那就是 Convex 函数将使用的。所以,在 Clerk,我们需要一个叫做 JWT 会话令牌的东西。所以,我们可以做的是,我们去会话,JWT 模板,我们将添加一个名为 Convex 的新模板。嗯,在这种情况下,您可以去模板,然后只点击 Convex 模板。就是这样。然后我想让您去签发,抓住它,然后点击保存。好的。现在我们将回到我们的 Convex。我们将把值粘贴在那里。然后我们将去,我们需要这个名字。正是如此。Clerk JWT 签发域,然后您点击保存。就是这样。对。现在您可以,就像我说的,您也可以在这里放置它。所以,您也可以在这里放置它。糟糕。嗯。哦,好的。所以,它实际上找到了我的。有趣。所以,它实际上找到了签发域。所以,也许它自己完成了。有趣的是。所以,让我们看看。让我先配置一下。好的。所以,但您仍然必须创建 JWT 令牌,就像我刚才做的一样。好的。嗯,接下来,让我们看看模式。所以,您想继续查看它做了什么。各位,很多人在这里做错了,他们倾向于继续接受,然后忘记了所有事情。好的。所以,我将要做的是,看,我已经做了很长时间了。所以,我知道该看什么。如果它是新的,并且是您的第一次,那么,请,试着填写它。所以,我的意思是,我们有一个模式。所以,如果我点击接受,对吧?所以,我们可以看到,这只是 Command accept。现在我们有一个用户表,一个组织表,工作,然后您可以看到不同的字段等等,申请等等,对吧?我们还有索引,这使得搜索更快。现在,我想让您理解的一件事是,如果您在任何时候感到困惑,我们作为开发者有哪些工具可用?对。如果我感到困惑,这里到底发生了什么,我可以把它拖过来。我可以执行 Command K,然后说,例如,解释一下,我还可以执行 Option Enter 来进行内联提问。然后它会内联解释。您看到了,所以,这就是您如何创建这个自我学习循环,这就是很多开发者现在没有做的事情,然后他们卡住了,然后他们就放弃了。所以,这将创建我们在 Convex 中的表。所以,如果我们去数据,您现在可以看到,看,我们已经有了表,旧的数字表已经消失了,因为我们从模式中删除了它。所以,我们可以删除它。所以,我们应该有四个表,就像这样,我们可以看到 1 2 3 4。对。所以,我们有我们的模式。然后我们有后端。这些都是我们的用户函数。所以,在这种情况下,如果您感到困惑,我将回到常规编辑器。但如果我们按下 Command I,我可以看到这里的计划。实际上,您知道,再次 Command E。让我们回到那个视图。我需要您习惯它。好的。让我们回到这里。抱歉,各位。我们转到 users.ts。所以,在 users.ts 文件中,您可以看到在 Convex 中,它创建了我们的 users.ts。所以,通常情况下,当我们修改,当我们创建 mutation 函数或 query 函数时,query 只是当我们获取信息时。Mutation 是当我们改变信息时,非常简单。好的。然后,我们通常将文件命名为文件夹名,表名。所以,users 将包含我们所有的 get user 函数。您可以看到这只是获取用户,对吧?而 get current user,我们之所以能够做到,是因为我们连接了 Clerk 和 Convex,我们可以使用这个特殊的函数叫做 context.orth.get user identity。但请注意,我甚至不需要知道这一点,因为它通过 Clerk 技能自己完成了。因为,如果您手动设置,如果您查看 layout.tsx 文件,您实际上可以看到,各位,看,有一个 Clerk provider,Convex 正在包装整个应用程序。现在,我不会深入研究 next.js JS 和所有这些。我们在社区中这样做。但我想说的是,您只需要理解 Clerk 和 Convex 正在包装您的应用程序,对吧?这基本上就是正在发生的事情。然后,这就是我们如何有效地告诉谁已登录。所以,身份,然后我们就知道谁已登录。然后我们进入数据库。我们查询数据库,其中 clerk ID 与登录者匹配,然后我们返回该值。所以,在这种情况下,upset user 是诸如 um 如何 um 变异用户值的等等。Internal 意味着它不是公开暴露的。所以,它只能由我们的内部函数使用,还有 delete user。所以,这些是更安全的使用方式。对。我们有组织相关的函数,我们可以创建组织,删除组织等等。然后,这是更重要的部分。Clerk Webhooks for Convex。现在,它的工作方式是,当您看到现在我需要创建 Convex HTTP 端点,直接使用 HTTP action 模式。我们不使用 next.js API 路由。这是一个绝对的宝石。对。如果您不知道 comx um um API,它非常强大。如果您转到函数,您会看到这个。这些是现在实时运行的 API 端点,仅仅因为我们所做的,对吧?所以,顺便说一句,当我在这里的终端中运行时,当它改变事物时,您可以看到它正在创建所有这些不同的事物。它正在创建函数。它正在创建所有这些后台的东西。好的。所以,这个 http.ts TS 文件基本上与您过去使用 express 类似,对吧?所以,http.oute out。您可以看到我们创建了一个路径 clerk webhook,它是一个 post 函数,立即,砰,我们有一个实时 post web 端点。如果您想访问它,您需要进入您的环境变量文件,他们会添加一些东西,叫做 your next convex next public comx site url。所以,现在在这个 URL 上,这个 URL/clerk-web hook 就是实时的,它实际上会命中这个端点,但它将是一个 get 请求,因为我从浏览器中这样做。
但是,这现在确实是一个实时帖子请求。所以你看,现在你不需要 enrock 或任何其他这些东西,以防你过去做过。它就是能用,这简直是不可思议的。对。所以,在这种情况下,我们有呃,这基本上是在检查 clerk 的签名是否真的来自 clerk。所以我们通常需要做一些叫做签名检查的事情,然后这就是这个验证。对。然后,如果它是,我们在这里做的是,当我们登录或当用户更新时,我们在我们的 convex 数据库中同步它。当我们的组织被创建或更新时,情况也是如此,我们在我们的数据库中同步它。当我们删除时,情况也是如此。所以,我们在这一级别上所做的就是确保在 clerk 中发生的任何操作,当用户登录时,当用户更新时,或者当一个组织被创建、更新或删除时,数据库中的一切都已同步。好的。所以,我们需要做的是,我们需要接入一个叫做 webhook 的东西。这意味着每次 clerk 上发生事情时,它都应该触发一个事件,然后我们刚刚在这里创建的 cler convex 函数正在监听那个事件。这样它们就能始终保持同步。对?所以,我们现在需要做的是,我们刚刚创建了那个呃 HTTPS 嗯呃函数。所以,如果你往下看,我会告诉你,它通常会向你解释,对?所以它在别处做了一些更改。Layout proxy.ts 是一个非常重要的文件,顺便说一句。这是 clerx 中间件。所以它说,如果你进入任何 forward/dashboard,我们说我们在保护那个路由。所以你必须登录才能访问它,对?然后,如果我们在这里往下看,或者 config,这是我们连接 clerk 的 JWT 令牌的地方,对,所以你可以在这里看到,然后我们再往下看一点,然后在这里我们可以看到它解释了之后会发生什么,好的,所以第一阶段已完成,等等等等,cl convex au 集成已完成,在这种情况下,我们在这里完成了,我在这里会注意到的一些模式,我不喜欢这样,你不应该这样做,你只是说,好的,是的,它在那里 100%。所以通常在这里,我会突出显示这一点。我会做 command L,然后我会说永远不要做呃,我们姑且说我会把它放回去。是的。所以,我会突出显示这一点。突出显示这一点。做 command L。现在说永远不要做呃,这个操作符。始终检查空值并抛出错误。对?然后我可以按回车键。基本上,你不需要,这基本上说值总是在那里。不,不,不,我们应该总是有检查。通常不要这样做,对?这样做是非常糟糕的做法。你不想那样做。所以这是你应该做的真正方式。你通常会继续,你甚至不需要把它放进呃,你可以在行内完成。不过没关系。但你说,如果没有呃,clerk JW2,那么我们就抛出一个错误。它没有设置,对,因为你应该在那个时候捕获它。好的。现在下一件事是 clerk web hooks。对?所以你看到创建了带有 clerk webbook 端点的 HTTP,但它没有告诉我,哦,是的,它在继续之前告诉你,你需要做以下步骤,convex dashboard 使用这个链接设置 clerk,我们已经完成了,clerk dashboard 创建一个名为 convex 的 JWT 模板,我们已经完成了,clerk dashboard 添加一个指向这里的 web hook 端点,好的,所以我们现在正在做的是订阅所有用户事件和组织事件,然后将签名密钥复制到 da。对。所以,在这种情况下,记住我给你们看的那个 URL,这个,diligent salmon,对?它已经告诉我们了。所以,我在这里可以做的是,我可以复制那个字段 http。就是这个,diligent salmon,对?然后,我将转到我的 clerk dashboard。所以,让我们去 clerk。你看到我没有手动编写很多东西,它自己完成了。对?现在我们可以输入,例如,web hooks。我们在开发者面板中找到了它。现在我要做的是,我将添加一个端点。我将粘贴我的端点,它已经上线了,对?你看到它与 fix play。你可以描述它,如果你愿意,但现在我们想订阅所有用户事件和所有组织事件。好的。所以,现在任何时候发生组织更改或用户更改,你就会看到,让我们订阅所有用户和组织,然后复制签名密钥。我们继续点击创建。再次,你不想向任何人透露的另一个秘密是这个签名密钥。当然,我会告诉你,因为它是一个演示。你复制你的签名密钥。这就是我们如何证明它来自实际的 clerk 账户。否则,别人可能会,你知道,如果他们获得了签名密钥的访问权限,你通常会轮换这个密钥。你会想轮换它。然后你会去这里,然后点击轮换密钥。现在,我们转到我们的 webhook 密钥,然后我们基本上粘贴它。对?现在我们的后端将要做的是,记住那个 HTTPS 函数。所以 HTTP 这个函数在这里面。它所做的是,你在这里看到它在检查,它说,好的,让我们假设一个事件从 clerk 触发。我怎么知道它真的来自 clerk?它可以来自任何地方。有人想黑我。不。别人不知道那个签名密钥是什么。而如果它来自 clerk,他们发送了签名密钥加密。所以这段代码基本上是我们解开它的地方。我们将其与 webhook 密钥进行比较,然后我们使用 svix,它基本上是一个库,用于验证它。如果它无效,那么我们就知道,啊,这两个值不同。发送者不是 clerk。所以这就是你可以测试它的方式。好的。你总是要确保,当你做任何 webhook 工作时,你总是要有一个签名或密钥签名。好的,好的。M rules 说呃,它叫什么?他说,“我可以使用 clerk 或通过 ME API 上传媒体到 Facebook 或 Instagram 吗?”我相信你可以。当你有了登录流程时,你实际上可以接入那些。好的。现在,伙计们,如果你喜欢这个,我只要求你摧毁那个点赞按钮。就像我之前说的,它极大地帮助了频道,对?然后让这个点赞数达到 200、300、400,以此类推。好的,我们已经超过 100 了。我们开始吧。好的,所以现在,我们准备进入第二阶段。好的,我们还做了一些清理工作。呃,所以让我们去我们的呃,它叫什么?我们的计划。现在,我没有做一步,我应该做的,对?当我们在计划这里时,很多人会做,这是一个非常坏的习惯,对?就是他们只是继续,就像我刚才做的那样,对?你实际上想去顶部这个地方,然后点击保存到工作区。现在,你为什么要保存它?因为如果我,你知道,创建了一个新的会话,或者我忘了我的计划是什么,而这以前发生过,它基本上现在已经保存到我们的光标计划中,它们有一个文件,在我给你的代码中,我给了你原始计划文件。好的,所以你可以看到原始计划的样子。好的,现在让我们来测试一下。对。所以,首先你可以看到 joby 寻找你的下一个机会登陆页面即将推出,第一阶段完成,登录,让我们去登录,让我们刷新一下,很可能需要刷新,好了,我已登录,让我们退出,登录,继续使用 Google,再做一次,就这样,我们应该已经登录了我们的用户,好了。而且我相信,如果我们去日志这里呃,它会在这里触发日志吗?也许不会。我想它实际上会在 clerk 端。所以,如果我们去用户这里,它同步用户了吗?还没有。好的。所以,在这种情况下,因为我最初没有创建用户,对?所以,在里面。呃,所以我想做的是,为了向你们演示一些东西,我将暂时删除这个用户。对?所以,你通常不想这样做,但我只是想尝试,我正在尝试向你们演示它是如何工作的。所以,如果我们回到那里,你看到我已注销。我们登录。继续使用 Google。现在,我们登录到我的账户。现在,因为创建了一个用户,它会触发一个 webhook,然后 convex HTTP webhook 后端请求现在在那里等待这个 post 请求的到来。Webhook 将会命中 M 请求,我们应该在我们的数据库中创建一个用户。所以,填写用户字段。我们只用 sunny SA 继续。哎呀,我不小心那样做了。那太傻了。然后你看到我们创建了那个用户。呃,让我们关闭它。现在,我想让你做的是,去 clerk,去开发者 web hooks,然后我想让你去日志。好的?你就可以看到用户创建或会话创建。就是这样。是的。所以,如果你愿意,你也可以在会话创建时这样做,对?但现在你可以看到,看,Sunny 登录了,它会完成所有这些事情。现在,因为这是一个用户创建事件,我们的后端应该已经捕获到了。所以,现在如果我们去这里,我们应该看到,如果我们去日志。是的,你看。clerk webhook。砰。我们有了。而且它是 500 错误。哦,你看到有些事情出错了。所以,我们没有正确设置。所以,在这一点上,有人可能会跑掉,然后说,“哦,我要构建应用程序。”好吧,这是一个问题。你需要解决它。好的。所以,这里到底发生了什么?就像,出了什么问题?所以,我们得到了一个 500 错误。所以,让我们看看问题是什么。所以,500。如果我们进入我们的设置,我们可以进入我们的环境变量。呃,嗯,首先,我会让你们非常简单。我会说呃,你可以做的是,你可以用几种方式来做。如果你去日志,点击这个,你就可以直接截图。你可以继续,例如,截图,就像这样。把它粘贴到这里。然后你可以继续说,粘贴,也许是呃,webhook 失败,出现 500。好的。现在让我们看看它做了什么。我故意展示这个,因为我想让你理解并看到它将如何使用技能来调试。所以,最可能的原因是缺少 Clark webhook 密钥,而 500 几乎可以肯定是因为 Clark webhook 密钥没有在 comx dashboard 中设置。你看。所以那是我的错,对?所以,请记住,我忘记在 convex dashboard 中说了,对?而这里的一个大问题实际上是我们使用它的地方。所以,如果我做 command shift F,然后我粘贴 CL webhook secret,然后我在这里看,你能看到它说,如果没有 webhook secret,缺少 Clark webhook secret,对?但这是在 convex 的一边发生的,对?所以,这实际上会发生在这一点上。所以,通常如果我们看到这个呃,它给我显示日志了吗?也许没有。好的,但我们在这里要做的是,基本上继续,然后去我们的设置环境变量,我们在这里需要添加实际的密钥。所以,你看到我把它放在了错误的地方,你看到 AI 如何帮助我解开了这个 bug。所以,如果我去 environment local,我需要我的 clerk webhook secret 在这里,就像这样。所以,让我们再做一次。让我们继续做。保存。是的。很酷。现在,当我们做数据时,我们需要再次重新进行那个测试。所以,让我们去这里。我将继续,只是去删除这个用户。让我暂时关闭它。删除这个用户。我将再次向你们展示整个测试流程。这就是你们如何测试它,对?所以,如果你不知道你在做什么,到这一点,你会认为它一切正常,然后你会说,啊,这是 AI 的垃圾。你看,你需要知道你在做什么。好的。所以,现在,呃,我们需要再次进行测试。所以,我将重新登录。你看到,它把我登出了,因为我删除了那个用户。所以,我将登录。然后,它将继续询问我呃,它叫什么?让我们看看。而且我相信我们应该在这里看到一个错误。我们应该在那里看到它。哦,我想是在这里。哦,那是 JWT 的那个。是的。但在这个例子中,看,Sunny Sanger。点击继续。现在,稍等片刻,如果我们回到这里,我们可以看到。抱歉,事情弄混了。所以,这里。耶。好的,看,Sunny 现在同步了。砰。我没做,它自己做的。我们去日志。我们可以看到,嘿,看。Sunny 创建了环境变量。然后我们删除用户。哒哒哒。然后我们添加了 post clerk webhook。所以,那是用户登录的时候。我们可以确认它是真的,因为如果我们去 clerk,然后我们去这里,首先我们有用户。我需要刷新。去配置。我们去开发者 web hook。然后现在如果我们看到日志,砰,用户创建。你看,就是这个。好的。所以,你看,这是完美的。以及交付尝试。砰。所以,失败的尝试也一样。实际上不是这样,因为我们刚刚正确地做了。所以,它可能是刷新了,或者只是有点延迟。但在这个例子中,日志实际上已经通过了。所以,它是正确的。好的。呃,你看。还有你看。成功。这就是我想要达到的。所以,你可以看到用户在这里创建了。完美的。好的。所以,这很好。现在,我们可以继续。所以,现在一旦我们完成了,你看,哦,没有人使用 Java 嗯,现在我们可以说,好的,所以,让我们说我想看看计划,我想知道第二阶段是什么,我只需要输入 command P plan,然后你就会看到它带我到计划,现在我可以去,然后我可以看看我在哪里,我在第二阶段,好的,所以第二阶段,clerk 组织和账单,对?所以,让我们假设,例如,让我们继续,或者只是说,你知道,保持非常整洁,说继续第二阶段,对?我变得懒惰,我经常这样做,但我正在向你们展示我所做的现实,对?继续第二阶段启用。在我这样做的时候,我会在旁边做,我将确保你知道,我仍然在 90K。这很好。你看到第二阶段,它要求我切换到计划模式。好的。所以,在这种情况下,让我们继续切换。所以,它实际上是光标中的一个非常新的功能。嗯,它建议我们应该呃,切换到计划模式,因为它可能更好,允许我们去找出我们需要在那部分做的一些事情,这非常好。好的。所以,我们想要为我们的雇主提供哪些计费计划?原始计划建议免费、专业和企业。对?所以,你可以使用这些,或者你可以在这里输入。所以,我要说的是,我们实际上想要有免费的,我们想要有专业的。现在,我们想要有入门级和专业级。对于入门级,我们将有 10 个席位。所以,10 个席位和 10 个职位发布。所以,10 个职位发布。对于专业级,我们将有 25 个席位和无限职位发布给公司。好的,现在这很完美。免费的我们可以说一个职位。是的,你看,现在我们按回车键。然后问题二,第二阶段有手动 clerk dashboard 步骤。我现在应该构建所有代码部分,然后给你一个仪表板步骤的清单吗?然后你可以说,或者你可以只给我一个仪表板,然后我告诉你。所以,为了节省时间,我们将说,是的,构建代码,然后给我仪表板清单。或者我可以说,给我清单,然后,一旦交付,编写应用程序,或者编写第二阶段。我通常只说 P2,对?因为我想在之前向你们展示,这样我就可以向你们展示我们必须做的步骤。好的,所以现在用户想要很多 D,让它做它的事情,它将继续,然后通常会为这个创建一个计划。所以,让第二阶段计划。现在,我不会保存第二阶段计划,通常,这取决于你是否想,但你可以看到,完成这些步骤才能做到。所以,我们将去组织配置组织设置。所以,配置组织。所以,我们需要在我们的应用程序中启用组织。需要成员资格,还是可选成员资格。现在,我们使用可选成员资格,因为来购买的人,你知道,不是购买房产,而是申请工作,他们不是企业成员,对?或者组织。所以,我们将做可选成员资格,我们可以做的是,我们呃,我们可以告诉它,它是计划的一部分。所以,它会是像 BTOC 客户申请工作的人不会是 org 的一部分,对?嗯,所以我们可以复制这个。我们可以说,所以,我将这个设置为可选,我们现在处于计划模式。所以,你知道,我只是确保它现在知道。通常,你知道,我非常擅长理解它是否起作用,但我正在向你展示顶部的步骤,以便你理解,对?所以,可选成员资格,有限的成员资格,我们可以说无限的,但在这个例子中,有限的。我将说成员资格限制是 25,对?而且,这些都是附加组件。所以,通常,如果你要使用组织,那么是的,你的 clerk 计划上会有附加组件,对?但在这种情况下,你可以免费使用开发模式中的所有内容,直到你进入生产模式,它就会改变。如果你愿意,你可以启用组织 slug。你可以有很多不同的东西,对?所以,而且,如果你在任何时候感到困惑,你也可以问 AI,你也可以直接截图,然后说,哦,你能告诉我应该使用哪个命令,哪个设置等等。好的,所以,在这种情况下,用户可以创建无限的组织。默认行集是可以的。允许新成员删除组织,当一个新组织,任何成员都可以删除它,默认情况下,我们不想那样做。好的,保存。现在让我们回到。好的,所以你看,正确的成员资格选项正是适合你的用例。你想知道它是如何知道那是正确的设置的。记住我们之前设置的所有技能和 MCP。你看,它是这样做的,对?所以,嘿,我们这里有 Yanni。Sunny Pop React。你们好吗?怎么样,伙计?快速点赞和问候。漂亮的展示 markdown 技能。我从头开始看的。我错过了。我得赶上。我很感激,伙计。非常感谢。很棒的家庭成员。对?在成员资格下,保持默认或稍后按计划设置。我们将把它设置为呃,25。现在,在创建者行下,确保管理员是默认的。好的。所以,在这种情况下,行和权限是下一步。所以,我们有默认行,它是管理员和成员。但我们将在这里创建一个行集。所以,我现在要告诉它,嗯,所以,让我们去这里。我要说,解释一下这里的行和权限。好的。我要说,我想要三种呃类型,对?管理员拥有所有访问权限。招聘人员,招聘人员拥有几乎或呃,招聘人员可以发布工作,但不能管理账单。嗯,我们可以说,或者邀请用户,对?然后我们还可以说,呃,成员只能查看工作列表和申请以及申请。好的,所以这是我们想要的步骤,对?所以,我们继续说解释。现在,它将直接给我们一个完整的流程,对?所以,Code Whisker 说,如果我们没有高级光标订阅,如何遵循这个。伙计们,请记住,你不需要光标高级,对?有一个免费的 Gemini 密钥,你可以使用。呃,再次,你的提示需要更精确,但就像你知道那样是可能的。呃,LIC web solution,因为这个家伙实际上免费提供了一个全栈游戏,而且只有 14 个人。是的。呃,跨平台是 200。是的,这太疯狂了。太疯狂了。但在你做之前,就像五六个手指的工作。阿门,伙计。100%。对?所以,在这种情况下,看,我们可以看到下面创建自定义权限。点击默认行集进行编辑。转到权限。创建这些权限,对?然后我们创建招聘人员角色。所以,在这种情况下,它们将与我所做的略有不同,但让我们一起完成。好的,默认行已设置为管理员和成员。你需要添加一个招聘人员角色并配置所有三个的权限。步骤一,点击默认行集进行添加。然后转到权限部分,创建这些权限或工作,管理。对?所以,让我们现在就做。所以,我们创建行集。是的,没问题。我们将说招聘人员。所以,在这种情况下,你想做呃,创建一个招聘人员行。好的,招聘人员。然后在这里,你看到了。描述,对?行。添加行。你可以看到这里有哪些行。新行。我们有添加这些行等等。我们做哪个?对?所以,在这种情况下,我们可以做新行。你可以看到创建这些权限。所以,我们现在以不同的方式做。所以,呃,现在我们正在创建行集。所以,这里我可以做,如果你卡住了,你可以直接截图,然后说,解释一下该怎么做。对?然后你就可以直接完成。我推荐你这样做的原因是因为如果你搞砸了这一部分,你就会搞砸一些可能很简单又做得很好的事情。对?你正在添加行屏幕。这是你应该做的。创建招聘人员行。新的,然后看,man,但不能管理账单或成员。所以,关键是 org recruiter,对?所以,关键实际上是 or recruiter。我不认为我们需要 or recruiter 的密钥。行是添加所有三个。回到可用选项卡。你现在应该看到三行。所以,让我们先创建这个。所以,你必须至少添加一行。呃,这个实际上是呃,关键招聘人员。添加所有三个行。回到可用管理员和行。我们看到这个。所以,现在我们看到这些。所以,我将做的是,为了突出显示它,显示这个,然后说,我们需要哪些?好的。所以,哪些?当然,如果它有意义,对?招聘人员不会有管理员权限。你会有成员加上一些行。所以,同时勾选管理员和成员。然后点击新行来创建招聘人员行,然后再提交。好的。所以,在这种情况下,我们一开始就给了它完全的访问权限,对?但我们最终会限制它。组织创建者行实际上是所以创建招聘人员的人是管理员,而新成员的默认行将是成员,默认情况下,他们不会默认加入为管理员。好的。所以,添加行,然后我们点击保存,然后创建下一步。所以,点击创建新的。所以,我们去哪里?所以,系统呃,点击新行组织选项卡。所以,让我们回到这里。所有行。现在,你可以看到管理员和成员。让我们点击添加行。然后我们做招聘人员。招聘人员。我之前在错误的部分。然后在这里,我们要做的是,包括行集。是的。自定义权限或系统权限。在这里,你可以看到这是我们一直在谈论的。所以,如果我们在这里往下看,我一遍又一遍地向你们展示这个的原因是因为你不想搞砸这个,对?解释。所以,在这里,我们要做的是说,已经。所以,我们有所有主要的。对?所以,招聘人员密钥或招聘人员。所以,他们说提供 or recruiter,但我不知道我们是否真的那样做。所以,让我们看看新功能开放,这个。所以,我们需要创建两个新功能,工作。所以,一个是工作。所以,我们可以说工作,你可以给它一个描述,对?所以,你知道,能够申请工作,等等,然后让我们再给一个。所以,工作,让我们说工作读取。这与我在构建中所做的略有不同,但没关系。工作读取能力。然后将权限分配给招聘人员行。创建功能后,你会在自定义权限下看到它们。每个功能都会生成权限,如 org jobs manage 或 jobs read。所以,如果你在这里看到,伙计们,如果我们点击创建权限呃,自定义权限,系统权限,你看到这个,比如管理组织等等。现在我想向你展示,呃,实际的,实际上不,我将这样做,因为我不想作弊,向你展示我是如何弄清楚的,我将向你展示,如果你卡住了,你现在会怎么做。所以,哪些选项?所以,这是在创建功能自定义权限。所以,让我们回到这里。所以,对于招聘人员行,只勾选组织系统账单读取组织系统读取账单,他们只能读取成员。所以,读取成员。好的。让我们点击保存,然后对于自定义权限,让我们回到这里,然后让我们展示这一点。所以,你看到它已经创建了 or recruiter。是的。所以,这就是我之前说的。现在,哪些选项,你只想,最好是有点偏执。你没有任何权限。是的。所以,现在我们创建实际的权限。所以,工作管理。对?所以,这个将是管理,然后现在这将有效地是 org jobs manage。所以,在你的代码中,你可以检查那个权限。这是基于行的访问。同样,工作读取,我们将做一个叫做读取,在这种情况下,是 orgs jobs read read right,而且,说实话,你也可以把它叫做 jobs read 和 right。嗯,然后之后保存,你对管理员行和成员行做同样的事情,只勾选 augs job read。好的,所以,在这种情况下,让我们回到我们的行,现在你可以看到管理员,我们转到自定义权限,我们可以做呃,管理员将拥有所有访问权限,而我们只勾选两者。所以,对于管理员,我们勾选两者,保存。对于成员,我们只去,然后只做 orgs job read,因为显然我们现在不想管理工作。所以,只有读取的能力。所以,现在我们设置了权限。好的。你可以做的是,你可以直接自己检查一下。但现在在行集中,我只想确保这是正确的。所以,如果我们点击行,然后点击添加行,然后我们点击招聘人员。现在,这是正确的,我相信。所以,如果我们进入招聘人员,添加行。现在,我只想再次检查一下,因为我认为我不确定我们是否已经给了他们太多的权限。这是正确的吗?好的。所以,最后一部分,一旦你设置好了,伙计们,说实话,你的基于角色的访问控制就完成了。就像它很容易实现一样,然后 AI 会飞速完成。好的。但我正在向你们展示如何自己调试。好的。而且,也要注意你的上下文。所以,107,我们现在在这里。好的。所以,当我们在这里时,我们可以看看呃,哎呀。应该是的。让我们再检查一下。这是正确的吗?让我们继续。有时它会冻结。呃,我将在一个单独的窗口中打开 Clerk。去我的仪表板,单独的项目。我只是把它放在下面,因为我也想检查一下我自己的。所以,我在这里做的是,我有了那个克隆,然后如果我们去配置,然后我们去我们的组织,或者实际的权限,抱歉。所以,组织行和权限。你看到,我有招聘行,它们是管理员。是的。所以,实际上是管理员、成员和招聘人员。而这在招聘行之下。所以,这三行是你可能成为的。你看到那个拥有一切。所以,嗯,这看起来像一个行集,等等。所以,创建好的,这是所有三个行应该是一个单一的记忆,用于权限,记忆三个权限。好的。所以,是的,在实际的构建中,我认为我给了太多的权限,你说话,研究也表明,学习代码也能提高问题。所以,是的,100% 伙计。所以,在这种情况下,权限在所有三个方面看起来都是正确的。需要注意的一点是,行集被命名为招聘人员,这有点令人困惑,因为它是一个内部行的名称,你可能想把它重命名为 jobly 或 default。因为这是一个将分配给所有组织的行,但这是化妆品,不影响功能。好的。所以,我们实际上想改变这个。所以,让我们回到我们的主一个,这样我们就不会和这两个混淆了。好的。所以,我们实际上想把这个行集改为呃,我们需要添加行。所以,这实际上是应用程序内的总行数。所以,你可以有三种不同的行,管理员、成员或招聘人员。这就是我有点困惑的原因。选择或管理员、组织成员或组织招聘人员。所以,这个应该是 jobly,实际网站名称。好的。所以,joby。好的。然后,我将要做的是,我将说这是我们将要保存的。所以,我将保存它,然后我将告诉它,这样它就能理解这是我设置的。而我这样做的原因是为了让它在计划中有上下文。对?所以,现在如果我们去行集,然后我们回到,你看到 jobly,默认行集不是这个。我们想把它设置为默认行集。所以,现在当他们注册时,他们的默认将是这个。好的。行集 jobly。对?然后我们也可以截图。继续在这里提供。看起来不错。重命名使其更好。然后也去所有行。我将继续分享。我将把它放在这里。这是最终设置。好的。而这之后,你就会开始飞了。就像这是我们真正开始飞的地方。现在继续第三步,账单,对?这就是我们将要做的账单。所以,让我们来做免费入门价格。呃,我们可以选择任何我们想要的价格。所以,如果我们去我们的账单,让我们去我们的订阅计划或设置。首先。而我想让你做的是,我们将启用组织账单。所以,我忘了点击那个该死的组织按钮。只是回到这里一会儿。组织呃,账单。抱歉。我们去启用组织账单。首先,点击保存。而这很酷。你可以为免费试用要求付款方式。一开始,我们将坚持使用 clerk 付款网关。一旦你进入生产环境,你将切换到 Stripe 账户。好的。所以,启用组织。让我们创建我们的第一个计划。现在,我们已经有一个免费计划。所以,免费计划是默认完成的。嗯,所以我想做的是,继续做这个。所以,免费计划、入门级和专业级。好的。所以,入门级将是,让我们称之为呃,每月 49 美元,因为它将面向企业。你可以给他们年折扣。呃,我们可以做一个像免费试用。以及功能,我们稍后会做。对?所以,首先,让我们先做这个。然后,让我们回到,你就可以看到,看,我们有免费和入门级计划。好的。现在,免费的,我想让你做的是,只把免费改为免费密钥。好的。你就可以看到我们实际上有两个功能在这里,工作和工作读取。所以,我们将确保它们是正确的,虽然我们不应该。我认为我们没有那些,但好的。我们稍后会弄清楚。所以,创建计划。我们将说专业和专业计划。而且,你应该做专业。你也可以给它一个描述,所有东西。但在这个例子中,我们可以说每月 99 美元。你可以给这个一个年折扣。也许我们只想要这个。我们可以说,如果你预先支付一年,这将是 90 美元,总共 1080 美元。点击保存。现在,我在这里说,为每个计划启用哪些功能。好的。现在,在这种情况下,功能将是组织默认获得的。好的。所以,我们去这里。你可以在这里看到,这里是创建计划时要分配给每个计划的功能。好的,工作读取,团队席位,无限发布。你看它给我们布局。它直接给我们完美的入门级,对?所以,免费的。让我们去这里,让我们保持一切呃,简单。所以,在这种情况下,添加功能。所以,我们有工作和工作读取。所以,是的,是的,然后否认这两个。好的。所以,否认这两个。所以,那些没问题。免费的很好。让我们去下一个入门级计划。让我们只把它写成大写的 S,让事情看起来更好一点。然后在这里,你也可以说,例如,入门级计划适用于所有人。入门级计划适用于所有人。呃,功能。我们想要这两个功能。我们将应用它们。然后,我们还将创建两个功能。嗯,我们将称之为团队席位,对?所以,团队席位和无限发布。所以,团队席位,这将是呃,邀请成员加入呃,组织的能力,对?嗯,团队成员公开可用。是的。基于 orgs 限制对该功能的访问。是的。所以,限制团队席位。和呃,抱歉,对于这个,你可以做的是,只给它一个好名字。所以,你可以说团队席位,如果你愿意,或者 10 个团队席位。好的。然后我们可以回去,然后去专业。这个将拥有,你知道,我们可以说最好的计划。我只是想让你看到它。呃,添加功能。我们想要工作。这 10 个团队团队席位。而且,实际上,我应该把那个改为呃,团队席位。我想我们不应该说 10。我们应该只说 10 个团队席位。无限发布是那个。无限发布。好的。在这里,我们可以说,漂亮的密钥。所以,无限发布。呃,发布无限工作的能力,公开可用。是的。对?而且,它没有添加所有其他。所以,工作完成。而且,现在这 10 个团队,哦,该死的。嗯,所以,首先点击保存,然后我们添加一个功能,那就是无限发布。你看,来吧。你必须全部添加。抱歉,伙计们。搞砸了。是的,无限发布。我们只是把它们放在一个漂亮的层级结构中。让我们编辑一下,这样它就不会说 10 个团队。它只说团队席位。更新功能。现在我们有了。好的。好的。所以,点击保存。然后我们添加一个功能,那就是无限发布。你看,来吧。你必须全部添加。抱歉,伙计们。搞砸了。是的,无限发布。我们只是把它们放在一个漂亮的层级结构中。让我们编辑一下,这样它就不会说 10 个团队。它只说团队席位。更新功能。现在我们有了。好的。好的。所以,你看,我们需要创建团队席位,我发布了其他计划。是的,工作已经从行设置中存在。实际的发布限制将在 convex create job mutation 中通过计算活动来执行。所以,我们将在前端执行它。现在,值得注意的是,Clerk 正在为此做工作。所以,如果你看看 Clerk 账单,他们确实有那个即将到来。如果你看看页面底部,这就是为什么我喜欢这些人,他们总是有东西。所以,如果你在这里看到,我们将很快有 Percy 账单,付费附加功能,优惠券和折扣。他们已经推出了试用。然后,基于使用量的账单将非常酷。好的。而且,当然,你还有税务支持。所以,呃,在这一点上,我们准备好了。所以,好的。然后我说完成。现在,如果我们继续看这里,创建第四步是创建账单计划。我们已经完成了所有这些。哦,抱歉,你知道吗?在计划本身,它实际上有很好的说明,我可能应该多看一点。嗯,我们还需要那些账单 webhook 事件。所以,呃,我做了,但我没有添加账单 webhook 事件。所以,我需要这样做。添加你现有的 webhook。所以,我们需要去,当你准备好时,去配置 web hooks,编辑你的端点,并订阅订阅和订阅项目事件。所以,让我们去 web hooks,开发者 web hooks,然后这要求我们呃,配置 web,编辑你的端点。编辑你的端点。是的,这个。然后我们将去编辑。抱歉,不是这个。抱歉。呃,实际上是这个。我的在哪里?是的,订阅事件。所以,这里订阅活动和订阅项目。所以,所有订阅项目和所有订阅,你看到这里发生了什么,伙计们?所有订阅的东西,活动、创建、逾期、更新,所有这些东西。我们已经更新了它。你看,启用,我的意思是,他们只是说创建、更新、活动、活动、取消、结束。呃,好的,也许今天我们就坚持这些,为了简单起见。订阅活动创建。我们目前不做逾期,但你可以很容易地做到,对?订阅活动取消结束。所以,放弃,我们做活动取消结束。我们不做这些。好的。所以,你看。然后,一旦所有仪表板都确认了,我就会构建代码。所以,现在它开始为下一步进行编码。所以,我们在这里看到,开始进入定价页面,仪表板账单页面,你可以看到它们正在使用组织定价表。好的。所以,我们很快应该看到的是,你知道,UI 将开始改变,然后在那之后,它将是 convex 中的功能门控。所以,它将开始设置一些功能门控代码逻辑,它将更新我们的 webhook 处理程序,它还将创建带有来自 convex 的组织切换器组件的仪表板布局。所以,让我们开始看看它在做什么,伙计们。而且,你也可以用几种方式来做。如果你点击审查,你也可以看到所有更改。你可以开始进行审查流程,我真的很喜欢这个页面。所以,如果你点击审查,你可以一边编码一边进行。我现在可以来,看看,好的,组织,我对这个很满意。所以,我可以继续保留对那个文件的更改。呃,这里我可以看到它做了一个 diff。所以,它在我的页面上做了一些更改。所以,在这种情况下,让我们把它缩小一点。我可以看到。好的。所以,它已经添加到了主页中,Jobly 用户按钮。这只是一个演示。我对这个很满意。呃,然后我们可以去 jobly 浏览。这是定价页面。所以,在这种情况下,Jobly 浏览工作,雇主仪表板。然后,它只是添加了带有组织账单计划的定价表。非常好。你看到你可以运行,就像在这一点上,你也可以添加聊天,你可以做快速编辑,你可以做很多像来回提示。好的。所以,在这里,我们对这个仪表板工作申请账单设置很满意。嗯,这将是仪表板视图的布局,这正是我们想要的。这是一个好的模式。而且,它这样做是因为它有技能,顺便说一句。所以,它知道要做这些,这些都是好的做法。这些是我在手动完成时会推崇的东西。好的。你能用 clerk MCP 设置或行设置,然后让 cler 设置吗?你知道吗?这是一个好问题。之后,提醒我,我会检查一下。我不知道我们是否能做到。嗯,但如果能做到就太棒了。嗯,因为那会很有用。所以,仪表板卡片也是如此。然后,你就可以看到你可以像那样浏览它。好的。现在,假设我们做到了。我将有点信任,因为我做过几次了。所以,我们可以做工作,等等。现在,我可以看到这些是不同的工作,不同的类型,全职、兼职、状态,活动、关闭、草稿,以及现场、远程等等。然后它更改了 HTTP。这是 webhook 处理程序,对?当然,我扫描代码时最看重的东西,对?我正在寻找的是,它是否使用了任何类型转换。所以,例如,如果我在这里看到任何类型,我会立即指出并说,“不,不,不,我们从不那样做。”好的?但我不再检查每一行。我更多地是在测试功能和来回编码,就像,我确保基础技能集足够强大,能够很好地编码。所以,我通常很信任这个,因为我使用的是 Opus。Opus 是一个很好的模型。它倾向于很好地编码。所以,我不必太担心所有事情。另外,我安装了一些非常棒的技能。好的,我之前向你们展示过。更新仪表板逻辑,一切干净。然后,你看到第二阶段已完成。前端页面,然后是仪表板布局,以及跟踪组织计划和状态的 convex 后端订阅表,从 clerk webhooks 同步。所以,让我们试试。所以,让我们继续刷新,然后点击登录,然后继续使用 Google。哎呀。我讨厌它这样做。所以,我自己做的。那是我自己做的。所以,呃,继续使用 Google,然后让我们做 Sunny。现在,我们可以看到,我们有几个页面,对?所以,for/pricing。所以,如果我们现在去 for/pricing,我们应该看到每个雇主的计划。然后,我可以看到,我们实际上还没有看到定价表。所以,这是一个典型的测试例子。所以,你看,之后它会做。所以,例如,我的定价表。所以,在哪里?如果我现在做 command E,我就可以看到我的编码视图,这对我个人来说更容易导航。而且,我可以
好的,这是您提供的英文文本的中文翻译:
查看,好的,定价,Jobly,计划,对于每个雇主,然后是定价表。嗯,为什么它没有显示?好的。所以,如果我们看一下检查器,我们能在这里看到什么原因吗?不,我们在这里看不到原因。让我们继续在这里看看。哦,这方面一切看起来都不错。所以,在这一点上,我现在可以去这里,然后说命令 L。嗯,我们可以说这在页面上没有显示。好了。现在,我们这里也有一些问题。当涉及到 Clerk 订阅时,您推荐哪个版本?从个人角度和公司角度来看。我使用 CL Claude Max,200 美元的计划,我也有一个 Cursor Ultra,200 美元的计划。嗯,在我看来,绝对是明智之举。令人难以置信的计划。嗯,我也可能会购买一个 GPT 的,因为我也使用 GPT Codeex。我写大量的代码,伙计们。所以,只需根据您的需求来做。但在我看来,Ultra 计划确实物有所值,尤其是 Claude,Claude 是一个非常有价值的计划。嗯,问题是人们会用完 token,因为他们不知道自己在做什么。这就是我之前提到的主要问题。即使是我们之前谈论过的关于上下文窗口的一些事情,对吧?所以,让我们在这里仔细检查一下。如果我们去账单,只想仔细检查一下。所以,我们确实启用了组织账单。是的,B2B。现在我们可以看到,现在尝试刷新页面。所以,公开可用。不在个人用户选项卡上。哦,不,我搞砸了。啊,该死。我搞砸了。我知道我搞砸了。好的,所以,如果我们去定价,订阅计划。不,我没有。好的,我确实有组织计划。这是正确的。是的,它们在这里。所以,让我们看看这里发生了什么。有趣。所以,查看命令和网络。我禁用缓存的原因,刷新。嗯,它实际上正在调用计划。嗯,它们正在到来。只是没有渲染出来。所以,我的意思是,你实际上可以拥有 Clerk 浏览器在这里。所以,嗯,Convex 的嗯,Cursor 浏览器。所以,我们可以说,嗯,让我关闭这个。抱歉。让我们去浏览器应用程序浏览器中检查一下。现在它会做什么,你甚至可以使用 Cursor 浏览器。所以,这将使用一个工具到工具调用。再次,请留意您的上下文窗口。134K。我们目前仍然很好。您看,它自己导航了。好的。非常奇怪。它为那个加载了。所以,你看,它确实加载了。页面价格没有渲染。它实际上为他们渲染了。所以,让我看看。所以,localhost。哎呀。localhost 3000 定价。有趣。也许是因为我运行了一些东西。我没有。这确实非常非常奇怪。我在这里也仔细检查一下。所以,localhost/pricing。啊,不,伙计们,我知道为什么了。我对此非常愚蠢。好了。所以,发生这种情况的原因是,我们是一个没有权限查看该定价表的用户的。所以,发生这种情况的原因是。所以,现在我们可以做什么,我们可以停止这个执行,然后说,我登录的用户可能没有正确的权限来查看组织定价表。帮我解决这个问题。因为请记住,通常只有管理员才能访问此。这意味着,要使组织定价表本身存在,我们必须创建一个组织。这就是现在的问题。这是为组织制定的计划,但还没有组织。我们没有创建一个组织。所以,再次,您看到基本原理会破坏事物。所以,它应该,我的意思是,它应该已经识别出来了,但在这种情况下,这是一个流程问题。好的。所以,用户是对的。定价表就是这个。是的,你看。所以,这实际上是令人难以置信的。它应该在仪表板上。所以,它应该是仪表板。让我们看看仪表板。您可以看到仪表板设置。啊,你看。所以,这是我们真正想看到的。所以,现在我可以停止这个,我甚至可以这样说,嗯,我们不,我们不想要一个/pricing 页面。我们只想要它在仪表板内,因为用户必须有一个活跃的组织,并且有正确的权限来修改账单,因为想想看,您不希望每个人都这样做。这就是多租户问题之一,对吧?您需要有一个活跃的组织。所以,我们必须把它放在仪表板后面,对吧?嗯,所以,这是一个例子,再次,您可以与此来回交谈,然后说,嗯,你知道,最终它会带您到那里。所以,我删除了公共定价页面,因为通常每个人都会是免费会员。嗯,然后,我们需要在仪表板内拥有它。问题是,当组织处于活动状态时,布局需要通过检查来管理组织相关内容。所以,您可以看到这里没有选择组织。你看,伙计们,没有选择组织。所以,现在我们在仪表板上。所以,如果我只去仪表板的主页,你看。所以,现在我想要一个不同的流程。所以,您看到这非常好,它正在做什么。我们可以说,如果为用户首次进入仪表板添加一个入职流程。这将是为首次创建他们的组织。您可以看到我们现在是如何通过这个流程的。所以,现在我们点击这个。让我们关闭它。再次,就像我,嗯,因为我们现在正在进行演示。我通常会跳过一些检查,但通常我会检查所有内容。嗯,当那发生时,我还会建议您做的是,时不时地,当您完成一个阶段时,您会检查,对它满意,然后提交该阶段,对吧?当然,因为我们正在进行演示,这是我们第一次采用这种方法。我有很多东西要通过直播与你们一起学习,但这只是值得注意的。好的,所以,在这一点上,我们有了 layout.tsx。所以,use organizations。现在,它开始检查了。是的。啊,你看,伙计们。欢迎来到 Jobly,为雇主服务。所以,第一次来到这个页面,现在,如果我们是在主页上,对吧?哎呀,不是那个。所以,如果我们在这里,现在,例如,我们最终会有这个登陆页面,我们只需要去 /dashboard,对吧?现在,然后您看到加载,啊,第一次创建组织。所以,在这种情况下,我们可以说,你知道,让我们创建我们的组织,它叫做 Papa,对吧?我们可以添加一个标志。所以我将在这里添加一个标志。我有了我的 Papa 标志。创建组织。这正在创建一个组织并添加一个用户。看看,邀请新成员。我们有三种不同的角色。所以我将邀请 Jay 作为招聘人员。或者,实际上,我将邀请我的另一个账户。所以,team papa react.com。我将邀请另一位成员加入团队。邀请。发送。完成。现在,当我们点击完成时,我们应该看到的是一个重定向流程。所以,当我们现在点击完成时,我们需要完成,就像设置那个一样。但与此同时,您也会注意到我们应该已经重定向了。所以,您可以简单地调试一下入职流程。所以,我们可以说,入职,当用户命中时,它应该刷新仪表板。好的,这是其中一件事。然后,当它修复那个的时候,再次,我们现在可以看到我们在里面,如果您有,这是多租户部分。所以,B2B 组织,对吧?假设,例如,我想拥有几个不同的会员资格,每个组织都有不同的账单计划,这就是为什么在这个组织中,我现在将为这个组织拥有一个账单计划,多租户,对吧?所以,如果我在这里,我创建一个不同的组织,也许称之为 Jobs are us,它不需要图片,例如,让它,让它完成调试,然后我们也可以测试一下。实际上,让它快速完成它的事情。当用户完成组织创建时。新会员资格触发。是的,对。刷新。所以,创建组织,然后跳过邀请流程。啊,你看。很好。所以,现在您可以看到每个不同的租户如何拥有不同的计划。所以我将升级这个到入门计划。所以,如果我们现在点击这个,入门计划。现在您可以看到它弹出来了,然后我们可以去付款。所以,在这种情况下,现在标题不应该有 z-index 的嗯,嗯,D。所以,在这种情况下,标题有一个 z-index,它没有被重构为标题。所以,删除标题 z-index,嗯,因为它会阻止定价叠加层。定价叠加层。现在,有一种方法可以让定价叠加层拥有更高的 z-index,但老实说,这有点棘手,我认为您不应该这样做。我认为这是 Clerk 方面的事情,他们会修复。但现在,这应该有一个像一百万一样的 z-index。所以,它总是在顶部。嗯,但在这种情况下,如果我们只是去掉那个,您可以看到。好了,暂时就这样吧,直到我们需要修复那部分。所以,让我们用开发卡或测试卡支付。您可以看到这个人可以访问 Jobs,再次,您可以更改这些名称,对吧?所以,现在我只是简单地做了 Jobs,Jobs,Read,Team Seats,对吧?Team Seats,无限发布等等,对吧?所以,您可以做所有这些事情,再次,即使是 Team Seats,我也还没有限制邀请流程,但您可以自行决定。好的,但现在,只是为了向您展示多租户在这里是活动的,如果我们进入 Jobs are us,他们将不会是入门计划,他们将是免费计划。您可以看到每个不同的租户如何拥有被邀请的成员,以及嗯,它叫什么,还有嗯,账单。我想解决这个评论。所以,Jade,让它留下。他说,Hafi Ahmed 说,Vibe Coders 不写代码,他们是扮演开发者的人,在损坏的按钮上堆叠 4D 动画,称之为极简主义,然后祈祷按钮,嗯,祈祷那个错误在演示前自行修复。给像这样的人的建议是,把他们踢出去,不要让他们在你身边散布负面情绪。嗯,说到底,要么你就接受它,要么你就擅长这个,要么你就落后了。所以,完全取决于你们想如何处理。但是,嗯,是的,值得一提的是,那种负面情绪在 Papa Fam 中是行不通的。Papa Fam,如果你继续说那样的话,社区会把你吞噬掉,就像你停顿一样。你会被社区吞噬掉。好的。所以,设置,嗯,这里我们有组织。所以,这实际上是一个内置屏幕。所以,这实际上是一个非常酷的屏幕,我想向您展示。如果我们去仪表板设置。所以,如果我转到页面,我可以看到仪表板设置在这里。你们可以看到我想在这里向你们展示。所以,组织配置文件。这是处理整个设置部分的一个组件,对吧?嗯,开玩笑的。我只是在开玩笑。N,你看,当我点名批评某人时很有趣。这总是一个有趣的抓包情况。伙计们,如果你们在频道上表现消极,我会点名批评所有人。嗯,但是,嗯,现实是,您想确保您了解您的基本原理。否则,嗯,人们,你知道,这自然会在那一边引起问题。所以,让我们开始构建事情的流程。好的。所以,下一个功能是阶段三。所以,我通常会在这里做的,再次,您应该做的典型流程是,回顾我所说的所有内容,对吧?一旦您对所有内容都满意了,那么我希望您做的就是继续提交。所以,在这种情况下,让我们假设我们提交了。我们对此感到满意。我不会做每一个步骤,因为我们在直播。我不想让它变得像一百万小时那么长。我们暂存了所有更改。我们可以提交它们。再次,不要只使用这个消息。实际上,使用正确的消息等等。但现在我们有一个干净的分支,然后我们就可以继续阶段三了。如果我们在这里按命令 D,在我们继续之前,我想检查我的上下文窗口。155K 个 token。一旦我们超过 200K,我们就会遇到问题。所以,我们想在这里做的是点击斜杠,我们有一个叫做总结的东西,对吧?现在,如果我们这样做,它会总结聊天上下文。所以,Claude Code 也有这个。但我们要做的现在是,我们将把我们的上下文窗口从 155K 大幅降低。现在关键是我们有一个计划。所以,如果我们这样做也没关系,对吧?如果您没有计划或没有保存您的计划,那么您就会陷入某种糟糕的境地。或者如果您重置了上下文,那么即将开始的新 AI 会话将不知道发生了什么。好了,这就是您如何保持成本不变。所以,在这一点上,现在我们去,这将在片刻后下拉,然后当这发生时,我们可以看看下一个计划步骤。所以,我们输入计划,您可以做到。所以,我们已经完成了阶段二,阶段三关键功能。就是工作本身,你知道,API 本身。列出活动工作,获取工作,列出组织工作,创建工作,更新工作,关闭工作,申请,申请工作,列出工作申请,更新申请状态,所有这些事情。现在,看,聊天上下文已总结。点击这个,您可以看到,如果我们去这里,嗯,它隐藏起来了。所以,这表明它确实做到了。我将向您展示它的价值较低。所以,我们可以说继续进行 P3。好的。所以,现在 P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P3 P P P P P P P P P P P P P P P P P P P P3 将会弹出。嗯,然后我们可以看到它应该会说正在继续进行阶段三。如果它不知道我们在说什么,我们可以简单地回到上面。用户希望继续进行计划的阶段三。是的。您可以看到它再次读取了计划。所以,这主要向您展示了当它总结时,它需要读取计划,引入状态。如果我们现在进入上下文窗口,77.2,对吧?所以,保持在 200K 以下。如果您正在使用,如果您正在使用 Opus,请将其保持在 200K 以下,除非您有一个真正非常复杂的应用程序正在处理。您不需要超过 200K token 并支付双倍的 API 密钥。嗯,这就是为什么人们在使用 Opus 时会耗尽资源,如果您不知道的话。好了,伙计们,我希望您发现这些技巧和窍门很有用。所以,请,就像我之前说的,摧毁点赞按钮,并确保您能够访问代码库。这样,您就知道当我发布新的社区、AI 代理工作流、Openclaw 教程,所有这些好东西时,您将获得所有这些东西的访问权限。您将是第一个知道的人,并且免费获得代码。所以,这是一个双赢。好的,继续进行 P3。所以,除了所有这些之外,基本上都是 API 的东西。所以,如果我们现在向下滚动,您可以看到它已经创建了一个待办事项列表,并开始运行它。好的,所以,我将去这里。所以,首先,都是 API 的东西,您可以看到我喜欢这个流程的原因是因为我们实际上正在做什么,它实际上也在教您正确的软件开发方式,对吧?所以,这实际上是 API,您构建所有 API,根据您的查询、您的突变,嗯,所有后端的东西。这是所有的后端工作,让事情完成的逻辑,连接。您可以看到编码是如何进行的。不要误会我的意思,就像现实是,是的,您可以,您可以批评那些这样做的人,但现实是,即使您,我只是假设,即使您不知道您在做什么,如果您这样做足够多,重复本身就会教您很多东西,您仍然会比那些不这样做的人领先。所以,在我看来,无论哪种方式,您最好开始练习这些东西。嗯,它显然是我的,不言而喻,如果您会编码并且能够正确使用 AI 和 AI 工具,我告诉你们,现在是成为开发者的最强大时期。现在作为开发者,您可以做的事情真是令人难以置信,对吧?我喜欢它。我现在喜欢这个领域。我有代理。我现在有大约 10 个 Openclaw 多代理流程在运行。嗯,我所以,我实际上有一个 AI 团队。如果您想了解所有这些东西,那么就像我说的,只需订阅,点赞,在频道上发表评论,您的男孩真的会全力以赴地发布这些内容。就像,我最近拍了很多东西。现在活着真是太令人兴奋了,嗯,在编码领域。所以,任何担心的人,您需要赶上。您需要确保您正在利用,您正在学习,您正在保持领先地位,所有这些好东西。好的,让我们来看看这个。您可以看到我们正在使用查询。默认情况下,Convex 是实时的,这很棒。再次,就像所有这些东西一样,仪表板卡,让您跳转,您可以看到它正在这样做。嗯,但我确实发现的是,这里的仪表板卡,这些东西。您看到仪表板卡是如何放在仪表板页面中的。再次,可能发生的是,您最终会编写大量代码。我建议您实际做的是,而且我也不知道我是否真的设置了 Shadien。哦,我实际上没有设置 Shadien。哎呀。是的。所以我实际上没有做 Shadien。所以,我将要做的是,我将在之后进行一次重构工作,它会添加 Chaden。我应该做到的。是的,我应该做到的。我才意识到组件是空的。所以,它现在正在内联完成所有事情,这不好。嗯,我们不想这样做。这就是为什么我一直在想,这个应用程序看起来有点无聊。所以,是的。嗯,值得注意的一点。命令 D。回到这里。嗯,我在这里也会这样做的是,看,所有干净的阶段三都完成了。这是后端所有构建内容的摘要。所以,申请工作,列出申请,工作 d 后端,获取组织统计数据,仪表板现在显示实时统计数据。好的,让我们这样做。嗯,您必须了解您的堆栈并有一个计划,否则 VibeCoin 只是风格混乱,称之为开发,100%。非常非常正确。嗯,我喜欢现在能量的变化,Shifi,欢迎来到直播,伙计。好了,在这种情况下,我们回到这里。是的,你看。所以,您可以看到,如果我们刷新,转到概览,你们可以看到自己。看,团队成员第一名。是的。我们去这里,我们有成员,我们有一个待处理的邀请给我的另一个成员在那里。太棒了。好的,现在这显然是手动设计的。目前,我们可以在这里做一个快速的暂停,然后实际上说,嗯,暂停并更新计划,以包括 Shaden 设计组件,组件和设计,强制执行最佳实践,嗯,使用组件和文件夹结构,并使用 Shad CN MCP 服务器。嗯,在我点击那个之前,我将进入计划模式,然后按回车键。当它这样做的时候,我将确保我们在项目中安装了 Chatien 服务器。以防我没有全局安装它。所以,我们要做的是,我们去 Chatien 的文档,向下滚动到 MTP 服务器,您可以看到它在这里,对吧?所以,您可以这样做,或者您可以点击 Cursor,然后您可以简单地执行 init client cursor。但我相信它会为我们做。所以,如果我们可以把它放在一边只是为了向您展示。但如果我做了 pmppm dlx,现在您可以看到它正在初始化 Cursor。现在您可以看到它正在添加它,配置 MTP 服务器,安装依赖项,然后,你看。所以,现在我们安装了 MTP 服务器,并且它为这个项目本地安装了它。您可以通过转到,我们去 cursor mcp.json,您可以看到 Shaden 最新。所以,它在这里本地添加了它。再次,请记住我一直说本地,因为您可以本地安装它们,也可以在全球级别安装它们。所以,这些是全局级别。我一直使用这些。但要知道,您也可以在另一个级别拥有它。好的。我保证 Shadium 很快就会有一个插件。所以,您不必做我刚才做的事情。您只需安装插件,然后就可以使用了。是的。好的。所以,现在它开始做一个计划。再次,为什么计划方法好?因为就像我们之前说的,它使用 Composer。Composer 在降低我们的 token 使用量方面效率更高。好的。如果我们现在去这里,设置,Cursor 设置,转到我们的计划和使用情况,您可以看到现在,嗯,1% 的 API 被使用了,对吧?所以,不多,对吧?它将在 12 天左右重置。嗯,但自动和 Composer 绝对什么都没有。就像您看到它对子代理是多么高效。所以,我们已经构建了所有这些,并且只使用了 1%。您可能会想,嗯,等等,我的使用了 10%。那是因为您在不处理上下文窗口的情况下就大肆使用它,对吧?所以,了解所有这些东西是很好的。所以,在这种情况下,它将继续添加所有这些。所以,现在它也在做一个 Shaden UI 重构。所以,项目有以下内容。第一步,初始化 Shien Tailwind,这将创建等等。安装 Shaden 组件,嗯,等等。现在,我想做的是,您看到我们现在正在进行一些并行工作。所以,我们有这个,你知道,在这里。所以,我现在要做的是,我说,让它完成它的事情,剩余的四个 MTP 使用密钥文件引用等等。所以,我实际上要重构这个。所以,这更像是一个重构和安装。所以,我们将把这个计划保存到工作区。好的,我们有 150,000 个 token。所以我现在要去总结。所以,我将在这里开始总结。我将打开这个侧边栏。我将创建一个新的代理,然后说,我在另一个代理会话中创建了一个计划,您将负责编码。我将在片刻后给您计划。哦,是的。我有时会把它人性化太多。您不需要这样做。是的。片刻后,我将给您计划。计划,您可以说计划在这里。计划是,然后基本上给它计划。对吧?所以,我们将其保存为 Shaden UI 重构。所以,在这种情况下,计划是计划 Shaden UI 重构。现在,我们可以做什么,嗯,这个,伙计们,叫做 Cursor。对吧?所以,我们向下滚动到最后,一旦它总结了。我可以提前准备一下,我说,我已经将这个 Shaden UI 重构移交给了另一个代理会话。请继续进行构建的第四阶段。好的,所以,您看到我们现在正在做什么。我基本上已经把它移交给了另一个。对吧?现在,您可以将其推向更远,然后在一个 Git 工作树上进行整个重构,这是一个完全不同的事情,因为现在重构可能会破坏很多东西。好的。所以,我们甚至可以采用这种方法。好的。但我不知道是否值得做工作树以及我们今天谈论的内容。我有点想让你们达到一个顺利的阶段。所以,它不会对你们来说太,太激烈。嗯,但让它做它的事情。我们可以直接启动这个。所以我只是本地做。所以,现在两个代理都将本地修改。所以,它们可能会发生冲突。但是,如果您曾经做过工作树,工作树基本上就像它在单独的分支上。这就是您想要达到的目标。顺便说一句,我倾向于同时运行几个代理,比如五个、六个代理,然后我在它们之间切换。我之所以不感到压力,是因为它们都在自己的 Git 工作树上,并且有效地拥有本地 Git PR 流程。所以,它们基本上可以,就像,在它们各自的树上工作,只有当它准备好时,它才会合并到一个中,然后我们可以创建一个 PR 到我们的主分支,对吧?或者,你知道,您决定做的任何事情。所以,请继续进行构建的第四阶段。你看。所以,现在我们有两个代理并行运行。对吧?所以,一个正在进行 Shaden UI 重构。第二个正在进行工作网站登陆页面。所以,它现在正在进行第四阶段。所以,用户希望我继续阅读第四阶段。所以,现在它正在继续进行第四阶段。您可以看到它已经读取了计划。我明白发生了什么。我希望您了解这些模式,并行工作流,那种东西,是因为您将真正很好地理解,就像,一旦您开始使用 Openclaw 进行类似代理的操作,等等,您可以拥有真正惊人的自动化、工作流、管道,我们在 Papa 中现在就这样做,而且它非常棒。我现在的团队流程非常高效。这太疯狂了。嗯,基本上,您可以说我通过让 AI 代理在团队内部工作,将我的团队扩大了 10 倍。现在,我有一个由 10 个 AI 代理组成的团队。嗯,它们都有很酷的名字。它们都遵循着硅谷的角色的名字。在 Instagram 上关注我。下面您将看到我的用户名,如果您想去,嗯,关注我。它只是 sssanganger。嗯,我基本上会在这里发布大量信息。所以,您可以随时查看。但第四阶段正在进行中。所以,让我们来看看第四阶段是什么。所以,让我们去我们的计划,是的,工作计划。您可以看到第四阶段是前端页面。所以,登陆页面,工作页面,能够浏览工作,工作详情页面,以及公共视图和申请公共定价页面的能力。H,我们实际上不想要那个。所以,我认为它应该去掉了。嗯,可以创建共享组件或安装。所以,它实际上是好的。不,我本来要说,是的,这个。是的。组织。所以,它最终会重构第一个。所以,如果您要正确地做这件事,真的,您可能会等待第一个完成它的事情。是的,但这里是我应该做工作树的地方。我应该做工作树。没关系。嗯,我们可以,我可以向您展示两种流程以及如何修复它。嗯,因为再次,您会发现自己处于这些情况中。所以,让我们继续。所以,向下滚动到这里。P4。所以,在这种情况下,让我们看看它在做什么。添加公共工作。在这里添加。添加公共登陆页面。嗯,删除空的定价和服务器 div。是的,这很酷。更新代理(如果需要)。验证构建。好了。所以,现在回到这里,我们可以看到这个正在进行 Shaden 方面的重构。这将安装所有 13 个 Chaten 组件。这将在 UI 上产生很大的不同。所以,这可能会导致我们的 um 失败,当那发生时,因为我们安装了很多东西。所以,如果我们现在去这里,嗯,您可以看到这里,这通常会发生。所以,我们可以做的是,我们停止服务器,然后我们可以做一个 m,嗯,pmppm dev,pmppm dev,只是重新启动服务器,这可能会在片刻后触发另一个东西,然后您可以看到两者都在运行。所以,它们都在做它们的事情。让我们回到这里。嗯,相信我,一旦您知道自己在做什么,您就可以成为一个绝对的动物,并以很棒的方式编写代码,男人。老实说,即使您可以让云代理运行。所以,如果我们做命令 shift p,您可以看到,如果我做 cloud create new cloud agent。所以,您实际上可以设置一个任务,比如这些任务之一,我可以将重构到一个云代理上,然后它可以继续在后台构建。然后,当它在后台构建时,我可以,我不知道,也许去吃点东西,回来,查看它在 Git 工作树上做的代码。我对此感到满意。将其合并到一个树中。所以,您看到我们可以获得非常好的流程,现在正在发生什么。这对你们来说应该是一件好事。就像以前,您可能会调试很长时间,然后出现一个错误,那很棒。但现在时代在变。您必须跟上。好的,仪表板重构正在进行中。看,我将并行重构所有仪表板页面,使用子代理。您可以看到这里,看,它正在使用 Opus 子代理。好的。所以,有趣的是。这里正在使用 Opus 子代理,而这个正在使用 Composer 1.5。好的。所以,取决于,而且,顺便说一句,我建议的是,对于更简单的事情,自动模式对您来说已经足够了。我正在直播。我不想让它变得愚蠢并搞砸事情。所以,我宁愿让它在 Opus 中,我也不介意付费。好的,让我们看看现在发生了什么。让我添加账单。让我们刷新一下。做命令 J。这是一个专家到 Turbo Pack 的。好的。所以,我们通常认为它正在运行。让我再次运行它。Mpm dev。好的,所以,我们现在有一个 Turbo Pack 问题,很可能是由于 Shadian 安装引起的。说实话,我们有很多工作要做。所以,我们将让它完成它的事情,然后我们再回来。但即使第四阶段完成了,让我们看看它做了什么。所以,第四阶段,新的登陆页面,工作浏览器,工作详情和申请页面,以及自定义注册和登录页面。删除空的应用程序定价和应用程序服务器目录。是的,已添加注册 URL。路由保护保持不变。仪表板中的任何内容都受到保护。所有公共页面都保持开放。有什么好处?他说,“嘿,伙计们,嘿,伙计。TypeScript 编译干净,没有错误。”好的,这很好。现在我们需要解决这个其他问题。所以,首先,检查您的上下文窗口。128。我们很好。嗯,让我们向下滚动。命令 J。抱歉,不是命令在这里。我们想要并且基本上,嗯,现在也在发生的是,它一直在启动两个。所以,我只想测试前端。所以我可以做 nextdev。所以我可以做 pmppm dev 前端。我可以在单独的终端中运行它们。老实说,我可以做 pmppdem 前端,如果我想要的话。我们可以暂时最小化它,给我们更多空间。我可以分割这个终端,我也可以做同样的事情。我说 pmppm dev 后端,PNPM dev 后端。所以,现在我的应用程序正在运行,我的 Convex 正在运行。所以,有时您只需要单独做,只是为了,你知道,解决那个小小的故障。所以,在这种情况下,你看,现在干净多了。所以,我们可以,我一眼就能看出来。所以,我们去 Jobly。嘿,看起来更干净了。好的,非常好。所以,Jobly,找到您的下一个机会。所以,首先,让我们搜索工作。让我们看看。所以,我们还没有工作。所以,我们之后会做一些种子功能。我们有一些基本的过滤。嗯,在这种情况下,你知道,我们不知道这是否有效,但让我们看看。我们可以在之后检查一下。雇主仪表板。让我们点击。砰。我们进来了。让我们去我们的工作。我们可以看到创建工作。嗯,您可以看到我们有一个完整的工作流程。我们有申请流程,账单和设置。很好。好的。所以,我现在建议的是,我们需要一些测试数据,对吧?所以,为了得到这个,我将把它重新打开。所以,这项工作现在有效地完成了,对吧?我们,假设我们完成了它,我们检查了它,一切都很好。不,不,抱歉,Chatm 的那个。我们对此相当满意。一切都很好。现在,让我们归档这个。所以,它完成了它的工作。干得好。好了,现在,让我们创建一个新的代理。我在这里想做的是,我将把它变成一个种子代理。所以,这个的职责是根据我们创建的计划来播种数据。所以,我将给您计划,我希望您为一些虚构的组织播种大量不同的工作申请,嗯,一些申请。基本上播种大量数据。还创建另一个组件,允许我传递我的 Clerk 用户 ID,然后您将播种我的个人资料数据,并且还允许我传递我的组织 ID,您可以播种所有,你知道,工作发布和虚假申请到那些工作发布。所以,是的,做吧。我太无聊了。是的,当然,这可能是一个有效的花费,但谁在乎?就像,没关系,对吧?不。不要做我刚才做的事情。点击停止,然后做计划。计划模式。是的。首先进入计划模式。现在,在这里,对于这个,再次,在您做任何事情之前,您通常会做什么?您会来到这里,确保您对此感到满意。然后,一旦您完成了,您将生成一个提交消息。再次,通常这些已经太大了,对吧?所以,您会希望以更小的块来做这些。但然后您有一个干净的分支。然后您继续下一个工作流程。对吧?所以,我们正在分阶段进行。好的。嗯,接下来是,请告诉我,伙计们,所以,你们有什么问题吗?因为我们有超过 150 人还在观看,对吧?你们有什么问题?问我你们的 AI 问题。我想知道,因为这对每个人都有价值。我保证你们很多人都有同样的问题。所以,现在正在播种,您可以看到它正在检查所有内容。公共工作浏览和申请仪表板。所以,这现在正在彻底检查数据库或代码库。它正在检查 Convex Schema,而且我忘了给它计划。所以,让我们看看它是否找到了计划。所以,我们可以中断它然后回去。不,它找到了计划。所以,让 Red Indeed 工作计划。你看。好的。然后,让我们继续进行下一个阶段。现在,您可以看到它正在顺利运行。好的,伙计们,如果您喜欢这个视频,请用力点赞。好了,我想我会继续做事情。我的意思是,即使就像,是的,只是更多的直播,更原始的格式。我认为它现在已经表明它很酷,对吧?你们喜欢这些东西。所以,Hab 说,“我如何使用 Cursor 本身来构建一个像 Cursor 这样的 ID?”嗯,老实说,有趣的是,您实际上可以做到。您实际上可以做到。您实际上可以去并从 VS Code 分叉。嗯,然后您使用 Cursor 来编码该存储库,并基本上构建您自己的嗯,您自己的 Cursor,我想。嗯,显然有一个后端,显然,一个很大的后端,他们有自己的 Composer 代理和一堆其他东西。但是的,所以,在这种情况下,我们准备好了种子脚本。让我们看看。所以,这个小快捷方式,顺便说一下,我总是忘记这个。它是命令 shift s,或者我不记得了,反正。是的。所以,嗯,什么被播种了,您的个人资料,在 org 1 用户记录,等等,等等,您的组织记录,一个 Pro 订阅为您的 org。嗯,在您的 org 下有三到四个发布,虚假数据。所以,它正在创建一个 Comx seed 函数。它正在创建一个组件 seed data 函数和客户端组件 React 组件 seed data。嗯,我们不想有一个组件。我想要脚本。所以,不,我不想,我不想让一个组件来做。所以我只想说,嗯,我们可以做一个组件,但我只是说,我只想执行脚本,允许我生成我们需要的数据。我不需要种子数据组件。嗯,Hard tuber 说,这是嗯,反重力吗?不,这实际上是 Cursor。好的。所以,在这种情况下,我们向下滚动,然后您可以看到这里。所以,这个在下一阶段,我们回到种子,它在另一个分支上做它的事情。只需计划,是的,工作计划。所以,现在阶段五,我们进入了阶段五的领域。所以,我们正在关键集成点,组织范围的 Convex 查询,当雇主与 Convex 交互时,传递组织 ID,嗯,Convex 作者 ID,包括组织声明,所以,这基本上是,你知道,我们之前谈到的基于行的访问控制。账单 Webhook,可选增强,可选地监听 Clerk 账单 Webhook 以同步计划状态到 Convex。您不知道,我们实际上不需要这个。我,实际上我不应该,我应该检查这个。嗯,返回计划。好的。不。所以,没关系。Common 切换到返回当前计划,组织的工作数量。所以,有一个,好的。你看,归根结底,您不需要 5.2。您可以使用,所以,我在这里说,而不是 5.2,嗯,账单 Webhook。我们可以使用 Clerk 作为信息源,并使用 Clerk 的组件,如 protect 和 has hook 来实现我们的身份验证检查。额外的同步是不必要的。所以,基本上,它所说的就是,这将有效地是 Clerk 和 Convex 之间的同步。嗯,我们实际上不需要那个,因为我们实际上不需要在 Convex 中存储用户的订阅。Clerk 处理所有这些,对吧?我们应该让 Clerk 做它的事情,处理它,然后我们基本上只使用 Clerk 提供的钩子和组件来限制用户,对吧?非常感谢。他说,顺便说一句,您做得很好。您是第一个我见过的人,他真正完全理解堆栈,并且知道如何正确地使用编码。嘿,我欣赏你。所以,工作数据播种。这看起来不错。所以,您将如何触发种子脚本?Convex 仪表板 CLI 脚本应用程序,我从 P 运行,因为 Convex mutation,内部加方便的 CLI。让我们都做。是的,因为我们需要一个函数,我们可以从 Convex 仪表板运行,以及一个。我们需要一个我们可以从本地启动的脚本。所以,是的,npx convex run seed。您看到这样的东西很不错,对吧?您看到计划模式的好处。计划模式通常比直接进入代理要消耗更少的上下文和 token。当您直接进入代理而没有计划时,您就在燃烧 token,我的朋友。我向您保证,您只会浪费 token,并且您将一直处于这种奇怪的循环中,只是修复愚蠢的错误。它本不应该是一个错误。好了,阶段五已完成。添加计划使用查询,返回当前计划名称,组织是否有限制,所有前端功能,获取 UI。不,不,不,我们不想要那个。我们不想要那个。我们想要它,是的。你看。利用 Clerk。我们不想这样做。所以,这是一个例子,我实际上会花更多时间来检查计划。显然,我们现在正在直播,所以我对您诚实。我没有仔细检查。嗯,但是,嗯,我们不需要订阅表和同步逻辑。这只是额外的带宽,没有理由。再次,您在用户数量少的时候不会注意到这一点,但当您达到一定规模时,假设您明天成为一个独角兽,拥有百万用户。是的,这将是持续同步订阅的巨大成本和带宽,而您不需要它,因为您无论如何都要为 Clerk 付费。让 Clerk 处理它。好了,数据播种计划已更新。删除 React 组件,包括 seed 和 clear。是的,你看。所以,现在我们有了种子组件。让我们让它构建。所以,在这种情况下,我们可以通过几种方式构建它。嗯,但我们可以从这里触发构建。所以,我们可以从这里或从这里。所以我将点击 seed data build。您可以看到它如何触发那个构建。在这里,您可以看到,而不是使用 pump 和 two,现在它仍然在思考,再次,可能应该在计划模式下做,但再次,这里您说,好主意,使用 Clerk 作为账单的来源,消除了对订阅表的需求,账单 Webhook 和 Convex 中的服务器端计划检查。您可以看到我们不需要任何额外的复杂性。这是 ragazzi 的一个典型例子,AI 可以去并使事情复杂化,这会耗尽您的 token,而且这根本不是正确的方法。所以,如果我只是让它这样做,那将是应用程序中的一个巨大的低效率。对吧?所以,我认为这些教程比以往任何时候都更加重要。Cohen J 说,“请说我的名字,因为我正在工作时观看。您可以引起我的注意。嗯,所以您可以引起我的注意。您是否已经使用了大多数 AI 编辑器?您会根据性能推荐哪一个,嗯,以及成本?”在我看来,我尝试了很多。嗯,它们都,它们都相当不错。我的意思是,就像 GPT 的 Codeex 的那个,我实际上还没有怎么玩过,新的那个,但在我看来,我就是喜欢 Cursor。我喜欢键盘,快捷键的方式,嗯,我们拥有代理视图和所有这些东西的方式。嗯,云代理是
挺酷的。嗯,我目前有两种方式进行编码。再说一遍,我将对你们坦诚相待。我不是在编码,所以不知道他是否在听,但他的用户名是“cone mjar”,但我的编码方式是,我不知道他是否在听,但我现在倾向于在 Cursor 上编码,或者在我的一个 Openclaw 机器人上。我有一个完整的 AI 开发团队,他们进行编码。这很棒,如果你想要的话,我会制作视频。但基本上,我要么在 Openclaw 中进行这些操作,它们直接修改文件,并且每个文件都有自己的工作树分支,然后有一个审查流程,还有一个完整的 PR 自动化机器人等等。这非常棒。但它们会直接修改实际文件,因为这是它们最高效的工作方式。所以,是的,我会使用 Cursor,但我的代理不使用 Claude Code。它们只是直接修改文件并以这种方式完成工作,但它们会使用自己的版本历史记录和工作树。移除订阅。是的,看,很多红色。把那些代码都删掉。好的。让我来修复它。所以,即使是种子文件,你也可以看到即使它必须删除订阅数据。所以,在这种情况下,在另一个代理会话中,我们实际上删除了所有订阅数据,以便我们可以将 Clerk 作为真相的来源。您的文件因此已更新,来自另一个代理。所以,请确保一切都按照 Clerk 作为真相的来源正确工作。让它做它该做的事。好的。Memo Assadi 说,“感谢 Sunny 进行这次直播。我从你那里学到了很多。你在 Cursor 聊天中使用 Claude Code 订阅吗?你是分开的吗?你在 Cursor ID 中有单独的 Claude Code 聊天吗?”哦,太好了。实际上,我没有想到在 Cursor ID 中使用 Claude Code。老实说,我喜欢 Cursor 的流程。但首先,我很高兴你喜欢这个视频。其次,不,我所有的订阅都是分开的。我使用 Claude Code Max 来处理一些事情。我有一个 Cursor Ultra,这是我的个人订阅。然后是 GPT Pro,我可能会订阅,说实话,因为我用得很快。所以,是的。当你花时间编码时,就会发生这种情况。但是的,我的订阅是分开的。所以,我每份订阅支付大约 200 美元,我总共支付大约 400 美元,但之后我通常会超出预算,然后我支付 API。请记住,API 的费率比套餐贵得多。所以,要知道这一点。所以,我今天谈到的效率对于人们来说非常重要,如果你想降低预算的话。Basel 说,“我是一名 Go 开发者。AI 经常犯错误。我使用 MTP 插件等。它对 Go 不好。喜欢这个视频。”首先,感谢你的赞赏。非常感谢你。并不是说它对 Go 不好,而是你使用它的方式,很可能你使用技能的方式。如果你正在与你的 AI 对话,而它没有充分发挥技能,只需输入一个斜杠,强制它使用一个技能。例如,如果我想强制它使用前端技能,请确保它这样做。再说一遍,多使用计划模式。很可能你没有足够地使用计划模式。计划模式非常非常重要。相信我。这样做,你会看到巨大的不同。好的。工作的数据种子。让我们看看。我们现在有了。是的。这太棒了。一切都处理得很好。我们将由另一个代理删除。所以,现在我想做的是显示更新东西的命令。所以,在那之前,我们可以去我们的 Clerk。我想获取用户或组织 ID。所以,我们有了农场,我们有了工作或用户农场组织 ID。所以,你有了 Clerk 用户 ID。所以,看到数据库将你的真实 Clerk ID 作为 JSON 参数传递。所以,在这种情况下,它实际上已经给出了。我的意思是,我希望它以一种更聪明的方式进行自己的种子填充,但我只想传递 Clerk 用户 ID 或组织 ID,然后你应该编写一个脚本来生成大量演示数据。所以,是的,这应该完成了。让我们回到工作,网站登陆。看到这个吗?所以,在工作架构旁边,现在更简单了。Clerk 拥有所有和账单状态。好了。现在让我们来看看。所以,让我们看看。还没有工作发布。现在请记住,在这个账单部分或设置部分,我们去成员,我们可以看到我们有一个邀请流程。所以,这是一个招聘人员。所以,首先,让我们检查一下门控是否有效。所以,我实际上要接受这个邀请。所以,我将打开我的电子邮件,并将在另一个屏幕上快速完成。所以,我可以确保没有敏感信息显示出来。我将确保该帐户,电子邮件正确弹出。好的。所以,你会看到,砰。你会看到这样的东西。一分钟,伙计们。让我试着把它弄成我可以展示的方式。嗯,基本上,你会收到一个邀请,对吧?我的意思是,关于这一点,真的没有什么可说的了。我的意思是,你收到一个邀请,在这里。invitation@ac accounts.deb。你看到 Sunny Sang 已邀请你加入 Papam 组织。所以,我将点击接受。然后,现在我们会看到,哎呀,我犯了同样的错误。抱歉,伙计们,我做了我经常做的那个烦人的事情。我已经登录了该帐户。所以,你应该做的是,不要这样做。做,我需要登录我的单独配置文件。测试时需要单独的配置文件。Gmail blah blah blah 引起了我的注意。感谢您深入的回答。太棒了。谢谢你,伙计。所以我只是要登录单独的配置文件。在 Arc 中,我使用单独的用户配置文件。这在测试中非常有帮助。如果你以前没做过的话。所以,现在我将接受邀请。然后,我们会看到,伙计们,是,哎呀。我一直在犯同样的错误。等一下。这非常令人沮丧。嗯,好的。所以,我会向你展示我的意思。所以,如果我们在这里,所以左边是我蓝色的。在这个方面,我是。所以,让我们进入实际的网站。所以,让我们进入本地 3000。你看到,我没有登录。所以,绿色不同的用户配置文件。所以,我可以轻松地在不同的用户配置文件之间切换。好的。所以,我将登录。嗯,现在,实际上,让我们在这个上做。所以,我将在紫色上做。所以在紫色上,我在一个不同的帐户。所以,让我们来看看这个。所以,让我们假设你知道,我正在登录 team@popreact.com 帐户。所以,继续 Google 团队。哦,不,不,不,不,不。错了。登录。继续。Teampop.com。所以,让它做它该做的事。继续。现在,usernames_1 团队帐户,只是为了让它更简单一点。现在,好了。所以,在这种情况下,显然你可以设置你的重定向到一个合适的地方,但如果我们现在去雇主仪表板,欢迎来到 Jobly for Employers。所以,这还没有加入。这很有趣。所以,如果我们去这里,我可以看到成员邀请。哦,我没有接受。这就是原因。哎呀,我的错。所以,是的,我没有接受我的邀请。所以,如果我进入这个,然后进入接受邀请,它会带我们回到应用程序和邀请流程。我不知道它是否接受了。还没有选择组织。所以,在这里,Papa Fam,对吧?所以,再次,你可以公平地说,你可以解决这些细微差别。你实际上可以让它进入一个,嘿,欢迎来到组织流程等等,对吧?但在这个例子中,没关系。所以,当我们重定向回来时,它没有这样做。所以,我可以创建一个新的代理,然后我说,当发送一个邀请,并且有人接受了加入一个组织的邀请时,让我们为该用户在组织内创建一次愉快的入职体验。所以,我们可以这样做。你可以看到,我使用了 50% 的包含 API 用量。所以,了解你做了什么很重要。好的。如果我们现在点击这个,你可以看到,我进来了。我只使用了 3%。自从我直播以来。所以,对于几乎整个应用程序来说,大部分内容,3% 不算差,对吧?所以,现在你只需要传递两个 ID,Clerk 用户 ID 和组织 ID。好的。所以,让那个同步发生一会儿。所以,让我们同步。让我们为这个用户添加一些种子数据。好的。所以,我们要做的是,我们需要获取这个用户的 ID。所以,这个组织。所以,我将只传递组织,然后我说,对于这个用户。所以,我将去我的用户,然后我将进行用户 ID。酷。然后用户 ID,我们就说,生成种子命令。然后,现在邀请。好的。所以,那个将会在这里添加一个入职流程。让我们向下看。所以,好的。我们有计划。我们的另一个计划是什么?所以,让我们回到我们的 Indeed 计划。第五阶段摘要需求仪表板。所以,我认为第五阶段是最后一部分。加入 Cable 的发票,实现 G 或保护。所以,我只是问接下来是什么。是的,接下来是什么?让它做它该做的事。回到这里。给我命令 PMP seed,在 package.json 中,这意味着我们有一个 seed 命令。所以,你可以看到 MPX convex run seed。就是这样。我们甚至还有一个 clear seed 函数。所以我已经给了它。它将为我生成函数。Command J。让我们 Command E 来做得更好一点。打开一个新的终端。让我们粘贴进去,看看会发生什么。所以,现在它将进行,希望是种子导入。所以,MPX run convex seed,让我们自己看看。所以,如果我们进入我们的应用程序,现在你应该看到它添加了很多用户到我们的应用程序中。所以,种子已创建。它有一个成功的调用。如果我们进入我们的数据,我们可以看到应用程序。哇。好的。所以,我们有很多很多申请。我们有求职信。我们有很多工作。是的。我们有组织。是的。我们有一些假的组织。我们有一些订阅。我们可以删除。它的名字旁边有一个星号,这意味着它已经完成了。用户。嗯,好的。所以,我们也有一些种子用户。酷。所以,现在我们的种子已经完成了。哦,是的。现在它们来了。好了。太好了。我不知道我刚才发出了什么声音,但总之,让我们来看看工作。所以,这个用户就像,嘿,这太棒了。所以,现在我可以看到工作产品经理。如果我点击它,我可以看到编辑工作发布申请。所以,你可以看到我可以改变它们的待定、已审查、已接受、拒绝状态。这很酷,对吧?所以,地点类型也是。现场,就业。所以,在这种情况下,如果我们选择远程或现场,保存更改。好了。已保存。我们有很好的吐司通知,这太棒了。申请。让我们看看。我们可以看到很多不同的示例申请。再说一遍,你可以根据需要构建它,对吧?但让我们看看前端。如果我们搜索工作,现在我可以开始看到一些工作了,对吧?嘿,我们有来自威尔士的 Mike,来自英国。我相信他就是这么说的。Michael Davies,你好,伙计。很高兴见到你。好的。所以,我接下来想向你们展示的是,基本上,是的。所以,如果我们申请的话。所以,首先,我的实际申请。所以,我作为一个用户,对吧?我从来没有去过我的个人资料,对吧?所以,在这种情况下,看,我还没有申请过任何东西,但我没有个人资料。我怎么能申请任何东西呢?对吧?所以,这是雇主仪表板,但我们需要完全分离流程。现在它很混乱。我应该去这里吗?我应该去这里吗?就像,一个普通用户会怎么做?对吧?所以,在这种情况下,如果我们输入软件,也许是解决方案架构师。如果我想申请,就像,我说你好,然后我点击提交。你即将申请解决方案架构师。确认并申请。所以,我申请了,但真正申请的是什么?所以,我们实际上还没有完成整个流程。好消息是它没有失败。但坏消息是我们还没有真正完成任何事情。对吧?所以,如果我们想正确地测试它,看,工作,让我们找一个。实习软件工程。所以,实习软件工程。所以,软件。嗯,它说那是我们自己的工作。所以,我们不能申请我们自己的。好的。嗯,软件工程,也许。是软件吗?不。好的。所以,我们不能申请。如果这是我们自己的仪表板。所以,好的,没关系。所以,我想向你展示的是,更多的是我的个人资料体验。所以,你看,在实际的应用程序上,编辑我的个人资料。所以,我们需要有这样的流程,你知道,就像 LinkedIn 那样的我的个人资料页面,对吧?所以,我们需要解释这个流程,对吧?所以,现在我们可以做的是,我们实际上已经完成了应用程序的主要部分,对吧?所以,看,对我来说。好的。不知道这是什么,这是邀请流程。哪个方向感觉对?哦,所以我们应该在那里使用计划模式。哎呀。嗯,我们可以有几个方向。欢迎模型叠加。多步引导式游览 B 快速入门检查。让我们开始吧。欢迎。我们就做一个。我们将说,去工作网站。接下来是什么?所以,这个,我们已经完成了。在这个阶段,MVP 在功能上是完整的,对吧?所以,它实际上不是。所以,哦,看,196K。所以,我想让你在这里做的是,继续并进行总结,以确保我们不超过 200K,否则我们将开始消耗大量 token。与此同时,我将把它改为计划模式,并开始规划下一部分。所以,我将说,目前用户可以使用封面信进行申请。然而,这并不理想。我们实际上需要一个我的个人资料页面。这里发生的是,它基本上就像一个 LinkedIn 页面。我们应该能够添加我们的工作经验,我们所有的以前的教育领域,任何相关的技能,比如关键词等等,以及我们所有的细节。它应该看起来很漂亮,很现代。然后,当我们申请时,它应该显示这些数据即将与公司共享,并且应该显示我们将与封面信一起共享的个人资料数据。这样,你就可以创建你的个人资料,然后你可以申请一份工作。然后在雇主面板方面,我们需要实际提取这些信息。所以,我们需要实际提取候选人的信息并显示出来。这样,作为雇主,我们可以深入审查候选人。好的。所以,我没有收到下一代项目的项目文件。有趣。好的。请发送电子邮件至 teampop.com。我们可以帮助你。好的。所以,在这种情况下,我将进入计划模式。你可以看到,现在按 Enter 键。然后,在这里,这已经开始进行入职流程。种子填充现在已经完成了。好的。所以,我只是想检查一下,所以,我只是想检查一下问题。我将说,你也可以问。所以我可以说,一个普通的,等等,一个普通人,一个组织成员,可以申请他们自己组织内列出的工作吗?所以,我现在有一个问题。所以我可以把它切换到问题模式,然后这样你就可以问一个问题。所以,入职体验也现在说它完成了。所以,我们实际上可以测试一下。所以,我现在可以进行一些测试。所以,我们回到这里寻找你的下一个机会。让我们去我们的雇主仪表板。啊,好了。所以,第一次进来,你已经加入了团队。这里有一个快速的概述,你可以做什么。浏览工作发布,审查,开始。不错。现在,如果我刷新,我们不应该再看到它了。现在,如果我们深入研究代码,让我们看看。在 Convex 模式中添加一个成员入职表,该表跟踪已完成每个组织的入职的用户。你可以这样做,对吧?所以,我不会说这是错误的方法。但恕我直言,这也不是最高效的方法。对吧?通常我会说的是,难道不更有效率地去使用 Clerk 用户字段中的公共元数据或私有元数据吗?这样我们就不用不断地查询数据库来确保有人已经完成了入职。现在,我将其切换到计划模式,因为基本上每次你进入页面时,会发生的是,它实际上会检查并进行一次数据库调用。这可能看起来不是问题,但这实际上并不是非常高效。而对于已登录用户的元数据,这很好。存储入职信息是一个很棒的地方。所以,你说得对。这是更好的方法。而且,当然,它有时会有点偏颇。它总是偏颇,但真实情况是,它确实要好得多。零额外的数据库查询。所以,看到了解基础知识很重要。好的。现在,在这个中,我将查看雇主的详细信息页面,以了解如何向雇主显示申请。我还想创建另一个代理,说进入计划模式。我将说,目前的登陆页面非常混乱。登陆页面的初始访问者很可能绝大多数是申请工作的人。所以,它应该展示针对这些特定个人的功能。也许在底部,以及在页眉中,我们可以说“面向雇主”。然而,应该有一个清晰的区别。现在它有点混合了两者,这非常混乱。然后让它做它该做的事,然后回到这里。所以,现在入职体验,这个计划,让我们去看看 J pop。为什么这更好?目前,每个仪表板加载都会触发一个 Convex 查询。这是你不知道的,除非你懂。对吧?Clerk 的公共元数据已经嵌入到用户会话令牌中,并且可以在客户端访问。无需网络调用。所以,更改创建一个服务器操作来更新元数据。更新欢迎模型。更新仪表板层。移除 Convex 入职基础设施。酷。构建它。下一个。数据种子。让我们在这里仔细检查一下。所以,这里说,是的,他们可以申请,只检查三件事。用户已认证,工作已激活。用户已申请过该工作。所以,我想检查一下。所以,如果我们去工作。所以,那是草稿。这就是为什么我没看到它,伙计们。但产品经理。所以,在这种情况下,让我们回到这里。让我们搜索工作。产品经理。所以,让我们申请这个。只是想测试一下。高。点击提交。现在让我们去我的申请。我可以看到我提交了这个。嗯,它应该显示实际提交。但是的,你可以看到它是待定的。好的。甚至通知,我们可以实现等等。但你可以看到,即使我没有重建所有东西,你也可以确切地看到我们将如何到达那里,对吧?嗯,如果我们去工作,例如,对吧?现在它正在编码,所以我们很可能会被阻止。再说一遍,这也是为什么工作树很有用,因为现在一切都在本地更改,这可能很危险,对吧?所以,这是这里的入职,它开始在这里编码,登陆页面。所以,让我们看看。申请人首次登陆页面。目前的登陆页面为申请人和雇主提供了大致相等的权重。是的,重构是 100% 面向申请人的。雇主只需通过页眉链接和一个紧凑的、清晰分开的部分。是的,这好多了,对吧?嗯。嗯。构建它。通常,是的,我会彻底检查这些东西。嗯,工作网站,登陆页面,用户个人资料系统,主题。这是一个大事。第一阶段,模式和后端。将配置文件表添加到 Convex 模式。酷。创建 Convex 配置文件。获取我的个人资料。upsert 配置文件。按 ID 获取配置文件。所以,你可以看到它倾向于遵循这种 API 方法,对吧?构建支持,数据库表,然后构建后端函数。然后构建个人资料页面 UI,对吧?这就是我们如何有效地访问我们的个人资料。三,第三阶段,更新申请流程,对吧?用一个多步申请体验替换简单的封面信。当用户点击申请时,他们应该检查他们是否有个人资料等等。第四,雇主候选人视图。所以,上传他们看到的东西。现在我想实现更多。我将说,我们还应该能够上传文件,比如简历或资源,在用户的个人资料部分。雇主可以在申请本身中看到。所以,作为申请的一部分,使用 Convex 文件上传来实现这一点。所以,这就是我们将如何实现文件上传。好的。这会完成它的工作。而且,你看,因为我们有插件,我可以很有把握地认为它会知道如何做所有这些事情,对吧?Michael Davis,你是使用单个数据库还是每个租户一个数据库来创建多租户?很好的问题。嗯,不,它是使用的,它是一个单一的数据库,基本上,你可以实现不同类型的安全层,如果你愿意,但我们有一个单一的数据库,它们只是对每个不同租户的信息的引用,基本上,所以你有一个巨大的,就像,你知道,表,然后基本上引用是查询正在抓取的东西,同样,突变等等,然后我们的查询和突变应该是我们实现我们作者作者卡的地方,对吧?你可以在每个调用级别做到这一点,或者你也可以在每个代理 TS 级别做到这一点。所有五个都已完成。申请人首次登陆页面。好的。所以,登陆页面现在已经完全改变了。所以,让我们看看。所以,首先,这看起来很酷。嗯,让我们回到 Jobly。所以,搜索工作。所以,最近的工作列表。不错。它实际上拉进来了。所以,那个小延迟,初始延迟是它加载那些。所以,这很酷。所以,实际上这些是真的,对吧?它的工作原理。浏览工作,创建帐户,一键申请。为求职者打造。你在招聘吗?不错。雇主仪表板。砰。然后我们去雇主仪表板。这就是我们想要的流程,对吧?如果我去看一个新用户,看,如果我向下看。你在招聘吗?发布工作。点击它。然后看,创建帐户,因为那将带我去组织流程,对吧?所以,这是一个新用户,非常好。好的。嗯,现在如果我们回到这里,让我们也看看。所以,现在我们可以做的是,我们对此很满意,我们可以丢弃它。好的。所以,入职体验,这个,我们开始构建这个了吗?这是为了这个入职检查。现在从 Clerk 会话令牌读取数据。是的,非常好。这基本上是我们想做的。现在你可以看到,我们已经移除了一整张表。好的。嗯,John 说,“我不是开发者,但 AI 已经改变了游戏规则,尤其是当我们学习工作流程和从像你一样聪明的人那里学习流行文本时。疯狂的东西。”非常感谢你,伙计。我真的在努力向所有人开放这个频道,这样我们就可以让每个人都能利用 AI 的力量。实际上,起初我还在想,“你知道吗?哦,太可惜了,因为我喜欢只有编码人员学习这些东西。”但不行,每个人都应该知道这些。就像,每个人都应该能够构建很棒的东西。这就是谁将获胜和谁不会的新的区分,对吧?那些愿意学习这些东西并付出努力来获得他们需要的结果的人,对吧?好的。所以,在这种情况下,这很好。入职体验已完成,我们对此很满意。再说一遍,我在这里跳过了一个步骤,我实际上会检查这些东西,但它,是的,这就是你通常会做的事情,对吧?用户个人资料系统。所以,上传的文件作为可下载链接,带有文件类型图标。好了。所以,再说一遍,你会通过计划来检查,确保你对计划满意。所以,在这种情况下,你会运行一遍,确保你满意。在这种情况下,让我们假设我们都很好,我们将构建。好的。嗯,顺便说一句,是的,我想说一下,即使你使用的是 Cursor Ultra 套餐,对吧?再说一遍,我会一遍又一遍地重复。很可能你并不总是需要 Opus 46 运行。当我实际上编码时,很多时候。问题是,如果你是新手,那么你最好直接使用 Opus 46。原因是,如果你使用一个更笨的模型,简单地说,你最终会团团转,修复像 Opus 46 可能不会犯的错误。而修复和调试以及所有这些的 token 消耗很可能加起来是一样的。所以,不要犯那个错误。而且,先使用计划模式,因为你看到了区别,就像使用计划模式一样,我们可以获得非常好的结果,并且在此基础上堆叠插件,这也有很大的不同,对吧?所以,现在我们有了配置文件,用户 ID,标题,你看到了引用数据库结构。这些是指向用户 ID,经验,教育,技能和文件的,这些是存储 ID。好了,存储,当然,我正在向你展示如何进行 Convex 文件存储。好的。你也可以很容易地将其替换为 AWS S3,然后基本上仍然使用 Convex 数据库,但对文件的引用可以存储在 S3 中,对吧?如果你愿意的话。所以,你真的可以混合搭配你的技术栈。而且,我一次都没有复制粘贴代码,因为那曾经让我很抓狂,当人们复制粘贴代码时。就像我向你展示的,我们一起以正确的方式进行了编码。请告诉我,顺便说一句,在等待这个发生的时候,你的想法是什么?你想要更多我们一起这样编码,分享技巧和窍门以及方法吗?你甚至想让我提前准备一些东西,还是我们应该在直播中从头开始构建?所以,这次我准备了一些东西,这样我就可以提前向你展示。所以我准备了,你知道,整个构建的例子。但一部分我还在想,也许我们应该从一个完全空白的项目开始,然后我在你面前直播构建它?比如,也许这比我事先有点想法然后把它构建出来更真实?告诉我。我真的很想知道,因为就像我说的,这个新系列将由你们指导。好的。所以,即使在这里,让我们搜索工作。我只是想检查一下过滤。所以,我们选择现场实习。好的,我们选择兼职。好了。所以,那正在顺利进行。再说一遍,即使是现在的搜索也可能非常基础。这是一个本地搜索。你可以进行防抖处理,并进行完整的查询驱动搜索。现在,这无关紧要,因为我们只有 15 个活跃列表,对吧?而通常,你实际上会想这样做,通过防抖输入。好的。所以,在这种情况下,我们可以现在做,而这个正在构建。我将再把它交给另一个代理。所以,让我们做 auto call。我将使用 auto plan。我将说,当候选人搜索工作时。目前,搜索是本地的。这不会扩展。我们想添加一个防抖,并在防抖完成后触发一个查询。让我们说,为了演示目的,防抖是 2 秒。你可以使用 lodash 来使其非常高效等等。给我看架构。我展示了我们使用了 Convex 作为后端。使其高效等等。嗯,是的。所以,现在我们正在进行 auto plan。老实说,这比从头开始要便宜得多。我不会称之为 vibe coding。vibe coding 听起来更像是没有经验,没有计划。这是 AI 软件工程。我喜欢这个,Jay。不要把它记下来。这是非常真实的。也许。是的,因为我有同样的感觉。我觉得 vibe coding 有一个非常糟糕的污名。我认为我们称之为 AI 软件工程。也许 AI 软件工程师。这是一个很好的观点。告诉我,伙计们,想想看,哪个名字最容易让你记住?AI 软件工程。是的,告诉我,因为 vibe coding 我确实同意。我觉得它有一个不好的污名,而且我们没有这样做。我们实际上是 AI 辅助编码,这是正确的,但 AI 辅助编码有点像,我喜欢 AI 软件工程。这相当不错,对吧?但是的,告诉我,因为我认为这对很多人来说都会非常重要。而且,即使是构建自动化,openclaw 的东西,我很乐意向你们展示。唯一的问题是,我认为我必须制作专门的视频,因为那些往往更具风险,因为可能会意外显示什么。而且我经常使用那些东西。所以,debounce 工作搜索查询。好了。页面加载所有活动工作,blah blah blah。但这不会扩展。每个客户端都接收全部,不进行本地过滤。搜索输入在用户停止输入后 2 秒进行防抖。位置和就业类型下拉菜单继续立即应用。它们只更改查询参数,并且需要防抖一个 Convex 查询。是的,lodash 新的 Convex 查询。搜索活动工作,这里是。所以,名字是,这更好。浏览工作页面,debounce 查询驱动列表,向后编译,保持列表活动工作不变,只切换 Convex 搜索指示。是的,不错,构建它。然后我将回到这里,让我们看看。是的,每个人都应该感兴趣,但我对看到很多邮政链接,谁在并行代理感到非常无聊。你到底是什么意思?我认为展示有益的用例更重要,因为尽管我看到了很多 AI 编码的讨论,但实际上我没有看到任何原始编码教程。所以,我认为这是人们不这样做的原因,因为事情可能会出错。但我认为人们需要看到这一点。所以,看,我的个人资料。让我们看看。好的,我的个人资料仍在构建中。嗯,让我们看看。是的,它仍在构建中。在这里,我们有它。找不到公共函数。所以,它还在构建中。是的。所以,我们之所以能看到,也是因为如果我们看看这里,伙计们,你可以看到,这通常是它在构建时,这是前端,后端,Convex 运行,对吧?顺便说一句,如果你没有使用 Convex,它对于这些东西来说太棒了。我们甚至不是 Convex 的赞助商。我只是说,它们非常好。而且它们在部署方面非常非常快,而且你所需要的一切都现成了。同样,Clerk 的身份验证也已处理。所以,你可以直接专注于你想构建的东西,而这些东西已经为你处理好了。特别是有了 AI,在我看来,这两者都是绝对的杀手。所以,这将在之后自行调试。仍在构建中。所以,让它做它该做的事。让我们看看工作搜索防抖。你可以看到它已经添加了 lodash。我相信我刚才看到了。是的,lodash。好了。几乎从肯尼亚调谐。Sunny 再次。哟,怎么样?很高兴见到你。哎呀,我不小心按到了。好了。让我们看看。工作安装了沙箱外的所有新依赖项。所以,有趣。我以为它会这样做。pmpp install,然后让它做它该做的事。lodash 正在进行。砰。回去。让我们看看 pro。不是这个。它还在构建中。让我们做搜索工作。搜索活动工作。哦,这是因为它无法部署,因为另一个树正在阻止它,因为 Convex 无法添加它需要的功能,因为它还在构建中。所以,如果我们看到待办事项,创建,更新。我不知道。所以,很可能,如果它不能修复这个,我们将不得不,是的,现在检查修改文件的错误。所以,这通常是你可以在这里做的,如果你有这种类似的体验。所以,成员入职表丢失,如补偿所述。让我检查一下成员入职表,正在探索,必须已经在状态中。不,所以这是通知。所以,这个实际上将是,我们使用 Clerk 元数据。所以,要监控用户入职的组织事宜,我们没有 B2C 入职流程。让我们稍后添加。所以,在那之前,我们也可以看看这个。所以,再说一遍,我喜欢打开很多屏幕,就像分开的屏幕一样,因为否则当我试图最小化东西时,你会看到这些东西发生了,这非常烦人。因为我不能向你们展示我想展示的东西。所以我将在这里保持第二个屏幕打开。PMPM dev 后端。入职流程已经由云元数据处理,而 B2C 入职流程是我们以后要单独处理的。是的。所以,现在它完成了用户个人资料系统,但它有两个 TypeScript 错误,用于个人资料页面。是的,就是这个。所以我找到了。现在,一旦它完成了这个,它就可以部署所有我们应该做的更改,我们就可以开始工作了。所以,看,Convex 函数已准备就绪。现在我们刷新。好了。所以,它正在加载工作。现在,如果我做 HR 协调员,你现在可以看到,一,二,砰,触发搜索。所以,我显然让它变慢了,向你们展示这里发生了什么。所以,让它一,二,砰,对吧?所以,初级开发人员,开发人员,在这种情况下,哎呀,初级开发人员工作,这有点太慢了,说实话。嗯,我也不知道为什么。嗯,很多时候,你应该始终测试你的流程。对吧?所以,在这里,那个在哪里?工作,debounce。所以,修复这个,并且也让 debounce 快得多。debounce 快得多。现在回到这里,让我们继续。所以,工作。所以,最后一个我们做的是元数据。哦,他实际上已经过去并开始自己做 debounce 了。停止。是的,它已经在这里完成了。搜索活动工作名称创建。所以,让这个,让我们让这个运行,因为它正在运行 opus,这是 bal。好的。现在,与此同时,我们需要做一些事情。我需要一个用户入职体验。所以,我们需要生成,哦,我们需要为申请人创建一个用户入职体验,当他们第一次创建帐户时,或者如果他们还没有配置个人资料,我们应该有一个入职体验。然后,我将说,将其存储在 Clerk 的公共元数据中,就像我们为组织所做的那样。所以,使用与 Clerk 组织相同的方法。为用户,B2C 路线做同样的事情。现在,我们,哦,不,不要那样做。再次停止。计划,也停止。我将这样做,只是为了让它现在运行,因为我不想陷入长时间的调试。我们将进入这里。你可以看到,到目前为止,在这个构建中,我们已经从 46% 增加到 55%。所以,BTC 入职流程是提示新工作,blah blah blah blah blah。所以,即使在这里,哦,看。我有一种预感,有什么东西过去了。所以,257。所以,现在最后 50K token 会很贵。所以,在这一点上,这是一个巨大的,即使我们继续总结它,它只会越来越大。在这一点上,我们可以说,关闭它,对吧?所以,那个已经完成了。所以我一直在想,它跳了一百分之一。我想,好吧,很可能我们超过了 200K,现在我们又回到了 41K。你们看到吗?你们能理解吗?如果你们不管理你们的上下文窗口,你们就会像火焰一样穿过你们的东西,这就是他们技术上希望你们做的。这是一个非常聪明的模型。因为如果你不知道你在做什么,那么你当然会像疯子一样消耗你的 token。嗯,Memo Assadi,从头开始。也许花三到四分钟与加入直播的人一起头脑风暴想法、文本,也许在开始时决定规划阶段。之后,你可以继续。是的,我同意。我认为这是一个,我认为这个想法本身,我们必须有一些想法,否则它会有点危险,因为我们可能在直播中想不出一个好主意。所以,我认为我们将有一些备用想法,然后我们可以开始直播,一起直播编码等等。那将是一种很酷的方式。酷。所以,接下来是创建用户。所以,最后一次构建中的一些东西,对吧?你可以看到,这只是 UI 方面的东西,我基本上只是,你知道,通过提示得到了这个,等等。再说一遍,如果你想要那些 UI 的差异,你知道,显然我们看这个。它现在非常基础。好的。这是非常非常简单的设计,你可以设置一个代理来处理整个体验。所以,当那个在工作时,让我们做一些事情。我想做 skills.sh,我想做网页设计,前端设计。这个很棒。现在它实际上提出了一些非常好的东西,颜色和主题。所以,显然你会安装它,然后让我们假设,例如,创建一个新的代理,然后在这里我会说,计划一个完整的应用程序前端设计重新设计。TC 前端设计升级设计或设计网页设计指南,对应用程序的重新设计。嗯,我们想要,是的,让我们只做一个计划应用程序重新设计,然后我将做一个,然后打开,让我们只保持计划模式,看看它会出来什么。好了。申请人入职流程。让我们看看当前状态。入职 B2B 组织工作流程如下。用户公共元数据,入职组织 ID。如果用户没有组织 ID,则渲染入职。这很好。当前的 BTOC 端目前没有入职。用户登陆主页,可以浏览工作,并且必须手动导航到个人资料才能设置个人资料,然后才能申请。完全镜像组织入职模式。在公共元数据中存储 profile_onboarded true。创建一个服务器操作来设置这个标志。然后我们基本上渲染出 UI。创建以下,你知道,服务器布局。然后我们有申请人入职,入职向导,多步。不错。无需更改中间件。是的,这实际上是一个非常好的流程。我们还应该说,如果用户还没有创建他们的个人资料,那么不要让他们提交申请。当然,因为我们已经完成了所有这些用户个人资料的更改,所以我们的种子数据很可能是不正确的。所以,我们必须做的是清除我们的种子数据,然后基本上以同样的方式再次进行。好的。所以,回到这里,我在做什么?回到应用程序本身。所以,让我们看看我的个人资料。嘿,看看这个。这很棒。我们有文件。上传。所以,在这种情况下,先保存你的个人资料才能上传文件。所以,我们可以填充它,如果我们想的话,但我们可以说,高级开发者,我拥有它。好的。伦敦电话。嗯,再说一遍,你可以做,就像,再次,种子。我将创建一个种子文件。我在这里很懒。让我们来创建这个。然后他们说上传文件。让我们来做,例如,硅谷的照片。让我们上传。你可以拖放等等。然后,好了,我们有了。我们可以下载那个文件,如果我们想的话。技能。让我们输入 React。好了。TypeScript AI。是的。教育。不错。好的。我们可以添加教育领域。工作经验。不错。我们也有关于字段。以及个人详细信息。好的。所以,这很酷。我们没有版权,伙计们。我不知道。我做到了。我不是这么说的。嗯,现在如果我们再次去我的申请,这很酷。你看,你可以,你知道,你可以一直走到我们想要的点。我认为即使我到达这个确切的点也不再那么有价值了,因为我已经经历了我们在这里可以做的很多事情。所以,嗯,组织。是的,我们应该已经实现了。嗯,哦,是的,我们可以再改变一个。是的。然后,是的,构建。现在,在最后,我将说,一旦你完成了,我希望种子脚本都已更新,以便我们可以重新填充新的申请,个人资料。还有一个用于填充我们自己的用户个人资料,包含个人资料信息,经验等等。嗯,是的,去做吧。所以,它将进行更新和种子填充,这很好,因为它将拥有我们所做的新更改的上下文。而且它是 87。所以,现在你是否有项目中的现有种子脚本,我也有种子脚本,但不知道在哪里。我不知道在哪里,我只是会在这里偷懒,让它自己弄清楚。它将搜索,让我找到现有的种子,这个重新设计是典型的,它会问你关于重新设计的问题,这是我发现的,如果你使用 opus,那会更好,它更擅长弄清楚你在做什么,但我想看看 auto 能做到什么。但这是很酷的,因为看,使用这两个技能,前端设计和网页设计,它不仅做出了不同的设计方法。好的。但它也会给我们一个很酷的东西。所以,当我们做,就像,网页界面指南时,它会做事情。
就像,呃,可访问性方面的东西,比如焦点状态、表单、正确的标签,所有这些都很棒。它将真正地做到那个程度,这将为你带来更好的 SEO um 排名,以及其他一些类似的东西。这两项技能都非常非常酷。好的。所以,文件检查参考,它有一些成功。是的,太棒了。让我们说做这件事。看看它做了什么。对。用户入门在这里。申请人入门流程现在是。是的。现在看起来,然后之后它应该做种子数据。哦,它现在正在写。我本来想说,是的。所以现在我有了现有的脚本,脚本创建了组织应用程序,但没有创建任何配置文件,而清除函数不删除配置文件。让我更新一下计划。很好。所以现在完成了。你可以检查一下。但我们只是要把它运行一遍,然后我们会检查那些假的个人资料标题摘要教育经历等等。现在我们正在进行重新设计,并且我们正在添加一个入门流程。呃,我们这里有一个来自 Memo Assadi 的问题。他说,“你能再解释一下如何管理上下文以降低光标和代码的成本吗?”是的。所以,通常你在这里的光标 um 上下文中。我喜欢它,因为我可以为 Open Claw 看到这个。我创建了自己的仪表板,所以我可以随时看到我的任何代理的上下文。这非常方便。所以,如果它接近 200k,我就会有一个红条。而且,对于 um claude code,你可以输入一个斜杠命令,我认为它是 /usage,我相信,它会向你展示 um,基本上是如何在那里做的。让我再检查一下。我认为我实际上可以,呃,现在就向你展示我的 clawed 版本。所以,1 分钟,让我们这样做,呃,cd documents builds,这是 jobly YouTube app。好的。所以,如果我在这里,一秒钟,各位。Claude。好的。所以,如果我打开 claude code。所以我这里运行着 CL code。缺少 API 密钥。哦,好的。我需要再次登录。但重点是,目前这处于使用计划中。但如果我们输入 /usage。是的。Usage。Show plan usage。而且我认为甚至上下文。是的。Visualize current context as a 所以你可以看到这个,如果你看到上下文。是的。CC 550 免费空间 154k 自动压缩缓冲区 um 1k 200k。所以,再次,对于这些模型来说,如果你接近它,它就会自动压缩或总结,压缩是你称之为 cloud code 中的东西,但对于 opus 来说,你知道它有一个百万的上下文窗口,这很棒,但相信我,你们大多数人不需要它,所以不要超过 200k,否则你将开始支付 API 限额的两倍,这就是人们被烧伤的地方,因为他们没有意识到他们每次请求都有 700,000 个 token,然后想象一下每次请求,即使是缓存读取,它仍然需要使用那个读取 um 缓存成本。嗯,所以我们来做这个读取。好了。好的,它开始做了。我的意思是,再次,它不是 opus,所以它可能不会,在我看来,它不会做出那么好的重新设计,但它现在看起来有点企业化。但 Opus,你可以达到非常好的水平,就像我基本上解释的那样,好的,我想要一种温暖的感觉。我想要这些漂浮的泡泡在周围漂浮。我希望它完全响应移动设备。你看,你真的,我甚至说,我想要容器查询而不是媒体查询。容器查询是按组件工作的,对吧?它们通常好得多。但即使那样,好的,所以我的意思是,它开始做事情了。所以,给它一个机会,对吧?看,嗯,应用程序重新设计。但有一些事情,当这一切发生的时候。好吧,当我们让它做它的事情时,用户入门体验也是 um,以及种子。是的。所以,当这一切发生的时候,我想继续向你展示更重要的事情。是的。所以,是什么让这一切成为可能,对吧?所以,今天它创造了巨大价值的东西是组织中的 Clerk。所以,Clerk 账单,Clerk 授权,认证,抱歉。嗯,所以即使在这里,比如在 Papa 里面,你可以看到这里的成员,邀请流程,订阅,你拥有所有的账单处理,付款,设置。各位,我告诉你,如果你必须自己构建这个,需要时间。而且,顺便说一句,如果你手动做这件事,有很多地方会出错。嗯,这是我认为不够多人理解的一件事。如果你手动做,即使你认为你已经编码了每一个角落的情况,我保证我可以指出五个边缘情况可能会发生什么。嗯,Danny 说,“兄弟,现场做这个太疯狂了。”我喜欢。耶!我们又回到了那种疯狂的现场感觉。我喜欢这样。说实话,我喜欢做你们觉得疯狂的事情。所以,我很感激。嗯,如果你喜欢,我很乐意做更多。我只要求你摧毁点赞按钮。就这样。我将永远免费做这些事情,各位。嗯,就像我之前说的,当你注册 Clerk 时,请通过描述中的链接。它让他们知道你来自这个教程,它让我能够尽可能长时间地为你做这件事。所以,非常感谢大家。好的,请确保使用描述中的链接。好的,现在让我们看看我们现在在哪里。我认为 um,值得一提的是最后的提问和那些东西。然后我会做一个我们构建的应用程序的演示。然后我显然已经给了你这个最终应用程序的代码。当然会有差异。总是会这样。嗯,你知道,但你可以随意。我已经给了你所有的代码,甚至保存的东西,通知的东西也是。通知,它实际上非常简单。嗯,事实上,当这一切发生的时候,我们甚至可以,你知道,现在就和一个代理谈谈,说我计划添加一个完整的通知系统。所以,当申请人收到关于他们的申请状态的更改通知,或者当雇主收到关于新申请到职位发布的通知时,让我们创建一个完整的应用程序,通知系统。这次不包括电子邮件。你当然可以做到。但现在我们不包括它,但是的,它会出现在文字记录中,但没关系。对。嗯,这个以后可以添加。好的,就这样。对。所以,让我们让它做它的事情。P。我计划在其中。顺便说一下,对于这个,我可能会选择 Opus。但在这种情况下,我不会选择 Opus,因为一,我节省了 token。这更多是为了向你们展示我推荐如何做。但再次,将其置于计划模式,让它做它的事情。好的。现在,用户入门体验。看到文件已移动。我相信它已经完成了。所以,所有已修改。在视频中,最终总结了所有完成的入门工作。漂亮的,多步入门。所以,让我们测试一下入门流程。所以,重新设计也在进行中。我不太喜欢这个重新设计,但它就是这样。没关系。嗯,让我们试试 pop.team@gmail.com。在我看来,对于视觉方面的东西,我推荐 Codeex 53,它在逻辑方面做得很好,价格也很好。然后我发现,呃,它叫什么?嗯,Opus 对于创意工作来说就是好太多了。比如设计,Opus 简直太棒了。嗯,让我们来做 test user。1,2,3。所以,我现在进来了。所以,好的。所以,我的意思是,我做到了,但我不知道如果我搜索工作,然后我在这里,设置个人资料。好的,漂亮。是的。所以,然后它会引导我。所以,如果我说,我不知道,嗨。嗨。嗨。显然,你可以添加你自己的验证。Hi.com 和 LinkedIn。继续。好的。工作经历。你可以暂时跳过,等等。但是的,酷。完成设置,现在当我欢迎来到 Job Sunny,砰,你可以看到我们刷新了。酷。好的。所以,你看,这是如何做到这一点的绝佳例子。嗯,现在我们有保存的个人资料。你甚至可以用 convex 默认使其实时。很容易做到。嗯,就这样。这就是入门流程。我们有后端入门流程,就像我们之前看到的。你可以再次点击职位发布,修改整个状态以及所有这些东西。状态实际上还没有,我们不能改变状态。所以,比如这里我们有职位发布的と状态。所以,再次,这些东西,你必须测试它,当然,对吧?所以,即使在这里,比如编辑职位发布 um,我们应该做一个新的,我们说 um,目前作为组织内的雇主或成员,我应该能够改变职位发布的と状态。目前,如果它是草稿,我无法改变它的と状态。而且,如果我创建一个新的职位发布,我也无法修改它的と状态。嘿,Sir 回到聊天了。怎么了,哥们。让我们来做。自动计划。把它放到计划里。让我们来做。所以,我正在计划一个完整的通知系统。让我们看看它做了什么。现在,我不知道我是否会在稍后启动它,但现在就在这里,在我们继续之前,我想向你展示一下重新设计方面的东西。所以,重新设计。这不同,因为 70.6 6% 的上下文在自动计划中与 Opus 完全不同,对吧?所以,这里它做了一些不同的事情。现在,我得说实话,我不喜欢这个重新设计。嗯,是的,它做了一些不错的事情,但我认为它看起来有点老派。你看,这是 Opus 与自动模型的一个绝佳例子。所以,只是一个绝佳的例子,对吧?就像这种差异就是你可以期待的。作为 um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um um