for (size_t i = 0; i < numElements;) {
		for (size_t j = leftStart; j < numElements; j++) {
			if (!tmpList[j].location) {
				if ((j - leftStart) == 1) leftStart = j;
				continue;
			}
			if (tmpList[j].location == locStart) {
				if (j != i) questList[i] = tmpList[j];
				if (++i >= numElements) break;
				tmpList[j].location = 0;
			}
		}
		if (++locStart > locLast) break;
	}

/*
 *    sfall
 *
 */

#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
#include "LoadGameHook.h"

#include "QuestList.h"

namespace sfall
{

enum ExitCode : int {
	Break = -1,
	Normal,
	Error,
	NextQuest
};

static int questsButtonsType;
static int questsScrollButtonsX;
static int questsScrollButtonsY;

static bool buttonsPressed = false;
static bool outRangeFlag = false;
static bool pageFlag = false;
static bool closeFlag = false;
static bool InQuestsList = false;

static bool calledflag = false;
static DWORD called_quest_number = 0;
static DWORD total_quests_pages = 0;
static DWORD curent_quest_page = 0;
static DWORD look_quests = 0; // check current quests

static DWORD first_quest_page = 0;
static DWORD last_quest_page = INT_MAX;

static std::vector<int> pageQuest;

// Fix crash when the quest list is too long
static void __declspec(naked) PipStatus_hook_printfix() {
	__asm {
		test outRangeFlag, 0xFF;
		jnz  force;
		call fo::funcoffs::_word_wrap_;
		push eax;
		movzx eax, word ptr [esp + 0x49C + 8];
		dec  eax;
		shl  eax, 1;
		add  eax, dword ptr ds:[FO_VAR_cursor_line];
		cmp  eax, dword ptr ds:[FO_VAR_bottom_line];  // check max
		jb   skip;
		mov  eax, dword ptr ds:[FO_VAR_quest_count];
		sub  eax, 2;
		mov  dword ptr [esp + 0x4BC - 0x24 + 8], eax; // set last counter
		mov  outRangeFlag, 1;
skip:
		pop  eax;
		retn;
force:
		or   eax, -1; // force log error "out of range"
		mov  outRangeFlag, 0;
		retn;
	}
}

// Add an unused bit for an additional text offset 60 pixels to the right
// it might be needed outside of the function to display quest list pages
static void __declspec(naked) pip_print_hack() {
	__asm {
		test bh, 1;
		jz   skip;
		add  edx, 60; // pixel offset
		jmp  end;
skip:
		test bh, 2;
		jz   end;
		retn;
end:
		add  dword ptr [esp], 0x14;
		retn;
	}
}

static void ResetPageValues() {
	if (total_quests_pages > 0) pageQuest.resize(1);

	pageFlag = false;
	curent_quest_page = 0;
	total_quests_pages = 0;
	first_quest_page = 0;
	last_quest_page = INT_MAX;
}

// Event of entering the quest list and up/down keystrokes
static void __declspec(naked) pipboy_hack_press0() {
	__asm {
		// fixed vanilla bug, preventing displaying the quest list of other locations when clicking on the pipboy screen
		test InQuestsList, 0xFF;
		jz   skip;
		test buttonsPressed, 0xFF;
		jnz  skip;
		add  dword ptr [esp], 0x0E;
		retn;
skip:
		mov  calledflag, 1;
		mov  called_quest_number, ebx
		// engine
		mov  edx, dword ptr ds:[FO_VAR_crnt_func];
		retn;
	}
}

// Pipboy keystroke event
static void __declspec(naked) pipboy_hack_press1() {
	__asm {
		mov  InQuestsList, 0;
		mov  calledflag, 0;
		test pageFlag, 0xFF;
		jz   skip;
		push eax;
		push edx;
		push ecx;
		call ResetPageValues;
		pop  ecx;
		pop  edx;
		pop  eax;
skip:
		// engine
		sub ebx, 0x1F4;
		retn;
	}
}

// Press back button
static void __declspec(naked) pipboy_hack_back() {
	__asm {
		mov  InQuestsList, 0;
		mov  calledflag, 0;
		test pageFlag, 0xFF;
		jz   skip;
		push eax;
		push edx;
		push ecx;
		call ResetPageValues;
		pop  ecx;
		pop  edx;
		pop  eax;
skip:
		// engine
		mov eax, 0x401;
		retn;
	}
}

static void AddPage(int lines) {
	total_quests_pages++;
	pageQuest.push_back(look_quests); // add the quest number to array at top of page
	fo::var::cursor_line = 3 + lines; // reset current line to beginning, and add text lines
	outRangeFlag = true;
}

// Print quests page text
static long __fastcall QuestsPrint(BYTE* count, int width, DWORD* buf, const char* text) {
	look_quests++; // quests counter

	if (outRangeFlag) {
		if (pageFlag) return ExitCode::Break; // pages are already counted
		// count the number of pages
		fo::func::_word_wrap(text, width, buf, count);

		// check whether the text of the quest leaves the current page
		int lines = 2 * ((int)*count - 1); // number of lines of text
		if (fo::var::cursor_line + lines >= fo::var::bottom_line) {
			AddPage(lines);                // quest does not fit in the current page, we add a page
		} else {
			fo::var::cursor_line += lines;
		}
		return ExitCode::NextQuest;
	}

	// check if current quest is in range
	if (look_quests < first_quest_page) { // check lower range
		return ExitCode::NextQuest;
	}
	if (look_quests > last_quest_page) {  // check upper range
		return ExitCode::Break;           // exit from quests loop
	}

	if (fo::func::_word_wrap(text, width, buf, count) == -1) return ExitCode::Error; // error wrap

	if (!pageFlag || last_quest_page == INT_MAX) {        // pages have not been calculated yet
		// check whether the text of the quest leaves the current page
		int lines = 2 * ((int)*count - 1);
		if (fo::var::cursor_line + lines >= fo::var::bottom_line) {
			AddPage(lines); // quest does not fit in the current page, we add a page
			return ExitCode::NextQuest;
		}
	}
	return ExitCode::Normal;
}

static void __declspec(naked) PipStatus_hack_print() {
	static const DWORD PipStatus_NormalRet = 0x49818B;
	static const DWORD PipStatus_NextRet   = 0x498237;
	static const DWORD PipStatus_BreakRet  = 0x4982A4;
	__asm {
		push ecx;
		push edx;
		push eax;         // text
		push ebx;         // buf
		call QuestsPrint; // ecx - count, edx - width
		pop  edx;
		pop  ecx;
		cmp  eax, 0;
		jl   jbreak;
		cmp  eax, 1;
		jg   jnext;
		jmp  PipStatus_NormalRet;
jnext:
		jmp  PipStatus_NextRet;
jbreak:
		jmp  PipStatus_BreakRet;
	}
}

static char bufPage[16];
static const char* format = "%s %d %s %d";

static void __declspec(naked) PrintPages() {
	__asm {
		// total pages
		mov  eax, total_quests_pages;
		inc  eax;
		push eax;
		mov  ebx, 212;                      // message
		mov  edx, FO_VAR_pipmesg;
		mov  eax, FO_VAR_pipboy_message_file;
		call fo::funcoffs::getmsg_;
		push eax;
		// current page
		mov  eax, curent_quest_page;
		inc  eax;
		push eax;
		mov  ebx, 213;                      // message
		mov  edx, FO_VAR_pipmesg;
		mov  eax, FO_VAR_pipboy_message_file;
		call fo::funcoffs::getmsg_;
		push eax;

		push format;
		lea  eax, [bufPage];
		push eax;                           // text buf
		call fo::funcoffs::sprintf_;
		add  esp, 0x18;

		mov  ebx, 1;
		mov  dword ptr ds:[FO_VAR_cursor_line], ebx;
		mov  bl, byte ptr ds:[FO_VAR_GreenColor];
		mov  edx, 0x21;
		lea  eax, [bufPage];
		jmp  fo::funcoffs::pip_print_;
	}
}

static void __declspec(naked) PipStatus_hook_end() {
	__asm {
		call fo::funcoffs::pip_back_;
		test total_quests_pages, 0xFF;
		jz   skip;
		push edx;
		call PrintPages;
		pop  edx;
skip:
		mov  look_quests, 0;
		mov  outRangeFlag, 0;
		mov  pageFlag, 1;     // pages are calculated, there is no need to do it again
		mov  closeFlag, 1;    // set flag, need to reset on close pipboy
		mov  InQuestsList, 1; // flag for fix bug
		retn;
	}
}

static DWORD __fastcall ActionButtons(DWORD key) {
	buttonsPressed = false;
	if (key == 0x300) { // up
		if (curent_quest_page == 0) return -1;
		last_quest_page = pageQuest[curent_quest_page] - 1;
		curent_quest_page--;
		first_quest_page = pageQuest[curent_quest_page];
		buttonsPressed = true;
		return called_quest_number;
	}
	if (key == 0x301) { // down
		if (curent_quest_page < total_quests_pages) {
			curent_quest_page++;
			first_quest_page = pageQuest[curent_quest_page];
			last_quest_page  = ((pageQuest.size() - 1) > curent_quest_page)
			                 ? pageQuest[curent_quest_page + 1] - 1
			                 : INT_MAX;
			buttonsPressed = true;
			return called_quest_number;
		}
	}
	return -1;
}

static void __declspec(naked) pipboy_hack_action() {
	__asm {
		test calledflag, 0xFF;
		jz   skip;
		push eax;
		push edx;
		mov  ecx, ebx;
		call ActionButtons;
		cmp  eax, -1;
		cmovne ebx, eax; // called_quest_number
		pop  edx;
		pop  eax;
		xor  ecx, ecx;
skip:
		// engine
		cmp  ebx, 0x1F4;
		retn;
	}
}

static void RegisterButtonSound() {
	__asm {
		mov  ebx, fo::funcoffs::gsound_red_butt_release_;
		mov  edx, fo::funcoffs::gsound_red_butt_press_;
		call fo::funcoffs::win_register_button_sound_func_; // eax - register button
	}
}

static void LoadArtButton(DWORD buttonKey, DWORD buttonMem, DWORD indexArt) { // indexArt - index from intrface.lst
	long artId = fo::func::art_id(fo::ArtType::OBJ_TYPE_INTRFACE, indexArt, 0, 0, 0);
	*(BYTE**)buttonMem = fo::func::art_ptr_lock_data(artId, 0, 0, (DWORD*)buttonKey); // first texture memory address
}

// Create buttons
static void __declspec(naked) StartPipboy_hack() {
	__asm {
		push edi;
		mov  ebp, esp; // prolog
		sub  esp, __LOCAL_SIZE;
	}

	DWORD xPos, yPos, height, width, winRef;
	BYTE *picDown, *picUp;

	int indexUpArt0;   // number from intrface.lst for dn button-up
	int indexDownArt0; // for dn button-down
	int indexUpArt1;   // for up button-up
	int indexDownArt1; // for up button-down

	if (questsButtonsType > 1) {
		height = 23;
		width = 22;

		indexUpArt0   = 54;
		indexDownArt0 = 52;
		indexUpArt1   = 53;
		indexDownArt1 = 50;
	} else {
		height = 14;
		width = 11;

		indexUpArt0   = 181;
		indexDownArt0 = 182;
		indexUpArt1   = 199;
		indexDownArt1 = 200;
	}

	// Load new texture for first (up) button. I used memory address for texture from buttons at chracter screen.
	// Everything fine, because this buttons can't use in one time, and they everytime recreating.
	// Down
	LoadArtButton(FO_VAR_optionsButtonUpKey,   FO_VAR_optionsButtonUp,   indexUpArt0);
	LoadArtButton(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown, indexDownArt0);
	// Up
	LoadArtButton(FO_VAR_optionsButtonUpKey,   FO_VAR_optionsButtonUp1,   indexUpArt1);
	LoadArtButton(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown1, indexDownArt1);

	xPos = questsScrollButtonsX;
	yPos = questsScrollButtonsY;
	winRef = fo::var::pip_win;

	picDown = (BYTE*)fo::var::optionsButtonDown1;
	picUp   = (BYTE*)fo::var::optionsButtonUp1;
	if (fo::func::win_register_button(winRef, xPos, yPos, width, height, -1, -1, -1, 0x300, picUp,  picDown, 0, 32) != -1) {
		RegisterButtonSound();
	}

	picDown = (BYTE*)fo::var::optionsButtonDown;
	picUp   = (BYTE*)fo::var::optionsButtonUp;
	if (fo::func::win_register_button(winRef, xPos, yPos + height, width, height, -1, -1, -1, 0x301, picUp,  picDown, 0, 32) != -1) {
		RegisterButtonSound();
	}

	__asm {
		mov  esp, ebp;   // epilog
		pop  edi;
		mov  ebp, 0x1F4; // overwrite engine code
		retn;
	}
}

// Reset states when closing pipboy
static void __declspec(naked) pipboy_hook() {
	__asm {
		call fo::funcoffs::EndPipboy_;
		test closeFlag, 0xFF;
		jz   skip;
		call ResetPageValues;
		mov  closeFlag, 0;
skip:
		mov  calledflag, 0;
		mov  InQuestsList, 0;
		retn;
	}
}

static void __fastcall QuestListSort(fo::QuestData* questList, size_t numElements) {
	if (numElements <= 1) return;

	fo::QuestData* tmpList = new fo::QuestData[numElements];
	std::memcpy(tmpList, questList, numElements * sizeof(fo::QuestData));

	long locStart = 1500; // message number from which the locations starting
	size_t leftStart = 0;
	long locLast = 0;

	for (size_t i = 0; i < numElements; i++) {
		long loc = tmpList[i].location;
		if (locStart > loc) locStart = loc;
		if (loc > locLast) locLast = loc;
	}

	delete[] tmpList;
}

static void __declspec(naked) quest_init_hook() {
	__asm {
		mov  ecx, eax;      // questList (base)
		jmp  QuestListSort; // edx - numElements
	}
}

void QuestListPatch() {
	MakeCall(0x4974E4, StartPipboy_hack);

	MakeCall(0x497173, pipboy_hack_action, 1);

	MakeCall(0x4971B2, pipboy_hack_press0, 1);
	MakeCall(0x497183, pipboy_hack_press1, 1);

	MakeCall(0x4971D9, pipboy_hack_back);
	HookCall(0x497219, pipboy_hook);

	MakeJump(0x498186, PipStatus_hack_print);
	HookCall(0x4982B0, PipStatus_hook_end);

	MakeCall(0x497A7D, pip_print_hack);
}

struct QuestFailure {
	long gvarNum;
	long failureVal;
};

std::vector<QuestFailure> questFailures;

static long FindGVarQuestFailure(long globalVarNum) {
	for (size_t i = 0; i < questFailures.size(); i++) {
		if (questFailures[i].gvarNum == globalVarNum) return i;
	}
	return -1;
}

void QuestList::AddQuestFailureValue(long globalVarNum, long failureThreshold) {
	long index = FindGVarQuestFailure(globalVarNum);
	if (index == -1) {
		questFailures.push_back({ globalVarNum, failureThreshold });
	} else {
		questFailures[index].failureVal = failureThreshold;
	}
}

static BYTE __fastcall CheckQuestFailureState(fo::QuestData* quest, BYTE completeColor) {
	if (questFailures.empty()) return completeColor;

	const BYTE failureColor = 137; // dark red

	long index = FindGVarQuestFailure(quest->gvarIndex);
	return (index != -1 && fo::var::game_global_vars[quest->gvarIndex] >= questFailures[index].failureVal) ? failureColor : completeColor;
}

static void __declspec(naked) PipStatus_hack() {
	__asm {
		push eax;
		push ecx;
		mov  dl, ds:[0x6A5B34]; // completeColor (dark green)
		mov  ecx, ds:[FO_VAR_quests];
		add  ecx, [esp + 0x4BC - 0x28 + 12];
		call CheckQuestFailureState;
		mov  bl, al;
		pop  ecx;
		pop  eax;
		retn;
	}
}

static void ResetQuests() {
	questFailures.clear();
}

void QuestList::init() {
	LoadGameHook::OnGameReset() += ResetQuests;

	MakeCall(0x498222, PipStatus_hack, 1);

	questsButtonsType = IniReader::GetConfigInt("Misc", "UseScrollingQuestsList", 0);
	if (questsButtonsType > 0) {
		dlog("Applying quests list patch.", DL_INIT);
		QuestListPatch();

		questsScrollButtonsX = IniReader::GetConfigInt("Misc", "QuestsScrollButtonsX", 140);
		if (questsScrollButtonsX < 0 || questsScrollButtonsX > 618) questsScrollButtonsX = 140;
		questsScrollButtonsY = IniReader::GetConfigInt("Misc", "QuestsScrollButtonsY", 334);
		if (questsScrollButtonsY < 0 || questsScrollButtonsY > 434) questsScrollButtonsY = 334;

		pageQuest.reserve(4); // init
		pageQuest.push_back(1);

		dlogr(" Done", DL_INIT);
	} else {
		HookCall(0x498186, PipStatus_hook_printfix); // fix "out of bounds" bug when printing a list of quests
	}

	// Replace the qsort_ unstable sorting function with a simple stable sorting algorithm
	HookCall(0x49A7C2, quest_init_hook);
}

}


/*
 *    sfall
 *
 */

#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
#include "LoadGameHook.h"

#include "QuestList.h"

namespace sfall
{

enum ExitCode : int {
	Break = -1,
	Normal,
	Error,
	NextQuest
};

static int questsButtonsType;
static int questsScrollButtonsX;
static int questsScrollButtonsY;

static bool buttonsPressed = false;
static bool outRangeFlag = false;
static bool pageFlag = false;
static bool closeFlag = false;
static bool InQuestsList = false;

static bool calledflag = false;
static DWORD called_quest_number = 0;
static DWORD total_quests_pages = 0;
static DWORD curent_quest_page = 0;
static DWORD look_quests = 0; // check current quests

static DWORD first_quest_page = 0;
static DWORD last_quest_page = INT_MAX;

static std::vector<int> pageQuest;

// Fix crash when the quest list is too long
static void __declspec(naked) PipStatus_hook_printfix() {
	__asm {
		test outRangeFlag, 0xFF;
		jnz  force;
		call fo::funcoffs::_word_wrap_;
		push eax;
		movzx eax, word ptr [esp + 0x49C + 8];
		dec  eax;
		shl  eax, 1;
		add  eax, dword ptr ds:[FO_VAR_cursor_line];
		cmp  eax, dword ptr ds:[FO_V

AR_bottom_line];  // check max
		jb   skip;
		mov  eax, dword ptr ds:[FO_VAR_quest_count];
		sub  eax, 2;
		mov  dword ptr [esp + 0x4BC - 0x24 + 8], eax; // set last counter
		mov  outRangeFlag, 1;
skip:
		pop  eax;
		retn;
force:
		or   eax, -1; // force log error "out of range"
		mov  outRangeFlag, 0;
		retn;
	}
}

// Add an unused bit for an additional text offset 60 pixels to the right
// it might be needed outside of the function to display quest list pages
static void __declspec(naked) pip_print_hack() {
	__asm {
		test bh, 1;
		jz   skip;
		add  edx, 60; // pixel offset
		jmp  end;
skip:
		test bh, 2;
		jz   end;
		retn;
end:
		add  dword ptr [esp], 0x14;
		retn;
	}
}

static void ResetPageValues() {
	if (total_quests_pages > 0) pageQuest.resize(1);

	pageFlag = false;
	curent_quest_page = 0;
	total_quests_pages = 0;
	first_quest_page = 0;
	last_quest_page = INT_MAX;
}

// Event of entering the quest list and up/down keystrokes
static void __declspec(naked) pipboy_hack_press0() {
	__asm {
		// fixed vanilla bug, preventing displaying the quest list of other locations when clicking on the pipboy screen
		test InQuestsList, 0xFF;
		jz   skip;
		test buttonsPressed, 0xFF;
		jnz  skip;
		add  dword ptr [esp], 0x0E;
		retn;
skip:
		mov  calledflag, 1;
		mov  called_quest_number, ebx
		// engine
		mov  edx, dword ptr ds:[FO_VAR_crnt_func];
		retn;
	}
}

// Pipboy keystroke event
static void __declspec(naked) pipboy_hack_press1() {
	__asm {
		mov  InQuestsList, 0;
		mov  calledflag, 0;
		test pageFlag, 0xFF;
		jz   skip;
		push eax;
		push edx;
		push ecx;
		call ResetPageValues;
		pop  ecx;
		pop  edx;
		pop  eax;
skip:
		// engine
		sub ebx, 0x1F4;
		retn;
	}
}

// Press back button
static void __declspec(naked) pipboy_hack_back() {
	__asm {
		mov  InQuestsList, 0;
		mov  calledflag, 0;
		test pageFlag, 0xFF;
		jz   skip;
		push eax;
		push edx;
		push ecx;
		call ResetPageValues;
		pop  ecx;
		pop  edx;
		pop  eax;
skip:
		// engine
		mov eax, 0x401;
		retn;
	}
}

static void AddPage(int lines) {
	total_quests_pages++;
	pageQuest.push_back(look_quests); // add the quest number to array at top of page
	fo::var::cursor_line = 3 + lines; // reset current line to beginning, and add text lines
	outRangeFlag = true;
}

// Print quests page text
static long __fastcall QuestsPrint(BYTE* count, int width, DWORD* buf, const char* text) {
	look_quests++; // quests counter

	if (outRangeFlag) {
		if (pageFlag) return ExitCode::Break; // pages are already counted
		// count the number of pages
		fo::func::_word_wrap(text, width, buf, count);

		// check whether the text of the quest leaves the current page
		int lines = 2 * ((int)*count - 1); // number of lines of text
		if (fo::var::cursor_line + lines >= fo::var::bottom_line) {
			AddPage(lines);                // quest does not fit in the current page, we add a page
		} else {
			fo::var::cursor_line += lines;
		}
		return ExitCode::NextQuest;
	}

	// check if current quest is in range
	if (look_quests < first_quest_page) { // check lower range
		return ExitCode::NextQuest;
	}
	if (look_quests > last_quest_page) {  // check upper range
		return ExitCode::Break;           // exit from quests loop
	}

	if (fo::func::_word_wrap(text, width, buf, count) == -1) return ExitCode::Error; // error wrap

	if (!pageFlag || last_quest_page == INT_MAX) {        // pages have not been calculated yet
		// check whether the text of the quest leaves the current page
		int lines = 2 * ((int)*count - 1);
		if (fo::var::cursor_line + lines >= fo::var::bottom_line) {
			AddPage(lines); // quest does not fit in the current page, we add a page
			return ExitCode::NextQuest;
		}
	}
	return ExitCode::Normal;
}

static void __declspec(naked) PipStatus_hack_print() {
	static const DWORD PipStatus_NormalRet = 0x49818B;
	static const DWORD PipStatus_NextRet   = 0x498237;
	static const DWORD PipStatus_BreakRet  = 0x4982A4;
	__asm {
		push ecx;
		push edx;
		push eax;         // text
		push ebx;         // buf
		call QuestsPrint; // ecx - count, edx - width
		pop  edx;
		pop  ecx;
		cmp  eax, 0;
		jl   jbreak;
		cmp  eax, 1;
		jg   jnext;
		jmp  PipStatus_NormalRet;
jnext:
		jmp  PipStatus_NextRet;
jbreak:
		jmp  PipStatus_BreakRet;
	}
}

static char bufPage[16];
static const char* format = "%s %d %s %d";

static void __declspec(naked) PrintPages() {
	__asm {
		// total pages
		mov  eax, total_quests_pages;
		inc  eax;
		push eax;
		mov  ebx, 212;                      // message
		mov  edx, FO_VAR_pipmesg;
		mov  eax, FO_VAR_pipboy_message_file;
		call fo::funcoffs::getmsg_;
		push eax;
		// current page
		mov  eax, curent_quest_page;
		inc  eax;
		push eax;
		mov  ebx, 213;                      // message
		mov  edx, FO_VAR_pipmesg;
		mov  eax, FO_VAR_pipboy_message_file;
		call fo::funcoffs::getmsg_;
		push eax;

		push format;
		lea  eax, [bufPage];
		push eax;                           // text buf
		call fo::funcoffs::sprintf_;
		add  esp, 0x18;

		mov  ebx, 1;
		mov  dword ptr ds:[FO_VAR_cursor_line], ebx;
		mov  bl, byte ptr ds:[FO_VAR_GreenColor];
		mov  edx, 0x21;
		lea  eax, [bufPage];
		jmp  fo::funcoffs::pip_print_;
	}
}

static void __declspec(naked) PipStatus_hook_end() {
	__asm {
		call fo::funcoffs::pip_back_;
		test total_quests_pages, 0xFF;
		jz   skip;
		push edx;
		call PrintPages;
		pop  edx;
skip:
		mov  look_quests, 0;
		mov  outRangeFlag, 0;
		mov  pageFlag, 1;     // pages are calculated, there is no need to do it again
		mov  closeFlag, 1;    // set flag, need to reset on close pipboy
		mov  InQuestsList, 1; // flag for fix bug
		retn;
	}
}

static DWORD __fastcall ActionButtons(DWORD key) {
	buttonsPressed = false;
	if (key == 0x300) { // up
		if (curent_quest_page == 0) return -1;
		last_quest_page = pageQuest[curent_quest_page] - 1;
		curent_quest_page--;
		first_quest_page = pageQuest[curent_quest_page];
		buttonsPressed = true;
		return called_quest_number;
	}
	if (key == 0x301) { // down
		if (curent_quest_page < total_quests_pages) {
			curent_quest_page++;
			first_quest_page = pageQuest[curent_quest_page];
			last_quest_page  = ((pageQuest.size() - 1) > curent_quest_page)
			                 ? pageQuest[curent_quest_page + 1] - 1
			                 : INT_MAX;
			buttonsPressed = true;
			return called_quest_number;
		}
	}
	return -1;
}

static void __declspec(naked) pipboy_hack_action() {
	__asm {
		test calledflag, 0xFF;
		jz   skip;
		push eax;
		push edx;
		mov  ecx, ebx;
		call ActionButtons;
		cmp  eax, -1;
		cmovne ebx, eax; // called_quest_number
		pop  edx;
		pop  eax;
		xor  ecx, ecx;
skip:
		// engine
		cmp  ebx, 0x1F4;
		retn;
	}
}

static void RegisterButtonSound() {
	__asm {
		mov  ebx, fo::funcoffs::gsound_red_butt_release_;
		mov  edx, fo::funcoffs::gsound_red_butt_press_;
		call fo::funcoffs::win_register_button_sound_func_; // eax - register button
	}
}

static void LoadArtButton(DWORD buttonKey, DWORD buttonMem, DWORD indexArt) { // indexArt - index from intrface.lst
	long artId = fo::func::art_id(fo::ArtType::OBJ_TYPE_INTRFACE, indexArt, 0, 0, 0);
	*(BYTE**)buttonMem = fo::func::art_ptr_lock_data(artId, 0, 0, (DWORD*)buttonKey); // first texture memory address
}

// Create buttons
static void __declspec(naked) StartPipboy_hack() {
	__asm {
		push edi;
		mov  ebp, esp; // prolog
		sub  esp, __LOCAL_SIZE;
	}

	DWORD xPos, yPos, height, width, winRef;
	BYTE *picDown, *picUp;

	int indexUpArt0;   // number from intrface.lst for dn button-up
	int indexDownArt0; // for dn button-down
	int indexUpArt1;   // for up button-up
	int indexDownArt1; // for up button-down

	if (questsButtonsType > 1) {
		height = 23;
		width = 22;

		indexUpArt0   = 54;
		indexDownArt0 = 52;
		indexUpArt1   = 53;
		indexDownArt1 = 50;
	} else {
		height = 14;
		width = 11;

		indexUpArt0   = 181;
		indexDownArt0 = 182;
		indexUpArt1   = 199;
		indexDownArt1 = 200;
	}

	// Load new texture for first (up) button. I used memory address for texture from buttons at chracter screen.
	// Everything fine, because this buttons can't use in one time, and they everytime recreating.
	// Down
	LoadArtButton(FO_VAR_optionsButtonUpKey,   FO_VAR_optionsButtonUp,   indexUpArt0);
	LoadArtButton(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown, indexDownArt0);
	// Up
	LoadArtButton(FO_VAR_optionsButtonUpKey,   FO_VAR_optionsButtonUp1,   indexUpArt1);
	LoadArtButton(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown1, indexDownArt1);

	xPos = questsScrollButtonsX;
	yPos = questsScrollButtonsY;
	winRef = fo::var::pip_win;

	picDown = (BYTE*)fo::var::optionsButtonDown1;
	picUp   = (BYTE*)fo::var::optionsButtonUp1;
	if (fo::func::win_register_button(winRef, xPos, yPos, width, height, -1, -1, -1, 0x300, picUp,  picDown, 0, 32) != -1) {
		RegisterButtonSound();
	}

	picDown = (BYTE*)fo::var::optionsButtonDown;
	picUp   = (BYTE*)fo::var::optionsButtonUp;
	if (fo::func::win_register_button(winRef, xPos, yPos + height, width, height, -1, -1, -1, 0x301, picUp,  picDown, 0, 32) != -1) {
		RegisterButtonSound();
	}

	__asm {
		mov  esp, ebp;   // epilog
		pop  edi;
		mov  ebp, 0x1F4; // overwrite engine code
		retn;
	}
}

// Reset states when closing pipboy
static void __declspec(naked) pipboy_hook() {
	__asm {
		call fo::funcoffs::EndPipboy_;
		test closeFlag, 0xFF;
		jz   skip;
		call ResetPageValues;
		mov  closeFlag, 0;
skip:
		mov  calledflag, 0;
		mov  InQuestsList, 0;
		retn;
	}
}

static void __fastcall QuestListSort(fo::QuestData* questList, size_t numElements) {
	if (numElements <= 1) return;

	fo::QuestData* tmpList = new fo::QuestData[numElements];
	std::memcpy(tmpList, questList, numElements * sizeof(fo::QuestData));

	long locStart = 1500; // message number from which the locations starting
	size_t leftStart = 0;
	long locLast = 0;

	for (size_t i = 0; i < numElements; i++) {
		long loc = tmpList[i].location;
		if (locStart > loc) locStart = loc;
		if (loc > locLast) locLast = loc;
	}

	for (size_t i = 0; i < numElements;) {
		for (size_t j = leftStart; j < numElements; j++) {
			if (!tmpList[j].location) {
				if ((j - leftStart) == 1) leftStart = j;
				continue;
			}
			if (tmpList[j].location == locStart) {
				if (j != i) questList[i] = tmpList[j];
				if (++i >= numElements) break;
				tmpList[j].location = 0;
			}
		}
		if (++locStart > locLast) break;
	}
	delete[] tmpList;
}

static void __declspec(naked) quest_init_hook() {
	__asm {
		mov  ecx, eax;      // questList (base)
		jmp  QuestListSort; // edx - numElements
	}
}

void QuestListPatch() {
	MakeCall(0x4974E4, StartPipboy_hack);

	MakeCall(0x497173, pipboy_hack_action, 1);

	MakeCall(0x4971B2, pipboy_hack_press0, 1);
	MakeCall(0x497183, pipboy_hack_press1, 1);

	MakeCall(0x4971D9, pipboy_hack_back);
	HookCall(0x497219, pipboy_hook);

	MakeJump(0x498186, PipStatus_hack_print);
	HookCall(0x4982B0, PipStatus_hook_end);

	MakeCall(0x497A7D, pip_print_hack);
}

struct QuestFailure {
	long gvarNum;
	long failureVal;
};

std::vector<QuestFailure> questFailures;

static long FindGVarQuestFailure(long globalVarNum) {
	for (size_t i = 0; i < questFailures.size(); i++) {
		if (questFailures[i].gvarNum == globalVarNum) return i;
	}
	return -1;
}

void QuestList::AddQuestFailureValue(long globalVarNum, long failureThreshold) {
	long index = FindGVarQuestFailure(globalVarNum);
	if (index == -1) {
		questFailures.push_back({ globalVarNum, failureThreshold });
	} else {
		questFailures[index].failureVal = failureThreshold;
	}
}

static BYTE __fastcall CheckQuestFailureState(fo::QuestData* quest, BYTE completeColor) {
	if (questFailures.empty()) return completeColor;

	const BYTE failureColor = 137; // dark red

	long index = FindGVarQuestFailure(quest->gvarIndex);
	return (index != -1 && fo::var::game_global_vars[quest->gvarIndex] >= questFailures[index].failureVal) ? failureColor : completeColor;
}

static void __declspec(naked) PipStatus_hack() {
	__asm {
		push eax;
		push ecx;
		mov  dl, ds:[0x6A5B34]; // completeColor (dark green)
		mov  ecx, ds:[FO_VAR_quests];
		add  ecx, [esp + 0x4BC - 0x28 + 12];
		call CheckQuestFailureState;
		mov  bl, al;
		pop  ecx;
		pop  eax;
		retn;
	}
}

static void ResetQuests() {
	questFailures.clear();
}

void QuestList::init() {
	LoadGameHook::OnGameReset() += ResetQuests;

	MakeCall(0x498222, PipStatus_hack, 1);

	questsButtonsType = IniReader::GetConfigInt("Misc", "UseScrollingQuestsList", 0);
	if (questsButtonsType > 0) {
		dlog("Applying quests list patch.", DL_INIT);
		QuestListPatch();

		questsScrollButtonsX = IniReader::GetConfigInt("Misc", "QuestsScrollButtonsX", 140);
		if (questsScrollButtonsX < 0 || questsScrollButtonsX > 618) questsScrollButtonsX = 140;
		questsScrollButtonsY = IniReader::GetConfigInt("Misc", "QuestsScrollButtonsY", 334);
		if (questsScrollButtonsY < 0 || questsScrollButtonsY > 434) questsScrollButtonsY = 334;

		pageQuest.reserve(4); // init
		pageQuest.push_back(1);

		dlogr(" Done", DL_INIT);
	} else {
		HookCall(0x498186, PipStatus_hook_printfix); // fix "out of bounds" bug when printing a list of quests
	}

	// Replace the qsort_ unstable sorting function with a simple stable sorting algorithm
	HookCall(0x49A7C2, quest_init_hook);
}

}


// Basic sanity check that header <boost/math/distributions/triangular.hpp>
// #includes all the files that it needs to.
#include <boost/math/distributions/triangular.hpp>
// Note this header includes no other headers, this is
// important if this test is to be meaningful:
#include "test_compile_result.hpp"

void compile_and_link_test()
{
   TEST_DIST_FUNC(triangular)
}

template class boost::math::triangular_distribution<float, boost::math::policies::policy<> >;
template class boost::math::triangular_distribution<double, boost::math::policies::policy<> >;
#ifnde

f BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
template class boost::math::triangular_distribution<long double, boost::math::policies::policy<> >;
#endif


/*
* its licensors.
*
*
*/

#include <AzCore/Serialization/SerializeContext.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Manipulators/RotationManipulators.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzCore/UnitTest/TestTypes.h>

#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>

namespace UnitTest
{
    using namespace AzToolsFramework;

    class ManipulatorViewTest
        : public AllocatorsTestFixture
    {
        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;

    public:
        void SetUp() override
        {
            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
            m_app.Start(AzFramework::Application::Descriptor());
        }

{
            m_app.Stop();
            m_serializeContext.reset();
        }

        ToolsApplication m_app;
    };

    TEST_F(ManipulatorViewTest, ViewDirectionForCameraAlignedManipulatorFacesCameraInManipulatorSpace)
    {
        // Given
        const AZ::Transform orientation =
            AZ::Transform::CreateFromQuaternion(
                AZ::Quaternion::CreateFromAxisAngleExact(
                    AZ::Vector3::CreateAxisX(), AZ::DegToRad(-90.0f)));

        const AZ::Transform translation =
            AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f));

        const AZ::Transform manipulatorSpace = translation * orientation;
        // create a rotation manipulator in an arbitrary space
        RotationManipulators rotationManipulators(manipulatorSpace);

        // When
        const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f);
        // transform the view direction to the space of the manipulator (space + local transform)
        const AZ::Vector3 viewDirection =
            CalculateViewDirection(rotationManipulators, worldCameraPosition);

        // Then
        // check the view direction is in the same space as the manipulator (space + local transform)
        EXPECT_THAT(viewDirection, IsClose(AZ::Vector3::CreateAxisZ()));
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceInFront)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceToTheSide)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }
} // namespace UnitTest


{
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }

/*
* its licensors.
*
*
*/

#include <AzCore/Serialization/SerializeContext.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Manipulators/RotationManipulators.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzCore/UnitTest/TestTypes.h>

#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>

namespace UnitTest
{
    using namespace AzToolsFramework;

    class ManipulatorViewTest
        : public AllocatorsTestFixture
    {
        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;

    public:
        void SetUp() override
        {
            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
            m_app.Start(AzFramework::Application::Descriptor());
        }

        void TearDown() override
        {
            m_app.Stop();
            m_serializeContext.reset();
        }

        ToolsApplication m_app;
    };

    TEST_F(ManipulatorViewTest, ViewDirectionForCameraAlignedManipulatorFacesCameraInManipulatorSpace)
    {
        // Given
        const AZ::Transform orientation =
            AZ::Transform::CreateFromQuaternion(
                AZ::Quaternion::CreateFromAxisAngleExact(
                    AZ::Vector3::CreateAxisX(), AZ::DegToRad(-90.0f)));

        const AZ::Transform translation =
            AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f));

        const AZ::Transform manipulatorSpace = translation * orientation;
        // create a rotation manipulator in an arbitrary space
        RotationManipulators rotationManipulators(manipulatorSpace);

        // When
        const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f);
        // transform the view direction to the space of the manipulator (space + local transform)
        const AZ::Vector3 viewDirection =
            CalculateViewDirection(rotationManipulators, worldCameraPosition);

        // Then
        // check the view direction is in the same space as the manipulator (space + local transform)
        EXPECT_THAT(viewDirection, IsClose(AZ::Vector3::CreateAxisZ()));
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceInFront)

    TEST(Manipulator, ScaleBasedOnCameraDistanceToTheSide)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }
} // namespace UnitTest


        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceToTheSide)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }
} // namespace UnitTest


cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);

/*
* its licensors.
*
*
*/

#include <AzCore/Serialization/SerializeContext.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Manipulators/RotationManipulators.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzCore/UnitTest/TestTypes.h>

#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>

namespace UnitTest
{
    using namespace AzToolsFramework;

    class ManipulatorViewTest
        : public AllocatorsTestFixture
    {
        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;

    public:
        void SetUp() override
        {
            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
            m_app.Start(AzFramework::Application::Descriptor());
        }

        void TearDown() override
        {
            m_app.Stop();
            m_serializeContext.reset();
        }

        ToolsApplication m_app;
    };

    TEST_F(ManipulatorViewTest, ViewDirectionForCameraAlignedManipulatorFacesCameraInManipulatorSpace)
    {
        // Given
        const AZ::Transform orientation =
            AZ::Transform::CreateFromQuaternion(
                AZ::Quaternion::CreateFromAxisAngleExact(
                    AZ::Vector3::CreateAxisX(), AZ::DegToRad(-90.0f)));

        const AZ::Transform translation =
            AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f));

        const AZ::Transform manipulatorSpace = translation * orientation;
        // create a rotation manipulator in an arbitrary space
        RotationManipulators rotationManipulators(manipulatorSpace);

        // When
        const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f);
        // transform the view direction to the space of the manipulator (space + local transform)
        const AZ::Vector3 viewDirection =
            CalculateViewDirection(rotationManipulators, worldCameraPosition);

        // Then
        // check the view direction is in the same space as the manipulator (space + local transform)
        EXPECT_THAT(viewDirection, IsClose(AZ::Vector3::CreateAxisZ()));
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceInFront)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceToTheSide)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }
} // namespace UnitTest


EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }

/*
* its licensors.
*
*
*/

#include <AzCore/Serialization/SerializeContext.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Manipulators/RotationManipulators.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzCore/UnitTest/TestTypes.h>

#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>

namespace UnitTest
{
    using namespace AzToolsFramework;

    class ManipulatorViewTest
        : public AllocatorsTestFixture
    {
        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;

    public:
        void SetUp() override
        {
            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
            m_app.Start(AzFramework::Application::Descriptor());
        }

        void TearDown() override
        {
            m_app.Stop();
            m_serializeContext.reset();
        }

        ToolsApplication m_app;
    };

    TEST_F(ManipulatorViewTest, ViewDirectionForCameraAlignedManipulatorFacesCameraInManipulatorSpace)
    {
        // Given
        const AZ::Transform orientation =
            AZ::Transform::CreateFromQuaternion(
                AZ::Quaternion::CreateFromAxisAngleExact(
                    AZ::Vector3::CreateAxisX(), AZ::DegToRad(-90.0f)));

        const AZ::Transform translation =
            AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f));

        const AZ::Transform manipulatorSpace = translation * orientation;
        // create a rotation manipulator in an arbitrary space
        RotationManipulators rotationManipulators(manipulatorSpace);

        // When
        const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f);
        // transform the view direction to the space of the manipulator (space + local transform)
        const AZ::Vector3 viewDirection =
            CalculateViewDirection(rotationManipulators, worldCameraPosition);

        // Then
        // check the view direction is in the same space as the manipulator (space + local transform)
        EXPECT_THAT(viewDirection, IsClose(AZ::Vector3::CreateAxisZ()));
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceInFront)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);


/*
* its licensors.
*
*
*/

#include <AzCore/Serialization/SerializeContext.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Manipulators/RotationManipulators.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzCore/UnitTest/TestTypes.h>

#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>

namespace UnitTest
{
    using namespace AzToolsFramework;

    class ManipulatorViewTest
        : public AllocatorsTestFixture
    {
        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;

    public:
        void SetUp() override
        {
            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
            m_app.Start(AzFramework::Application::Descriptor());
        }

        void TearDown() override
        {
            m_app.Stop();
            m_serializeContext.reset();
        }

        ToolsApplication m_app;
    };

    TEST_F(ManipulatorViewTest, ViewDirectionForCameraAlignedManipulatorFacesCameraInManipulatorSpace)
    {
        // Given
        const AZ::Transform orientation =
            AZ::Transform::CreateFromQuaternion(
                AZ::Quaternion::CreateFromAxisAngleExact(
                    AZ::Vector3::CreateAxisX(), AZ::DegToRad(-90.0f)));

        const AZ::Transform translation =
            AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f));

        const AZ::Transform manipulatorSpace = translation * orientation;
        // create a rotation manipulator in an arbitrary space
        RotationManipulators rotationManipulators(manipulatorSpace);

        // When
        const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f);
        // transform the view direction to the space of the manipulator (space + local transform)
        const AZ::Vector3 viewDirection =
            CalculateViewDirection(rotationManipulators, worldCameraPosition);

        // Then
        // check the view direction is in the same space as the manipulator (space + local transform)
        EXPECT_THAT(viewDirection, IsClose(AZ::Vector3::CreateAxisZ()));
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceInFront)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceToTheSide)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0

        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }
} // namespace UnitTest


/*
* its licensors.
*
*
*/

#include <AzCore/Serialization/SerializeContext.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Manipulators/RotationManipulators.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzCore/UnitTest/TestTypes.h>

#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>

namespace UnitTest
{
    using namespace AzToolsFramework;

    class ManipulatorViewTest
        : public AllocatorsTestFixture
    {
        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;

    public:
        void SetUp() override
        {
            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
            m_app.Start(AzFramework::Application::Descriptor());
        }

        void TearDown() override
        {
            m_app.Stop();
            m_serializeContext.reset();
        }

        ToolsApplication m_app;
    };

    TEST_F(ManipulatorViewTest, ViewDirectionForCameraAlignedManip

ulatorFacesCameraInManipulatorSpace)
    {
        // Given
        const AZ::Transform orientation =
            AZ::Transform::CreateFromQuaternion(
                AZ::Quaternion::CreateFromAxisAngleExact(
                    AZ::Vector3::CreateAxisX(), AZ::DegToRad(-90.0f)));

        const AZ::Transform translation =
            AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f));

        const AZ::Transform manipulatorSpace = translation * orientation;
        // create a rotation manipulator in an arbitrary space
        RotationManipulators rotationManipulators(manipulatorSpace);

        // When
        const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f);
        // transform the view direction to the space of the manipulator (space + local transform)
        const AZ::Vector3 viewDirection =
            CalculateViewDirection(rotationManipulators, worldCameraPosition);

        // Then
        // check the view direction is in the same space as the manipulator (space + local transform)
        EXPECT_THAT(viewDirection, IsClose(AZ::Vector3::CreateAxisZ()));
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceInFront)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }

    TEST(Manipulator, ScaleBasedOnCameraDistanceToTheSide)
    {
        AzFramework::CameraState cameraState{};
        cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
        cameraState.m_forward = -AZ::Vector3::CreateAxisY();

        const float scale =
            AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState);

        EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
    }
} // namespace UnitTest


#include "clang/Tooling/Syntax/Nodes.h"
#include "clang/Basic/TokenKinds.h"

using namespace clang;

llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
  switch (K) {
  case NodeKind::Leaf:
    return OS << "Leaf";
  case NodeKind::TranslationUnit:
    return OS << "TranslationUnit";
  case NodeKind::UnknownExpression:
    return OS << "UnknownExpression";
  case NodeKind::CxxNullPtrExpression:
    return OS << "CxxNullPtrExpression";
  case NodeKind::IntegerLiteralExpression:
    return OS << "IntegerLiteralExpression";
  case NodeKind::PrefixUnaryOperatorExpression:
    return OS << "PrefixUnaryOperatorExpression";
  case NodeKind::PostfixUnaryOperatorExpression:
    return OS << "PostfixUnaryOperatorExpression";
  case NodeKind::BinaryOperatorExpression:
    return OS << "BinaryOperatorExpression";
  case NodeKind::UnqualifiedId:
    return OS << "UnqualifiedId";
  case NodeKind::IdExpression:
    return OS << "IdExpression";
  case NodeKind::UnknownStatement:
    return OS << "UnknownStatement";
  case NodeKind::DeclarationStatement:
    return OS << "DeclarationStatement";
  case NodeKind::EmptyStatement:
    return OS << "EmptyStatement";
  case NodeKind::SwitchStatement:
    return OS << "SwitchStatement";
  case NodeKind::CaseStatement:
    return OS << "CaseStatement";
  case NodeKind::DefaultStatement:
    return OS << "DefaultStatement";
  case NodeKind::IfStatement:
    return OS << "IfStatement";
  case NodeKind::ForStatement:
    return OS << "ForStatement";
  case NodeKind::WhileStatement:
    return OS << "WhileStatement";
  case NodeKind::ContinueStatement:
    return OS << "ContinueStatement";
  case NodeKind::BreakStatement:
    return OS << "BreakStatement";
  case NodeKind::ReturnStatement:
    return OS << "ReturnStatement";
  case NodeKind::RangeBasedForStatement:
    return OS << "RangeBasedForStatement";
  case NodeKind::ExpressionStatement:
    return OS << "ExpressionStatement";
  case NodeKind::CompoundStatement:
    return OS << "CompoundStatement";
  case NodeKind::UnknownDeclaration:
    return OS << "UnknownDeclaration";
  case NodeKind::EmptyDeclaration:
    return OS << "EmptyDeclaration";
  case NodeKind::StaticAssertDeclaration:
    return OS << "StaticAssertDeclaration";
  case NodeKind::LinkageSpecificationDeclaration:
    return OS << "LinkageSpecificationDeclaration";
  case NodeKind::SimpleDeclaration:
    return OS << "SimpleDeclaration";
  case NodeKind::TemplateDeclaration:
    return OS << "TemplateDeclaration";
  case NodeKind::ExplicitTemplateInstantiation:
    return OS << "ExplicitTemplateInstantiation";
  case NodeKind::NamespaceDefinition:
    return OS << "NamespaceDefinition";
  case NodeKind::NamespaceAliasDefinition:
    return OS << "NamespaceAliasDefinition";
  case NodeKind::UsingNamespaceDirective:
    return OS << "UsingNamespaceDirective";
  case NodeKind::UsingDeclaration:
    return OS << "UsingDeclaration";
  case NodeKind::TypeAliasDeclaration:
    return OS << "TypeAliasDeclaration";
  case NodeKind::SimpleDeclarator:
    return OS << "SimpleDeclarator";
  case NodeKind::ParenDeclarator:
    return OS << "ParenDeclarator";
  case NodeKind::ArraySubscript:
    return OS << "ArraySubscript";
  case NodeKind::TrailingReturnType:
    return OS << "TrailingReturnType";
  case NodeKind::ParametersAndQualifiers:
    return OS << "ParametersAndQualifiers";
  case NodeKind::MemberPointer:
    return OS << "MemberPointer";
  case NodeKind::NameSpecifier:
    return OS << "NameSpecifier";
  case NodeKind::NestedNameSpecifier:
    return OS << "NestedNameSpecifier";
  }
  llvm_unreachable("unknown node kind");
}

llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
  switch (R) {
  case syntax::NodeRole::Detached:
    return OS << "Detached";
  case syntax::NodeRole::Unknown:
    return OS << "Unknown";
  case syntax::NodeRole::OpenParen:
    return OS << "OpenParen";
  case syntax::NodeRole::CloseParen:
    return OS << "CloseParen";
  case syntax::NodeRole::IntroducerKeyword:
    return OS << "IntroducerKeyword";
  case syntax::NodeRole::LiteralToken:
    return OS << "LiteralToken";
  case syntax::NodeRole::ArrowToken:
    return OS << "ArrowToken";
  case syntax::NodeRole::ExternKeyword:
    return OS << "ExternKeyword";
  case syntax::NodeRole::BodyStatement:
    return OS << "BodyStatement";
  case syntax::NodeRole::CaseStatement_value:
    return OS << "CaseStatement_value";
  case syntax::NodeRole::IfStatement_thenStatement:
    return OS << "IfStatement_thenStatement";
  case syntax::NodeRole::IfStatement_elseKeyword:
    return OS << "IfStatement_elseKeyword";
  case syntax::NodeRole::IfStatement_elseStatement:
    return OS << "IfStatement_elseStatement";
  case syntax::NodeRole::OperatorExpression_operatorToken:
    return OS << "OperatorExpression_operatorToken";
  case syntax::NodeRole::UnaryOperatorExpression_operand:
    return OS << "UnaryOperatorExpression_operand";
  case syntax::NodeRole::BinaryOperatorExpression_leftHandSide:
    return OS << "BinaryOperatorExpression_leftHandSide";
  case syntax::NodeRole::BinaryOperatorExpression_rightHandSide:
    return OS << "BinaryOperatorExpression_rightHandSide";
  case syntax::NodeRole::ReturnStatement_value:
    return OS << "ReturnStatement_value";
  case syntax::NodeRole::ExpressionStatement_expression:
    return OS << "ExpressionStatement_expression";
  case syntax::NodeRole::CompoundStatement_statement:
    return OS << "CompoundStatement_statement";
  case syntax::NodeRole::StaticAssertDeclaration_condition:
    return OS << "StaticAssertDeclaration_condition";
  case syntax::NodeRole::StaticAssertDeclaration_message:
    return OS << "StaticAssertDeclaration_message";
  case syntax::NodeRole::SimpleDeclaration_declarator:
    return OS << "SimpleDeclaration_declarator";
  case syntax::NodeRole::TemplateDeclaration_declaration:
    return OS << "TemplateDeclaration_declaration";
  case syntax::NodeRole::ExplicitTemplateInstantiation_declaration:
    return OS << "ExplicitTemplateInstantiation_declaration";
  case syntax::NodeRole::ArraySubscript_sizeExpression:
    return OS << "ArraySubscript_sizeExpression";
  case syntax::NodeRole::TrailingReturnType_declarator:
    return OS << "TrailingReturnType_declarator";
  case syntax::NodeRole::ParametersAndQualifiers_parameter:
    return OS << "ParametersAndQualifiers_parameter";
  case syntax::NodeRole::ParametersAndQualifiers_trailingReturn:
    return OS << "ParametersAndQualifiers_trailingReturn";
  case syntax::NodeRole::IdExpression_id:
    return OS << "IdExpression_id";
  case syntax::NodeRole::IdExpression_qualifier:
    return OS << "IdExpression_qualifier";
  case syntax::NodeRole::NestedNameSpecifier_specifier:
    return OS << "NestedNameSpecifier_specifier";
  }
  llvm_unreachable("invalid role");
}

std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::specifiers() {
  std::vector<syntax::NameSpecifier *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    assert(C->role() == syntax::NodeRole::NestedNameSpecifier_specifier);
    Children.push_back(llvm::cast<syntax::NameSpecifier>(C));
  }
  return Children;
}

syntax::NestedNameSpecifier *syntax::IdExpression::qualifier() {
  return llvm::cast_or_null<syntax::NestedNameSpecifier>(
      findChild(syntax::NodeRole::IdExpression_qualifier));
}

syntax::UnqualifiedId *syntax::IdExpression::unqualifiedId() {
  return llvm::cast_or_null<syntax::UnqualifiedId>(
      findChild(syntax::NodeRole::IdExpression_id));
}

syntax::Leaf *syntax::IntegerLiteralExpression::literalToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::LiteralToken));
}

syntax::Leaf *syntax::CxxNullPtrExpression::nullPtrKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::LiteralToken));
}

syntax::Expression *syntax::BinaryOperatorExpression::lhs() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::BinaryOperatorExpression_leftHandSide));
}

syntax::Leaf *syntax::UnaryOperatorExpression::operatorToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OperatorExpression_operatorToken));
}

syntax::Expression *syntax::UnaryOperatorExpression::operand() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::UnaryOperatorExpression_operand));
}

syntax::Leaf *syntax::BinaryOperatorExpression::operatorToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OperatorExpression_operatorToken));
}

syntax::Expression *syntax::BinaryOperatorExpression::rhs() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::BinaryOperatorExpression_rightHandSide));
}

{
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::SwitchStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::CaseStatement::caseKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Expression *syntax::CaseStatement::value() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::CaseStatement_value));
}

syntax::Statement *syntax::CaseStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::DefaultStatement::defaultKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::DefaultStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::IfStatement::ifKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::IfStatement::thenStatement() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::IfStatement_thenStatement));
}

syntax::Leaf *syntax::IfStatement::elseKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IfStatement_elseKeyword));
}

syntax::Statement *syntax::IfStatement::elseStatement() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::IfStatement_elseStatement));
}

syntax::Leaf *syntax::ForStatement::forKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::ForStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::WhileStatement::whileKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::WhileStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::ContinueStatement::continueKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::BreakStatement::breakKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::ReturnStatement::returnKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Expression *syntax::ReturnStatement::value() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ReturnStatement_value));
}

syntax::Leaf *syntax::RangeBasedForStatement::forKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::RangeBasedForStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Expression *syntax::ExpressionStatement::expression() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ExpressionStatement_expression));
}

syntax::Leaf *syntax::CompoundStatement::lbrace() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

std::vector<syntax::Statement *> syntax::CompoundStatement::statements() {
  std::vector<syntax::Statement *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    assert(C->role() == syntax::NodeRole::CompoundStatement_statement);
    Children.push_back(llvm::cast<syntax::Statement>(C));
  }
  return Children;
}

syntax::Leaf *syntax::CompoundStatement::rbrace() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Expression *syntax::StaticAssertDeclaration::condition() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::StaticAssertDeclaration_condition));
}

syntax::Expression *syntax::StaticAssertDeclaration::message() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::StaticAssertDeclaration_message));
}

std::vector<syntax::SimpleDeclarator *>
syntax::SimpleDeclaration::declarators() {
  std::vector<syntax::SimpleDeclarator *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    if (C->role() == syntax::NodeRole::SimpleDeclaration_declarator)
      Children.push_back(llvm::cast<syntax::SimpleDeclarator>(C));
  }
  return Children;
}

syntax::Leaf *syntax::TemplateDeclaration::templateKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Declaration *syntax::TemplateDeclaration::declaration() {
  return llvm::cast_or_null<syntax::Declaration>(
      findChild(syntax::NodeRole::TemplateDeclaration_declaration));
}

syntax::Leaf *syntax::ExplicitTemplateInstantiation::templateKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::ExplicitTemplateInstantiation::externKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::ExternKeyword));
}

syntax::Declaration *syntax::ExplicitTemplateInstantiation::declaration() {
  return llvm::cast_or_null<syntax::Declaration>(
      findChild(syntax::NodeRole::ExplicitTemplateInstantiation_declaration));
}

syntax::Leaf *syntax::ParenDeclarator::lparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

syntax::Leaf *syntax::ParenDeclarator::rparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Leaf *syntax::ArraySubscript::lbracket() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

syntax::Expression *syntax::ArraySubscript::sizeExpression() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ArraySubscript_sizeExpression));
}

syntax::Leaf *syntax::ArraySubscript::rbracket() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Leaf *syntax::TrailingReturnType::arrowToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::ArrowToken));
}

syntax::SimpleDeclarator *syntax::TrailingReturnType::declarator() {
  return llvm::cast_or_null<syntax::SimpleDeclarator>(
      findChild(syntax::NodeRole::TrailingReturnType_declarator));
}

syntax::Leaf *syntax::ParametersAndQualifiers::lparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

std::vector<syntax::SimpleDeclaration *>
syntax::ParametersAndQualifiers::parameters() {
  std::vector<syntax::SimpleDeclaration *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    if (C->role() == syntax::NodeRole::ParametersAndQualifiers_parameter)
      Children.push_back(llvm::cast<syntax::SimpleDeclaration>(C));
  }
  return Children;
}

syntax::Leaf *syntax::ParametersAndQualifiers::rparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::TrailingReturnType *syntax::ParametersAndQualifiers::trailingReturn() {
  return llvm::cast_or_null<syntax::TrailingReturnType>(
      findChild(syntax::NodeRole::ParametersAndQualifiers_trailingReturn));
}


#include "clang/Tooling/Syntax/Nodes.h"
#include "clang/Basic/TokenKinds.h"

using namespace clang;

llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
  switch (K) {
  case NodeKind::Leaf:
    return OS << "Leaf";
  case NodeKind::TranslationUnit:
    return OS << "TranslationUnit";
  case NodeKind::UnknownExpression:
    return OS << "UnknownExpression";
  case NodeKind::CxxNullPtrExpression:
    return OS << "CxxNullPtrExpression";
  case NodeKind::IntegerLiteralExpression:
    return OS << "IntegerLiteralExpression";
  case NodeKind::PrefixUnaryOperatorExpression:
    return OS << "PrefixUnaryOperatorExpression";
  case NodeKind::PostfixUnaryOperatorExpression:
    return OS << "PostfixUnaryOperatorExpression";
  case NodeKind::BinaryOperatorExpression:
    return OS << "BinaryOperatorExpression";
  case NodeKind::UnqualifiedId:
    return OS << "UnqualifiedId";
  case NodeKind::IdExpression:
    return OS << "IdExpression";
  case NodeKind::UnknownStatement:
    return OS << "UnknownStatement";
  case NodeKind::DeclarationStatement:
    return OS << "DeclarationStatement";
  case NodeKind::EmptyStatement:
    return OS << "EmptyStatement";
  case NodeKind::SwitchStatement:
    return OS << "SwitchStatement";
  case NodeKind::CaseStatement:
    return OS << "CaseStatement";
  case NodeKind::DefaultStatement:
    return OS << "DefaultStatement";
  case NodeKind::IfStatement:
    return OS << "IfStatement";
  case NodeKind::ForStatement:
    return OS << "ForStatement";
  case NodeKind::WhileStatement:
    return OS << "WhileStatement";
  case NodeKind::ContinueStatement:
    return OS << "ContinueStatement";
  case NodeKind::BreakStatement:
    return OS << "BreakStatement";
  case NodeKind::ReturnStatement:
    return OS << "ReturnStatement";
  case NodeKind::RangeBasedForStatement:
    return OS << "RangeBasedForStatement";
  case NodeKind::ExpressionStatement:
    return OS << "ExpressionStatement";
  case NodeKind::CompoundStatement:
    return OS << "CompoundStatement";
  case NodeKind::UnknownDeclaration:
    return OS << "UnknownDeclaration";
  case NodeKind::EmptyDeclaration:
    return OS << "EmptyDeclaration";
  case NodeKind::StaticAssertDeclaration:
    return OS << "StaticAssertDeclaration";
  case NodeKind::LinkageSpecificationDeclaration:
    return OS << "LinkageSpecificationDeclaration";
  case NodeKind::SimpleDeclaration:
    return OS << "SimpleDeclaration";
  case NodeKind::TemplateDeclaration:
    return OS << "TemplateDeclaration";
  case NodeKind::ExplicitTemplateInstantiation:
    return OS << "ExplicitTemplateInstantiation";
  case NodeKind::NamespaceDefinition:
    return OS << "NamespaceDefinition";
  case NodeKind::NamespaceAliasDefinition:
    return OS << "NamespaceAliasDefinition";
  case NodeKind::UsingNamespaceDirective:
    return OS << "UsingNamespaceDirective";
  case NodeKind::UsingDeclaration:
    return OS << "UsingDeclaration";
  case NodeKind::TypeAliasDeclaration:
    return OS << "TypeAliasDeclaration";
  case NodeKind::SimpleDeclarator:
    return OS << "SimpleDeclarator";
  case NodeKind::ParenDeclarator:
    return OS << "ParenDeclarator";
  case NodeKind::ArraySubscript:
    return OS << "ArraySubscript";
  case NodeKind::TrailingReturnType:
    return OS << "TrailingReturnType";
  case NodeKind::ParametersAndQualifiers:
    return OS << "ParametersAndQualifiers";
  case NodeKind::MemberPointer:
    return OS << "MemberPointer";
  case NodeKind::NameSpecifier:
    return OS << "NameSpecifier";
  case NodeKind::NestedNameSpecifier:
    return OS << "NestedNameSpecifier";
  }
  llvm_unreachable("unknown node kind");
}

llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
  switch (R) {
  case syntax::NodeRole::Detached:
    return OS << "Detached";
  case syntax::NodeRole::Unknown:
    return OS << "Unknown";
  case syntax::NodeRole::OpenParen:
    return OS << "OpenParen";
  case syntax::NodeRole::CloseParen:
    return OS << "CloseParen";
  case syntax::NodeRole::IntroducerKeyword:
    return OS << "IntroducerKeyword";
  case syntax::NodeRole::LiteralToken:
    return OS << "LiteralToken";
  case syntax::NodeRole::ArrowToken:
    return OS << "ArrowToken";
  case syntax::NodeRole::ExternKeyword:
    return OS << "ExternKeyword";
  case syntax::NodeRole::BodyStatement:
    return OS << "BodyStatement";
  case syntax::NodeRole::CaseStatement_value:
    return OS << "CaseStatement_value";
  case syntax::NodeRole::IfStatement_thenStatement:
    return OS << "IfStatement_thenStatement";
  case syntax::NodeRole::IfStatement_elseKeyword:
    return OS << "IfStatement_elseKeyword";
  case syntax::NodeRole::IfStatement_elseStatement:
    return OS << "IfStatement_elseStatement";
  case syntax::NodeRole::OperatorExpression_operatorToken:
    return OS << "OperatorExpression_operatorToken";
  case syntax::NodeRole::UnaryOperatorExpression_operand:
    return OS << "UnaryOperatorExpression_operand";
  case syntax::NodeRole::BinaryOperatorExpression_leftHandSide:
    return OS << "BinaryOperatorExpression_leftHandSide";
  case syntax::NodeRole::BinaryOperatorExpression_rightHandSide:
    return OS << "BinaryOperatorExpression_rightHandSide";
  case syntax::NodeRole::ReturnStatement_value:
    return OS << "ReturnStatement_value";
  case syntax::NodeRole::ExpressionStatement_expression:
    return OS << "ExpressionStatement_expression";
  case syntax::NodeRole::CompoundStatement_statement:
    return OS << "CompoundStatement_statement";
  case syntax::NodeRole::StaticAssertDeclaration_condition:
    return OS << "StaticAssertDeclaration_condition";
  case syntax::NodeRole::StaticAssertDeclaration_message:
    return OS << "StaticAssertDeclaration_message";
  case syntax::NodeRole::SimpleDeclaration_declarator:
    return OS << "SimpleDeclaration_declarator";
  case syntax::NodeRole::TemplateDeclaration_declaration:
    return OS << "TemplateDeclaration_declaration";
  case syntax::NodeRole::ExplicitTemplateInstantiation_declaration:
    return OS << "ExplicitTemplateInstantiation_declaration";
  case syntax::NodeRole::ArraySubscript_sizeExpression:
    return OS << "ArraySubscript_sizeExpression";
  case syntax::NodeRole::TrailingReturnType_declarator:
    return OS << "TrailingReturnType_declarator";
  case syntax::NodeRole::ParametersAndQualifiers_parameter:
    return OS << "ParametersAndQualifiers_parameter";
  case syntax::NodeRole::ParametersAndQualifiers_trailingReturn:
    return OS << "ParametersAndQualifiers_trailingReturn";
  case syntax::NodeRole::IdExpression_id:
    return OS << "IdExpression_id";
  case syntax::NodeRole::IdExpression_qualifier:
    return OS << "IdExpression_qualifier";
  case syntax::NodeRole::NestedNameSpecifier_specifier:
    return OS << "NestedNameSpecifier_specifier";
  }
  llvm_unreachable("invalid role");
}

std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::specifiers() {
  std::vector<syntax::NameSpecifier *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    assert(C->role() == syntax::NodeRole::NestedNameSpecifier_specifier);
    Children.push_back(llvm::cast<syntax::NameSpecifier>(C));
  }
  return Children;
}

syntax::NestedNameSpecifier *syntax::IdExpression::qualifier() {
  return llvm::cast_or_null<syntax::NestedNameSpecifier>(
      findChild(syntax::NodeRole::IdExpression_qualifier));
}

syntax::UnqualifiedId *syntax::IdExpression::unqualifiedId() {
  return llvm::cast_or_null<syntax::UnqualifiedId>(
      findChild(syntax::NodeRole::IdExpression_id));
}

syntax::Leaf *syntax::IntegerLiteralExpression::literalToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::LiteralToken));
}

syntax::Leaf *syntax::CxxNullPtrExpression::nullPtrKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::LiteralToken));
}

syntax::Expression *syntax::BinaryOperatorExpression::lhs() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::BinaryOperatorExpression_leftHandSide));
}

syntax::Leaf *syntax::UnaryOperatorExpression::operatorToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OperatorExpression_operatorToken));
}

syntax::Expression *syntax::UnaryOperatorExpression::operand() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::UnaryOperatorExpression_operand));
}

syntax::Leaf *syntax::BinaryOperatorExpression::operatorToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OperatorExpression_operatorToken));
}

syntax::Expression *syntax::BinaryOperatorExpression::rhs() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::BinaryOperatorExpression_rightHandSide));
}

syntax::Leaf *syntax::SwitchStatement::switchKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::SwitchStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::CaseStatement::caseKeyword()

syntax::Expression *syntax::CaseStatement::value() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::CaseStatement_value));
}

syntax::Statement *syntax::CaseStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::DefaultStatement::defaultKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::DefaultStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::IfStatement::ifKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::IfStatement::thenStatement() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::IfStatement_thenStatement));
}

syntax::Leaf *syntax::IfStatement::elseKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IfStatement_elseKeyword));
}

syntax::Statement *syntax::IfStatement::elseStatement() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::IfStatement_elseStatement));
}

syntax::Leaf *syntax::ForStatement::forKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::ForStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::WhileStatement::whileKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::WhileStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::ContinueStatement::continueKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::BreakStatement::breakKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::ReturnStatement::returnKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Expression *syntax::ReturnStatement::value() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ReturnStatement_value));
}

syntax::Leaf *syntax::RangeBasedForStatement::forKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::RangeBasedForStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Expression *syntax::ExpressionStatement::expression() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ExpressionStatement_expression));
}

syntax::Leaf *syntax::CompoundStatement::lbrace() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

std::vector<syntax::Statement *> syntax::CompoundStatement::statements() {
  std::vector<syntax::Statement *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    assert(C->role() == syntax::NodeRole::CompoundStatement_statement);
    Children.push_back(llvm::cast<syntax::Statement>(C));
  }
  return Children;
}

syntax::Leaf *syntax::CompoundStatement::rbrace() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Expression *syntax::StaticAssertDeclaration::condition() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::StaticAssertDeclaration_condition));
}

syntax::Expression *syntax::StaticAssertDeclaration::message() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::StaticAssertDeclaration_message));
}

std::vector<syntax::SimpleDeclarator *>
syntax::SimpleDeclaration::declarators() {
  std::vector<syntax::SimpleDeclarator *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    if (C->role() == syntax::NodeRole::SimpleDeclaration_declarator)
      Children.push_back(llvm::cast<syntax::SimpleDeclarator>(C));
  }
  return Children;
}

syntax::Leaf *syntax::TemplateDeclaration::templateKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Declaration *syntax::TemplateDeclaration::declaration() {
  return llvm::cast_or_null<syntax::Declaration>(
      findChild(syntax::NodeRole::TemplateDeclaration_declaration));
}

syntax::Leaf *syntax::ExplicitTemplateInstantiation::templateKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::ExplicitTemplateInstantiation::externKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::ExternKeyword));
}

syntax::Declaration *syntax::ExplicitTemplateInstantiation::declaration() {
  return llvm::cast_or_null<syntax::Declaration>(
      findChild(syntax::NodeRole::ExplicitTemplateInstantiation_declaration));
}

syntax::Leaf *syntax::ParenDeclarator::lparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

syntax::Leaf *syntax::ParenDeclarator::rparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Leaf *syntax::ArraySubscript::lbracket() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

syntax::Expression *syntax::ArraySubscript::sizeExpression() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ArraySubscript_sizeExpression));
}

syntax::Leaf *syntax::ArraySubscript::rbracket() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Leaf *syntax::TrailingReturnType::arrowToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::ArrowToken));
}

syntax::SimpleDeclarator *syntax::TrailingReturnType::declarator() {
  return llvm::cast_or_null<syntax::SimpleDeclarator>(
      findChild(syntax::NodeRole::TrailingReturnType_declarator));
}

syntax::Leaf *syntax::ParametersAndQualifiers::lparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

std::vector<syntax::SimpleDeclaration *>
syntax::ParametersAndQualifiers::parameters() {
  std::vector<syntax::SimpleDeclaration *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    if (C->role() == syntax::NodeRole::ParametersAndQualifiers_parameter)
      Children.push_back(llvm::cast<syntax::SimpleDeclaration>(C));
  }
  return Children;
}

syntax::Leaf *syntax::ParametersAndQualifiers::rparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::TrailingReturnType *syntax::ParametersAndQualifiers::trailingReturn() {
  return llvm::cast_or_null<syntax::TrailingReturnType>(
      findChild(syntax::NodeRole::ParametersAndQualifiers_trailingReturn));
}


{
  std::vector<syntax::SimpleDeclaration *> Children;

#include "clang/Tooling/Syntax/Nodes.h"
#include "clang/Basic/TokenKinds.h"

using namespace clang;

llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
  switch (K) {
  case NodeKind::Leaf:
    return OS << "Leaf";
  case NodeKind::TranslationUnit:
    return OS << "TranslationUnit";
  case NodeKind::UnknownExpression:
    return OS << "UnknownExpression";
  case NodeKind::CxxNullPtrExpression:
    return OS << "CxxNullPtrExpression";
  case NodeKind::IntegerLiteralExpression:
    return OS << "IntegerLiteralExpression";
  case NodeKind::PrefixUnaryOperatorExpression:
    return OS << "PrefixUnaryOperatorExpression";
  case NodeKind::PostfixUnaryOperatorExpression:
    return OS << "PostfixUnaryOperatorExpression";
  case NodeKind::BinaryOperatorExpression:
    return OS << "BinaryOperatorExpression";
  case NodeKind::UnqualifiedId:
    return OS << "UnqualifiedId";
  case NodeKind::IdExpression:
    return OS << "IdExpression";
  case NodeKind::UnknownStatement:
    return OS << "UnknownStatement";
  case NodeKind::DeclarationStatement:
    return OS << "DeclarationStatement";
  case NodeKind::EmptyStatement:
    return OS << "EmptyStatement";
  case NodeKind::SwitchStatement:
    return OS << "SwitchStatement";
  case NodeKind::CaseStatement:
    return OS << "CaseStatement";
  case NodeKind::DefaultStatement:
    return OS << "DefaultStatement";
  case NodeKind::IfStatement:
    return OS << "IfStatement";
  case NodeKind::ForStatement:
    return OS << "ForStatement";
  case NodeKind::WhileStatement:
    return OS << "WhileStatement";
  case NodeKind::ContinueStatement:
    return OS << "ContinueStatement";
  case NodeKind::BreakStatement:
    return OS << "BreakStatement";
  case NodeKind::ReturnStatement:
    return OS << "ReturnStatement";
  case NodeKind::RangeBasedForStatement:
    return OS << "RangeBasedForStatement";
  case NodeKind::ExpressionStatement:
    return OS << "ExpressionStatement";
  case NodeKind::CompoundStatement:
    return OS << "CompoundStatement";
  case NodeKind::UnknownDeclaration:
    return OS << "UnknownDeclaration";
  case NodeKind::EmptyDeclaration:
    return OS << "EmptyDeclaration";
  case NodeKind::StaticAssertDeclaration:
    return OS << "StaticAssertDeclaration";
  case NodeKind::LinkageSpecificationDeclaration:
    return OS << "LinkageSpecificationDeclaration";
  case NodeKind::SimpleDeclaration:
    return OS << "SimpleDeclaration";
  case NodeKind::TemplateDeclaration:
    return OS << "TemplateDeclaration";
  case NodeKind::ExplicitTemplateInstantiation:
    return OS << "ExplicitTemplateInstantiation";
  case NodeKind::NamespaceDefinition:
    return OS << "NamespaceDefinition";
  case NodeKind::NamespaceAliasDefinition:
    return OS << "NamespaceAliasDefinition";
  case NodeKind::UsingNamespaceDirective:
    return OS << "UsingNamespaceDirective";
  case NodeKind::UsingDeclaration:
    return OS << "UsingDeclaration";
  case NodeKind::TypeAliasDeclaration:
    return OS << "TypeAliasDeclaration";
  case NodeKind::SimpleDeclarator:
    return OS << "SimpleDeclarator";
  case NodeKind::ParenDeclarator:
    return OS << "ParenDeclarator";
  case NodeKind::ArraySubscript:
    return OS << "ArraySubscript";
  case NodeKind::TrailingReturnType:
    return OS << "TrailingReturnType";
  case NodeKind::ParametersAndQualifiers:
    return OS << "ParametersAndQualifiers";
  case NodeKind::MemberPointer:
    return OS << "MemberPointer";
  case NodeKind::NameSpecifier:
    return OS << "NameSpecifier";
  case NodeKind::NestedNameSpecifier:
    return OS << "NestedNameSpecifier";
  }
  llvm_unreachable("unknown node kind");
}

llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
  switch (R) {
  case syntax::NodeRole::Detached:
    return OS << "Detached";
  case syntax::NodeRole::Unknown:
    return OS << "Unknown";
  case syntax::NodeRole::OpenParen:
    return OS << "OpenParen";
  case syntax::NodeRole::CloseParen:
    return OS << "CloseParen";
  case syntax::NodeRole::IntroducerKeyword:
    return OS << "IntroducerKeyword";
  case syntax::NodeRole::LiteralToken:
    return OS << "LiteralToken";
  case syntax::NodeRole::ArrowToken:
    return OS << "ArrowToken";
  case syntax::NodeRole::ExternKeyword:
    return OS << "ExternKeyword";
  case syntax::NodeRole::BodyStatement:
    return OS << "BodyStatement";
  case syntax::NodeRole::CaseStatement_value:
    return OS << "CaseStatement_value";
  case syntax::NodeRole::IfStatement_thenStatement:
    return OS << "IfStatement_thenStatement";
  case syntax::NodeRole::IfStatement_elseKeyword:
    return OS << "IfStatement_elseKeyword";
  case syntax::NodeRole::IfStatement_elseStatement:
    return OS << "IfStatement_elseStatement";
  case syntax::NodeRole::OperatorExpression_operatorToken:
    return OS << "OperatorExpression_operatorToken";
  case syntax::NodeRole::UnaryOperatorExpression_operand:
    return OS << "UnaryOperatorExpression_operand";
  case syntax::NodeRole::BinaryOperatorExpression_leftHandSide:
    return OS << "BinaryOperatorExpression_leftHandSide";
  case syntax::NodeRole::BinaryOperatorExpression_rightHandSide:
    return OS << "BinaryOperatorExpression_rightHandSide";
  case syntax::NodeRole::ReturnStatement_value:
    return OS << "ReturnStatement_value";
  case syntax::NodeRole::ExpressionStatement_expression:
    return OS << "ExpressionStatement_expression";
  case syntax::NodeRole::CompoundStatement_statement:
    return OS << "CompoundStatement_statement";
  case syntax::NodeRole::StaticAssertDeclaration_condition:
    return OS << "StaticAssertDeclaration_condition";
  case syntax::NodeRole::StaticAssertDeclaration_message:
    return OS << "StaticAssertDeclaration_message";
  case syntax::NodeRole::SimpleDeclaration_declarator:
    return OS << "SimpleDeclaration_declarator";
  case syntax::NodeRole::TemplateDeclaration_declaration:
    return OS << "TemplateDeclaration_declaration";
  case syntax::NodeRole::ExplicitTemplateInstantiation_declaration:
    return OS << "ExplicitTemplateInstantiation_declaration";
  case syntax::NodeRole::ArraySubscript_sizeExpression:
    return OS << "ArraySubscript_sizeExpression";
  case syntax::NodeRole::TrailingReturnType_declarator:
    return OS << "TrailingReturnType_declarator";
  case syntax::NodeRole::ParametersAndQualifiers_parameter:
    return OS << "ParametersAndQualifiers_parameter";
  case syntax::NodeRole::ParametersAndQualifiers_trailingReturn:
    return OS << "ParametersAndQualifiers_trailingReturn";
  case syntax::NodeRole::IdExpression_id:
    return OS << "IdExpression_id";
  case syntax::NodeRole::IdExpression_qualifier:
    return OS << "IdExpression_qualifier";
  case syntax::NodeRole::NestedNameSpecifier_specifier:
    return OS << "NestedNameSpecifier_specifier";
  }
  llvm_unreachable("invalid role");
}

std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::specifiers() {
  std::vector<syntax::NameSpecifier *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    assert(C->role() == syntax::NodeRole::NestedNameSpecifier_specifier);
    Children.push_back(llvm::cast<syntax::NameSpecifier>(C));
  }
  return Children;
}

syntax::NestedNameSpecifier *syntax::IdExpression::qualifier() {
  return llvm::cast_or_null<syntax::NestedNameSpecifier>(
      findChild(syntax::NodeRole::IdExpression_qualifier));
}

syntax::UnqualifiedId *syntax::IdExpression::unqualifiedId() {
  return llvm::cast_or_null<syntax::UnqualifiedId>(
      findChild(syntax::NodeRole::IdExpression_id));
}

syntax::Leaf *syntax::IntegerLiteralExpression::literalToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::LiteralToken));
}

syntax::Leaf *syntax::CxxNullPtrExpression::nullPtrKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::LiteralToken));
}

syntax::Expression *syntax::BinaryOperatorExpression::lhs() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::BinaryOperatorExpression_leftHandSide));
}

syntax::Leaf *syntax::UnaryOperatorExpression::operatorToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OperatorExpression_operatorToken));
}

syntax::Expression *syntax::UnaryOperatorExpression::operand() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::UnaryOperatorExpression_operand));
}

syntax::Leaf *syntax::BinaryOperatorExpression::operatorToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OperatorExpression_operatorToken));
}

syntax::Expression *syntax::BinaryOperatorExpression::rhs() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::BinaryOperatorExpression_rightHandSide));
}

syntax::Leaf *syntax::SwitchStatement::switchKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::SwitchStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::CaseStatement::caseKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Expression *syntax::CaseStatement::value() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::CaseStatement_value));
}

syntax::Statement *syntax::CaseStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::DefaultStatement::defaultKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::DefaultStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::IfStatement::ifKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::IfStatement::thenStatement() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::IfStatement_thenStatement));
}

syntax::Leaf *syntax::IfStatement::elseKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IfStatement_elseKeyword));
}

syntax::Statement *syntax::IfStatement::elseStatement() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::IfStatement_elseStatement));
}

syntax::Leaf *syntax::ForStatement::forKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::ForStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::WhileStatement::whileKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::WhileStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Leaf *syntax::ContinueStatement::continueKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::BreakStatement::breakKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::ReturnStatement::returnKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Expression *syntax::ReturnStatement::value() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ReturnStatement_value));
}

syntax::Leaf *syntax::RangeBasedForStatement::forKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Statement *syntax::RangeBasedForStatement::body() {
  return llvm::cast_or_null<syntax::Statement>(
      findChild(syntax::NodeRole::BodyStatement));
}

syntax::Expression *syntax::ExpressionStatement::expression() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ExpressionStatement_expression));
}

syntax::Leaf *syntax::CompoundStatement::lbrace() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

std::vector<syntax::Statement *> syntax::CompoundStatement::statements() {
  std::vector<syntax::Statement *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    assert(C->role() == syntax::NodeRole::CompoundStatement_statement);
    Children.push_back(llvm::cast<syntax::Statement>(C));
  }
  return Children;
}

syntax::Leaf *syntax::CompoundStatement::rbrace() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Expression *syntax::StaticAssertDeclaration::condition() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::StaticAssertDeclaration_condition));
}

syntax::Expression *syntax::StaticAssertDeclaration::message() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::StaticAssertDeclaration_message));
}

std::vector<syntax::SimpleDeclarator *>
syntax::SimpleDeclaration::declarators() {
  std::vector<syntax::SimpleDeclarator *> Children;
  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    if (C->role() == syntax::NodeRole::SimpleDeclaration_declarator)
      Children.push_back(llvm::cast<syntax::SimpleDeclarator>(C));
  }
  return Children;
}

syntax::Leaf *syntax::TemplateDeclaration::templateKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Declaration *syntax::TemplateDeclaration::declaration() {
  return llvm::cast_or_null<syntax::Declaration>(
      findChild(syntax::NodeRole::TemplateDeclaration_declaration));
}

syntax::Leaf *syntax::ExplicitTemplateInstantiation::templateKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::IntroducerKeyword));
}

syntax::Leaf *syntax::ExplicitTemplateInstantiation::externKeyword() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::ExternKeyword));
}

syntax::Declaration *syntax::ExplicitTemplateInstantiation::declaration() {
  return llvm::cast_or_null<syntax::Declaration>(
      findChild(syntax::NodeRole::ExplicitTemplateInstantiation_declaration));
}

syntax::Leaf *syntax::ParenDeclarator::lparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

syntax::Leaf *syntax::ParenDeclarator::rparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Leaf *syntax::ArraySubscript::lbracket() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

syntax::Expression *syntax::ArraySubscript::sizeExpression() {
  return llvm::cast_or_null<syntax::Expression>(
      findChild(syntax::NodeRole::ArraySubscript_sizeExpression));
}

syntax::Leaf *syntax::ArraySubscript::rbracket() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::Leaf *syntax::TrailingReturnType::arrowToken() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::ArrowToken));
}

syntax::SimpleDeclarator *syntax::TrailingReturnType::declarator() {
  return llvm::cast_or_null<syntax::SimpleDeclarator>(
      findChild(syntax::NodeRole::TrailingReturnType_declarator));
}

syntax::Leaf *syntax::ParametersAndQualifiers::lparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::OpenParen));
}

std::vector<syntax::SimpleDeclaration *>
syntax::ParametersAndQualifiers::parameters()

  for (auto *C = firstChild(); C; C = C->nextSibling()) {
    if (C->role() == syntax::NodeRole::ParametersAndQualifiers_parameter)
      Children.push_back(llvm::cast<syntax::SimpleDeclaration>(C));
  }
  return Children;
}

syntax::Leaf *syntax::ParametersAndQualifiers::rparen() {
  return llvm::cast_or_null<syntax::Leaf>(
      findChild(syntax::NodeRole::CloseParen));
}

syntax::TrailingReturnType *syntax::ParametersAndQualifiers::trailingReturn() {
  return llvm::cast_or_null<syntax::TrailingReturnType>(
      findChild(syntax::NodeRole::ParametersAndQualifiers_trailingReturn));
}