Best JavaScript code snippet using redwood
ExecutionView.js
Source:ExecutionView.js
...406 if((value == "") &&(record.get("resultID")) &&(record.get("baseState"))){407 value = "Running";408 }409 if ((value == "Passed") || (value == "Running")){410 return "<a style= 'color: blue;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + value +"</a>";411 //return "<p style='color:green'>"+value+"</p>"412 }413 else if (value == "Failed"){414 return "<a style= 'color: red;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + value +"</a>";415 //return "<p style='color:red'>"+value+"</p>"416 }417 else{418 return value;419 }420 }421 },422 {423 header: 'Machine Base State',424 dataIndex: "baseState",425 width:200,426 renderer: function(value,metaData,record, rowIndex, colIndex, store, view){427 if (value){428 var action = Ext.data.StoreManager.lookup('Actions').getById(value);429 if(action){430 return action.get("name");431 }432 else{433 record.set("baseState",null);434 record.set("result",null);435 return "";436 }437 var actionName = Ext.data.StoreManager.lookup('Actions').getById(value).get("name");438 var url = "<a style= 'color: red;' href='javascript:openAction(""+ record.get("baseState") +"")'>" + actionName +"</a>";439 return url;440 }441 else{442 if(record.get("result")) record.set("result",null);443 return value444 }445 },446 editor: {447 xtype: "actionpicker",448 itemId: "actionpicker",449 width: 400,450 plugins:[451 Ext.create('Ext.ux.SearchPlugin')452 ],453 paramNames:["tag","name"],454 store: Ext.data.StoreManager.lookup('ActionsCombo'),455 autoSelect:false,456 forceSelection:false,457 queryMode: 'local',458 triggerAction: 'all',459 lastQuery: '',460 typeAhead: false,461 displayField: 'name',462 valueField: '_id'463 }464 },465 {466 header: 'Tags',467 dataIndex: 'tag',468 //flex: 1,469 width: 250470 }471 ]472 });473 var templates = [];474 var templatesStore = Ext.data.StoreManager.lookup('Templates');475 templatesStore.query("_id",/.*/).each(function(template){476 //var foundMachine = false;477 var baseState = null;478 var baseStateTCID = null;479 var result = null;480 var resultID = null;481 var threads = 1;482 var instances = 1;483 if ((me.dataRecord != null)&&(me.dataRecord.get("templates"))){484 me.dataRecord.get("templates").forEach(function(recordedTemplate){485 if(recordedTemplate._id === template.get("_id")){486 //baseState = recordedTemplate.baseState;487 //baseStateTCID = recordedTemplate.baseStateTCID;488 result = recordedTemplate.result;489 //resultID = recordedTemplate.resultID;490 if (recordedTemplate.threads){491 threads = recordedTemplate.threads;492 }493 else{494 threads = 1;495 }496 if (recordedTemplate.instances){497 instances = recordedTemplate.instances;498 }499 else{500 instances = 1;501 }502 }503 })504 }505 //if (baseStateTCID == null) baseStateTCID = Ext.uniqueId();506 templates.push({name:template.get("name"),threads:threads,instances:instances,result:result,description:template.get("description"),_id:template.get("_id")});507 //templates.push({host:template.get("name"),tag:template.get("tag"),state:template.get("state"),maxThreads:template.get("maxThreads"),threads:threads,result:result,resultID:resultID,baseState:baseState,baseStateTCID:baseStateTCID,description:template.get("description"),roles:template.get("roles"),port:template.get("port"),vncport:template.get("vncport"),_id:template.get("_id")})508 });509 var linkedTemplateStore = new Ext.data.Store({510 sorters: [{511 property : 'name'512 }],513 fields: [514 {name: 'name', type: 'string'},515 {name: 'instances', type: 'int'},516 {name: 'threads', type: 'int'},517 {name: 'result', type: 'string'},518 {name: 'description', type: 'string'},519 {name: '_id', type: 'string'}520 ],521 data: templates/*,522 listeners:{523 update:function(store, record, operation, modifiedFieldNames){524 if (me.loadingData === false){525 if (modifiedFieldNames){526 modifiedFieldNames.forEach(function(field){527 if (field === "baseState"){528 me.markDirty();529 }530 });531 }532 }533 }534 }535 */536 });537 me.templatesListener = function(options,eOpts){538 if (options.create){539 options.create.forEach(function(r){540 r.set("threads",1);541 r.set("instances",1);542 linkedTemplateStore.add(r);543 });544 }545 if (options.destroy){546 options.destroy.forEach(function(r){547 if (r) linkedTemplateStore.remove(linkedTemplateStore.query("_id", r.get("_id")).getAt(0));548 });549 }550 if (options.update){551 options.update.forEach(function(r){552 var linkedRecord = linkedTemplateStore.query("_id", r.get("_id")).getAt(0);553 if(!linkedRecord) return;554 if (r.get("name") != linkedRecord.get("name")){555 linkedRecord.set("name", r.get("name"));556 }557 if (r.get("description") != linkedRecord.get("description")){558 linkedRecord.set("description", r.get("description"));559 }560 });561 }562 };563 templatesStore.on("beforesync", me.templatesListener);564 var templatesGrid = new Ext.grid.Panel({565 store: linkedTemplateStore,566 itemId:"executionTemplates",567 selType: 'rowmodel',568 tbar:{569 xtype: 'toolbar',570 dock: 'top',571 items: [572 {573 width: 400,574 fieldLabel: 'Search',575 labelWidth: 50,576 xtype: 'searchfield',577 paramNames: ["name"],578 store: linkedTemplateStore579 }580 ]581 },582 viewConfig: {583 preserveScrollOnRefresh: true,584 markDirty: false585 },586 plugins: [587 Ext.create('Ext.grid.plugin.CellEditing', {588 clicksToEdit: 1,589 listeners:{590 beforeedit: function(editor,e){591 if(e.field == "threads"){592 templatesGrid.editingRecord = e.record;593 }594 else if(e.field == "instances"){595 templatesGrid.editingRecord = e.record;596 }597 }598 }599 })],600 maxHeight: 250,601 minHeight: 150,602 manageHeight: true,603 flex: 1,604 overflowY: 'auto',605 selModel: Ext.create('Ext.selection.CheckboxModel', {606 singleSelect: true,607 mode:"SINGLE",608 sortable: true,609 stateful: true,610 showHeaderCheckbox: true611 }),612 listeners:{613 edit: function(editor, e ){614 templatesGrid.getSelectionModel().select([e.record]);615 }616 },617 columns:[618 {619 header: 'Name',620 dataIndex: 'name',621 itemId:"nameColumn",622 width: 200623 },624 {625 header: 'Instances',626 dataIndex: 'instances',627 width: 100,628 editor: {629 xtype: 'numberfield',630 allowBlank: false,631 minValue: 1,632 listeners:{633 focus: function(field){634 //field.setMaxValue(machinesGrid.editingRecord.get("maxThreads"))635 }636 }637 }638 },639 {640 header: 'Threads',641 dataIndex: 'threads',642 width: 100,643 editor: {644 xtype: 'numberfield',645 allowBlank: false,646 minValue: 1,647 listeners:{648 focus: function(field){649 //field.setMaxValue(machinesGrid.editingRecord.get("maxThreads"))650 }651 }652 }653 },654 {655 header: 'Description',656 dataIndex: 'description',657 flex: 1658 },659 {660 header: "Result",661 dataIndex: "result",662 width: 120663 /*664 renderer: function(value,style,record){665 //style.tdAttr = 'data-qtip="' + record.get("error") + '"';666 if((value == "") &&(record.get("resultID")) &&(record.get("baseState"))){667 value = "Running";668 }669 if ((value == "Passed") || (value == "Running")){670 return "<a style= 'color: blue;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + value +"</a>";671 //return "<p style='color:green'>"+value+"</p>"672 }673 else if (value == "Failed"){674 return "<a style= 'color: red;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + value +"</a>";675 //return "<p style='color:red'>"+value+"</p>"676 }677 else{678 return value;679 }680 }681 */682 }683 ]684 });685 var executionTCStore = new Ext.data.Store({686 storeId: "ExecutionTCs"+this.itemId,687 //groupField: 'status',688 sorters: [{689 property : 'name'690 }],691 fields: [692 {name: 'name', type: 'string'},693 {name: 'tag', type: 'array'},694 {name: 'status', type: 'string'},695 {name: 'host', type: 'string'},696 {name: 'vncport', type: 'string'},697 {name: 'resultID', type: 'string'},698 {name: 'result', type: 'string'},699 {name: 'startAction', type: 'string'},700 {name: 'endAction', type: 'string'},701 {name: 'startdate', type: 'date'},702 {name: 'enddate', type: 'date'},703 {name: 'runtime', type: 'string'},704 {name: 'error', type: 'string'},705 {name: 'note', type: 'string'},706 {name: '_id', type: 'string'},707 {name: 'testcaseID', type: 'string'}708 ],709 data: []710 });711 me.executionTCStore = executionTCStore;712 me.updateTotals = function(execution){713 me.down("#totalPassed").setRawValue(execution.passed);714 me.down("#totalFailed").setRawValue(execution.failed);715 me.down("#totalNotRun").setRawValue(execution.notRun);716 me.down("#totalTestCases").setRawValue(execution.total);717 me.down("#runtime").setRawValue(execution.runtime);718 me.chartStore.findRecord("name","Passed").set("data",execution.passed);719 me.chartStore.findRecord("name","Failed").set("data",execution.failed);720 me.chartStore.findRecord("name","Not Run").set("data",execution.notRun);721 };722 me.updateCloudStatus = function(execution){723 me.down("#cloudStatus").setValue(execution.cloudStatus);724 };725 me.initialTotals = function(){726 if (me.dataRecord){727 me.down("#totalPassed").setRawValue(me.dataRecord.get("passed"));728 me.down("#totalFailed").setRawValue(me.dataRecord.get("failed"));729 me.down("#totalNotRun").setRawValue(me.dataRecord.get("notRun"));730 me.down("#totalTestCases").setRawValue(me.dataRecord.get("total"));731 me.down("#runtime").setRawValue(me.dataRecord.get("runtime"));732 me.chartStore.findRecord("name","Passed").set("data",me.dataRecord.get("passed"));733 me.chartStore.findRecord("name","Failed").set("data",me.dataRecord.get("failed"));734 me.chartStore.findRecord("name","Not Run").set("data",me.dataRecord.get("notRun"));735 }736 else{737 me.down("#totalPassed").setRawValue(0);738 me.down("#totalFailed").setRawValue(0);739 me.down("#totalNotRun").setRawValue(0);740 me.down("#totalTestCases").setRawValue(0);741 me.down("#runtime").setRawValue(0);742 }743 };744 executionTCStore.on("datachanged",function(store){745 //me.updateTotals(store);746 });747 executionTCStore.on("beforesync",function(options){748 if (options.update){749 //me.updateTotals(executionTCStore);750 }751 });752 var testcasesGrid = new Ext.grid.Panel({753 store: executionTCStore,754 itemId:"executionTestcases",755 selType: 'rowmodel',756 overflowY: 'auto',757 tbar:{758 xtype: 'toolbar',759 dock: 'top',760 items: [761 {762 width: 400,763 fieldLabel: 'Search',764 labelWidth: 50,765 xtype: 'searchfield',766 paramNames: ["name","tag"],767 //paramNames: ["tempName","tag","status","result"],768 store: executionTCStore769 },"->",770 {771 xtype:"checkbox",772 fieldLabel: "Debug",773 labelWidth: 40,774 checked: false,775 handler: function(widget){776 if(widget.getValue() == true){777 testcasesGrid.down('[dataIndex=startAction]').setVisible(true);778 testcasesGrid.down('[dataIndex=endAction]').setVisible(true);779 }780 else{781 testcasesGrid.down('[dataIndex=startAction]').setVisible(false);782 testcasesGrid.down('[dataIndex=endAction]').setVisible(false);783 }784 },785 listeners:{786 afterrender: function(){787 Ext.data.StoreManager.lookup('Executions').filter(me.lockedFilter);788 }789 }790 },791 {792 icon: 'images/note_add.png',793 hidden:true,794 tooltip:"Add Note to Selected Test Cases",795 handler: function(){796 if(testcasesGrid.getSelectionModel().getSelection().length == 0){797 Ext.Msg.alert('Error', "Please select test cases you want to attach note to.");798 return;799 }800 var win = Ext.create('Redwood.view.TestCaseNote',{801 onNoteSave:function(note){802 testcasesGrid.getSelectionModel().getSelection().forEach(function(testcase){803 testcase.set("note",note);804 me.markDirty();805 me.noteChanged = true;806 });807 }808 });809 win.show();810 }811 },"-","",812 {813 width: 400,814 fieldLabel: 'Search Notes',815 labelWidth: 80,816 xtype: 'searchfield',817 paramNames: ["note"],818 //paramNames: ["tempName","tag","status","result"],819 store: executionTCStore820 }821 ]822 },823 viewConfig: {824 markDirty: false,825 enableTextSelection: true826 },827 selModel: Ext.create('Ext.selection.CheckboxModel', {828 singleSelect: false,829 sortable: true,830 stateful: true,831 showHeaderCheckbox: true,832 listeners: {}833 }),834 minHeight: 150,835 height: 500,836 manageHeight: true,837 flex: 1,838 plugins: [839 "bufferedrenderer",840 Ext.create('Ext.grid.plugin.CellEditing', {841 clicksToEdit: 1842 })],843 listeners:{844 validateedit: function(editor,e){845 if(e.field == "note"){846 Ext.Ajax.request({847 url:"/executiontestcasenotes",848 method:"PUT",849 jsonData : {_id:e.record.get("_id"),note:e.value},850 success: function(response) {851 //if(obj.error != null){852 // Ext.Msg.alert('Error', obj.error);853 //}854 }855 });856 }857 },858 edit: function(editor, e ){859 if ((e.field == "endAction") &&(e.value != "") &&(e.record.get("startAction") == "")){860 e.record.set("startAction",1);861 }862 testcasesGrid.getSelectionModel().select([e.record]);863 }/*,864 cellclick: function(grid, td, cellIndex, record, tr, rowIndex, e ) {865 if (cellIndex == 11){866 var win = Ext.create('Redwood.view.TestCaseNote',{867 value: record.get("note"),868 onNoteSave:function(note){869 record.set("note",note);870 me.markDirty();871 me.noteChanged = true;872 }873 });874 win.show();875 }876 }*/877 },878 columns:[879 {880 header: 'Name',881 dataIndex: 'name',882 flex: 1,883 minWidth:200,884 renderer: function (value, meta, record) {885 //if (record.get("status") == "Finished"){886 //if (record.get("resultID")){887 // return "<a style= 'color: blue;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + value +"</a>";888 //}889 //else{890 // return value;891 //}892 //console.log(value);893 if (record.get("resultID")){894 //if(value.indexOf("<a style") == -1){895 //record.set("tempName",value);896 //record.set("name","<a style= 'color: blue;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + value +"</a>");897 //}898 //return value;899 return "<a style= 'color: blue;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + value +"</a>";900 }901 //record.set("name")902 return value;903 }904 },905 {906 header: 'Tags',907 dataIndex: 'tag',908 width: 120909 },910 {911 header: 'Start Action',912 dataIndex: 'startAction',913 width: 80,914 hidden:true,915 editor: {916 xtype: 'textfield',917 maskRe: /^\d+$/,918 allowBlank: true,919 listeners:{920 focus: function(){921 this.selectText();922 }923 }924 }925 },926 {927 header: 'End Action',928 dataIndex: 'endAction',929 hidden:true,930 width: 80,931 editor: {932 xtype: 'textfield',933 maskRe: /^\d+$/,934 allowBlank: true,935 listeners:{936 focus: function(){937 this.selectText();938 }939 }940 }941 },942 {943 header: 'Status',944 dataIndex: 'status',945 width: 100,946 renderer: function (value, meta, record) {947 //if(record.get("resultID") != ""){948 // record.set("name","<a style= 'color: blue;' href='javascript:openResultDetails(""+ record.get("resultID") +"")'>" + record.get("tempName") +"</a>");949 //}950 if(record.get("host") && (value == "Running")){951 return "<a style= 'color: blue;' href='javascript:vncToMachine(""+ record.get("host") +"",""+ record.get("vncport") +"")'>" + value +"</a>";952 }953 else if (value == "Finished"){954 return "<p style='color:green'>"+value+"</p>";955 }956 else if ( value == "Not Run"){957 return "<p style='color:#ffb013'>"+value+"</p>";958 }959 else{960 return value;961 }962 }...
ResultsRow.js
Source:ResultsRow.js
1import { deleteResult, deleteUserResult } from '@/legasy/firebase/results'2import { ROUTES } from '@/legasy/ROUTES'3import { getStyleInfo } from '@/legasy/src/CONSTANTS/SWIMMING_TESTS'4import { formatInputDate } from '@/legasy/src/utils/Dates'5import { AddIcon, CloseIcon, TrashBinIcon } from '@/legasy/src/utils/Icons'6import { averageRecordSpeed } from '@/legasy/src/utils/Records'7import Button from '@/legasy/src/components/inputs/Button'8import DeleteModal from '@/legasy/src/components/Modals/DeleteModal'9import { useRouter } from 'next/router'10import { useEffect, useState } from 'react'11import AwardBadge from './AwardBadge'12export default function ResultsRow({ results = [] }) {13 return (14 <div className="">15 <h3 className="font-bold text-md"></h3>16 <div className="grid grid-flow-col overflow-auto gap-5 px-3 py-2">17 <NewResultCard />18 {results?.map((result) => (19 <ResultCard key={result?.id} result={result} />20 ))}21 </div>22 </div>23 )24}25const NewResultCard = () => {26 const router = useRouter()27 // TODO deberia crear un nuevo record para el athleta no para el usuario28 return (29 <button30 onClick={() => router.push(ROUTES.records.newPersonal())}31 className="relative text-base border h-full rounded-b-3xl w-24 flex flex-col justify-center items-center text-center "32 >33 Nueva prueba34 <AddIcon />35 </button>36 )37}38const ResultCard = ({ result }) => {39 const { record = '', distance, style, awards } = result?.test || {}40 const [openResultDetails, setOpenResultDetails] = useState()41 const handleOpenResultDetails = () => {42 setOpenResultDetails(!openResultDetails)43 }44 return (45 <>46 <button47 onClick={handleOpenResultDetails}48 className="relative text-base border h-full rounded-b-3xl w-24"49 >50 <header className="italic text-xs flex w-full justify-center items-center bg-red-400">51 {result.date ? formatInputDate(result?.date, 'dd MMM yy') : 'no date'}52 </header>53 <div className="absolute -top-4 -right-5">54 {awards?.map((award) => (55 <AwardBadge key={award} award={award} size="xs" />56 ))}57 </div>58 <footer className="p-1 text-sm text-center">59 <div>{`${distance}m `}</div>60 <div>{`${getStyleInfo(style)?.largeLabel}`}</div>61 <div className="text-lg font-thin">{record}</div>62 <div className="text-lg font-thin">63 {averageRecordSpeed(distance, record)}64 <span className="text-xs">ms</span>65 </div>66 </footer>67 </button>68 <ResultModal69 open={openResultDetails}70 handleOpen={handleOpenResultDetails}71 result={result}72 />73 </>74 )75}76function ResultModal({ open, handleOpen = () => {}, result }) {77 useEffect(() => {78 const a = document.getElementById(`modal-${result.id}`)79 a.addEventListener('click', (e) => {80 const { id } = e.target81 if (id === `modal-${result.id}`) handleOpen()82 })83 }, [open])84 const [openDeleteModal, setOpenDeleteModal] = useState(false)85 const handleOpenDeleteModal = () => {86 setOpenDeleteModal(!openDeleteModal)87 }88 const handleDelete = () => {89 const isEventNull = !!Object.keys(result.event).length90 if (isEventNull) {91 deleteResult(result.id)92 } else {93 deleteUserResult(result.id)94 }95 }96 const { record = '', distance, style, awards } = result?.test || {}97 return (98 <div99 className="fixed top-0 right-0 left-0 bottom-0 bg-black bg-opacity-50 z-10 flex justify-center items-center"100 id={`modal-${result.id}`}101 style={{ display: !open && 'none' }}102 >103 <div104 id="modal-content"105 className={`relative z-50 bg-primary dark:bg-primary-dark rounded-b-full h-72 w-48 border px-2 flex flex-col justify-between items-center pb-4`}106 >107 <button className="absolute -top-6 right-0" onClick={handleOpen}>108 <CloseIcon />109 </button>110 <div>111 {result.date ? formatInputDate(result?.date, 'dd MMM yy') : 'no date'}112 </div>113 <div>{result?.event?.title || 'Registro personal'}</div>114 <div>115 {!awards?.length && 'Sin premios aún '}116 {awards?.map((award) => (117 <AwardBadge key={award} award={award} size="xs" />118 ))}119 </div>120 <div className="flex flex-wrap text-center">121 <div className="w-1/2">{distance ? `${distance}m ` : ''}</div>122 <div className="w-1/2">{`${123 getStyleInfo(style)?.largeLabel || ''124 }`}</div>125 <div className="w-1/2 text-lg font-thin">{record || ''}</div>126 <div className="w-1/2 text-lg font-thin">127 {averageRecordSpeed(distance, record)}128 <span className="text-xs">ms</span>129 </div>130 </div>131 {/*132 TODO We need include we write or validate this 133 <div>juez </div> */}134 <div>135 <Button136 iconOnly137 size="xs"138 variant="danger"139 onClick={handleOpenDeleteModal}140 >141 <TrashBinIcon size="1.2rem" />142 </Button>143 </div>144 </div>145 <DeleteModal146 open={openDeleteModal}147 handleOpen={handleOpenDeleteModal}148 handleDelete={handleDelete}149 title="Eliminar marca"150 text="Dejas de ver esta marca, pero no se eliminara del evento (si es que existe)"151 />152 </div>153 )...
component-test-results-element.component.ts
Source:component-test-results-element.component.ts
...15 ngOnInit() {16 console.log(this.componentInstance);17 // this.setStatusNumbers();18 }19 openResultDetails() {20 console.log(this.componentInstance);21 console.log(this.parentComponent);22 this.runTestService.notifyOpenComponentInstanceResultDetails(this.componentInstance, this.parentComponent);23 }24 setStatusNumbers() {25 let okCounter = 0;26 let nokCounter = 0;27 let errCounter = 0;28 if (this.componentInstance.caseInstances.length > 0) {29 for (const caseInstance of this.componentInstance.caseInstances) {30 if (caseInstance.stepInstances.length > 0) {31 for (const stepInstance of caseInstance.stepInstances) {32 if (stepInstance.status === 'OK') {33 okCounter++;...
Using AI Code Generation
1function testOpenResultDetails(){2 var resultId = "123456789";3 var result = {4 "attributes": {5 }6 };7 var redwood = window.redwoodInstance;8 redwood.openResultDetails(result);9}10### redwoodInstance.openResultDetails(result)11### redwoodInstance.getResults()12### redwoodInstance.getResult(id)13### redwoodInstance.updateResult(result)
Using AI Code Generation
1function openResultDetails() {2 redwoodApp.openResultDetails();3}4function openResultDetails() {5 redwoodApp.openResultDetails();6}7function openResultDetails() {8 redwoodApp.openResultDetails();9}10function openResultDetails() {11 redwoodApp.openResultDetails();12}13function openResultDetails() {14 redwoodApp.openResultDetails();15}16function openResultDetails() {17 redwoodApp.openResultDetails();18}19window.redwoodApp = {20 openResultDetails: function() {21 }22};23function openResultDetails() {
Using AI Code Generation
1var redwood = require('redwood');2var result = redwood.test('Test', function (t) {3 t.openResultDetails('Details');4});5![Result Details](images/result_details.png)6#### constructor(name, [options], testFn)7#### run()8#### pass()9#### fail(message)10#### skip()11#### timeout()12#### openResultDetails([message])13#### constructor(name, [options], suiteFn)14#### run()15#### pass()
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!