Auto-Duolingo

[Lite Version] Automatically farm experience points, hacking Duolingo is so easy!

// ==UserScript==
// @name         Auto-Duolingo
// @version      1.0.7
// @author       DevX
// @namespace    http://tampermonkey.net/
// @description  [Lite Version] Automatically farm experience points, hacking Duolingo is so easy!
// @match        https://*.duolingo.com/*
// @grant        none
// @license      MIT
// @icon         https://autoduolingo.click/assets/imgs/favicon.ico
// ==/UserScript==

(() => {
	const AUTODUOLINGO_STORAGE = "autoDuolingoStorage";
	const { isSafeMode, isShowUI, isAnimationOff, exp, time, version, isNewNotify, rmNotifyVersion, rmNotifyContent } =
		getSession();
	const { notifyVersion } = getLocal();

	const autoDuoLite = {
		createSignature: function () {
			this.signatureElm = document.createElement("div");
			Object.assign(this.signatureElm, {
				className: "signature-listening",
				innerHTML: `
					<div>
						Auto-Duolingo DevX
						<div class="autoduo-lite-version">
							LITE VERSION
						</div>
					</div>
				`,
			});
			document.body.appendChild(this.signatureElm);
		},

		createContact: function () {
			this.contactWrapper = document.createElement("div");
			Object.assign(this.contactWrapper, {
				className: "contact-wrapper-listening",
				innerHTML: `<a class="contact-item-listening" href="https://t.me/imdevx" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/tele-icon.ndx')">
								<p class="popup">Chat with DevX</p>
							</a>
							<a class="contact-item-listening" href="https://t.me/autoduofamily" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/tele-gr-icon.ndx')">
								<p class="popup">Telegram Community</p>
							</a>
							<a class="contact-item-listening" href="https://zalo.me/g/lmhfps187" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/zalo-icon.ndx')">
								<p class="popup">Zalo Community</p>
							</a>
							<a class="contact-item-listening" href="https://www.youtube.com/@autoduofamily" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/youtube-icon.ndx')">
								<p class="popup">Youtube Channel</p>
							</a>
							<a class="contact-item-listening" id="greasyfork" href="https://greasyfork.org/en/scripts/487867-auto-duolingo" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/greasyfork-icon.ndx')">
								<p class="popup">Greasy Fork</p>
							</a>`,
			});
		},

		createPopup: function () {
			this.updateGuidePopup = document.createElement("div");
			Object.assign(this.updateGuidePopup, {
				className: "update-guide-popup",
				innerHTML: `
					<div class="guide-popup-main">
						<h2 class="guide-popup-title">UPDATE GUIDE</h2>
						<div class="guide-popup-content">
							<p class="guide-popup-text" style="color: rgb(0,159,235)">
								The full version unlocks all features and receives priority updates for new features and bug fixes. 
								To upgrade, follow the instructions below:
							</p>
							<p class="guide-popup-text">
								<b>Step 1:</b> Click the "Go update" button below, then proceed to click the "Update" (or maybe "Reinstall", "Override") button 
								in the popup window to confirm the update process.
							</p>
							<p class="guide-popup-text">
								<b>Step 2</b>: Refresh the Duolingo page to update the interface of the full version of Auto-Duolingo.
							</p>
							<div class="guide-popup-btn">
								<button class="autoduo-btn popup-btn-close">Close</button>
								<a class="autoduo-btn btn-green popup-btn-access" href="#">Go Update</a>
							</div>
						</div>
					</div>
				`,
			});

			const closePopupBtn = this.updateGuidePopup.querySelector(".popup-btn-close");
			closePopupBtn.addEventListener("click", () => {
				document.body.contains(this.updateGuidePopup) && this.updateGuidePopup.remove();
			});
		},

		createBtn: function () {
			this.autoBtn = document.createElement("button");
			Object.assign(this.autoBtn, {
				className: "autoduo-btn btn-green auto-farm-btn-listening",
				innerText: "START FARM XP",
				onclick: () => {
					this.isAuto ? this.stop() : this.start();
				},
			});

			this.updateBtn = document.createElement("button");
			Object.assign(this.updateBtn, {
				className: "autoduo-btn update-btn-listening",
				innerText: "Update to the full version",
				onclick: () => {
					this.isAuto && this.stop();
					document.body.appendChild(this.updateGuidePopup);
				},
			});

			this.showHideBtn = document.createElement("button");
			Object.assign(this.showHideBtn, {
				className: "show-hide-listening",
				style: `--data-version: 'V${this.version}'`,
				innerHTML: "<i></i>",
			});

			this.showHideBtn.addEventListener("click", () => {
				this.isShowUI = !this.isShowUI;
				this.handleShowHideUI(true);
			});
			document.body.append(this.showHideBtn);

			new Promise((resolve) => {
				setTimeout(
					resolve.bind(window, notAvailable("aHR0cHM6Ly9pbnN0YWxsLmF1dG9kdW9saW5nby5jbGljaw==")),
					1000
				);
			}).then((res) => {
				this.updateGuidePopup.querySelector(".popup-btn-access").href = res;
			});
		},

		createBubbles: function () {
			this.notifyBubble = document.createElement("button");
			Object.assign(this.notifyBubble, {
				className: "bubble-item-listening notify-bubble-listening",
				title: "Notification",
			});

			this.superBubble = document.createElement("a");
			Object.assign(this.superBubble, {
				className: "bubble-item-listening super-bubble-listening",
				title: "Duolingo Super Free",
				href: "https://t.me/duolingosuperfree",
				target: "_blank",
			});
		},

		createStatistics: function () {
			this.statistic = document.createElement("div");
			this.keyTypeElm = document.createElement("p");
			this.expElm = document.createElement("p");
			this.dateElm = document.createElement("p");
			const statisticWrapper = document.createElement("div");

			Object.assign(this.keyTypeElm, {
				className: "key-type-listening",
				style: `--data-name: "Type"`,
				innerHTML: "<b style='color: #009feb'>Auto-Duolingo Lite</b>",
			});

			this.expElm.className = "total-exp-listening";
			this.expElm.innerText = this.exp;
			this.statistic.className = "statistic-listening";
			this.dateElm.className = "time-listening";
			statisticWrapper.className = "statistic-wrapper-listening";

			statisticWrapper.append(this.expElm, this.dateElm);
			this.statistic.append(this.keyTypeElm, statisticWrapper);
		},

		createFunctions: function () {
			this.animationOffWrapper = document.createElement("div");
			this.animationOffWrapper.style = `--data-name: "Hide Animation"`;
			const animationOffInfo =
				"HIDE ANIMATION MODE:\n" +
				"- When this mode is enabled, images and animations on the website will be hidden to optimize performance.\n\n" +
				"Suggestion: To achieve the best performance, you should find and disable items related to effects in Duolingo's settings!";
			this.autoduoCreateSwitch(
				animationOffInfo,
				this.animationOffWrapper,
				1,
				this.isAnimationOff,
				(setSwitch) => {
					this.isAnimationOff = !this.isAnimationOff;
					this.handleAnimationOff(true);
					setSwitch(this.isAnimationOff);
				}
			);

			this.safeModeWrapper = document.createElement("div");
			this.safeModeWrapper.style = `--data-name: "Safe Mode"`;
			const safeModeInfo =
				"SAFE MODE:\n" +
				"- When this mode is enabled, the system will simulate user actions when using auto. The speed will be more relaxed, " +
				"in exchange for the completion time of lessons and the amount of experience will be the most natural, minimizing " +
				"the risks of REPORT and account BAN!";
			this.autoduoCreateSwitch(safeModeInfo, this.safeModeWrapper, 2, this.isSafeMode, () => {
				this.isSafeMode ? this.handleSafeModeOff() : this.handleSafeModeOn();
			});

			this.turboModeWrapper = document.createElement("div");
			this.turboModeWrapper.style = `--data-name: "Turbo Mode"`;
			const turboModeInfo =
				"TURBO MODE:\n" +
				"- When enabled, the system will significantly boost the auto speed. It will utilize higher performance and " +
				"is not recommended for use on low-performance devices.\n- Turn it off and refresh the page if you encounter " +
				"issues while activating this mode!\n\n- Note: This is an experimental feature and requires a VIP Key to use. " +
				"Only enable it when you truly require speed and understand its implications!!";
			this.autoduoCreateSwitch(turboModeInfo, this.turboModeWrapper, 4, false);

			this.legendModeWrapper = document.createElement("div");
			this.legendModeWrapper.style = `--data-name: "Lesson Pass Mode"`;
			const legendModeInfo =
				"LESSON PASS MODE:\n" +
				"- When activated, the system won't repeat exercises as in the regular mode but will engage in exercises actively selected by the user. " +
				"This mode is used for legendary exercises, story exercises, and most other similar exercises.\n- You need to enter the lesson you want to " +
				"pass in, and then the system will automatically complete that lesson for you!\n" +
				"- When this mode is activated, the basic auto button will be temporarily disabled.";
			this.autoduoCreateSwitch(legendModeInfo, this.legendModeWrapper, 5, false);

			this.targetModeWrapper = document.createElement("div");
			this.targetModeWrapper.style = `--data-name: "XP Target Mode"`;
			const targetModeInfo =
				"EXPERIENCE POINT TARGET MODE:\n" +
				"- By setting an experience point target, the system will automatically stop auto mode when the total experience points " +
				"obtained equal or exceed the specified target.\n- This helps you better control the auto function, " +
				"preventing unintentional accumulation of excess experience points due to forgetting to turn off auto mode!\n\n" +
				"- Note: The experience point target must be greater than the current amount of experience points obtained through auto mode!";
			this.autoduoCreateSwitch(targetModeInfo, this.targetModeWrapper, 6, false);

			this.passModeWrapper = document.createElement("div");
			this.passModeWrapper.style = `--data-name: "Auto Pass Mode"`;
			const passModeInfo =
				"AUTO PASS MODE:\n" +
				"- By setting the number of lessons you wish to pass, the system will automatically pass the corresponding " +
				"number of new lessons as per the value you've set!\n\n" +
				"- Note: the lesson value should be within the range of 1 - 1000 (Enter 0 for unlimited auto)!";
			this.autoduoCreateSwitch(passModeInfo, this.passModeWrapper, 7, false);

			this.darkModeWrapper = document.createElement("div");
			this.darkModeWrapper.style = `--data-name: "Dark Mode"`;
			const darkModeInfo = "DARK MODE\n- Enable/disable website dark mode faster!";
			this.autoduoCreateSwitch(darkModeInfo, this.darkModeWrapper, 3, this.isDarkMode, (setSwitch) => {
				this.isDarkMode = !this.isDarkMode;
				const [theme, value] = this.isDarkMode ? ["dark", "on"] : ["light", "off"];
				document.documentElement.setAttribute("data-duo-theme", theme);
				localStorage.setItem("duo.darkMode", `{"1291358081":"${value}","1313105280":"${value}"}`);
				setSwitch(this.isDarkMode);
			});

			this.farmingLocationWrapper = document.createElement("div");
			this.farmingLocationWrapper.style = `--data-name: "Set XP Farm Location"`;
			const farmingLocationInfo =
				"SET XP FARM LOCATION\n" +
				"- By default, the system can only Farm XP in practice exercises or listening practices. However, with this feature, you can Farm XP " +
				"in any lesson you want, even in story lessons!\n" +
				"- Usage: Activate the feature and enter the URL of the lesson you want, then enable the XP Farm mode to start farming.\n" +
				"- NOTE: The URL to the lesson must be accurate and the lesson must be repeatable. Entering an inaccurate URL may lead " +
				"to errors or even pose risks to your account!";
			this.autoduoCreateSwitch(farmingLocationInfo, this.farmingLocationWrapper, 8, false);

			this.autoX2Wrapper = document.createElement("div");
			this.autoX2Wrapper.style = `--data-name: "Auto Collect x2 XP"`;
			const autoX2Info =
				"AUTO COLLECT X2 XP:\n" +
				'- This is a supplementary feature for "Auto Farm KN", helping to maintain the x2 KN status during farming. When enabled, ' +
				"it will check and automatically do new lessons to get x2 KN rewards if it detects the current state doesn't have x2. " +
				"This will help you farm more KN points than usual. \n\n- NOTE: This feature will do new lessons to maintain the x2 status, so " +
				"consider before enabling it if you have constraints with these lessons.";
			this.autoduoCreateSwitch(autoX2Info, this.autoX2Wrapper, 8, false);

			this.functionWrapper = document.createElement("div");
			this.functionWrapper.className = "function-wrapper-listening";
			this.functionWrapper.append(
				this.darkModeWrapper,
				this.animationOffWrapper,
				this.safeModeWrapper,
				this.turboModeWrapper
			);
		},

		createSetting: function () {
			this.settingBtn = document.createElement("button");
			Object.assign(this.settingBtn, {
				className: "autoduo-btn setting-btn-listening",
				innerText: "Other settings",
			});
			this.settingBtn.addEventListener("click", () => {
				this.controlContainer.contains(this.settingOverlay) ||
					this.controlContainer.appendChild(this.settingOverlay);
			});

			this.closeSettingBtn = document.createElement("button");
			Object.assign(this.closeSettingBtn, {
				className: "autoduo-btn close-setting-btn-listening",
				innerText: "Close",
			});
			this.closeSettingBtn.addEventListener("click", () => {
				this.controlContainer.contains(this.settingOverlay) &&
					this.controlContainer.removeChild(this.settingOverlay);
			});

			this.settingOverlay = document.createElement("div");
			Object.assign(this.settingOverlay, {
				className: "setting-overlay-listening",
				innerHTML: `
					<h3>Other settings</h3>
				`,
			});

			this.settingFunction = document.createElement("div");
			this.settingFunction.className = "setting-function-listening";
			this.settingFunction.append(
				this.legendModeWrapper,
				this.passModeWrapper,
				this.targetModeWrapper,
				this.farmingLocationWrapper,
				this.autoX2Wrapper
			);

			this.settingOverlay.append(this.settingFunction, this.closeSettingBtn);
		},

		createContainer: function () {
			this.autoContainer = document.createElement("div");
			this.autoContainer.className = "auto-container-listening";
			this.autoContainer.append(
				this.statistic,
				this.functionWrapper,
				this.settingBtn,
				this.autoBtn,
				this.updateBtn
			);

			this.overlayContainer = document.createElement("div");
			this.overlayContainer.className = "overlay-listening";

			this.controlContainer = document.createElement("div");
			this.controlContainer.className = "control-container-listening";
			this.controlContainer.append(this.autoContainer, this.contactWrapper);

			this.bubbleContainer = document.createElement("div");
			this.bubbleContainer.className = "bubble-container-listening";
			this.bubbleContainer.append(this.superBubble, this.notifyBubble);

			document.body.append(this.controlContainer, this.bubbleContainer);
		},

		fetchNotify: async function () {
			try {
				const res = await (
					await fetch("https://api.autoduolingo.click/super/data/notify/?c7f54a73e6340a16176=91bf0d18b83")
				)?.json();
				if (res?.code === 200) {
					const { notifyVersion: rmVersion, notifyContent: rmContent } = res.data[0];
					setDataSession({
						isNewNotify: (this.isNewNotify = +rmVersion > this.notifyVersion),
						rmNotifyVersion: (this.rmNotifyVersion = +rmVersion),
						rmNotifyContent: (this.rmNotifyContent = rmContent.replaceAll("\\n", "\n")),
					});
					this.setNotify();
				}
			} catch (e) {}
		},

		setNotify: function () {
			if (!this.rmNotifyVersion) {
				return;
			}
			if (this.isNewNotify) {
				this.notifyBubble.classList.add("new");
			}
			this.notifyBubble.addEventListener("click", () => {
				if (this.isNewNotify) {
					this.notifyBubble.classList.remove("new");
					setDataSession("isNewNotify", (this.isNewNotify = false));
					setDataLocal("notifyVersion", this.rmNotifyVersion);
				}
				window.alert(this.rmNotifyContent);
			});
		},

		handleShowHideUI: function (isSave = false) {
			if (this.isShowUI) {
				this.showHideBtn.classList.remove("hide");
				document.body.append(this.controlContainer, this.signatureElm, this.bubbleContainer);
			} else {
				this.showHideBtn.classList.add("hide");
				this.controlContainer.remove();
				this.signatureElm.remove();
				this.bubbleContainer.remove();
			}

			if (isSave) {
				setDataSession("isShowUI", this.isShowUI);
				this.controlContainer.classList.contains("autoduo-animate") ||
					this.controlContainer.classList.add("autoduo-animate");
			}
		},

		handleAnimationOff: function (isSave = false) {
			this.isAnimationOff
				? document.head.appendChild(this.animationStyle)
				: document.head.removeChild(this.animationStyle);
			isSave && setDataSession("isAnimationOff", this.isAnimationOff);
		},

		handleSafeModeOn: function () {
			this.safeModeWrapper.setAutoduoSwitch(this.setSafeMode(true));
		},

		handleSafeModeOff: function () {
			this.safeModeWrapper.setAutoduoSwitch(this.setSafeMode(false));
		},

		start: function () {
			if (this.isAuto || this.isAutoRunning) {
				return;
			}

			document.body.appendChild(this.overlayContainer);
			this.isAuto = true;
			this.autoBtn.classList.add("running");
			this.autoBtn.innerText = "STOP FARM XP";
			setDataSession("isBasicAuto", this.isAuto);
			this.startTm = Date.now();
			this.handleLocation();
		},

		stop: function () {
			if (!this.isAuto || this.isLegendMode) {
				return;
			}
			document.body.removeChild(this.overlayContainer);
			this.isAuto = false;
			this.autoBtn.classList.remove("running");
			this.autoBtn.innerText = "START FARM XP";
			setDataSession("isBasicAuto", this.isAuto);
		},

		handleLocation: function () {
			if (!this.isAuto) {
				return;
			}

			const currentPath = window.location.pathname;

			switch (currentPath) {
				case this.practiceHubPath:
					this.goPracticeHubChallenge();
					break;

				case this.listeningPacticePath:
					this.handlePracticeHubChallenge();
					break;

				default:
					this.autoduoError(
						"Inappropriate location: Only enable auto when on the practice page (with the dumbbell icon) of Duolingo Super!" +
							"\n- Enabling auto on Duolingo Super's practice page will automatically farm listening exercises (20 XP)." +
							"\n- If you want to auto farm practice exercises without needing Super or automatically complete most other exercises, please update to the full version of Auto-Duolingo!"
					);
					break;
			}
		},

		goPracticeHubChallenge: function () {
			if (this.isAuto === false) {
				return;
			}
			const challengeBtn = $(
				'img[src="https://d35aaqx5ub95lt.cloudfront.net/images/practiceHub/2ebe830fd55a7f2754d371bcd79faf32.svg"]'
			);

			if (!challengeBtn) {
				setTimeout(this.goPracticeHubChallenge.bind(this), 1000);
				return;
			}

			challengeBtn.click();
			setTimeout(this.handlePracticeHubChallenge.bind(this), 1000);
		},

		handlePracticeHubChallenge: function () {
			if (window.location.pathname === this.practiceHubPath) {
				this.goPracticeHubChallenge();
				return;
			}

			// Flag:BETA
			const challengeWrapper = $(".wqSzE");
			if (challengeWrapper) {
				this.getDataStateNode(challengeWrapper);
				this.next();
				return;
			}
			const nextActiveBtn = $('[data-test="player-next"][aria-disabled="false"]');

			if (nextActiveBtn) {
				this.next();
				return;
			}

			setTimeout(this.handlePracticeHubChallenge.bind(this), 1000);
		},

		handleChallenge: async function () {
			if (this.isSafeMode) {
				await this.sleep(500);
			}
			if (!this.isAuto || this.isAutoRunning) {
				return;
			}

			const challengeTypeElm = $('[data-test*="challenge challenge"]');

			if (!challengeTypeElm) {
				return this.autoduoError("Undefined challenge!!");
			}

			const challengeType = challengeTypeElm.dataset.test?.slice(10);

			this.setAutoRunning(true);
			switch (challengeType) {
				case "challenge-listenTap":
					this.handleChallengeTranslate();
					break;

				case "challenge-gapFill":
				case "challenge-listenIsolation":
				case "challenge-assist":
				case "challenge-selectTranscription":
				case "challenge-characterIntro":
				case "challenge-characterSelect":
				case "challenge-selectPronunciation":
				case "challenge-dialogue":
				case "challenge-readComprehension":
				case "challenge-listenComprehension":
				case "challenge-select":
				case "challenge-form":
				case "challenge-definition":
				case "challenge-sameDifferent":
					this.handleChallengeChoice();
					break;

				default:
					this.autoduoError(
						"This exercise is not currently supported in this version. Try updating to the full version of Auto-Duolingo and try again!"
					);
					break;
			}
		},

		handleChallengeTranslate: function () {
			if (this.isAuto === false) {
				return;
			}

			let data = this.getData("correctTokens");

			if (this.isAuto === false) {
				return;
			}

			if (!data?.length) {
				data = this.getData(["challengeResponseTrackingProperties", "best_solution"])?.split(" ");
			}

			if (!data) {
				return this.autoduoError("Lesson data not found.");
			}

			const textArea = $('textarea[data-test="challenge-translate-input"]:not([disabled])');
			if (textArea) {
				const toggleKeyboard = $('[data-test="player-toggle-keyboard"]');
				if (toggleKeyboard) {
					toggleKeyboard.click();
					return setTimeout(this.handleChallengeTranslate.bind(this), 500);
				}

				const inputEvent = new Event("input", {
					bubbles: true,
				});

				let answer = "";

				const inputCaseHandler = () => {
					setTimeout(() => {
						if (data.length === 0) {
							this.setAutoRunning(false);
							this.next(true);
							return;
						}

						answer += " " + data.shift();
						this.nativeTextareaValueSetter.call(textArea, answer);
						textArea.dispatchEvent(inputEvent);
						inputCaseHandler();
					}, this.rmSafeDlTm());
				};
				inputCaseHandler();
				return;
			}

			// Flag:BETA
			let options = arr($$('button[data-test*="challenge-tap-token"]'));
			if (options.length === 0) {
				return setTimeout(this.handleChallengeTranslate.bind(this), 500);
			}

			const getIndexOfOption = (targetData) => {
				const index = options.findIndex((option) => option.textContent === targetData);
				return index;
			};

			const selectCaseHandler = () => {
				setTimeout(() => {
					if (data.length === 0) {
						this.setAutoRunning(false);
						this.next(true);
						return;
					}

					const firstValue = data.shift();
					const index = getIndexOfOption(firstValue);

					if (index === -1) {
						return this.autoduoLessonError("No suitable option found.");
					}

					options[index].click();
					options.splice(index, 1);
					selectCaseHandler();
				}, this.rmSafeDlTm());
			};
			selectCaseHandler();
		},

		handleChallengeChoice: function () {
			if (!this.isAuto) {
				return;
			}

			const optionElm = $$('[data-test="challenge-choice"]');
			const correctIndex = this.getData("correctIndex");

			if (correctIndex === null) {
				return this.autoduoError("Lesson data not found.");
			}

			setTimeout(() => {
				optionElm[correctIndex].click();
				setTimeout(() => {
					this.setAutoRunning(false);
					this.next();
				}, this.rmSafeDlTm());
			}, this.rmSafeDlTm());
		},

		next: function () {
			if (!this.isAuto) {
				return;
			}

			// Flag:BETA
			const expWrapper = $('[class="_1XNQX"]');
			if (expWrapper) {
				const exp = this.getExp(expWrapper);

				if (exp !== undefined) {
					this.exp += exp;
					this.expElm.innerText = this.exp;

					const timeNow = Date.now();
					const finishTime = timeNow - this.startTm;
					this.totalTime += finishTime;
					this.startTm = timeNow;
					this.renderTime();

					setDataSession({
						exp: this.exp,
						time: this.totalTime,
					});

					const currentPath = window.location.pathname;
					if (currentPath === this.listeningPacticePath) {
						if ((this.totalReloadTime += finishTime) >= this.reloadTm) {
							window.location.reload();
							return;
						}
					}
				}
			}

			const nextBtn = $('[data-test="player-next"]');

			if (!nextBtn) {
				setTimeout(this.handleLocation.bind(this), this.goChallengeTm);
				return;
			}

			const isDisabled = nextBtn.getAttribute("aria-disabled") === "true";
			const isFullProgress = !!$('[aria-valuenow="1"]');

			if (isDisabled && !isFullProgress) {
				boom(this.handleChallenge.bind(this));
				return;
			}

			!isDisabled && nextBtn.click();
			boom(this.next.bind(this));
		},

		findReactProps: function (wrapperElm) {
			this.reactProps = Object.keys(wrapperElm).find((key) => key.startsWith("__reactProps"));

			if (!this.reactProps) {
				return this.autoduoError("ERROR");
			}
		},

		getDataStateNode: function (wrapperElm) {
			this.reactProps === null && this.findReactProps(wrapperElm);
			const childrenData = wrapperElm?.[this.reactProps]?.children;

			if (Array.isArray(childrenData)) {
				this.dataStateNode = childrenData?.[0]?._owner?.stateNode;
			} else {
				this.dataStateNode = childrenData?._owner?.stateNode;
			}
		},

		getData: function (subGenealogy) {
			const currentChallenge = this.dataStateNode?.props?.currentChallenge;
			if (!currentChallenge) {
				return this.autoduoError("There was an error while loading challenge data!");
			}

			if (Array.isArray(subGenealogy)) {
				const result = subGenealogy.reduce((acc, currentKey) => {
					if (acc === null) {
						return null;
					}

					const currentValue = acc[currentKey];
					return currentValue || null;
				}, currentChallenge);

				if (result === null) {
					return this.autoduoError("There was an error while getting the data!");
				}

				return Array.isArray(result) ? [...result] : result;
			} else {
				const result = currentChallenge[subGenealogy];
				return Array.isArray(result) ? [...result] : result;
			}
		},

		getExp: function (expWrapper) {
			const keys = Object.keys(expWrapper);
			const key = keys.find((key) => key.startsWith("__reactProps"));

			const exp = expWrapper?.[key]?.children?.props?.slide?.xpGoalSessionProgress?.totalXpThisSession;
			return exp;
		},

		renderTime: function () {
			const timeString = timeFormat(this.totalTime);
			this.dateElm.innerText = timeString;
		},

		setAutoRunning: function (isRunning) {
			this.isAutoRunning = isRunning;
		},

		setSafeMode: function (isSafeMode) {
			this.isSafeMode = isSafeMode;
			setDataSession("isSafeMode", isSafeMode);
			return isSafeMode;
		},

		rmSafeDlTm: function () {
			if (!this.isSafeMode) {
				return 0;
			}
			return Math.floor(Math.random() * 800 + 100);
		},

		sleep: async function (time) {
			await new Promise((resolve) => setTimeout(resolve, time));
		},

		autoduoError: function (message) {
			this.isAutoRunning && this.setAutoRunning(false);
			this.isAuto && this.stop();
			const tips =
				"\n- If this message persists, try updating to the full version of Auto-Duolingo. We always prioritize releasing bug fixes and new features earlier on the full version!";
			alert("ERROR: " + message + tips);
		},

		autoduoLessonError: function (errorText) {
			// Flag:BETA
			const settingIcon = $("._2VEsk");
			if (settingIcon) {
				settingIcon.click();

				return setTimeout(() => {
					this.autoduoError(
						`${errorText}. If you are currently displaying the pronunciation guide, please turn it off first, then reload the page, and finally turn on auto again!`
					);
				}, 800);
			}
			return this.autoduoError(errorText);
		},

		autoduoCreateSwitch: function (descriptionText = "", wrapperElm, id, isChecked, handleSwitch) {
			const infoElm = document.createElement("i");
			Object.assign(infoElm, {
				className: "switch-info-listening",
				title: "Detail",
				onclick: () => {
					alert(descriptionText);
				},
			});

			const checkboxElm = document.createElement("input");
			Object.assign(checkboxElm, {
				type: "checkbox",
				hidden: true,
				checked: isChecked,
			});

			const setSwitch = (isEnable) => {
				checkboxElm.checked = isEnable;
			};

			const labelElm = document.createElement("label");
			labelElm.addEventListener("click", () => {
				id > 3 ? notAvailable() : handleSwitch(setSwitch);
			});

			const switchContainer = document.createElement("div");
			switchContainer.className = "switch-container-listening";
			switchContainer.append(infoElm, checkboxElm, labelElm);

			wrapperElm.classList.add("switch-wrapper-listening");
			if (id > 3) {
				wrapperElm.classList.add("unavailable");
			}
			wrapperElm.append(switchContainer);
			wrapperElm.setAutoduoSwitch = setSwitch;
		},

		autoduoCheckUpdate: async function () {
			let rmVersion =
				version || (await (await fetch("https://api.autoduolingo.click/lite/version/"))?.json())?.version;

			if (this.version !== rmVersion) {
				$("#greasyfork").classList.add("has-update");
				$("#greasyfork .popup").innerText = "A new updated version is available!";
			}

			if (!version) {
				setDataSession("version", rmVersion);
			}
		},

		createStyle: function () {
			this.animationStyle = document.createElement("style");
			this.animationStyle.innerHTML = `
			img, svg, canvas {
				visibility: hidden !important;
			} 
			div:not(.autoduo-animate):not(.setting-overlay-listening) {
				transition: none !important;
				animation-duration: 0s !important;
			}
			.fSJFz {
				display: none !important;
			}
			`;

			const listenStyle = document.createElement("style");
			listenStyle.innerHTML = `
			:root{
				--autoduo-bg: 255,255,255;
				--autoduo-color: 75,75,75;
				--autoduo-h-color: 0,159,235;
			}
			:root[data-duo-theme="dark"]{
				--autoduo-bg: 19,31,36;
				--autoduo-color: 241,247,251;
				--autoduo-h-color: 241,247,251;
			}
			.control-container-listening{
				position: fixed;
                z-index: 9999999;
                left: 20px;
                bottom: 75px;
				padding: 12px 10px;
				border: 2px dotted #00b3c1;
				border-radius: 20px;
				box-shadow: rgba(14, 30, 37, 0.12) 0px 2px 4px 0px, rgba(14, 30, 37, 0.32) 0px 2px 16px 0px;
				background-color: rgba(var(--autoduo-bg), 0.4);
				backdrop-filter: blur(4px);
			}
			.autoduo-animate{
				animation: autoduo-control-eff .15s;
			}
			.autoduo-animate::after{
				animation: autoduo-control-border-eff .35s .12s backwards;
			}
			@keyframes autoduo-control-eff {
				from {
					transform: scale(.8);
					opacity: .5;
				}
				to {
					transform: scale(1);
					opacity: 1;
				}
			}
			@keyframes autoduo-control-border-eff {
				from {
					transform: scale(1);
					opacity: 1;
				}
				to {
					transform: scale(1.15);
					opacity: 0;
				}
			}
			.control-container-listening::after{
				content: '';
				position: absolute;
				z-index: -1;
				inset: 0;
				border-radius: inherit;
				background-color: transparent;
				box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 5px;
				opacity: 0;
			}
            .auto-container-listening{
				width: 250px !important;
            }
			.setting-overlay-listening {
				position: absolute;
				inset: 0;
				display: flex;
				flex-direction: column;
				padding: inherit;
				padding-bottom: 20px;
				border-radius: inherit;
				backdrop-filter: inherit;
				background-color: rgba(var(--autoduo-bg), 0.8);
				animation: setting-overlay-eff 0.4s;
			}
			@keyframes setting-overlay-eff {
				from {
					opacity: 0;
					transform: perspective(450px) rotateY(-90deg);
				}
				to {
					opacity: 1;
					transform: perspective(450px) rotateY(0deg);
				}
			}
			.setting-overlay-listening h3 {
				padding: 8px 0 12px 0;
				text-align: center;
				text-transform: uppercase;
			}
			.setting-function-listening{
				flex-grow: 1;
			}
			.setting-function-listening .switch-wrapper-listening {
				margin-bottom: 11px;
				font-weight: bold;
				color: #ff4e00;
			}
			.close-setting-btn-listening {
				width: 80%;
				margin: 0 auto;
			}
			.autoduo-btn {
				display: flex;
				justify-content: center;
				align-items: center;
				position: relative;
				height: 46px;
				margin-bottom: 4px;
				background-color: transparent;
				color: rgb(var(--autoduo-bg));
				border: none;
				border-radius: 16px;
				text-transform: uppercase;
				letter-spacing: 1px;
				font-weight: bold;
				font-size: 15px;
				cursor: pointer;
				user-select: none;
			}
			.autoduo-btn::before {
				content: '';
				position: absolute;
				inset: 0;
				z-index: -1;
				background-color: #1cb0f6;
				color: rgb(25, 132, 183);
				border-radius: inherit;
				box-shadow: 0 4px 0;
			}
			.autoduo-btn:hover {
				filter: brightness(1.1);
			}
			.autoduo-btn:active {
				transform: translateY(4px);
			}
			.autoduo-btn:active::before {
				box-shadow: none;
			}
			.btn-green::before {
				background-color: #58CC02;
				color: rgb(81, 151, 4);
			}
			button.setting-btn-listening {
				width: 100% !important;
				margin-top: 10px;
			}
			button.setting-btn-listening::before {
				background-image: url(https://autoduolingo.click/assets/client/setting.svg);
				background-repeat: no-repeat;
				background-size: 22px;
				background-position: 18px;
			}
			button.auto-farm-btn-listening{
				width: 100% !important;
				margin-top: 8px;
			}
			button.auto-farm-btn-listening::before {
				background-image: url(https://autoduolingo.click/assets/client/xp.svg);
				background-repeat: no-repeat;
				background-size: 32px;
				background-position: 12px;
			}
			button.auto-farm-btn-listening.running::before {
				background-color: #FF4B4B;
				color: rgb(234,43,43);
			}
            .statistic-listening {
                color: rgb(var(--autoduo-color));
                font-size: 18px;
                font-weight: bold;
            }
			.statistic-listening p{
				margin-bottom: 8px;
			}
			.statistic-listening > p::before{
				display: inline-block;
				min-width: 60px;
			}
			.statistic-wrapper-listening{
				display: flex;
				justify-content: space-between;
				margin: 16px 0;
			}
			.time-listening, .total-exp-listening{
				display: flex;
				align-items: center;
				margin-bottom: 0 !important;
			}
			.time-listening::before,
			.total-exp-listening::before{
				content: '';
				width: 21px;
				height: 21px;
				margin-right: 4px;
				background-image: url('https://autoduolingo.click/assets/client/clock.svg');
				background-size: cover;
			}
			.total-exp-listening::before{
				width: 16px;
				height: 21px;
				background-image: url('https://autoduolingo.click/assets/client/exp.svg');
			}
            .total-exp-listening::after{
                content: 'XP';
				margin-left: 4px;
            }
			.update-btn-listening{
				width: 100%;
				margin-top: 8px;
			}
			.update-btn-listening::before{
				background-image: url('https://autoduolingo.click/assets/client/twinkle.ndx');
    			background-size: 85px auto;
			}
			.notify-bubble-listening::before {
				background-image: url('https://autoduolingo.click/assets/client/notify-icon-lite.png');
			}
			.super-bubble-listening::before {
				background-image: url('https://autoduolingo.click/assets/client/superfree-icon.png');
			}
			.bubble-container-listening {
				position: fixed;
				z-index: 99999;
				right: 8px;
				bottom: 69px;
				display: flex;
				flex-direction: column;
			}
			.bubble-item-listening + .bubble-item-listening {
				margin-top: 16px;
			}
			.bubble-item-listening {
				position: relative;
				width: 48px;
				height: 48px;
				border-radius: 50%;
				border: 1px solid #ccc;
				background-color: #ffffff40;
				backdrop-filter: blur(4px);
				box-shadow: rgba(0, 0, 0, 0.25) 0px 0.0625em 0.0625em, rgba(0, 0, 0, 0.25) 0px 0.125em 0.5em, rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset;
				cursor: pointer;
			}
			.bubble-item-listening:hover {
				filter: brightness(0.9);
			}
			.bubble-item-listening::before,
			.bubble-item-listening::after {
				content: '';
				position: absolute;
				inset: 0;
				border-radius: inherit;
				pointer-events: none;
			}
			.bubble-item-listening::before {
				background-size: cover;
			}
			.bubble-item-listening::after {
				display: none;
				border: 1px solid #009febdb;
				box-shadow: 2px 2px 5px #ccc, -2px -2px 5px #ccc;
				animation: notify-border-eff 2s infinite;
			}
			.bubble-item-listening.new {
				animation: notify-eff 2s infinite;
			}
			.bubble-item-listening.new::before {
				animation: notify-bell-eff 2s infinite;
			}
			.bubble-item-listening.new::after {
				display: block;
			}
			@keyframes notify-border-eff {
				70% {
					transform: scale(1.6);
					opacity: 0.1;
				}
				100% {
					transform: scale(1.6);
					opacity: 0;
				}
			}
			@keyframes notify-eff {
				0%, 75%, 100% {
					transform: scale(1);
				}
				10% {
					transform: scale(1.1);
				}
			}
			@keyframes notify-bell-eff {
				5%, 15% {
					transform: rotate(25deg);
				}
				10%, 20% {
					transform: rotate(-25deg);
				}
				25%, 100% {
					transform: rotate(0deg);
				}
			}
			.signature-listening{
				position: fixed;
                z-index: 99999999;
				top: 4px;
				left: 50%;
				transform: translateX(-50%);
				color: rgb(var(--autoduo-h-color));
				background-color: rgba(255, 255, 255, .5);
				font-style: italic;
				font-size: 15px;
				font-weight: 700;
				padding: 2px 8px;
				border-radius: 8px;
				width: max-content;
				display: flex;
				align-items: center;
			}
			.signature-listening::before{
				content: '';
				width: 50px;
				height: 50px;
				background-image: url(https://autoduolingo.click/assets/client/autoduosuperThumb.ndx);
				background-size: cover;
				margin: -4px 0;
				margin-right: 4px;
			}
			.autoduo-lite-version{
				position: relative;
				font-size: 13px;
				font-style: normal;
				text-align: center;
			}
			.key-type-listening::before,
			.key-expired-listening::before {
				content: var(--data-name);
			}
			.show-hide-listening{
				position: fixed;
				right: 8px;
				top: 50%;
				transform: translateY(-50%);
				z-index: 99999999;
				padding: 0;
				width: 50px;
				height: 50px;
				border-radius: 50%;
				color: rgb(var(--autoduo-h-color));
				background-color: #00DBDE;
				background-image: linear-gradient(90deg, #00DBDE 0%, #FC00FF 100%);
				border: 2px solid currentColor;
				
				display: flex;
				justify-content: center;
				align-items: center;
				font-size: 32px;
				padding-top: 2px;
				cursor: pointer;
			}
			.show-hide-listening.vip::before{
				content: '';
				position: absolute;
				inset: 0;
				background-image: url('https://autoduolingo.click/assets/client/vipCircle.ndx');
				background-size: cover;
				transform: scale(1.2);
			}
			.show-hide-listening::after{
				content: var(--data-version);
				position: absolute;
				left: 50%;
				bottom: 0;
				transform: translate(-50%, 130%);
				font-size: 15px;
				font-weight: bold;
			}
			.show-hide-listening.older::after{
				text-decoration: line-through;
			}
			.show-hide-listening i {
				position: relative;
				flex-shrink: 0;
				width: 35px;
				height: 35px;
				background-image: url('https://autoduolingo.click/assets/client/eye.svg');
				background-size: cover;
			}
			.show-hide-listening.hide i::after{
				content: '';
				position: absolute;
				top: 50%;
				left: 0;
				width: 110%;
				height: 5px;
				transform: rotate(45deg) translateX(-3px);
				background-color: #c0efff;
				border-radius: 7px;
			}
			.overlay-listening{
				position: fixed;
				inset: 0;
				z-index: 9999
			}

			.switch-wrapper-listening{
				display: flex;
				align-items: center;
				margin-bottom: 8px;
			}
			.switch-wrapper-listening::before{
				content: var(--data-name);
			}
			.switch-wrapper-listening.disable{
				opacity: .4;
				pointer-events: none !important;
				user-select: none !important;
				-ms-user-select: none !important;
				-moz-user-select: none !important;
				-webkit-user-select: none !important;
			}
			.switch-wrapper-listening.unavailable{
				color: #808080;
			}
			.switch-wrapper-listening.unavailable label{
				opacity: .6;
			}
			.switch-container-listening{
				flex-grow: 1;
				display: flex;
				justify-content: space-between;
				align-items: center;
			}
			.switch-info-listening{
				width: 18px;
				height: 18px;
				margin-left: 4px;
				margin-right: 8px;
				border-radius: 50%;
				background-image: url('https://autoduolingo.click/assets/client/infomation-icon.ndx');
				background-size: cover;
				cursor: pointer;
			}
			.switch-info-listening:hover{
				filter: brightness(0.8);
			}

			.switch-wrapper-listening label{
				position: relative;
				width: 46px;
				height: 24px;
				background-color: #bbb;
				box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 3px;
				border-radius: 20px;
				transition: .2s;
			}
			
			.switch-wrapper-listening label::after{
				content: '';
				position: absolute;
				left: 2px;
				top: 2px;
				width: 20px;
				height: 20px;
				border-radius: 50%;
				background-color: white;
				transition: .2s;
			}
			.switch-wrapper-listening input:checked + label{
				background-color: #1FC2FF;
			}
			.switch-wrapper-listening input:checked + label::after {
				left: 24px;
			}
			
			.function-wrapper-listening{
				font-weight: bold;
				font-size: 18px;
				color: #ff4e00;
			}

			.contact-wrapper-listening{
				display: flex;
				justify-content: center;
				flex-wrap: wrap;
				margin: 10px 0 -4px 0;
			}
			.contact-item-listening{
				position: relative;
				width: 34px;
				height: 34px;
				margin: 2px 4px;
				border-radius: 50%;
				background-image: var(--data-img);
				background-size: cover;
				transition: .12s;
				color: rgb(var(--autoduo-color));
			}
			.contact-item-listening:hover{
				box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 3px;
				transform: scale(1.11);
			}
			.contact-item-listening:hover .popup {
				display: block;
			}
			.contact-item-listening .popup {
				display: none;
				position: absolute;
				bottom: 100%;
				left: 50%;
				transform: translateX(-50%);
				margin-bottom: 12px;
				padding: 2px 6px;
				width: max-content;
				font-size: 12px;
				font-weight: bold;
				border: 1px solid #ccc;
				border-radius: 6px;
				background-color: rgb(var(--autoduo-bg));
				box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;
				animation: contact-popup-eff 0.2s;
			}
			@keyframes contact-popup-eff {
				from {
					opacity: 0;
					bottom: 50%;
				}
				to {
					opacity: 1;
					bottom: 100%;
				}
			}
			@keyframes contact-popup-update-eff {
				0%, 100% {
					transform: translateY(3px)
				}
				50% {
					transform: translateY(-3px)
				}
			}
			@keyframes spin-eff {
				0% {
					transform: scale(var(--scale)) rotate(0deg);
				}
				100% {
					transform: scale(var(--scale)) rotate(360deg);
				}
			}
			.contact-item-listening .popup::before{
				content: '';
				position: absolute;
				top: calc(100% - 2px);
				left: 50%;
				transform: translateX(-50%);
				border: 10px solid transparent;
				border-top-color: rgb(var(--autoduo-bg));

			}
			.contact-item-listening.has-update {
				transform: scale(1.11) !important;
				box-shadow: rgb(117 117 117 / 50%) 0px 0px 0px 3px;
			}
			.contact-item-listening.has-update::before {
				content: '';
				--scale: 1.05;
				position: absolute;
				inset: 0;
				border-radius: 50%;
				border: 2px solid white;
				border-top-color: transparent;
				border-bottom-color: transparent;
				animation: spin-eff 1.1s linear infinite;
			}
			.contact-item-listening.has-update .popup{
				display: block !important;
				transform: unset;
				right: -70%;
				left: unset;
				animation: contact-popup-update-eff 1.2s infinite;
			}
			.contact-item-listening.has-update .popup::before {
				left: 75%;
				transform: unset;
			}
			.control-container-listening.vip .contact-item-listening:hover{
				box-shadow: rgb(199 138 217 / 50%) 0px 0px 0px 3px;
			}
			.update-guide-popup {
				position: fixed;
				inset: 0;
				z-index: 99999999;
				display: flex;
				justify-content: center;
				align-items: center;
				background-color: rgba(0, 0, 0, 0.4);
				backdrop-filter: blur(4px);
				box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
				animation: popup-overlay-eff 0.25s;
			}
			.guide-popup-main {
				display: flex;
				flex-direction: column;
				width: 480px;
				margin: 4px;
				background-color: #009ee9;
				border: 2px solid #fff;
				border-radius: 20px;
				overflow: hidden;
				animation: popup-main-eff 0.25s;
			}
			.guide-popup-title {
				text-align: center;
				padding: 14px 8px 10px 8px;
				margin: 0;
				color: white;
				font-size: 22px;
			}
			.guide-popup-content {
				flex-grow: 1;
				padding: 20px 16px;
    			text-align: justify;
				background-color: rgb(var(--autoduo-bg));
				border-top-left-radius: 18px;
				border-top-right-radius: 18px;
			}
			..guide-popup-text {
				line-height: 24px;
				color: rgb(var(--autoduo-color));
				margin-bottom: 18px;
			}
			.guide-popup-btn {
				display: flex;
				justify-content: space-between;
				margin-top: 26px;
			}
			.guide-popup-btn .autoduo-btn {
				z-index: 1;
				width: calc(50% - 4px);
			}
			@keyframes popup-overlay-eff {
				from {
					opacity: 0;
				}
				to{
					opacity: 1;
				}
			}
			@keyframes popup-main-eff {
				from {
					transform: scale(0.5);
				}
				to{
					transform: scale(1);
				}
			}
			@media (max-height: 550px) {
				.control-container-listening {
					bottom: 4px;
				}
			}
			@media (max-width: 320px) {
				.guide-popup-btn .autoduo-btn {
					width: 100%;
					margin-top: 4px;
				}
				.guide-popup-btn {
					flex-direction: column-reverse;
				}
			}
        `;
			document.head.appendChild(listenStyle);
			const tm = +notAvailable("MjAw");
			window.boom = (cb) => {
				if (Number.isNaN(tm)) return;
				setTimeout(cb, tm);
			};
		},

		setup: function () {
			this.createStyle();
			this.createSignature();
			this.createContact();
			this.createPopup();
			this.createBtn();
			this.createBubbles();
			this.createStatistics();
			this.createFunctions();
			this.createSetting();
			this.createContainer();
			!isShowUI && this.handleShowHideUI();
			isAnimationOff && this.handleAnimationOff();
			this.renderTime();
			getDataSession("isBasicAuto") && this.start();
			this.autoduoCheckUpdate();
			this.rmNotifyVersion ? this.setNotify() : this.fetchNotify();
		},

		version: "1.0.7",
		isAuto: false,
		isAutoRunning: false,
		isSafeMode: !!isSafeMode,
		isAnimationOff: !!isAnimationOff,
		goChallengeTm: 500,
		reloadTm: 1800000,
		startTm: null,
		isShowUI: isShowUI === undefined || isShowUI,
		exp: exp || 0,
		totalTime: time || 0,
		practiceHubPath: "/practice-hub",
		listeningPacticePath: "/practice-hub/listening-practice",
		lessonWrapper: "._3js2_",
		reactProps: null,
		dataStateNode: null,
		nativeTextareaValueSetter: Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set,
		isDarkMode: document.documentElement.getAttribute("data-duo-theme") === "dark",
		notifyVersion: +notifyVersion || 0,
		isNewNotify: isNewNotify,
		rmNotifyVersion: rmNotifyVersion,
		rmNotifyContent: rmNotifyContent,
	};

	function timeFormat(ms) {
		const h = String(parseInt(ms / 1000 / 60 / 60));
		const m = String(parseInt((ms / 1000 / 60) % 60));
		return `${h.padStart(2, "0")}h:${m.padStart(2, "0")}m`;
	}

	function notAvailable(str) {
		try {
			return str
				? atob(str)
				: window.alert(
						"The current functionality is not available! To use this feature, please update to the full version of Auto-Duolingo!"
				  );
		} catch (e) {
			autoDuoLite.start = () => {};
		}
	}

	const $ = document.querySelector.bind(document);
	const $$ = document.querySelectorAll.bind(document);

	const arr = (nodeList) => {
		return Array.from(nodeList);
	};

	function getSession() {
		const dataStorage = sessionStorage.getItem(AUTODUOLINGO_STORAGE) || "{}";
		return JSON.parse(dataStorage);
	}
	function setDataSession(key, value) {
		const dataStorage = getSession();
		if (key instanceof Object) {
			Object.assign(dataStorage, key);
		} else {
			dataStorage[key] = value;
		}
		sessionStorage.setItem(AUTODUOLINGO_STORAGE, JSON.stringify(dataStorage));
	}
	function getDataSession(key) {
		const dataStorage = getSession();
		return dataStorage[key];
	}
	function getLocal() {
		const dataStorage = localStorage.getItem(AUTODUOLINGO_STORAGE) || "{}";
		try {
			return JSON.parse(dataStorage);
		} catch (e) {
			return {};
		}
	}
	function setDataLocal(key, value) {
		const dataStorage = getLocal();
		dataStorage[key] = value;
		localStorage.setItem(AUTODUOLINGO_STORAGE, JSON.stringify(dataStorage));
	}

	autoDuoLite.setup();
})();