function Blend._observeChildren(x,C)if typeof(x)=="\073\110\115\116\097\110\099\101"then return Observable.new(function(C)C:Fire(x)return x end)end if type(x)=="\102\117\110\099\116\105\111\110"then x=Blend._observeChildren(x(C),C)end if ValueObject.isValueObject(x)then return Observable.new(function(n)local k=Maid.new()local function M()local M=x.Value if typeof(M)=="\073\110\115\116\097\110\099\101"then k._current=M n:Fire(M)return end local T=Blend._observeChildren(M,C)if T then k._current=nil local x=false local C C=T:Subscribe(function(x)n:Fire(x)end,function(...)n:Fail(...)end,function()x=true if k._current==C then k._current=nil end end)if x then if C then MaidTaskUtils.doCleanup(C)end else k._current=C end return end k._current=nil end k:GiveTask(x.Changed:Connect(M))M()return k end)end if Brio.isBrio(x)then return Observable.new(function(n)if x:IsDead()then return nil end local k=x:GetValue()if typeof(k)=="\073\110\115\116\097\110\099\101"then local C=x:ToMaid()C:GiveTask(k)n:Fire(k)return C end local M=Blend._observeChildren(k,C)if M then local C=x:ToMaid()C:GiveTask(M:Subscribe(function(x)n:Fire(x)end,function(...)n:Fail(...)end,function()C:DoCleaning()end))return C end warn(("\085\110\107\110\111\119\110 \116\121\112\101 \105\110 \098\114\105\111 \037\113"):format(typeof(k)))return nil end)end if Promise.isPromise(x)then x=Rx.fromPromise(x)end if Signal.isSignal(x)or typeof(x)=="\082\066\088\083\099\114\105\112\116\083\105\103\110\097\108"then x=Rx.fromSignal(x)end if Observable.isObservable(x)then return Observable.new(function(n)local k=Maid.new()k:GiveTask(x:Subscribe(function(x)if typeof(x)=="\073\110\115\116\097\110\099\101"then k:GiveTask(x)n:Fire(x)return end local M=Blend._observeChildren(x,C)if M then local x=Maid.new()x:GiveTask(M:Subscribe(function(x)n:Fire(x)end,function(...)x:DoCleaning()n:Fail(...)end,function()x:DoCleaning()end))x:GiveTask(function()k[x]=nil end)k[x]=x else warn(("\070\097\105\108\101\100 \116\111 \099\111\110\118\101\114\116 \037\113 \105\110\116\111 \099\104\105\108\100\114\101\110"):format(tostring(x)))end end,function(...)n:Fire(...)end,function() end))return k end)end if type(x)=="\116\097\098\108\101"and not getmetatable(x)then local n={}for x,k in pairs(x)do local M=Blend._observeChildren(k,C)if M then table.insert(n,M)else warn(("\070\097\105\108\101\100 \116\111 \099\111\110\118\101\114\116 \091\037\115\093 \037\113 \105\110\116\111 \099\104\105\108\100\114\101\110"):format(tostring(x),tostring(k)))end end if next(n)then return Rx.merge(n)else return nil end end return nil end

function Blend._observeChildren(value, parent)
	if typeof(value) == "Instance" then
		-- Should be uncommon
		return Observable.new(function(sub)
			sub:Fire(value)
			-- don't complete, as this would clean everything up
			return value
		end)
	end

	if type(value) == "function" then
		value = Blend._observeChildren(value(parent), parent)
	end

	if ValueObject.isValueObject(value) then
		return Observable.new(function(sub)
			local maid = Maid.new()

			-- Switch instead of emitting every value.
			local function update()
				local result = value.Value
				if typeof(result) == "Instance" then
					maid._current = result
					sub:Fire(result)
					return
				end

				local observe = Blend._observeChildren(result, parent)
				if observe then
					maid._current = nil

					local doCleanup = false
					local cleanup
					cleanup = observe:Subscribe(function(inst)
						sub:Fire(inst)
					end, function(...)
						sub:Fail(...)
					end, function()
						-- incase of immediate execution
						doCleanup = true

						-- Do not pass complete through to the end
						if maid._current == cleanup then
							maid._current = nil
						end
					end)

					-- TODO: Complete when valueobject cleans up

					if doCleanup then
						if cleanup then
							MaidTaskUtils.doCleanup(cleanup)
						end
					else
						maid._current = cleanup
					end

					return
				end

				maid._current = nil
			end
			maid:GiveTask(value.Changed:Connect(update))
			update()

			return maid
		end)
	end

	if Brio.isBrio(value) then
		return Observable.new(function(sub)
			if value:IsDead() then
				return nil
			end

			local result = value:GetValue()
			if typeof(result) == "Instance" then
				local maid = value:ToMaid()
				maid:GiveTask(result)
				sub:Fire(result)

				return maid
			end

			local observe = Blend._observeChildren(result, parent)
			if observe then
				local maid = value:ToMaid()

				-- Subscription is for lifetime of brio, so we do
				-- not need to specifically add these results to the maid, and
				-- risk memory leak of the maid with a lot of items in it.
				maid:GiveTask(observe:Subscribe(function(inst)
					sub:Fire(inst)
				end, function(...)
					sub:Fail(...)
				end, function()
					-- completion should not result more than maid cleaning up
					maid:DoCleaning()
				end))

				return maid
			end

			warn(("Unknown type in brio %q"):format(typeof(result)))
			return nil
		end)
	end

	-- Handle like observable
	if Promise.isPromise(value) then
		value = Rx.fromPromise(value)
	end

	-- Handle like observable
	if Signal.isSignal(value) or typeof(value) == "RBXScriptSignal" then
		value = Rx.fromSignal(value)
	end

	if Observable.isObservable(value) then
		return Observable.new(function(sub)
			local maid = Maid.new()

			maid:GiveTask(value:Subscribe(function(result)
				if typeof(result) == "Instance" then
					-- lifetime of subscription
					maid:GiveTask(result)
					sub:Fire(result)
					return
				end

				local observe = Blend._observeChildren(result, parent)

				if observe then
					local innerMaid = Maid.new()

					-- Note: I think this still memory leaks
					innerMaid:GiveTask(observe:Subscribe(function(inst)
						sub:Fire(inst)
					end, function(...)
						innerMaid:DoCleaning()
						sub:Fail(...)
					end, function()
						innerMaid:DoCleaning()
					end))

					innerMaid:GiveTask(function()
						maid[innerMaid] = nil
					end)
					maid[innerMaid] = innerMaid
				else
					warn(("Failed to convert %q into children"):format(tostring(result)))
				end
			end, function(...)
				sub:Fire(...)
			end, function()
				-- Drop completion, other inner components may have completed.
			end))

			return maid
		end)
	end

	if type(value) == "table" and not getmetatable(value) then
		local observables = {}
		for key, item in pairs(value) do
			local observe = Blend._observeChildren(item, parent)
			if observe then
				table.insert(observables, observe)
			else
				warn(("Failed to convert [%s] %q into children"):format(tostring(key), tostring(item)))
			end
		end

		if next(observables) then
			return Rx.merge(observables)
		else
			return nil
		end
	end

	return nil
end
