2019-12-31 10:12:04 -08:00
|
|
|
-------------- INIT VARIABLES ------------------
|
2019-03-18 12:32:39 +00:00
|
|
|
local modstorage = minetest.get_mod_storage()
|
|
|
|
local world_path = minetest.get_worldpath()
|
|
|
|
local world_name = world_path:match( "([^/]+)$" )
|
|
|
|
local waypoints = minetest.deserialize(modstorage:get_string(world_name)) or {}
|
|
|
|
|
2019-12-31 10:12:04 -08:00
|
|
|
--------------- HELPER FUNCTIONS ---------------
|
2019-03-18 12:32:39 +00:00
|
|
|
local function save() -- dumps table to modstorage
|
2020-01-03 05:36:14 -08:00
|
|
|
modstorage:set_string(world_name, minetest.serialize(waypoints))
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local function getIndexByName(table, n)
|
2020-01-03 05:36:14 -08:00
|
|
|
for k,v in pairs(table) do
|
2019-03-18 12:32:39 +00:00
|
|
|
if v.name == n then
|
2020-01-03 05:36:14 -08:00
|
|
|
return k
|
2024-08-24 02:55:38 -07:00
|
|
|
end
|
2020-01-03 05:36:14 -08:00
|
|
|
end
|
2024-08-24 02:55:38 -07:00
|
|
|
return nil --Index not found
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local function getPosByName(table, n)
|
2020-01-03 05:36:14 -08:00
|
|
|
for k,v in pairs(table) do
|
2019-03-18 12:32:39 +00:00
|
|
|
if v.name == n then
|
2020-01-03 05:36:14 -08:00
|
|
|
return v.pos
|
2024-08-24 02:55:38 -07:00
|
|
|
end
|
2020-01-03 05:36:14 -08:00
|
|
|
end
|
2024-08-24 02:55:38 -07:00
|
|
|
return nil -- Position not found
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local function waypointExists(table, n)
|
|
|
|
for k,v in pairs(table) do
|
2024-08-24 02:55:38 -07:00
|
|
|
if v.name == n then
|
|
|
|
return "Waypoint exists."
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
2024-08-24 02:55:38 -07:00
|
|
|
return nil --Waypoint doesn't exist
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
|
2020-01-03 05:36:14 -08:00
|
|
|
local function addWaypointHud(table, player)
|
|
|
|
local wayName = waypoints[#waypoints].name
|
|
|
|
local wayPos = minetest.string_to_pos(waypoints[#waypoints].pos)
|
|
|
|
table[#table].hudId = player:hud_add({
|
|
|
|
hud_elem_type = "waypoint",
|
|
|
|
name = wayName,
|
|
|
|
text = "m",
|
|
|
|
number = 0xFFFFFF,
|
|
|
|
world_pos = wayPos,
|
|
|
|
})
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
2020-01-03 05:36:14 -08:00
|
|
|
local function refreshWaypointHud(table, player)
|
|
|
|
local wayName = waypoints[selected_idx].name
|
|
|
|
local wayPos = minetest.string_to_pos(waypoints[selected_idx].pos)
|
|
|
|
table[#table].hudId = player:hud_add({
|
|
|
|
hud_elem_type = "waypoint",
|
|
|
|
name = wayName,
|
|
|
|
text = "m",
|
|
|
|
number = 0xFFFFFF,
|
|
|
|
world_pos = wayPos,
|
|
|
|
})
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
2020-01-03 05:36:14 -08:00
|
|
|
local function loadWaypointsHud(table, player)
|
|
|
|
for k,v in pairs(waypoints) do
|
|
|
|
player:hud_add({
|
|
|
|
hud_elem_type = "waypoint",
|
|
|
|
name = v.name,
|
|
|
|
text = "m",
|
|
|
|
number = 0xFFFFFF,
|
|
|
|
world_pos = minetest.string_to_pos(v.pos),
|
|
|
|
})
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
2019-12-31 10:12:04 -08:00
|
|
|
--------------- ON JOIN ------------------
|
2019-03-18 12:32:39 +00:00
|
|
|
local join = minetest.register_on_joinplayer(function(player)
|
2020-01-03 05:36:14 -08:00
|
|
|
minetest.after(.5, function()
|
|
|
|
loadWaypointsHud(waypoints, player)
|
|
|
|
end)
|
2019-03-18 12:32:39 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
-------------- NODE DEFINITIONS -----------------
|
|
|
|
local palette = {"blue", "green", "orange", "pink", "purple", "red", "white", "yellow"}
|
|
|
|
|
2019-12-31 10:12:04 -08:00
|
|
|
-- BEACON DEFINITION
|
2019-03-18 12:32:39 +00:00
|
|
|
for _, color in ipairs(palette) do
|
2020-01-03 05:36:14 -08:00
|
|
|
minetest.register_node("simple_waypoints:"..color.."_beacon", {
|
|
|
|
visual_scale = 1.0,
|
|
|
|
drawtype = "plantlike",
|
|
|
|
tiles = {"beacon_"..color..".png"},
|
|
|
|
paramtype = "light",
|
|
|
|
walkable = false,
|
|
|
|
diggable = false,
|
|
|
|
light_source = 13,
|
|
|
|
groups = {not_in_creative_inventory=1}
|
|
|
|
})
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
2019-12-31 10:12:04 -08:00
|
|
|
-- BEACON FUNCTIONS
|
2020-01-03 05:36:14 -08:00
|
|
|
local function placeBeacon(pos, color)
|
|
|
|
local random = math.random(1,#palette)
|
|
|
|
for i=0,50 do
|
|
|
|
local target_node = minetest.get_node({x=pos.x, y=pos.y+i, z=pos.z})
|
|
|
|
if target_node.name == "air" then
|
|
|
|
if color == nil then
|
|
|
|
minetest.add_node({x=pos.x, y=pos.y+i, z=pos.z},
|
|
|
|
{name="simple_waypoints:"..palette[random].."_beacon"})
|
|
|
|
else
|
|
|
|
minetest.add_node({x=pos.x, y=pos.y+i, z=pos.z},
|
|
|
|
{name="simple_waypoints:"..color.."_beacon"})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local function removeBeacon(pos)
|
2020-01-03 05:36:14 -08:00
|
|
|
for _,v in ipairs(palette) do
|
|
|
|
for i=0,50 do
|
|
|
|
local target_node = minetest.get_node({x=pos.x, y=pos.y+i, z=pos.z})
|
|
|
|
if target_node.name == "simple_waypoints:"..v.."_beacon" then
|
|
|
|
minetest.add_node({x=pos.x, y=pos.y+i, z=pos.z}, {name="air"})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
end
|
2019-12-31 10:12:04 -08:00
|
|
|
|
2019-03-18 12:32:39 +00:00
|
|
|
--------------- CHAT COMMANDS -------------------
|
|
|
|
|
2024-11-10 05:01:28 -08:00
|
|
|
-- Load beacon setting from settings.conf
|
|
|
|
local beacons_enabled = minetest.settings:get_bool("beacons.enable", false)
|
|
|
|
|
2019-03-18 12:32:39 +00:00
|
|
|
-- CREATE WAYPOINT
|
|
|
|
minetest.register_chatcommand("wc", {
|
|
|
|
params = "<waypoint_name>",
|
|
|
|
description = "create a waypoint at current position using a unique name",
|
2024-11-10 04:22:25 -08:00
|
|
|
privs = {teleport = true},
|
2019-03-18 12:32:39 +00:00
|
|
|
func = function (name, params)
|
|
|
|
local player = minetest.get_player_by_name(name)
|
2020-01-03 05:36:14 -08:00
|
|
|
local p_pos = player:get_pos()
|
|
|
|
local round_pos = vector.round(p_pos)
|
2024-08-23 17:10:05 -07:00
|
|
|
|
2024-08-24 19:25:12 -07:00
|
|
|
-- Check if the waypoint name is at least 1 character long
|
|
|
|
if string.len(params) < 1 then
|
|
|
|
return nil, "Waypoint name must be at least 1 character long"
|
|
|
|
end
|
|
|
|
|
2024-08-23 17:10:05 -07:00
|
|
|
-- Check if a waypoint with the given name already exists
|
2024-08-24 19:02:20 -07:00
|
|
|
if not waypointExists(waypoints, params) == true then
|
2024-08-24 19:25:12 -07:00
|
|
|
-- Add the new waypoint to the table
|
|
|
|
waypoints[#waypoints+1] = { name = params,
|
|
|
|
pos = minetest.pos_to_string(round_pos) }
|
2024-08-23 17:10:05 -07:00
|
|
|
|
2024-08-24 19:25:12 -07:00
|
|
|
-- Add the waypoint to the player's HUD
|
|
|
|
addWaypointHud(waypoints, player)
|
2024-08-23 17:10:05 -07:00
|
|
|
|
2024-11-10 05:01:28 -08:00
|
|
|
-- Check if beacons are enabled before placing a beacon
|
|
|
|
if beacons_enabled then
|
|
|
|
placeBeacon(round_pos)
|
|
|
|
end
|
2024-08-23 17:10:05 -07:00
|
|
|
|
2024-08-24 19:25:12 -07:00
|
|
|
-- Save the waypoints to modstorage
|
|
|
|
save()
|
2024-08-23 17:10:05 -07:00
|
|
|
|
2024-08-24 19:25:12 -07:00
|
|
|
-- Return success message
|
|
|
|
return true, "Waypoint "..params.." created!"
|
2024-08-23 17:10:05 -07:00
|
|
|
else
|
2024-08-24 19:25:12 -07:00
|
|
|
return nil, "Waypoint with that name already exists"
|
2020-01-03 05:36:14 -08:00
|
|
|
end
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
})
|
|
|
|
|
2024-08-24 19:05:59 -07:00
|
|
|
|
2019-03-18 12:32:39 +00:00
|
|
|
-- DELETE WAYPOINT
|
|
|
|
minetest.register_chatcommand("wd", {
|
2020-01-03 05:36:14 -08:00
|
|
|
params = "<waypoint_name>",
|
|
|
|
description = "Delete a waypoint using its name.",
|
2024-11-10 04:22:25 -08:00
|
|
|
privs = {teleport = true},
|
2020-01-03 05:36:14 -08:00
|
|
|
func = function(name,params)
|
|
|
|
local player = minetest.get_player_by_name(name)
|
|
|
|
local targetIndex = getIndexByName(waypoints, params)
|
|
|
|
local beaconPos = getPosByName(waypoints, params)
|
2024-08-24 19:25:12 -07:00
|
|
|
if (type(targetIndex) == "number") then
|
2020-01-03 05:36:14 -08:00
|
|
|
removeBeacon(minetest.string_to_pos(beaconPos))
|
|
|
|
player:hud_remove(waypoints[targetIndex].hudId)
|
2024-08-23 17:10:05 -07:00
|
|
|
|
|
|
|
-- Remove the waypoint from the table
|
2020-01-03 05:36:14 -08:00
|
|
|
table.remove(waypoints, targetIndex)
|
2024-08-23 17:10:05 -07:00
|
|
|
|
|
|
|
-- Now get the correct index for the hud update
|
|
|
|
targetIndex = getIndexByName(waypoints, params)
|
|
|
|
|
|
|
|
-- Update the HUD
|
|
|
|
if targetIndex ~= nil then
|
|
|
|
player:hud_remove(waypoints[targetIndex].hudId)
|
|
|
|
end
|
|
|
|
|
2019-03-18 12:32:39 +00:00
|
|
|
save()
|
2024-08-23 17:10:05 -07:00
|
|
|
return true, "Waypoint deleted."
|
2019-03-18 12:32:39 +00:00
|
|
|
elseif type(targetIndex) ~= "number" then
|
2024-08-23 17:10:05 -07:00
|
|
|
return false, "Waypoint "..params.." is invalid or inexistent."
|
2020-01-03 05:36:14 -08:00
|
|
|
end
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
})
|
|
|
|
|
2024-08-23 17:10:05 -07:00
|
|
|
|
2019-03-18 12:32:39 +00:00
|
|
|
-- LIST WAYPOINTS
|
|
|
|
minetest.register_chatcommand("wl", {
|
2020-01-03 05:36:14 -08:00
|
|
|
params = "",
|
|
|
|
description = "Lists your waypoints.",
|
2024-11-10 04:22:25 -08:00
|
|
|
privs = {teleport = true},
|
2020-01-03 05:36:14 -08:00
|
|
|
func = function(name)
|
|
|
|
local player = minetest.get_player_by_name(name)
|
|
|
|
local p_name = player:get_player_name()
|
2024-08-23 17:10:05 -07:00
|
|
|
|
|
|
|
-- Iterate through the waypoints table and send each waypoint's details to the player
|
2020-01-03 05:36:14 -08:00
|
|
|
for k,v in pairs(waypoints) do
|
|
|
|
minetest.chat_send_player(p_name, tostring(k.." "..v.name.." "..v.pos))
|
|
|
|
end
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
-- TELEPORT TO WAYPOINT
|
|
|
|
minetest.register_chatcommand("wt", {
|
2020-01-03 05:36:14 -08:00
|
|
|
params = "<waypoint_name>",
|
|
|
|
description = "Teleports you to a specified waypoint.",
|
2024-11-10 04:22:25 -08:00
|
|
|
privs = {teleport = true},
|
2020-01-03 05:36:14 -08:00
|
|
|
func = function(name, params)
|
|
|
|
local player = minetest.get_player_by_name(name)
|
2019-03-18 12:32:39 +00:00
|
|
|
local p_name = player:get_player_name()
|
|
|
|
local targetPos = getPosByName(waypoints, params)
|
2024-08-23 17:10:05 -07:00
|
|
|
|
|
|
|
-- Check if the waypoint exists and has a valid position
|
2024-08-24 19:25:12 -07:00
|
|
|
if (type(targetPos) == "string") then
|
2024-08-23 17:10:05 -07:00
|
|
|
-- Teleport the player to the waypoint position
|
2019-03-18 12:32:39 +00:00
|
|
|
player:set_pos(minetest.string_to_pos(targetPos))
|
|
|
|
return true, tostring("Teleported "..p_name.." to "..params..".")
|
|
|
|
elseif type(targetPos) ~= "string" then
|
|
|
|
return true, tostring("Waypoint "..params.." is invalid or inexistent.")
|
2020-01-03 05:36:14 -08:00
|
|
|
end
|
|
|
|
end
|
2019-03-18 12:32:39 +00:00
|
|
|
})
|
2019-12-31 10:12:04 -08:00
|
|
|
|
|
|
|
-- SHOW WAYPOINTS FORMSPEC
|
|
|
|
minetest.register_chatcommand("wf", {
|
2024-11-10 04:22:25 -08:00
|
|
|
description = "Brings up the GUI.",
|
|
|
|
privs = {teleport = true},
|
2020-01-03 05:36:14 -08:00
|
|
|
func = function(name)
|
2024-08-23 17:10:05 -07:00
|
|
|
-- Show the waypoints formspec to the player
|
2020-01-03 05:36:14 -08:00
|
|
|
minetest.show_formspec(name, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_main())
|
|
|
|
end,
|
2019-12-31 10:12:04 -08:00
|
|
|
})
|
|
|
|
|
|
|
|
--------------- FORMSPEC -----------------------
|
2020-01-03 05:36:14 -08:00
|
|
|
waypoints_formspec = {}
|
2019-12-31 10:12:04 -08:00
|
|
|
|
2020-01-03 05:36:14 -08:00
|
|
|
-- MAIN PAGE
|
|
|
|
function waypoints_formspec.get_main()
|
|
|
|
local text = "Waypoints list."
|
2019-12-31 10:12:04 -08:00
|
|
|
formspec = {
|
|
|
|
"size[11,14]",
|
|
|
|
"real_coordinates[true]",
|
|
|
|
"label[0.375,0.5;", minetest.formspec_escape(text), "]",
|
|
|
|
"button_exit[8.7,0.75;2,1;teleport;Teleport]",
|
|
|
|
"button[8.7,1.75;2,1;add;Add]",
|
2020-01-03 05:36:14 -08:00
|
|
|
"button[8.7,2.75;2,1;delete;Delete]",
|
2019-12-31 10:12:04 -08:00
|
|
|
"button[8.7,3.75;2,1;rename;Rename]",
|
|
|
|
}
|
|
|
|
|
|
|
|
local f = ""
|
|
|
|
f = f..
|
2020-01-03 05:36:14 -08:00
|
|
|
"textlist[0.375,0.75;8,13;waylist;"
|
2019-12-31 10:12:04 -08:00
|
|
|
for i = 1, #waypoints do
|
2020-01-03 05:36:14 -08:00
|
|
|
f = f..i.." "..minetest.formspec_escape(waypoints[i].name.." "..waypoints[i].pos)..","
|
2019-12-31 10:12:04 -08:00
|
|
|
end
|
2020-01-03 05:36:14 -08:00
|
|
|
formspec[#formspec+1] = f.."]"
|
|
|
|
return table.concat(formspec, " ")
|
2019-12-31 10:12:04 -08:00
|
|
|
end
|
|
|
|
|
2020-01-03 05:36:14 -08:00
|
|
|
function waypoints_formspec.get_add()
|
|
|
|
local text = "Add waypoint at current position. Random color if unselected."
|
|
|
|
local text2 = "Color:"
|
|
|
|
formspec = {
|
|
|
|
"size[10,5]",
|
|
|
|
"real_coordinates[true]",
|
|
|
|
"label[0.375,0.5;", text, "]",
|
|
|
|
"label[5.375,1.80;", text2, "]",
|
|
|
|
"field[0.375,2;4,0.6;name;Name:;]",
|
|
|
|
"dropdown[5.375,2;4,0.6;color;blue,green,orange,pink,purple,red,white,yellow;0]",
|
|
|
|
"button[4,3.5;2,1;create;Create]"
|
|
|
|
}
|
|
|
|
return table.concat(formspec, " ")
|
|
|
|
end
|
|
|
|
-- RENAME PAGE
|
|
|
|
function waypoints_formspec.get_rename()
|
|
|
|
local text = "Enter a new name:"
|
|
|
|
formspec = {
|
|
|
|
"size[4,2.5]",
|
|
|
|
"real_coordinates[true]",
|
|
|
|
"label[0.58,0.5;", text, "]",
|
|
|
|
"field[0.25,0.9;3.5,0.6;new_name;;]",
|
|
|
|
"button[1.5,1.75;1,0.5;ok;OK]"
|
|
|
|
}
|
|
|
|
return table.concat(formspec, " ")
|
2019-12-31 10:12:04 -08:00
|
|
|
end
|
|
|
|
|
2020-01-03 05:36:14 -08:00
|
|
|
function waypoints_formspec.get_exists()
|
|
|
|
local text = "A waypoint with that name already exists!"
|
|
|
|
local text2 = "Please choose a unique name."
|
|
|
|
formspec = {
|
|
|
|
"size[7,3]",
|
|
|
|
"real_coordinates[true]",
|
|
|
|
"label[0.375,0.5;", text, "]",
|
|
|
|
"label[1.15,1;"; text2, "]",
|
|
|
|
"button[2.5,1.5;2,1;back;Back]"
|
|
|
|
}
|
|
|
|
return table.concat(formspec, " ")
|
|
|
|
end
|
2019-12-31 10:12:04 -08:00
|
|
|
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
2020-01-03 05:36:14 -08:00
|
|
|
local pname = player:get_player_name()
|
|
|
|
if formname ~= "simple_waypoints:waypoints_formspec" then return
|
2019-12-31 10:12:04 -08:00
|
|
|
elseif fields.waylist then
|
2020-01-03 05:36:14 -08:00
|
|
|
local event = minetest.explode_textlist_event(fields.waylist)
|
2019-12-31 10:12:04 -08:00
|
|
|
if(event.type == "CHG") then
|
|
|
|
selected_idx = event.index
|
|
|
|
end
|
|
|
|
elseif fields.teleport then
|
2020-01-03 05:36:14 -08:00
|
|
|
if waypoints[selected_idx] ~= nil then
|
|
|
|
player:set_pos(minetest.string_to_pos(waypoints[selected_idx].pos))
|
2019-12-31 10:12:04 -08:00
|
|
|
minetest.chat_send_all(pname .. " Teleported to " .. waypoints[selected_idx].name)
|
|
|
|
selected_idx = nil -- "Teleport" button remembers the last location when you don't select a valid item. This is a reset.
|
|
|
|
end
|
2020-01-03 05:36:14 -08:00
|
|
|
elseif fields.add then
|
|
|
|
minetest.show_formspec(pname, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_add())
|
|
|
|
elseif fields.create or fields.key_enter_field then
|
|
|
|
if fields.name ~= nil and string.len(fields.name) ~= 0 then
|
|
|
|
local player = minetest.get_player_by_name(pname)
|
|
|
|
local p_pos = player:get_pos()
|
|
|
|
local round_pos = vector.round(p_pos)
|
|
|
|
if not waypointExists(waypoints, fields.name) then
|
|
|
|
waypoints[#waypoints+1] = { name = fields.name, pos = minetest.pos_to_string(round_pos) }
|
|
|
|
addWaypointHud(waypoints, player)
|
2024-11-10 05:42:44 -08:00
|
|
|
if beacons_enabled then
|
|
|
|
placeBeacon(round_pos, fields.color)
|
|
|
|
end
|
2020-01-03 05:36:14 -08:00
|
|
|
save()
|
|
|
|
minetest.show_formspec(pname, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_main())
|
|
|
|
else minetest.show_formspec(pname, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_exists())
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif fields.back then
|
|
|
|
minetest.show_formspec(pname, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_add())
|
|
|
|
elseif fields.delete then
|
|
|
|
if waypoints[selected_idx] ~= nil then
|
|
|
|
local beaconPos = getPosByName(waypoints, waypoints[selected_idx].name)
|
|
|
|
removeBeacon(minetest.string_to_pos(beaconPos))
|
|
|
|
player:hud_remove(waypoints[selected_idx].hudId)
|
|
|
|
table.remove(waypoints, selected_idx)
|
|
|
|
save()
|
|
|
|
minetest.show_formspec(pname, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_main())
|
|
|
|
end
|
|
|
|
elseif fields.rename then
|
|
|
|
if waypoints[selected_idx] ~= nil then
|
|
|
|
minetest.show_formspec(pname, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_rename())
|
|
|
|
end
|
|
|
|
elseif fields.ok or fields.key_enter_field then
|
|
|
|
if fields.new_name ~= nil and string.len(fields.new_name) ~= 0 then
|
|
|
|
waypoints[selected_idx].name = fields.new_name
|
|
|
|
player:hud_remove(waypoints[selected_idx].hudId)
|
|
|
|
refreshWaypointHud(waypoints, player)
|
|
|
|
minetest.show_formspec(pname, "simple_waypoints:waypoints_formspec", waypoints_formspec.get_main())
|
|
|
|
end
|
2019-12-31 10:12:04 -08:00
|
|
|
end
|
|
|
|
end)
|