local beautifiers = {
	-- std::basic_string
	{
		-- pattern=[[^std::basic_string<.*>$]];
		-- use high performance native beautifier
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local buffer_cap = 16;
			local type_suffix = type_name:sub(-1);
			if type_suffix ~= "*" and type_suffix ~= "&" then
				type_suffix = "";
			end;
			if type_name:match([[std::basic_string<%s*char%s*.*]]) ~= nil then
				sym:set_typename("std::string"..type_suffix);
				buffer_cap = 16;
			elseif type_name:match([[std::basic_string<%s*wchar_t%s*.*]]) ~= nil then
				sym:set_typename("std::wstring"..type_suffix);
				buffer_cap = 8;
			end;
			local capacity_sym = sym:add_member_map("capacity", {"_Mypair","_Myval2","_Myres"});
			capacity_sym.simple_value = true;
			local size_sym = sym:add_member_map("size", {"_Mypair","_Myval2","_Mysize"});
			size_sym.simple_value = true;
			local value;
			if capacity_sym.value>=buffer_cap then
				value = sym:add_member_map("ptr", {"_Mypair","_Myval2","_Bx","_Ptr"});
			else
				value = sym:add_member_map("ptr", {"_Mypair","_Myval2","_Bx","_Buf"});
			end;
			-- make ptr as the string's value member
			sym:set_display_mem_value("ptr");
			-- override value with custom format
			sym:set_display_value(([[{size=%d,%s}]]):format(size_sym.value, value.value));
			return true;
		end;
	};
	-- std::basic_regex
	{
		pattern=[[^std::basic_regex<.*>$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local val_sym = sym:add_member_map("vis", {"_Visualization"});
			sym:set_display_mem_value("vis");
			return true;
		end;
	};
	-- std::list
	{
		-- pattern=[[^std::list<.*>$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local size_sym =sym:add_member_map("size", {"_Mypair","_Myval2","_Mysize"});
			size_sym.simple_value = true;
			local size = size_sym.value;
			sym:add_linked_list("[%d]", size, {"_Mypair","_Myval2","_Myhead","_Next"}, {"_Next"}, {"_Myval"});
			sym:set_display_value(([[{size=%d}]]):format(size));
			return true;
		end;
	};
	-- std::vector
	{
		pattern=[[^std::vector<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local size_sym = sym:add_empty_member("size");
			size_sym.simple_value = true;
			local size = sym:add_array_range("[%d]", {"_Mypair","_Myval2","_Myfirst"}, {"_Mypair","_Myval2","_Mylast"});
			size_sym:set_display_value(tostring(size));
			size_sym:set_typename("size_t");
			sym:set_display_value(([[{size=%d}]]):format(size));
			return true;
		end;
	};
	-- std::initializer_list
	{
		pattern=[[^std::initializer_list<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local size_sym = sym:add_empty_member("size");
			size_sym.simple_value = true;
			local size = sym:add_array_range("[%d]", {"_First"}, {"_Last"});
			size_sym:set_display_value(tostring(size));
			size_sym:set_typename("size_t");
			sym:set_display_value(([[{size=%d}]]):format(size));
			return true;
		end;
	};
	-- std::array
	{
		pattern=[[^std::array<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			local array_size = {type_name:match([[^std::array<.*,%s*(%d+)%s*>$]])};
			sym:set_expand_member("_Elems");
			sym:set_display_value(([[{size=%s}]]):format(array_size[1]));
			return true;
		end;
	};
	-- std::pair
	{
		-- pattern=[[^struct std::pair<.*>$]];
		-- use high performance native beautifier
		handler=function(self, id, type_name, sym)
			sym:map_members();
			local first = sym:add_member_map("first", {"first"});
			local second = sym:add_member_map("second", {"second"});
			sym:set_display_value(([[{%s, %s}]]):format(first.value,second.value));
			return true;
		end;
	};
	-- std::shared_ptr, std::weak_ptr
	{
		-- pattern=[[^std::(shared|weak)_ptr<.*>$]];
		-- use high performance native beautifier
		handler=function(self, id, type_name, sym)
			local val, typename = sym:get_member_value({"_Rep"});
			sym:add_member_map("[raw]", nil);
			if val == 0 then
				local ptr_sym = sym:add_empty_member("ptr");
				ptr_sym:set_display_value("(empty)");
				sym:set_display_value("(empty)");
				return true;
			end;
			local ref_sym = sym:add_member_map("[ref]", {"_Rep", "_Uses"});
			ref_sym.simple_value = true;
			local weak_ref_sym = sym:add_member_map("[weak_ref]", {"_Rep", "_Weaks"});
			weak_ref_sym.simple_value = true;
			local ptr_sym = sym:add_member_map("ptr", {"_Ptr"});
			sym:set_expand_member("ptr");
			return true;
		end;
	};
	-- std::unique_ptr
	{
		-- pattern=[[^std::unique_ptr<.*>$]];
		-- use high performance native beautifier
		handler=function(self, id, type_name, sym)
			local val, typename = sym:get_member_value({"_Mypair","_Myval2"});
			if val == 0 then
				local ptr_sym = sym:add_empty_member("ptr");
				ptr_sym:set_display_value("(empty)");
				sym:set_display_value("(empty)");
				return true;
			end;
			local ptr_sym = sym:add_member_map("ptr", {"_Mypair","_Myval2"});
			sym:set_expand_member("ptr");
			return true;
		end;
	};
	-- std::map, std::set, std::multimap, std::multiset, std::_Tree
	{
		pattern=[[^std::(?:map|set|multimap|multiset|_Tree)<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local size_sym = sym:add_member_map("size", {"_Mypair","_Myval2","_Myval2","_Mysize"});
			size_sym.simple_value = true;
			local size = size_sym.value;
			sym:add_multi_linked_list("[%d]", size,
				{"_Mypair","_Myval2","_Myval2","_Myhead", "_Parent"},
				{{"_Left"},{"_Right"}},
				{"_Myval"},
				{"_Mypair","_Myval2","_Myval2","_Myhead"},
				{"_Isnil"},
				1
			);
			sym:set_display_value(([[{size=%d}]]):format(size));
			return true;
		end;
	};
	-- std::queue<>, std::stack<>
	{
		pattern=[[^std::(?:queue|stack)<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local size_sym = sym:add_member_map("size", {"c", "_Mypair", "_Myval2", "_Mysize"});
			size_sym.simple_value = true;

			local offset_sym = sym:add_member_map("offset", {"c", "_Mypair", "_Myval2", "_Myoff"});
			offset_sym.simple_value = true;

			local mapsize_sym = sym:add_member_map("capacity", {"c", "_Mypair", "_Myval2", "_Mapsize"});
			mapsize_sym.simple_value = true;

			sym:add_array_offset("[%d]", offset_sym.value, size_sym.value, {"c", "_Mypair", "_Myval2", "_Map"});

			sym:set_display_value(([[{size=%d}]]):format(size_sym.value));
			return true;
		end;
	};
	-- std::deque<>
	{
		pattern=[[^std::(?:deque)<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local size_sym = sym:add_member_map("size", {"_Mypair", "_Myval2", "_Mysize"});
			size_sym.simple_value = true;

			local offset_sym = sym:add_member_map("offset", {"_Mypair", "_Myval2", "_Myoff"});
			offset_sym.simple_value = true;

			local mapsize_sym = sym:add_member_map("capacity", {"_Mypair", "_Myval2", "_Mapsize"});
			mapsize_sym.simple_value = true;

			sym:add_array_offset("[%d]", offset_sym.value, size_sym.value, {"_Mypair", "_Myval2", "_Map"});

			sym:set_display_value(([[{size=%d}]]):format(size_sym.value));
			return true;
		end;
	};
	-- std::thread
	{
		pattern=[[^std::thread$]];
		handler=function(self, id, type_name, sym)
			local id_sym = sym:add_member_map("id", {"_Thr", "_Id"});
			id_sym.simple_value = true;

			local handle_sym = sym:add_member_map("handle", {"_Thr", "_Hnd"});
			handle_sym.simple_value = true;
			handle_sym:set_typename("HANDLE");
			handle_sym:map_members();

			sym:set_display_value(([[{id=%d, handle=0x%04X}]]):format(id_sym.value, handle_sym.value));
			return true;
		end;
	};
	-- struct std::atomic<.*>
	{
		pattern=[[^struct std::atomic<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			local ptr_sym = sym:add_member_map("val", {"_Storage","_Value"});
			sym.simple_value = true;
			sym:set_expand_member("val");
			return true;
		end;
	};
	-- struct std::function<.*>
	{
		pattern=[[^std::function<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			return true;
		end;
	};
	-- std::unordered_map std::unordered_set std::unordered_multimap std::unordered_multiset
	{
		pattern=[[^std::unordered_(:?multi)?(:?map|set)<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("list", {"_List"});
			sym:set_expand_member("list");
			return true;
		end;
	};
	-- std::_List_iterator<>, std::_List_const_iterator<>
	{
		pattern=[[^std::_List(:?_const)?_iterator<.*>$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local ptr_sym = sym:add_member_map("val", {"_Ptr","_Myval"});
			ptr_sym.simple_value = true;
			sym:set_expand_member("val");
			return true;
		end;
	};
	-- std::_Deque_iterator<>, std::_Deque_const_iterator<>
	{
		pattern=[[^std::_Deque(:?_const)?_iterator<.*>$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local target_type = ""
			if type_name:sub(1, 21) == "std::_Deque_iterator<" then
				target_type = type_name:sub(22, #type_name - 2);
			else
				target_type = type_name:sub(28, #type_name - 2);
			end;
			local ptr_sym = sym:add_member_map_ex("ptr", target_type.."*", {"_Myproxy", "_Mycont"});
			local offset = sym:get_member_value({"_Myoff"});

			local base_offset = ptr_sym:get_member_value({"_Myoff"});
			local size = ptr_sym:get_member_value({"_Mysize"});
			if offset >= size then
				sym:set_display_value(("{offset=%d, (end)}"):format(offset));
				ptr_sym:set_display_value("(end)");
				return;
			end;
			
			ptr_sym:add_array_offset("[%d]", offset, 1, {"_Map"});
			local target_sym = ptr_sym:get_mapped_member("[0]");
			ptr_sym:set_display_value(target_sym.value);
			ptr_sym.simple_value = true;
			sym:set_expand_member("ptr");
			sym:set_display_value(("{offset=%d, %s}"):format(offset, target_sym.value));
			return true;
		end;
	};
	-- std::_Tree_iterator<>, std::_Tree_const_iterator<>
	{
		pattern=[[^std::_Tree(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local is_nil = sym:get_member_value({"_Ptr", "_Isnil"});
			if is_nil == 1 then
				sym:set_display_value("(end)");
			else
				local ptr_sym = sym:add_member_map("val", {"_Ptr","_Myval"});
				ptr_sym.simple_value = true;
				sym:set_expand_member("val");
			end;
			return true;
		end;
	};
	-- std::_String_iterator<>, std::_String_const_iterator<>
	{
		pattern=[[^std::_String(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("ptr", {"_Ptr"});
			sym:set_expand_member("ptr");
			return true;
		end;
	};
	-- std::_String_view_iterator<>
	{
		pattern=[[^std::_String_view_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("ptr", {"_Myptr"});
			sym:set_expand_member("ptr");
			return true;
		end;
	};
	-- std::_Vector_iterator<>, std::_Vector_const_iterator<>
	{
		pattern=[[^std::_Vector(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("ptr", {"_Ptr"});
			sym:set_expand_member("ptr");
			return true;
		end;
	};
	-- std::_Array_iterator<>, std::_Array_const_iterator<>
	{
		pattern=[[^std::_Array(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("ptr", {"_Ptr"});
			sym:set_expand_member("ptr");
			return true;
		end;
	};
	-- std::reverse_iterator<std::_List_iterator<>, std::reverse_iterator<std::_List_const_iterator<>
	{
		pattern=[[^std::reverse_iterator<std::_List(:?_const)?_iterator<.*>$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("current", {"current"});
			return true;
		end;
	};
	-- std::reverse_iterator<std::_Tree_iterator<>, std::reverse_iterator<std::_Tree_const_iterator<>
	{
		pattern=[[^std::reverse_iterator<std::_Tree(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("current", {"current"});
			return true;
		end;
	};
	-- std::reverse_iterator<std::_String_iterator<>, std::reverse_iterator<std::_String_const_iterator<>
	{
		pattern=[[^std::reverse_iterator<std::_String(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("current", {"current"});
			return true;
		end;
	};
	-- std::reverse_iterator<std::_String_view_iterator<>
	{
		pattern=[[^std::reverse_iterator<std::_String_view_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("current", {"current"});
			return true;
		end;
	};
	-- std::reverse_iterator<std::_Vector_iterator<>, std::reverse_iterator<std::_Vector_const_iterator<>
	{
		pattern=[[^std::reverse_iterator<std::_Vector(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("current", {"current"});
			return true;
		end;
	};
	-- std::reverse_iterator<std::_Array_iterator<>, std::reverse_iterator<std::_Array_const_iterator<>
	{
		pattern=[[^std::reverse_iterator<std::_Array(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("current", {"current"});
			return true;
		end;
	};
	-- std::reverse_iterator<std::_Deque_iterator<>, std::reverse_iterator<std::_Deque_const_iterator<>
	{
		pattern=[[^std::reverse_iterator<std::_Deque(:?_const)?_iterator<.*>( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			sym:add_member_map("current", {"current"});
			return true;
		end;
	};
	-- std::filesystem::directory_entry
	{
		pattern=[[^std::filesystem::directory_entry( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local value_sym = sym:add_member_map("path", {"_Path"});
			value_sym.simple_value = true;
			sym:set_display_mem_value("path");
			return true;
		end;
	};
	-- std::filesystem::path
	{
		pattern=[[^std::filesystem::path( &)?$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local value_sym = sym:add_member_map("value", {"_Text"});
			value_sym.simple_value = true;
			sym:set_expand_member("value");
			return true;
		end;
	};

	
	-- cpp::memory::fixed_chunk<block_size, block_count>
	{
		pattern=[[^cpp::memory::fixed_chunk<.*>.*$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local chunk_info = {type_name:match([[^cpp::memory::fixed_chunk<%s*(%d+)%s*,%s*(%d+)%s*>.*$]])};
			local block_size = tonumber(chunk_info[1]);
			local block_count = tonumber(chunk_info[2]);
			sym:add_member_map("size", {"_chunk_num"}).simple_value = true;

			local first_chunk = sym:get_member_value({"_first_chunk"});
			local chunk_idx = first_chunk;
			local cumulative_count = 0;
			while chunk_idx < block_count do
				local block_sym = sym:add_member_map(("[%d]"):format(chunk_idx), {"_chunk", chunk_idx});
				block_sym:map_members();
				block_sym:add_member_map("[raw]", nil);
				local size_sym = block_sym:add_member_map("size",  {"_size"});
				local next_sym = block_sym:add_member_map("next",  {"_next"});
				local block_size = size_sym.value;
				if block_size <= 0 or block_size > block_count then
					-- incorrect block size
					break;
				end;
				cumulative_count = cumulative_count + block_size;
				if cumulative_count > block_count then
					-- incorrect chunk
					break;
				end;
				size_sym.simple_value = true;
				next_sym.simple_value = true;
				chunk_idx = next_sym.value;
				local next_val;
				if chunk_idx >= block_count then
					next_sym:set_display_value("(tail)");
					next_val = "tail";
				else
					next_val = tostring(next_sym.value);
				end;
				block_sym:set_display_value(([[(%d,%s)]]):format(size_sym.value, next_val));
			end;

			sym:add_empty_member("BLOCK_SIZE"):set_display_value(block_size);
			sym:add_empty_member("BLOCK_COUNT"):set_display_value(block_count);
			return true;
		end;
	};
	-- cpp::memory::mass_chunk<block_size, block_count>
	{
		pattern=[[^cpp::memory::mass_chunk<.*>.*$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local chunk_info = {type_name:match([[^cpp::memory::mass_chunk<%s*(%d+)%s*,%s*(%d+)%s*>.*$]])};
			local block_size = tonumber(chunk_info[1]);
			local block_count = tonumber(chunk_info[2]);
			local size_sym = sym:add_member_map("size", {"_chunk_num"});
			size_sym.simple_value = true;

			local alloc_map_sym = sym:add_member_map("alloc_map", {"_allocated_flags"});
			alloc_map_sym:add_member_map("[raw]", nil);
			alloc_map_sym:map_members();
			alloc_map_sym:add_bit_array([[%d~%d]], 32, nil);

			sym:add_member_map("first_chunk", {"_first_chunk"}).simple_value = true;
			sym:add_member_map("last_chunk", {"_last_chunk"}).simple_value = true;

			local first_chunk = sym:get_member_value({"_first_chunk"});
			local single_chunk = sym:get_member_value({"_single_chunk"});
			local chunk_idx = first_chunk;
			local cumulative_count = 0;
			while chunk_idx < block_count do
				local block_sym = sym:add_member_map(("[%d]"):format(chunk_idx), {"_chunk", chunk_idx});
				block_sym:map_members();
				block_sym:add_member_map("[raw]", nil);
				local block_size_sym = block_sym:add_member_map("size",  {"_size"});
				local next_sym = block_sym:add_member_map("next",  {"_next"});

				local block_size = block_size_sym.value;
				if block_size <= 0 or block_size > block_count then
					-- incorrect block size
					break;
				end;
				cumulative_count = cumulative_count + block_size;
				if cumulative_count > block_count then
					-- incorrect chunk
					break;
				end;

				block_size_sym.simple_value = true;
				next_sym.simple_value = true;
				chunk_idx = next_sym.value;
				local next_val;
				if chunk_idx >= block_count then
					next_sym:set_display_value("(tail)");
					next_val = "tail";
				else
					next_val = tostring(next_sym.value);
				end;
				sym:add_empty_member("BLOCK_SIZE"):set_display_value(block_size);
				sym:add_empty_member("BLOCK_COUNT"):set_display_value(block_count);
				block_sym:set_display_value(([[(%d,%s)]]):format(block_size_sym.value, next_val));
			end;

			chunk_idx = single_chunk;
			while chunk_idx < block_count do
				local block_sym = sym:add_member_map(("s[%d]"):format(chunk_idx), {"_chunk", chunk_idx});
				block_sym:map_members();
				local block_size_sym = block_sym:add_member_map("size",  {"_size"});
				local next_sym = block_sym:add_member_map("next",  {"_next"});
				local block_size = block_size_sym.value;
				if block_size ~= 1 then
					-- incorrect block size
					break;
				end;
				cumulative_count = cumulative_count + block_size;
				if cumulative_count > block_count then
					-- incorrect chunk
					break;
				end;


				block_size_sym.simple_value = true;
				next_sym.simple_value = true;
				chunk_idx = next_sym.value;
				local next_val;
				if chunk_idx >= block_count then
					next_sym:set_display_value("(tail)");
					next_val = "tail";
				else
					next_val = tostring(next_sym.value);
				end;
				block_sym:set_display_value(([[(%d,%s)]]):format(block_size_sym.value, next_val));
			end;

			sym:set_display_value(([[{free=%d,capacity=%d}]]):format(size_sym.value*block_size, block_count*block_size));
			return true;
		end;
	};
	-- cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >
	{
		pattern=[[^cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local root_sym = sym:add_member_map_ex("root", [[cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_tag*]], {"_nodes", "_first"});
			root_sym:set_typename("simple_xml::root");
			sym:set_typename("simple_xml");
			sym:set_display_mem_value("root");
			return true;
		end;
	};
	-- cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_base_t<.>
	{
		pattern=[[^cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_base_t<.*>$]];
		handler=function(self, id, type_name, sym)
			local my_type = sym:get_member_value({"type"});
			local ptr_suffix = "";
			if type_name:sub(-1) == "*" then
				ptr_suffix = "*";
			end;
			if my_type == 1 then
				sym:cast([[cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_tag]]..ptr_suffix);
			elseif my_type == 2 then
				sym:cast([[cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_text]]..ptr_suffix);
			elseif my_type == 3 then
				sym:cast([[cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_attribute]]..ptr_suffix);
			elseif my_type == 5 then
				sym:cast([[cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_comment]]..ptr_suffix);
			end;
			return true;
		end;
	};
	-- cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_nodes::_xml_node_iterator_t<.>
	{
		pattern=[[^cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_nodes::_xml_node_iterator_t<.*>$]];
		handler=function(self, id, type_name, sym)
			local iter_type = tonumber(type_name:sub(-2,-2));
			local iter_type_map = {
				"simple_xml::tag_iterator",
				"simple_xml::text_iterator",
				"simple_xml::attr_iterator",
				"simple_xml::comment_iterator"
			};
			local type_name = iter_type_map[iter_type];
			if type_name then
				sym:set_typename(type_name);
			end;
			sym:set_expand_member("_cur_node");
			return true;
		end;
	};
	-- cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_tag
	{
		pattern=[[^cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_tag$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			-- sym:add_member_map("[raw]", nil);
			local name_sym = sym:add_member_map("name", {"_name"});
			sym:set_display_mem_value("name");
			local value = name_sym:get_member_value({"ptr"});
			value = value:gsub([["(.*)"]],"<%1>");
			sym:set_typename("simple_xml::tag");
			sym:set_display_value(value);
			sym:add_multi_linked_list("[%d]", 99, {"_first"}, {{"_next"}}, nil, {"_last"}, {"type"}, 0);
			return true;
		end;
	};
	-- cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_text
	{
		pattern=[[^cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_text$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			-- sym:add_member_map("[raw]", nil);
			local text_sym = sym:add_member_map("text", {"_text"});
			sym:set_display_mem_value("text");
			local value = text_sym:get_member_value({"ptr"});
			sym:set_typename("simple_xml::text");
			sym:set_display_value(value);
			return true;
		end;
	};
	-- cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_comment
	{
		pattern=[[^cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_comment$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			-- sym:add_member_map("[raw]", nil);
			local comment_sym = sym:add_member_map("comment", {"_data"});
			sym:set_display_mem_value("comment");
			local value = comment_sym:get_member_value({"ptr"});
			sym:set_typename("simple_xml::comment");
			value = value:gsub([["(.*)"]],"<!-- %1 -->");
			sym:set_display_value(value);
			return true;
		end;
	};
	-- cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_attribute
	{
		pattern=[[^cpp::utils::xml_t<cpp::utils::xml_parser_t<cpp::utils::xml_t> >::_xml_node_attribute$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			-- sym:add_member_map("[raw]", nil);
			local key_sym = sym:add_member_map("key", {"_name"});
			local value_sym = sym:add_member_map("value", {"_value"});
			sym:set_display_mem_value("key");

			local key = key_sym:get_member_value({"ptr"});
			local value = value_sym:get_member_value({"ptr"});
			sym:set_typename("simple_xml::attribute");
			key = key:gsub([["(.*)"]],"%1");
			sym:set_display_value(([[%s=%s]]):format(key, value));
			return true;
		end;
	};
	-- union cpp::utils::__xml_private::_xml_parser_common::_simple_string
	{
		pattern=[[^union cpp::utils::(__xml_private::_xml_parser_common::_simple_string|.*::_xml_string)$]];
		handler=function(self, id, type_name, sym)
			sym:map_members();
			sym:add_member_map("[raw]", nil);
			local inline_size = sym:get_member_value({"_inline_size"});
			local size_sym;
			local value;
			local size;
			if inline_size >= 0x80 then
				-- is inline text
				size_sym = sym:add_empty_member("size");
				size = inline_size-0x80;
				size_sym:set_display_value( size );
				value = sym:add_member_map("ptr", {"_inline_buf"});
			else
				size_sym = sym:add_member_map("size", {"_size"});
				size_sym.simple_value = true;
				size = size_sym.value;
				value = sym:add_member_map("ptr", {"_buf"});
			end;
			-- make ptr as the string's value member
			sym:set_display_mem_value("ptr");
			-- override value with custom format
			sym:set_typename("simple_xml::string");
			sym:set_display_value(([[{size=%d,%s}]]):format(size, value.value));
			return true;
		end;
	};
	-- cpp::utils::smart_ptr_t<.*,cpp::utils::external_reference_policy_t<.*>,.*>
	{
		pattern=[[^cpp::utils::smart_ptr_t<.*,cpp::utils::external_reference_policy_t<.*>,.*>$]];
		handler=function(self, id, type_name, sym)
			sym:add_member_map("[raw]", nil);
			local member_val = sym:get_member_value({"_instance", "_counter", "_instance"});
			if not member_val or member_val == 0 then
				sym:set_display_value("(empty)");
				return true;
			end;
			local ref_sym = sym:add_member_map("ref", {"_instance", "_counter", "_instance"});
			ref_sym.simple_value = true;
			local ptr_sym = sym:add_member_map("ptr", {"_instance", "_obj"});

			sym:set_display_value(([[{ref=%d,0x%X}]]):format(ref_sym.value, ptr_sym.value));
			sym:set_expand_member("ptr");
			return true;
		end;
	};
	-- cpp::utils::smart_ptr_t<.*,cpp::utils::reference_counter_policy_t<.*>,.*>
	{
		pattern=[[^cpp::utils::smart_ptr_t<.*,cpp::utils::reference_counter_policy_t<.*>,.*>$]];
		handler=function(self, id, type_name, sym)
			local member_val = sym:get_member_value({"_instance"});
			if not member_val or member_val == 0 then
				sym:set_display_value("(empty)");
				return true;
			end;
			local ptr_sym = sym:add_member_map("ptr", {"_instance"});
			sym:set_expand_member("ptr");
			return true;
		end;
	};
};

wdbg_beautifier = edx.get_debugger_beautifier("windbg");

function wdbg_beautifier.on_beautify_symbol(self, id, type_name, sym)
	local handler = self.__beautifiers[id];
	if not handler then
		return false;
	end;
	return handler(id, type_name, sym);
end;

local wdbg_beautifier_map = {};

for i, obj in ipairs(beautifiers) do
	if obj.pattern then
		local idx = wdbg_beautifier:add_beautify_pattern(obj.pattern);
		wdbg_beautifier_map[idx] = (function(the_obj)
				return function(...)
					return the_obj:handler(...);
				end;
		end)(obj);
	end;
end;

wdbg_beautifier.__beautifiers = wdbg_beautifier_map;

print( "load windbg beautifier ok!");
