So I made a simple script that duplicates two columns basically.
When I run it from the scripteditor I get the correct result, but when I apply this script to a button suddenly it's broken...
this is the code:
function DuplicateSelectedRows() {
var spreadsheet = SpreadsheetApp.getActive();
//Insert rows
spreadsheet.getActiveSheet().insertColumns("4");
spreadsheet.getActiveSheet().insertColumns("4");
// merge cells top
spreadsheet.getRange('D2:E2').activate()
.mergeAcross();
spreadsheet.getRange('D3:E3').activate()
.mergeAcross();
//paste values in newly created rows
spreadsheet.getRange('B4:C20').copyTo(spreadsheet.getRange("D4:E20"));
spreadsheet.getRange('B3:C3').copyTo(spreadsheet.getRange("D3:E3"));
spreadsheet.getRange('B2:C2').copyTo(spreadsheet.getRange("D2:E2"));
// clear data new training
spreadsheet.getRange('B5:C20').clearContent();
};
In your script editor, you are running the script 'DuplicateSelectedRows' but on your button, you are running the script 'NewTraining'
Although it says "Assign script" what you actually need to put is the name of the Apps Script function you want to link to the image [1], in this case you have to put 'DuplicateSelectedRows'.
[1] https://developers.google.com/apps-script/guides/menus#clickable_images_and_drawings_in_google_sheets
Related
Often in Jupyter I'd move to different parts of the notebook to look at something, and when I am done I want to jump back to where I was working on previously. Right now I'd have to navigate to the closest Markdown section (through the Jupyter Notebook Extensions) and move up or down to get to where I was. Is there a way to jump directly to the last cell that I have made an edit (preferably through keyboard shortcut)? Thanks!
Ideally this would be a built-in shortcut of course, but in the meantime:
Option 1: Custom JavaScript
If you get a browser extension like Custom JavaScript for Websites 2 (open-source), then you can use this code to record a stack of scroll position histories and jump backwards with Ctrl+Shift+X:
// Visit JupyterLab in browser and click the Custom JS browser extension icon and then paste this:
if(location.href.startsWith("http://localhost:8888/lab")) {
let scrollLocationsHistories = new Map();
let scrollBinHeight = 100;
window.addEventListener("keydown", (e) => {
let notebookEl = document.querySelector(".jp-mod-searchable .jp-NotebookPanel-notebook");
if(!scrollLocationsHistories.has(notebookEl)) scrollLocationsHistories.set(notebookEl, [])
let scrollLocationsHistory = scrollLocationsHistories.get(notebookEl);
if(e.ctrlKey && e.shiftKey && e.key === "X") {
if(scrollLocationsHistory.length > 0) {
e.preventDefault();
let origScrollPos = notebookEl.scrollTop;
notebookEl.scrollTo(0, scrollLocationsHistory.pop()*scrollBinHeight);
let newScrollPos = notebookEl.scrollTop;
if(Math.abs(origScrollPos-newScrollPos) < scrollBinHeight && scrollLocationsHistory.length > 0) {
notebookEl.scrollTo(0, scrollLocationsHistory.pop()*scrollBinHeight); // jump back again because last edit position was close to current position
}
console.log("Scroll History (newest locations at end):", scrollLocationsHistory.map(v => v*scrollBinHeight))
}
} else if(!e.ctrlKey && !e.shiftKey && document.activeElement.tagName.toLowerCase() === "textarea") {
let scrollBin = Math.round(notebookEl.scrollTop/scrollBinHeight);
if(scrollLocationsHistory[scrollLocationsHistory.length-1] !== scrollBin) {
scrollLocationsHistory.push(scrollBin);
if(scrollLocationsHistory.length > 500) scrollLocationsHistory = scrollLocationsHistory.slice(-250);
}
}
});
}
It's just an initial prototype, but it seems to work quite well so far. You may want to adjust it a bit - e.g. scrollBinHeight causes nearby edits that are within scrollBinHeight pixels of one another to not create a second history entry. You'll need to edit http://localhost:8888/lab to match the URL that you want to enable it on. If you're reading this long after I've written it, then you may also need to change document.querySelector(".jp-mod-searchable .jp-NotebookPanel-notebook") (i.e. the main scrolling element of the active notebook) in case they've updated the HTML class names, or HTML structure.
Option 2: Fold Often
Another possible option (which may be impractical depending on your use case) is to get used to folding cells that you're not currently working on. That makes it much easy to quickly scroll between cells that you're working on.
Option 3: Search Hack
If you're working on a particular cell but often have to jump to another one, you can add a comment like #vv (or any random easy-to-type string) to both of those cells and then whenever you need to jump between them, just press Ctrl+F and then Enter. The first time you do this you'll obviously need to type vv in the search box, but after that it'll be remembered (unless you use the search for another string). The disadvantage of this approach is that you need to "prune" the #vvs from cells that you're no longer working on.
echap to go to command mode, then Ctrl + z will undo your last change, which will bring the focus on the last edited cell. ctrl + y will redo the last modification.
(Only tested on python3 kernel)
EDIT Actually if you press ctrl + z just once, you only get the focus part, without modifying your cell. Then press enter to go to edit mode, which scrolls the page to the active cell.
I have code in which I am sourcing multiple codes one after the other. Something like below
source("t1.r")
source("t2.r")
source("t3.r")
source("t4.r")
While running this main script if any source statement gives an error, I don't want to source any remaining scripts (i.e. don't want to run any subsequent statements).
I don't want to write if error condition after every source statement. I want to do something universal and at the beginning only.
What change should I do in the main script to do this?
Edited as per suggested by Nicola and RHertel
setwd("/Users/xxxx/Desktop/Sub")
scripts<-list.files(pattern="*.R")
for (f in scripts)
{
c<-try(source(f))
ifelse (class(c)!="try-error", print(paste("Script Sourced:", f,sep=" ")), setwd("/Users/xxxx/Desktop")
}
This script prints the scripts sourced. That way you can recognise which didnt get sourced.
I am trying to run an R-script file using windows task scheduler that runs it every two hours. What I am trying to do is gather some tweets through Twitter API and run a sentiment analysis that produces two graphs and saves it in a directory. The problem is, when the script is run again it replaces the already existing files with that name in the directory.
As an example, when I used the pdf("file") function, it ran fine for the first time as no file with that name already existED in the directory. Problem is I want the R-script to be running every other hour. So, I need some solution that creates a new file in the directory instead of replacing that file. Just like what happens when a file is downloaded multiple times from Google Chrome.
I'd just time-stamp the file name.
> filename = paste("output-",now(),sep="")
> filename
[1] "output-2014-08-21 16:02:45"
Use any of the standard date formatting functions to customise to taste - maybe you don't want spaces and colons in your file names:
> filename = paste("output-",format(Sys.time(), "%a-%b-%d-%H-%M-%S-%Y"),sep="")
> filename
[1] "output-Thu-Aug-21-16-03-30-2014"
If you want the behaviour of adding a number to the file name, then something like this:
serialNext = function(prefix){
if(!file.exists(prefix)){return(prefix)}
i=1
repeat {
f = paste(prefix,i,sep=".")
if(!file.exists(f)){return(f)}
i=i+1
}
}
Usage. First, "foo" doesn't exist, so it returns "foo":
> serialNext("foo")
[1] "foo"
Write a file called "foo":
> cat("fnord",file="foo")
Now it returns "foo.1":
> serialNext("foo")
[1] "foo.1"
Create that, then it returns "foo.2" and so on...
> cat("fnord",file="foo.1")
> serialNext("foo")
[1] "foo.2"
This kind of thing can break if more than one process might be writing a new file though - if both processes check at the same time there's a window of opportunity where both processes don't see "foo.2" and think they can both create it. The same thing will happen with timestamps if you have two processes trying to write new files at the same time.
Both these issues can be resolved by generating a random UUID and pasting that on the filename, otherwise you need something that's atomic at the operating system level.
But for a twice-hourly job I reckon a timestamp down to minutes is probably enough.
See ?files for file manipulation functions. You can check if file exists with file.exists, and then either rename the existing file, or create a different name for the new one.
I am facing an issue where I need to run script with three features. Let's say we have 3 feature files with tag names as #smoke1, #smoke2 and #smoke3. And I want these to be executed in that sequence.
Issue is that smoke3 is executing first and rest of them afterwards.
This is my script:
#Cucumber.Options(
glue = { "com.abc", "cucumber.runtime.java.spring.hooks" },
features = "classpath:",
format = { "json", "json:target/cucumber.json" },
tags = "#smoke1, #smoke2, #smoke3"
)
public class ex_Test extends AbstractTest { }
Warning: This only works in older versions of Cucumber.
Cucumber feature files are executed in alphabetical order by path and filename. The execution order is not based on tags.
However, if you specifically specify features, they should be run in the order declared.
For example:
#Cucumber.Options(features={"first_smoke.feature", "another_smoke.feature"})
Should run first_smoke and then another_smoke (compared to the default which is to run in the other order.
Ok we got it , We can have multiple tags for a single scenario like this #tag1 #tag2 #tag3.
You can not define the order in way below.
#Cucumber.Options(features={"first_smoke.feature", "another_smoke.feature"})
Cucumber determines the only alphabetical order and even only first letter of the word.
You can have how many tags you want in feature file, if you want to trigger feature file more times, it's not working like you will add tag more time or more tags from feature like:
tags = {"#Reports,#Reports"}
And tests are triggered in alphabetical order, it's checking tags not feature file name.
I am searching for a way to get user input inside a loop while executing in batch mode.
readLines() and scan() work well for me in interactive mode only, in batch mode they start to read in lines of code as user input, unless all the code is surrounded by {}, which is inconvenient. I need a simple solution to get just 1 integer value in a way that I can just type in value and press ENTER, so
the input field (if the solution involves GUI) must automatically get focus and
ENTER must trigger end of input/submission.
I can't find a way to do it that will satisfy both conditions, e.g. ginput() from gWidgets activates the input field, but ENTER doesn't trigger form submission.
Here is how I solved my own problem:
require(gWidgets)
options(guiToolkit="RGtk2")
INPUT <- function(message) {
CHOICE <- NA
w <- gbasicdialog(title=message, handler = function(h,...) CHOICE <<- svalue(input))
input <- gedit("", initial.msg="", cont=w, width=10)
addHandlerChanged(input, handler=function (h, ...) {
CHOICE <<- svalue(input)
dispose(w)
})
visible(w, set=TRUE)
return(CHOICE)
}
repeat{
x=INPUT("Input an integer")
if(!is.na(as.integer(x))) break
}
print(x)
Update:
I can't test this right now, but take a look at ?menu and have it pop up a gui window.
I'm not certain if that will work, but it is different in that it takes a mouse-click response.
original answer:
As per the documentation to ?readline:
This can only be used in an interactive session.
..
In non-interactive use the result is as if the response was RETURN and the value is "".
If you are simply waiting for one piece of information, and you do not know this piece of information before beginning the execution of the script (presumably, there is a decision to be made which is dependent on the results earlier in the script), then one alternative is to simply break your script up into three parts:
everything before the decision point.
an interactive script which prompts for input
everything after the decision point.
And simply chain the three together by having the first end by calling the second in an interactive session. Then have the second end by calling the third.