Skip to content

Unit ​

概览 ​

字段值
KindUnit · 单位 Unit
Realmcommon

继承关系 ​

Unit 是所有场景单位的基础类型,通过父子关系把对象组织成一棵可遍历的层级树,并承载名称、描述、预设标识与父节点等通用信息。它提供按名称、类型或路径查找后代的能力,也能判断祖先与后代关系、统计子节点数量并按索引取子节点,同时支持自定义属性的读写与变化信号。借助克隆、销毁和子节点增删事件,可以完整地管理一个单位的生命周期。

适用场景 ​

当脚本需要把新创建的单位挂载到已有场景层级之下,或按名称、类型、路径定位某个后代节点并监听其属性变化时,都可以通过 Unit 的层级与属性接口完成。

使用要点 ​

Unit 是所有场景单位的基础类型,可通过 World:CreateUnit("Unit", {}) 创建 Unit 实例,也可通过 World:CreateUnit 或 game:CreateUnit 创建具体公开 Unit 子类(如 Folder、WorldUnit、RenderUnit),或从服务和对象树 API 获取实例;不支持 Unit.New(...) 或 Unit(...) 直接构造。随后使用 GetChildren、FindFirstChild、SetAttribute、Destroy 等继承的公共能力。

注意事项 ​

Unit 是所有场景单位的基础类型。Meta 公开且可写的属性支持 unit.Property = value,也隐式支持 unit:SetProperty(value);读取可使用 unit.Property 或 unit:GetProperty()。readOnly=true 的属性只允许读取/Get,不允许直接赋值或 Set。SetAttribute/GetAttribute 只操作按名称创建的自定义属性,不是修改 Name、Parent、Position 等 Meta 属性的通用入口。FindFromPath 使用 '.' 分隔路径(如 unit:FindFromPath("ModelGroup.MyModel.Part1")),与 GetFullPath 返回的路径格式一致,可直接互通。FindFirstChild/FindFirstAncestor 等系列方法用名称匹配,Recursive 参数控制是否递归搜索后代。GetChildAtIndex 的 Lua 入参从 1 开始,GetChildAtIndex(1) 返回第一个子节点,不要传 0。

代码示例 ​

通过具体 Unit 子类管理子节点 ​

lua
-- @runtime client
local world = game:GetService("World")
local root = world:CreateUnit("Folder", { Name = "RootContainer" })
world:CreateUnit("Folder", { Name = "ChildA", Parent = root })
world:CreateUnit("Folder", { Name = "ChildB", Parent = root })
print("子节点数量:", root:GetChildCount())
local firstChild = root:GetChildAtIndex(1)
if firstChild ~= nil then print("第一个子节点:", firstChild.Name) end
root:ClearAllChildren()

安全监听子节点添加与移除 ​

lua
-- @runtime client
local world = game:GetService("World")
local root = world:CreateUnit("Folder", { Name = "EventRoot" })
root.ChildAdded:Once(function(child)
    print("子节点已添加:", child.Name)
end)
local child = world:CreateUnit("Folder", { Name = "TempChild", Parent = root })
local childName = child.Name
root.ChildRemoved:Once(function()
    print("子节点已移除:", childName)
end)
child:Destroy()

属性 (4) ​

Name类型默认值说明
AssetIdString""AssetId 是 Unit 类型下的一个只读字符串属性,标题为“预设ID”,用于承载该 Unit 对应的预设资源标识。它随 Unit 实例一起存在,作者只能读取,不能通过脚本写入。
NameString名称1Unit 的名称属性,类型为字符串,用于标识该节点。
DescString描述1Unit 的描述属性,类型为字符串,用于存放该节点的文字说明。
ParentUnit-Unit 的父节点属性,类型为 Unit,表示当前节点在层级中的上级节点。

事件 (6) ​

ChildAdded ​

签名:ChildAdded(child: Unit) 触发:local

当节点新增一个直接子节点时触发的事件,回调参数为 child(Unit,被添加的子节点)。

回调参数类型说明
childUnit新增的子节点

示例代码

ChildAdded Demo

lua
-- @runtime client
-- 获取 World 服务,用于创建单位
local world = game:GetService("World")
local parent = world:CreateUnit("Folder", { Name = "ParentUnit" })
if parent == nil then return end
-- 先监听再挂载子节点,事件才会被触发
parent.ChildAdded:Once(function(child)
    print("新增子节点:", child.Name)
end)
local child = world:CreateUnit("Folder", { Name = "ChildUnit", Parent = parent })
if child == nil then return end
print("当前子节点数量:", parent:GetChildCount())
print("子节点名称:", child.Name)

ChildRemoved ​

签名:ChildRemoved(child: Unit) 触发:local

当节点的一个直接子节点被移除时触发的事件,回调参数为 child(Unit,被移除的子节点)。

⚙ ChildRemoved 回调触发时,child 可能已经处于脱离父节点或销毁流程中;不要在回调里继续调用 child:GetAttribute()/HasTag() 等依赖完整对象状态的接口。需要判断属性或标签时,在移除前缓存必要信息,或把清理逻辑放在可控的移除流程中。

回调参数类型说明
childUnit移除的子节点

示例代码

安全处理 ChildRemoved

lua
-- @runtime client
local world = game:GetService("World")
local parent = world:CreateUnit("Folder", { Name = "Parent" })
local child = world:CreateUnit("Folder", { Name = "Child", Parent = parent })
local childName = child.Name

parent.ChildRemoved:Once(function()
    -- 使用移除前缓存的信息,不继续访问正在销毁的 child
    print("子节点已移除:", childName)
end)
child:Destroy()

DescendantAdded ​

签名:DescendantAdded(descendant: Unit) 触发:local

当节点的任意后代节点(包含更深层级)被添加时触发的事件,回调参数为 descendant(Unit,被添加的后代节点)。

回调参数类型说明
descendantUnit新增的后代节点

示例代码

监听 DescendantAdded

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
unit.DescendantAdded:Once(function(descendant)
    print("descendant: " .. tostring(descendant))
end)

DescendantRemoving ​

签名:DescendantRemoving(descendant: Unit) 触发:local

当节点的任意后代节点(包含更深层级)被移除时触发的事件,回调参数为 descendant(Unit,被移除的后代节点)。

回调参数类型说明
descendantUnit移除的后代节点

示例代码

监听 DescendantRemoving

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
unit.DescendantRemoving:Once(function(descendant)
    print("descendant: " .. tostring(descendant))
end)

AncestryChanged ​

签名:AncestryChanged(child: Unit, oldParent: Unit) 触发:local

当节点的父节点发生变更时触发的事件,回调参数依次为 child(Unit,发生变化的节点)与 oldParent(Unit,变更前的父节点)。

回调参数类型说明
childUnit变更的节点
oldParentUnit原父节点

示例代码

AncestryChanged Demo

lua
-- @runtime client
local world = game:GetService("World")
local oldParent = world:CreateUnit("Folder", { Name = "OldParentUnit" })
if oldParent == nil then return end
local child = world:CreateUnit("Folder", { Name = "MovedChild", Parent = oldParent })
if child == nil then return end
-- 回调参数分别为发生变更的节点与变更前的父节点
child.AncestryChanged:Once(function(changedChild, previousParent)
    print("发生层级变更的节点:", changedChild.Name)
    print("变更前是否无父节点:", previousParent == nil)
end)
-- 脱离原父节点以触发层级变更
child.Parent = nil
print("变更后父节点是否为空:", child.Parent == nil)

Destroying ​

签名:Destroying() 触发:local

当节点被销毁时触发的事件,没有回调参数。

示例代码

监听 Destroying

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
unit.Destroying:Once(function()
    print("Destroying event")
end)

函数 (25) ​

ClearAllChildren ​

签名:ClearAllChildren() -> void

移除当前节点的所有直接子节点,无参数、无返回值。

返回值 void

示例代码

调用 ClearAllChildren

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
unit:ClearAllChildren()
print("调用完成", unit)

GetChildren ​

签名:GetChildren() -> Array<Unit> (子节点列表)

获取当前节点的全部直接子节点,无参数,返回子节点列表(Unit 数组)。

返回值 Array<Unit> (子节点列表)

示例代码

调用 GetChildren

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local result = unit:GetChildren()  -- 返回 Array
if result ~= nil then
    for index, item in ipairs(result) do
        print(index, item)
    end
end

GetDescendants ​

签名:GetDescendants() -> Array&lt;Unit&gt; (所有后代节点列表)

获取当前节点的所有后代节点(包含各层级),无参数,返回所有后代节点列表(Unit 数组)。

返回值 Array<Unit> (所有后代节点列表)

示例代码

调用 GetDescendants

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local result = unit:GetDescendants()  -- 返回 Array
if result ~= nil then
    for index, item in ipairs(result) do
        print(index, item)
    end
end

IsAncestorOf ​

签名:IsAncestorOf(Descendant: Unit) -> Bool (是否为指定节点的祖先)

判断当前节点是否为指定节点的祖先,参数 Descendant 为 Unit,返回布尔值。

参数类型说明
DescendantUnit要判断的后代节点

返回值 Bool (是否为指定节点的祖先)

示例代码

调用 IsAncestorOf

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local world = game:GetService("World")
local Descendant = world:CreateUnit("Folder", {})
if Descendant == nil then return end
local result = unit:IsAncestorOf(Descendant)  -- 返回 Bool
if result then
    print("调用结果为 true")
else
    print("调用结果为 false")
end

IsDescendantOf ​

签名:IsDescendantOf(Ancestor: Unit) -> Bool (是否为指定节点的后代)

判断当前节点是否为指定节点的后代,参数 Ancestor 为 Unit,返回布尔值。

参数类型说明
AncestorUnit要判断的祖先节点

返回值 Bool (是否为指定节点的后代)

示例代码

调用 IsDescendantOf

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local world = game:GetService("World")
local Ancestor = world:CreateUnit("Folder", {})
if Ancestor == nil then return end
local result = unit:IsDescendantOf(Ancestor)  -- 返回 Bool
if result then
    print("调用结果为 true")
else
    print("调用结果为 false")
end

FindFirstAncestor ​

签名:FindFirstAncestor(Name: String) -> Unit (匹配的祖先节点)

按名称查找当前节点的第一个祖先节点,参数 Name 为字符串,返回匹配的祖先节点(Unit)。

参数类型说明
NameString要查找的祖先节点名称

返回值 Unit (匹配的祖先节点)

示例代码

调用 FindFirstAncestor

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local Name = "default"  -- String
local result = unit:FindFirstAncestor(Name)  -- 返回 Unit
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

FindFirstAncestorWhichIsA ​

签名:FindFirstAncestorWhichIsA(ClassName: String) -> Unit (匹配类型的祖先节点)

按类型查找当前节点的第一个祖先节点(IsA 语义),参数 ClassName 为字符串,返回匹配类型的祖先节点(Unit)。

参数类型说明
ClassNameString要匹配的类型名称

返回值 Unit (匹配类型的祖先节点)

示例代码

调用 FindFirstAncestorWhichIsA

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local ClassName = "default"  -- String
local result = unit:FindFirstAncestorWhichIsA(ClassName)  -- 返回 Unit
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

FindFirstAncestorOfClass ​

签名:FindFirstAncestorOfClass(ClassName: String) -> Unit (匹配类的祖先节点)

按类名查找当前节点的第一个祖先节点,参数 ClassName 为字符串,返回匹配类的祖先节点(Unit)。

参数类型说明
ClassNameString要精确匹配的类型名称

返回值 Unit (匹配类的祖先节点)

示例代码

调用 FindFirstAncestorOfClass

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local ClassName = "default"  -- String
local result = unit:FindFirstAncestorOfClass(ClassName)  -- 返回 Unit
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

FindFirstChild ​

签名:FindFirstChild(Name: String, Recursive?: Bool) -> Unit (匹配的子节点)

按名称查找当前节点的第一个子节点,参数 Name 为字符串,可选参数 Recursive 为布尔值,返回匹配的子节点(Unit)。

参数类型说明
NameString要查找的子节点名称
Recursive?Booltrue 时递归搜索所有后代节点

返回值 Unit (匹配的子节点)

示例代码

调用 FindFirstChild

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local Name = "default"  -- String
local Recursive = false  -- Bool
local result = unit:FindFirstChild(Name, Recursive)  -- 返回 Unit
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

FindFirstChildWhichIsA ​

签名:FindFirstChildWhichIsA(ClassName: String, Recursive?: Bool) -> Unit (匹配类型的子节点)

按类型查找当前节点的第一个子节点(IsA 语义),参数 ClassName 为字符串,可选参数 Recursive 为布尔值,返回匹配类型的子节点(Unit)。

参数类型说明
ClassNameString要匹配的类型名称
Recursive?Booltrue 时递归搜索所有后代节点

返回值 Unit (匹配类型的子节点)

示例代码

调用 FindFirstChildWhichIsA

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local ClassName = "default"  -- String
local Recursive = false  -- Bool
local result = unit:FindFirstChildWhichIsA(ClassName, Recursive)  -- 返回 Unit
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

FindFirstChildOfClass ​

签名:FindFirstChildOfClass(ClassName: String, Recursive?: Bool) -> Unit (匹配类的子节点)

按类名查找当前节点的第一个子节点,参数 ClassName 为字符串,可选参数 Recursive 为布尔值,返回匹配类的子节点(Unit)。

参数类型说明
ClassNameString要精确匹配的类型名称
Recursive?Booltrue 时递归搜索所有后代节点

返回值 Unit (匹配类的子节点)

示例代码

调用 FindFirstChildOfClass

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local ClassName = "default"  -- String
local Recursive = false  -- Bool
local result = unit:FindFirstChildOfClass(ClassName, Recursive)  -- 返回 Unit
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

HasChildren ​

签名:HasChildren() -> Bool (是否有子节点)

判断当前节点是否存在子节点,无参数,返回布尔值。

返回值 Bool (是否有子节点)

示例代码

调用 HasChildren

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local result = unit:HasChildren()  -- 返回 Bool
if result then
    print("调用结果为 true")
else
    print("调用结果为 false")
end

GetChildCount ​

签名:GetChildCount() -> Int (子节点数量)

获取当前节点的直接子节点数量,无参数,返回整数。

返回值 Int (子节点数量)

示例代码

调用 GetChildCount

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local result = unit:GetChildCount()  -- 返回 Int
if result ~= nil then
    print(result)
    if result ~= 0 then
        print("结果非零")
    end
end

GetChildAtIndex ​

签名:GetChildAtIndex(Index: Int) -> Unit (指定索引的子节点)

按索引获取当前节点的子节点,参数 Index 为整数,返回指定索引的子节点(Unit)。

⚙ Lua API 使用 1-based 索引;传 1 获取第一个直接子节点,传 0 无法表示第一个子节点。

参数类型说明
IndexInt子节点的索引位置,从 1 开始

返回值 Unit (指定索引的子节点)

示例代码

按 1-based 索引获取子节点

lua
-- @runtime client
local world = game:GetService("World")
local parent = world:CreateUnit("Folder", { Name = "Parent" })
world:CreateUnit("Folder", { Name = "FirstChild", Parent = parent })

-- GetChildAtIndex 使用 1-based 索引:1 表示第一个子节点
local firstChild = parent:GetChildAtIndex(1)
if firstChild then
  print("第一个子节点: " .. firstChild.Name)
end

SetAttribute ​

签名:SetAttribute(attrName: String, value: Any) -> void

为当前节点设置指定名称的自定义属性,参数 attrName 为字符串、value 为任意类型,无返回值。

参数类型说明
attrNameString自定义属性的键名
valueAny自定义属性的值,支持任意类型

返回值 void

示例代码

调用 SetAttribute

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local attrName = "default"  -- String
local value = nil  -- Any
unit:SetAttribute(attrName, value)
local currentValue = unit:GetAttribute(attrName)
if currentValue ~= nil then
    print("当前值: " .. tostring(currentValue))
end

GetAttribute ​

签名:GetAttribute(attrName: String) -> Any (属性值)

获取指定名称的自定义属性值,参数 attrName 为字符串,返回属性值(Any)。

参数类型说明
attrNameString自定义属性的键名

返回值 Any (属性值)

示例代码

调用 GetAttribute

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local attrName = "default"  -- String
local result = unit:GetAttribute(attrName)  -- 返回 Any
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

GetAllProps ​

签名:GetAllProps() -> Map (所有属性键值表)

收集当前节点的所有属性,无参数,返回属性键值表(Map)。

返回值 Map (所有属性键值表)

示例代码

遍历当前单位的公开属性映射

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("WorldUnit", { Name = "TestUnit" })
local props = unit:GetAllProps()
for propertyName, propertyValue in pairs(props) do
    print(propertyName, propertyValue)
end

Clone ​

签名:Clone() -> Unit (克隆得到的新 Unit)

克隆当前 Unit 及其子节点,返回新的 Unit 副本。

返回值 Unit (克隆得到的新 Unit)

示例代码

调用 Clone

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local result = unit:Clone()  -- 返回 Unit
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

IsA ​

签名:IsA(className: String) -> Bool (是否为指定类型)

判断当前节点是否为指定类型,参数 className 为字符串,返回布尔值。

参数类型说明
classNameString要判断的类型名称

返回值 Bool (是否为指定类型)

示例代码

调用 IsA

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local className = "default"  -- String
local result = unit:IsA(className)  -- 返回 Bool
if result then
    print("调用结果为 true")
else
    print("调用结果为 false")
end

Destroy ​

签名:Destroy() -> void

删除当前节点,无参数、无返回值。

返回值 void

示例代码

调用 Destroy

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
unit:Destroy()
print("调用完成", unit)

GetPropertyChangedSignal ​

签名:GetPropertyChangedSignal(propName: String) -> Signal (属性变化信号)

获取指定属性的变化信号,参数 propName 为字符串,返回该属性的变化信号(Signal)。

参数类型说明
propNameString要监听的属性名称

返回值 Signal (属性变化信号)

示例代码

调用 GetPropertyChangedSignal

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", {})
if unit == nil then return end
local propName = "default"  -- String
local result = unit:GetPropertyChangedSignal(propName)  -- 返回 Signal
if result ~= nil then
    print("调用成功,结果: " .. tostring(result))
end

GetAttributeChangedSignal ​

签名:GetAttributeChangedSignal(attrName: String) -> Signal (自定义属性变化信号)

获取指定自定义属性的变化信号,参数 attrName 为字符串,返回该属性的变化信号(Signal)。

⚙ 该方法监听 SetAttribute/GetAttribute 管理的自定义属性。客户端启动入口对 LocalPlayer 立即注册时,信号代理可能尚未就绪;当前运行包反馈需延迟约 1 秒。延迟时长属于兼容性 workaround,不是稳定 API 契约,注册后还应主动读取一次当前值。

参数类型说明
attrNameString要监听的自定义属性名称

返回值 Signal (自定义属性变化信号)

示例代码

延迟注册本地玩家自定义属性监听

lua
-- @runtime client
local Players = game:GetService("Players")
local Task = game:GetService("Task")

Task:Delay(1, function()
    local player = Players.LocalPlayer
    if player == nil then return end

    local attributeName = "Ready"
    player:GetAttributeChangedSignal(attributeName):Connect(function()
        print(attributeName, player:GetAttribute(attributeName))
    end)
    -- 避免遗漏注册前已经写入的值
    print(attributeName, player:GetAttribute(attributeName))
end)

FindFromPath ​

签名:FindFromPath(path: String) -> Unit (查找到的节点,路径不合法或中途断开返回 nil)

按路径字符串查找节点,参数 path 为字符串,返回查找到的节点(Unit);路径不合法或中途断开时返回 nil。

参数类型说明
pathString以 '.' 分隔的层级路径,如 '父节点.子节点.目标节点'

返回值 Unit (查找到的节点,路径不合法或中途断开返回 nil)

示例代码

按 '.' 分隔路径逐级查找节点

lua
-- @runtime client
local world = game:GetService("World")
local root = world:CreateUnit("Folder", { Name = "Root" })
local mid = world:CreateUnit("Folder", { Name = "Mid", Parent = root })
world:CreateUnit("Folder", { Name = "Leaf", Parent = mid })

-- 按 '.' 分隔的路径逐级查找(与 GetFullPath 返回格式互通)
local found = root:FindFromPath("Mid.Leaf")
if found then
  print("找到节点: " .. found.Name)  -- 输出 Leaf
end

GetFullPath ​

签名:GetFullPath() -> String (完整路径字符串('.'分隔))

获取当前节点的完整路径字符串,无参数,返回以 '.' 分隔的路径。

返回值 String (完整路径字符串('.'分隔))

示例代码

获取从根到自身的 '.' 分隔路径

lua
-- @runtime client
local world = game:GetService("World")
local root = world:CreateUnit("Folder", { Name = "Root" })
local mid = world:CreateUnit("Folder", { Name = "Mid", Parent = root })
local leaf = world:CreateUnit("Folder", { Name = "Leaf", Parent = mid })

-- 返回从根到自身的 '.' 分隔路径(不含根),可直接传回 FindFromPath
local path = leaf:GetFullPath()
print("完整路径: " .. path)  -- 输出 Root.Mid.Leaf(不含 World 根)

GetDebugId ​

签名:GetDebugId() -> String (调试标识)

获取当前节点的调试标识,无参数,返回字符串。

返回值 String (调试标识)

示例代码

读取具体 Unit 子类实例的调试标识

lua
-- @runtime client
local world = game:GetService("World")
local unit = world:CreateUnit("Folder", { Name = "DebugTarget" })
local debugId = unit:GetDebugId()
if debugId ~= nil and debugId ~= "" then
    print("调试标识:", debugId)
end