local GUN = GUN_Troops
--#=================================================#
--Stealing SA-Sonic's formatting, I'll store all seperate GUN robot functions here for easy redirecting.
--Use CTRL+F and you should find what you're looking for. I placed quote comments since I'm used to finding functions like that.
--Do note I'm use sub functions this time rather than rawsets. In your mod, you MUST check if the GUN_Troops table is valid first!
--#=================================================#

--You can give characters a higher power than usual. Otherwise, it'll go by default.
if not (GUNpowertable) rawset(_G, "GUNpowertable", {}) end
GUNpowertable["sms"] = 1

--How powerful is our enemy?  "GUN.TargetPower"
GUN.TargetPower = function(t)
	if not (t and t.valid) return 0 end
	if not t.player
		return (t.GUNpower) and t.GUNpower or (t.flags & MF_BOSS) and 1 or 0
	end	
	local p = t.player
	local ADD = p.hypermysticsonic and FRACUNIT*3333 or GUNpowertable[t.skin] or 0
	if p.powers[pw_super] or (p.solchar and p.solstar.istransformed)
		return 2+ADD --Extreme danger!
	elseif p.powers[pw_invulnerability] or p.mysticsuper
		return 1+ADD --High alert!
	end 
	return 0+ADD --
end

--We're doing a death animation?!
GUN.HunterDeathAnim = function(s)
if s.health return false end	
local yu = s.GUN_HunterTable
	if yu.deathanim
		yu.deathanim = $-1
		s.flags = $|MF_BOUNCE|MF_NOCLIPTHING|MF_NOBLOCKMAP & ~(MF_NOCLIP|MF_NOCLIPHEIGHT) --Bounce off walls when dying.
		s.tics = 8 s.anim_duration = 8
		if (yu.deathanim % 2)
			s.spritexoffset = GUN.RNG(FRACUNIT, 7*FRACUNIT, s)
			s.spriteyoffset = GUN.RNG(-FRACUNIT, 3*FRACUNIT, s)	
		else
			s.spritexoffset = $*-1
			s.spriteyoffset = 0		
		end
		if (yu.deathanim < 5)
			if ((s.frame & FF_FRAMEMASK) < H)
				s.frame = $+1
			end
			s.spritexscale = min(FRACUNIT*3, $+7999)
			s.spriteyscale = min(FRACUNIT*3, $+7999)
			if yu.deathanim == 3
				GUN.SA2Explosion(s)
				local SfX = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK) --Death sound.
				SfX.flags2 = MF2_DONTDRAW SfX.tics = 99
				S_StartSound(SfX, sfx_yuedth)
			end
		elseif (yu.deathanim % 5 == 0) 
			A_BossScream(s,0,MT_SONIC3KBOSSEXPLODE)
			if (yu.deathanim % 10 == 0) 
				GUN.SA2Explosion(s)
				if ((s.frame & FF_FRAMEMASK) < H)
					s.frame = $+1
				end			
			end
			if (yu.deathanim < 16) and ((s.frame & FF_TRANSMASK) < FF_TRANS80)
				s.frame = $+(FRACUNIT*2)
			end
		end	
	end return true --
end

--Returns knockback force if we've taken any knockback"
GUN.KnockBack = function(s, DIV)
	local yu = s.GUN_HunterTable
	if yu.forceANG == nil return 0 end  --
	
	local RETURNFORCE = 0
	DIV = (DIV) or 21
	
	--Shoved horizontally?
	if yu.forceXY
		if (abs(yu.forceXY) < 2*s.scale)
		or not P_TryMove(s, s.x+FixedMul(yu.forceXY, cos(yu.forceANG)), s.y+FixedMul(yu.forceXY, sin(yu.forceANG)), true)
			yu.forceXY = 0
			if (abs(s.momz) < 5*s.scale)
				GUN.SpawnDust(s, nil, nil, true)
				GUN.SpawnDust(s)
			end		
		else
			RETURNFORCE = $+abs(yu.forceXY)
			yu.forceXY = FixedDiv(FixedMul($,20),DIV) --Diminish force over time.
		end
	end
	if yu.forceZ --Be slammed into the air?
		if (s.momz*P_MobjFlip(s) < 0)
		or (abs(yu.forceZ) < s.scale)
			yu.forceZ = 0
		else
			if P_IsObjectOnGround(s)
				s.z = $+s.scale*P_MobjFlip(s)
			end
			s.momz = yu.forceZ
			RETURNFORCE = $+abs(yu.forceZ)
			yu.forceZ = FixedDiv(FixedMul($,22),DIV+2)
		end
	end
	return RETURNFORCE --
end

--Drop your shield if you're low and got one.
GUN.DropShield = function(s, FORCEANG, FORCE)
	if s.GUNshield
		if s.GUNshield.valid
			local ghs = GUN.CraterSpew(s, ANGLE, RANGE)
			if ghs and ghs.valid
				P_Thrust(ghs, (FORCEANG) or s.angle, (FORCE) and FORCE or -33*s.scale)
				ghs.sprite = SPR_G1SH
				ghs.frame = A
				ghs.rollangle = GUN.RNG(-50,50, s)
				ghs.color = s.GUNshield.color
				ghs.colorized = s.GUNshield.colorized
				S_StartSound(ghs, sfx_ghsfxl) --boing
			end
			s.GUNshield.state = S_NULL
		end
		s.GUNshield = nil return true --
	end return false --
end

--Is this object (t) within your cone of vision?
--Will check for hearing if vision fails, the number determines the range. HEARING MUST be a number value.
GUN.CanDetect = function(s, t, CONE, HEARING)
	if CONE == 360
		return true --Always return true if the cone is 360!
	elseif not CONE or ((GUN.AngleDifference(s.angle, R_PointToAngle2(s.x, s.y, t.x, t.y), 2)) <= CONE)
		return (P_CheckSight(s,t)) and true or false
	end
	if not HEARING return false end --
	
	if (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < HEARING)
		if not t.player
			if ((netgame) == true) or S_OriginPlaying(t) 
				return (P_CheckSight(s,t)) and true or false --Non-players can't sneak.
			end
		end

		local p = t.player --You can slowly sneak past if you're careful. 
		--I can't actually check if the player's making sounds because that would desync.
		if P_IsObjectOnGround(t)
		and ((p.panim != PA_WALK) and (p.panim != PA_IDLE) and not (p.pflags & PF_SPINNING) or (p.speed > 34*s.scale) or p.skidtime)
		
		or (p.pflags & (PF_STARTDASH|PF_THOKKED|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY))
		
		or (p.pflags & PF_STARTJUMP) and (p.cmd.buttons & BT_JUMP) and (t.momz*P_MobjFlip(t) > 0)
		
		or (s.eflags & (MFE_JUSTHITFLOOR|MFE_TOUCHWATER|MFE_TOUCHLAVA|MFE_SPRUNG))
			
		or ((netgame) != true) and S_OriginPlaying(t) --NEVER check for sounds in netgames, that shit's local.		
			return (CONE == 360) and true or (P_CheckSight(s,t)) and true or false --
		end
	end return false --Nothing found!
end

--Reflection!
GUN.Reflect = function(s, v, COLOR)
	local SPEED = abs(s.momx)+abs(s.momy)+abs(s.momz/3)
	local ANGLE = R_PointToAngle2(s.x, s.y, s.x+s.momy, s.y+s.momy) or s.angle
	S_StartSound(v, sfx_corkh)
	S_StartSound(s, sfx_corkh)
	
	--Recoil on the player.
	if (v.momz*P_MobjFlip(v) < 0)
		v.momz = $-1
	end
	P_SetObjectMomZ(v, 6*FRACUNIT + min(12*FRACUNIT, SPEED/12), true) --Momentum! ...plus some guaranteed height.
	P_Thrust(v, ANGLE+ANGLE_180, min(25*FRACUNIT, SPEED/6))
	GUN.CircleWave(s, 1, (COLOR) or SKINCOLOR_ROSY)
	if v.player
		v.player.pflags = $ & ~PF_THOKKED
	end
	
	--Now reflect the projectile in the direction you're looking.
	P_InstaThrust(s, v.angle, SPEED+(24*v.scale))
	if (s.momz > 0) and s.target and s.target.valid and (s.target.z < v.z)
		s.momz = $/4
	elseif s.momz
		s.momz = $*-1
	end
	
	s.target = v --DONE!
end

--Lob a grenade that'll do the kaboom.
GUN.HunterGrenade = function(s, t, BEETLE)
	if BEETLE
		local SHOT = P_SpawnMissile(s, t, MT_GUNHUNTER_GRENADE)
		if not (SHOT and SHOT.valid) return end  --Drop straight down.
		SHOT.momx = s.momx
		SHOT.momy = s.momy
		SHOT.momz = s.momz*-1
		SHOT.dispoffset = -2
	else
		A_LobShot(s, MT_GUNHUNTER_GRENADE, 96)
		S_StartSound(s, (leveltime % 2) and sfx_ghsfx5 or sfx_ghsfx8) --5 is the default laser fire!
	end

	--Flash heavily red!
	local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_GUNOVERLAY)
	ghs.tracer = s
	ghs.frame = FF_TRANS30
	ghs.renderflags = RF_FULLBRIGHT
	ghs.blendmode = AST_ADD
	ghs.fusefade,ghs.fuse = 8,8
	ghs.colorized = true
	ghs.color = SKINCOLOR_CRIMSON
	ghs.copyframe = true
	GUN.OverLayThink(ghs)
	
	if BEETLE return end --
	
	local SHOTANGLE = s.angle-(ANG20*2)
	
	--Shooting GFX.
	local ghs = GUN.CircleWave(s, 1, SKINCOLOR_RED, 9, FRACUNIT/3)
	P_SetOrigin(ghs, s.x+FixedMul(54*s.scale, cos(SHOTANGLE)), s.y+FixedMul(54*s.scale, sin(SHOTANGLE)), ghs.z)
	ghs.frame = Z+4|FF_TRANS20
	ghs.colorized = true
	ghs.GSoffsetX = 54*s.scale
	ghs.GSoffsetY = 54*s.scale
	ghs.GSoffsetZ = 57*s.scale
	ghs.sttfade = 6
	ghs.scalespeed = $*2
	ghs.ditchtracer = nil
	ghs.GSoffsetang = s.angle-(ANG20*2)
	ghs.GSoffsetangFACE = false --Keep facing us.
	
	GUN.QuickDust(s, SKINCOLOR_GOLDENROD, AST_ADD, 20*FRACUNIT)
end

--Shoot the GUN Hunter's basic laser!
GUN.HunterLaser = function(s, t, BEETLE)
	local SHOT
	local SHOTANGLE = s.angle-(ANG20*2)
	for i = 1,4 --Try 4 seperate times to shoot missile from slightly different positions, incase it clips in a wall immediately.
		if i == 4 or BEETLE --Least preferred missile type.
			SHOT = P_SpawnMissile(s, t, MT_GUNHUNTER_LASER) i=4
		else
			SHOT = P_SpawnXYZMissile(s, t, MT_GUNHUNTER_LASER, 
			s.x+FixedMul(54*s.scale/i, cos(SHOTANGLE)),
			s.y+FixedMul(54*s.scale/i, sin(SHOTANGLE)), 
			s.z+ (s.height/2) )
		end
		if (SHOT and SHOT.valid) --Okay, so we DID manage!
			if s.GUN_HunterTable and s.GUN_HunterTable.weapon == 2 --Temporary sniper code.
				S_StartSound(s, sfx_ghsfx8)
				local DIST = FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z)
				local MULT = 2
				if (DIST >= 1000*FRACUNIT) --The further away you are, the faster this shot goes!
					MULT = $+min(15, FixedInt(DIST/500)-2)
					MULT = max($,3)
				end
				if t.player
					local p = t.player
					if (p.panim >= PA_ABILITY)
					and not P_IsObjectOnGround(s)
						if p.powers[pw_tailsfly] 
						or (p.pflags & (PF_GLIDING|PF_THOKKED)) and p.glidetime
						or p.climbing
							if not P_IsObjectOnGround(s)
								MULT = $+11
								SHOT.scale = $*3
								SHOT.height = $+30*FRACUNIT
							end
						end
					end
				end
				if (MULT > 8)
					SHOT.flags2 = $|MF2_EXPLOSION
				end
				SHOT.momx = $*MULT
				SHOT.momy = $*MULT
				SHOT.momz = $*MULT
				if (SHOT.momz < 0) and (SHOT.momz >= -6*FRACUNIT)
					SHOT.momz = $+(FRACUNIT)
				end
				SHOT.scale = $*2
				SHOT.color = SKINCOLOR_RED
				SHOT.snipershot = true
				S_StartSound(SHOT, sfx_gravch)
				S_StartSound(SHOT, sfx_rail1)
				S_StartSound(SHOT, sfx_rail2)
				S_StartSound(SHOT, sfx_s3k57)
				GUN.CircleWave(SHOT, 1, SKINCOLOR_PURPLE, 31, FRACUNIT)
				local ghs = GUN.LightFlash(SHOT, SKINCOLOR_RED, 22)
				ghs.tracer = SHOT
				ghs.spriteyoffset = $-11*FRACUNIT
				
				local ghs = GUN.ElectricBody(SHOT, 50, SKINCOLOR_CRIMSON)	
				ghs.tracer = SHOT
				ghs.blendmode = AST_SUBTRACT
				ghs.colorized = true
				ghs.spriteyoffset = $-4*FRACUNIT
			end
			S_StartSound(s, (leveltime % 2) and sfx_ghsfx5 or sfx_ghsfx8) --5 is the default laser fire!

			--Flash white for a second!
			local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_GUNOVERLAY)
			ghs.tracer = s
			ghs.frame = FF_TRANS70
			ghs.renderflags = RF_FULLBRIGHT
			ghs.blendmode = AST_ADD
			ghs.fusefade,ghs.fuse = (BEETLE) and 8 or 4, (BEETLE) and 8 or 4
			ghs.colorized = true
			ghs.color = SKINCOLOR_SUPERGOLD1
			ghs.copyframe = true
			GUN.OverLayThink(ghs)
			
			if BEETLE --Stop early for beetle variants.
				local ths = GUN.LightFlash(s, SKINCOLOR_EMERALD, 13)	
				ths.frame = $+(FRACUNIT*2)
				ths.scalespeed = FRACUNIT/2
				ths.tracer = ghs
				ths.GSoffsetX = 30*s.scale
				ths.GSoffsetY = 30*s.scale
				ths.GSoffsetZ = s.height/3
				ths.sttYspeed = -47000
				return SHOT --
			end
			
			--Shooting GFX.
			local ghs = GUN.CircleWave(s, 1, SKINCOLOR_GOLDENROD, 18, FRACUNIT+12000)
			P_SetOrigin(ghs, s.x+FixedMul(54*s.scale, cos(SHOTANGLE)), s.y+FixedMul(54*s.scale, sin(SHOTANGLE)), ghs.z)
			ghs.GSoffsetX = 54*s.scale
			ghs.GSoffsetY = 54*s.scale
			ghs.GSoffsetZ = 57*s.scale
			ghs.sttfade = 18
			ghs.frame = $+FRACUNIT
			ghs.ditchtracer = nil
			ghs.GSoffsetang = s.angle-(ANG20*2)
			ghs.GSoffsetangFACE = false --Keep facing us.
						
			local ths = GUN.LightFlash(s, SKINCOLOR_RED, 14, nil, -11*FRACUNIT)	
			ths.frame = $+(FRACUNIT*2)
			ths.scalespeed = FRACUNIT/2
			ths.tracer = ghs
			P_SetOrigin(ths, ghs.x, ghs.y, ghs.z)
			ths.sttYspeed = -47000
			
			local ghs,ths = GUN.QuickDust(s, SKINCOLOR_BEIGE, nil, 25*FRACUNIT)
			if ghs and ghs.valid and ths and ths.valid
				ghs.frame = $ & ~FF_TRANSMASK
				ths.frame = $ & ~FF_TRANSMASK
				ths.z = s.z
				ghs.z = s.z
				ghs.dispoffset = -2
				ths.dispoffset = -2
				P_Thrust(ghs, s.angle, -3*s.scale)
				P_Thrust(ths, s.angle, -3*s.scale)
			end
			return SHOT --Success!
		end
	end return --
end

--Look for a target intelligently! All arguments besides "s" are optional.
--DIST is how far we can see. Defaults to 1500 FRACUNITs.

--SEARCHTYPE determines who we'll be looking for.
--0 = Players only.(default)
--1 = Enemies only. 
--2 = Both, with a bias for targeting players if found alongside an enemy.
--3 = Both, targeting whatever is most convenient.
--4 = Both, with a bias for targeting enemies if found alongside a player. 

--CONE decides how wide your vision radius is. Will look all around if no cone is set.
--HEARING adds a hearing radius. Will be deaf if no radius is set.
--PREF when set to 1 selects the closest target if multiple were found. If set to 2, then the furthest! Selects whatever otherwise.

GUN.SearchTarget = function(s, DIST, SEARCHTYPE, CONE, HEARING, PREF)

	DIST = (DIST) or 1500*s.scale
	local PREFMOBJ,LASTDIST
	local CURRENT = 8000*FRACUNIT
	local CLOSEST = 8000*FRACUNIT	
	
		--Search for players!	
		if SEARCHTYPE != 1		
			for z in players.iterate
				if z.mo and z.mo.health
				local m = z.mo
				CURRENT = FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)					
					if (CURRENT < CLOSEST)
						CLOSEST = CURRENT --Keep check of what the closest foe was.
					end
					
					if (CURRENT < DIST)
					and GUN.CanDetect(s, z.mo, CONE, HEARING)
						if not PREF
							return m,CURRENT --First guy we see, ATTACK!
						elseif not LASTDIST
						or (PREF == 1) and (CURRENT < LASTDIST) --PREF 1 looks for closest guy!
						or (PREF == 2) and (CURRENT > LASTDIST)	--PREF 2 looks for furthest guy!		
							PREFMOBJ = m LASTDIST = CURRENT					
						end
					end
				end
			end		
		end		
		if PREFMOBJ and (SEARCHTYPE < 3) and PREFMOBJ.valid
			return PREFMOBJ,LASTDIST --Unless searchtype is 3/4, lets not bother with the blockmap search if we found a player.
		end
		
		--Look for enemies as well?
		if SEARCHTYPE
			if (SEARCHTYPE == 4) LASTDIST = nil end --Create a sudden bias for enemies!
			
			searchBlockmap("objects",function(s,m)
				if (m.flags & (MF_ENEMY|MF_BOSS))
				and (m.flags & MF_SHOOTABLE)
				and m.health 
				and not m.GUNally --Don't shoot allies!
				CURRENT = FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)
					if (CURRENT < CLOSEST)
						CLOSEST = CURRENT
					end
					if (CURRENT < DIST)
					and GUN.CanDetect(s, m, CONE, HEARING)
						if not PREF
							return m,CURRENT --Attack first enemy!
						elseif not LASTDIST
						or (PREF == 1) and (CURRENT < LASTDIST)
						or (PREF == 2) and (CURRENT > LASTDIST)
							PREFMOBJ = z.mo 
							LASTDIST = CURRENT		
						end
					end
				end
			end,s, s.x-DIST,s.x+DIST, s.y-DIST,s.y+DIST)
		end
		if PREFMOBJ and PREFMOBJ.valid
			return PREFMOBJ,LASTDIST --Halt! You're under arrest!
		end
		return nil,CLOSEST --return whatever our closest found mobj was, so we know what to look for next.
end

--Gradually turn towards your target or at a manual angle. Return the amount we've turned.
GUN.GradualTurn = function(s, t, MAXTURN, MANUAL)
	if (MANUAL == nil) and not (t and t.valid) return end --
	MAXTURN = (MAXTURN) or ANG10
	
	local destANGLE = (MANUAL) or (t and t.valid) and R_PointToAngle2(s.x, s.y, t.x, t.y) or s.angle
	local ANGLE,PLUS = GUN.AngleDifference(s.angle, destANGLE, 2, MAXTURN)
	if (ANGLE > ANGLE_135) PLUS = $*3 end	
	s.angle = $-(ANGLE*PLUS)
	return ANGLE,PLUS --
end

--How far are we from the floor? INVERT checks the other way around.
GUN.GroundZDiff = function(s, INVERT)
	if P_IsObjectOnGround(s) return 0 end --Duh, you're on the ground...
	local FLIPPED = ((s.eflags & MFE_VERTICALFLIP) or (s.flags2 & MF2_OBJECTFLIP)) and -1 or 1
	if (INVERT) FLIPPED = $*-1 end
	local secT = s.subsector and s.subsector.sector
	if secT
		if FLIPPED
			return abs(s.z-secT.ceilingheight) --
		else
			return abs(s.z-secT.floorheight) --
		end
	end return 0 --
end

--How big is the difference from one angle to another? This function returns the answer!
GUN.AngleDifference = function(ANG_1, ANG_2, Rformat, maxANG, divide)
	local diff = (ANG_1-ANG_2)
	if not diff return 0,1 end --The result's 0. ...that was easy.	
	
	diff = (diff > ANGLE_180) and InvAngle(InvAngle(diff)/((divide) or 1)) or diff/((divide) or 1)	
	
	--This function NEVER gives negative results. 
	--ANGLE_270 or -ANGLE_90 for example would return as ANGLE_90, with PLUS simply becoming -1.
	local PLUS = (diff < 0) and -1 or 1
	if diff < 0 diff = InvAngle(diff) end
	
	if maxANG --Return a maximum value?
		diff = min(maxANG, diff)
	end
	if Rformat != 2
		if Rformat == 1 --Turns the result into FRACUNITs. From 0 to 180*FRACUNIT
			diff = AngleFixed(diff)
		elseif Rformat == 0 --Turns result into regular numbers. From 0 to 180.
			diff = (diff >= ANG1) and diff/ANG1 or 0
		end
	end
	return diff, PLUS --
end


--Auto-calculates proper gravity offsets for effects. "GUN.FlipZ" 
--s = Object to check for.
--ghs = the effect mobj we're flipping.
GUN.FlipZ = function(s, ghs)
	if not (s.eflags & MFE_VERTICALFLIP)
		ghs.eflags = $ & ~MFE_VERTICALFLIP
		return ghs.z --remain the same.
	else
		ghs.eflags = $|MFE_VERTICALFLIP
		return s.z+s.height-FixedMul(ghs.height, s.scale)
	end
end

--SMS-stolen RNG function. Doesn't cause desyncs like when you spam P_RandomRange.
--This has the limitation of giving the same result if you give it the same input on the same frame.
--It also requires a reference mobj to work! That's what s is.  "GUN.RNG"
GUN.RNG = function(a, b, s)
	local smsRNGseed = (leveltime % 3 == 0) and 15228646 or (leveltime % 2 == 0) and 2327299421 or 313512858
	
	smsRNGseed = $*(max(gamemap+leveltime,1) % 128) - (s.x-s.z) + (s.momy-s.frame+s.type) + (s.player and s.player.jointime*2 or 5)
	smsRNGseed = ($) and $/3 or 1626124580
	local final = ((smsRNGseed*36548569) >> 4) & (FRACUNIT-1)	
	return ((final * (b-a+1)) >> FRACBITS) + a
end

--Create a quake for any nearby players. DIST is optional. "GUN_Quake"
GUN.Quake = function(m, intensity, tics, DIST)
	if displayplayer and displayplayer.mo and m
		local s = displayplayer.mo
		DIST = (DIST) or 512*FRACUNIT
		if ( (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)) <= DIST)
			P_StartQuake(intensity, tics)
		end
	end
end

--Create a flash for any nearby players. DIST is optional. "GUN.Flash"
GUN.Flash = function(s, pal, tics, DIST)
	if displayplayer and displayplayer.mo and s
		local m = displayplayer.mo
		DIST = (DIST) or 512*FRACUNIT
		if ( (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)) <= DIST)
			P_FlashPal(displayplayer, pal, tics)
		end
	end
end

--For animations. Insert how many frames you want, and there you go. If it's 8 frames, insert 8, not 7. "GUN.TimeFrame"
GUN.TimeFrame = function(no)
	for i = no,0,-1
		if leveltime % max(i,1) == 0 return i end --
	end
end

