function onEdit(e) {
var columnToWatch = 116;
var sheet = SpreadsheetApp.getActiveSheet();
var clickedCell = sheet.getActiveCell();
if (clickedCell.getColumn() == columnToWatch) {
showOptionWindow(clickedCell);
}
}
function showOptionWindow(clickedCell) {
var html = '<html><body><form><p>Options :</p>';
html += '<input type="checkbox" name="option1" value="APIs/Storefront">APIs/Storefront<br>';
html += '<input type="checkbox" name="option2" value="Employee Rewards">Employee Rewards<br>';
html += '<input type="checkbox" name="option3" value="Channel Incentives">Channel Incentives<br>';
html += '<input type="checkbox" name="option4" value="Customer Rewards">Customer Rewards<br>';
html += '<input type="checkbox" name="option5" value="Payouts">Payouts<br>';
html += '<br>'
html += '<input type="submit" value="Submit" style="font-weight:bold; background-color:black; color:white;" onclick="google.script.run.processForm(this.form)">';
html += '</form></body></html>';
var ui = HtmlService.createHtmlOutput(html)
.setWidth(250)
.setHeight(275);
SpreadsheetApp.getUi().showModalDialog(ui, 'Pillar Selection');
}
function processForm(form) {
var selectedOptions = [];
if (form.option1.checked) {
selectedOptions.push(form.option1.value);
}
if (form.option2.checked) {
selectedOptions.push(form.option2.value);
}
if (form.option3.checked) {
selectedOptions.push(form.option3.value);
}
if (form.option4.checked) {
selectedOptions.push(form.option4.value);
}
if (form.option5.checked) {
selectedOptions.push(form.option5.value);
}
var sheet = SpreadsheetApp.getActiveSheet();
var clickedCell = sheet.getActiveCell();
clickedCell.setValue(selectedOptions.join(', '));
SpreadsheetApp.getUi().alert('You selected: ' + selectedOptions.join(', '));
SpreadsheetApp.getUi().close();
}
When the user submits the form by clicking the submit button, the script runs the processForm function to process the form data. The selected options are stored in an array, selectedOptions, and joined into a string with a comma-space separator. The value of the clicked cell is then set to the joined string of selected options and a confirmation alert is displayed to the user.
I think it would be simpler to just allow the user to close the dialog than automate it because no solutions are working. I did find an article about this topic on Spreadsheet Dev regarding your issue.
Hope it helps!
Try this:
Use an installable onEdit trigger:
function showOptionWindow() {
var html = '<html><body><form><p>Options :</p>';
html += '<input type="checkbox" name="option1" value="APIs/Storefront">APIs/Storefront<br>';
html += '<input type="checkbox" name="option2" value="Employee Rewards">Employee Rewards<br>';
html += '<input type="checkbox" name="option3" value="Channel Incentives">Channel Incentives<br>';
html += '<input type="checkbox" name="option4" value="Customer Rewards">Customer Rewards<br>';
html += '<input type="checkbox" name="option5" value="Payouts">Payouts<br>';
html += '<br>'
html += '<input type="button" value="Submit" style="font-weight:bold; background-color:black; color:white;" onclick="google.script.run.withSuccessHandler((v) => {google.script.host.close();}).processForm(this.parentNode)"/>';
html += '</form></body></html>';
var ui = HtmlService.createHtmlOutput(html)
.setWidth(250)
.setHeight(275);
SpreadsheetApp.getUi().showModelessDialog(ui, 'Pillar Selection');
}
function onMyEdit(e) {
//e.source.toast("Entry")
const sh = e.range.getSheet();
if (e.range.columnStart == 1 && sh.getName() == "Sheet0") {
//e.source.toast("Gate1")
showOptionWindow(e.range);
}
}
function processForm(obj) {
Logger.log(JSON.stringify(obj))
var selectedOptions = [];
if (obj.hasOwnProperty("option1")) {
selectedOptions.push(obj.option1);
}
if (obj.hasOwnProperty("option2")) {
selectedOptions.push(obj.option2);
}
if (obj.hasOwnProperty("option3")) {
selectedOptions.push(obj.option3);
}
if (obj.hasOwnProperty("option4")) {
selectedOptions.push(obj.option4);
}
if (obj.hasOwnProperty("option5")) {
selectedOptions.push(obj.option5);
}
Logger.log(JSON.stringify(selectedOptions));
var sheet = SpreadsheetApp.getActiveSheet();
var clickedCell = sheet.getActiveCell();
clickedCell.setValue(selectedOptions.join(', '));
SpreadsheetApp.getUi().alert('You selected: ' + selectedOptions.join(', '));
return true;
}
Here is an example of how to close the modal dialog. I have split the html into its own file to better manage the html code.
Code.gs
function showTest() {
var html = HtmlService.createHtmlOutputFromFile("HTML_Test");
SpreadsheetApp.getUi().showModalDialog(html,"Test");
}
HTML_Test.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
<p>Options :</p>
<input type="checkbox" name="option1" value="APIs/Storefront">APIs/Storefront<br>
<input type="checkbox" name="option2" value="Employee Rewards">Employee Rewards<br>
<input type="checkbox" name="option3" value="Channel Incentives">Channel Incentives<br>
<input type="checkbox" name="option4" value="Customer Rewards">Customer Rewards<br>
<input type="checkbox" name="option5" value="Payouts">Payouts<br>
<br>
<input type="submit" value="Submit" style="font-weight:bold; background-color:black; color:white;" onclick="clickSubmit(this.form)">
</form>
<script>
function clickSubmit(form) {
try {
google.script.run.withSuccessHandler(
function() {
google.script.host.close();
}
).processForm(form);
}
catch(err) {
alert(err);
}
}
</script>
</body>
</html>
Related
I have a simple HTML form that is used for bookings. Once completed it submits the fields via e-mail which can then be automatically uploaded into my Access database with VBA.
The process works fine if there is just text in the form but I want to include radio button choices as well. The problem is that it doesn't include an indication as to which button has been chosen.
The body of the e-mail, if "text" was entered into the text box and choice2 was selected would be:
text
Choice1
Choice2
Choice3
What I would like it to be is:
text
Choice2.
Can this be done?
A simplified version of my code so far is:
function displayRadioValue() {
var ele = document.getElementsByName('Choice');
for (j = 0; j < ele.length; j++) {
if (ele[j].checked)
document.getElementById("result").innerHTML = ele[j].value;
}
}
function btnClick() {
var link = "mailto:username#domain.com" +
"&subject=" + escape("Radio button trial") +
"&body=" + escape(buildForm());
window.location.href = link;
}
function buildForm() {
var str = "";
var elem = document.getElementById('RBT').elements;
for (var i = 1; i < elem.length; i++) {
if (elem[i].type != "button") {
str += elem[i].value + "\r\n";
}
}
return str;
}
<body>
<form id="RBT" name="RBT">
<fieldset>
<p></p>
<legend>Complete the form and\or choose an option</legend><br>
<div>
<label for "text1">Text1</label><br>
<input id="text1" name="text1"><br>
<input type="radio" id="radio1" name="Choice" value="Choice1" checked onclick="displayRadioValue()">
<label for="radio1">Choice1</label><br>
<input type="radio" id="radio2" name="Choice" value="Choice2" onclick="displayRadioValue()">
<label for="radio2">Choice2</label><br>
<input type="radio" id="radio3" name="Choice" value="Choice3" onclick="displayRadioValue()">
<label for="radio3">Choice3</label><br>
<br></div>
<div id="result" name="result" value="result"></div>
</fieldset>
</form>
<BUTTON type=submit onclick="btnClick()" />
<FONT size=5 bold>Submit choice</FONT>
</BUTTON>
You need to check if the element is checked.
And since you're adding it in the same loop as the text field you also need to make sure the element that has to be checked is actually a radio button:
if(elem[i].type != "radio" || elem[i].checked) {
str += elem[i].value + "\r\n";
}
But: In your snippet everything is added to the TO field of the mail, is that intended?
function displayRadioValue() {
var ele = document.getElementsByName('Choice');
for (j = 0; j < ele.length; j++) {
if (ele[j].checked)
document.getElementById("result").innerHTML = ele[j].value;
}
}
function btnClick() {
var link = "mailto:username#domain.com" +
"&subject=" + escape("Radio button trial") +
"&body=" + escape(buildForm());
window.location.href = link;
}
function buildForm() {
var str = "";
var elem = document.getElementById('RBT').elements;
for (var i = 1; i < elem.length; i++) {
if (elem[i].type != "button") {
if(elem[i].type != "radio" || elem[i].checked) {
str += elem[i].value + "\r\n";
}
}
}
return str;
}
<html>
<head>
<title>Radio button trial</title>
</head>
<body>
<form id="RBT" name="RBT">
<fieldset>
<p></p>
<legend>Complete the form and\or choose an option</legend><br>
<div>
<label for "text1">Text1</label><br>
<input id="text1" name="text1"><br>
<input type="radio" id="radio1" name="Choice" value="Choice1" checked onclick="displayRadioValue()">
<label for="radio1">Choice1</label><br>
<input type="radio" id="radio2" name="Choice" value="Choice2" onclick="displayRadioValue()">
<label for="radio2">Choice2</label><br>
<input type="radio" id="radio3" name="Choice" value="Choice3" onclick="displayRadioValue()">
<label for="radio3">Choice3</label><br>
<br></div>
<div id="result" name="result" value="result"></div>
</fieldset>
</form>
<BUTTON type=submit onclick="btnClick()" />
<FONT size=5 bold>Submit choice</FONT>
</BUTTON>
</body>
</html>
I created a script which exports a CSV from Google Sheets. This CSV is exported to a Drive folder, and I initially placed an ID in the code using var folder = DriveApp.getFolderById("ID goes here");
Now, I want to make the export location dynamic for my users. I also want them to select the frequency of automated exports. I created an html file and call a dialog box up for users to input their desired ID and frequency.
function openFolderForm() {
var html = HtmlService.createHtmlOutputFromFile('html')
.setHeight(525)
.setWidth(800);
SpreadsheetApp.getUi().showModalDialog(html, 'Export Settings');
}
In the html file, I have..
<form id="form">
<div class="block form-group">
<input type='text' name='IDdrive' id="IDdrive" style="width: 300px;"/>
</div>
<br>
<p>Frequency?</p>
<div>
<input type="radio" name="radio" id="radioDaily">
<label for="radioDaily">Daily</label>
</div>
<div>
<input type="radio" name="radio" id="radioWeekly">
<label for="radioWeekly">Weekly</label>
</div>
<button type = "submit" class = "action"
onClick="google.script.run.updateSettings();">Submit</button>
</form>
Finally, in my code I have...
function updateSettings(form) {
var formQ1 = form.IDdrive;
if (form.radioDaily == true) { var formQ2 = 1; } else { var formQ2 = 7}
};
function exportCSV() {
var changelogSheetName = "data";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var tab = ss.getSheetByName('data');
var folder = DriveApp.getFolderById(formQ1); //putting in dynamic form
etc etc etc
function createTimeTrigger() {
ScriptApp.newTrigger("exportCSV")
.timeBased()
.atHour(3)
.inTimezone("America/Los_Angeles")
.everyDays(formQ2) //input radio variable answer here
.create();
}
};
However, my code is not working. The variables for the form answers are not passing to client side successfully. The code does work if I put in the ID directly.
I realize that this has been asked in various forms already on this site, but I have read most of those threads and have still been unable to resolve. Could someone help out of Scripts App newbie please? :)
Full code below, starting with .gs :
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ui = SpreadsheetApp.getUi();
ui.createMenu('Scripts')
.addItem('Export CSV', 'exportCSV')
.addItem('Update export settings', 'openFolderForm')
.addToUi();
}
function openFolderForm() {
var html = HtmlService.createHtmlOutputFromFile('html').setHeight(525).setWidth(800);
SpreadsheetApp.getUi().showModalDialog(html, 'Export Settings');
}
function updateSettings(form) {
var formQ1 = form.IDdrive;
if (form.radioDaily == true) { var formQ2 = 1; } else { var formQ2 = 7};
google.script.host.close();
};
function exportCSV() {
var changelogSheetName = "data";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var tab = ss.getSheetByName('data');
var folder = DriveApp.getFolderById(formQ1);
//export code here
}
function convertRangeToCsvFile_(csvFileName, sheet) {
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var csvFile = undefined;
if (data.length > 1) {
var csv = "";
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
if (row < data.length-1) {
csv += data[row].join(",") + "\r\n";
}
else {
csv += data[row];
}
}
csvFile = csv;
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
function createTrigger() {
ScriptApp.newTrigger('exportCSV')
.timeBased()
.atHour(3)
.everyDays(formQ2) //radio question here
.inTimezone("America/Los_Angeles")
.create();
and HTML full...
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<title><b>Output Folder</b></title>
</head>
<body>
<p>Enter the ID of your output folder. A Drive ID is made up by the characters after the last /folder/ in the URL</p>
<form id="form">
<div class="block form-group">
<input type='text' name='IDdrive' id="IDdrive" style="width: 300px;"/>
</div>
<div>
<input type="radio" name="radio" id="radioDaily"> <label for="radioDaily">Daily</label>
</div>
<div>
<input type="radio" name="radio" id="radioWeekly"> <label for="radioWeekly">Weekly</label>
</div>
<br>
<div class="inline form-group">
<input type="button" value="Submit" class="action" onClick="google.script.run.updateSettings();" /> //or "google.script.run.updateSettings(this.parentNode);"
<input type="button" value="Cancel" class="cancel" onClick="google.script.host.close();" />
</div>
<br>
</form>
</body>
</html>
Your not passing anything to updateSettings google.script.run.updateSettings();>
I would do it like this:
<input type = "button" value="Submit" onClick="google.script.run.updateSettings(this.parentNode);" />
I'm running this as a dialog and it runs okay now. I added values to the radio buttons and now the weekly one returns 'weekly' and the daily one returns 'daily' and the IDdrive returns a string.
gs:
function openFolderForm() { SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutputFromFile('ah1').setHeight(525).setWidth(800), 'Export Settings');
}
function updateSettings(form) {
console.log(form)
var formQ1=form.IDdrive;
if (form.radioDaily == true) { var formQ2 = 1; } else { var formQ2 = 7}
}
function exportCSV() {
var changelogSheetName = "data";
var ss=SpreadsheetApp.getActive();
var sheets=ss.getSheets();
var tab=ss.getSheetByName('data');
var folder=DriveApp.getFolderById(formQ1);
}
html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<title><b>Output Folder</b></title>
</head>
<body>
<p>Enter the ID of your output folder. A Drive ID is made up by the characters after the last /folder/ in the URL</p>
<form>
<input type='text' name='IDdrive' id="IDdrive" style="width: 300px;"/><br />
<input type="radio" name="radio" id="radioDaily" value="daily"> <label for="radioDaily">Daily</label><br />
<input type="radio" name="radio" id="radioWeekly" value="weekly"> <label for="radioWeekly">Weekly</label><br />
<input type="button" value="Submit" class="action" onClick="google.script.run.updateSettings(this.parentNode);" />
<input type="button" value="Cancel" class="cancel" onClick="google.script.host.close();" />
</form>
</body>
</html>
Got it to work. The secret was needed to just JSON to properly store the form input criteria.
CODE
function updateSettings(formObject) {
var uiForm = SpreadsheetApp.getUi();
JSON.stringify(formObject);
var formText = formObject.formQ1;
var formRadio = formObject.formQ2;
if (formRadio == "Daily") { var frequency = 1; } else { var frequency = 7};
etc etc
HTML
<form id="myForm" onsubmit="event.preventDefault(); google.script.run.updateSettings(this); google.script.host.close();">
<div>
<input type='text' name='formQ1' id="formQ1" style="width: 300px;"/>
</div>
<div class="inline form-group">
<input type="radio" name="formQ2" id="formQ2" value="Daily" /> <label for="radioDaily">Daily</label>
</div>
<div>
<input type="radio" name="formQ2" id="formQ2" value="Weekly" /> <label for="radioWeekly">Weekly</label>
</div>
<br><br>
<div class="inline form-group">
<input type="submit" value="Submit" style="color:#4285F4"/>
<input type="button" value="Cancel" class="cancel" onClick="google.script.host.close();" />
Say I have <input type="checkbox" id="box1" /> and <div id="createhere"></div> and in a javascript file I have:
function(){
var box=document.getElementById("box").checked;
var s = "";
if(box){
s = "<input type="text" name="text" id="text" />"
document.getElementById("createhere").innerHTML = s;
}else{
s = "";
document.getElementById("createhere").innerHTML = s;
}
}
Now this works BUT it only creates the text box when I refresh the browser(firefox).
How can I do the same without refreshing the browser?
This code work on jQuery. I used jQuery because question has a jQuery tag!
You could try this.
$("#box").on('change', function(){
var check = $(this).prop("checked");
var inputHTML = "";
if ( check )
inputHTML = "<input type='text' name='text' id='text' />";
$("#createhere").html( inputHTML );
}).trigger("change");
Use a change event handler
function update() {
var box = document.getElementById("box").checked;
var s = "";
if (box) {
s = '<input type="text" name="text" id="text" />';
} else {
s = "";
}
document.getElementById("createhere").innerHTML = s;
}
<input type="checkbox" id="box" onchange="update()" />
<div id="createhere"></div>
With jQuery
jQuery(function($) {
$('#box').change(function() {
$('#createhere').html(this.checked ? '<input type="text" name="text" id="text" />' : '');
}).change()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="checkbox" id="box" />
<div id="createhere"></div>
My input texts work fine when i click the 'Edit HTML Below then Click Display' button, but my tinymce textareas won't work when I edit them. They'll send it's old value to the iframe, but not the new value. How can I send the new values when I edit the tinymce textareas? Here's the jsfiddle: http://jsfiddle.net/Ms3NG/1/ and code below:
<script type="text/javascript">
function init(buttonid, name, iframeid) {
document.getElementById(buttonid).addEventListener('click',function() {
// this.style.backgroundColor = '#cc0000';
gJSL_displayInput(name, iframeid)
},false);
gJSL_displayInput(name, iframeid);
}
window.onload = function() {
init('thisButton','test','iframetest');
init('thisButtona','testa','iframetesta');
init('thisButtonb','testb','iframetestb');
}
function gJSL_displayInput(nameInput, idOutput) {
var loc = "::JSLearning::gJSL_displayInput()";
try {
var ifrm = document.getElementById(idOutput);
var cnt = (ifrm.contentWindow || ifrm.contentDocument);
var doc;
doc = cnt.document;
doc.open();
var inputs = document.getElementsByName(nameInput);
for(var i = 0; i < inputs.length; i++) {
doc.write(inputs[i].value + "<br />");
}
doc.close();
} catch (e) {
exceptionAlert(loc, e);
}
}
</script>
<script src="//tinymce.cachefly.net/4.0/tinymce.min.js"></script>
<script>
tinymce.init({selector:'textarea'});
</script>
<div class="scrollbar">
<input id="test1" name="test" value="ajkla;ldkfj">
<input id="test2" name="test" value="bla2">
<input id="test3" name="test" value="bla3">
<input id="test4" name="test" value="bla4">
<input id="test5" name="test" value="bla5">
<br><br>
<textarea class="ckeditor" id="test6" name="test"></textarea>
<br><br>
<input id="test7" name="test" value="bla7">
<br><br>
<textarea id="test8" name="test">HELLO WORLD</textarea>
<br><br>
<textarea id="test9" name="test">HI EVERYBODY</textarea>
<br><br>
<input id="thisButton" type="button" name="Display" value="Edit HTML Below then Click to Display"/>
</div>
<div class="scrollbar"><iframe id="iframetest" src="" style="background: White;"></iframe></div>
You can use this code:
content8 = tinyMCE.get('test8').getContent();
doc.write(content8);
content9 = tinyMCE.get('test9').getContent();
doc.write(content9);
to get the values from the tinyMCE updated values.
Check this JSFiddle that I've build for you.
The last time I used tinyMCE, it doesn't have autoupdate textarea feature..
So, before submit the form, use .getContent() to update your textarea..
here is the link http://www.tinymce.com/wiki.php/API3:method.tinymce.Editor.getContent
So, your code will looks like
function gJSL_displayInput(nameInput, idOutput) {
var loc = "::JSLearning::gJSL_displayInput()";
try {
var ifrm = document.getElementById(idOutput);
var cnt = (ifrm.contentWindow || ifrm.contentDocument);
var doc;
doc = cnt.document;
doc.open();
var inputs = document.getElementsByName(nameInput);
for(var i = 0; i < inputs.length; i++) {
if(inputs[i].tagName == 'TEXTAREA')
doc.write(tinyMCE.get(inputs[i].id).getContent() + "<br />");
else
doc.write(inputs[i].value + "<br />");
}
doc.close();
} catch (e) {
exceptionAlert(loc, e);
}
}
I am new to javascript and html and I am writing a program that displays a dropdown list and depending on what option is selected, I then display two radio buttons and a textfield. I am having trouble getting access to the values of these inputs (both for the radio buttons and for the text box).
<html>
<script type="text/javascript">
window.onload = function()
{
var select = document.getElementById("select");
var texts = document.getElementById("texts");
select.onchange = function()
{
var val = select.options[select.selectedIndex].value;
texts.innerHTML = "";
if (val == "employees")
{
texts.innerHTML += '<div><input type="radio" name="condition_employees" value="select_money" /> ></div>';
texts.innerHTML += '<div><input type="radio" name="condition_employees" value="select_money1" /> <</div>';
texts.innerHTML += '<div><input type="text" name="input_employees" value="select_employees" /></div>';
//var realValue = document.getElementByName('input_employees')[0].value;
//texts.innerHTML += '<div>realValue</div>';
}
if (val == "total_money")
{
texts.innerHTML += '<div><input type="radio" name="condition_money" value="select_money" /> ></div>';
texts.innerHTML += '<div><input type="radio" name="condition_money" value="select_money1" /> <</div>';
texts.innerHTML += '<div><input type="text" name="input_money"' + '" value="select_money" /></div>';
}
if (val == "hits")
{
texts.innerHTML += '<div><input type="radio" name="condition_hits" value="select_money" /> ></div>';
texts.innerHTML += '<div><input type="radio" name="condition_hits" value="select_money1" /> <</div>';
texts.innerHTML += '<div><input type="text" name="input_hits"' + '" value="select_hits" /></div>';
}
if (val == "time_founded")
{
texts.innerHTML += '<div><input type="radio" name="condition_time" value="select_money" /> before date </div>';
texts.innerHTML += '<div><input type="radio" name="condition_time" value="select_money1" /> after date</div>';
texts.innerHTML += '<div><input type="text" name="input_time"' + '" value="select_date" /></div>';
}
}
}
var print = function()
{
var category = document.droplist.select.value;
document.getElementById("category").innerHTML = category
}
</script>
<body>
<form name="droplist" action="html_form_action.asp" method = "get">
<select id="select" size="1">
<option value=" " selected="selected"> </option>
<option value="employees">Number of Employees</option>
<option value="hits">Hits on TechCrunch</option>
<option value="time_founded">Time Founded</option>
<option value="total_money">Total Money</option>
</select>
<hr/>
<div id="texts"></div>
<input type="button" value="Submit" onClick="print()"/>
</form>
<div id="category"></div>
</body>
I tried to do this by using "//var realValue = document.getElementByName('input_employees')[0].value;" but this is clearly not working. I would also like to know how to then pass on this information as a paramater for a function in my python app.
Thanks!
Might I suggest the following:
Don't re-write the <div>s in your javascript. You can write to the <div>'s innerHTML.
Instead of constantly writing these values, why not disable/enable as necessary?
I unfortunately cannot comment on the question, so I had to post here. Sorry about that.