#include <MsgBoxConstants.au3> ; to declare the Constants of MsgBox
Local $sRegex = "(?m)^(/\*)(\n)(\*)(.*?)(\n)(\*/$)|(?<!:)(//)(.*?)$"
Local $sString = "// intraday.gs -- Supports downloading intraday (minute-by-minute) step data" & @CRLF & _
"// Will not work without special permission from Fitbit" & @CRLF & _
"" & @CRLF & _
"// Simon Bromberg (http://sbromberg.com)" & @CRLF & _
"// You are free to use, modify, copy any of the code in this script for your own purposes, as long as it's not for evil" & @CRLF & _
"// If you do anything cool with it, let me know!" & @CRLF & _
"// Note: there are minor improvements/cleanups still to be made in this file, but it should work as is if everything is setup properly" & @CRLF & _
"// See readme on github repo for more information" & @CRLF & _
"" & @CRLF & _
"// Script based on post here http://quantifiedself.com/2014/09/download-minute-fitbit-data/ by Ernesto Ramirez" & @CRLF & _
"/*" & @CRLF & _
"* Do not change these key names. These are just keys to access these properties once you set them up by running the Setup function from the Fitbit menu" & @CRLF & _
"*/" & @CRLF & _
"// Key of ScriptProperty for Firtbit consumer key." & @CRLF & _
"var CONSUMER_KEY_PROPERTY_NAME = "fitbitConsumerKey";" & @CRLF & _
"// Key of ScriptProperty for Fitbit consumer secret." & @CRLF & _
"var CONSUMER_SECRET_PROPERTY_NAME = "fitbitConsumerSecret";" & @CRLF & _
"" & @CRLF & _
"var SERVICE_IDENTIFIER = 'fitbit';" & @CRLF & _
"" & @CRLF & _
"function onOpen() {" & @CRLF & _
" var ss = SpreadsheetApp.getActiveSpreadsheet();" & @CRLF & _
" var menuEntries = [" & @CRLF & _
" {" & @CRLF & _
" name: "Setup"," & @CRLF & _
" functionName: "setup"" & @CRLF & _
" }," & @CRLF & _
" {" & @CRLF & _
" name: "Authorize"," & @CRLF & _
" functionName: "showSidebar"" & @CRLF & _
" }," & @CRLF & _
" {" & @CRLF & _
" name: "Reset"," & @CRLF & _
" functionName: "clearService"" & @CRLF & _
" }," & @CRLF & _
" {" & @CRLF & _
" name: "Download data"," & @CRLF & _
" functionName: "refreshTimeSeries"" & @CRLF & _
" }];" & @CRLF & _
" ss.addMenu("Fitbit", menuEntries);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"" & @CRLF & _
"function isConfigured() {" & @CRLF & _
" return getConsumerKey() != "" && getConsumerSecret() != "";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function setConsumerKey(key) {" & @CRLF & _
" ScriptProperties.setProperty(CONSUMER_KEY_PROPERTY_NAME, key);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getConsumerKey() {" & @CRLF & _
" var key = ScriptProperties.getProperty(CONSUMER_KEY_PROPERTY_NAME);" & @CRLF & _
" if (key == null) {" & @CRLF & _
" key = "";" & @CRLF & _
" }" & @CRLF & _
" return key;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function setLoggables(loggable) {" & @CRLF & _
" ScriptProperties.setProperty("loggables", loggable);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getLoggables() {" & @CRLF & _
" var loggable = ScriptProperties.getProperty("loggables");" & @CRLF & _
" if (loggable == null) {" & @CRLF & _
" loggable = LOGGABLES;" & @CRLF & _
" } else {" & @CRLF & _
" loggable = loggable.split(',');" & @CRLF & _
" }" & @CRLF & _
" return loggable;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function setConsumerSecret(secret) {" & @CRLF & _
" ScriptProperties.setProperty(CONSUMER_SECRET_PROPERTY_NAME, secret);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getConsumerSecret() {" & @CRLF & _
" var secret = ScriptProperties.getProperty(CONSUMER_SECRET_PROPERTY_NAME);" & @CRLF & _
" if (secret == null) {" & @CRLF & _
" secret = "";" & @CRLF & _
" }" & @CRLF & _
" return secret;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"// function saveSetup saves the setup params from the UI" & @CRLF & _
"function saveSetup(e) {" & @CRLF & _
" setConsumerKey(e.parameter.consumerKey);" & @CRLF & _
" setConsumerSecret(e.parameter.consumerSecret);" & @CRLF & _
" setLoggables(e.parameter.loggables);" & @CRLF & _
" setFirstDate(e.parameter.firstDate);" & @CRLF & _
" setLastDate(e.parameter.lastDate);" & @CRLF & _
" var app = UiApp.getActiveApplication();" & @CRLF & _
" app.close();" & @CRLF & _
" return app;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function setFirstDate(firstDate) {" & @CRLF & _
" ScriptProperties.setProperty("firstDate", firstDate);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getFirstDate() {" & @CRLF & _
" var firstDate = ScriptProperties.getProperty("firstDate");" & @CRLF & _
" if (firstDate == null) {" & @CRLF & _
" firstDate = "2012-01-01";" & @CRLF & _
" }" & @CRLF & _
" return firstDate;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function setLastDate(lastDate) {" & @CRLF & _
" ScriptProperties.setProperty("lastDate", lastDate);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getLastDate() {" & @CRLF & _
" var lastDate = ScriptProperties.getProperty("lastDate");" & @CRLF & _
" if (lastDate == null) {" & @CRLF & _
" var today = new Date();" & @CRLF & _
" lastDate = Utilities.formatDate(new Date(), SpreadsheetApp.getActive().getSpreadsheetTimeZone(),"yyyy-mm-dd");" & @CRLF & _
" }" & @CRLF & _
" return lastDate;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"// function setup accepts and stores the Consumer Key, Consumer Secret, Project Key, firstDate, and list of Data Elements" & @CRLF & _
"function setup() {" & @CRLF & _
" var doc = SpreadsheetApp.getActiveSpreadsheet();" & @CRLF & _
" var app = UiApp.createApplication().setTitle("Setup Fitbit Download");" & @CRLF & _
" app.setStyleAttribute("padding", "10px");" & @CRLF & _
"" & @CRLF & _
" var consumerKeyLabel = app.createLabel("Fitbit OAuth 2.0 Client ID:*");" & @CRLF & _
" var consumerKey = app.createTextBox();" & @CRLF & _
" consumerKey.setName("consumerKey");" & @CRLF & _
" consumerKey.setWidth("100%");" & @CRLF & _
" consumerKey.setText(getConsumerKey());" & @CRLF & _
" " & @CRLF & _
" var consumerSecretLabel = app.createLabel("Fitbit OAuth Consumer Secret:*");" & @CRLF & _
" var consumerSecret = app.createTextBox();" & @CRLF & _
" consumerSecret.setName("consumerSecret");" & @CRLF & _
" consumerSecret.setWidth("100%");" & @CRLF & _
" consumerSecret.setText(getConsumerSecret());" & @CRLF & _
" " & @CRLF & _
" var projectKeyTitleLabel = app.createLabel("Project key: ");" & @CRLF & _
" var projectKeyLabel = app.createLabel(ScriptApp.getProjectKey());" & @CRLF & _
" " & @CRLF & _
" var firstDate = app.createTextBox().setId("firstDate").setName("firstDate");" & @CRLF & _
" firstDate.setName("firstDate");" & @CRLF & _
" firstDate.setWidth("100%");" & @CRLF & _
" firstDate.setText(getFirstDate());" & @CRLF & _
"" & @CRLF & _
" var lastDate = app.createTextBox().setId("lastDate").setName("lastDate");" & @CRLF & _
" lastDate.setName("lastDate");" & @CRLF & _
" lastDate.setWidth("100%");" & @CRLF & _
" lastDate.setText(getLastDate());" & @CRLF & _
" // create the save handler and button" & @CRLF & _
" var saveHandler = app.createServerClickHandler("saveSetup");" & @CRLF & _
" var saveButton = app.createButton("Save Setup", saveHandler);" & @CRLF & _
"" & @CRLF & _
" // put the controls in a grid" & @CRLF & _
" var listPanel = app.createGrid(8, 3);" & @CRLF & _
" listPanel.setWidget(1, 0, consumerKeyLabel);" & @CRLF & _
" listPanel.setWidget(1, 1, consumerKey);" & @CRLF & _
" listPanel.setWidget(2, 0, consumerSecretLabel);" & @CRLF & _
" listPanel.setWidget(2, 1, consumerSecret);" & @CRLF & _
" listPanel.setWidget(3, 0, app.createLabel(" * (obtain these at dev.fitbit.com, use OAuth2.0)"));" & @CRLF & _
" listPanel.setWidget(4, 0, projectKeyTitleLabel);" & @CRLF & _
" listPanel.setWidget(4, 1, projectKeyLabel);" & @CRLF & _
" listPanel.setWidget(5, 0, app.createLabel("Start Date for download (yyyy-mm-dd)"));" & @CRLF & _
" listPanel.setWidget(5, 1, firstDate);" & @CRLF & _
" listPanel.setWidget(6, 0, app.createLabel("End date for download (yyyy-mm-dd)"));" & @CRLF & _
" listPanel.setWidget(6, 1, lastDate);" & @CRLF & _
" listPanel.setWidget(7, 0, app.createLabel("Very long intervals will not work; exceed Fitbit rate limit and/or function will timeout"));" & @CRLF & _
" " & @CRLF & _
" // Ensure that all controls in the grid are handled" & @CRLF & _
" saveHandler.addCallbackElement(listPanel);" & @CRLF & _
" // Build a FlowPanel, adding the grid and the save button" & @CRLF & _
" var dialogPanel = app.createFlowPanel();" & @CRLF & _
" dialogPanel.add(listPanel);" & @CRLF & _
" dialogPanel.add(saveButton);" & @CRLF & _
" app.add(dialogPanel);" & @CRLF & _
" doc.show(app);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getFitbitService() {" & @CRLF & _
" // Create a new service with the given name. The name will be used when" & @CRLF & _
" // persisting the authorized token, so ensure it is unique within the" & @CRLF & _
" // scope of the property store" & @CRLF & _
" Logger.log(PropertiesService.getUserProperties());" & @CRLF & _
" return OAuth2.createService(SERVICE_IDENTIFIER)" & @CRLF & _
"" & @CRLF & _
" // Set the endpoint URLs, which are the same for all Google services." & @CRLF & _
" .setAuthorizationBaseUrl('https://www.fitbit.com/oauth2/authorize')" & @CRLF & _
" .setTokenUrl('https://api.fitbit.com/oauth2/token')" & @CRLF & _
"" & @CRLF & _
" // Set the client ID and secret, from the Google Developers Console." & @CRLF & _
" .setClientId(getConsumerKey())" & @CRLF & _
" .setClientSecret(getConsumerSecret())" & @CRLF & _
"" & @CRLF & _
" // Set the name of the callback function in the script referenced" & @CRLF & _
" // above that should be invoked to complete the OAuth flow." & @CRLF & _
" .setCallbackFunction('authCallback')" & @CRLF & _
"" & @CRLF & _
" // Set the property store where authorized tokens should be persisted." & @CRLF & _
" .setPropertyStore(PropertiesService.getUserProperties())" & @CRLF & _
"" & @CRLF & _
" .setScope('activity profile')" & @CRLF & _
" " & @CRLF & _
" .setTokenHeaders({" & @CRLF & _
" 'Authorization': 'Basic ' + Utilities.base64Encode(getConsumerKey() + ':' + getConsumerSecret())" & @CRLF & _
" });" & @CRLF & _
"" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function clearService(){" & @CRLF & _
" OAuth2.createService(SERVICE_IDENTIFIER)" & @CRLF & _
" .setPropertyStore(PropertiesService.getUserProperties())" & @CRLF & _
" .reset();" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function showSidebar() {" & @CRLF & _
" var service = getFitbitService();" & @CRLF & _
" if (!service.hasAccess()) {" & @CRLF & _
" var authorizationUrl = service.getAuthorizationUrl();" & @CRLF & _
" var template = HtmlService.createTemplate(" & @CRLF & _
" '<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +" & @CRLF & _
" 'Reopen the sidebar when the authorization is complete.');" & @CRLF & _
" template.authorizationUrl = authorizationUrl;" & @CRLF & _
" var page = template.evaluate();" & @CRLF & _
" SpreadsheetApp.getUi().showSidebar(page);" & @CRLF & _
" } else {" & @CRLF & _
" Logger.log("Has access!!!!");" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function authCallback(request) {" & @CRLF & _
" Logger.log("authcallback");" & @CRLF & _
" var service = getFitbitService();" & @CRLF & _
" var isAuthorized = service.handleCallback(request);" & @CRLF & _
" if (isAuthorized) {" & @CRLF & _
" Logger.log("success");" & @CRLF & _
" return HtmlService.createHtmlOutput('Success! You can close this tab.');" & @CRLF & _
" } else {" & @CRLF & _
" Logger.log("denied");" & @CRLF & _
" return HtmlService.createHtmlOutput('Denied. You can close this tab');" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getUser() {" & @CRLF & _
" var service = getFitbitService();" & @CRLF & _
"" & @CRLF & _
" var options = {" & @CRLF & _
" headers: {" & @CRLF & _
" "Authorization": "Bearer " + service.getAccessToken()," & @CRLF & _
" "method": "GET"" & @CRLF & _
" }};" & @CRLF & _
" var response = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/profile.json",options);" & @CRLF & _
" var o = JSON.parse(response.getContentText());" & @CRLF & _
" return o.user;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function refreshTimeSeries() {" & @CRLF & _
" if (!isConfigured()) {" & @CRLF & _
" setup();" & @CRLF & _
" return;" & @CRLF & _
" }" & @CRLF & _
" var user = getUser();" & @CRLF & _
" var doc = SpreadsheetApp.getActiveSpreadsheet();" & @CRLF & _
" doc.setFrozenRows(2);" & @CRLF & _
" // two header rows" & @CRLF & _
" doc.getRange("a1").setValue(user.fullName);" & @CRLF & _
" doc.getRange("a1").setComment("DOB:" + user.dateOfBirth)" & @CRLF & _
" doc.getRange("b1").setValue(user.country + "/" + user.state + "/" + user.city);" & @CRLF & _
"" & @CRLF & _
" var options =" & @CRLF & _
" {headers:{" & @CRLF & _
" "Authorization": 'Bearer ' + getFitbitService().getAccessToken()," & @CRLF & _
" "method": "GET"" & @CRLF & _
" }};" & @CRLF & _
" var activities = ["activities/log/steps"];" & @CRLF & _
" var intradays = ["activities-log-steps-intraday"];" & @CRLF & _
"" & @CRLF & _
" var lastIndex = 0;" & @CRLF & _
" for (var activity in activities) {" & @CRLF & _
" var index = 0;" & @CRLF & _
" var dateString = getFirstDate();" & @CRLF & _
" date = parseDate(dateString);" & @CRLF & _
" var table = new Array();" & @CRLF & _
" while (1) {" & @CRLF & _
" var currentActivity = activities[activity];" & @CRLF & _
" try {" & @CRLF & _
" var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/" + currentActivity + "/date/" + dateString+ "/" + dateString + ".json", options);" & @CRLF & _
" } catch(exception) {" & @CRLF & _
" Logger.log(exception);" & @CRLF & _
" }" & @CRLF & _
" var o = JSON.parse(result.getContentText());" & @CRLF & _
"" & @CRLF & _
" var cell = doc.getRange('a3');" & @CRLF & _
" var titleCell = doc.getRange("a2");" & @CRLF & _
" titleCell.setValue("Date");" & @CRLF & _
" var title = currentActivity.split("/");" & @CRLF & _
" title = title[title.length - 1];" & @CRLF & _
" titleCell.offset(0, 1 + activity * 1.0).setValue(title);" & @CRLF & _
" var row = o[intradays[activity]]["dataset"];" & @CRLF & _
" for (var j in row) {" & @CRLF & _
" var val = row[j];" & @CRLF & _
" var arr = new Array(2);" & @CRLF & _
" arr[0] = dateString + ' ' + val["time"];" & @CRLF & _
" arr[1] = val["value"];" & @CRLF & _
" table.push(arr);" & @CRLF & _
" // set the value index index" & @CRLF & _
" index++;" & @CRLF & _
" }" & @CRLF & _
" date.setDate(date.getDate()+1);" & @CRLF & _
" dateString = Utilities.formatDate(date, "GMT", "yyyy-MM-dd");" & @CRLF & _
" if (dateString > getLastDate()) {" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" }" & @CRLF & _
" " & @CRLF & _
" // Batch set values of table, much faster than doing each time per loop run, this wouldn't work as is if there were multiple activities being listed" & @CRLF & _
" doc.getRange("A3:B"+(table.length+2)).setValues(table);" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"// parse a date in yyyy-mm-dd format" & @CRLF & _
"function parseDate(input) {" & @CRLF & _
" var parts = input.match(/(\d+)/g);" & @CRLF & _
" // new Date(year, month [, date [, hours[, minutes[, seconds[, ms]]]]])" & @CRLF & _
" return new Date(parts[0], parts[1]-1, parts[2]); // months are 0-based" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"// parse a date in 2011-10-25T23:57:00.000 format" & @CRLF & _
"function parseDate2(input) {" & @CRLF & _
" var parts = input.match(/(\d+)/g);" & @CRLF & _
" return new Date(parts[0], parts[1]-1, parts[2], parts[3], parts[4]);" & @CRLF & _
"}"
Local $sSubst = "\2'\4\5\8"
Local $sResult = StringRegExpReplace($sString, $sRegex, $sSubst)
MsgBox($MB_SYSTEMMODAL, "Result", $sResult)
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for AutoIt, please visit: https://www.autoitscript.com/autoit3/docs/functions/StringRegExp.htm