Best JavaScript code snippet using playwright-internal
jquery.placeholder.js
Source:jquery.placeholder.js
1/*! http://mths.be/placeholder v2.0.8 by @mathias */2;(function(window, document, $) {3 // Opera Mini v7 doesnât support placeholder although its DOM seems to indicate so4 var isOperaMini = Object.prototype.toString.call(window.operamini) == '[object OperaMini]';5 var isInputSupported = 'placeholder' in document.createElement('input') && !isOperaMini;6 var isTextareaSupported = 'placeholder' in document.createElement('textarea') && !isOperaMini;7 var prototype = $.fn;8 var valHooks = $.valHooks;9 var propHooks = $.propHooks;10 var hooks;11 var placeholder;12 if (isInputSupported && isTextareaSupported) {13 placeholder = prototype.placeholder = function() {14 return this;15 };16 placeholder.input = placeholder.textarea = true;17 } else {18 placeholder = prototype.placeholder = function() {19 var $this = this;20 $this21 .filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]')22 .not('.placeholder')23 .bind({24 'focus.placeholder': clearPlaceholder,25 'blur.placeholder': setPlaceholder26 })27 .data('placeholder-enabled', true)28 .trigger('blur.placeholder');29 return $this;30 };31 placeholder.input = isInputSupported;32 placeholder.textarea = isTextareaSupported;33 hooks = {34 'get': function(element) {35 var $element = $(element);36 var $passwordInput = $element.data('placeholder-password');37 if ($passwordInput) {38 return $passwordInput[0].value;39 }40 return $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '' : element.value;41 },42 'set': function(element, value) {43 var $element = $(element);44 var $passwordInput = $element.data('placeholder-password');45 if ($passwordInput) {46 return $passwordInput[0].value = value;47 }48 if (!$element.data('placeholder-enabled')) {49 return element.value = value;50 }51 if (value == '') {52 element.value = value;53 // Issue #56: Setting the placeholder causes problems if the element continues to have focus.54 if (element != safeActiveElement()) {55 // We can't use `triggerHandler` here because of dummy text/password inputs :(56 setPlaceholder.call(element);57 }58 } else if ($element.hasClass('placeholder')) {59 clearPlaceholder.call(element, true, value) || (element.value = value);60 } else {61 element.value = value;62 }63 // `set` can not return `undefined`; see http://jsapi.info/jquery/1.7.1/val#L236364 return $element;65 }66 };67 if (!isInputSupported) {68 valHooks.input = hooks;69 propHooks.value = hooks;70 }71 if (!isTextareaSupported) {72 valHooks.textarea = hooks;73 propHooks.value = hooks;74 }75 $(function() {76 // Look for forms77 $(document).delegate('form', 'submit.placeholder', function() {78 // Clear the placeholder values so they don't get submitted79 var $inputs = $('.placeholder', this).each(clearPlaceholder);80 setTimeout(function() {81 $inputs.each(setPlaceholder);82 }, 10);83 });84 });85 // Clear placeholder values upon page reload86 $(window).bind('beforeunload.placeholder', function() {87 $('.placeholder').each(function() {88 this.value = '';89 });90 });91 }92 function args(elem) {93 // Return an object of element attributes94 var newAttrs = {};95 var rinlinejQuery = /^jQuery\d+$/;96 $.each(elem.attributes, function(i, attr) {97 if (attr.specified && !rinlinejQuery.test(attr.name)) {98 newAttrs[attr.name] = attr.value;99 }100 });101 return newAttrs;102 }103 function clearPlaceholder(event, value) {104 var input = this;105 var $input = $(input);106 if (input.value == $input.attr('placeholder') && $input.hasClass('placeholder')) {107 if ($input.data('placeholder-password')) {108 $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));109 // If `clearPlaceholder` was called from `$.valHooks.input.set`110 if (event === true) {111 return $input[0].value = value;112 }113 $input.focus();114 } else {115 input.value = '';116 $input.removeClass('placeholder');117 input == safeActiveElement() && input.select();118 }119 }120 }121 function setPlaceholder() {122 var $replacement;123 var input = this;124 var $input = $(input);125 var id = this.id;126 if (input.value == '') {127 if (input.type == 'password') {128 if (!$input.data('placeholder-textinput')) {129 try {130 $replacement = $input.clone().attr({ 'type': 'text' });131 } catch(e) {132 $replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));133 }134 $replacement135 .removeAttr('name')136 .data({137 'placeholder-password': $input,138 'placeholder-id': id139 })140 .bind('focus.placeholder', clearPlaceholder);141 $input142 .data({143 'placeholder-textinput': $replacement,144 'placeholder-id': id145 })146 .before($replacement);147 }148 $input = $input.removeAttr('id').hide().prev().attr('id', id).show();149 // Note: `$input[0] != input` now!150 }151 $input.addClass('placeholder');152 $input[0].value = $input.attr('placeholder');153 } else {154 $input.removeClass('placeholder');155 }156 }157 function safeActiveElement() {158 // Avoid IE9 `document.activeElement` of death159 // https://github.com/mathiasbynens/jquery-placeholder/pull/99160 try {161 return document.activeElement;162 } catch (exception) {}163 }...
foundation.placeholder.js
Source:foundation.placeholder.js
...149 init : function (scope, method, options) {150 this.scope = scope || this.scope;151 if (typeof method !== 'string') {152 window.onload = function () {153 $('input, textarea').placeholder();154 }155 }156 }157 };...
tests.js
Source:tests.js
...9 }10 var testElement = function($el) {11 var el = $el[0];12 var placeholder = el.getAttribute('placeholder');13 strictEqual($el.placeholder(), $el, 'should be chainable');14 strictEqual(el.value, placeholder, 'should set `placeholder` text as `value`');15 strictEqual($el.prop('value'), '', 'propHooks works properly');16 strictEqual($el.val(), '', 'valHooks works properly');17 ok($el.hasClass('placeholder'), 'should have `placeholder` class');18 // test on focus19 $el.focus();20 strictEqual(el.value, '', '`value` should be the empty string on focus');21 strictEqual($el.prop('value'), '', 'propHooks works properly');22 strictEqual($el.val(), '', 'valHooks works properly');23 ok(!$el.hasClass('placeholder'), 'should not have `placeholder` class on focus');24 // and unfocus (blur) again25 $el.blur();26 strictEqual(el.value, placeholder, 'should set `placeholder` text as `value`');27 strictEqual($el.prop('value'), '', 'propHooks works properly');28 strictEqual($el.val(), '', 'valHooks works properly');29 ok($el.hasClass('placeholder'), 'should have `placeholder` class');30 // change the value31 $el.val('lorem ipsum');32 strictEqual($el.prop('value'), 'lorem ipsum', '`$el.val(string)` should change the `value` property');33 strictEqual(el.value, 'lorem ipsum', '`$el.val(string)` should change the `value` attribute');34 ok(!$el.hasClass('placeholder'), '`$el.val(string)` should remove `placeholder` class');35 // and clear it again36 $el.val('');37 strictEqual($el.prop('value'), '', '`$el.val("")` should change the `value` property');38 strictEqual(el.value, placeholder, '`$el.val("")` should change the `value` attribute');39 ok($el.hasClass('placeholder'), '`$el.val("")` should re-enable `placeholder` class');40 // make sure the placeholder property works as expected.41 strictEqual($el.prop('placeholder'), placeholder, '$el.prop(`placeholder`) should return the placeholder value');42 $el.prop('placeholder', 'new placeholder');43 strictEqual($el.prop('placeholder'), 'new placeholder', '$el.prop(`placeholder`, <string>) should set the placeholder value');44 strictEqual($el.value, 'new placeholder', '$el.prop(`placeholder`, <string>) should update the displayed placeholder value');45 $el.prop('placeholder', placeholder);46 };47 test('emulates placeholder for <input type=text>', function() {48 testElement( $('#input-type-text') );49 });50 test('emulates placeholder for <input type=search>', function() {51 testElement( $('#input-type-search') );52 });53 test('emulates placeholder for <input type=email>', function() {54 testElement( $('#input-type-email') );55 });56 test('emulates placeholder for <input type=url>', function() {57 testElement( $('#input-type-url') );58 });59 test('emulates placeholder for <input type=tel>', function() {60 testElement( $('#input-type-tel') );61 });62 test('emulates placeholder for <input type=tel>', function() {63 testElement( $('#input-type-tel') );64 });65 test('emulates placeholder for <input type=password>', function() {66 var selector = '#input-type-password';67 var $el = $(selector);68 var el = $el[0];69 var placeholder = el.getAttribute('placeholder');70 strictEqual($el.placeholder(), $el, 'should be chainable');71 // Re-select the element, as it gets replaced by another one in some browsers72 $el = $(selector);73 el = $el[0];74 strictEqual(el.value, placeholder, 'should set `placeholder` text as `value`');75 strictEqual($el.prop('value'), '', 'propHooks works properly');76 strictEqual($el.val(), '', 'valHooks works properly');77 ok($el.hasClass('placeholder'), 'should have `placeholder` class');78 // test on focus79 $el.focus();80 // Re-select the element, as it gets replaced by another one in some browsers81 $el = $(selector);82 el = $el[0];83 strictEqual(el.value, '', '`value` should be the empty string on focus');84 strictEqual($el.prop('value'), '', 'propHooks works properly');...
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.fill('input[placeholder="Search"]', 'placeholder');7 await page.screenshot({ path: `placeholder.png` });8 await browser.close();9})();10const { chromium } = require('playwright');11(async () => {12 const browser = await chromium.launch();13 const context = await browser.newContext();14 const page = await context.newPage();15 await page.fill('input[aria-label="Search"]', 'aria-label');16 await page.screenshot({ path: `aria-label.png` });17 await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const context = await browser.newContext();23 const page = await context.newPage();24 await page.fill('input[aria-labelledby="search"]', 'aria-labelledby');25 await page.screenshot({ path: `aria-labelledby.png` });26 await browser.close();27})();28const { chromium } = require('playwright');29(async () => {30 const browser = await chromium.launch();31 const context = await browser.newContext();32 const page = await context.newPage();33 await page.fill('input[aria-labelledby="search"]', 'aria-labelledby');34 await page.screenshot({ path: `aria-labelledby.png` });35 await browser.close();36})();37const { chromium } = require('playwright');38(async () => {39 const browser = await chromium.launch();40 const context = await browser.newContext();41 const page = await context.newPage();42 await page.fill('input[aria-labelledby="search"]', 'aria-labelledby');
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({ headless: false });4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.fill('input[placeholder="Search"]', 'Hello World');7 await page.click('input[type="submit"]');8 await page.waitForLoadState('networkidle');9 await browser.close();10})();
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');10module.exports = {11 use: {12 viewport: { width: 1280, height: 720 },13 launchOptions: {14 executablePath: chromium.executablePath(),15 }16 }17};18const { chromium } = require('playwright');19module.exports = {20 use: {21 viewport: { width: 1280, height: 720 },22 launchOptions: {23 executablePath: chromium.executablePath(),24 }25 }26};27const { chromium } = require('playwright');28module.exports = {29 use: {30 viewport: { width: 1280, height: 720 },31 launchOptions: {32 executablePath: chromium.executablePath(),33 }34 }35};36const { chromium } = require('playwright');37module.exports = {38 use: {39 viewport: { width: 1280, height: 720 },
Using AI Code Generation
1const {chromium} = require('playwright');2(async () => {3 const browser = await chromium.launch({headless: false});4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.click('text=Get started');7 await page.click('text=Docs');8 await page.click('text=API');9 await page.click('text=class Page');10 await page.click('text=click');11 await page.click('text=Parameters');12 await page.click('text=selector');13 await page.click('text=string');14 await page.click('text=Options');15 await page.click('text=force');16 await page.click('text=boolean');17 await page.click('text=timeout');18 await page.click('text=number');19 await page.click('text=stabilize');20 await page.click('text=boolean');21 await page.click('text=position');22 await page.click('text=Position');23 await page.click('text=button');24 await page.click('text=left');25 await page.click('text=middle');26 await page.click('text=right');27 await page.click('text=offset');28 await page.click('text=Point');29 await page.click('text=modifiers');30 await page.click('text=Array<string>');31 await page.click('text=Signal');32 await page.click('text=Example');33 await page.click('text=page.click(“#box”);');34 await page.click('text=page.click(“#box”, {force: true});');35 await page.click('text=page.click(“#box”, {button: “right”});');36 await page.click('text=page.click(“#box”, {delay: 1000});');37 await page.click('text=page.click(“#box”, {clickCount: 2});');38 await page.click('text=page.click(“#box”, {position: {x: 10, y: 10}});');39 await page.click('text=page.click(“#box”, {modifiers: [“Shift”]});');40 await page.click('text=page.click(“#box”, {timeout: 5000});');41 await page.click('text=page.click(“#box”,
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 const elementHandle = await page.$('input');7 await elementHandle.press('ArrowDown');8 await browser.close();9})();10const { chromium } = require('playwright');11(async () => {12 const browser = await chromium.launch();13 const context = await browser.newContext();14 const page = await context.newPage();15 const elementHandle = await page.$('input');16 await elementHandle.press('ArrowDown');17 await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const context = await browser.newContext();23 const page = await context.newPage();24 const elementHandle = await page.$('input');25 await elementHandle.press('ArrowDown');26 await browser.close();27})();28const { chromium } = require('playwright');29(async () => {30 const browser = await chromium.launch();31 const context = await browser.newContext();32 const page = await context.newPage();33 const elementHandle = await page.$('input');34 await elementHandle.press('ArrowDown');35 await browser.close();36})();37const { chromium } = require('playwright');38(async () => {39 const browser = await chromium.launch();40 const context = await browser.newContext();41 const page = await context.newPage();42 const elementHandle = await page.$('input');43 await elementHandle.press('ArrowDown');44 await browser.close();45})();46const { chromium } = require('playwright');47(async () => {48 const browser = await chromium.launch();49 const context = await browser.newContext();50 const page = await context.newPage();51 const elementHandle = await page.$('input');52 await elementHandle.press('ArrowDown');53 await browser.close();54})();55const { chromium } = require('playwright');56(async () => {57 const browser = await chromium.launch();
Using AI Code Generation
1const { chromium, firefox, webkit } = 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('#gb > div.gb_Kc.gb_8c.gb_R > div > div.gb_9c.gb_Ac > a');7 await page.screenshot({ path: `example.png` });8 await browser.close();9})();10const { chromium, firefox, webkit } = require('playwright');11(async () => {12 const browser = await chromium.launch();13 const context = await browser.newContext();14 const page = await context.newPage();15 await page.click('#gb > div.gb_Kc.gb_8c.gb_R > div > div.gb_9c.gb_Ac > a');16 await page.screenshot({ path: `example.png` });17 await browser.close();18})();19const { chromium, firefox, webkit } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const context = await browser.newContext();23 const page = await context.newPage();24 await page.click('#gb > div.gb_Kc.gb_8c.gb_R > div > div.gb_9c.gb_Ac > a');25 await page.screenshot({ path: `example.png` });26 await browser.close();27})();28const { chromium, firefox, webkit } = require('playwright');29(async () => {30 const browser = await chromium.launch();31 const context = await browser.newContext();32 const page = await context.newPage();33 await page.click('#gb > div.gb_Kc.gb_8c.gb_R > div > div.gb_9c.gb_Ac > a');34 await page.screenshot({ path: `example.png` });35 await browser.close();36})();
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({ headless: false, slowMo: 500 });4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.fill('input[name="q"]', 'Playwright');7 await page.click('input[name="btnK"]');8 await page.waitForSelector('text=Playwright - Google Search');9 await browser.close();10})();11const { chromium } = require('playwright');12(async () => {13 const browser = await chromium.launch({ headless: false, slowMo: 500 });14 const context = await browser.newContext();15 const page = await context.newPage();16 await page.fill('input[name="q"]', 'Playwright');17 await page.click('input[name="btnK"]');18 await page.waitForSelector('text=Playwright - Google Search');19 await browser.close();20})();21const { chromium } = require('playwright');22(async () => {23 const browser = await chromium.launch({ headless: false, slowMo: 500 });24 const context = await browser.newContext();25 const page = await context.newPage();26 await page.fill('input[name="q"]', 'Playwright');27 await page.click('input[name="btnK"]');28 await page.waitForSelector('text=Playwright - Google Search');29 await browser.close();30})();31const { chromium } = require('playwright');32(async () => {33 const browser = await chromium.launch({ headheadless: false, slowMo: 500 });34 const context = await browser.newContext();35 const page = await context.newPage();36 await page.fill('input[name="q"]', 'Playwright');37 await page.click('input[name="btnK"]');38 await page.waitForSelector('text=Playwright - Google Search');39 await browser.close();40})();
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.click('text=I agree');6 await page.fill('[name="q"]', 'Playwright');7 await page.click('input[type="submit"]');8 await page.screenshot({ path: `example.png` });9 await browser.close();10})();11const {chromium} = require('playwright');12(async () => {13 const browser = await chromium.launch();14 const page = await browser.newPage();15 await page.click('text="I agree"');16 await page.fill('[name="q"]', 'Playwright');17 await page.click('input[type="submit"]');18 await page.screenshot({ path: `example.png` });19 await browser.close();20})();
Using AI Code Generation
1const { test, expect } = require('@playwright/test');2test('test', async ({ page }) => {3 await page.click('text=Get started');4 await page.click('text=Docs');5 await page.click('text=API');6 await page.click('text=class: Page');7 await page.click('text=click');8 const element = await page.$('text=click');9 await element.scrollIntoViewIfNeeded();10 await page.click('text=click');11 const element2 = await page.$('text=click');12 await element2.scrollIntoViewIfNeeded();13 await page.click('text=click');14 const element3 = await page.$('text=click');15 await element3.scrollIntoViewIfNeeded();16 await page.click('text=click');17 const element4 = await page.$('text=click');18 await element4.scrollIntoViewIfNeeded();19 await page.click('text=click');20 const element5 = await page.$('text=click');21 await element5.scrollIntoViewIfNeeded();22 await page.click('text=click');23 const element6 = await page.$('text=click');24 await element6.scrollIntoViewIfNeeded();25 await page.click('text=click');26 const element7 = await page.$('text=click');27 await element7.scrollIntoViewIfNeeded();28 await page.click('text=click');29 const element8 = await page.$('text=click');30 await element8.scrollIntoViewIfNeeded();31 await page.click('text=click');32 const element9 = await page.$('text=click');33 await element9.scrollIntoViewIfNeeded();34 await page.click('text=click');35 const element10 = await page.$('text=click');36 await element10.scrollIntoViewIfNeeded();37 await page.click('text=click');38 const element11 = await page.$('text=click');39 await element11.scrollIntoViewIfNeeded();40 await page.click('text=click');41 const element12 = await page.$('text=click');42 await element12.scrollIntoViewIfNeeded();43 await page.click('text=click');44 const element13 = await page.$('text=click');45 await element13.scrollIntoViewIfNeeded();46 await page.click('text=click');47 const element14 = await page.$('text=click');
firefox browser does not start in playwright
Jest + Playwright - Test callbacks of event-based DOM library
How to run a list of test suites in a single file concurrently in jest?
Running Playwright in Azure Function
firefox browser does not start in playwright
Is it possible to get the selector from a locator object in playwright?
I found the error. It was because of some missing libraries need. I discovered this when I downgraded playwright to version 1.9 and ran the the code then this was the error msg:
(node:12876) UnhandledPromiseRejectionWarning: browserType.launch: Host system is missing dependencies!
Some of the Universal C Runtime files cannot be found on the system. You can fix
that by installing Microsoft Visual C++ Redistributable for Visual Studio from:
https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads
Full list of missing libraries:
vcruntime140.dll
msvcp140.dll
Error
at Object.captureStackTrace (D:\Projects\snkrs-play\node_modules\playwright\lib\utils\stackTrace.js:48:19)
at Connection.sendMessageToServer (D:\Projects\snkrs-play\node_modules\playwright\lib\client\connection.js:69:48)
at Proxy.<anonymous> (D:\Projects\snkrs-play\node_modules\playwright\lib\client\channelOwner.js:64:61)
at D:\Projects\snkrs-play\node_modules\playwright\lib\client\browserType.js:64:67
at BrowserType._wrapApiCall (D:\Projects\snkrs-play\node_modules\playwright\lib\client\channelOwner.js:77:34)
at BrowserType.launch (D:\Projects\snkrs-play\node_modules\playwright\lib\client\browserType.js:55:21)
at D:\Projects\snkrs-play\index.js:4:35
at Object.<anonymous> (D:\Projects\snkrs-play\index.js:7:3)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:12876) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:12876) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
A list of missing libraries was provided. After successful installments, firefox ran fine. I upgraded again to version 1.10 and firefox still works.
Check out the latest blogs from LambdaTest on this topic:
The best agile teams are built from people who work together as one unit, where each team member has both the technical and the personal skills to allow the team to become self-organized, cross-functional, and self-motivated. These are all big words that I hear in almost every agile project. Still, the criteria to make a fantastic agile team are practically impossible to achieve without one major factor: motivation towards a common goal.
Dries Buytaert, a graduate student at the University of Antwerp, came up with the idea of developing something similar to a chat room. Moreover, he modified the conventional chat rooms into a website where his friends could post their queries and reply through comments. However, for this project, he thought of creating a temporary archive of posts.
Building a website is all about keeping the user experience in mind. Ultimately, it’s about providing visitors with a mind-blowing experience so they’ll keep coming back. One way to ensure visitors have a great time on your site is to add some eye-catching text or image animations.
Technical debt was originally defined as code restructuring, but in today’s fast-paced software delivery environment, it has evolved. Technical debt may be anything that the software development team puts off for later, such as ineffective code, unfixed defects, lacking unit tests, excessive manual tests, or missing automated tests. And, like financial debt, it is challenging to pay back.
Greetings folks! With the new year finally upon us, we’re excited to announce a collection of brand-new product updates. At LambdaTest, we strive to provide you with a comprehensive test orchestration and execution platform to ensure the ultimate web and mobile experience.
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!!