Related
I have a relatively basic set of code here that is programmed to roll 3 dice and give me the results whenever I type "/roll" in discord.
However, the results displayed on my command terminal are always different from those in the discord message from the bot.
async execute(interaction)
{
var num = 3;
num = Number(num);
function rollingDice(num) {
// make the dice rolling "num" times.
// return the results.
var diceResults = "";
for (var i = 0; i < num; i++) {
var resultOfEachDice = "";
resultOfEachDice = Math.floor((Math.random() * 6) + 1);
diceResults += resultOfEachDice + ", ";
}
var lastComma = diceResults.lastIndexOf(", ");
diceResults = diceResults.slice(0, lastComma);
return diceResults;
}
var diceResults = rollingDice()
console.log("Rolled " + num + " dice: " + rollingDice(num));
console.log(process.argv);
await interaction.reply('You rolled: ' + rollingDice(num));
So I will type /roll and my terminal will say I rolled "3, 5, 2" while the message would have something entirely different like "1, 6, 4".
This happens every time I run the command and I am not sure what the issue is.
GAS is quite powerful and you could write a full fledged web-app using a Google Sheet as the DB back-end. There are many reasons not to do this but I figure in some cases it is okay.
I think the biggest issue will be performance issues when looking for rows based on some criteria in a sheet with a lot of rows. I know there are many ways to "query" a sheet but I can't find reliable information on which is the fastest.
One of the complexities is that many people can edit a sheet which means there are a variable number of situations you'd have to account for. For the sake of simplicity, I want to assume the sheet:
Is locked down so only one person can see it
The first column has the row number (=row())
The most basic query is finding a row where a specific column equals some value.
Which method would be the fastest?
I have a sheet with ~19k rows and ~38 columns, filled with all sorts of unsorted real-world data. That is almost 700k rows so I figured it would be a good sheet to time a few methods and see which is the fastest.
method 1: get sheet as a 2D array then go through each row
method 2: get sheet as a 2D array, sort it, then using a binary search algorithm to find the row
method 3: make a UrlFetch call to Google visualization query and don't provide last row
method 4: make a UrlFetch call to Google visualization query and provide last row
Here are the my query functions.
function method1(spreadsheetID, sheetName, columnIndex, query)
{
// get the sheet values excluding header,
var rowValues = SpreadsheetApp.openById(spreadsheetID).getSheetByName(sheetName).getSheetValues(2, 1, -1, -1);
// loop through each row
for(var i = 0, numRows = rowValues.length; i < numRows; ++i)
{
// return it if found
if(rowValues[i][columnIndex] == query) return rowValues[i]
}
return false;
}
function method2(spreadsheetID, sheetName, columnIndex, query)
{
// get the sheet values excluding header
var rowValues = SpreadsheetApp.openById(spreadsheetID).getSheetByName(sheetName).getSheetValues(2, 1, -1, -1);
// sort it
rowValues.sort(function(a, b){
if(a[columnIndex] < b[columnIndex]) return -1;
if(a[columnIndex] > b[columnIndex]) return 1;
return 0;
});
// search using binary search
var foundRow = matrixBinarySearch(rowValues, columnIndex, query, 0, rowValues.length - 1);
// return if found
if(foundRow != -1)
{
return rowValues[foundRow];
}
return false;
}
function method3(spreadsheetID, sheetName, queryColumnLetterStart, queryColumnLetterEnd, queryColumnLetterSearch, query)
{
// SQL like query
myQuery = "SELECT * WHERE " + queryColumnLetterSearch + " = '" + query + "'";
// the query URL
// don't provide last row in range selection
var qvizURL = 'https://docs.google.com/spreadsheets/d/' + spreadsheetID + '/gviz/tq?tqx=out:json&headers=1&sheet=' + sheetName + '&range=' + queryColumnLetterStart + ":" + queryColumnLetterEnd + '&tq=' + encodeURIComponent(myQuery);
// fetch the data
var ret = UrlFetchApp.fetch(qvizURL, {headers: {Authorization: 'Bearer ' + ScriptApp.getOAuthToken()}}).getContentText();
// remove some crap from the return string
return JSON.parse(ret.replace("/*O_o*/", "").replace("google.visualization.Query.setResponse(", "").slice(0, -2));
}
function method4(spreadsheetID, sheetName, queryColumnLetterStart, queryColumnLetterEnd, queryColumnLetterSearch, query)
{
// find the last row in the sheet
var lastRow = SpreadsheetApp.openById(spreadsheetID).getSheetByName(sheetName).getLastRow();
// SQL like query
myQuery = "SELECT * WHERE " + queryColumnLetterSearch + " = '" + query + "'";
// the query URL
var qvizURL = 'https://docs.google.com/spreadsheets/d/' + spreadsheetID + '/gviz/tq?tqx=out:json&headers=1&sheet=' + sheetName + '&range=' + queryColumnLetterStart + "1:" + queryColumnLetterEnd + lastRow + '&tq=' + encodeURIComponent(myQuery);
// fetch the data
var ret = UrlFetchApp.fetch(qvizURL, {headers: {Authorization: 'Bearer ' + ScriptApp.getOAuthToken()}}).getContentText();
// remove some crap from the return string
return JSON.parse(ret.replace("/*O_o*/", "").replace("google.visualization.Query.setResponse(", "").slice(0, -2));
}
My binary search algorithm:
function matrixBinarySearch(matrix, columnIndex, query, firstIndex, lastIndex)
{
// find the value using binary search
// https://www.w3resource.com/javascript-exercises/javascript-array-exercise-18.php
// first make sure the query string is valid
// if it is less than the smallest value
// or larger than the largest value
// it is not valid
if(query < matrix[firstIndex][columnIndex] || query > matrix[lastIndex][columnIndex]) return -1;
// if its the first row
if(query == matrix[firstIndex][columnIndex]) return firstIndex;
// if its the last row
if(query == matrix[lastIndex][columnIndex]) return lastIndex;
// now start doing binary search
var middleIndex = Math.floor((lastIndex + firstIndex)/2);
while(matrix[middleIndex][columnIndex] != query && firstIndex < lastIndex)
{
if(query < matrix[middleIndex][columnIndex])
{
lastIndex = middleIndex - 1;
}
else if(query > matrix[middleIndex][columnIndex])
{
firstIndex = middleIndex + 1;
}
middleIndex = Math.floor((lastIndex + firstIndex)/2);
}
return matrix[middleIndex][columnIndex] == query ? middleIndex : -1;
}
This is the function I used to test them all:
// each time this function is called it will try one method
// the first time it is called it will try method1
// then method2, then method3, then method4
// after it does method4 it will start back at method1
// we will use script properties to save which method is next
// we also want to use the same query string for each batch so we'll save that in script properties too
function testIt()
{
// get the sheet where we're staving run times
var runTimesSheet = SpreadsheetApp.openById("...").getSheetByName("times");
// we want to see true speed tests and don't want server side caching so we a copy of our data sheet
// make a copy of our data sheet and get its ID
var tempSheetID = SpreadsheetApp.openById("...").copy("temp sheet").getId();
// get script properties
var scriptProperties = PropertiesService.getScriptProperties();
// the counter
var searchCounter = Number(scriptProperties.getProperty("searchCounter"));
// index of search list we want to query for
var searchListIndex = Number(scriptProperties.getProperty("searchListIndex"));
// if we're at 0 then we need to get the index of the query string
if(searchCounter == 0)
{
searchListIndex = Math.floor(Math.random() * searchList.length);
scriptProperties.setProperty("searchListIndex", searchListIndex);
}
// query string
var query = searchList[searchListIndex];
// save relevant data
var timerRow = ["method" + (searchCounter + 1), searchListIndex, query, 0, "", "", "", ""];
// run the appropriate method
switch(searchCounter)
{
case 0:
// start time
var start = (new Date()).getTime();
// run the query
var ret = method1(tempSheetID, "Extract", 1, query);
// end time
timerRow[3] = ((new Date()).getTime() - start) / 1000;
// if we found the row save its values in the timer output so we can confirm it was found
if(ret)
{
timerRow[4] = ret[0];
timerRow[5] = ret[1];
timerRow[6] = ret[2];
timerRow[7] = ret[3];
}
break;
case 1:
var start = (new Date()).getTime();
var ret = method2(tempSheetID, "Extract", 1, query);
timerRow[3] = ((new Date()).getTime() - start) / 1000;
if(ret)
{
timerRow[4] = ret[0];
timerRow[5] = ret[1];
timerRow[6] = ret[2];
timerRow[7] = ret[3];
}
break;
case 2:
var start = (new Date()).getTime();
var ret = method3(tempSheetID, "Extract", "A", "AL", "B", query);
timerRow[3] = ((new Date()).getTime() - start) / 1000;
if(ret.table.rows.length)
{
timerRow[4] = ret.table.rows[0].c[0].v;
timerRow[5] = ret.table.rows[0].c[1].v;
timerRow[6] = ret.table.rows[0].c[2].v;
timerRow[7] = ret.table.rows[0].c[3].v;
}
break;
case 3:
var start = (new Date()).getTime();
var ret = method3(tempSheetID, "Extract", "A", "AL", "B", query);
timerRow[3] = ((new Date()).getTime() - start) / 1000;
if(ret.table.rows.length)
{
timerRow[4] = ret.table.rows[0].c[0].v;
timerRow[5] = ret.table.rows[0].c[1].v;
timerRow[6] = ret.table.rows[0].c[2].v;
timerRow[7] = ret.table.rows[0].c[3].v;
}
break;
}
// delete the temp file
DriveApp.getFileById(tempSheetID).setTrashed(true);
// save run times
runTimesSheet.appendRow(timerRow);
// start back at 0 if we're the end
if(++searchCounter == 4) searchCounter = 0;
// save the search counter
scriptProperties.setProperty("searchCounter", searchCounter);
}
I have a global variable searchList that is an array of various query strings -- some are in the sheet, some are not.
I ran testit on a trigger to run every minute. After 152 iterations I had 38 batches. Looking at the result, this is what I see for each method:
| Method | Minimum Seconds | Maximum Seconds | Average Seconds |
|---------|-----------------|-----------------|-----------------|
| method1 | 8.24 | 36.94 | 11.86 |
| method2 | 9.93 | 23.38 | 14.09 |
| method3 | 1.92 | 5.48 | 3.06 |
| method4 | 2.20 | 11.14 | 3.36 |
So it appears that, at least for my data-set, is using Google visualization query is the fastest.
so I am new to Processing and basically I am doing a program that when it runs, it opens a window with 4 different images, each of the image have description underneath. In the methods below, I created two random methods, one for the reviews number and the other for the review comments, I would like the comments to not be generated all the time for every film - more like popping up randomly, because it cause too much chaos trying to read them all. Also to check weather I can add arrays together of string and integer for the average value of the review number.
Below is the code, would appreciate your help. thanks.
import g4p_controls.*;
import ddf.minim.*;
PFont font;
PImage img1,img2; // background images for two different windows
PImage fimg1, fimg2, fimg3, fimg4, fimg5, fimg6; //images of movies
int rectX,rectY;
GButton btn;
GWindow window;
Minim minim;
AudioPlayer player;
String[] rev_film1 = {"The Best Wolverine Movie","Logan is another level","Disappointment","Such a sad farewell"}; //Logan
String[] rev_film2 = {"A scary movie that isn't scary.","Terrifyingly brilliant.","The perfect blend of comedy and horror","The IT Factor"}; //IT
String[] rev_film3 = {"Soul-less,Confused,Loud.","Devastatingly Disappointed","A technical masterpiece","A visual wonder that lacks depth"}; //Dunkirk
String[] rev_film4 = {"Disgrace", "Worst Star Wars movie", "TERRIBLE","A Betrayal to the Legacy"}; //Starwars
int[] rat_film1 = {9,8,2,2};
float r;
void setup()
{
size(1150,600,JAVA2D);
surface.setTitle(" - The Theatre of Dreams Database - ");
font = loadFont("BerlinSansFB-Reg-48.vlw");
img1 = loadImage("film2.jpg");
background(img1);
btn = new GButton(this,900,350,100,50, "Enter Website");
minim = new Minim(this);
player = minim.loadFile("sound.mp3");
player.play();
}
void draw()
{
fill(255);
textFont(font,32);
text("Welcome to", 850, 85);
text("The Theatre of Dreams", 760, 175);
text("Database", 870, 220);
}
void handleButtonEvents(GButton button, GEvent event)
{
if (button == btn && event == GEvent.CLICKED)
{
createWindow();
btn.setEnabled(false);
}
}
void createWindow() // creating new window with mouse click
{
window = GWindow.getWindow(this, " - Top 4 Movies in 2017 - ", 100, 50, 1150, 600, JAVA2D);
window.addDrawHandler(this, "windowDraw");
window.addOnCloseHandler(this, "windowClosing");
window.setActionOnClose(GWindow.CLOSE_WINDOW);
}
void windowDraw(PApplet app, GWinData data)
{
img2 = loadImage("film3.jpg");
app.background(img2);
app.text(" - Top 4 Movies in 2017 - ",440,85);
app.fill(255);
app.textFont(font,25);
fimg1 = loadImage("logan.jpg");
fimg2 = loadImage("it.jpg");
fimg3 = loadImage("dunkirk.jpg");
fimg4 = loadImage("starwars.jpg");
//////////Film 1 - LOGAN
app.image(fimg1,5,140,180,170);
app.text("Rating: 8.1 / 10",5,340); //fixed rating
app.text("Genres: Action | Drama", 5, 365);
app.text("| Sci-Fi | Thriller",5,390);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(0, 6);
}
String user = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user, 5,430);
// the random function of the comments
int index = int(random(rev_film1.length));
String user11 = "Reviews: " + "\n" + rev_film1[index];
app.text(user11, 5,460);
////////////////////Film 2 - IT
app.image(fimg2,960,360,180,170);
app.text("Rating: 7.6 / 10", 700,400);
app.text("Genres: Drama | Horror",700,430);
app.text("| Thriller",700,460);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(5, 10);
}
String user2 = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user2, 700,500);
int index2 = int(random(rev_film2.length)); // the random function of the comments
String user22 = "Reviews: " + "\n" + rev_film2[index2];
app.text(user22, 700,540);
/////////Film 3 - DUNKIRK
app.image(fimg3,320,250,180,170);
app.text("Rating: 8.1 / 10",320,445); //fixed rating
app.text("Genres: Action | Drama", 320, 470);
app.text("| History | Thriller | War",320,495);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(0, 5);
}
String user3 = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user3, 320,530);
int index3 = int(random(rev_film3.length)); // the random function of the comments
String user33 = "Reviews: " + "\n" + rev_film3[index3];
app.text(user33, 320,560);
/////////////Film 4 - STAR WARS
app.image(fimg4,570,120,180,170);
app.text("Rating: 7.6 / 10", 760,140); //fixed rating
app.text("Genres: Action | Adventure | Fantasy ", 760,168);
app.text("| Sci-Fi", 760,195);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(0, 2);
}
String user4 = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user4, 760,220);
int index4 = int(random(rev_film4.length)); // the random function of the comments
String user44 = "Reviews: " + "\n" + rev_film4[index4];
app.text(user44, 760,250);
}
public void windowClosing(GWindow w)
{
btn.setEnabled(false);
player.close();
minim.stop();
exit();
}
Please try to post a MCVE instead of your full program. For example, try creating a simple sketch that shows a circle every X seconds. That way we can focus on your problem instead of all the extra stuff that has nothing to do with your question.
But to answer your question, you can use the millis() function or the frameCount variable to check how much time has gone by, then do something every X seconds or every X frames.
Related posts:
How to make a delay in processing project?
How can I draw only every x frames?
Removing element from ArrayList every 500 frames
Timing based events in Processing
How to add +1 to variable every 10 seconds in Processing?
How to create something happen when time = x
making a “poke back” program in processing
Processing: How do i create an object every “x” time
Timer using frameRate and frame counter reliable?
Please also consult the Processing reference for more information.
If you still can't get it working, please post a MCVE (not your full project!) in a new question and we'll go from there. Good luck.
I have a script that changes the layer name of my illustrator file to "Test 1, Test 2, etc..." All I want to accomplish is to add leading zero to single digits. "Test 01, Test 02 ... Test 10, Test 11, etc..."
var doc = app.activeDocument;
idLayers("Test "); // Rename visible layers
// Hidden layers will be skipped and not counted
function idLayers(prefix){
var counter = 1;
for(i=0;doc.layers.length>i;i++){
var currentLayer = doc.layers[i];
// if layer is visible...
if (currentLayer.visible) {
currentLayer.name= prefix + counter;
counter++;
}
}
}
I found the following that would help but I'm not sure where to add it to the above code.
function pad(n) {
return (n < 10) ? ("0" + n) : n;
}
Total noob here so any help would be greatly appreciated. Thank you in advance!
You simply need to add the function that you already found at the end of your script (or at the beginning, it does not really matter) and then call it in the line, where the layer is named. So the whole script would look like this:
var doc = app.activeDocument;
idLayers("Test "); // Rename visible layers
// Hidden layers will be skipped and not counted
function idLayers(prefix){
var counter = 1;
for(i=0;doc.layers.length>i;i++){
var currentLayer = doc.layers[i];
// if layer is visible...
if (currentLayer.visible) {
currentLayer.name= prefix + pad(counter);
counter++;
}
}
}
function pad(n) {
return (n < 10) ? ("0" + n) : n;
}
I want to print or read complete contact list using appium (suppose my .apk is a contact application and it shows complete A to Z contacts and by scrolling i can view all of the contacts).
I am able to count/print contacts shown in the first screen (i.e the screen which shows some contact say 10 contacts by default and for more i have to scroll).i have come to solution of the above and its working for some time but after that it throws an error, Please help how to rectify this issue
java.lang.IndexOutOfBoundsException: Index: 9, Size: 9
My code is `
AppiumDriver driver = null;
ArrayList values = new ArrayList();
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability(MobileCapabilityType.DEVICE_NAME, "Galaxy S4");
cap.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4.4");
cap.setCapability(MobileCapabilityType.APP_PACKAGE, "com.brainworks.contacts");
cap.setCapability(MobileCapabilityType.APP_ACTIVITY, "com.brainworks.contacts.ui.Main");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),cap);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
List<WebElement> allContactsOnfirstScreen = driver.findElements(By.xpath("//*[#resource-id='com.brainworks.contacts:id/txt_name']"));
driver.context("NATIVE_APP");
Dimension size = driver.manage().window().getSize();
int StartY = (int)(size.height * 0.70);
int EndY = (int)(size.height * 0.55);
int StartX = size.width/2;
for(int i =0;i<200;i++){
System.out.println("Contacts are = " + allContactsOnfirstScreen.get(i).getAttribute("text"));
String Values = allContactsOnfirstScreen.get(i).getAttribute("text");
values.add(Values);
System.out.println("Value is = " + values);
String ext = Values;
String [] a = ext.split(",");
String [] b = a[a.length-1].split("//]");
System.out.println("val = " + b[0]);
driver.swipe(StartX, StartY, StartX, EndY , 1000);
}`
Second way which i have tried
AppiumDriver driver = null;
// desired cap as above in the first try
// same as above -but now what i am doing is i am printing the list in for loop
// then do a swipe form last element to first element then again print the new list
// and this cycle keeps on running until i reach the end of the list or the parameter
// in the if loop.
int XOfFirstElement = allContactsOnfirstScreen.get(0).getLocation().getX();
int YOfFirstElement = allContactsOnfirstScreen.get(0).getLocation().getY();
System.out.println("X for XOfFirstElement = " + XOfFirstElement);
System.out.println("Y for YOfFirstElement = " + YOfFirstElement);
int XOfLastElement = allContactsOnfirstScreen.get(allContactsOnfirstScreen.size()-1).getLocation().getX();
int YOfLastElement = allContactsOnfirstScreen.get(allContactsOnfirstScreen.size()-1).getLocation().getY();
System.out.println("X for XOfLastElement = " + XOfLastElement);
System.out.println("Y for YOfLastElement = " + YOfLastElement);
int XOfSecondLastElement = allContactsOnfirstScreen.get(allContactsOnfirstScreen.size()-2).getLocation().getX();
int YOfSecondLastElement = allContactsOnfirstScreen.get(allContactsOnfirstScreen.size()-2).getLocation().getY();
System.out.println("X for XOfSecondLastElement = " + XOfSecondLastElement);
System.out.println("Y for YOfSecondLastElement = " + YOfSecondLastElement);
while(true){
for(int i = 0 ;i<allContactsOnfirstScreen.size();i++){
System.out.println("Value is for " + allContactsOnfirstScreen.get(i).getAttribute("text"));
}
driver.swipe(XOfLastElement, YOfLastElement, XOfFirstElement, YOfFirstElement, 1000);
Thread.sleep(1000L);
String LastName = allContactsOnfirstScreen.get(allContactsOnfirstScreen.size()-1).getAttribute("text");
if(LastName.equals("MyLastContactText"))
break;
}
Now the problem is
1.>Every thing is working as expected but what is happening is sometime it prints the duplicate value (Contact) (may be due to coordinates for that contact do not changes after a swipe)
2. i am not able to print the last contact name every time cause my if statement in the while loop takes me out and script stops.
if anyone can help then it will be great if any new way plz also let me know Thanks in advance
I suppose, following the code snippet, that the problem in the String [] b = a[a.length-1].split("//]"); line. You probably receive 0 from a.length and this goes to the exception. Could you please add print variable a before this line?
Also if this is not the problem, could you please add full exception stack to the post?