Best JavaScript code snippet using playwright-internal
top-mover-content.jsx
Source:top-mover-content.jsx
1/**2 * The TopMoverContent component displays the user's Content in descending3 * Karma order. It allows them to update the price of each Content.4 *5 * :copyright: Copyright (c) 2022 Chris Hughes6 * :license: MIT License7 */8import './content.css';9import ContentCard from './content-card';10import { getReasonablySizedName, range, scaleDownKarma } from './common';11import React, { useContext, useEffect, useRef, useState } from 'react';12import Web3Context from './web3-context';13/**14 * Creates a new object which contains content about a piece of content15 *16 * @param {Object} input Input parameters17 * @return {Promise} resolves to Object18 */19async function createMetaContent(input) {20 const { web3,21 ownerIndex,22 props,23 name,24 isMounted} = input;25 if (!isMounted.current || !web3.activeAccount || !props.account) {26 return { };27 }28 29 const tokenId = await web3.contracts.content.tokenOfOwnerByIndex(30 props.account, ownerIndex31 );32 const { 1: txt,33 2: price,34 3: karma,35 4: creator } = await web3.contracts.content.getContentNft(tokenId);36 const heading = props.account === web3.activeAccount && props.createPricePopup ?37 (<button onClick={ props.createPricePopup(tokenId) }>Set Price</button>) :38 (<div>{ `Shared by ${name}` }</div>);39 return {40 txt: txt,41 creator: creator,42 price: Number(scaleDownKarma(price)),43 karma: Number(scaleDownKarma(karma)),44 html: (45 <div key={ tokenId }>46 { heading }47 <ContentCard tokenId={ tokenId } onError={ props.onError }/>48 </div>49 ),50 };51}52/**53 * Generates the content for the top movers page54 *55 * @param {Object} input Input parameters56 * @return {undefined}57 */58async function generateContent(input) {59 const { setState,60 props,61 web3,62 isMounted,63 name } = input;64 65 if (!web3.contracts.content || !isMounted.current || !props.account) {66 return;67 }68 69 const contentBalance = await web3.contracts.content.balanceOf(70 props.account71 );72 const promiseOfContent = range(contentBalance.toNumber()).map(73 async (idx) => createMetaContent({74 ownerIndex: idx,75 props: props,76 web3: web3,77 name: name,78 isMounted: isMounted,79 })80 );81 const content = await Promise.all(promiseOfContent);82 content.sort((a, b) => b.karma - a.karma);83 if (isMounted.current) {84 setState(content.map(c => c.html));85 }86}87/**88 * Component89 */90function TopMoverContent(props) {91 const isMounted = useRef(false);92 useEffect(() => {93 isMounted.current = true;94 return () => {95 isMounted.current = false;96 };97 }, []);98 99 const web3 = useContext(Web3Context);100 const [name, setName] = useState(getReasonablySizedName(props.account));101 useEffect(() => {102 async function getHumanReadableName() {103 if (!props.account) {104 return;105 }106 107 const nameFromChain = await web3.contracts.stake.getUserName(108 props.account109 );110 if (nameFromChain && isMounted.current) {111 setName(getReasonablySizedName(nameFromChain));112 }113 }114 getHumanReadableName();115 }, [web3, props.account]);116 117 const [content, setContent] = useState(undefined);118 useEffect(() => {119 generateContent({120 setState: setContent,121 props: props,122 web3: web3,123 isMounted: isMounted,124 name: name,125 });126 }, [props, web3, isMounted, name]);127 return (128 <div className='content'>129 { content }130 </div>131 );132}...
usePost.js
Source:usePost.js
1import { useRef, useEffect, useState, useContext } from 'react';2import { format } from 'date-fns';3import * as StoreSecure from 'expo-secure-store';4import { updateStore } from '../../../helpers/store_secure';5import { api } from '../../../api/config';6const usePost = (navigation, Platform) => {7 const isMounted = useRef(false);8 useEffect(() => {9 isMounted.current = true;10 return () => isMounted.current = false;11 }, [])12 const [input, setInput] = useState({13 body: '',14 time: '',15 })16 const [inputErrors, setInputErrors] = useState({17 body: '',18 time: '',19 })20 const [isLoading, setIsLoading] = useState(false);21 const [date, setDate] = useState(new Date(1598051730000));22 const [mode, setMode] = useState('time');23 const [show, setShow] = useState(false);24 const onChange = (event, selectedDate) => {25 const currentDate = event.nativeEvent.timestamp || selectedDate;26 const formattedTimeStamp = format(event.nativeEvent.timestamp, "HH:mm");27 if (isMounted.current) setShow(Platform.OS === 'ios');28 if (isMounted.current) setDate(new Date(currentDate));29 if (isMounted.current) setInput({ ...input, time: formattedTimeStamp });30 };31 const showMode = (currentMode) => {32 if (isMounted.current) setShow(true);33 if (isMounted.current) setMode(currentMode);34 };35 const showTimepicker = () => {36 if (isMounted.current) showMode('time');37 };38 const createReminder = () => {39 const errorState = { body: '', time: '' };40 //Body validation41 if (input.body === '') {42 errorState.body = 'Please enter a reminder';43 } else {44 errorState.body = '';45 }46 //Time validation47 if (input.time === '') {48 errorState.time = 'Please enter a time';49 } else {50 errorState.time = '';51 }52 if (isMounted.current) setInputErrors({ ...errorState });53 if (input.body !== '' && input.time !== '') {54 if (isMounted.current) setIsLoading(prev => !prev);55 api().post('/reminder/create', {56 body: input.body,57 time: input.time,58 })59 .then(async res => {60 const reminderTimes = await StoreSecure.getItemAsync('reminderTimes');61 const parsedReminderTimes = JSON.parse(reminderTimes);62 if (isMounted.current) parsedReminderTimes.push({ _id: res.data._id, body: res.data.body, time: res.data.time });63 if (isMounted.current) await updateStore('reminderTimes', JSON.stringify(parsedReminderTimes));64 if (isMounted.current) setIsLoading(prev => !prev);65 if (isMounted.current) setInput({ body: '', time: '' });66 if (isMounted.current) setInputErrors({ body: '', time: '' });67 if (isMounted.current) navigation.navigate('Reminders', { reminder: res.data });68 })69 .catch(error => {70 if (isMounted.current) setIsLoading(prev => !prev);71 console.log(error);72 })73 }74 }75 return { input, setInput, inputErrors, onChange, showTimepicker, mode, date, isLoading, createReminder, };76}...
user-stats.jsx
Source:user-stats.jsx
1/**2 * The UserStats component displays the users staked and client's Karma3 *4 * :copyright: Copyright (c) 2022 Chris Hughes5 * :license: MIT License6 */7import './user-stats.css';8import config from './config';9import React, { useContext, useEffect, useRef, useState } from 'react';10import { scaleDownKarma } from './common';11import Web3Context from './web3-context';12/**13 * Gets the initial Karma balance14 *15 * @param {Object} web3 Web3Context16 * @param {Function} setState Mutator on component state 17 * @param {Boolean} isMounted Indicates if component is still mounted18 * @param {Number} account Account to request19 * @return {Promise}20 */21async function setInitialKarma(web3, setState, isMounted, account) {22 if (!web3.contracts.karma || !account) {23 return;24 }25 26 const karmaBalance = await web3.contracts.karma.balanceOf(account);27 let scaledKarmaBalance = scaleDownKarma(karmaBalance);28 if (scaledKarmaBalance.length === 0) {29 scaledKarmaBalance = '0';30 }31 32 if (isMounted.current) {33 setState(scaledKarmaBalance);34 }35}36/**37 * Sets the number of users staked to this user38 *39 * @param {Object} web3 Web3Context40 * @param {Function} setState Mutator on component state 41 * @param {Boolean} isMounted Indicates if component is still mounted42 * @param {Number} account Account to request43 * @return {Promise}44 */45async function setInitialStaked(web3, setState, isMounted, account) {46 if (!web3.contracts.stake || !account) {47 return;48 }49 50 const numStaked = await web3.contracts.stake.getIncomingStakes(account);51 if (isMounted.current) {52 setState(numStaked.toNumber());53 }54}55/**56 * Component57 */58function UserStats(props) {59 const isMounted = useRef(false);60 useEffect(() => {61 isMounted.current = true;62 return () => {63 isMounted.current = false;64 };65 }, []);66 67 const web3 = useContext(Web3Context);68 const [karmaBalance, setKarmaBalance] = useState(0);69 useEffect(() => {70 setInitialKarma(web3, setKarmaBalance, isMounted, props.user);71 }, [web3, isMounted, props.user]);72 const [numStaked, setNumStaked] = useState(0);73 useEffect(() => {74 setInitialStaked(web3, setNumStaked, isMounted, props.user);75 }, [web3, isMounted, props.user]);76 useEffect(() => {77 let periodicUpdate;78 if (props.user === web3.activeAccount) {79 setInterval(async () => {80 await setInitialKarma(web3, setKarmaBalance, isMounted, props.user);81 }, config.PERIODIC_UPDATE_INTERVAL);82 }83 return () => {84 if (periodicUpdate) {85 clearInterval(periodicUpdate);86 }87 };88 }, [props.user, web3]);89 return (90 <div className='user-stats'>91 <div>92 <span className='icon'>☛</span>93 <span>{ numStaked } Staked</span>94 <span className='icon'>♥</span>95 <span>{ karmaBalance } Karma</span>96 </div>97 </div>98 );99}...
useCrawlers.js
Source:useCrawlers.js
1import { useCallback } from "react";2import { useMountedState } from "./"3import Axios from "axios";4export default function useCrawlers(api) {5 const isMounted = useMountedState();6 const fetchCrawlers = useCallback(() => {7 return new Promise((resolve, reject) => {8 Axios.get(api + "/crawler")9 .then((res) => {10 if (isMounted) {11 resolve(res.data);12 }13 })14 .catch((err) => {15 if (isMounted) reject(err)16 })17 })18 }, [api, isMounted])19 const startCrawler = useCallback(crawlerId => {20 return new Promise((resolve, reject) => {21 Axios.post(api + `/crawler/${crawlerId}/start`)22 .then((res) => {23 if (isMounted) {24 resolve(res.data);25 }26 })27 .catch((err) => {28 if (isMounted) reject(err)29 })30 })31 }, [api, isMounted])32 const stopCrawler = useCallback(crawlerId => {33 return new Promise((resolve, reject) => {34 Axios.post(api + `/crawler/${crawlerId}/stop`)35 .then((res) => {36 if (isMounted) {37 resolve(res.data);38 }39 })40 .catch((err) => {41 if (isMounted) reject(err)42 })43 })44 }, [api, isMounted])45 const toggleAutorestart = useCallback(crawlerId => {46 return new Promise((resolve, reject) => {47 Axios.post(api + `/crawler/${crawlerId}/toggleAutorestart`)48 .then((res) => {49 if (isMounted) {50 resolve(res.data);51 }52 })53 .catch((err) => {54 if (isMounted) reject(err)55 })56 })57 }, [api, isMounted])58 const resetIndex = useCallback(crawlerId => {59 return new Promise((resolve, reject) => {60 Axios.post(api + `/crawler/${crawlerId}/resetIndex`)61 .then((res) => {62 if (isMounted) {63 resolve(res.data);64 }65 })66 .catch((err) => {67 if (isMounted) reject(err)68 })69 })70 }, [api, isMounted])71 return {72 fetchCrawlers,73 startCrawler,74 stopCrawler,75 toggleAutorestart,76 resetIndex77 }...
_app.js
Source:_app.js
1import React, { useEffect, useState } from "react";2import Head from "next/head";3import { useRouter } from "next/router";4import Navigation from "../components/Navigation/Navigation";5import { NavShowContext } from "../utils/context/navContext";6import "../styles/globals.css";7function useDelayUnmount({ isMounted, setIsmounted }, delayTime) {8 const [shouldRender, setShouldRender] = useState(false);9 useEffect(() => {10 let timeoutId;11 if (isMounted && !shouldRender) {12 setShouldRender(true);13 } else if (!isMounted && shouldRender) {14 timeoutId = setTimeout(() => {15 setShouldRender(false);16 // setIsmounted(true);17 }, delayTime);18 }19 return () => clearTimeout(timeoutId);20 }, [isMounted, delayTime, shouldRender]);21 return shouldRender;22}23function MyApp({ Component, pageProps }) {24 const [isMounted, setIsmounted] = useState(true);25 const shouldRenderChild = useDelayUnmount({ isMounted, setIsmounted }, 500);26 const [showNav, setShowNav] = useState(true);27 console.log({28 Component,29 isMounted,30 shouldRenderChild,31 route: useRouter().pathname,32 });33 return (34 <>35 <Head>36 <meta name="viewport" content="width=device-width, initial-scale=1.0" />37 </Head>38 <NavShowContext.Provider value={{ showNav, setShowNav }}>39 <main className={`${showNav ? "grid_with_nav" : "grid_no_nav"}`}>40 {showNav && <Navigation setIsmounted={setIsmounted} />}41 {shouldRenderChild && (42 <div43 className={`sr-wrapper ${44 isMounted === false ? "sr_remove" : null45 }`}46 >47 <div className="sr-container">48 <Component {...pageProps} />49 </div>50 </div>51 )}52 </main>53 </NavShowContext.Provider>54 </>55 );56}...
Person.js
Source:Person.js
1import React, { useState, useEffect, useRef, memo } from "react";2// set globally wont affect each state change, but it is better to put it within function scope3// let isMounted = true;4const Person = memo(({ name, age, deletePerson, idx }) => {5 const [state, setState] = useState(() => true);6 // use useRef so it persist within the state change7 let isMounted = useRef(true);8 // let isMounted = true;9 let counter = useRef(0);10 console.log(name + " : " + counter.current++);11 console.log(name + " outside isMounted: ", isMounted);12 useEffect(() => {13 return () => {14 // when element unmount15 isMounted.current = false;16 console.log(" unmount", isMounted.current);17 // isMounted = false;18 // console.log("counter from unmount", counter.current);19 // console.log("unmount", isMounted);20 };21 }, []);22 return (23 <div>24 {state ? "loading.." : "finished!"}25 <p>26 im {name} and {age} years old27 </p>28 <button29 onClick={() =>30 setTimeout(() => {31 console.log("onclick finished", isMounted.current);32 if (isMounted.current) setState(false);33 // console.log("counter from click", counter.current);34 // console.log("onclick finished", isMounted);35 // if (isMounted) setState(false);36 }, 2000)37 }38 >39 finish40 </button>41 <button onClick={() => deletePerson(idx)}>remove</button>42 </div>43 );44});...
DelayedUnmounting.js
Source:DelayedUnmounting.js
1// https://medium.com/@tomaszferens/delay-unmounting-of-the-component-in-react-8d6f6e73cdc2// function delayUnmounting(Component) {3// return class extends React.Component {4// state = {5// shouldRender: this.props.isMounted6// };7// componentDidUpdate(prevProps) {8// if (prevProps.isMounted && !this.props.isMounted) {9// setTimeout(10// () => this.setState({ shouldRender: false }),11// this.props.delayTime12// );13// } else if (!prevProps.isMounted && this.props.isMounted) {14// this.setState({ shouldRender: true });15// }16// }17// render() {18// return this.state.shouldRender ? <Component {...this.props} /> : null;19// }20// };21// }22// function Box(props) {23// return (24// <div>25// â¨ð¶â¨ð¶â¨ð¶â¨ð¶â¨26// </div>27// )28// }29// const DelayedComponent = delayUnmounting(Box)30// class App extends React.Component {31// state = {32// isMounted: false33// }34// toggle = () => {35// this.setState(state => ({ isMounted: !state.isMounted }))36// }37// render() {38// return (39// <div>40// <DelayedComponent delayTime={500} isMounted={this.state.isMounted} />41// <button onClick={this.toggle}>TOGGLE</button>42// </div>43// )44// }...
customHooks.js
Source:customHooks.js
1/* eslint-disable react-hooks/exhaustive-deps */2import { useRef, useEffect } from 'react'3export const useDidMountEffect = (didMountFun, inputs) => {4 const isMounted = useRef(false);5 useEffect(() => {6 if (!isMounted.current) {7 isMounted.current = true;8 didMountFun();9 }10 }, inputs)11}12export const useDidUpdateEffect = (fun, inputs) => {13 const isMounted = useRef(false);14 useEffect(() => {15 if (!isMounted.current) {16 isMounted.current = true;17 } else {18 fun();19 }20 }, inputs)21}22export const useAnimationOnUpdate = (setClasses, [initialClasses, animationClass, animatedClass], toogler, inputs) => {23 const isMounted = useRef(false);24 useEffect(() => {25 if (!isMounted.current) {26 isMounted.current = true;27 setClasses(!toogler ? [].concat(initialClasses) : [].concat(initialClasses, animatedClass));28 } else {29 setClasses(!toogler ? [].concat(initialClasses, animationClass) : [].concat(initialClasses, animatedClass, animationClass));30 }31 }, inputs)32}33export const useIsMounted = () => {34 const isMounted = useRef(false)35 useEffect(() => {36 isMounted.current = true37 return () => isMounted.current = false38 }, [])39 return isMounted...
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.click('text=Get started');7 await page.waitForSelector('text=Playwright is a Node library to automate');8 await page.click('text=Docs');9 await page.waitForTimeout(1000);10 await page.waitForSelector('text=API');11 if (page.isClosed()) {12 console.log('Page is closed');13 } else {14 console.log('Page is still open');15 }16 await page.close();17 if (page.isClosed()) {18 console.log('Page is closed');19 } else {20 console.log('Page is still open');21 }22 await browser.close();23})();24Page.isClosed() → boolean25Page.close()
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 for (const browserType of BROWSER) {4 const browser = await playwright[browserType].launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 console.log(await page.title());8 await browser.close();9 }10})();11const playwright = require('playwright');12(async () => {13 for (const browserType of BROWSER) {14 const browser = await playwright[browserType].launch();15 const context = await browser.newContext();16 const page = await context.newPage();17 console.log(await page.title());18 await browser.close();19 }20})();21const playwright = require('playwright');22(async () => {23 for (const browserType of BROWSER) {24 const browser = await playwright[browserType].launch();25 const context = await browser.newContext();26 const page = await context.newPage();27 console.log(await page.title());28 await browser.close();29 }30})();31const playwright = require('playwright');32(async () => {33 for (const browserType of BROWSER) {34 const browser = await playwright[browserType].launch();35 const context = await browser.newContext();36 const page = await context.newPage();37 console.log(await page.title());38 await browser.close();39 }40})();41const playwright = require('playwright');42(async () => {43 for (const browserType of BROWSER) {44 const browser = await playwright[browserType].launch();45 const context = await browser.newContext();46 const page = await context.newPage();47 console.log(await page.title());48 await browser.close();49 }50})();51const playwright = require('playwright');52(async () => {53 for (const browserType of BROWSER)
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.screenshot({ path: `example.png` });7 await browser.close();8})();9const { chromium } = require('playwright');10(async () => {11 const browser = await chromium.launch();12 const context = await browser.newContext();13 const page = await context.newPage();14 await page.screenshot({ path: `example.png` });15 await browser.close();16})();17const { chromium } = require('playwright');18(async () => {19 const browser = await chromium.launch();20 const context = await browser.newContext();21 const page = await context.newPage();22 await page.screenshot({ path: `example.png` });23 await browser.close();24})();25const { chromium } = require('playwright');26(async () => {27 const browser = await chromium.launch();28 const context = await browser.newContext();29 const page = await context.newPage();30 await page.screenshot({ path: `example.png` });31 await browser.close();32})();33const { chromium } = require('playwright');34(async () => {35 const browser = await chromium.launch();36 const context = await browser.newContext();37 const page = await context.newPage();38 await page.screenshot({ path: `example.png` });39 await browser.close();40})();41const { chromium } = require('playwright');42(async () => {43 const browser = await chromium.launch();44 const context = await browser.newContext();45 const page = await context.newPage();46 await page.screenshot({ path
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 console.log(page.isPage());7 await page.screenshot({ path: `example.png` });8 await browser.close();9})();10Your name to display (optional):11Your name to display (optional):12Your name to display (optional):
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 console.log(page.isMounted());7 await page.close();8 await context.close();9 await browser.close();10})();11const { chromium } = require('playwright');12(async () => {13 const browser = await chromium.launch();14 const context = await browser.newContext();15 const page = await context.newPage();16 console.log(page.isMounted());17 await page.close();18 await context.close();19 await browser.close();20})();21This has been a guide to the isMounted() method of the Playwright Internal Page class. Here we discuss the definition, syntax, and examples of the isMounted() method along with its code implementation. You may also look at the following articles to learn more –
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const page = await browser.newPage();5 await page.waitForSelector('text=Get started');6 await page.click('text=Get started');7 await page.click('text=API');8 await page.waitForSelector('text=Page');9 await page.click('text=Page');10 await page.click('text=isMounted');11 await page.waitForSelector('text=isMounted');12 await page.click('text=isMounted');13 const isMounted = await page.isMounted();14 console.log("isMounted: " + isMounted);15 await page.close();16 await browser.close();17})();
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 console.log(page.isClosed());7 await page.close();8 console.log(page.isClosed());9 await browser.close();10})();11Playwright Internal Page isClosed() method12page.isClosed()13const { chromium } = require('playwright');14(async () => {15 const browser = await chromium.launch();16 const context = await browser.newContext();17 const page = await context.newPage();18 console.log(page.isClosed());19 await page.close();20 console.log(page.isClosed());21 await browser.close();22})();23Playwright Internal Page setDefaultTimeout() method24page.setDefaultTimeout(timeout)25const { chromium } = require('playwright');26(async () => {27 const browser = await chromium.launch();28 const context = await browser.newContext();29 const page = await context.newPage();30 page.setDefaultTimeout(500);31 console.log(page.isClosed());32 await page.close();33 console.log(page.isClosed());34 await browser.close();35})();36Playwright Internal Page setViewportSize() method37page.setViewportSize(size)38const { chromium } = require('playwright');39(async () => {40 const browser = await chromium.launch();41 const context = await browser.newContext();42 const page = await context.newPage();43 await page.setViewportSize({ width: 1280, height: 720 });44 await page.screenshot({ path: `screenshot.png` });45 await browser.close();46})();
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const page = await browser.newPage();5 const selector = 'text=Get started';6 await page.waitForSelector(selector);7 console.log(await page.isSelectorVisible(selector));8 await browser.close();9})();10const { chromium } = require('playwright');11(async () => {12 const browser = await chromium.launch();13 const page = await browser.newPage();14 const selector = 'text=Get started';15 await page.waitForSelector(selector);16 console.log(await page.isSelectorVisible(selector));17 await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const page = await browser.newPage();23 const selector = 'text=Get started';24 await page.waitForSelector(selector);25 console.log(await page.isSelectorVisible(selector));26 await browser.close();27})();28const { chromium } = require('playwright');29(async () => {30 const browser = await chromium.launch();
Using AI Code Generation
1const { isMounted } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const page = await browser.newPage();5 await page.click('text=Get started');6 await page.click('text=Docs');7 await page.click('text=API');8 await page.click('text=Page');9 await page.click('text=isMounted');10 const isMounted = await page.evaluate(() => {11 return document.querySelector('h1').textContent;12 });13 console.log(isMounted);14 await browser.close();15})();
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!