Roblox/luau_corpus huggingface dataset:
--- Registers a command based purely on its definition.
-- Prefer using Registry:RegisterCommand for proper handling of server/client model.
function Registry:RegisterCommandObject (commandObject, fromCmdr)
	for key in pairs(commandObject) do
		if self.CommandMethods[key] == nil then
			error("Unknown key/method in command " .. (commandObject.Name or "unknown command") .. ": " .. key)
		end
	end

	if commandObject.Args then
		for i, arg in pairs(commandObject.Args) do
			if type(arg) == "table" then
				for key in pairs(arg) do
					if self.CommandArgProps[key] == nil then
						error(('Unknown property in command "%s" argument #%d: %s'):format(commandObject.Name or "unknown", i, key))
					end
				end
			end
		end
	end

	if commandObject.AutoExec and RunService:IsClient() then
		table.insert(self.AutoExecBuffer, commandObject.AutoExec)
		self:FlushAutoExecBufferDeferred()
	end

	-- Unregister the old command if it exists...
	local oldCommand = self.Commands[commandObject.Name:lower()]
	if oldCommand and oldCommand.Aliases then
		for _, alias in pairs(oldCommand.Aliases) do
			self.Commands[alias:lower()] = nil
		end
	elseif not oldCommand then
		table.insert(self.CommandsArray, commandObject)
	end

	self.Commands[commandObject.Name:lower()] = commandObject

	if commandObject.Aliases then
		for _, alias in pairs(commandObject.Aliases) do
			self.Commands[alias:lower()] = commandObject
		end
	end
end
--[=[
	Requires all the modules that are children of the given parent. This is an easy
	way to quickly load all services that might be in a folder.
	```lua
	Knit.AddServices(somewhere.Services)
	```
]=]
function KnitServer.AddServices(parent: Instance): {Service}
	local addedServices = {}
	for _,v in ipairs(parent:GetChildren()) do
		if not v:IsA("ModuleScript") then continue end
		table.insert(addedServices, require(v))
	end
	return addedServices
end
--[[
	
	CameraShakePresets.Bump
	CameraShakePresets.Explosion
	CameraShakePresets.Earthquake
	CameraShakePresets.BadTrip
	CameraShakePresets.HandheldCamera
	CameraShakePresets.Vibration
	CameraShakePresets.RoughDriving
	
--]]



local CameraShakeInstance = require(script.Parent.CameraShakeInstance)

local CameraShakePresets = {
	
	
	-- A high-magnitude, short, yet smooth shake.
	-- Should happen once.
	Bump = function()
		local c = CameraShakeInstance.new(2.5, 4, 0.1, 0.75)
		c.PositionInfluence = Vector3.new(0.15, 0.15, 0.15)
		c.RotationInfluence = Vector3.new(1, 1, 1)
		return c
	end;
	
	
	-- An intense and rough shake.
	-- Should happen once.
	Explosion = function()
		local c = CameraShakeInstance.new(5, 10, 0, 1.5)
		c.PositionInfluence = Vector3.new(0.25, 0.25, 0.25)
		c.RotationInfluence = Vector3.new(4, 1, 1)
		return c
	end;
	
	
	-- A continuous, rough shake
	-- Sustained.
	Earthquake = function()
		local c = CameraShakeInstance.new(0.6, 3.5, 2, 10)
		c.PositionInfluence = Vector3.new(0.25, 0.25, 0.25)
		c.RotationInfluence = Vector3.new(1, 1, 4)
		return c
	end;
	
	
	-- A bizarre shake with a very high magnitude and low roughness.
	-- Sustained.
	BadTrip = function()
		local c = CameraShakeInstance.new(10, 0.15, 5, 10)
		c.PositionInfluence = Vector3.new(0, 0, 0.15)
		c.RotationInfluence = Vector3.new(2, 1, 4)
		return c
	end;
	
	
	-- A subtle, slow shake.
	-- Sustained.
	HandheldCamera = function()
		local c = CameraShakeInstance.new(.5, 1, 4, 4)
		c.PositionInfluence = Vector3.new(2,0,0)
		c.RotationInfluence = Vector3.new(1.25,0,0)
		return c
	end;
	
	
	-- A very rough, yet low magnitude shake.
	-- Sustained.
	Vibration = function()
		local c = CameraShakeInstance.new(0.4, 20, 2, 2)
		c.PositionInfluence = Vector3.new(0, 0.15, 0)
		c.RotationInfluence = Vector3.new(1.25, 0, 4)
		return c
	end;
	
	
	-- A slightly rough, medium magnitude shake.
	-- Sustained.
	RoughDriving = function()
		local c = CameraShakeInstance.new(1, 2, 1, 1)
		c.PositionInfluence = Vector3.new(0, 0, 0)
		c.RotationInfluence = Vector3.new(1, 1, 1)
		return c
	end;
	
	
}


return setmetatable({}, {
	__index = function(t, i)
		local f = CameraShakePresets[i]
		if (type(f) == "function") then
			return f()
		end
		error("No preset found with index \"" .. i .. "\"")
	end;
})
----------do not edit anything below this line
local function createMessageOnClient(msg)
	game.StarterGui:SetCore("ChatMakeSystemMessage", {
		Text = msg;
		Font = Enum.Font.Arcade;
		Color = sm;
		FontSize = Enum.FontSize.Size18;
	})
end

if welcomeMessageOn then
	createMessageOnClient(welcomeMessage)
end

if displayJoinMessage then
	createMessageOnClient(game:GetService("Players").LocalPlayer.Name..joinMessage)
	game:GetService('Players').PlayerAdded:Connect(function(plr)
		createMessageOnClient(plr.Name..joinMessage)
	end)
end

if displayLeaveMessage then
	game:GetService('Players').PlayerRemoving:Connect(function(plr)
		createMessageOnClient(plr.Name..leftMessage)
	end)
end
--Remove Existing Mass
function DReduce(p)
	for i,v in pairs(p:GetChildren())do
		if v:IsA("BasePart") then
			if v.CustomPhysicalProperties == nil then v.CustomPhysicalProperties = PhysicalProperties.new(v.Material) end
			v.CustomPhysicalProperties = PhysicalProperties.new(
				0,
				v.CustomPhysicalProperties.Friction,
				v.CustomPhysicalProperties.Elasticity,
				v.CustomPhysicalProperties.FrictionWeight,
				v.CustomPhysicalProperties.ElasticityWeight
			)
		end
		DReduce(v)
	end
end
DReduce(bike)
-- Global matchers object holds the list of available matchers and
-- the state, that can hold matcher specific values that change over time.
local JEST_MATCHERS_OBJECT = Symbol.for_("$$jest-matchers-object")
-- Adjust the movement of the firefly, allowing them to roam around.

local Fly = script.Parent

while true do -- Alter the flies movement direction every once a while to make it roam around
	Fly.BodyVelocity.velocity = Vector3.new(math.random(-20,20)*0.1,math.random(-20,20)*0.1,math.random(-20,20)*0.1)
	wait(math.random(10,25)*0.1)
end
--// Holstering
	HolsteringEnabled = false;
	HolsterPos = CFrame.new(0.140751064, 0, -0.616261482, -4.10752676e-08, -0.342020065, 0.939692616, -1.49501727e-08, 0.939692557, 0.342020094, -0.99999994, 0, -4.37113847e-08);

	}

return Settings
-- Edit stuff here

DATA_STORE 		= "TopCoins" --< Name of the Data store values will be saved in

SCORE_UPDATE 	= 30 --< How often you want the leaderboards to update in seconds (no less than 30)

PLAYER_UPDATE 	= 30 --< How often you want the player's current stat to save in seconds (no less than 30)

PLAYER_SAVE 	= "leaderstats" --< Do not change unless you are using something that is not leaderstats

NAME_OF_STAT 	= "Coins" --< Name of the stat you want to save (HAS to be inside 'leaderstats' or whatever PLAYER_SAVE is)
-- Tween

local tween = game:GetService("TweenService")
local info = TweenInfo.new(
	3,
	Enum.EasingStyle.Linear,
	Enum.EasingDirection.InOut,
	0,
	false,
	0
)

local abrindo = {
	CFrame = cf1.CFrame
}

local fechando = {
    CFrame = doorpos
}

local create1 = tween:Create(portao,info,abrindo)
local create2 = tween:Create(portao,info,fechando)
------------------------------------------------------------------
local AimingCursor = "http://www.roblox.com/asset/?id=107455536"
local LockedCursor = "http://www.roblox.com/asset/?id=107455986"
local TargetCursor = "http://www.roblox.com/asset/?id=107455960"
local NormalCursor = "http://www.roblox.com/asset/?id=116176885"
--[[Transmission]]
	Tune.TransModes		= {"Auto", "Semi", "Manual"}								--[[
	[Modes]
		"Auto"		: Automatic shifting
		"Semi"		: Clutchless manual shifting, dual clutch transmission
		"Manual"	: Manual shifting with clutch
		
		>Include within brackets
			eg: {"Semi"} or {"Auto", "Manual"}								
		>First mode is default mode													]]
	
	--Automatic Settings
	Tune.AutoShiftMode	= "Speed"												--[[
	[Modes]
		"Speed"		: Shifts based on wheel speed
		"RPM"		: Shifts based on RPM											]]	
	Tune.AutoUpThresh	= -200		--Automatic upshift point 	(relative to peak RPM, positive = Over-rev)
	Tune.AutoDownThresh = 1400		--Automatic downshift point (relative to peak RPM, positive = Under-rev)
	
	--Gear Ratios
	Tune.FinalDrive		= 3.92			-- Gearing determines top speed and wheel torque
	Tune.Ratios			= {				-- Higher ratio = more torque, Lower ratio = higher top speed
		--[[Reverse]]	3.70		,	-- Copy and paste a ratio to add a gear
		--[[Neutral]]	0			,	-- Ratios can also be deleted
		--[[ 1 ]]		3.53		,	-- Reverse, Neutral, and 1st gear are required
		--[[ 2 ]]		2.04		,
		--[[ 3 ]]		1.38		,
		--[[ 4 ]]		1.03		,
		--[[ 5 ]]		0.81		,
		--[[ 6 ]]		0.64		,
	}
	Tune.FDMult			= 1.6			-- Ratio multiplier (Change this value instead of FinalDrive if car is struggling with torque ; Default = 1)
-- #endif
--]]
        f.is_vararg = f.is_vararg + self.VARARG_ISVARARG
      else
        luaX:syntaxerror(ls, "<name> or "..self:LUA_QL("...").." expected")
      end
    until f.is_vararg ~= 0 or not self:testnext(ls, ",")
  end--if
  self:adjustlocalvars(ls, nparams)
  -- NOTE: the following works only when HASARG_MASK is 2!
  f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK)
  luaK:reserveregs(fs, fs.nactvar)  -- reserve register for parameters
end
-- This script gets placed into StarterPlayerScripts where it will locally play the background music for each player.

local plr = game.Players.LocalPlayer
local char
local torso

local container = game.ReplicatedStorage:WaitForChild("CinderingBGM")
local settings = require(container:WaitForChild("Settings"))
local musicfolder = container:WaitForChild("MusicFolder")
local globalfolder = musicfolder:WaitForChild("GlobalMusic")
local zonesfolder = musicfolder:WaitForChild("MusicZones")
local servercount = container:WaitForChild("ObjectCount").Value

function GetMatchingCount() --objects can take some time to actually replicate to the client. make sure that the client sees the correct # of objects in the music folder before initializing the rest of the script
	local count = 0
	local function recurse(instance)
		for _,v in pairs(instance:GetChildren()) do
			count = count + 1
			recurse(v)
		end
	end
	recurse(musicfolder)
	if count == servercount then return true end
end

while not GetMatchingCount() do
	wait(.5)
end


function IsCleanRotation(v3values) --check to see whether the rotation is at clean 90 degree increments so we can use the more simplistic calculations for it
	for _,v in pairs(v3values) do
		if not (v%90 <= 0.01 or v%90 >= 89.99) then --why not just check for (v%90 == 0)? because rotations can suffer from floating point inaccuracies
			return false
		end
	end
	return true
end
-------- OMG HAX

r = game:service("RunService")


Tool = script.Parent

local equalizingForce = 236 / 1.2 -- amount of force required to levitate a mass
local gravity = 2 -- things float at > 1

local ghostEffect = nil
local massCon1 = nil
local massCon2 = nil

function recursiveGetLift(node)
	local m = 0
	local c = node:GetChildren()
	for i=1,#c do
		if c[i].className == "Part" then
			if c[i].Name == "Handle" then
				m = m + (c[i]:GetMass() * equalizingForce * 1) -- hack that makes hats weightless, so different hats don't change your jump height
			else
				m = m + (c[i]:GetMass() * equalizingForce * gravity)
			end
		end
		m = m + recursiveGetLift(c[i])
	end
	return m
end


function onMassChanged(child, char)
	print("Mass changed:" .. child.Name .. "    " .. char.Name)
	if (ghostEffect ~= nil) then
		ghostEffect.force = Vector3.new(0, recursiveGetLift(char) ,0)
	end
end



function UpdateGhostState(isUnequipping)

	if isUnequipping == true then
		ghostEffect:Remove()
		ghostEffect = nil
		massCon1:disconnect()
		massCon2:disconnect()
	else
		if ghostEffect == nil then
			local char = Tool.Parent
			if char == nil then return end
			ghostEffect = Instance.new("BodyForce")
			ghostEffect.Name = "GravityCoilEffect"
			ghostEffect.force = Vector3.new(0, recursiveGetLift(char) ,0)
			ghostEffect.Parent = char.Head
			ghostChar = char
			massCon1 = char.ChildAdded:connect(function(child)  onMassChanged(child, char) end)
			massCon2 = char.ChildRemoved:connect(function(child)  onMassChanged(child, char) end)
		end
	end
	

end



function onEquipped()
	Tool.Handle.CoilSound:Play()
	UpdateGhostState(false)
end

function onUnequipped()
	UpdateGhostState(true)
end


script.Parent.Equipped:connect(onEquipped)
script.Parent.Unequipped:connect(onUnequipped)
-- Decompiled with the Synapse X Luau decompiler.

local l__LocalPlayer__1 = game:GetService("Players").LocalPlayer;
local l__SoundService__1 = game:GetService("SoundService");
if l__LocalPlayer__1.Character then
	l__SoundService__1:SetListener(Enum.ListenerType.ObjectPosition, (l__LocalPlayer__1.Character:WaitForChild("Head")));
end;
l__LocalPlayer__1.CharacterAdded:connect(function(p1)
	l__SoundService__1:SetListener(Enum.ListenerType.ObjectPosition, (p1:WaitForChild("Head")));
end);
-- * Fires when the local player's MouseButton1 interacts with the
--	 `ExitButton` GUI. Sets `Interacting` BoolValue to false.
--
--	 Arguments: None
--	 Return: None
-- * 
function hide()
	MainFrame.Visible = false
	InteractionButton.Visible = false
	
	-- Unfreeze the player
	humanoid.WalkSpeed = prevWalkSpeed or humanoid.WalkSpeed
	humanoid:SetStateEnabled(Enum.HumanoidStateType.Jumping, true)
end

function show()
	MainFrame.Visible = true
	InteractionButton.Visible = false
	
	-- Freeze the player
	prevWalkSpeed = humanoid.WalkSpeed
	humanoid.WalkSpeed = 0
	humanoid:SetStateEnabled(Enum.HumanoidStateType.Jumping, false)
end
--[[
	Creates a function that invokes a callback with correct error handling and
	resolution mechanisms.
]]
local function createAdvancer(traceback, callback, resolve, reject)
	return function(...)
		local ok, resultLength, result = runExecutor(traceback, callback, ...)

		if ok then
			resolve(unpack(result, 1, resultLength))
		else
			reject(result[1])
		end
	end
end

local function isEmpty(t)
	return next(t) == nil
end

local Promise = {
	Error = Error,
	Status = makeEnum("Promise.Status", {"Started", "Resolved", "Rejected", "Cancelled"}),
	_getTime = os.clock,
	_timeEvent = game:GetService("RunService").Heartbeat,
	_unhandledRejectionCallbacks = {},
}
Promise.prototype = {}
Promise.__index = Promise.prototype
--handler:FireServer("stopSound",Your sound here)
wait()
handler:FireServer("playSound",bike.DriveSeat.Rev)
--[[ todo: player animations when entering vehicle
--Get in a seat
local function enterStart()
	--Wait until player lets go of button (causing them to get in) or seat out of range (nothing happens)
	while EnterKeyDown and AdornedSeat do
		wait()
	end

	if AdornedSeat then
		--Tell server we are getting in seat
		Remotes.GetInSeat:FireServer(AdornedSeat)
		local n = 0
		repeat
			wait()
			n = n + 1
		until AdornedSeat == nil or n>20
		EnterImageButton.Visible = true
		
		local hum = getLocalHumanoid()
		if hum then
			if hum.Sit then
				-- load animations only when player is in the vehicle
				local hum = getLocalHumanoid()
				if hum ~= currentHumanoid then -- load only when we have a new humanoid
					currentHumanoid = hum
					local anims = animationFolder:GetChildren()
					for i = 1, #anims do
						AnimationTracks[anims[i].Name] = hum:LoadAnimation(anims[i])
					end
				end
				
				-- play seated animation
				local seat = hum.SeatPart
				local prefix = (seat.ClassName == "VehicleSeat" and "Driver" or "Passenger")
				local preferredAnimation = AnimationTracks[prefix.."_Seated"]
				if preferredAnimation then
					preferredAnimation.Priority = Enum.AnimationPriority.Action
					preferredAnimation:Play()
				end
			end
		end
	end
end
]]--
--[[Steering]]
	Tune.SteerInner		= 70		-- Inner wheel steering angle (in degrees)
	Tune.SteerOuter		= 70		-- Outer wheel steering angle (in degrees)
	Tune.SteerSpeed		= .05		-- Steering increment per tick (in degrees)
	Tune.ReturnSpeed	= .1		-- Steering increment per tick (in degrees)
	Tune.SteerDecay		= 320		-- Speed of gradient cutoff (in SPS)
	Tune.MinSteer		= 10		-- Minimum steering at max steer decay (in percent)
	Tune.MSteerExp		= 1			-- Mouse steering exponential degree
	
	--Steer Gyro Tuning
	Tune.SteerD			= 1000		-- Steering Dampening
	Tune.SteerMaxTorque	= 50000		-- Steering Force
	Tune.SteerP			= 100000	-- Steering Aggressiveness
--[[
	CameraModule - This ModuleScript implements a singleton class to manage the
	selection, activation, and deactivation of the current camera controller,
	character occlusion controller, and transparency controller. This script binds to
	RenderStepped at Camera priority and calls the Update() methods on the active
	controller instances.
	
	The camera controller ModuleScripts implement classes which are instantiated and
	activated as-needed, they are no longer all instantiated up front as they were in
	the previous generation of PlayerScripts.
	
	2018 PlayerScripts Update - AllYourBlox		
--]]

local CameraModule = {}
CameraModule.__index = CameraModule
-- Endgame gui
local endgameGui = EndgameGui.new()
local endgameGuiFrame = endgameGui:createFrame(Endgame)

return nil
--///////////////////////// Constructors
--//////////////////////////////////////

function module.new()
	local obj = setmetatable({}, methods)

	obj.GuiObject = nil
	obj.GuiObjects = {}

	obj.ChannelTabs = {}
	obj.NumTabs = 0
	obj.CurPageNum = 0

	obj.ScrollChannelsFrameLock = false

	obj.AnimParams = {}

	obj:InitializeAnimParams()

	ChatSettings.SettingsChanged:connect(function(setting, value)
		if (setting == "ChatChannelsTabTextSize") then
			obj:ResizeChannelTabText(value)
		end
	end)

	return obj
end

return module
--[[
	
	Returns true if value exists in array.
	
	Functions.SearchArray(
		array,					<-- |REQ| 	Array to search through
		search,					<-- |REQ| 	Search value
	)
	
--]]



return function(array, search)
	--- Scan array
	for _, value in ipairs(array) do
		if value == search then
			--- Matching value!
			return true
		end
	end
	
	--- No matching value
	return false
end
--only works for R6
game.Players.PlayerAdded:connect(function(player)
		player.CharacterAdded:connect(function(character)
		player.Character.Animate.walk.WalkAnim.AnimationId = "http://www.roblox.com/asset/?id=6866085991" -- Insert your animation's ID here or leave this one, I don't really care--
		end)
end)
--[[
	
Change log:

09/18
	Fixed checkbox mouseover sprite
	Encapsulated checkbox creation into separate method
	Fixed another checkbox issue

09/15
	Invalid input is ignored instead of setting to default of that data type
	Consolidated control methods and simplified them
	All input goes through ToValue method
	Fixed position of BrickColor palette
	Made DropDown appear above row if it would otherwise exceed the page height
	Cleaned up stylesheets

09/14
	Made properties window scroll when mouse wheel scrolled
	Object/Instance and Color3 data types handled properly
	Multiple BrickColor controls interfering with each other fixed
	Added support for Content data type
	
--]]

wait(0.2)

local print = function(s)
	print(tostring(s))
end
--[[Manage Plugins]]
	
script.Parent.Interface:WaitForChild("Bike").Value=bike
script.Parent.Interface:WaitForChild("Car").Value=bike
for i,v in pairs(script.Parent.Plugins:GetChildren()) do
	for _,a in pairs(v:GetChildren()) do
		if a:IsA("RemoteEvent") or a:IsA("RemoteFunction") then 
			a.Parent=bike
			for _,b in pairs(a:GetChildren()) do
				if b:IsA("Script") then b.Disabled=false end
			end	
		end
	end
	v.Parent = script.Parent.Interface
end
script.Parent.Plugins:Destroy()
-- Functions
players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		
		local rootPart = character:WaitForChild("HumanoidRootPart")
		
		local footstepsSound = Instance.new("Sound")
		footstepsSound.Name = "Footsteps"
		footstepsSound.RollOffMaxDistance = 22.5
		footstepsSound.RollOffMode = Enum.RollOffMode.Linear
		footstepsSound.PlayOnRemove = true
		footstepsSound.Volume = 1.2
		
		footstepsSound.Parent = rootPart
		
	end)
end)
-- True ...... Synchronized
-- False ..... Free Run

val = script.Parent.Parent.Parent.Parent.AudibleCircuit
val2 = script.Parent.Parent.Parent.Parent.VisualCircuit
horn = script.Parent.horn
strobe = script.Parent.Parent.Strobe
alarm = false
salarm = false

horn.Pitch = math.random(80,107)/100

if candela == 0 then
	strobe.Flasher.Size = UDim2.new(3,0,3,0)
elseif candela == 1 then
	strobe.Flasher.Size = UDim2.new(4,0,4,0)
elseif candela == 2 then
	strobe.Flasher.Size = UDim2.new(5,0,5,0)
elseif candela == 3 then
	strobe.Flasher.Size = UDim2.new(6.5,0,6.5,0)
end

function Sound()
	if val.Value == 1 then
	horn:Play()
	else
	wait(0.03)
	horn:Stop()
	end
end

val.Changed:connect(Sound)

function Flash()
strobe.BrickColor = BrickColor.new(1001)
strobe.Flasher.Strobe.Visible = true
strobe.Light.Enabled = true
wait(0.06)
strobe.BrickColor = BrickColor.new(194)
strobe.Flasher.Strobe.Visible = false
strobe.Light.Enabled = false
end

sval = math.random(85,95)/100

function PowerStrobe()
	if salarm then return end
	salarm = true
	wait(sval)
	while val2.Value == 1 do
	Flash()
	wait(sval)
	end
	salarm = false
end

if strobesync then
val2.Changed:connect(function() if val2.Value == 1 then Flash() end end)
else
val2.Changed:connect(function() if val2.Value == 1 then PowerStrobe() end end)	
end
-- Decompiled with the Synapse X Luau decompiler.

local u1 = nil;
coroutine.wrap(function()
	u1 = require(game.ReplicatedStorage:WaitForChild("Framework"):WaitForChild("Library"));
end)();
return function(p1, p2)
	p1 = math.clamp(p1, 0, 1);
	if math.clamp(p2 and p1, 0, 1) <= 0.0002 and p1 <= 0.001 then
		return u1.Functions.FormatOdds(p1);
	end;
	return u1.Functions.FormatPercent(p1);
end;
--%%Functions%%--
script.Parent.FlushSoon.Touched:connect(whileTouching)
script.Parent.FlushSoon.TouchEnded:connect(letGo)
--[=[
	Sort of equivalent of promise.then()

	This takes a stream of observables

	@param project (value: T) -> Observable<U>
	@param resultSelector ((initialValue: T, outputValue: U) -> U)?
	@return (source: Observable<T>) -> Observable<U>
]=]
function Rx.flatMap(project, resultSelector)
	assert(type(project) == "function", "Bad project")

	return function(source)
		assert(Observable.isObservable(source), "Bad observable")

		return Observable.new(function(sub)
			local maid = Maid.new()

			local pendingCount = 0
			local topComplete = false

			maid:GiveTask(source:Subscribe(
				function(...)
					local outerValue = ...

					local observable = project(...)
					assert(Observable.isObservable(observable), "Bad observable from project")

					pendingCount = pendingCount + 1

					local innerMaid = Maid.new()

					innerMaid:GiveTask(observable:Subscribe(
						function(...)
							-- Merge each inner observable
							if resultSelector then
								sub:Fire(resultSelector(outerValue, ...))
							else
								sub:Fire(...)
							end
						end,
						function(...)
							sub:Fail(...)
						end, -- Emit failure automatically
						function()
							innerMaid:DoCleaning()
							pendingCount = pendingCount - 1
							if pendingCount == 0 and topComplete then
								sub:Complete()
								maid:DoCleaning()
							end
						end))

					local key = maid:GiveTask(innerMaid)

					-- Cleanup
					innerMaid:GiveTask(function()
						maid[key] = nil
					end)
				end,
				function(...)
					sub:Fail(...) -- Also reflect failures up to the top!
					maid:DoCleaning()
				end,
				function()
					topComplete = true
					if pendingCount == 0 then
						sub:Complete()
						maid:DoCleaning()
					end
				end))

			return maid
		end)
	end
end

function Rx.switchMap(project)
	return Rx.pipe({
		Rx.map(project);
		Rx.switchAll();
	})
end

function Rx.takeUntil(notifier)
	assert(Observable.isObservable(notifier))

	return function(source)
		assert(Observable.isObservable(source), "Bad observable")

		return Observable.new(function(sub)
			local maid = Maid.new()
			local cancelled = false

			local function cancel()
				maid:DoCleaning()
				cancelled = true
			end

			-- Any value emitted will cancel (complete without any values allows all values to pass)
			maid:GiveTask(notifier:Subscribe(cancel, cancel, nil))

			-- Cancelled immediately? Oh boy.
			if cancelled then
				maid:DoCleaning()
				return nil
			end

			-- Subscribe!
			maid:GiveTask(source:Subscribe(sub:GetFireFailComplete()))

			return maid
		end)
	end
end