SWEP throwing a lua error

This error only shows up in the console and only happens rarely, but I’m not sure how to go about fixing it… any ideas?

Here’s the error


Lua Error: [ERROR] addons/spas/lua/weapons/weapon_real_spas/shared.lua:417: Tried to use a NULL entity! 1. MuzzleFlash - [C]:-1 2. CSShootBullet - addons/spas/lua/weapons/weapon_real_spas/shared.lua:417 3. RecoilPower - addons/spas/lua/weapons/weapon_real_spas/shared.lua:358 4. unknown - addons/spas/lua/weapons/weapon_real_spas/shared.lua:180

and the swep



local h3 = {}
h3["channel"] = CHAN_WEAPON
h3["level"]   = SNDLVL_GUNFIRE
h3["sound"]   = "weapons/spas/spas12-1.wav"
h3["name"]    = "Weapon_H3.Single"
h3["script"]  = "scripts/sounds/hl2_game_sounds_weapons.txt"

local h31 = {}
h31["channel"] = CHAN_ITEM
h31["level"]   = SNDLVL_NORM
h31["sound"]   = "weapons/spas/m3_insertshell.wav"
h31["name"]    = "Spas12.Insert"
h31["script"]  = "scripts/sounds/hl2_game_sounds_weapons.txt"
h31["pitch"]   = "95,105"
sound.Add(h31)

local h36 = {}
h36["channel"] = CHAN_ITEM
h36["level"]   = SNDLVL_NORM
h36["sound"]   = "weapons/spas/m3_pump.wav"
h36["name"]    = "Spas12.Pump"
h36["script"]  = "scripts/sounds/hl2_game_sounds_weapons.txt"
h36["pitch"]   = "95,105"
sound.Add(h36)
sound.Add(h3)

-- CAN THE SHOTGUN DESTROY DOORS WITH THE BUCKSHOT ROUNDS? 1 = YES, 0 = NO
SWEP.DestroyDoor = 1
--------------------------------------------------------------------------

-- Read the weapon_real_base if you really want to know what each action does

/*---------------------------------------------------------*/
local HitImpact = function(attacker, tr, dmginfo)

	local hit = EffectData()
	hit:SetOrigin(tr.HitPos)
	hit:SetNormal(tr.HitNormal)
	hit:SetScale(20)
	util.Effect("effect_hit", hit)

	return true
end
/*---------------------------------------------------------*/

if (SERVER) then
	AddCSLuaFile("shared.lua")
end

if (CLIENT) then
	SWEP.PrintName 		= "SPAS-12"
	SWEP.Author = "Buu342"
	SWEP.Slot 			= 3
	SWEP.SlotPos 		= 1
	SWEP.IconLetter 		= "k"
	SWEP.Purpose 		= "shooting things"
	killicon.AddFont("weapon_spas_12", "CSKillIcons", SWEP.IconLetter, Color( 255, 80, 0, 255 ))
end
/*---------------------------------------------------------
Muzzle Effect + Shell Effect
---------------------------------------------------------*/
SWEP.MuzzleEffect			= "rg_muzzle_grenade" -- This is an extra muzzleflash effect
-- Available muzzle effects: rg_muzzle_grenade, rg_muzzle_highcal, rg_muzzle_hmg, rg_muzzle_pistol, rg_muzzle_rifle, rg_muzzle_silenced, none

SWEP.ShellEffect			= "rg_shelleject_shotgun" -- This is a shell ejection effect
-- Available shell eject effects: rg_shelleject, rg_shelleject_rifle, rg_shelleject_shotgun, none

SWEP.MuzzleAttachment		= "1" -- Should be "1" for CSS models or "muzzle" for hl2 models
SWEP.ShellEjectAttachment	= "2" -- Should be "2" for CSS models or "1" for hl2 models

SWEP.EjectDelay			= 0.53
/*-------------------------------------------------------*/

local DoorSound = Sound("physics/wood/wood_box_impact_hard3.wav")
local ShotgunReloading
ShotgunReloading = false

SWEP.Instructions 		= "Buckshot Damage (Per buckshot lead): 9% 
Slug Damage (Per slug): 88% 
Recoil: 50% 
Buckshot Precision: 55% 
Slug Precision: 85% 
Type: Pump-Action 

Change Mode: E + Right Click"

SWEP.Category			= "SPAS12"	-- For HAXORS: feel free to change this if you want this swep in a different category
SWEP.Base 			= "weapon_real_base_pistol"

SWEP.HoldType 			= "shotgun"

SWEP.Spawnable 			= true
SWEP.AdminSpawnable 		= false

SWEP.ViewModel 			= "models/weapons/v_spas12_shotgun.mdl"
SWEP.WorldModel 		= "models/weapons/w_spas12_shotgun.mdl"

SWEP.Primary.Sound 		= Sound("Weapon_H3.Single")
SWEP.Primary.Recoil 		= 5
SWEP.Primary.Damage 		= 20
SWEP.Primary.NumShots 		= 15
SWEP.Primary.Cone 		= 0.045
SWEP.Primary.ClipSize 		= 8
SWEP.Primary.Delay 		= 0.95
SWEP.Primary.DefaultClip 	= 40
SWEP.Primary.Automatic 		= false
SWEP.Primary.Ammo 		= "buckshot"
SWEP.Primary.Force		= 2000

SWEP.Secondary.ClipSize 	= -1
SWEP.Secondary.DefaultClip 	= -1
SWEP.Secondary.Automatic 	= false
SWEP.Secondary.Ammo 		= "none"

SWEP.IronSightsPos              = Vector (2.8603, -1.2217, 0.8227)
SWEP.IronSightsAng              = Vector (1.3197, 0.0305, -0.0001)
SWEP.RunArmOffset 		= Vector (3.8652, -2.8154, -0.3196)
SWEP.RunArmAngle 		= Vector (-13.4962, 29.1912, -4.9571)

SWEP.data 			= {}
SWEP.mode 			= "burst"	-- Start with the buckshot rounds

SWEP.data.burst 		= {}		-- Buckshot Rounds
SWEP.data.burst.Cone 		= 0.045	-- Cone of the buckshot rounds
SWEP.data.burst.NumShots 	= 12		-- 12 little leads
SWEP.data.burst.Damage 		= 9		-- Damage of a lead

SWEP.data.semi 			= {}		-- Slug Rounds
SWEP.data.semi.Cone 		= 0.015	-- Cone of the slug rounds
SWEP.data.semi.NumShots 	= 1		-- 1 big lead
SWEP.data.semi.Damage 		= 88		-- Damage of the big lead

function SWEP:Initialize()

automode = false

end


/*---------------------------------------------------------
PrimaryAttack
---------------------------------------------------------*/
function SWEP:PrimaryAttack()
	
	if self.Owner:KeyDown(IN_USE) then
	if automode == false then
		automode = true
		self.Owner:PrintMessage( HUD_PRINTCENTER, "Automatic Mode" )
		self.Weapon:SetNextSecondaryFire(CurTime() + 1)
		self.Weapon:SetNextPrimaryFire(CurTime() + 1)
		self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
		timer.Simple(0.3, function() self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH) end)	
		self.Primary.Delay = 0.4	
		self.Primary.Cone = 1
		else
		automode = false
		self.Owner:PrintMessage( HUD_PRINTCENTER, "Pump Mode" )
		self.Weapon:SetNextSecondaryFire(CurTime() + 1)
		self.Weapon:SetNextPrimaryFire(CurTime() + 1)
		self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
		timer.Simple(0.3, function() self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH) end)	
		self.Primary.Delay = 0.95
		self.Primary.Cone = 0.045
				end
			elseif SERVER then
			end


	if !self.Owner:KeyDown(IN_USE) then

	if not self:CanPrimaryAttack() or self.Owner:WaterLevel() > 2 then return end
	-- If your gun have a problem or if you are under water, you'll not be able to fire

	self.Reloadaftershoot = CurTime() + self.Primary.Delay
	-- Set the reload after shoot to be not able to reload when firering

	self.Weapon:SetNextSecondaryFire(CurTime() + self.Primary.Delay)
	-- Set next secondary fire after your fire delay

	self.Weapon:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
	-- Set next primary fire after your fire delay

	self.Weapon:EmitSound(self.Primary.Sound)
	-- Emit the gun sound when you fire

	self:RecoilPower()

	self:TakePrimaryAmmo(1)
	-- Take 1 ammo in you clip

	if ((game.SinglePlayer() and SERVER) or CLIENT) then
		self.Weapon:SetNetworkedFloat("LastShootTime", CurTime())	

	
		end
	end
end

/*---------------------------------------------------------
SecondaryAttack
---------------------------------------------------------*/
function SWEP:SecondaryAttack()

	if self.Owner:KeyDown(IN_USE) then
		if self.mode == "semi" then
			self.mode = "burst"
			self.Owner:PrintMessage( HUD_PRINTCENTER, "Buckshot Rounds" )
			self.Weapon:SetNextSecondaryFire(CurTime() + 1)
			self.Weapon:SetNextPrimaryFire(CurTime() + 1)
			self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
			timer.Simple(0.3, function() self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH) end)
		else
			self.mode = "semi"
			self.Owner:PrintMessage( HUD_PRINTCENTER, "Slug Rounds" )
			self.Weapon:SetNextSecondaryFire(CurTime() + 1)
			self.Weapon:SetNextPrimaryFire(CurTime() + 1)
			self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
			timer.Simple(0.3, function() self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH) end)
		end
		self.data[self.mode].Init(self)

	elseif SERVER then
		end
end

/*---------------------------------------------------------
Deploy
---------------------------------------------------------*/
function SWEP:Deploy()

	self.Weapon:SendWeaponAnim( ACT_VM_DRAW )
	-- Set the deploy animation when deploying

	self:SetIronsights( false )
	-- Set the ironsight mod to false

	self.Weapon:SetNextPrimaryFire(CurTime() + 1)
	-- Set the next primary fire to 1 second after deploying

	ShotgunReloading = false
	self.Weapon:SetNetworkedBool( "reloading", false)

	self.Weapon:SendWeaponAnim( ACT_VM_DRAW )
	-- Set the deploy animation when deploying

	self:SetIronsights( false )
	-- Set the ironsight mod to false

	self.Weapon:SetNextPrimaryFire(CurTime() + 1)
	-- Set the next primary fire to 1 second after deploying

	self.Reloadaftershoot = CurTime() + 1

	return true
end

/*---------------------------------------------------------
Reload
---------------------------------------------------------*/
function SWEP:Reload()

	if ( self.Reloadaftershoot > CurTime() ) then return end

	if (self.Weapon:GetNWBool("reloading", false)) or ShotgunReloading then return end

	if (self.Weapon:Clip1() < self.Primary.ClipSize and self.Owner:GetAmmoCount(self.Primary.Ammo) > 0) then
			ShotgunReloading = true
			self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
			self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)
			self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
		timer.Simple(0.3, function()
			ShotgunReloading = false
			self.Weapon:SetNetworkedBool("reloading", true)
			self.Weapon:SetVar("reloadtimer", CurTime() + 1)
			self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
			self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)
		end)
	end

	self.Owner:SetFOV( 0, 0.15 )
	-- Zoom = 0

	self:SetIronsights(false)
	-- Set the ironsight to false
end

/*---------------------------------------------------------
Think
---------------------------------------------------------*/
function SWEP:Think()

	if self.Weapon:Clip1() > self.Primary.ClipSize then
		self.Weapon:SetClip1(self.Primary.ClipSize)
	end

	if self.Weapon:GetNetworkedBool( "reloading") == true then
	
		if self.Weapon:GetNetworkedInt( "reloadtimer") < CurTime() then
			if self.unavailable then return end

			if ( self.Weapon:Clip1() >= self.Primary.ClipSize || self.Owner:GetAmmoCount( self.Primary.Ammo ) <= 0 ) then
				self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
				self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)
				self.Weapon:SetNetworkedBool( "reloading", false)
				self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
			else
			
			self.Weapon:SetNetworkedInt( "reloadtimer", CurTime() + 0.45 )
			self.Weapon:SendWeaponAnim( ACT_VM_RELOAD )
			self.Owner:RemoveAmmo( 1, self.Primary.Ammo, false )
			self.Weapon:SetClip1(  self.Weapon:Clip1() + 1 )
			self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
			self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)

				if ( self.Weapon:Clip1() >= self.Primary.ClipSize || self.Owner:GetAmmoCount( self.Primary.Ammo ) <= 0) then
					self.Weapon:SetNextPrimaryFire(CurTime() + 1.5)
					self.Weapon:SetNextSecondaryFire(CurTime() + 1.5)
				else
					self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
					self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)
				end
			end
		end
	end

	self:IronSight()

	if self.Owner:KeyPressed(IN_ATTACK) and (self.Weapon:GetNWBool("reloading", true)) then
		self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
		self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
		self.Weapon:SetNetworkedBool( "reloading", false)
		self.Weapon:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
	end
end

/*---------------------------------------------------------
RecoilPower | Shotgun
---------------------------------------------------------*/
function SWEP:RecoilPower()

	if not self.Owner:IsOnGround() then
		if (self:GetIronsights() == true) then
			self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Put normal recoil when you're in ironsight mod

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * (self.Primary.Recoil), math.Rand(-1,1) * (self.Primary.Recoil), 0))
			-- Punch the screen 1x less hard when you're in ironsigh mod
		else
			self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil * 2.5, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Recoil * 2.5

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * (self.Primary.Recoil * 2.5), math.Rand(-1,1) * (self.Primary.Recoil * 2.5), 0))
			-- Punch the screen * 2.5
		end

	elseif self.Owner:KeyDown(bit.bor(IN_FORWARD, IN_BACK, IN_MOVELEFT, IN_MOVERIGHT)) then
		if (self:GetIronsights() == true) then
			self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil / 2, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Put recoil / 2 when you're in ironsight mod

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * (self.Primary.Recoil / 1.5), math.Rand(-1,1) * (self.Primary.Recoil / 1.5), 0))
			-- Punch the screen 1.5x less hard when you're in ironsigh mod
		else
			self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil * 1.5, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Recoil * 1.5

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * (self.Primary.Recoil * 1.5), math.Rand(-1,1) * (self.Primary.Recoil * 1.5), 0))
			-- Punch the screen * 1.5
		end

	elseif self.Owner:Crouching() then
		if (self:GetIronsights() == true) then
			self:CSShootBullet(self.data[self.mode].Damage, 0, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Put 0 recoil when you're in ironsight mod

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * (self.Primary.Recoil / 3), math.Rand(-1,1) * (self.Primary.Recoil / 3), 0))
			-- Punch the screen 3x less hard when you're in ironsigh mod
		else
			self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil / 2, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Recoil / 2

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * (self.Primary.Recoil / 2), math.Rand(-1,1) * (self.Primary.Recoil / 2), 0))
			-- Punch the screen / 2
		end
	else
		if (self:GetIronsights() == true) then
			self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil / 6, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Put recoil / 4 when you're in ironsight mod

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * (self.Primary.Recoil / 2), math.Rand(-1,1) * (self.Primary.Recoil / 2), 0))
			-- Punch the screen 2x less hard when you're in ironsigh mod
		else
			self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil, self.data[self.mode].NumShots, self.data[self.mode].Cone)
			-- Put normal recoil when you're not in ironsight mod

			self.Owner:ViewPunch(Angle(math.Rand(-0.5,-2.5) * self.Primary.Recoil, math.Rand(-1,1) *self.Primary.Recoil, 0))
			-- Punch the screen
		end
	end
end

/*---------------------------------------------------------
ShootBullet
---------------------------------------------------------*/
function SWEP:CSShootBullet(dmg, recoil, numbul, cone)

	numbul 		= numbul or 1
	cone 			= cone or 0.01

	local bullet 	= {}
	bullet.Num  	= numbul
	bullet.Src 		= self.Owner:GetShootPos()       					-- Source
	bullet.Dir 		= self.Owner:GetAimVector()      					-- Dir of bullet
	bullet.Spread 	= Vector(cone, cone, 0)     						-- Aim Cone
	bullet.Tracer 	= 1       									-- Show a tracer on every x bullets
	bullet.Force 	= 2000  								-- Amount of force to give to phys objects
	bullet.Damage 	= 20										-- Amount of damage to give to the bullets
	bullet.Callback 	= HitImpact
-- 	bullet.Callback	= function ( a, b, c ) BulletPenetration( 0, a, b, c ) end 	-- CALL THE FUNCTION BULLETPENETRATION

	self.Owner:FireBullets(bullet)					-- Fire the bullets
	self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)      	-- View model animation
	self.Owner:MuzzleFlash()        					-- Crappy muzzle light
	self.Owner:SetAnimation(PLAYER_ATTACK1)       			-- 3rd Person Animation

	local fx 		= EffectData()
	fx:SetEntity(self.Weapon)
	fx:SetOrigin(self.Owner:GetShootPos())
	fx:SetNormal(self.Owner:GetAimVector())
	fx:SetAttachment(self.MuzzleAttachment)
	util.Effect(self.MuzzleEffect,fx)					-- Additional muzzle effects
	
	timer.Simple( self.EjectDelay, function()
		if  not IsFirstTimePredicted() then 
			return
		end

			local fx 	= EffectData()
			fx:SetEntity(self.Weapon)
			fx:SetNormal(self.Owner:GetAimVector())
			fx:SetAttachment(self.ShellEjectAttachment)

			util.Effect(self.ShellEffect,fx)				-- Shell ejection
	end)

	if ((game.SinglePlayer() and SERVER) or (not game.SinglePlayer() and CLIENT)) then
		local eyeang = self.Owner:EyeAngles()
		eyeang.pitch = eyeang.pitch - recoil
		self.Owner:SetEyeAngles(eyeang)
	end

 	local trace = self.Owner:GetEyeTrace();

	if trace.HitPos:Distance(self.Owner:GetShootPos()) > 250 or self.DestroyDoor == 0 then return end

	if trace.Entity:GetClass() == "prop_door_rotating" and self.mode == "burst" and (SERVER) then

		trace.Entity:Fire("open", "", 0.001)
		trace.Entity:Fire("unlock", "", 0.001)

		local pos = trace.Entity:GetPos()
		local ang = trace.Entity:GetAngles()
		local model = trace.Entity:GetModel()
		local skin = trace.Entity:GetSkin()

		local smoke = EffectData()
			smoke:SetOrigin(pos)
			util.Effect("effect_smokedoor", smoke)

		trace.Entity:SetNotSolid(true)
		trace.Entity:SetNoDraw(true)

		local function ResetDoor(door, fakedoor)
			door:SetNotSolid(false)
			door:SetNoDraw(false)
			fakedoor:Remove()
		end

		local norm = (pos - self.Owner:GetPos())
		norm:Normalize()
		local push = 1000 * norm
		local ent = ents.Create("prop_physics")

		ent:SetPos(pos)
		ent:SetAngles(ang)
		ent:SetModel(model)

		if(skin) then
			ent:SetSkin(skin)
		end

		ent:Spawn()

		timer.Simple(0.01, function() if ent and push then ent:GetPhysicsObject():SetVelocity(push) end end)              
		timer.Simple(0.01, function() if ent and push then ent:GetPhysicsObject():SetVelocity(push) end end)
		timer.Simple(25, function() ResetDoor( trace.Entity, ent, 10) end )
	end
end

Using notepad++ I looked at each error, but is there even anything I can do to fix it without breaking the swep?

Line 417 -


self.Owner:MuzzleFlash()        					-- Crappy muzzle light

Line 358 -


self:CSShootBullet(self.data[self.mode].Damage, self.Primary.Recoil * 1.5, self.data[self.mode].NumShots, self.data[self.mode].Cone)

Line 180 -


self:RecoilPower()

MuzzleFlash has to go in ShootEffects.

Ah, thank you.

So this should work if I replace it at line 417? Will this make the other two errors go away?


function SWEP:ShootEffects()

	self.Owner:MuzzleFlash() -- Crappy muzzle light
end

You can’t have a function inside a function like that :v:

Can I just remove this part of the script to fix it? The flash isn’t that important, I’d rather have no errors.

What about the other two errors. Would removing the recoil one mess the swep up?

I guess, but it would be easier to just put the function with the muzzleflash in the correct place; outside of all functions.

Also, the others aren’t errors. It’s called a stackwalk.

Here’s how I do it:

I put it into ShootEffects, but I pass in 2 additional arguments from PrimaryAttack which uses a helper-function to grab muzzle which is either “muzzle” or “1 or 2”

[lua]function SWEP:ShootEffects( muzzle, ejectionPort )
if ( !muzzle ) then return; end

if ( CLIENT ) then
	local recoil = math.Rand( 0.5, 1.5 );
	local _eyes = self.Owner:EyeAngles()
	_eyes.pitch = math.Clamp( _eyes.pitch - recoil, -90, 90 )
	self.Owner:SetEyeAngles( self.Owner:EyeAngles() - Angle( math.Clamp( recoil, -90, 90 ), 0, 0 ) )
end

local effectdata = EffectData( );
effectdata:SetOrigin( self.Owner:GetShootPos( ) );
effectdata:SetEntity( self ); // self is the same as self.Weapon, but self.Weapon is deprecated
effectdata:SetStart( self.Owner:GetShootPos( ) );
effectdata:SetNormal( self.Owner:GetAimVector( ) );
effectdata:SetAttachment( 1 );

timer.Simple( 0, function( )
	if ( !self.Owner ) then return end
	if ( !IsFirstTimePredicted( ) ) then return; end
	util.Effect( "gunsmoke", effectdata );
end );

end[/lua]