return function(b,H,J)local Y=H.CollectionService local w=b.canvases local O=configuration.getValues()local P=O.rowsPerCanvas*O.colsPerCanvas for b,H in ipairs(Y:GetTagged(constants.Tags.SurfaceCanvas))do local Y=Canvas.new()local O={}for b=1,P,1 do local w=Spot.new()w.onArtChanged=function(b,H)J.SpotChanged:FireAllClients(Y.id,w.id,b,H)end H:SetAttribute(constants.Attributes.SpotIdPrefix..b,w.id)table.insert(O,w)end Y:registerSpots(O)H:SetAttribute(constants.Attributes.SurfaceCanvasId,Y.id)w[Y.id]=Y end end
--[[
	Setup all canvases and initialize all spots within a canvas. We perform the following:

	1. Create a new Canvas object for each tagged model
	2. Create Spot objects, set event callbacks, and register them with the canvas object
	3. Set associated attributes on models so clients can easily initialize UI to listen to
			the correct IDs
]]
return function(contexts, services, remoteEvents)
	local CollectionService = services.CollectionService

	local canvases = contexts.canvases

	-- TODO: This should be injected instead for testability purposes,
	-- handle this in another PR
	local config = configuration.getValues()

	-- Initialize all objects to keep track of canvases in the world
	local spotsPerCanvas = config.rowsPerCanvas * config.colsPerCanvas
	for _, model in ipairs(CollectionService:GetTagged(constants.Tags.SurfaceCanvas)) do
		local canvas = Canvas.new()

		-- Register spots with the canvas
		local spots = {}
		for i = 1, spotsPerCanvas do
			local spot = Spot.new()
			spot.onArtChanged = function(artId, ownerUserId)
				remoteEvents.SpotChanged:FireAllClients(canvas.id, spot.id, artId, ownerUserId)
			end

			model:SetAttribute(constants.Attributes.SpotIdPrefix .. i, spot.id)
			table.insert(spots, spot)
		end
		canvas:registerSpots(spots)

		model:SetAttribute(constants.Attributes.SurfaceCanvasId, canvas.id)
		canvases[canvas.id] = canvas
	end
end
