Miscellany
You can also follow my programming updates on GitHub.
BPM tapper
This is an R script for a function that will produce an estimate of beats per minute (BPM) based on the rate of return presses. As with the password generator, there are already existing places that do this, but none I found seem to allow cumulative estimation past a couple dozen taps or provide more detailed information about the number of taps supplied & or what measure of central tendency is actually returned.
bpm <- function(df = NULL, timeOut = 5, plot = F) {
if (is.null(df)) {
df <- data.frame(rep = 0, Sys.time = as.numeric(Sys.time()), BPM = NA)
df[1:2,] <- c(0,1, Sys.time(), Sys.time(), NA, NA)
bpm(df, timeOut)
} else if (nrow(df) < 2) {
df <- data.frame(rep = 0, Sys.time = as.numeric(Sys.time()), BPM = NA)
df[1:2,] <- c(0,1, Sys.time(), Sys.time(), NA, NA)
bpm(df, timeOut)
} else if (df[nrow(df),2] - df[nrow(df)-1,2] < timeOut) {
if (nrow(df) > 3 & is.na(df[1,3])) df <- df[2:nrow(df),]
readline(cat('Current median BPM:',round(median(df[,3], na.rm = T), 1),'\nPress Return\n'))
y <- as.numeric(Sys.time())
df[nrow(df) + 1, 1] <- nrow(df)
df[nrow(df), 2] <- y
df[nrow(df), 3] <- 60/(df[nrow(df), 2] - df[nrow(df) -1, 2])
bpm(df, timeOut)
} else {
df <- df[1:nrow(df)-1,]
if (plot == F) {
cat('Break: timeOut reached.','\nMean:', round(mean(df[,3], na.rm = T), 1), 'bpm\nMedian:', round(median(df[,3], na.rm = T), 1), 'bpm\nEstimated beats per minute is:', round((round(mean(df[,3], na.rm = T), 1)+round(median(df[,3], na.rm = T), 1))/2), '\n')
df
} else if (plot == T) hist(df[,3]) #not plotting for some reason
}
}
#shapiro.test(tap[,3]) #experimenting with testing the normaility, potentially to detect multiple bpms within one series (song)
Password generator
Here's script for a function to generate random passwords using R. You can either make random strings (style = 'rando') or use dictionary words (style = 'words'). Both of these options meet most modern password requirements (e.g., at least 1 uppercase letter, 1 number, 1 special character), but include custamizability in the password length.
This is behind the curve in that many web browsers and other programs will do this for you, but this was more fun.
Please give it a try! If you have R but aren't entirely sure how to use this, all you need to do is copy and paste the file into a script (or directly into the terminal), run the first line of code, which will build the function and store it in your global environment, so now you can use it just like any other function (while in the same R session). The last two lines provide an example for each of the two methods.
genPass <- function(nChar = 20, nSpchar = 2, ncLet = 5, nLet = 10, nNum = 5, style = 'rando', nWord = 4, replace = T) {
specChar <- c('!','?',':','-','_','@','#','$','%','&','*','+','/','^','(',')','[',']','{','}','~',"'",',','.')
if(style == 'rando') {
if(nChar > 6) {
repeat {pw1 <- sample(c(specChar, 0:9, LETTERS, letters), nChar) #works, magically.
if(!all(!all(is.na(pmatch(pw1, specChar))),
!all(is.na(pmatch(pw1, 0:9))),
!all(is.na(pmatch(pw1, LETTERS))),
!all(is.na(pmatch(pw1, letters)))) == F) break
}
pw2 <- toString(pw1)
pw <- gsub(',', '', gsub("\\s", "",pw2))
return(pw)} else if(nChar > 3) {
repeat {pw1 <- sample(c(specChar, 0:9, LETTERS, letters), nChar) #works, magically.
if(!all(!all(is.na(pmatch(pw1, specChar))),
!all(is.na(pmatch(pw1, 0:9))),
!all(is.na(pmatch(pw1, LETTERS))),
!all(is.na(pmatch(pw1, letters)))) == F) break
}
pw2 <- toString(pw1)
pw <- gsub(',', '', gsub("\\s", "",pw2))
return(c('Warning! A secure password requires at least 8 characters. 20 is recommended.', pw))} else if(nChar < 4) {return('Error! At least 4 characters are required to work.')}
} else
if(style == 'words') {
if(Sys.info()['sysname'] == 'Darwin')
{dic <- read.table("/usr/share/dict/words")} else
if(Sys.info()['sysname'] == 'Windows') {dic <- read.table('%AppData%/Microsoft/Spelling/default.acl')} else
if('try-error' %in% calss(read.table(file = 'https://users.cs.duke.edu/~ola/ap/linuxwords'))) {return('Cannot find local words list. Please connect to the internet.')}
else {dic <- read.table(file = 'https://users.cs.duke.edu/~ola/ap/linuxwords')}
wrd <- sample(levels(dic$V1), nWord)
if (nWord > 1) {
repeat {c1 <- sample(c(specChar, 0:9, LETTERS), 3)
if(!all(!all(is.na(pmatch(c1, specChar))),
!all(is.na(pmatch(c1, 0:9))),
!all(is.na(pmatch(c1, LETTERS)))) == F) break
}
} else {return('Error: must contain at least 2 words!')}
wpw1 <- sample(c(c1, wrd))
wpw2 <- toString(wpw1)
wpw <- gsub(',', '', gsub("\\s", "",wpw2))
if(nchar(wpw) > 127) {return(c(substr(wpw, 1, 127), 'Notice: normal character string length reached. Password has been truncated to 127 characters.'))} else return(wpw)
} else {return("Error: style must be 'rando' or 'words'")}
}
genPass(style = 'words', nWord = 2)
genPass(nChar = 4)