I have a spreadsheet with multiple sheets each sheet has the same layout with Date in column "A" and Time Elapsed in column "P" I need to calculate days between column A and today on all four sheets. If checkbox in column "N" is set to true then instead calculate column "O" from "A".
So far I have been able to code this bit but, need help getting over the hurdle.
function getDateDifference(event) {
var ss = event.source;
var s = ss.getSheetByName('Alpha'); // I need this to run on all four pages
var r = event.source.getActiveRange();
var startDate = sheet.getRange(3,1).getValue();
var endDate = new Date();
var duration = (endDate - startDate)
var r = event.source.getActiveRange();
if (r.getColumn() == 14 && r.getValue() == true) {
var endDate = sheet.getRange(3, 15);
var duration = (endDate - startDate);
sheet.getRange(3, 16).setValue(duration);
}
else {sheet.getRange(3, 16).setValue(duration);}
}
Example sheet for reference
https://docs.google.com/spreadsheets/d/1OKFoS17le-Y5SAOecoLE4EJxiKqKVjRLRHtMzwHNwxM/edit?usp=sharing
Calculate Diff in Days for selected sheets
function calcdiffindays() {
const ss = SpreadsheetApp.getActive();
const incl = ['Alpha', 'Sheet2', 'Sheet3'];//Add the desired sheet names
const dt = new Date();
const dtv = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
ss.getSheets().filter(sh => ~incl.indexOf(sh.getName())).forEach(s => {
s.getRange(3, 1, s.getLastRow() - 2, s.getLastColumn()).getValues().forEach((r, i) => {
if (r[13] == true) {
let d = new Date(r[0]);
let dv = new Date(d.getFullYear(), d.getMonth(), d.getDate());
s.getRange(i + 3, 15).setValue(DiffInDays(dtv, dv));
}
})
})
}
function DiffInDays(Day1,Day2) {
if(Day1 && Day2 && (Object.prototype.toString.call(Day1) === '[object Date]') && (Object.prototype.toString.call(Day2) === '[object Date]')) {
var day=86400000;
var t1=new Date(Day1).valueOf();
var t2=new Date(Day2).valueOf();
var d=Math.abs(t2-t1);
var days=Math.floor(d/day);
//Logger.log(days);
return days;
} else {
throw 'Invalid Inputs';
}
}
Test Sheet:
COL1
COL2
COL3
COL4
COL5
COL6
COL7
COL8
COL9
COL10
COL11
COL12
COL13
COL14
COL15
7/1/2022
2
3
4
5
6
7
8
9
10
11
12
13
TRUE
3
7/2/2022
3
4
5
6
7
8
9
10
11
12
13
14
TRUE
4
7/3/2022
4
5
6
7
8
9
10
11
12
13
14
15
TRUE
5
7/4/2022
5
6
7
8
9
10
11
12
13
14
15
16
TRUE
6
7/5/2022
6
7
8
9
10
11
12
13
14
15
16
17
TRUE
7
7/6/2022
7
8
9
10
11
12
13
14
15
16
17
18
TRUE
8
7/7/2022
8
9
10
11
12
13
14
15
16
17
18
19
TRUE
9
7/8/2022
9
10
11
12
13
14
15
16
17
18
19
20
TRUE
10
7/9/2022
10
11
12
13
14
15
16
17
18
19
20
21
TRUE
11
7/10/2022
11
12
13
14
15
16
17
18
19
20
21
22
TRUE
12
7/11/2022
12
13
14
15
16
17
18
19
20
21
22
23
TRUE
13
7/12/2022
13
14
15
16
17
18
19
20
21
22
23
24
TRUE
14
7/13/2022
14
15
16
17
18
19
20
21
22
23
24
25
TRUE
15
7/14/2022
15
16
17
18
19
20
21
22
23
24
25
26
TRUE
16
7/15/2022
16
17
18
19
20
21
22
23
24
25
26
27
FALSE
7/16/2022
17
18
19
20
21
22
23
24
25
26
27
28
TRUE
18
7/17/2022
18
19
20
21
22
23
24
25
26
27
28
29
FALSE
7/18/2022
19
20
21
22
23
24
25
26
27
28
29
30
TRUE
20
7/19/2022
20
21
22
23
24
25
26
27
28
29
30
31
FALSE
7/20/2022
21
22
23
24
25
26
27
28
29
30
31
32
TRUE
22
You appeared to be attempting to use a trigger. However, you did not specify a trigger and there were no triggers defined in your spreadsheet. So I went without triggers.
An onEdit Version:
function onEdit(e) {
const sh = e.range.getSheet();
const incl = ['Alpha', 'Sheet2', 'Sheet3'];//Add the desired sheet names
const idx = incl.indexOf(sh.getName())
if (~idx && e.range.columnStart == 14 && e.range.rowStart > 2 && e.value == "TRUE") {
const dt = new Date();
const dtv = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
let d = new Date(sh.getRange(e.range.rowStart, 1).getValue());
let dv = new Date(d.getFullYear(), d.getMonth(), d.getDate());
e.range.offset(0, 1).setValue(DiffInDays(dtv, dv));
}
}
To insert timestamps in column O when the checkboxes in column N are ticked, use a timestamping script such as yetAnotherTimestamp_ with these parameters:
// [START modifiable parameters]
{
sheetName: /^(Alpha|Beta|Charlie|Delta)$/i,
watchColumn: ['N'],
stampColumn: ['O'],
watchRowStart: 3,
watchRowEnd: +Infinity,
timestampFormat: 'yyyy-MM-dd',
overwriteTimestamp: true,
eraseTimestampOnDelete: true,
},
// [END modifiable parameters]
Then put this formula in cell P2:
=arrayformula(
{
"Days Elapsed";
if( N3:N = "Yes", O3:O - A3:A, iferror(1/0) )
}
)
The formula will give the number of days between the timestamp and the form submission in the rows where a checkbox is ticked.
Related
I am trying to sort specific columns on a google sheet but exluding a few different tabs. I use google scripts a decent amount in my job but most of the scripts I get from Stack and then edit them because I am not a developer/engineer, I'm in a non-tech role but I know a slight amount about coding.
Can someone that knows coding tell me what I am doing wrong?
I know there is a more efficient way to do the naming conventions of the columns and the ascending and I will change that later but wanted to see if anyone knows why I am getting this error? Thanks!
I found this code from a Stack post that I changed that I feel like should work but I keep getting this error on my trigger which is "onEdit":
"Error: The coordinates of the range are outside the dimensions of the sheet."
function sortEverySheetTest() {
var excludeSheetNames = ["Sheet 1","Sheet 2","Sheet 3", "Sheet 4", "Sheet 5", "Sheet 6", "Sheet 7", "Sheet 8"]; // <--- Added
var sortFirst = 5;
var sortFirstAsc = true;
var sortSecond = 6;
var sortSecondAsc = true;
var sortThird = 7;
var sortThirdAsc = true;
var headerRows = 2;
var activeSheet = SpreadsheetApp.getActiveSheet();
var sheetName = activeSheet.getSheetName();
if (excludeSheetNames.includes(sheetName)) return; // <--- Added
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
var range = sheet.getRange(headerRows+1, 1, sheet.getMaxRows()-headerRows, sheet.getLastColumn());
range.sort([{ column: sortFirst, ascending: sortFirstAsc }, { column: sortSecond, ascending: sortSecondAsc }, { column: sortThird, ascending: sortThirdAsc }]);
}
Try this:
function onMyEdit(e) {
e.source.toast("Entry");
const excl = ["Sheet 1","Sheet 2","Sheet 3", "Sheet 4", "Sheet 5", "Sheet 6", "Sheet 7", "Sheet 8"];
const sh = e.range.getSheet();
const shts = e.source.getSheets().filter(sh => !~excl.indexOf(sh.getName())).map(sh => sh.getName());
const idx = shts.indexOf(sh.getName());
if(~idx) {
e.source.toast("Gate1");
let rg = sh.getRange(3,1,sh.getLastRow() - 2,sh.getLastColumn());
rg.sort([{column:5,ascending:true},{column:6,ascending:true},{column:7,ascending:true}]);
}
}
Here's the markdown table for my sheet data after sorting:
A
B
C
D
E
F
G
H
I
J
2
COL1
COL2
COL3
COL4
COL5
COL6
COL7
COL8
COL9
COL10
3
10
17
6
7
0
6
14
14
6
0
4
2
4
33
19
0
16
0
0
19
14
5
3
18
16
5
2
7
9
5
16
19
6
16
0
12
3
3
4
13
19
17
12
7
14
2
19
4
6
14
2
16
12
8
8
10
5
5
13
10
3
8
2
15
15
9
14
5
16
9
10
13
0
17
16
7
10
4
9
8
4
10
13
10
17
19
0
11
0
9
8
7
11
0
15
4
14
19
12
17
12
2
9
12
4
13
5
11
17
13
14
4
0
5
14
5
1
5
17
2
14
5
5
18
19
14
9
0
5
9
2
15
15
5
13
15
16
2
7
1
14
19
16
10
15
18
17
16
13
16
13
10
11
17
9
12
1
3
17
3
5
1
2
9
18
12
5
16
10
17
5
1
8
14
9
19
16
2
99
2
17
8
11
2
2
14
20
19
13
16
13
17
16
11
10
14
15
21
2
18
9
10
18
3
16
1
17
19
22
2
7
12
6
18
9
3
6
13
18
I'm trying to sort columns from left to right based on dates, here is an example of the issue that I'm facing:
https://docs.google.com/spreadsheets/d/1CuDW-VRZxrwXXjyBj4BeUleMFqL8DUQrW3sku6WjMh0/edit?usp=sharing
I'm sorting from column E to N based on the dates in row 6. The script that I'm currently using works okay as far as cell E6 has a date and there is no empty columns in between the full ones, otherwise the script won't work.
Here's the script that I'm using:
function sortLToR() {
//Defining the spreadsheet variables and setting ranges
var sheet = SpreadsheetApp.getActive().getSheetByName("Sort");
var range3 = sheet.getRange(5, 5, 88,sheet.getLastColumn()-4)
var range = sheet.getRange(5, 5, 88,sheet.getLastColumn()-4).getValues();
Logger.log(sheet.getLastColumn())
//Defining a blank array that can hold the result
var trans = [];
//transpose the data stored in range variable
for(var column = 0; column < range[0].length; column++){
trans[column] = [];
for(var row = 0; row < range.length; row++){
trans[column][row] = range[row][column];
}
}
function sortByDate(a, b) {
return new Date(b[1]).getTime() - new Date(a[1]).getTime();
}
var range2 = trans.sort(sortByDate);
var trans2 = [];
//transpose the data stored in range variable
for(var column = 0; column < range2[0].length; column++){
trans2[column] = [];
for(var row = 0; row < range2.length; row++){
trans2[column][row] = range2[row][column];
}
}
range3.setValues(trans2);
}
Any ideas how to fix this?
Thanks
Sort Columns by date and move blank columns to right so that data always starts in Column E
This version puts the blank columns to the right and always starts at E
function sortLToR() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const rg = sh.getRange(5, 5, sh.getLastRow() -4, sh.getLastColumn() - 4)
const vs = rg.getValues();
let b = transpose(vs);
b.sort((a,b) => {
if(a[1] && b[1]) {
return new Date(a[1]).valueOf() - new Date(b[1]).valueOf();
} else if(a[1] && !b[1]){
return -1;
} else if(!a[1] && b[1]) {
return +1
}
});
let c = transpose(b)
rg.setValues(c);
}
Demo:
Before Sort:
A
B
C
D
E
F
G
H
I
J
K
L
M
N
COL2
COL3
COL4
COL5
COL6
COL7
COL8
COL9
COL10
5/19/2022
5/18/2022
5/17/2022
5/16/2022
5/15/2022
5/14/2022
5/13/2022
5/12/2022
5/11/2022
3
4
5
6
7
8
9
10
11
4
5
6
7
8
9
10
11
12
5
6
7
8
9
10
11
12
13
6
7
8
9
10
11
12
13
14
7
8
9
10
11
12
13
14
15
8
9
10
11
12
13
14
15
16
9
10
11
12
13
14
15
16
17
10
11
12
13
14
15
16
17
18
11
12
13
14
15
16
17
18
19
12
13
14
15
16
17
18
19
20
13
14
15
16
17
18
19
20
21
14
15
16
17
18
19
20
21
22
15
16
17
18
19
20
21
22
23
16
17
18
19
20
21
22
23
24
17
18
19
20
21
22
23
24
25
18
19
20
21
22
23
24
25
26
19
20
21
22
23
24
25
26
27
20
21
22
23
24
25
26
27
28
21
22
23
24
25
26
27
28
29
After Sort:
A
B
C
D
E
F
G
H
I
J
K
L
M
N
COL10
COL9
COL8
COL7
COL6
COL5
COL4
COL3
COL2
5/11/2022
5/12/2022
5/13/2022
5/14/2022
5/15/2022
5/16/2022
5/17/2022
5/18/2022
5/19/2022
11
10
9
8
7
6
5
4
3
12
11
10
9
8
7
6
5
4
13
12
11
10
9
8
7
6
5
14
13
12
11
10
9
8
7
6
15
14
13
12
11
10
9
8
7
16
15
14
13
12
11
10
9
8
17
16
15
14
13
12
11
10
9
18
17
16
15
14
13
12
11
10
19
18
17
16
15
14
13
12
11
20
19
18
17
16
15
14
13
12
21
20
19
18
17
16
15
14
13
22
21
20
19
18
17
16
15
14
23
22
21
20
19
18
17
16
15
24
23
22
21
20
19
18
17
16
25
24
23
22
21
20
19
18
17
26
25
24
23
22
21
20
19
18
27
26
25
24
23
22
21
20
19
28
27
26
25
24
23
22
21
20
29
28
27
26
25
24
23
22
21
I'm not sure if this is a viable solution, but you could just add another sheet or use a range in columns to the right, I think you could accomplish what you want.
=transpose(sort(TRANSPOSE(filter(F:N,F:F<>"")),6,true))
See example here of before and after.
Updated to account for potential breaks in data:
=transpose(sort(TRANSPOSE(filter(Before!E:N,Row(Before!E:E)<=max(arrayformula(--NOt(ISBLANK(Before!E:N))*row(Before!E:N))))),6,true))
One could then leverage this formula in an appscript to overwrite the data with something like this:
function makeRange(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const yourSheetName = "Before"; //sheet name with data
const zFormula = "=transpose(sort(TRANSPOSE(filter('zzzzz'!E:N,Row('zzzzz'!E:E)<=max(arrayformula(--NOt(ISBLANK('zzzzz'!E:N))*row('zzzzz'!E:N))))),6,true))";//
var newSheet = ss.insertSheet();
var newFormula = zFormula.replace(/zzzzz/g,yourSheetName)
newSheet.getRange("E1").setFormula(newFormula);
var newValues = newSheet.getRange("E:N").getValues();
ss.getSheetByName(yourSheetName).getRange("E:N").setValues(newValues);
ss.deleteSheet(newSheet);
}
Trying to create a Google App Script for Sheets that will do the following:
Copy Date found in column C to column F
IF: Date in column C is <= C1.AND: E = "Yes"
For all rows in sheet range A6:F
Example sheet,
/
A
B
C
D
E
F
1
Mark received if before:
12/15/2021
2
3
4
5
INVOICE No
CUS No
Invoice Date
JOBamount
PayAtService
Received date
6
1
3
12/10/2021
$15.00
Yes
7
2
1
12/6/2021
$15.00
Yes
8
3
21
12/14/2021
$45.00
Yes
9
4
20
12/14/2021
$15.00
Yes
10
5
13
12/15/2021
$12.00
No
11
6
14
12/15/2021
$10.00
No
12
7
12
12/15/2021
$12.00
No
13
9
9
12/15/2021
$30.00
No
14
10
1
12/15/2021
$15.00
Yes
15
11
18
12/15/2021
$12.00
No
16
12
17
12/15/2021
$25.00
No
17
13
15
12/15/2021
$12.00
Yes
18
14
16
12/15/2021
$20.00
No
19
15
19
12/15/2021
$30.00
Yes
20
16
4
12/16/2021
$15.00
No
21
17
5
12/16/2021
$7.00
Yes
22
18
6
12/16/2021
$5.00
Yes
23
19
7
12/16/2021
$7.00
No
24
20
8
12/16/2021
$6.00
Yes
25
21
10
12/20/2021
$15.00
No
26
22
23
12/20/2021
$30.00
Yes
27
23
13
12/29/2021
$12.00
Yes
28
24
12
12/29/2021
$12.00
Yes
29
26
9
12/29/2021
$30.00
Yes
30
27
15
12/29/2021
$12.00
Yes
31
28
16
12/29/2021
$20.00
No
32
29
23
12/29/2021
$30.00
No
(This seems like it would be simple but haven't quite figured out how)
I tried something like this but I think I am limiting my range (want to all rows in sheet to be in range) and it is also simply full of errors...
function ReceivedDate() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('sheet1');
var vs = sh.getRange(6, 1, 500, 6).getValues() //getRange(row, column, numRows, numColumns) but this needs to be whole sheet from row 6 down
var cutoffDate = new Date(sh.getRange('F2').getValue());
vs.forEach(row => {
if (row[5] != 'Yes' && new Date(row[3]).valueOf() <= cutoffDate)
vs(row, 6).setValue(row, 3);
}
}
Try this.
function ReceivedDate() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('sheet1');
var vs = sh.getRange(6, 1, 500, 6).getValues() //getRange(row, column, numRows, numColumns) but this needs to be whole sheet from row 6 down
var cutoffDate = new Date(sh.getRange('C1').getValue());
vs.forEach((row,index)=> {
if (row[4] == 'Yes' && new Date(row[2]) <= cutoffDate){
sh.getRange(index+6,6).setValue(row[2]);
}
})
}
I do not know if you want a solution in AppScript or just a solution. But for your requirement above, a simple formula as below should work.
=IF(AND(DATEVALUE(C6) <= DATEVALUE($C$1), E6 = "Yes"),C6,"")
I need to import a csv attachment from my email to a google sheet. I found a script online that seemed like what I needed and when I click 'run' it shows execution completed, but my google sheet is still blank.
I would prefer the code was able to append the data, but if not that's okay as well.
Here's the script I currently have and links to the sheet with current data, email example, report example
function importCSVFromGmail() {
var threads = GmailApp.search("from:MY EMAIL");
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
attachment.setContentTypeFromExtension();
if (attachment.getContentType() === "CSV") {
var sheet = SpreadsheetApp.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
Import attachment to google sheet
I have only one message that has an attachment
function myfunk() {
let ts = GmailApp.getInboxThreads();
ts.forEach(t => {
let msgs = t.getMessages();
msgs.forEach(m => {
if(m.getAttachments().length > 0) {
let csv = m.getAttachments()[0].getDataAsString();
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
const vs = Utilities.parseCsv(csv);
sh.getRange(1,1,vs.length,vs[0].length).setValues(vs);
}
})
})
}
The original file:
COL1,COL2,COL3,COL4,COL5,COL6,COL7,COL8,COL9,COL10
1,23,31,14,24,27,12,9,33,18
7,19,23,20,16,33,25,18,12,21
16,11,19,35,14,30,4,14,31,15
33,25,9,29,23,1,26,34,1,14
32,19,20,6,34,20,12,3,7,15
29,31,12,33,33,24,36,20,35,23
13,2,9,39,6,23,5,37,30,38
36,5,10,1,32,24,19,6,28,12
38,39,6,15,30,4,3,13,26,37
Sheet1:
COL1
COL2
COL3
COL4
COL5
COL6
COL7
COL8
COL9
COL10
1
23
31
14
24
27
12
9
33
18
7
19
23
20
16
33
25
18
12
21
16
11
19
35
14
30
4
14
31
15
33
25
9
29
23
1
26
34
1
14
32
19
20
6
34
20
12
3
7
15
29
31
12
33
33
24
36
20
35
23
13
2
9
39
6
23
5
37
30
38
36
5
10
1
32
24
19
6
28
12
38
39
6
15
30
4
3
13
26
37
I have this globalVariables function with a variable array:
function globalVariables(){
var varArray = {
spreadsheetId : 'MY_SPREADSHEET_ID',
dataRange : 'Air Database!A2:P', // Where I want to include another range
idRange : 'Air Database!B2:B',
lastCol : 'S',
insertRange : 'Air Database!A1:P1',
sheetID : 'MY_SHEET_ID_#'
};
return varArray;
}
On dataRange above, I want to skip columns D & E. I want it to be something like:
dataRange : 'Air Database!A2:C,F2:P',
I've tried what I wrote above but it returned blank (even the A2:C didn't show up). I've also tried the ones I listed below and all of them returned the same thing (blank). aws is my sheet
dataRange : 'Air Database!A2:C' & 'Air Database!F2:P',
dataRange : 'Air Database!A2:C&F2:P',
dataRange : 'Air Database!A2:C && F2:P',
dataRange : 'Air Database!A2:C','Air Database!F2:P',
dataRange : ['Air Database!A2:C','Air Database!F2:P'],
dataRange : aws.getRangeList(['A2:C', 'F2:P']),
dataRange : [aws.getRange('A2:C'), aws.getRange('F2:P')],
UPDATE: No need to answer the question since I already just worked around the problem. If in case you do have tips for other people with the same problem, feel free to answer. Thank you!
My Sheet0:
COL1
COL2
COL3
COL4
COL5
COL6
COL7
COL8
COL9
COL10
7
8
4
15
14
14
9
16
17
2
10
17
0
11
10
5
6
17
10
16
8
4
12
0
16
17
2
16
15
0
14
13
17
12
5
2
13
9
11
14
0
4
15
4
9
3
14
8
16
1
6
3
19
17
14
8
19
0
0
1
18
9
2
6
7
16
13
13
8
0
12
9
9
15
17
12
1
1
18
14
8
4
18
1
15
18
2
16
17
3
19
3
12
0
18
2
4
3
13
7
6
5
3
5
6
17
11
13
6
19
1
9
3
2
9
2
12
8
10
14
19
14
6
18
2
17
13
2
4
18
11
16
2
14
2
17
17
13
5
9
10
10
12
1
6
3
6
4
12
11
3
10
16
14
13
17
2
9
15
13
10
7
0
15
13
3
13
19
17
10
18
8
14
9
9
8
12
18
12
8
15
17
7
17
4
3
18
1
7
6
11
3
3
12
0
19
4
7
1
0
Rangelist Code:
function myfunc() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const rgl = sh.getRangeList(['Sheet0!A2:C', 'E1:J']);
rgl.getRanges().forEach(r => {
let arr = r.getValues().filter(r => r[0]);
Logger.log('Range: ' + r.getA1Notation())
Logger.log(JSON.stringify(arr));
});
}
Execution log
11:27:09 AM Notice Execution started
11:27:10 AM Info Range: A2:C
11:27:10 AM Info [[7,8,4],[10,17,0],[8,4,12],[14,13,17],[6,3,19],[18,9,2],[12,9,9],[8,4,18],[19,3,12],[6,5,3],[1,9,3],[19,14,6],[11,16,2],[10,10,12],[3,10,16],[10,7,0],[18,8,14],[15,17,7],[11,3,3]]
11:27:11 AM Info Range: E1:J
11:27:11 AM Info [["COL5","COL6","COL7","COL8","COL9","COL10"],[14,14,9,16,17,2],[10,5,6,17,10,16],[16,17,2,16,15,0],[5,2,13,9,11,14],[9,3,14,8,16,1],[14,8,19,0,0,1],[7,16,13,13,8,0],[17,12,1,1,18,14],[15,18,2,16,17,3],[18,2,4,3,13,7],[6,17,11,13,6,19],[9,2,12,8,10,14],[2,17,13,2,4,18],[2,17,17,13,5,9],[6,3,6,4,12,11],[13,17,2,9,15,13],[13,3,13,19,17,10],[9,8,12,18,12,8],[4,3,18,1,7,6]]
11:27:11 AM Notice Execution completed