Google App Script - Trouble Outputting and Parsing Data - json

I'm using a google app script to pull data in regards to our chrome book devices, all is working ok apart from when trying to interrogate the "cpuStatusReports"
If i use
cputemp = JSON.stringify(chromebooks[i].cpuStatusReports)
Logger.log(cputemp);
the output i get is this
[{"cpuUtilizationPercentageInfo":[23,16,12,18,15,12,18,15,20,16],"cpuTemperatureInfo":[{"temperature":43,"label":"soc_dts0\n"},{"temperature":43,"label":"soc_dts1\n"}],"reportTime":"2019-06-24T11:53:24.973Z"},{"cpuUtilizationPercentageInfo":[45],"cpuTemperatureInfo":[{"temperature":33,"label":"soc_dts0\n"},{"temperature":34,"label":"soc_dts1\n"}],"reportTime":"2019-06-25T12:43:40.826Z"},{"cpuUtilizationPercentageInfo":[12],"cpuTemperatureInfo":[{"temperature":42,"label":"soc_dts0\n"},{"temperature":42,"label":"soc_dts1\n"}],"reportTime":"2019-06-25T14:01:47.016Z"},{"cpuUtilizationPercentageInfo":[27],"cpuTemperatureInfo":[{"temperature":29,"label":"soc_dts0\n"},{"temperature":30,"label":"soc_dts1\n"}],"reportTime":"2019-06-26T07:59:40.739Z"},{"cpuUtilizationPercentageInfo":[12,12,7,8,3,4,14,13,27,12],"cpuTemperatureInfo":[{"temperature":45,"label":"soc_dts0\n"},{"temperature":46,"label":"soc_dts1\n"}],"reportTime":"2019-06-26T10:59:41.370Z"}]
How can i split this? in particular im after the "cpuTemperatureInfo" field?
If someone could provide a working example i can then use this for the Diskreport as well as this is also outputting in the same format.
Thankyou for your help!
UPDATE:
** Full code of function
function chromebookdetails2() {
var domain, chromebooks, page, ss, sheet, pageToken, i
var sheetData4 = onSheet.getSheetByName("chromebook")
//sheetData4.clear();
domain = "my domain here"
chromebooks= new Array()
do{
page = AdminDirectory.Chromeosdevices.list("my_customer",
{domain: domain,
maxResults: 1000,
pageToken: pageToken
})
for (i in page.chromeosdevices){
chromebooks.push(page.chromeosdevices[i])
}
pageToken = page.nextPageToken
}while(pageToken){
var row = 3 //starting row position
for (var i = 0; i < chromebooks.length; i++) {
var sheetData4 = onSheet.getSheetByName("chromebook")
/////////////////////Header////////////////////////////////////////
var date = Utilities.formatDate(new Date(), "GMT+1", "dd/MM/yyyy")
sheetData4.getRange(1,1).setValue("Date Ran - "+date); //(2,1 means 2nd row, 1st column)
sheetData4.getRange(2,1).setValue("orgUnitPath"); //(2,1 means 2nd row, 1st column)
sheetData4.getRange(2,2).setValue("annotatedUser");
sheetData4.getRange(2,3).setValue("annotatedLocation");
sheetData4.getRange(2,4).setValue("annotatedAssetId");
sheetData4.getRange(2,5).setValue("serialNumber");
sheetData4.getRange(2,6).setValue("lastEnrollmentTime");
sheetData4.getRange(2,7).setValue("deviceId");
sheetData4.getRange(2,8).setValue("bootMode");
sheetData4.getRange(2,9).setValue("recentUsers");
sheetData4.getRange(2,10).setValue("macAddress");
sheetData4.getRange(2,11).setValue("lastSync");
sheetData4.getRange(2,12).setValue("osVersion");
sheetData4.getRange(2,13).setValue("platformVersion");
sheetData4.getRange(2,14).setValue("activeTimeRanges");
sheetData4.getRange(2,15).setValue("model");
sheetData4.getRange(2,16).setValue("etag");
sheetData4.getRange(2,17).setValue("firmwareVersion");
sheetData4.getRange(2,18).setValue("status");
sheetData4.getRange(2,19).setValue("ethernetMacAddress");
sheetData4.getRange(2,20).setValue("notes");
sheetData4.getRange(2,21).setValue("systemRamTotal");
sheetData4.getRange(2,22).setValue("CPU");
if(chromebooks[i].length == 0){
// array is empty
Logger.log('empty');
} else {
//array not empty
Logger.log('not empty');
cputemp = JSON.stringify(chromebooks[i].cpuStatusReports)
Logger.log(cputemp);
/////////////////////Array Data///////////////////////////////////
sheetData4.getRange(row,1).setValue(chromebooks[i].orgUnitPath);
sheetData4.getRange(row,2).setValue(chromebooks[i].annotatedUser);
sheetData4.getRange(row,3).setValue(chromebooks[i].annotatedLocation);
sheetData4.getRange(row,4).setValue(chromebooks[i].annotatedAssetId);
sheetData4.getRange(row,5).setValue(chromebooks[i].serialNumber);
sheetData4.getRange(row,6).setValue(chromebooks[i].lastEnrollmentTime);
sheetData4.getRange(row,7).setValue(chromebooks[i].deviceId);
sheetData4.getRange(row,8).setValue(chromebooks[i].bootMode);
sheetData4.getRange(row,9).setValue(chromebooks[i].recentUsers);
sheetData4.getRange(row,10).setValue(chromebooks[i].macAddress);
sheetData4.getRange(row,11).setValue(chromebooks[i].lastSync);
sheetData4.getRange(row,12).setValue(chromebooks[i].osVersion);
sheetData4.getRange(row,13).setValue(chromebooks[i].platformVersion);
sheetData4.getRange(row,14).setValue(chromebooks[i].activeTimeRanges);
sheetData4.getRange(row,15).setValue(chromebooks[i].model);
sheetData4.getRange(row,16).setValue(chromebooks[i].etag);
sheetData4.getRange(row,17).setValue(chromebooks[i].firmwareVersion);
sheetData4.getRange(row,18).setValue(chromebooks[i].status);
sheetData4.getRange(row,19).setValue(chromebooks[i].ethernetMacAddress);
sheetData4.getRange(row,20).setValue(chromebooks[i].notes);
sheetData4.getRange(row,21).setValue(chromebooks[i].systemRamTotal / (1024*1024) /1024); // "/ (1024*1024)" converts bytes to Mb "/1024" then converts back to Gb
//sheetData4.getRange(row,22).setValue(placeholder for cpu temp results));
}
row++
Logger.log(row)
}
}
}

Try this:
cputemp =(chromebooks[i].cpuStatusReports).toString().split(",");
Logger.log(cputemp);
for (var j in cputemp)
{
var element = cputemp[j];
Logger.log(element);
}
You can see then which j has the entry you need

Related

How to fix "Service Documents failed while accessing document" while inserting a lot of data?

This is a follow-up question derivated from How to solve error when adding big number of tables
With the code below, I get the following message when, for 500 tables. BUt it works fine for 200 for example.
Exception: Service Documents failed while accessing document with id
The error happens on line 22, inside de if body = DocumentApp.getActiveDocument().getBody();
You also have the table template id to try, but here is an image
Image Table Template
function RequirementTemplate_Copy() {
var templatedoc = DocumentApp.openById("1oJt02MfOIQPFptdWCwDpj5j-zFdO_Wrq-I48mUq9I-w");
return templatedoc.getBody().getChild(1).copy()
}
function insertSpecification_withSection(){
// Retuns a Table Template Copied from another Document
reqTableItem = RequirementTemplate_Copy();
var body = DocumentApp.getActiveDocument().getBody();
// Creates X number of separated tables from the template
for (var i = 1; i < 501; i++){
table = reqTableItem.copy().replaceText("#Title#",String(i))
body.appendTable(table);
if((i % 100) === 0) {
DocumentApp.getActiveDocument().saveAndClose();
body = DocumentApp.getActiveDocument().getBody()
}
}
}
It looks that the error message isn't related to the number of tables to be inserted because it occurs before adding the tables.
Just wait a bit an try again. If the problem persist try your code using a different account if the code runs on the second account it's very possible that you first account exceeded a limit... there are some limits to prevent abuse that aren't published and that might change without any announcement.
Using the fix suggested for the code from my answer to the previous question and changing the number for iteration limit to 1000 and 2000 works fine
The following screenshot shows the result for 1000
Here is the code used for the tests
function insertSpecification_withSection(){
startTime = new Date()
console.log("Starting Function... ");
// Retuns a Table Template Copied from another Document
reqTableItem = RequirementTemplate_Copy();
var body = DocumentApp.getActiveDocument().getBody();
// Creates X number of separated tables from the template
for (var i = 0; i < 2000; i++){
table = body.appendTable(reqTableItem.copy());
// if((i % 100) === 0) {
// DocumentApp.getActiveDocument().saveAndClose();
// }
//
}
endTime = new Date();
timeDiff = endTime - startTime;
console.log("Ending Function..."+ timeDiff + " ms");
}
function RequirementTemplate_Copy() {
//---------------------------------------------------------------------------------------------------------------------------------------------------
var ReqTableID = PropertiesService.getDocumentProperties().getProperty('ReqTableID');
try{
var templatedoc = DocumentApp.openById(ReqTableID);
} catch (error) {
DocumentApp.getUi().alert("Could not find the document. Confirm it was not deleted and that anyone have read access with the link.");
//Logger.log("Document not accessible", ReqTableID)
}
var reqTableItem = templatedoc.getChild(1).copy();
//---------------------------------------------------------------------------------------------------------------------------------------------------
return reqTableItem
}
function setReqTableID(){
PropertiesService.getDocumentProperties().setProperty('ReqTableID', '1NS9nOb3qEBrqkcAQ3H83OhTJ4fxeySOQx7yM4vKSFu0')
}

Google APP script to convert value into TRUE for setting MultipleChoice answer key

I’ve searched a script that automates google form from my question banks (g-sheets).
All of my questions are multiple choice. I already added the setPoints() and setRequired(), however, for the answer key, I can’t find a way on how to script the value of my Answer’s column into TRUE when it meets the criteria. Below are the codes:
function getSpreadsheetData(sheetName) {
// This function gives you an array of objects modeling a worksheet's tabular data, where the first items — column headers — become the property names.
var arrayOfArrays = SpreadsheetApp.openById("GoogleSheetID").getSheetByName(sheetName || 'question').getDataRange().getValues();
console.log("Spreadsheet: " + arrayOfArrays[0]);
console.log("Spreadsheet: " + arrayOfArrays[1]);
var headers = arrayOfArrays.shift();
return arrayOfArrays.map(function (row) {
return row.reduce(function (memo, value, index) {
if (value) {
memo[headers[index]] = value;
}
return memo;
}, {});
});
}
function onOpen(e){
var form = FormApp.openById("GoogleFormID");
form.setTitle('DO ANY TITLE YOU WANT HERE');
form.setDescription('This is an example of Form generation');
getSpreadsheetData().forEach(function (row) {
var capitalizedName = row.Number.charAt(0).toUpperCase() + row.Number.slice(1);
console.log("Spreadsheet: " + capitalizedName);
form.addPageBreakItem()
.setTitle(capitalizedName);
var item = form.addMultipleChoiceItem();
item.setTitle(row.Questions)
.setPoints(1)
.setRequired(true)
.setChoices([
item.createChoice(row.Option1),
item.createChoice(row.Option2),
item.createChoice(row.Option3),
item.createChoice(row.Option4)
]);
});
}
function onSubmit(e) {
var form = FormApp.getActiveForm();
var items = form.getItems();
while(items.length > 0){
form.deleteItem(items.pop());
}
}
I’ve also search that to make choices the right answer, you just put TRUE or something like this:
item.createChoice(row.Option1, true),
item.createChoice(row.Option2, false),
item.createChoice(row.Option3, false),
item.createChoice(row.Option4, false)
However, this will only set Option1 as always the right answer. I want that TRUE or FALSE will be automatically place when found the right answer as stated in column G of my google sheets. Attach is my sheet:
GoogleSheet
This took me a while and I experience a weird issue, which is: After the Questions are set and the form saved, refreshing the page or trying to answer deletes all the options from one of the options (not always the same option).
I still have no clue why does this happen and I will investigate it later, but my code can give you an idea.
I changed your code a bit and added a new function which returns true or false for each option depending on the value of the G column:
form.addPageBreakItem()
.setTitle(capitalizedName);
var item = form.addMultipleChoiceItem();
item.setTitle(row.Questions)
.setPoints(1)
.setRequired(true)
.setChoices([
item.createChoice(row.Option1, checktrue(row, row.Option1)),
item.createChoice(row.Option2, checktrue(row, row.Option2)),
item.createChoice(row.Option3, checktrue(row, row.Option3)),
item.createChoice(row.Option4, checktrue(row, row.Option4))
]);
});
}
function checktrue(row, option){
var numRow = 2;
var sprsheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var colA = sprsheet.getRange("A2:A5").getValues();
for (var i = 0; i < colA.length; i++){
if (colA[i] == row.Number){
numRow += i;
}
}
var answer = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("G"+numRow).getValue();
if (option == answer){
return true
} else {
return false
}
}

Resolving "Limit Exceeded DriveApp" in Google Apps Script

The problem I'm running into is that I'm hitting a certain quota when processing my spread sheets. I process a bunch of spreadsheets each day and when I added in a new system that sends my google script more spreadsheets to process, I get the error:
Limit Exceeded DriveApp
The line that it ends on is always orderedCsv.getBlob().getDataAsString(); where orderedCsv is the current spreadsheet.
My questions are
1. Which quota could i be hitting?
2. How can I check my current quota usage?
I think it could be Properties read/write over exceeding since I import the original data which could be anywhere from 3000-9000 lines of data.
The error transcript it gives me is:
Error Transcript Pastebin
function ps_csvsToSheet ( currSheet, sheetCsvs, csvDict, sheetN, sheetOrderIndex){
// import csvs into the sheet with formatting
lib_formatSheet(currSheet);
var row = 39;
var orderedCsv;
// loop for importing CSVs into one sheet in the order we want~~~~~~
for (var i = 0; i < ps_statOrdering.length; i++) {
// loop through all the sheets stored in a dictionary we created before
for (var j = 0; j < sheetCsvs.length; j++) {
var sheetName = sheetCsvs[j].getName();
// additional test to ensure Draw chart and not DrawCall
if ( ps_statOrdering[i] == 'Draw') {
if ( sheetName.indexOf(ps_statOrdering[i]) !== -1 && sheetName.indexOf('DrawCalls') == -1) {
orderedCsv = sheetCsvs[j];
break;
}
} else if ( sheetName.indexOf(ps_statOrdering[i]) !== -1) {
orderedCsv = sheetCsvs[j];
break;
}
}
try{
// import the csvs for spreadsheet
var strData = orderedCsv.getBlob().getDataAsString(); //**********[Line it ends on]***********
var importedData = lib_importCSV(row+1, 1, strData, currSheet);
}
catch(error) {
Logger.log("Catch Error : " + error);
return
}
// make formatting [][] for the importedData. Here we are working off
// of pre-knowledge of what is expected
var nRows = importedData['rows'];
var nCols = importedData['cols'];
var c;
var weightArr = new Array(nRows);
var numFormatArr = new Array(nRows);
for (var r = 0; r < nRows; r++) {
weightArr[r] = new Array(nCols);
numFormatArr[r] = new Array(nCols);
if (r == 0) {
c = nCols;
while(c--) {
weightArr[r][c] = "bold";
numFormatArr[r][c] = '';
}
} else {
c = nCols;
while(c--) {
weightArr[r][c] = "normal";
numFormatArr[r][c] = '0.00';
}
weightArr[r][0] = "bold";
numFormatArr[r][0] = '';
if( sheetOrderIndex !== -1) {
numFormatArr[r][0] = 'MMM.dd';
}
}
}
importedData['range'].setFontWeights(weightArr)
.setNumberFormats(numFormatArr);
//Create the header of the sheet
lib_inputSheetHeader(currSheet, row, nCols, (sheetN + " " + ps_statOrdering[i]
+ " Averages"), ps_profileColors[0]) ;
// insert appropriate graph
var key = ps_statOrdering[i];
if( sheetOrderIndex !== -1) {
// this is a setting trend sheet, line chart
lib_makeLineChart(importedData['range'], ps_statLocDict[key][0], ps_statLocDict[key][1],
(sheetN + " " + ps_statOrdering[i] ), currSheet,
ps_statVRange[key][0], ps_statVRange[key][1], ps_statAxisDict[key]);
} else {
// this is a map sheet, bar chart
// debugPrint(importedData['range'].getValues().toString());
lib_makeBarChart(importedData['range'], ps_statLocDict[key][0], ps_statLocDict[key][1],
(sheetN + " " + ps_statOrdering[i] ), currSheet,
ps_statVRange[key][0], ps_statVRange[key][1], ps_statAxisDict[key]);
}
row += importedData['rows'] +2;
} // for loop close, import csv ~~~~
sleep(1000);
SpreadsheetApp.flush();
}
So what i did was i off loaded a lot of calculations to python with pandas. That way I could import a data sheet that is already pre formatted and run a couple of operations on it in google to save execution time.
The code i used to make this work is a bit large, because of specific data operation i had to do. Here is a quick summary of the code done in python:
import pandas as pd
import numpy as np #used in case of needing np.NAN in our data
class DataProcessing():
def __init__(self):
rawData = pd.DataFrame.from_csv( **<enter path to csv>** )
#From here i would run operations on the dataframe named rawdata
#until the data frame matched what i needed it to look like.
#PyCharm is a python IDE that can help you visualize the data frame
#through break points.
#After im done modifying my dataframe i sent it to my google drive.
#If you download google drive to your PC you can send it to a folder
#in your PC that will auto sync files to your google drive.
rawData.to_csv(os.path.join(**<GoogleFolder Path>**, csvName))
Learning pandas is a little tricky at the start but here is a resource that helped me modify my data right.
https://github.com/pandas-dev/pandas/blob/master/doc/cheatsheet/Pandas_Cheat_Sheet.pdf
Help this helps!

Can Google apps script be used to randomize page order on Google forms?

Update #2: Okay, I'm pretty sure my error in update #1 was because of indexing out of bounds over the array (I'm still not used to JS indexing at 0). But here is the new problem... if I write out the different combinations of the loop manually, setting the page index to 1 in moveItem() like so:
newForm.moveItem(itemsArray[0][0], 1);
newForm.moveItem(itemsArray[0][1], 1);
newForm.moveItem(itemsArray[0][2], 1);
newForm.moveItem(itemsArray[1][0], 1);
newForm.moveItem(itemsArray[1][1], 1);
newForm.moveItem(itemsArray[1][2], 1);
newForm.moveItem(itemsArray[2][0], 1);
...
...I don't get any errors but the items end up on different pages! What is going on?
Update #1:: Using Sandy Good's answer as well as a script I found at this WordPress blog, I have managed to get closer to what I needed. I believe Sandy Good misinterpreted what I wanted to do because I wasn't specific enough in my question.
I would like to:
Get all items from a page (section header, images, question etc)
Put them into an array
Do this for all pages, adding these arrays to an array (i.e: [[all items from page 1][all items from page 2][all items from page 3]...])
Shuffle the elements of this array
Repopulate a new form with each element of this array. In this way, page order will be randomized.
My JavaScript skills are poor (this is the first time I've used it). There is a step that produces null entries and I don't know why... I had to remove them manually. I am not able to complete step 5 as I get the following error:
Cannot convert Item,Item,Item to (class).
"Item,Item,Item" is the array element containing all the items from a particular page. So it seems that I can't add three items to a page at a time? Or is something else going on here?
Here is my code:
function shuffleForms() {
var itemsArray,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,shuffle, sections;
// Copy template form by ID, set a new name
newFormFile = DriveApp.getFileById('1prfcl-RhaD4gn0b2oP4sbcKaRcZT5XoCAQCbLm1PR7I')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
// Get ID of new form and open it
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
// Initialize array to put IDs in
itemsArray = [];
function getPageItems(thisPageNum) {
Logger.log("Getting items for page number: " + thisPageNum );
var thisPageItems = []; // Used for result
var thisPageBreakIndex = getPageItem(thisPageNum).getIndex();
Logger.log( "This is index num : " + thisPageBreakIndex );
// Get all items from page
var allItems = newForm.getItems();
thisPageItems.push(allItems[thisPageBreakIndex]);
Logger.log( "Added pagebreak item: " + allItems[thisPageBreakIndex].getIndex() );
for( var i = thisPageBreakIndex+1; ( i < allItems.length ) && ( allItems[i].getType() != FormApp.ItemType.PAGE_BREAK ); ++i ) {
thisPageItems.push(allItems[i]);
Logger.log( "Added non-pagebreak item: " + allItems[i].getIndex() );
}
return thisPageItems;
}
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
Logger.log('shuffle ran')
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function shuffleAndMove() {
// Get page items for all pages into an array
for(i = 2; i <= 5; i++) {
itemsArray[i] = getPageItems(i);
}
// Removes null values from array
itemsArray = itemsArray.filter(function(x){return x});
// Shuffle page items
itemsArray = shuffle(itemsArray);
// Move page items to the new form
for(i = 2; i <= 5; ++i) {
newForm.moveItem(itemsArray[i], i);
}
}
shuffleAndMove();
}
Original post: I have used Google forms to create a questionnaire. For my purposes, each question needs to be on a separate page but I need the pages to be randomized. A quick Google search shows this feature has not been added yet.
I see that the Form class in the Google apps script has a number of methods that alter/give access to various properties of Google Forms. Since I do not know Javascript and am not too familiar with Google apps/API I would like to know if what I am trying to do is even possible before diving in and figuring it all out.
If it is possible, I would appreciate any insight on what methods would be relevant for this task just to give me some direction to get started.
Based on comments from Sandy Good and two SE questions found here and here, this is the code I have so far:
// Script to shuffle question in a Google Form when the questions are in separate sections
function shuffleFormSections() {
getQuestionID();
createNewShuffledForm();
}
// Get question IDs
function getQuestionID() {
var form = FormApp.getActiveForm();
var items = form.getItems();
arrayID = [];
for (var i in items) {
arrayID[i] = items[i].getId();
}
// Logger.log(arrayID);
return(arrayID);
}
// Shuffle function
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i--) {
j = Math.floor(Math.random() * i);
x = a[i - 1];
a[i - 1] = a[j];
a[j] = x;
}
}
// Shuffle IDs and create new form with new question order
function createNewShuffledForm() {
shuffle(arrayID);
// Logger.log(arrayID);
var newForm = FormApp.create('Shuffled Form');
for (var i in arrayID) {
arrayID[i].getItemsbyId();
}
}
Try this. There's a few "constants" to be set at the top of the function, check the comments. Form file copying and opening borrowed from Sandy Good's answer, thanks!
// This is the function to run, all the others here are helper functions
// You'll need to set your source file id and your destination file name in the
// constants at the top of this function here.
// It appears that the "Title" page does not count as a page, so you don't need
// to include it in the PAGES_AT_BEGINNING_TO_NOT_SHUFFLE count.
function shuffleFormPages() {
// UPDATE THESE CONSTANTS AS NEEDED
var PAGES_AT_BEGINNING_TO_NOT_SHUFFLE = 2; // preserve X intro pages; shuffle everything after page X
var SOURCE_FILE_ID = 'YOUR_SOURCE_FILE_ID_HERE';
var DESTINATION_FILE_NAME = 'YOUR_DESTINATION_FILE_NAME_HERE';
// Copy template form by ID, set a new name
var newFormFile = DriveApp.getFileById(SOURCE_FILE_ID).makeCopy();
newFormFile.setName(DESTINATION_FILE_NAME);
// Open the duplicated form file as a form
var newForm = FormApp.openById(newFormFile.getId());
var pages = extractPages(newForm);
shuffleEndOfPages(pages, PAGES_AT_BEGINNING_TO_NOT_SHUFFLE);
var shuffledFormItems = flatten(pages);
setFormItems(newForm, shuffledFormItems);
}
// Builds an array of "page" arrays. Each page array starts with a page break
// and continues until the next page break.
function extractPages(form) {
var formItems = form.getItems();
var currentPage = [];
var allPages = [];
formItems.forEach(function(item) {
if (item.getType() == FormApp.ItemType.PAGE_BREAK && currentPage.length > 0) {
// found a page break (and it isn't the first one)
allPages.push(currentPage); // push what we've built for this page onto the output array
currentPage = [item]; // reset the current page to just this most recent item
} else {
currentPage.push(item);
}
});
// We've got the last page dangling, so add it
allPages.push(currentPage);
return allPages;
};
// startIndex is the array index to start shuffling from. E.g. to start
// shuffling on page 5, startIndex should be 4. startIndex could also be thought
// of as the number of pages to keep unshuffled.
// This function has no return value, it just mutates pages
function shuffleEndOfPages(pages, startIndex) {
var currentIndex = pages.length;
// While there remain elements to shuffle...
while (currentIndex > startIndex) {
// Pick an element between startIndex and currentIndex (inclusive)
var randomIndex = Math.floor(Math.random() * (currentIndex - startIndex)) + startIndex;
currentIndex -= 1;
// And swap it with the current element.
var temporaryValue = pages[currentIndex];
pages[currentIndex] = pages[randomIndex];
pages[randomIndex] = temporaryValue;
}
};
// Sourced from elsewhere on SO:
// https://stackoverflow.com/a/15030117/4280232
function flatten(array) {
return array.reduce(
function (flattenedArray, toFlatten) {
return flattenedArray.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
},
[]
);
};
// No safety checks around items being the same as the form length or whatever.
// This mutates form.
function setFormItems(form, items) {
items.forEach(function(item, index) {
form.moveItem(item, index);
});
};
I tested this code. It created a new Form, and then shuffled the questions in the new Form. It excludes page breaks, images and section headers. You need to provide a source file ID for the original template Form. This function has 3 inner sub-functions. The inner functions are at the top, and they are called at the bottom of the outer function. The arrayOfIDs variable does not need to be returned or passed to another function because it is available in the outer scope.
function shuffleFormSections() {
var arrayOfIDs,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,items,shuffle;
newFormFile = DriveApp.getFileById('Put the source file ID here')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
arrayOfIDs = [];
fncGetQuestionID = function() {
var i,L,thisID,thisItem,thisType;
items = newForm.getItems();
L = items.length;
for (i=0;i<L;i++) {
thisItem = items[i];
thisType = thisItem.getType();
if (thisType === FormApp.ItemType.PAGE_BREAK ||
thisType === FormApp.ItemType.SECTION_HEADER ||
thisType === FormApp.ItemType.IMAGE) {
continue;
}
thisID = thisItem.getId();
arrayOfIDs.push(thisID);
}
Logger.log('arrayOfIDs: ' + arrayOfIDs);
//the array arrayOfIDs does not need to be returned since it is available
//in the outermost scope
}// End of fncGetQuestionID function
shuffle = function() {// Shuffle function
var j, x, i;
Logger.log('shuffle ran')
for (i = arrayOfIDs.length; i; i--) {
j = Math.floor(Math.random() * i);
Logger.log('j: ' + j)
x = arrayOfIDs[i - 1];
Logger.log('x: ' + x)
arrayOfIDs[i - 1] = arrayOfIDs[j];
arrayOfIDs[j] = x;
}
Logger.log('arrayOfIDs: ' + arrayOfIDs)
}
shuffleQuestionsInNewForm = function() {
var i,L,thisID,thisItem,thisQuestion,questionType;
L = arrayOfIDs.length;
for (i=0;i<L;i++) {
thisID = arrayOfIDs[i];
Logger.log('thisID: ' + thisID)
thisItem = newForm.getItemById(thisID);
newForm.moveItem(thisItem, i)
}
}
fncGetQuestionID();//Get all the question ID's and put them into an array
shuffle();
shuffleQuestionsInNewForm();
}

find the length of a string in google script

I'm trying to make a script for google sheet, who can count a letter in a text. But it seems that .length doesn't work. Anyone who can give directions on where to find the the solution.
function Tjekkode(tekst , bogstav){
var test = "";
// find the length of laengdeTekst
var laengdeTekst = tekst.length;
var t = 0;
// through the text character by character
for ( var i = 1; i<laengdeTekst ; i++) {
var test = tekst.substr(i,1);
if (test == bogstav) {
// if the letter is found, it is counted up
// REMEMBER == means compare
var t = t + 1;
}
}
// returns percent appearance of the letter
Return = t / længdeTekst * 100
}
Thanks in advance
length is ok in your code. To test it, run this script:
function test( ) {
var test = "123456";
// finder længden på teksten
var laengdeTekst = test.length;
Logger.log(laengdeTekst);
}
After you run it, check Log, press [Ctrl + Enter]
The correct code in your case:
function Tjekkode(tekst, bogstav) {
var test = "";
var laengdeTekst = tekst.length;
var t = 0;
// start looping from zero!
for ( var i = 0; i<laengdeTekst; i++) {
var test = tekst.substr(i,1);
if (test == bogstav) {
var t = t + 1;
}
}
// JavaScript is case sensitive: 'return != Return'
return t / laengdeTekst * 100;
}
Please, look at this tutorial for more info
thanks
I'll guess that I might get the one with the R instead of r at the end, but the script didn't run that line, because it kinda stopped at the .length line :/
the comments in danish is for my pupils (I'm a teacher in elementary school)
I'll see if google wants to cooperate today :|
This is the google script that worked for me. Note the 24 - that's the length of an empty message that has markup like <div>...</div>
function TrashEmptyDrafts() {
var thread = GmailApp.getDraftMessages();
for (var i = 0; i < thread.length; i++) {
b=thread[i].getBody();
if (b.length <= 24.0){
thread[i].moveToTrash();
}
}}