export default function Dashboard(props: DashboardProps) {
	const { user, onAdapterListChanged } = props;

	const history = useHistory<AdapterCheckLocationState>();
	const [categories, setCategories] = useState<Record<string, CardGridProps>>(
		{
			Resources: { cards: resourcesCards },
			Social: { cards: socialCards },
			Tools: { cards: getToolsCards(!!user) },
			[MY_ADAPTERS_CATEGORY]: { cards: [] },
		},
	);
	let storedCollapsed;
	try {
		storedCollapsed = JSON.parse(
			localStorage.getItem(COLLAPSED_CATEGORIES_KEY) || "[]",
		);
	} catch {
		storedCollapsed = [];
	}
	const [collapsed, setCollapsed] = useState<boolean[]>(storedCollapsed);
	const [showAddWatch, setShowAddWatch] = useState(false);

	const handleAccordion = (index: number) => {
		setCollapsed((old) => {
			const result = [...old];
			result[index] = !result[index];
			localStorage.setItem(
				COLLAPSED_CATEGORIES_KEY,
				JSON.stringify(result),
			);
			return result;
		});
	};

	const loadWatchedAdapters = async (user: User) => {
		setCategories((old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
		})); // clear the list (and show the spinner)

		let adapters: DashboardCardProps[] = [];
		try {
			const infos = await getWatchedAdapterInfos(user.token);
			const cards = await Promise.all(
				infos.map((info) =>
					getAdapterCard(info, history, user, () =>
						handleRemoveWatch(info).catch(console.error),
					).catch(console.error),
				),
			);

			adapters = cards
				.filter((c) => !!c)
				.map((c) => c as DashboardCardProps);
		} catch (error) {
			console.error(error);
		}

		setCategories((old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: {
				cards: [...adapters],
				onAdd: () => setShowAddWatch(true),
			},
		}));
	};

	useEffect(() => {
		const loadMyAdapters = async (user: User) => {
			setCategories((old) => ({
				...old,
				[MY_ADAPTERS_CATEGORY]: { cards: [] },
			})); // clear the list (and show the spinner)

			const infos = await getMyAdapterInfos(user.token);
			const cards = await Promise.all(
				infos.map((info) =>
					getAdapterCard(info, history, user).catch(console.error),
				),
			);

			const adapters = cards
				.filter((c) => !!c)
				.map((c) => c as DashboardCardProps);
			if (adapters.length === 0) {
				adapters.push({
					title: "No adapters found",
					img: "images/adapter-creator.png",
					text: "You can create your first ioBroker adapter by answering questions in the Adapter Creator.",
					buttons: [
						<CardButton
							text="Open Adapter Creator"
							to="/create-adapter"
						/>,
					],
				});
			}
			setCategories((old) => ({
				...old,
				Tools: { cards: getToolsCards(true) },
				[MY_ADAPTERS_CATEGORY]: { cards: [...adapters] },
			}));
		};

		if (user) {
			loadMyAdapters(user).catch(console.error);
			loadWatchedAdapters(user).catch(console.error);
		} else {
			const loginCard = (type: string) => ({
				title: "Login Required",
				img: "images/github.png",
				text: `You must be logged in to see your ${type}.`,
				buttons: [<CardButton text="Login" onClick={handleLogin} />],
			});
			setCategories((old) => {
				const result = { ...old };
				result.Tools = { cards: getToolsCards(false) };
				result[MY_ADAPTERS_CATEGORY] = {
					cards: [loginCard("adapters")],
				};
				delete result[WATCHED_ADAPTERS_CATEGORY];
				return result;
			});
		}
	}, [user]);

	useEffect(() => {
		const updateBlogIcon = async () => {
			const url =
				"https://raw.githubusercontent.com/ioBroker/ioBroker.docs/master/engine/front-end/public/blog.json";
			const { data: blog } = await axios.get<{
				pages: Record<
					string,
					{
						date: string;
						title: Record<string, string>;
						logo: string;
					}
				>;
			}>(url);
			const page = Object.values(blog.pages)[0];
			if (!page) return;
			setCategories((old) => {
				const res = old.Resources;
				const index = res.cards.findIndex((c) => c.title === "Blog");
				if (index >= 0) {
					const card = res.cards[index];
					const date = page.date.replace(
						/^(\d{4})\.(\d{2})\.(\d{2})$/,
						"$3.$2.$1",
					);
					res.cards[index] = {
						...card,
						img: `https://www.iobroker.net/${page.logo}`,
						text: `${card.text}\n \nLatest entry: ${page.title.en} (${date})`,
					};
				}
				return { ...old };
			});
		};
		updateBlogIcon().catch(console.error);
	}, []);

	const handleAddWatch = async (repo?: string) => {
		setShowAddWatch(false);
		if (!repo) {
			return;
		}
		try {
			setCategories((old) => ({
				...old,
				[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
			})); // show spinner
			const url = getApiUrl("user");
			const { data: dbUser } = await axios.get<DbUser>(url);
			dbUser.watches.push(repo);
			await axios.put(url, dbUser);
			onAdapterListChanged();
			await loadWatchedAdapters(user!);
		} catch (error) {
			console.error(error);
		}
	};

	const handleRemoveWatch = async (info: AdapterInfos) => {
		setCategories((old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
		})); // show spinner
		const url = getApiUrl("user");
		const { data: dbUser } = await axios.get<DbUser>(url);
		dbUser.watches = dbUser.watches.filter(
			(w) => !equalIgnoreCase(w, info.repo.full_name),
		);
		await axios.put(url, dbUser);
		onAdapterListChanged();
		await loadWatchedAdapters(user!);
	};

	return (
		<>
			{user && (
				<AddWatchDialog
					user={user}
					open={showAddWatch}
					onClose={handleAddWatch}
				/>
			)}


() => {
		const loadPullRequests = async () => {
			if (!repo.open_issues) {
				setCounts("no open PRs / no open issues");
				return;
			}

			const gitHub = GitHubComm.forToken(user.token);
			const pullRequests = await gitHub
				.getRepo(repo)
				.getPullRequests("open");
			const prCount = pullRequests.length;
			const issueCount = repo.open_issues - prCount;
			const getText = (value: number, type: string) => {
				return `${value || "no"} open ${type}${value === 1 ? "" : "s"}`;
			};

			setCounts(
				`${getText(prCount, "PR")} / ${getText(issueCount, "issue")}`,
			);
			setColor(prCount > 0 ? "error" : "primary");
		};
		loadPullRequests().catch(console.error);
	}


async () => {
			if (!repo.open_issues) {
				setCounts("no open PRs / no open issues");
				return;
			}

			const gitHub = GitHubComm.forToken(user.token);
			const pullRequests = await gitHub
				.getRepo(repo)
				.getPullRequests("open");
			const prCount = pullRequests.length;
			const issueCount = repo.open_issues - prCount;
			const getText = (value: number, type: string) => {
				return `${value || "no"} open ${type}${value === 1 ? "" : "s"}`;
			};

			setCounts(
				`${getText(prCount, "PR")} / ${getText(issueCount, "issue")}`,
			);
			setColor(prCount > 0 ? "error" : "primary");
		}


(value: number, type: string) => {
				return `${value || "no"} open ${type}${value === 1 ? "" : "s"}`;
			}


(props: { errors: number[]; children: any }, ref: any) => {
		const { errors, children } = props;
		const errorCount = errors[0] || errors[1];
		const color = errors[0] ? "error" : "primary";
		return (
			<Badge badgeContent={errorCount} color={color} {


() => {
		if (projects.length === 0) {
			return;
		}

		const loadProjectInfos = async () => {
			const stats24h = await getSentryStats(
				projects.map((p) => p.id),
				"24h",
			);
			const stats30d = await getSentryStats(
				projects.map((p) => p.id),
				"30d",
			);
			const errors = [
				stats24h.map(
					(stat) => stat.stats.reduce((old, num) => old + num[1], 0),
					0,
				),
				stats30d.map(
					(stat) => stat.stats.reduce((old, num) => old + num[1], 0),
					0,
				),
			];
			setErrorCounts(errors);

			const totalErrors = errors.map((e) =>
				e.reduce((old, err) => old + err, 0),
			);
			setErrorCount(totalErrors);

			if (totalErrors[0]) {
				setTooltip(
					`Sentry (${totalErrors[0]} errors in the last 24 hours)`,
				);
			} else {
				setTooltip(
					`Sentry (${totalErrors[1]} errors in the last 30 days)`,
				);
			}
		};
		loadProjectInfos().catch(console.error);
	}


async () => {
			const stats24h = await getSentryStats(
				projects.map((p) => p.id),
				"24h",
			);
			const stats30d = await getSentryStats(
				projects.map((p) => p.id),
				"30d",
			);
			const errors = [
				stats24h.map(
					(stat) => stat.stats.reduce((old, num) => old + num[1], 0),
					0,
				),
				stats30d.map(
					(stat) => stat.stats.reduce((old, num) => old + num[1], 0),
					0,
				),
			];
			setErrorCounts(errors);

			const totalErrors = errors.map((e) =>
				e.reduce((old, err) => old + err, 0),
			);
			setErrorCount(totalErrors);

			if (totalErrors[0]) {
				setTooltip(
					`Sentry (${totalErrors[0]} errors in the last 24 hours)`,
				);
			} else {
				setTooltip(
					`Sentry (${totalErrors[1]} errors in the last 30 days)`,
				);
			}
		}


(stat) => stat.stats.reduce((old, num) => old + num[1], 0)


(old, num) => old + num[1]


(e) =>
				e.reduce((old, err) => old + err, 0)


(old, err) => old + err


(project: ProjectInfo) => {
			window.open(
				`https://sentry.iobroker.net/organizations/iobroker/issues/?project=${project.id}`,
				"_blank",
			);
		}


(project, index) => (
							<ListItem
								button


() => {
		if (!open) {
			return;
		}
		const loadData = async () => {
			const latest = await getLatest();
			const names = Object.keys(latest).map((adapterName) =>
				latest[adapterName].meta.replace(
					/^\w+:\/\/[^/]+\/([^/]+\/[^/]+)\/.+$/,
					"$1",
				),
			);
			setRepoNames(names);
		};
		loadData().catch(console.error);
	}


async () => {
			const latest = await getLatest();
			const names = Object.keys(latest).map((adapterName) =>
				latest[adapterName].meta.replace(
					/^\w+:\/\/[^/]+\/([^/]+\/[^/]+)\/.+$/,
					"$1",
				),
			);
			setRepoNames(names);
		}


(adapterName) =>
				latest[adapterName].meta.replace(
					/^\w+:\/\/[^/]+\/([^/]+\/[^/]+)\/.+$/,
					"$1",
				)


async () => {
		setValidating(true);
		try {
			const gitHub = GitHubComm.forToken(user.token);
			const [owner, repo] = repoName.split("/", 2);
			const latest = await getLatest();
			const infos = await getAdapterInfos(
				await gitHub.getRepo(owner, repo).getRepo(),
				latest,
			);
			if (!infos.info) {
				throw new Error("This is not an ioBroker adapter");
			}
			onClose(repoName);
		} catch (error: any) {
			setError(error.message || error);
		} finally {
			setValidating(false);
		}
	}


() => onClose()


(c: any) => c.name === adapterName


(p) => p.adapterName === adapterName


() => {
		history.push("/adapter-check", {
			repoFullName: repo.full_name,
		});
	}


(index: number) => {
		setCollapsed((old) => {
			const result = [...old];
			result[index] = !result[index];
			localStorage.setItem(
				COLLAPSED_CATEGORIES_KEY,
				JSON.stringify(result),
			);
			return result;
		});
	}


(old) => {
			const result = [...old];
			result[index] = !result[index];
			localStorage.setItem(
				COLLAPSED_CATEGORIES_KEY,
				JSON.stringify(result),
			);
			return result;
		}


async (user: User) => {
		setCategories((old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
		})); // clear the list (and show the spinner)

		let adapters: DashboardCardProps[] = [];
		try {
			const infos = await getWatchedAdapterInfos(user.token);
			const cards = await Promise.all(
				infos.map((info) =>
					getAdapterCard(info, history, user, () =>
						handleRemoveWatch(info).catch(console.error),
					).catch(console.error),
				),
			);

			adapters = cards
				.filter((c) => !!c)
				.map((c) => c as DashboardCardProps);
		} catch (error) {
			console.error(error);
		}

		setCategories((old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: {
				cards: [...adapters],
				onAdd: () => setShowAddWatch(true),
			},
		}));
	}


(old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
		})


(info) =>
					getAdapterCard(info, history, user, () =>
						handleRemoveWatch(info).catch(console.error),
					).catch(console.error)


() =>
						handleRemoveWatch(info).catch(console.error)


(c) => !!c


(c) => c as DashboardCardProps


(old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: {
				cards: [...adapters],
				onAdd: () => setShowAddWatch(true),
			},
		})


() => setShowAddWatch(true)


() => {
		const loadMyAdapters = async (user: User) => {
			setCategories((old) => ({
				...old,
				[MY_ADAPTERS_CATEGORY]: { cards: [] },
			})); // clear the list (and show the spinner)

			const infos = await getMyAdapterInfos(user.token);
			const cards = await Promise.all(
				infos.map((info) =>
					getAdapterCard(info, history, user).catch(console.error),
				),
			);

			const adapters = cards
				.filter((c) => !!c)
				.map((c) => c as DashboardCardProps);
			if (adapters.length === 0) {
				adapters.push({
					title: "No adapters found",
					img: "images/adapter-creator.png",
					text: "You can create your first ioBroker adapter by answering questions in the Adapter Creator.",
					buttons: [
						<CardButton
							text="Open Adapter Creator"
							to="/create-adapter"
						/>,
					],
				});
			}
			setCategories((old) => ({
				...old,
				Tools: { cards: getToolsCards(true) },
				[MY_ADAPTERS_CATEGORY]: { cards: [...adapters] },
			}));
		};

		if (user) {
			loadMyAdapters(user).catch(console.error);
			loadWatchedAdapters(user).catch(console.error);
		} else {
			const loginCard = (type: string) => ({
				title: "Login Required",
				img: "images/github.png",
				text: `You must be logged in to see your ${type}.`,
				buttons: [<CardButton text="Login" onClick={handleLogin} />],
			});
			setCategories((old) => {
				const result = { ...old };
				result.Tools = { cards: getToolsCards(false) };
				result[MY_ADAPTERS_CATEGORY] = {
					cards: [loginCard("adapters")],
				};
				delete result[WATCHED_ADAPTERS_CATEGORY];
				return result;
			});
		}
	}


async (user: User) => {
			setCategories((old) => ({
				...old,
				[MY_ADAPTERS_CATEGORY]: { cards: [] },
			})); // clear the list (and show the spinner)

			const infos = await getMyAdapterInfos(user.token);
			const cards = await Promise.all(
				infos.map((info) =>
					getAdapterCard(info, history, user).catch(console.error),
				),
			);

			const adapters = cards
				.filter((c) => !!c)
				.map((c) => c as DashboardCardProps);
			if (adapters.length === 0) {
				adapters.push({
					title: "No adapters found",
					img: "images/adapter-creator.png",
					text: "You can create your first ioBroker adapter by answering questions in the Adapter Creator.",
					buttons: [
						<CardButton
							text="Open Adapter Creator"
							to="/create-adapter"
						/>,
					],
				});
			}
			setCategories((old) => ({
				...old,
				Tools: { cards: getToolsCards(true) },
				[MY_ADAPTERS_CATEGORY]: { cards: [...adapters] },
			}));
		}


(old) => ({
				...old,
				[MY_ADAPTERS_CATEGORY]: { cards: [] },
			})


(info) =>
					getAdapterCard(info, history, user).catch(console.error)


(old) => ({
				...old,
				Tools: { cards: getToolsCards(true) },
				[MY_ADAPTERS_CATEGORY]: { cards: [...adapters] },
			})


(type: string) => ({
				title: "Login Required",
				img: "images/github.png",
				text: `You must be logged in to see your ${type}.`,
				buttons: [<CardButton text="Login" onClick={handleLogin} />],
			})


(old) => {
				const result = { ...old };
				result.Tools = { cards: getToolsCards(false) };
				result[MY_ADAPTERS_CATEGORY] = {
					cards: [loginCard("adapters")],
				};
				delete result[WATCHED_ADAPTERS_CATEGORY];
				return result;
			}


() => {
		const updateBlogIcon = async () => {
			const url =
				"https://raw.githubusercontent.com/ioBroker/ioBroker.docs/master/engine/front-end/public/blog.json";
			const { data: blog } = await axios.get<{
				pages: Record<
					string,
					{
						date: string;
						title: Record<string, string>;
						logo: string;
					}
				>;
			}>(url);
			const page = Object.values(blog.pages)[0];
			if (!page) return;
			setCategories((old) => {
				const res = old.Resources;
				const index = res.cards.findIndex((c) => c.title === "Blog");
				if (index >= 0) {
					const card = res.cards[index];
					const date = page.date.replace(
						/^(\d{4})\.(\d{2})\.(\d{2})$/,
						"$3.$2.$1",
					);
					res.cards[index] = {
						...card,
						img: `https://www.iobroker.net/${page.logo}`,
						text: `${card.text}\n \nLatest entry: ${page.title.en} (${date})`,
					};
				}
				return { ...old };
			});
		};
		updateBlogIcon().catch(console.error);
	}


async () => {
			const url =
				"https://raw.githubusercontent.com/ioBroker/ioBroker.docs/master/engine/front-end/public/blog.json";
			const { data: blog } = await axios.get<{
				pages: Record<
					string,
					{
						date: string;
						title: Record<string, string>;
						logo: string;
					}
				>;
			}>(url);
			const page = Object.values(blog.pages)[0];
			if (!page) return;
			setCategories((old) => {
				const res = old.Resources;
				const index = res.cards.findIndex((c) => c.title === "Blog");
				if (index >= 0) {
					const card = res.cards[index];
					const date = page.date.replace(
						/^(\d{4})\.(\d{2})\.(\d{2})$/,
						"$3.$2.$1",
					);
					res.cards[index] = {
						...card,
						img: `https://www.iobroker.net/${page.logo}`,
						text: `${card.text}\n \nLatest entry: ${page.title.en} (${date})`,
					};
				}
				return { ...old };
			});
		}


(old) => {
				const res = old.Resources;
				const index = res.cards.findIndex((c) => c.title === "Blog");
				if (index >= 0) {
					const card = res.cards[index];
					const date = page.date.replace(
						/^(\d{4})\.(\d{2})\.(\d{2})$/,
						"$3.$2.$1",
					);
					res.cards[index] = {
						...card,
						img: `https://www.iobroker.net/${page.logo}`,
						text: `${card.text}\n \nLatest entry: ${page.title.en} (${date})`,
					};
				}
				return { ...old };
			}


(c) => c.title === "Blog"


async (repo?: string) => {
		setShowAddWatch(false);
		if (!repo) {
			return;
		}
		try {
			setCategories((old) => ({
				...old,
				[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
			})); // show spinner
			const url = getApiUrl("user");
			const { data: dbUser } = await axios.get<DbUser>(url);
			dbUser.watches.push(repo);
			await axios.put(url, dbUser);
			onAdapterListChanged();
			await loadWatchedAdapters(user!);
		} catch (error) {
			console.error(error);
		}
	}


(old) => ({
				...old,
				[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
			})


async (info: AdapterInfos) => {
		setCategories((old) => ({
			...old,
			[WATCHED_ADAPTERS_CATEGORY]: { cards: [] },
		})); // show spinner
		const url = getApiUrl("user");
		const { data: dbUser } = await axios.get<DbUser>(url);
		dbUser.watches = dbUser.watches.filter(
			(w) => !equalIgnoreCase(w, info.repo.full_name),
		);
		await axios.put(url, dbUser);
		onAdapterListChanged();
		await loadWatchedAdapters(user!);
	}


(w) => !equalIgnoreCase(w, info.repo.full_name)


(title, index) => {
				const grid = categories[title];
				return (
					<Accordion
						key={index}
						expanded={!collapsed[index]}


interface AddWatchDialogProps {
	user: User;
	open?: boolean;
	onClose: (repo?: string) => void;
}


interface DashboardProps {
	user?: User;
	onAdapterListChanged: () => void;
}


(str) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? "-" : "") + $.toLowerCase())


($, ofs) => (ofs ? "-" : "") + $.toLowerCase()


export function shift(event: Partial<KeyboardEvent>) {
  return { ...event, shiftKey: true }
}


export function word(input: string): Partial<KeyboardEvent>[] {
  return input.split('').map(key => ({ key }))
}


export async function type(events: Partial<KeyboardEvent>[]) {
  jest.useFakeTimers()

  try {
    if (document.activeElement === null) return expect(document.activeElement).not.toBe(null)

    const element = document.activeElement
    const d = disposables()

    events.forEach(event => {
      fireEvent.keyDown(element, event)
    })

    // We don't want to actually wait in our tests, so let's advance
    jest.runAllTimers()

    await new Promise(d.nextFrame)
  } catch (err) {
    if (Error.captureStackTrace) Error.captureStackTrace(err, type)
    throw err
  } finally {
    jest.useRealTimers()
  }
}


export async function press(event: Partial<KeyboardEvent>) {
  return type([event])
}


export async function click(element: Document | Element | Window | Node | null) {
  try {
    if (element === null) return expect(element).not.toBe(null)

    const d = disposables()

    fireEvent.pointerDown(element)
    fireEvent.mouseDown(element)
    fireEvent.pointerUp(element)
    fireEvent.mouseUp(element)
    fireEvent.click(element)

    await new Promise(d.nextFrame)
  } catch (err) {
    if (Error.captureStackTrace) Error.captureStackTrace(err, click)
    throw err
  }
}


export async function focus(element: Document | Element | Window | Node | null) {
  try {
    if (element === null) return expect(element).not.toBe(null)

    const d = disposables()

    fireEvent.focus(element)

    await new Promise(d.nextFrame)
  } catch (err) {
    if (Error.captureStackTrace) Error.captureStackTrace(err, focus)
    throw err
  }
}


export async function mouseMove(element: Document | Element | Window | Node | null) {
  try {
    if (element === null) return expect(element).not.toBe(null)

    const d = disposables()

    fireEvent.mouseMove(element)

    await new Promise(d.nextFrame)
  } catch (err) {
    if (Error.captureStackTrace) Error.captureStackTrace(err, mouseMove)
    throw err
  }
}


export async function hover(element: Document | Element | Window | Node | null) {
  try {
    if (element === null) return expect(element).not.toBe(null)

    const d = disposables()

    fireEvent.pointerOver(element)
    fireEvent.pointerEnter(element)
    fireEvent.mouseOver(element)

    await new Promise(d.nextFrame)
  } catch (err) {
    if (Error.captureStackTrace) Error.captureStackTrace(err, hover)
    throw err
  }
}


export async function unHover(element: Document | Element | Window | Node | null) {
  try {
    if (element === null) return expect(element).not.toBe(null)

    const d = disposables()

    fireEvent.pointerOut(element)
    fireEvent.pointerLeave(element)
    fireEvent.mouseOut(element)
    fireEvent.mouseLeave(element)

    await new Promise(d.nextFrame)
  } catch (err) {
    if (Error.captureStackTrace) Error.captureStackTrace(err, unHover)
    throw err
  }
}


key => ({ key })


event => {
      fireEvent.keyDown(element, event)
    }


() => {
    const DEPT = {
        id: '1',
        whom: 'Paul',
        amount: '5000',
        currency: 'RUB',
        date: '2020-05-30',
        comment: 'Comment',
    };

    const INITIAL_STATE: DeptsState = {
        depts: [],
        isFetching: false,
        errorMessage: undefined,
    };

    let dispatchedActions: any[];
    let fakeStore: {};

    beforeEach(() => {
        dispatchedActions = [];
        fakeStore = {
            getState: () => INITIAL_STATE,
            dispatch: (action: Action) => dispatchedActions.push(action),
        };
    });

    describe('fetchDeptsAsync', () => {
        it('should load depts and handle them in case of success', async () => {
            const mockedDepts = [DEPT, DEPT];

            utils.request = jest.fn(() => Promise.resolve(mockedDepts));

            await runSaga(fakeStore, fetchDeptsAsync);

            expect(utils.request.mock.calls.length).toBe(1);
            expect(dispatchedActions).toContainEqual(fetchDeptsSuccess(mockedDepts));
        });

        it('should handle errors in case of fail', async () => {
            const error = { message: 'Some error is thrown' };

            utils.request = jest.fn(() => Promise.reject(error));

            await runSaga(fakeStore, fetchDeptsAsync);

            expect(utils.request.mock.calls.length).toBe(1);
            expect(dispatchedActions).toContainEqual(fetchDeptsFailure(error.message));
        });
    });
}


() => {
        dispatchedActions = [];
        fakeStore = {
            getState: () => INITIAL_STATE,
            dispatch: (action: Action) => dispatchedActions.push(action),
        };
    }


() => INITIAL_STATE


(action: Action) => dispatchedActions.push(action)


() => {
        it('should load depts and handle them in case of success', async () => {
            const mockedDepts = [DEPT, DEPT];

            utils.request = jest.fn(() => Promise.resolve(mockedDepts));

            await runSaga(fakeStore, fetchDeptsAsync);

            expect(utils.request.mock.calls.length).toBe(1);
            expect(dispatchedActions).toContainEqual(fetchDeptsSuccess(mockedDepts));
        });

        it('should handle errors in case of fail', async () => {
            const error = { message: 'Some error is thrown' };

            utils.request = jest.fn(() => Promise.reject(error));

            await runSaga(fakeStore, fetchDeptsAsync);

            expect(utils.request.mock.calls.length).toBe(1);
            expect(dispatchedActions).toContainEqual(fetchDeptsFailure(error.message));
        });
    }


async () => {
            const mockedDepts = [DEPT, DEPT];

            utils.request = jest.fn(() => Promise.resolve(mockedDepts));

            await runSaga(fakeStore, fetchDeptsAsync);

            expect(utils.request.mock.calls.length).toBe(1);
            expect(dispatchedActions).toContainEqual(fetchDeptsSuccess(mockedDepts));
        }


() => Promise.resolve(mockedDepts)


async () => {
            const error = { message: 'Some error is thrown' };

            utils.request = jest.fn(() => Promise.reject(error));

            await runSaga(fakeStore, fetchDeptsAsync);

            expect(utils.request.mock.calls.length).toBe(1);
            expect(dispatchedActions).toContainEqual(fetchDeptsFailure(error.message));
        }


function getCSSPath(el: any, ignoreIds: boolean) {
  if (!(el instanceof Element)) {
    return
  }
  const path = []
  while (el.nodeType === Node.ELEMENT_NODE) {
    let selector = el.nodeName.toLowerCase()
    if (el.id && !ignoreIds) {
      selector += '#' + el.id.replace(/(:|\.|\[|\]|,)/g, '\\$1')
      path.unshift(selector)
      break
    } else {
      let sib = el
      let nth = 1
      /* tslint:disable-next-line: no-conditional-assignment */
      while ((sib = sib.previousElementSibling)) {
        if (sib.nodeName.toLowerCase() === selector) {
          nth++
        }
      }
      if (nth !== 1) {
        selector += `:nth-of-type(${nth})`
      }
    }
    path.unshift(selector)
    el = el.parentNode
    if (el == null) {
      return
    }
  }
  return path.join(' > ')
}


function processPath(elementPath: any) {
  if (!elementPath) { return '' }

  const numPathElements = elementPath.length
  const path = []

  let uniqueEl = false
  for (let i = 0; i < numPathElements - 1 && !uniqueEl; i++) {
    if (elementPath[i].id != null && elementPath[i].id !== '') {
      uniqueEl = true
      path.push({
        uniqueId: elementPath[i].id,
        tagName: elementPath[i].tagName
      })
    } else {
      let childIndex = null
      for (let j = 0; elementPath[i].parentNode != null && j < elementPath[i].parentNode.childNodes.length; j++) {
        if (elementPath[i].parentNode.childNodes[j] === elementPath[i]) {
          childIndex = j
        }
      }
      if (childIndex == null && elementPath[i] === document) {
        // WTF
      } else {
        path.push({
          uniqueId: null,
          childIndex,
          tagName: elementPath[i].tagName
        })
      }
    }
  }

  return path
}


(store: any) => {
  if (store.isRecording) {
    startRecording()
  } else {
    removeListeners()
  }
}


(msg, sender, sendResponse) => {
  console.log('message:', msg)
  if (msg.record === true) {
    console.log('starting to record')
    startRecording()
    chrome.runtime.sendMessage({ type: MessageType.Record, payload: true })
    chrome.runtime.sendMessage({
      type: MessageType.NewEvent,
      payload: {
        name: 'start',
        data: {url: window.location.href, screenWidth: window.screen.width, screenHeight: window.screen.height},
        time: Number(Date.now())
      }
    })
  } else if (msg.record === false) {
    console.log('stopping to record')
    removeListeners()
    chrome.runtime.sendMessage({
      type: MessageType.NewEvent,
      payload: {
        name: 'end',
        data: {url: window.location.href},
        time: Number(Date.now())
      }
    })
    chrome.runtime.sendMessage({ type: MessageType.StopRecording, payload: msg.scenarioId })
  } else {
    sendResponse('unknown command.')
  }
}


() => {
  console.log('removing listeners')
  Array.from(listeners.keys()).forEach((k: string) => {
    const lst = listeners.get(k)
    if (lst) {
      lst.forEach((l: EventListenerOrEventListenerObject) => {
        console.log('removing listener', k)
        document.body.removeEventListener(k, l)
      })
    }
  })
  const scl = listeners.get('scroll')
  if (scl) {
    window.removeEventListener('scroll', scl[0], false)
  }
}


(k: string) => {
    const lst = listeners.get(k)
    if (lst) {
      lst.forEach((l: EventListenerOrEventListenerObject) => {
        console.log('removing listener', k)
        document.body.removeEventListener(k, l)
      })
    }
  }


(l: EventListenerOrEventListenerObject) => {
        console.log('removing listener', k)
        document.body.removeEventListener(k, l)
      }


() => {
  console.log('adding listeners')
  Object.values(DOMEvent).forEach(addDocumentEventListener)
}


(eventName: string) => {
  const listener = listenerHandler(eventName)
  const evtListeners = listeners.get(eventName)
  if (evtListeners) {
    evtListeners.push(listener)
  } else {
    listeners.set(eventName, [listener])
  }
  if (eventName === DOMEvent.Scroll) {
    window.addEventListener(eventName, throttle(listener, 1000))
  } else {
    document.body.addEventListener(eventName, listener, false)
  }
}


(eventName: string) => (e: Event | any) => {
  const mEvt = e as MouseEvent
  const kEvt = e as KeyboardEvent
  const eventData = {
    path: processPath(e.path),
    csspath: getCSSPath(e.target, false),
    csspathfull: getCSSPath(e.target, true),
    clientX: mEvt.clientX,
    clientY: mEvt.clientY,
    scrollX: window.scrollX,
    scrollY: window.scrollY,
    // altKey: mEvt.altKey,
    // ctrlKey: mEvt.ctrlKey,
    // shiftKey: mEvt.shiftKey,
    // metaKey: mEvt.metaKey,
    button: mEvt.button,
    // bubbles: e.bubbles,
    keyCode: -1,
    selectValue: '',
    value: '',
    type: '',
    // cancelable: e.cancelable,
    innerText: e.target ? (e.target as HTMLInputElement).innerText || '' : '',
    url: window.location.href
  }

  if (eventName === 'select') {
    eventData.selectValue = kEvt.target ? (kEvt.target as HTMLSelectElement).value : ''
  }

  if (eventName === 'keyup' || eventName === 'keydown' || eventName === 'keypress') {
    eventData.keyCode = kEvt.keyCode
  }

  if (eventName === 'input' || eventName === 'propertychange' || eventName === 'change') {
    eventData.type = kEvt.target ? (kEvt.target as HTMLInputElement).tagName.toLowerCase() : ''

    /* tslint:disable-next-line: prefer-conditional-expression */
    if (eventData.type === 'input' || eventData.type === 'textarea') {
      eventData.value = (e.target as HTMLInputElement).value
    } else {
      eventData.value = (e.target as HTMLInputElement).innerText
    }
  }

  if (eventName === 'cut') {
    eventName = 'clipboard_cut'
  }
  if (eventName === 'copy') {
    eventName = 'clipboard_copy'
  }
  if (eventName === 'paste') {
    eventName = 'clipboard_paste'
  }
  if (eventName === 'wfSubmit') {
    eventName = 'submit'
  }
  chrome.storage.local.get(StorageKey.IsRecording, (store: any) => {
    if (store.isRecording) {
      chrome.runtime.sendMessage({
        type: MessageType.NewEvent,
        payload: {
          name: eventName,
          data: eventData,
          time: Number(Date.now())
        }
      })
    }
  })
}


(e: Event | any) => {
  const mEvt = e as MouseEvent
  const kEvt = e as KeyboardEvent
  const eventData = {
    path: processPath(e.path),
    csspath: getCSSPath(e.target, false),
    csspathfull: getCSSPath(e.target, true),
    clientX: mEvt.clientX,
    clientY: mEvt.clientY,
    scrollX: window.scrollX,
    scrollY: window.scrollY,
    // altKey: mEvt.altKey,
    // ctrlKey: mEvt.ctrlKey,
    // shiftKey: mEvt.shiftKey,
    // metaKey: mEvt.metaKey,
    button: mEvt.button,
    // bubbles: e.bubbles,
    keyCode: -1,
    selectValue: '',
    value: '',
    type: '',
    // cancelable: e.cancelable,
    innerText: e.target ? (e.target as HTMLInputElement).innerText || '' : '',
    url: window.location.href
  }

  if (eventName === 'select') {
    eventData.selectValue = kEvt.target ? (kEvt.target as HTMLSelectElement).value : ''
  }

  if (eventName === 'keyup' || eventName === 'keydown' || eventName === 'keypress') {
    eventData.keyCode = kEvt.keyCode
  }

  if (eventName === 'input' || eventName === 'propertychange' || eventName === 'change') {
    eventData.type = kEvt.target ? (kEvt.target as HTMLInputElement).tagName.toLowerCase() : ''

    /* tslint:disable-next-line: prefer-conditional-expression */
    if (eventData.type === 'input' || eventData.type === 'textarea') {
      eventData.value = (e.target as HTMLInputElement).value
    } else {
      eventData.value = (e.target as HTMLInputElement).innerText
    }
  }

  if (eventName === 'cut') {
    eventName = 'clipboard_cut'
  }
  if (eventName === 'copy') {
    eventName = 'clipboard_copy'
  }
  if (eventName === 'paste') {
    eventName = 'clipboard_paste'
  }
  if (eventName === 'wfSubmit') {
    eventName = 'submit'
  }
  chrome.storage.local.get(StorageKey.IsRecording, (store: any) => {
    if (store.isRecording) {
      chrome.runtime.sendMessage({
        type: MessageType.NewEvent,
        payload: {
          name: eventName,
          data: eventData,
          time: Number(Date.now())
        }
      })
    }
  })
}


(store: any) => {
    if (store.isRecording) {
      chrome.runtime.sendMessage({
        type: MessageType.NewEvent,
        payload: {
          name: eventName,
          data: eventData,
          time: Number(Date.now())
        }
      })
    }
  }


export async function handler(argv: any) {
  verifySetup();

  if (!argv.skipBuild && argv.buildTaskName && argv.buildTaskName.length > 0) {
    runPackageScript([argv.buildTaskName]);
  }

  const options = {
    destinationPath: argv.destination,
    sourcePath: argv.source,
    excludeFile: argv.exclude,
    clean: argv.clean,
  };

  if (!options.sourcePath || !options.destinationPath) {
    const packageJson = await resolvePackage();

    if (!options.sourcePath) {
      options.sourcePath = packageJson.config.buildArtifactsPath;
      if (!options.sourcePath) {
        // nothing explicit set, let's try to imply a path. 'build/index.html' = CRA convention
        if (fs.existsSync('build/index.html')) {
          options.sourcePath = path.resolve('build');
        } else if (fs.existsSync('dist/client.bundle.js')) {
          // /dist = non-CRA convention
          options.sourcePath = path.resolve('dist');
        } else {
          throw new Error(
            'No source path specified, conventional build paths missing, and buildArtifactsPath config is not defined in package.json!'
          );
        }
      }
    }

    if (!options.destinationPath) {
      const scJssConfig = await resolveScJssConfig();

      options.destinationPath = path.join(
        scJssConfig.sitecore.instancePath as string,
        packageJson.config.sitecoreDistPath
      );
    }
  }

  deploy(options);
}


(props: RenderLayerProps) => {
    const {
        diagram,
        previewItems,
        renderContainer,
        rendererService,
        onRender,
    } = props;

    const shapesRendered = React.useRef(onRender);
    const shapeRefsById = React.useRef<{ [id: string]: ShapeRef }>({});

    const orderedShapes = React.useMemo(() => {
        const flattenShapes: DiagramItem[] = [];

        if (diagram) {
            let handleContainer: (itemIds: DiagramContainer) => any;

            // eslint-disable-next-line prefer-const
            handleContainer = itemIds => {
                for (const id of itemIds.values) {
                    const item = diagram.items.get(id);

                    if (item) {
                        if (item.type === 'Shape') {
                            flattenShapes.push(item);
                        }

                        if (item.type === 'Group') {
                            handleContainer(item.childIds);
                        }
                    }
                }
            };

            handleContainer(diagram.itemIds);
        }

        return flattenShapes;
    }, [diagram]);

    React.useEffect(() => {
        const allShapesById: { [id: string]: boolean } = {};
        const allShapes = orderedShapes;

        allShapes.forEach(item => {
            allShapesById[item.id] = true;
        });

        const references = shapeRefsById.current;

        // Delete old shapes.
        for (const [id, ref] of Object.entries(references)) {
            if (!allShapesById[id]) {
                ref.remove();

                delete references[id];
            }
        }

        // Create missing shapes.
        for (const shape of allShapes) {
            if (!references[shape.id]) {
                const rendererInstance = rendererService.get(shape.renderer);

                references[shape.id] = new ShapeRef(renderContainer, rendererInstance, showDebugOutlines);
            }
        }

        let hasIdChanged = false;

        allShapes.forEach((shape, i) => {
            if (!references[shape.id].checkIndex(i)) {
                hasIdChanged = true;
            }
        });

        // If the index of at least once shape has changed we have to remove them all to render them in the correct order.
        if (hasIdChanged) {
            for (const ref of Object.values(references)) {
                ref.remove();
            }
        }

        for (const shape of allShapes) {
            references[shape.id].render(shape);
        }

        if (shapesRendered.current) {
            shapesRendered.current();
        }
    }, [renderContainer, orderedShapes, rendererService]);

    React.useEffect(() => {
        if (previewItems) {
            for (const item of previewItems) {
                shapeRefsById.current[item.id]?.setPreview(item);
            }
        } else {
            for (const reference of Object.values(shapeRefsById.current)) {
                reference.setPreview(null);
            }
        }
    }, [previewItems]);

    return null;
}


() => {
        const flattenShapes: DiagramItem[] = [];

        if (diagram) {
            let handleContainer: (itemIds: DiagramContainer) => any;

            // eslint-disable-next-line prefer-const
            handleContainer = itemIds => {
                for (const id of itemIds.values) {
                    const item = diagram.items.get(id);

                    if (item) {
                        if (item.type === 'Shape') {
                            flattenShapes.push(item);
                        }

                        if (item.type === 'Group') {
                            handleContainer(item.childIds);
                        }
                    }
                }
            };

            handleContainer(diagram.itemIds);
        }

        return flattenShapes;
    }


itemIds => {
                for (const id of itemIds.values) {
                    const item = diagram.items.get(id);

                    if (item) {
                        if (item.type === 'Shape') {
                            flattenShapes.push(item);
                        }

                        if (item.type === 'Group') {
                            handleContainer(item.childIds);
                        }
                    }
                }
            }


() => {
        const allShapesById: { [id: string]: boolean } = {};
        const allShapes = orderedShapes;

        allShapes.forEach(item => {
            allShapesById[item.id] = true;
        });

        const references = shapeRefsById.current;

        // Delete old shapes.
        for (const [id, ref] of Object.entries(references)) {
            if (!allShapesById[id]) {
                ref.remove();

                delete references[id];
            }
        }

        // Create missing shapes.
        for (const shape of allShapes) {
            if (!references[shape.id]) {
                const rendererInstance = rendererService.get(shape.renderer);

                references[shape.id] = new ShapeRef(renderContainer, rendererInstance, showDebugOutlines);
            }
        }

        let hasIdChanged = false;

        allShapes.forEach((shape, i) => {
            if (!references[shape.id].checkIndex(i)) {
                hasIdChanged = true;
            }
        });

        // If the index of at least once shape has changed we have to remove them all to render them in the correct order.
        if (hasIdChanged) {
            for (const ref of Object.values(references)) {
                ref.remove();
            }
        }

        for (const shape of allShapes) {
            references[shape.id].render(shape);
        }

        if (shapesRendered.current) {
            shapesRendered.current();
        }
    }


item => {
            allShapesById[item.id] = true;
        }


(shape, i) => {
            if (!references[shape.id].checkIndex(i)) {
                hasIdChanged = true;
            }
        }


() => {
        if (previewItems) {
            for (const item of previewItems) {
                shapeRefsById.current[item.id]?.setPreview(item);
            }
        } else {
            for (const reference of Object.values(shapeRefsById.current)) {
                reference.setPreview(null);
            }
        }
    }


export interface RenderLayerProps {
    // The renderer service.
    rendererService: RendererService;

    // The selected diagram.
    diagram?: Diagram;

    // The container to render on.
    renderContainer: svg.Container;

    // The preview items.
    previewItems?: ReadonlyArray<DiagramItem>;

    // True when rendered.
    onRender?: () => void;
}


export default function () {
  on("RESIZE_WINDOW", function (windowSize: { width: number; height: number }) {
    const { width, height } = windowSize;
    figma.ui.resize(width, height);
  });

  showUI({
    height: 500,
    width: 500,
  });
}


function _CalendarHeader<T>({
  dateRange,
  cellHeight,
  style,
  allDayEvents,
  onPressDateHeader,
  DayNumberContainerStyle,
  events,
  onPressEvent = () => console.log('onPressEvent'),
}: CalendarHeaderProps<T>) {
  const _onPress = React.useCallback(
    (date: Date) => {
      onPressDateHeader && onPressDateHeader(date)
    },
    [onPressDateHeader],
  )

  const theme = useTheme()
  // const [showMore, setShowMore] = React.useState(false)

  const borderColor = { borderColor: theme.palette.gray['200'] }
  const primaryBg = { backgroundColor: theme.palette.primary.main }

  const appendZero = (hexaValue) => {
    while (hexaValue.length < 2) hexaValue = '0' + hexaValue
    return hexaValue
  }

  const calculateWeightedColor = (dayEvents) => {
    let totalDuration = 0
    let totalR = 0
    let totalG = 0
    let totalB = 0
    dayEvents.forEach((element) => {
      const r = parseInt(element.color.substring(0, 2), 16) * element.duration
      const g = parseInt(element.color.substring(2, 4), 16) * element.duration
      const b = parseInt(element.color.substring(4, 6), 16) * element.duration
      totalR = totalR + r
      totalG = totalG + g
      totalB = totalB + b
      totalDuration = totalDuration + element.duration
    })
    const meanR = Math.round(totalR / totalDuration)
    const meanG = Math.round(totalG / totalDuration)
    const meanB = Math.round(totalB / totalDuration)
    const weightedColor =
      '#' +
      appendZero(meanR.toString(16).toUpperCase()) +
      appendZero(meanG.toString(16).toUpperCase()) +
      appendZero(meanB.toString(16).toUpperCase())
    return weightedColor
  }

  const todayColor = (date, isTopDay) => {
    const todayEvents = events
      .filter(({ start }) =>
        dayjs(start).isBetween(date.startOf('day'), date.endOf('day'), null, '[)'),
      )
      .map((i) => {
        if (!(i && i.color)) i.color = '#FFFF00'
        return {
          color: i.color.substring(1, 7),
          duration: dayjs(i.end).diff(dayjs(i.start), 'hour', true),
        }
      })
    if (todayEvents.length == 0 && !isTopDay) return 'transparent'
    if (todayEvents.length == 0 && isTopDay) return '#2E2E2E'
    let weightedColor = calculateWeightedColor(todayEvents)
    return weightedColor
  }

  return (
    <View
      style={[
        u['border-b-2'],
        u['pt-2'],
        { backgroundColor: '#FAFAFA' },
        borderColor,
        theme.isRTL ? u['flex-row-reverse'] : u['flex-row'],
        style,
      ]}
    >
      <View style={[u['w-50'], u['items-center']]}>
        <Text style={[theme.typography.xs, u['mb-4']]}>Week</Text>
        <View style={[u['w-36'], u['h-36'], u['bordered'], u['justify-center'], u['items-center']]}>
          <Text style={[theme.typography.xl]}>
            {Math.ceil(parseInt(dayjs(dateRange[0]).format('DD')) / 7)}
          </Text>
        </View>
        <Text style={[theme.typography.xs, u['mt-6']]}>All day</Text>
      </View>
      {dateRange.map((date) => {
        const _isToday = isToday(date)
        return (
          <TouchableOpacity
            style={[u['flex-1'], u['pt-2'], u['mb-2']]}
            onPress={() => _onPress(date.toDate())}
            disabled={onPressDateHeader === undefined}
            key={date.toString()}
          >
            <View style={[u['justify-between'], { minHeight: cellHeight }]}>
              <Text
                style={[
                  theme.typography.xs,
                  u['text-center'],
                  u['mb-4'],
                  {
                    color: todayColor(date, true),
                    fontFamily: 'segoeui',
                    fontSize: 11,
                  },
                ]}
              >
                {date.format('ddd')[0]}
              </Text>
              <View
                style={
                  !_isToday
                    ? [
                        primaryBg,
                        u['h-36'],
                        u['w-36'],
                        u['rounded-full'],
                        u['items-center'],
                        u['justify-center'],
                        u['self-center'],
                        u['z-20'],
                        DayNumberContainerStyle,
                        { backgroundColor: todayColor(date, false) },
                      ]
                    : [
                        primaryBg,
                        u['h-36'],
                        u['w-36'],
                        u['pb-2'],
                        u['rounded-full'],
                        u['items-center'],
                        u['justify-center'],
                        u['self-center'],
                        u['z-20'],
                        {
                          borderWidth: 2.5,
                          borderColor: todayColor(date, false),
                          backgroundColor: 'transparent',
                        },
                      ]
                }


() => console.log('onPressEvent')


(date: Date) => {
      onPressDateHeader && onPressDateHeader(date)
    }


(hexaValue) => {
    while (hexaValue.length < 2) hexaValue = '0' + hexaValue
    return hexaValue
  }


(dayEvents) => {
    let totalDuration = 0
    let totalR = 0
    let totalG = 0
    let totalB = 0
    dayEvents.forEach((element) => {
      const r = parseInt(element.color.substring(0, 2), 16) * element.duration
      const g = parseInt(element.color.substring(2, 4), 16) * element.duration
      const b = parseInt(element.color.substring(4, 6), 16) * element.duration
      totalR = totalR + r
      totalG = totalG + g
      totalB = totalB + b
      totalDuration = totalDuration + element.duration
    })
    const meanR = Math.round(totalR / totalDuration)
    const meanG = Math.round(totalG / totalDuration)
    const meanB = Math.round(totalB / totalDuration)
    const weightedColor =
      '#' +
      appendZero(meanR.toString(16).toUpperCase()) +
      appendZero(meanG.toString(16).toUpperCase()) +
      appendZero(meanB.toString(16).toUpperCase())
    return weightedColor
  }


(element) => {
      const r = parseInt(element.color.substring(0, 2), 16) * element.duration
      const g = parseInt(element.color.substring(2, 4), 16) * element.duration
      const b = parseInt(element.color.substring(4, 6), 16) * element.duration
      totalR = totalR + r
      totalG = totalG + g
      totalB = totalB + b
      totalDuration = totalDuration + element.duration
    }


(date, isTopDay) => {
    const todayEvents = events
      .filter(({ start }) =>
        dayjs(start).isBetween(date.startOf('day'), date.endOf('day'), null, '[)'),
      )
      .map((i) => {
        if (!(i && i.color)) i.color = '#FFFF00'
        return {
          color: i.color.substring(1, 7),
          duration: dayjs(i.end).diff(dayjs(i.start), 'hour', true),
        }
      })
    if (todayEvents.length == 0 && !isTopDay) return 'transparent'
    if (todayEvents.length == 0 && isTopDay) return '#2E2E2E'
    let weightedColor = calculateWeightedColor(todayEvents)
    return weightedColor
  }


({ start }) =>
        dayjs(start).isBetween(date.startOf('day'), date.endOf('day'), null, '[)')


(i) => {
        if (!(i && i.color)) i.color = '#FFFF00'
        return {
          color: i.color.substring(1, 7),
          duration: dayjs(i.end).diff(dayjs(i.start), 'hour', true),
        }
      }


(date) => {
        const _isToday = isToday(date)
        return (
          <TouchableOpacity
            style={[u['flex-1'], u['pt-2'], u['mb-2']]}
            onPress={() => _onPress(date.toDate())}


(event, index) => {
                if (!dayjs(event.start).isSame(date, 'day')) {
                  return null
                }
                if (index <= 2)
                  return (
                    <TouchableOpacity
                      style={[
                        eventCellCss.style,
                        primaryBg,
                        { width: getWidthOfAllDayInPercent(event.start, event.end) + '%' },
                      ]}
                      key={`${event.start}${event.title}`}


export interface CalendarHeaderProps<T> {
  dateRange: dayjs.Dayjs[]
  cellHeight: number
  style: ViewStyle
  allDayEvents: ICalendarEvent<T>[]
  DayNumberContainerStyle: ViewStyle
  events: ICalendarEvent<T>[]
  onPressDateHeader?: (date: Date) => void
  onPressEvent?: (event: ICalendarEvent<T>) => void
}


moment(date


export declare class FormatTimerPipe implements PipeTransform {
    transform(totalSeconds: number): string;
    static ɵfac: ɵngcc0.ɵɵFactoryDef<FormatTimerPipe, never>;
    static ɵpipe: ɵngcc0.ɵɵPipeDefWithMeta<FormatTimerPipe, "formatTimer">;
}


transform(totalSeconds: number): string;


({ host, apiKey }) =>
  ({
    headers: { host },
    header: jest.fn().mockReturnValue(apiKey),
  } as unknown as Request)


({ req = makeRequestObject(collections.apikeys[0]) }) => {
  const json = jest.fn();
  const next = jest.fn();
  const status = jest.fn().mockReturnValue({ json });

  return {
    sut: validateApiKey(
      req,
      {
        status,
      } as unknown as Response,
      next
    ),
    next,
    status,
    json,
  };
}


() => {
  beforeAll(async () => {
    await connect();
    await collectionInit(ApiKeyModel, CollectionNames.ApiKeys);
  });

  afterAll(async () => {
    await dropDatabase();
    await disconnect();
  });

  it('should increment the usage of api key', async () => {
    const { next, sut } = makeSut({});
    await sut;
    expect(next).toHaveBeenCalledTimes(1);
  });

  it('should add new usage of api key', async () => {
    const { next, sut } = makeSut({ req: makeRequestObject(collections.apikeys[2]) });
    await sut;
    expect(next).toHaveBeenCalledTimes(1);
  });

  it('should call status with 429 due to max api key usage exceeded', async () => {
    const { status, sut } = makeSut({
      req: makeRequestObject(collections.apikeys[1]),
    });
    await sut;
    expect(status).toHaveBeenCalledWith(429);
  });

  it('should call status with 403 due to api key undefined', async () => {
    const { status, sut } = makeSut({
      req: { host: 'localhost' } as any,
    });
    await sut;
    expect(status).toHaveBeenCalledWith(403);
  });
}


async () => {
    await connect();
    await collectionInit(ApiKeyModel, CollectionNames.ApiKeys);
  }


async () => {
    await dropDatabase();
    await disconnect();
  }


async () => {
    const { next, sut } = makeSut({});
    await sut;
    expect(next).toHaveBeenCalledTimes(1);
  }


async () => {
    const { next, sut } = makeSut({ req: makeRequestObject(collections.apikeys[2]) });
    await sut;
    expect(next).toHaveBeenCalledTimes(1);
  }


async () => {
    const { status, sut } = makeSut({
      req: makeRequestObject(collections.apikeys[1]),
    });
    await sut;
    expect(status).toHaveBeenCalledWith(429);
  }


async () => {
    const { status, sut } = makeSut({
      req: { host: 'localhost' } as any,
    });
    await sut;
    expect(status).toHaveBeenCalledWith(403);
  }


export interface IResourcePieChartProps extends PieChartProps {
  resourceCollection: ResourceCollection;
  render?(data: any): React.ReactNode | React.ReactNodeArray;
}


() => { this.view_loaded(); }


/**
     * This is the base controller that all other controllers should utilize.
     *
     * It handles saving a reference to the Angular scope, newing up the given
     * model object type, and injecting the view model and controller onto the
     * scope object for use in views.
     *
     * T - The parameter type for the model.
     */
export abstract class BaseController<T> {
        protected scope: ng.IScope;
        protected viewModel: T;

        constructor(scope: ng.IScope, ModelType: { new (): T; }) {

            // Uncomment for debugging view events.
            //console.log("ctor()  " + this.constructor["ID"]);

            // Save a reference to Angular's scope object.
            this.scope = scope;

            // Create the view model.
            this.viewModel = new ModelType();

            /* tslint:disable:no-string-literal */

            // Push the view model onto the scope so it can be
            // referenced from the template/views.
            this.scope["viewModel"] = this.viewModel;

            // Push the controller onto the scope so it can be
            // used to reference events for controls etc.
            this.scope["controller"] = this;

            /* tslint:enable:no-string-literal */

            _.defer(() => { this.view_loaded(); });
        }

        /**
         * Invoked when the controller has been bound to a template.
         *
         * Can be overridden by implementing controllers.
         */
        protected view_loaded(): void {
            /* tslint:disable:no-empty */
            /* tslint:enable:no-empty */
        }
    }


/**
         * Invoked when the controller has been bound to a template.
         *
         * Can be overridden by implementing controllers.
         */
protected view_loaded(): void {
            /* tslint:disable:no-empty */
            /* tslint:enable:no-empty */
        }


export default function Plans() {
    const router = useRouter();

    const [location, setLocation] = useState('');

    useEffect(() => {
        setLocation('Estados Unidos');
    }, []);

    const switchLocation = (location: string) => {
        setLocation(location);
    };

    return (
        <>

 switchLocation('Estados Unidos')}


() => {
        setLocation('Estados Unidos');
    }


(location: string) => {
        setLocation(location);
    }


() => router.push('/servers')


() => <Panel>{lorem}</Panel>)
  .add("narrow", () => <Panel narrow={true}>{lorem}</Panel>)
  .add("with header text", () => <Panel headerText="Sample header text">{lorem}</Panel>)
  .add("with header text and icon", () => (
    <Panel headerText="Sample header text" icon={icon}>
      {lorem}
    </Panel>
  ))
  .add("with header text and right component", () => (
    <Panel
      headerText="Sample header text"
      rightComponent={<ButtonInline onClick={action("onClick")}>Go to Wallet</ButtonInline>}
    >
      {lorem}
    </Panel>
  ))
  .add("rounded", () => <PanelRounded>{lorem}</PanelRounded>);


() => <Panel narrow


() => <Panel headerText


() => (
    <Panel headerText="Sample header text"


() => (
    <Panel
      headerText="Sample header text"


() => <PanelRounded>{lorem}</PanelRounded>);


action("onClick")


() => {
  return (
    <>
      <Seo templateTitle='Ingfo' />

Ingfo

                  Situs ini {'"'}terinspirasi{'"'} dari punyanya informatika,
                  buatannya si{' '}
                  <CustomLink href='https://theodorusclarence.com'>
                    Clarence
                  </CustomLink>
                  . Nih{' '}
                  <CustomLink href='https://class.thcl.dev/'>
                    linknya
                  </CustomLink>

                  Kalau ada bug atau saran fitur bisa bikin issue atau kalo bisa
                  PR ke repo berikut:

                <ArrowLink href='https://github.com/lordronz/dtk-class-helper'>
                  Source code
                </ArrowLink>

                  Bisa jg lewat{' '}
                  <CustomLink href='#comment-section'>
                    comment section
                  </CustomLink>{' '}
                  yg ada disini atau di{' '}
                  <CustomLink href='/#comment-section'>Home</CustomLink>

Atau pm aja sih ya, buat yg kenal

                  Karena yang buat ini juga manusia, bisa aja salah, mungkin
                  salah typo/bug lain. Kalo saran fitur jg sangat boleh. Atau
                  mungkin mau komplen soal styling jg ga masalah. Misal warnanya
                  dark bgt nih, merah semua nih, atau ga keliatan fontnya atau
                  kekecilan fontnya atau ada saran font jg sangat diperbolehkan.

Data matkul

                <ArrowLink href='/api/matkul' openNewTab>
                  Link API JSON
                </ArrowLink>

Kontak

                <Contact />

              <ArrowLink href='/' className='text-primary-200' direction='left'>
                Balik ke Home
              </ArrowLink>

              <Comment />

    </>


/**
 *
Creates and defines the settings for a classification job.

 * @example
 * Use a bare-bones client and the command you need to make an API call.
 * ```javascript
 * import { Macie2Client, CreateClassificationJobCommand } from "@aws-sdk/client-macie2"; // ES Modules import
 * // const { Macie2Client, CreateClassificationJobCommand } = require("@aws-sdk/client-macie2"); // CommonJS import
 * const client = new Macie2Client(config);
 * const command = new CreateClassificationJobCommand(input);
 * const response = await client.send(command);
 * ```
 *
 * @see {@link CreateClassificationJobCommandInput} for command's `input` shape.
 * @see {@link CreateClassificationJobCommandOutput} for command's `response` shape.
 * @see {@link Macie2ClientResolvedConfig | config} for command's `input` shape.
 *
 */
export class CreateClassificationJobCommand extends $Command<
  CreateClassificationJobCommandInput,
  CreateClassificationJobCommandOutput,
  Macie2ClientResolvedConfig
> {
  // Start section: command_properties
  // End section: command_properties

  constructor(readonly input: CreateClassificationJobCommandInput) {
    // Start section: command_constructor
    super();
    // End section: command_constructor
  }

  /**
   * @internal
   */
  resolveMiddleware(
    clientStack: MiddlewareStack<ServiceInputTypes, ServiceOutputTypes>,
    configuration: Macie2ClientResolvedConfig,
    options?: __HttpHandlerOptions
  ): Handler<CreateClassificationJobCommandInput, CreateClassificationJobCommandOutput> {
    this.middlewareStack.use(getSerdePlugin(configuration, this.serialize, this.deserialize));

    const stack = clientStack.concat(this.middlewareStack);

    const { logger } = configuration;
    const clientName = "Macie2Client";
    const commandName = "CreateClassificationJobCommand";
    const handlerExecutionContext: HandlerExecutionContext = {
      logger,
      clientName,
      commandName,
      inputFilterSensitiveLog: CreateClassificationJobRequest.filterSensitiveLog,
      outputFilterSensitiveLog: CreateClassificationJobResponse.filterSensitiveLog,
    };
    const { requestHandler } = configuration;
    return stack.resolve(
      (request: FinalizeHandlerArguments<any>) =>
        requestHandler.handle(request.request as __HttpRequest, options || {}),
      handlerExecutionContext
    );
  }

  private serialize(input: CreateClassificationJobCommandInput, context: __SerdeContext): Promise<__HttpRequest> {
    return serializeAws_restJson1CreateClassificationJobCommand(input, context);
  }

  private deserialize(output: __HttpResponse, context: __SerdeContext): Promise<CreateClassificationJobCommandOutput> {
    return deserializeAws_restJson1CreateClassificationJobCommand(output, context);
  }

  // Start section: command_body_extra
  // End section: command_body_extra
}


export interface CreateClassificationJobCommandInput extends CreateClassificationJobRequest {}


export interface CreateClassificationJobCommandOutput extends CreateClassificationJobResponse, __MetadataBearer {}


/**
   * @internal
   */
resolveMiddleware(
    clientStack: MiddlewareStack<ServiceInputTypes, ServiceOutputTypes>,
    configuration: Macie2ClientResolvedConfig,
    options?: __HttpHandlerOptions
  ): Handler<CreateClassificationJobCommandInput, CreateClassificationJobCommandOutput> {
    this.middlewareStack.use(getSerdePlugin(configuration, this.serialize, this.deserialize));

    const stack = clientStack.concat(this.middlewareStack);

    const { logger } = configuration;
    const clientName = "Macie2Client";
    const commandName = "CreateClassificationJobCommand";
    const handlerExecutionContext: HandlerExecutionContext = {
      logger,
      clientName,
      commandName,
      inputFilterSensitiveLog: CreateClassificationJobRequest.filterSensitiveLog,
      outputFilterSensitiveLog: CreateClassificationJobResponse.filterSensitiveLog,
    };
    const { requestHandler } = configuration;
    return stack.resolve(
      (request: FinalizeHandlerArguments<any>) =>
        requestHandler.handle(request.request as __HttpRequest, options || {}),
      handlerExecutionContext
    );
  }


private serialize(input: CreateClassificationJobCommandInput, context: __SerdeContext): Promise<__HttpRequest> {
    return serializeAws_restJson1CreateClassificationJobCommand(input, context);
  }


private deserialize(output: __HttpResponse, context: __SerdeContext): Promise<CreateClassificationJobCommandOutput> {
    return deserializeAws_restJson1CreateClassificationJobCommand(output, context);
  }


({
  title, description, typographyProps, to, external, linkText, onClick,
}: Props) => {
  const hasLinkText = useMemo(() => Boolean(linkText), [linkText]);

  const renderTitle = useCallback(() => {
    const { typography = 'Subtitle1', ...restTypographyProps } = typographyProps || {};
    return (
      <Title md={typography} {...restTypographyProps}


() => Boolean(linkText)


() => {
    const { typography = 'Subtitle1', ...restTypographyProps } = typographyProps || {};
    return (
      <Title md={typography} {


() => (
    <>
      <HeaderTop>
        {renderTitle()}
        <LinkButton />
      </HeaderTop>


() => {
    if (to) {
      return (
        <>
          <Link to={to} external={external} onClick={onClick}>
            {renderLinkHeaderTop()}
          </Link>
          {hasLinkText && (
            <TextLink to={to} external={external} onClick={onClick}>
              {linkText}
            </TextLink>


(props) => (props.hasLinkText
    ? `
        justify-content: space-between;
        align-items: flex-end;
      `
    : `
        flex-direction: column
  `)


interface Props {
  title?: ReactNode;
  description?: string;
  typographyProps?: TypographyProps;
  to?: string;
  external?: boolean;
  linkText?: string;
  onClick?: () => void;
}


export type TypographyProps = { typography?: Typo } & Partial<HeadlineTypoProps>;


renderLinkHeaderTop()


rows => this.getSeats().subscribe(seats => {
      rows.map(row => {
        if (!row.seats) {
          row.seats = [];
        }

        seats.filter(seat => seat.rowId === row.id).map(seat => row.seats.push(seat));
      });

      this.rows = rows;
    })


seats => {
      rows.map(row => {
        if (!row.seats) {
          row.seats = [];
        }

        seats.filter(seat => seat.rowId === row.id).map(seat => row.seats.push(seat));
      });

      this.rows = rows;
    }


row => {
        if (!row.seats) {
          row.seats = [];
        }

        seats.filter(seat => seat.rowId === row.id).map(seat => row.seats.push(seat));
      }


seat => seat.rowId === row.id


seat => row.seats.push(seat)


@Injectable()
export class SeatService {
  rows: Row[];

  constructor(private http: Http) {
    this.getRows().subscribe(rows => this.getSeats().subscribe(seats => {
      rows.map(row => {
        if (!row.seats) {
          row.seats = [];
        }

        seats.filter(seat => seat.rowId === row.id).map(seat => row.seats.push(seat));
      });

      this.rows = rows;
    }));
  }

  private getRows(): Observable<Row[]> {
    return this.http.get('http://localhost:3000/api/rows').map(res => res.json()).catch(this.handleError);
  }

  private getSeats(): Observable<Seat[]> {
    return this.http.get('http://localhost:3000/api/seats?filter[order]=column%20ASC').map(res => res.json()).catch(this.handleError);
  }

  private handleError (error: Response | any) {
    let errMsg: string;
    if (error instanceof Response) {
      const body = error.json() || '';
      const err = body.error || JSON.stringify(body);
      errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
    } else {
      errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
  }
}


export class Row {
  public seats: Seat[];

  constructor(public id: string) { }
}


private getRows(): Observable<Row[]> {
    return this.http.get('http://localhost:3000/api/rows').map(res => res.json()).catch(this.handleError);
  }


private getSeats(): Observable<Seat[]> {
    return this.http.get('http://localhost:3000/api/seats?filter[order]=column%20ASC').map(res => res.json()).catch(this.handleError);
  }


private handleError (error: Response | any) {
    let errMsg: string;
    if (error instanceof Response) {
      const body = error.json() || '';
      const err = body.error || JSON.stringify(body);
      errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
    } else {
      errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
  }


(obj: ImageState): any => ({
    ...obj,
  })


(obj: Ami): any => ({
    ...obj,
  })


(obj: LaunchPermissionConfiguration): any => ({
    ...obj,
  })


(obj: AmiDistributionConfiguration): any => ({
    ...obj,
  })


(obj: CallRateLimitExceededException): any => ({
    ...obj,
  })


(obj: CancelImageCreationRequest): any => ({
    ...obj,
  })


(obj: CancelImageCreationResponse): any => ({
    ...obj,
  })


(obj: ClientException): any => ({
    ...obj,
  })


(obj: ForbiddenException): any => ({
    ...obj,
  })


(obj: IdempotentParameterMismatchException): any => ({
    ...obj,
  })


(obj: InvalidRequestException): any => ({
    ...obj,
  })


(obj: ServiceUnavailableException): any => ({
    ...obj,
  })


(obj: Component): any => ({
    ...obj,
  })


(obj: ComponentConfiguration): any => ({
    ...obj,
  })


(obj: ComponentSummary): any => ({
    ...obj,
  })


(obj: ComponentVersion): any => ({
    ...obj,
  })


(obj: CreateComponentRequest): any => ({
    ...obj,
  })


(obj: CreateComponentResponse): any => ({
    ...obj,
  })


(obj: InvalidParameterCombinationException): any => ({
    ...obj,
  })


(obj: InvalidVersionNumberException): any => ({
    ...obj,
  })


(obj: ServiceQuotaExceededException): any => ({
    ...obj,
  })


(obj: Distribution): any => ({
    ...obj,
  })


(obj: CreateDistributionConfigurationRequest): any => ({
    ...obj,
  })


(obj: CreateDistributionConfigurationResponse): any => ({
    ...obj,
  })


(obj: ResourceAlreadyExistsException): any => ({
    ...obj,
  })


(obj: ImageTestsConfiguration): any => ({
    ...obj,
  })


(obj: CreateImageRequest): any => ({
    ...obj,
  })


(obj: CreateImageResponse): any => ({
    ...obj,
  })


(obj: Schedule): any => ({
    ...obj,
  })


(obj: CreateImagePipelineRequest): any => ({
    ...obj,
  })


(obj: CreateImagePipelineResponse): any => ({
    ...obj,
  })


(obj: EbsInstanceBlockDeviceSpecification): any => ({
    ...obj,
  })


(obj: InstanceBlockDeviceMapping): any => ({
    ...obj,
  })


(obj: CreateImageRecipeRequest): any => ({
    ...obj,
  })


(obj: CreateImageRecipeResponse): any => ({
    ...obj,
  })


(obj: S3Logs): any => ({
    ...obj,
  })


(obj: Logging): any => ({
    ...obj,
  })


(obj: CreateInfrastructureConfigurationRequest): any => ({
    ...obj,
  })


(obj: CreateInfrastructureConfigurationResponse): any => ({
    ...obj,
  })


(obj: DeleteComponentRequest): any => ({
    ...obj,
  })


(obj: DeleteComponentResponse): any => ({
    ...obj,
  })


(obj: ResourceDependencyException): any => ({
    ...obj,
  })


(obj: DeleteDistributionConfigurationRequest): any => ({
    ...obj,
  })


(obj: DeleteDistributionConfigurationResponse): any => ({
    ...obj,
  })


(obj: DeleteImageRequest): any => ({
    ...obj,
  })


(obj: DeleteImageResponse): any => ({
    ...obj,
  })


(obj: DeleteImagePipelineRequest): any => ({
    ...obj,
  })


(obj: DeleteImagePipelineResponse): any => ({
    ...obj,
  })


(obj: DeleteImageRecipeRequest): any => ({
    ...obj,
  })


(obj: DeleteImageRecipeResponse): any => ({
    ...obj,
  })


(obj: DeleteInfrastructureConfigurationRequest): any => ({
    ...obj,
  })


(obj: DeleteInfrastructureConfigurationResponse): any => ({
    ...obj,
  })


(obj: DistributionConfiguration): any => ({
    ...obj,
  })


(obj: DistributionConfigurationSummary): any => ({
    ...obj,
  })


(obj: Filter): any => ({
    ...obj,
  })


(obj: GetComponentRequest): any => ({
    ...obj,
  })


(obj: GetComponentResponse): any => ({
    ...obj,
  })


(obj: GetComponentPolicyRequest): any => ({
    ...obj,
  })


(obj: GetComponentPolicyResponse): any => ({
    ...obj,
  })


(obj: GetDistributionConfigurationRequest): any => ({
    ...obj,
  })


(obj: GetDistributionConfigurationResponse): any => ({
    ...obj,
  })


(obj: GetImageRequest): any => ({
    ...obj,
  })


(obj: ImageRecipe): any => ({
    ...obj,
  })


(obj: InfrastructureConfiguration): any => ({
    ...obj,
  })


(obj: OutputResources): any => ({
    ...obj,
  })


(obj: Image): any => ({
    ...obj,
  })


(obj: GetImageResponse): any => ({
    ...obj,
  })


(obj: GetImagePipelineRequest): any => ({
    ...obj,
  })


(obj: ImagePipeline): any => ({
    ...obj,
  })


(obj: GetImagePipelineResponse): any => ({
    ...obj,
  })


(obj: GetImagePolicyRequest): any => ({
    ...obj,
  })


(obj: GetImagePolicyResponse): any => ({
    ...obj,
  })


(obj: GetImageRecipeRequest): any => ({
    ...obj,
  })


(obj: GetImageRecipeResponse): any => ({
    ...obj,
  })


(obj: GetImageRecipePolicyRequest): any => ({
    ...obj,
  })


(obj: GetImageRecipePolicyResponse): any => ({
    ...obj,
  })


(obj: GetInfrastructureConfigurationRequest): any => ({
    ...obj,
  })


(obj: GetInfrastructureConfigurationResponse): any => ({
    ...obj,
  })


(obj: ImportComponentRequest): any => ({
    ...obj,
  })


(obj: ImportComponentResponse): any => ({
    ...obj,
  })


(obj: InvalidPaginationTokenException): any => ({
    ...obj,
  })


(obj: ListComponentBuildVersionsRequest): any => ({
    ...obj,
  })


(obj: ListComponentBuildVersionsResponse): any => ({
    ...obj,
  })


(obj: ListComponentsRequest): any => ({
    ...obj,
  })


(obj: ListComponentsResponse): any => ({
    ...obj,
  })


(obj: ListDistributionConfigurationsRequest): any => ({
    ...obj,
  })


(obj: ListDistributionConfigurationsResponse): any => ({
    ...obj,
  })


(obj: ListImageBuildVersionsRequest): any => ({
    ...obj,
  })


(obj: ImageSummary): any => ({
    ...obj,
  })


(obj: ListImageBuildVersionsResponse): any => ({
    ...obj,
  })


(obj: ListImagePipelineImagesRequest): any => ({
    ...obj,
  })


(obj: ListImagePipelineImagesResponse): any => ({
    ...obj,
  })


(obj: ListImagePipelinesRequest): any => ({
    ...obj,
  })


(obj: ListImagePipelinesResponse): any => ({
    ...obj,
  })


(obj: ListImageRecipesRequest): any => ({
    ...obj,
  })


(obj: ImageRecipeSummary): any => ({
    ...obj,
  })


(obj: ListImageRecipesResponse): any => ({
    ...obj,
  })


(obj: ListImagesRequest): any => ({
    ...obj,
  })


(obj: ImageVersion): any => ({
    ...obj,
  })


(obj: ListImagesResponse): any => ({
    ...obj,
  })


(obj: ListInfrastructureConfigurationsRequest): any => ({
    ...obj,
  })


(obj: InfrastructureConfigurationSummary): any => ({
    ...obj,
  })


(obj: ListInfrastructureConfigurationsResponse): any => ({
    ...obj,
  })


(obj: InvalidParameterException): any => ({
    ...obj,
  })


(obj: ListTagsForResourceRequest): any => ({
    ...obj,
  })


(obj: ListTagsForResourceResponse): any => ({
    ...obj,
  })


(obj: PutComponentPolicyRequest): any => ({
    ...obj,
  })


(obj: PutComponentPolicyResponse): any => ({
    ...obj,
  })


(obj: PutImagePolicyRequest): any => ({
    ...obj,
  })


(obj: PutImagePolicyResponse): any => ({
    ...obj,
  })


(obj: PutImageRecipePolicyRequest): any => ({
    ...obj,
  })


(obj: PutImageRecipePolicyResponse): any => ({
    ...obj,
  })


(obj: StartImagePipelineExecutionRequest): any => ({
    ...obj,
  })


(obj: StartImagePipelineExecutionResponse): any => ({
    ...obj,
  })


(obj: TagResourceResponse): any => ({
    ...obj,
  })


(obj: UntagResourceResponse): any => ({
    ...obj,
  })


(obj: UpdateDistributionConfigurationRequest): any => ({
    ...obj,
  })


(obj: UpdateDistributionConfigurationResponse): any => ({
    ...obj,
  })


(obj: UpdateImagePipelineRequest): any => ({
    ...obj,
  })


(obj: UpdateImagePipelineResponse): any => ({
    ...obj,
  })


(obj: UpdateInfrastructureConfigurationRequest): any => ({
    ...obj,
  })


(obj: UpdateInfrastructureConfigurationResponse): any => ({
    ...obj,
  })


/**
 *
 Image state shows the image status and the reason for that status.

 */
export interface ImageState {
  /**
   *
The status of the image.

   */
  status?: ImageStatus | string;

  /**
   *
The reason for the image's status.

   */
  reason?: string;
}


/**
 *
 Details of an EC2 AMI.

 */
export interface Ami {
  /**
   *
The description of the EC2 AMI.

   */
  description?: string;

  /**
   *
The AMI ID of the EC2 AMI.

   */
  image?: string;

  /**
   *
 Image state shows the image status and the reason for that status.

   */
  state?: ImageState;

  /**
   *
The name of the EC2 AMI.

   */
  name?: string;

  /**
   *
The AWS Region of the EC2 AMI.

   */
  region?: string;
}


/**
 *
Describes the configuration for a launch permission. The launch permission modification request is sent to the EC2 ModifyImageAttribute API on behalf of the user for each Region they have selected to distribute the AMI. To make an AMI public, set the launch permission authorized accounts to all. See the examples for making an AMI public at EC2 ModifyImageAttribute.

 */
export interface LaunchPermissionConfiguration {
  /**
   *
The name of the group.

   */
  userGroups?: string[];

  /**
   *
The AWS account ID.

   */
  userIds?: string[];
}


/**
 *
 Define and configure the output AMIs of the pipeline.

 */
export interface AmiDistributionConfiguration {
  /**
   *
The tags to apply to AMIs distributed to this Region.

   */
  amiTags?: { [key: string]: string };

  /**
   *
The description of the distribution configuration.

   */
  description?: string;

  /**
   *
The name of the distribution configuration.

   */
  name?: string;

  /**
   *
 Launch permissions can be used to configure which AWS accounts can use the AMI to launch instances.

   */
  launchPermission?: LaunchPermissionConfiguration;

  /**
   *
 The KMS key identifier used to encrypt the distributed image.

   */
  kmsKeyId?: string;
}


/**
 *
You have exceeded the permitted request rate for the specific operation.

 */
export interface CallRateLimitExceededException extends __SmithyException, $MetadataBearer {
  name: "CallRateLimitExceededException";
  $fault: "client";
  message?: string;
}


export interface CancelImageCreationRequest {
  /**
   *
The Amazon Resource Name (ARN) of the image whose creation you want to cancel.

   */
  imageBuildVersionArn: string | undefined;

  /**
   *
The idempotency token used to make this request idempotent.

   */
  clientToken?: string;
}


export interface CancelImageCreationResponse {
  /**
   *
The request ID that uniquely identifies this request.

   */
  requestId?: string;

  /**
   *
The idempotency token used to make this request idempotent.

   */
  clientToken?: string;

  /**
   *
The Amazon Resource Name (ARN) of the image whose creation has been cancelled.

   */
  imageBuildVersionArn?: string;
}


/**
 *
These errors are usually caused by a client action, such as using an action or resource on behalf of a user that doesn't have permissions to use the action or resource, or specifying an invalid resource identifier.

 */
export interface ClientException extends __SmithyException, $MetadataBearer {
  name: "ClientException";
  $fault: "client";
  message?: string;
}


/**
 *
You are not authorized to perform the requested operation.

 */
export interface ForbiddenException extends __SmithyException, $MetadataBearer {
  name: "ForbiddenException";
  $fault: "client";
  message?: string;
}


/**
 *
You have specified a client token for an operation using parameter values that differ from a previous request that used the same client token.

 */
export interface IdempotentParameterMismatchException extends __SmithyException, $MetadataBearer {
  name: "IdempotentParameterMismatchException";
  $fault: "client";
  message?: string;
}


/**
 *
You have made a request for an action that is not supported by the service.

 */
export interface InvalidRequestException extends __SmithyException, $MetadataBearer {
  name: "InvalidRequestException";
  $fault: "client";
  message?: string;
}


/**
 *
The resource that you are trying to operate on is currently in use. Review the message details and retry later.

 */
export interface ResourceInUseException extends __SmithyException, $MetadataBearer {
  name: "ResourceInUseException";
  $fault: "client";
  message?: string;
}


/**
 *
This exception is thrown when the service encounters an unrecoverable exception.

 */
export interface ServiceException extends __SmithyException, $MetadataBearer {
  name: "ServiceException";
  $fault: "server";
  message?: string;
}


/**
 *
The service is unable to process your request at this time.

 */
export interface ServiceUnavailableException extends __SmithyException, $MetadataBearer {
  name: "ServiceUnavailableException";
  $fault: "server";
  message?: string;
}


/**
 *
A detailed view of a component.

 */
export interface Component {
  /**
   *
The owner of the component.

   */
  owner?: string;

  /**
   *
The change description of the component.

   */
  changeDescription?: string;

  /**
   *
The Amazon Resource Name (ARN) of the component.

   */
  arn?: string;

  /**
   *
The tags associated with the component.

   */
  tags?: { [key: string]: string };

  /**
   *
The type of the component denotes whether the component is used to build the image or only to test it.

   */
  type?: ComponentType | string;

  /**
   *
The platform of the component.

   */
  platform?: Platform | string;

  /**
   *
The version of the component.

   */
  version?: string;

  /**
   *
The operating system (OS) version supported by the component. If the OS information is available, a prefix match is performed against the parent image OS version during image recipe creation.

   */
  supportedOsVersions?: string[];

  /**
   *
The date that the component was created.

   */
  dateCreated?: string;

  /**
   *
The description of the component.

   */
  description?: string;

  /**
   *
The KMS key identifier used to encrypt the component.

   */
  kmsKeyId?: string;

  /**
   *
The name of the component.

   */
  name?: string;

  /**
   *
The encryption status of the component.

   */
  encrypted?: boolean;

  /**
   *
The data of the component.

   */
  data?: string;
}


/**
 * <p> Configuration details of the component. </p>
 */
export interface ComponentConfiguration {
  /**
   * <p>The Amazon Resource Name (ARN) of the component. </p>
   */
  componentArn: string | undefined;
}


/**
 *
A high-level summary of a component.

 */
export interface ComponentSummary {
  /**
   *
The name of the component.

   */
  name?: string;

  /**
   *
The description of the component.

   */
  description?: string;

  /**
   *
The type of the component denotes whether the component is used to build the image or only to test it.

   */
  type?: ComponentType | string;

  /**
   *
The tags associated with the component.

   */
  tags?: { [key: string]: string };

  /**
   *
The version of the component.

   */
  version?: string;

  /**
   *
The Amazon Resource Name (ARN) of the component.

   */
  arn?: string;

  /**
   *
The platform of the component.

   */
  platform?: Platform | string;

  /**
   *
The owner of the component.

   */
  owner?: string;

  /**
   *
The change description of the component.

   */
  changeDescription?: string;

  /**
   *
The date that the component was created.

   */
  dateCreated?: string;

  /**
   *
The operating system (OS) version supported by the component. If the OS information is available, a prefix match is performed against the parent image OS version during image recipe creation.

   */
  supportedOsVersions?: string[];
}


/**
 *
A high-level overview of a component semantic version.

 */
export interface ComponentVersion {
  /**
   *
The Amazon Resource Name (ARN) of the component.

   */
  arn?: string;

  /**
   *
The owner of the component.

   */
  owner?: string;

  /**
   *
 The operating system (OS) version supported by the component. If the OS information is available, a prefix match is performed against the parent image OS version during image recipe creation.

   */
  supportedOsVersions?: string[];

  /**
   *
The semantic version of the component.

   */
  version?: string;

  /**
   *
The date that the component was created.

   */
  dateCreated?: string;

  /**
   *
The description of the component.

   */
  description?: string;

  /**
   *
The name of the component.

   */
  name?: string;

  /**
   *
The platform of the component.

   */
  platform?: Platform | string;

  /**
   *
The type of the component denotes whether the component is used to build the image or only to test it.

   */
  type?: ComponentType | string;
}


export interface CreateComponentRequest {
  /**
   *
The tags of the component.

   */
  tags?: { [key: string]: string };

  /**
   *
 The operating system (OS) version supported by the component. If the OS information is available, a prefix match is performed against the parent image OS version during image recipe creation.

   */
  supportedOsVersions?: string[];

  /**
   *
The semantic version of the component. This version follows the semantic version syntax. For example, major.minor.patch. This could be versioned like software (2.0.1) or like a date (2019.12.01).

   */
  semanticVersion: string | undefined;

  /**
   *
The ID of the KMS key that should be used to encrypt this component.

   */
  kmsKeyId?: string;

  /**
   *
The change description of the component. Describes what change has been made in this version, or what makes this version different from other versions of this component.

   */
  changeDescription?: string;

  /**
   *
The uri of the component. Must be an S3 URL and the requester must have permission to access the S3 bucket. If you use S3, you can specify component content up to your service quota. Either data or uri can be used to specify the data within the component.

   */
  uri?: string;

  /**
   *
The name of the component.

   */
  name: string | undefined;

  /**
   *
The data of the component. Used to specify the data inline. Either data or uri can be used to specify the data within the component.

   */
  data?: string;

  /**
   *
The platform of the component.

   */
  platform: Platform | string | undefined;

  /**
   *
The idempotency token of the component.

   */
  clientToken?: string;

  /**
   *
The description of the component. Describes the contents of the component.

   */
  description?: string;
}


export interface CreateComponentResponse {
  /**
   *
The Amazon Resource Name (ARN) of the component that was created by this request.

   */
  componentBuildVersionArn?: string;

  /**
   *
The idempotency token used to make this request idempotent.

   */
  clientToken?: string;

  /**
   *
The request ID that uniquely identifies this request.

   */
  requestId?: string;
}


/**
 *
You have specified two or more mutually exclusive parameters. Review the error message for details.

 */
export interface InvalidParameterCombinationException extends __SmithyException, $MetadataBearer {
  name: "InvalidParameterCombinationException";
  $fault: "client";
  message?: string;
}


/**
 *
Your version number is out of bounds or does not follow the required syntax.

 */
export interface InvalidVersionNumberException extends __SmithyException, $MetadataBearer {
  name: "InvalidVersionNumberException";
  $fault: "client";
  message?: string;
}


/**
 *
You have exceeded the number of permitted resources or operations for this service. For service quotas, see EC2 Image Builder endpoints and quotas.

 */
export interface ServiceQuotaExceededException extends __SmithyException, $MetadataBearer {
  name: "ServiceQuotaExceededException";
  $fault: "client";
  message?: string;
}


/**
 *
 Defines the settings for a specific Region.

 */
export interface Distribution {
  /**
   *
The specific AMI settings (for example, launch permissions, AMI tags).

   */
  amiDistributionConfiguration?: AmiDistributionConfiguration;

  /**
   *
The License Manager Configuration to associate with the AMI in the specified Region.

   */
  licenseConfigurationArns?: string[];

  /**
   *
The target Region.

   */
  region: string | undefined;
}


export interface CreateDistributionConfigurationRequest {
  /**
   * <p> The description of the distribution configuration. </p>
   */
  description?: string;

  /**
   * <p> The idempotency token of the distribution configuration. </p>
   */
  clientToken?: string;

  /**
   * <p> The name of the distribution configuration. </p>
   */
  name: string | undefined;

  /**
   * <p> The tags of the distribution configuration. </p>
   */
  tags?: { [key: string]: string };

  /**
   * <p> The distributions of the distribution configuration. </p>
   */
  distributions: Distribution[] | undefined;
}


export interface CreateDistributionConfigurationResponse {
  /**
   * <p> The idempotency token used to make this request idempotent. </p>
   */
  clientToken?: string;

  /**
   * <p> The request ID that uniquely identifies this request. </p>
   */
  requestId?: string;

  /**
   * <p> The Amazon Resource Name (ARN) of the distribution configuration that was created by this request. </p>
   */
  distributionConfigurationArn?: string;
}


/**
 *
The resource that you are trying to create already exists.

 */
export interface ResourceAlreadyExistsException extends __SmithyException, $MetadataBearer {
  name: "ResourceAlreadyExistsException";
  $fault: "client";
  message?: string;
}


/**
 *
Image tests configuration.

 */
export interface ImageTestsConfiguration {
  /**
   *
The maximum time in minutes that tests are permitted to run.

   */
  timeoutMinutes?: number;

  /**
   *
Defines if tests should be executed when building this image.

   */
  imageTestsEnabled?: boolean;
}


export interface CreateImageRequest {
  /**
   * <p> The Amazon Resource Name (ARN) of the infrastructure configuration that defines the environment in which your image will be built and tested. </p>
   */
  infrastructureConfigurationArn: string | undefined;

  /**
   * <p> The Amazon Resource Name (ARN) of the distribution configuration that defines and configures the outputs of your pipeline. </p>
   */
  distributionConfigurationArn?: string;

  /**
   * <p> Collects additional information about the image being created, including the operating system (OS) version and package list. This information is used to enhance the overall experience of using EC2 Image Builder. Enabled by default. </p>
   */
  enhancedImageMetadataEnabled?: boolean;

  /**
   * <p> The tags of the image. </p>
   */
  tags?: { [key: string]: string };

  /**
   * <p> The image tests configuration of the image. </p>
   */
  imageTestsConfiguration?: ImageTestsConfiguration;

  /**
   * <p> The Amazon Resource Name (ARN) of the image recipe that defines how images are configured, tested, and assessed. </p>
   */
  imageRecipeArn: string | undefined;

  /**
   * <p> The idempotency token used to make this request idempotent. </p>
   */
  clientToken?: string;
}


export interface CreateImageResponse {
  /**
   * <p> The idempotency token used to make this request idempotent. </p>
   */
  clientToken?: string;

  /**
   * <p> The request ID that uniquely identifies this request. </p>
   */
  requestId?: string;

  /**
   * <p> The Amazon Resource Name (ARN) of the image that was created by this request. </p>
   */
  imageBuildVersionArn?: string;
}


/**
 *
A schedule configures how often and when a pipeline will automatically create a new image.

 */
export interface Schedule {
  /**
   *
The expression determines how often EC2 Image Builder evaluates your pipelineExecutionStartCondition.

   */
  scheduleExpression?: string;

  /**
   *
The condition configures when the pipeline should trigger a new image build. When the pipelineExecutionStartCondition is set to EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE, EC2 Image Builder will build a new image only when there are known changes pending. When it is set to EXPRESSION_MATCH_ONLY, it will build a new image every time the CRON expression matches the current time.

   */
  pipelineExecutionStartCondition?: PipelineExecutionStartCondition | string;
}


export interface CreateImagePipelineRequest {
  /**
   * <p> The tags of the image pipeline. </p>
   */
  tags?: { [key: string]: string };

  /**
   * <p> The Amazon Resource Name (ARN) of the image recipe that will be used to configure images created by this image pipeline. </p>
   */
  imageRecipeArn: string | undefined;

  /**
   * <p> The status of the image pipeline. </p>
   */
  status?: PipelineStatus | string;

  /**
   * <p> The idempotency token used to make this request idempotent. </p>
   */
  clientToken?: string;

  /**
   * <p> The schedule of the image pipeline. </p>
   */
  schedule?: Schedule;

  /**
   * <p> The image test configuration of the image pipeline. </p>
   */
  imageTestsConfiguration?: ImageTestsConfiguration;

  /**
   * <p> The Amazon Resource Name (ARN) of the infrastructure configuration that will be used to build images created by this image pipeline. </p>
   */
  infrastructureConfigurationArn: string | undefined;

  /**
   * <p> Collects additional information about the image being created, including the operating system (OS) version and package list. This information is used to enhance the overall experience of using EC2 Image Builder. Enabled by default. </p>
   */
  enhancedImageMetadataEnabled?: boolean;

  /**
   * <p> The Amazon Resource Name (ARN) of the distribution configuration that will be used to configure and distribute images created by this image pipeline. </p>
   */
  distributionConfigurationArn?: string;

  /**
   * <p> The name of the image pipeline. </p>
   */
  name: string | undefined;

  /**
   * <p> The description of the image pipeline. </p>
   */
  description?: string;
}


export interface CreateImagePipelineResponse {
  /**
   * <p> The idempotency token used to make this request idempotent. </p>
   */
  clientToken?: string;

  /**
   * <p> The Amazon Resource Name (ARN) of the image pipeline that was created by this request. </p>
   */
  imagePipelineArn?: string;

  /**
   * <p> The request ID that uniquely identifies this request. </p>
   */
  requestId?: string;
}


/**
 *
Amazon EBS-specific block device mapping specifications.

 */
export interface EbsInstanceBlockDeviceSpecification {
  /**
   *
Use to configure delete on termination of the associated device.

   */
  deleteOnTermination?: boolean;

  /**
   *
Use to override the device's volume type.

   */
  volumeType?: EbsVolumeType | string;

  /**
   *
Use to configure the KMS key to use when encrypting the device.

   */
  kmsKeyId?: string;

  /**
   *
Use to configure device IOPS.

   */
  iops?: number;

  /**
   *
The snapshot that defines the device contents.

   */
  snapshotId?: string;

  /**
   *
Use to configure device encryption.

   */
  encrypted?: boolean;

  /**
   *
Use to override the device's volume size.

   */
  volumeSize?: number;
}


/**
 *
Defines block device mappings for the instance used to configure your image.

 */
export interface InstanceBlockDeviceMapping {
  /**
   *
Use to remove a mapping from the parent image.

   */
  noDevice?: string;

  /**
   *
The device to which these mappings apply.

   */
  deviceName?: string;

  /**
   *
Use to manage Amazon EBS-specific configuration for this mapping.

   */
  ebs?: EbsInstanceBlockDeviceSpecification;

  /**
   *
Use to manage instance ephemeral devices.

   */
  virtualName?: string;
}


export interface CreateImageRecipeRequest {
  /**
   *
The components of the image recipe.

   */
  components: ComponentConfiguration[] | undefined;

  /**
   *
The idempotency token used to make this request idempotent.

   */
  clientToken?: string;

  /**
   *
The working directory to be used during build and test workflows.

   */
  workingDirectory?: string;

  /**
   *
The block device mappings of the image recipe.

   */
  blockDeviceMappings?: InstanceBlockDeviceMapping[];

  /**
   *
The parent image of the image recipe. The value of the string can be the ARN of the parent image or an AMI ID. The format for the ARN follows this example: arn:aws:imagebuilder:us-west-2:aws:image/windows-server-2016-english-full-base-x86/2019.x.x. The ARN ends with /20xx.x.x, which communicates to EC2 Image Builder that you want to use the latest AMI created in 20xx (year). You can provide the specific version that you want to use, or you can use a wildcard in all of the fields. If you enter an AMI ID for the string value, you must have access to the AMI, and the AMI must be in the same Region in which you are using Image Builder.

   */
  parentImage: string | undefined;

  /**
   *
 The name of the image recipe.

   */
  name: string | undefined;

  /**
   *
 The description of the image recipe.

   */
  description?: string;

  /**
   *
 The tags of the image recipe.

   */
  tags?: { [key: string]: string };

  /**
   *
The semantic version of the image recipe.

   */
  semanticVersion: string | undefined;
}


export interface CreateImageRecipeResponse {
  /**
   *
The request ID that uniquely identifies this request.

   */
  requestId?: string;

  /**
   *
The Amazon Resource Name (ARN) of the image recipe that was created by this request.

   */
  imageRecipeArn?: string;

  /**
   *
The idempotency token used to make this request idempotent.

   */
  clientToken?: string;
}


/**
 *
Amazon S3 logging configuration.

 */
export interface S3Logs {
  /**
   *
The Amazon S3 path in which to store the logs.

   */
  s3KeyPrefix?: string;

  /**
   *
The Amazon S3 bucket in which to store the logs.

   */
  s3BucketName?: string;
}


/**
 *
Logging configuration defines where Image Builder uploads your logs.

 */
export interface Logging {
  /**
   *
The Amazon S3 logging configuration.

   */
  s3Logs?: S3Logs;
}


export interface CreateInfrastructureConfigurationRequest {
  /**
   *
The subnet ID in which to place the instance used to customize your EC2 AMI.

   */
  subnetId?: string;

  /**
   *
The description of the infrastructure configuration.

   */
  description?: string;

  /**
   *
The idempotency token used to make this request idempotent.

   */
  clientToken?: string;

  /**
   *
The tags of the infrastructure configuration.

   */
  tags?: { [key: string]: string };

  /**
   *
The terminate instance on failure setting of the infrastructure configuration. Set to false if you want Image Builder to retain the instance used to configure your AMI if the build or test phase of your workflow fails.

   */
  terminateInstanceOnFailure?: boolean;

  /**
   *
The tags attached to the resource created by Image Builder.

   */
  resourceTags?: { [key: string]: string };

  /**
   *
The SNS topic on which to send image build events.

   */
  snsTopicArn?: string;

  /**
   *
The security group IDs to associate with the instance used to customize your EC2 AMI.

   */
  securityGroupIds?: string[];

  /**
   *
The instance profile to associate with the instance used to customize your EC2 AMI.

   */
  instanceProfileName: string | undefined;

  /**
   *
The key pair of the infrastructure configuration. This can be used to log on to and debug the instance used to create your image.

   */
  keyPair?: string;

  /**
   *
The logging configuration of the infrastructure configuration.

   */
  logging?: Logging;

  /**
   *
The name of the infrastructure configuration.

   */
  name: string | undefined;

  /**
   *
The instance types of the infrastructure configuration. You can specify one or more instance types to use for this build. The service will pick one of these instance types based on availability.

   */
  instanceTypes?: string[];
}


export interface CreateInfrastructureConfigurationResponse {
  /**
   *
The idempotency token used to make this request idempotent.

   */
  clientToken?: string;

  /**
   *
The request ID that uniquely identifies this request.

   */
  requestId?: string;

  /**
   *
The Amazon Resource Name (ARN) of the infrastructure configuration that was created by this request.

   */
  infrastructureConfigurationArn?: string;
}


export interface DeleteComponentRequest {
  /**
   * <p>The Amazon Resource Name (ARN) of the component build version to delete. </p>
   */
  componentBuildVersionArn: string | undefined;
}