Showing posts with label advanced. Show all posts
Showing posts with label advanced. Show all posts

Friday, May 3, 2013

Put AdWords Data to Amazon S3 Using Scripts

I'm not sure about you, but writing all these scripts is putting me on Google Spreadsheet overload. With the release of the ability to access any of the AdWords reports, the data quickly starts to get unwieldy. Once things get over a few thousand rows, I much prefer to use Excel or store and manipulate data in a database.

So I was looking for other ways to get data from an AdWords report out of the scripts world and I thought of Amazon S3. Amazon offers a RESTful API through their Amazon Web Services that allows you to store and retrieve large amounts of data from the cloud. I figured I could use them to store some CSV files of account/campaign/keyword performance for downloading or processing later, maybe by another script or software.

The script below tries to encapsulate all the logic required to build and authorize a proper S3 put request. I followed the documentation found here.

To get started for free, sign up for Amazon S3 here and find your access and secret keys here:


Next, create a new S3 bucket to hold all your data through the AWS console. Fill in the details below and try a test file. Ideally, you would combine this with one of the other AdWords reporting scripts found here to start storing your data in the cloud.

NOTE: This is a very specific set of functions which represent the bare minimum required information to PUT a file to Amazon S3. For more information, please check out the full Amazon S3 Docs.

Thanks,
Russ

//-----------------------------------
// Put Data To Amazon S3
// Created By: Russ Savage
// FreeAdWordsScripts.com
//-----------------------------------
var ACCESS_KEY = 'YOUR_ACCESS_KEY_HERE';
var SECRET_KEY = 'YOUR_SECRET_KEY_HERE';
var S3_BUCKET = 'YOUR_S3_BUCKET_NAME_HERE';
  

function main() {
  var date_str = Utilities.formatDate(new Date(),AdWordsApp.currentAccount().getTimeZone(),'yyyy-MM-dd');
  var file_name = 'adwords_keyword_perf_'+date_str+'.csv';
  putDataToBucket(S3_BUCKET,'/'+file_name,'this is where the data from an AdWords report would go.');
}


function putDataToBucket(bucket,file_path,data) {
  var auth_options = {  
    method : 'PUT',
    base_url : "http://" + bucket + ".s3.amazonaws.com",
    s3_bucket : bucket,
    path : file_path,
    headers : { 
       "Date" : getDate(),
       "Content-Type" : "application/x-www-form-urlencoded"
    },
  };
  
  var auth_string = generateAuthString(auth_options);
  auth_options.headers["Authorization"] = auth_string;
  
  var options = {
    method : auth_options.method,
    headers : auth_options.headers,
    payload : data
  };
  
  return (UrlFetchApp.fetch(auth_options.base_url+auth_options.path, options).getResponseCode() == 200);
}

//Generates an AWS Auth String
//For more info, see the AWS docs - http://goo.gl/m5nCe
function generateAuthString(url) {
  var string_to_sign =  getStringToSign(url);
  Logger.log(string_to_sign);
  var signature = getSignature(SECRET_KEY,string_to_sign);
  return "AWS" + " " + ACCESS_KEY + ":" + signature;
}

//Generates an AWS Signature
//For more info, see the AWS docs - http://goo.gl/m5nCe
function getSignature(SECRET_KEY,string_to_sign) {
  return  Utilities.base64Encode(
    Utilities.computeHmacSignature(
      Utilities.MacAlgorithm.HMAC_SHA_1,
      string_to_sign,
      SECRET_KEY,
      Utilities.Charset.UTF_8
    )
  );
}

//Generates an AWS string to sign
//For more info, see the AWS docs - http://goo.gl/m5nCe
function getStringToSign(url,params) {
  var method = url.method;
  var date = url.headers.Date;
  
  return method + "\n" + "\n" + 
    url.headers['Content-Type'] + "\n" +
    date + "\n" + 
    getCanonicalizedAmzHeaders(url);
}

//Generates the Canonicalized Amazon Headers (not really)
//For more info, see the AWS docs - http://goo.gl/m5nCe
function getCanonicalizedAmzHeaders(url) {
  var ret_val = "/" + url.s3_bucket;
  ret_val += url.path;
  return ret_val;
}

function getDate() {
  return Utilities.formatDate(new Date(),"GMT", "EEE, dd MMM yyyy HH:mm:ss +0000");
}

Friday, April 5, 2013

Dynamically Adjust Campaign Budgets v2.0

UPDATE 2013-04-06: Made sure daily budgets are multiplied by 30.5 to turn them into monthly budgets (line 150).

UPDATE 2013-04-06: Made sure that when the budgets are reset, they are divided by 30.5 to turn them into daily budgets (line 95).

UPDATE 2013-04-07: A big thank you to FoxSUP for helping me track down an issue with updating the budgets. Fixed line 78 to multiply the current budget by 1+to_change instead of just to_change. Also fixed a bug in calculating the change(line 56).


This is an update to a previous script I put together to dynamically adjust campaign budgets. There have been a few asks from some of the comments and I figured it would be easier to combine them into a new post.

The script will now keep track of the budgets you set at the beginning of the month via a Google Spreadsheet. You can also fill in the LABEL value if you only want this to operate on campaigns with that label name. Leaving it blank operates on all campaigns.

Thanks,
Russ

/********************************
* Dynamically Adjust Campaign Budgets v2.1
* Changelog v2.1 - Fixed opening of spreadsheet
* Created By: Russ Savage
* FreeAdWordsScripts.com
********************************/
// Let's set some constants
var TIMEFRAME = "THIS_MONTH";
//if the campaign is not in the spreadsheet, the budget is reset
//to this value at the beginning of the month.
var DEFAULT_BUDGET = 100; 
var SPREADSHEET_URL = "PLACE EMPYT SPREADSHEET URL HERE";
var LABEL = ""; //Fill in if you only want to operate on campaigns with this label
 
var SIG_FIGS = 1000; //this means round all calculations to 3 decimal places
var MONTHLY_BUDGET = 0; // we will set this later
 
function main() {
  MONTHLY_BUDGET = _pull_budget_data_from_spreadsheet();
  var tot_cost_mtd = _get_total_cost();
  var is_first_of_the_month = ((new Date()).getDate() == 1);
  is_first_of_the_month = (is_first_of_the_month && ((new Date()).getHours() == 0));
  Logger.log("Total cost: " + tot_cost_mtd + ", Monthly budget:" + MONTHLY_BUDGET);
   
  if(is_first_of_the_month) {
    _reset_budgets();
  } else {
    _adjust_campaign_budget(tot_cost_mtd);
  }
   
}
 
// Returns the total cost for the set TIMEFRAME
function _get_total_cost() {
  var camp_iter = (LABEL == "") ? AdWordsApp.campaigns().get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
   
  var tot_cost = 0;
  while(camp_iter.hasNext()) {
    tot_cost += camp_iter.next().getStatsFor(TIMEFRAME).getCost();
  }
  return tot_cost;
}
 
// Calculates run rate and adjusts campaign bids as needed.
function _adjust_campaign_budget(my_tot_cost) {
  var today = new Date();
  // Accounting for December
  var eom = (today.getMonth() == 11) ? new Date(today.getFullYear()+1,0,1) : 
                                       new Date(today.getFullYear(),today.getMonth()+1,1);
  var days_left = Math.round((eom-today)/1000/60/60/24);
  var days_spent = today.getDate();
  var run_rate = Math.round(my_tot_cost/days_spent*SIG_FIGS)/SIG_FIGS;
  var projected_total = my_tot_cost + (run_rate * days_left);
  var perc_over = Math.round(((MONTHLY_BUDGET-projected_total)/projected_total)*SIG_FIGS)/SIG_FIGS; 
  _change_spend(perc_over,my_tot_cost);
}
 
//Adjusts the budget for a given campaign based on percentage of total spend
//Note: if the cost of a campaign is $0 mtd, the budget is not changed.
function _change_spend(perc_to_change,my_tot_cost) {
  var camp_iter = (LABEL == '') ? AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
   
  while(camp_iter.hasNext()) {
    var camp = camp_iter.next();
    var camp_cost = camp.getStatsFor(TIMEFRAME).getCost();
    var perc_of_total = Math.round(camp_cost/my_tot_cost*SIG_FIGS)/SIG_FIGS;
    //If there is no cost for the campaign, let's not change it.
    var to_change = (perc_of_total) ? (perc_of_total*perc_to_change) : 0;
    camp.setBudget(camp.getBudget()*(1+to_change));
  }
}
 
// Resets the budget unevenly
function _reset_budgets() {
  var camp_budget_map = _pull_campaign_data_from_spreadsheet();
  var camp_iter = (LABEL == '') ? AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
  while(camp_iter.hasNext()) {
    var camp = camp_iter.next();
    if(camp_budget_map[camp.getName()]) {
      camp.setBudget(camp_budget_map[camp.getName()]/30.5);
    } else {
      camp.setBudget(DEFAULT_BUDGET);
    }
  }
}
 
function _pull_campaign_data_from_spreadsheet() {
  var spreadsheet = getSpreadsheet(SPREADSHEET_URL);
  var sheet = spreadsheet.getActiveSheet();
  var data = sheet.getRange("A:B").getValues();
  if(data[0][0] == "") {
    //This means this is the first run and we should populate the data.
    _populate_spreadsheet(sheet);
    data = sheet.getRange("A:B").getValues();
  }
  var campaign_budget_map = {};
  for(var i in data) {
    if(i == 0) { continue; } //ignore the header
    if(data[i][0] == "") { break; } //stop when there is no more data
    campaign_budget_map[data[i][0]] = parseFloat(data[i][1]);
  }
  return campaign_budget_map;
}
 
function _pull_budget_data_from_spreadsheet() {
  var spreadsheet = getSpreadsheet(SPREADSHEET_URL);
  var sheet = spreadsheet.getActiveSheet();
  var data = sheet.getRange("A:B").getValues();
  if(data[0][0] == "") {
    //This means this is the first run and we should populate the data.
    _populate_spreadsheet(sheet);
    data = sheet.getRange("A:B").getValues();
  }
  var tot_budget = 0;
  for(var i in data) {
    if(i == 0) { continue; } //ignore the header
    if(data[i][1] == "") { break; } //stop when there is no more data
    tot_budget += parseFloat(data[i][1]);
  }
  return tot_budget;
}
 
function _populate_spreadsheet(sheet) {
  sheet.clear();
  sheet.appendRow(['Campaign Name','Monthly Budget']);
  var camp_iter = (LABEL == '') ? AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
  while(camp_iter.hasNext()) {
    var camp = camp_iter.next();
    sheet.appendRow([camp.getName(),(camp.getBudget()*30.5)]);
  }
}
 
function getSpreadsheet(spreadsheetUrl) {
  return SpreadsheetApp.openByUrl(spreadsheetUrl);
}

Monday, March 18, 2013

Dynamically Adjust Campaign Budgets

UPDATE 2013-04-05: There is an updated version of this script. Check it out. Dynamically Adjust Campaign Budgets v2.0.

UPDATE 2013-04-07: A big thank you to FoxSUP for helping me track down an issue with updating the budgets. Fixed line 78 to multiply the current budget by 1+to_change instead of just to_change. Also fixed a bug in calculating the change (line 76).

Here is a request from a reader:
I manage many small business PPC accounts, and some of these accounts have multiple campaigns, and they usually have a relatively small monthly click budget. I'm looking for a way to pause ALL campaigns if the entire account has spent over a certain amount month-to-date.

This is actually a pretty easy script to put together. Below is a script that will do just that. You can set the MONTHLY_BUDGET at the beginning of the script and run this script daily on your account. Once the campaigns have a total cost greater than the budget specified, it will pause all the campaigns in the account.

Then, on the first of the next month, it will enable those campaigns once again. If you make no changes to the script below, it should do just that. But let's go one step further.

You actually have the power to get and set your campaign budgets using scripts. So let's say your monthly budget is $100, but you want to make sure your ads are spaced out through the month. I have added a function below called _adjust_campaign_budget() which can be enabled through the flag ADJUST_BUDGETS at the top of the script.

The script will then attempt to calculate a run rate for your campaign to figure out if you are going to meet your budget or not. If you are going to go over, it will lower the budget of each campaign (weighted by campaign cost) so that you come in at your target. If you are going to under-spend, it will also attempt to increase your campaign budget to try to allow you to hit your goal. I have also added a _reset_budgets() function to the end that gets called on the first of the month. If you run this script more frequently, you should enable the code for checking if it is the first hour of the first day of the month.

Now understandably, this script comes with a few cautions. THIS SCRIPT MAY CAUSE YOU TO SPEND A LOT OF MONEY. I'm sure the campaigns I was testing this on were quite a bit smaller than your campaigns, with budgets to match.

Thanks,
Russ

/******************************************
* Keep Your Campaigns In Budget
* Version 1.1
* ChangeLog v1.1 
*   - cleaned up code
*   - added ability for any dates
* Created By: Russ Savage
* FreeAdWordsScripts.com
******************************************/
// Let's set some constants
var MONTHLY_BUDGET = 5000.00;

//If you want to work with a monthly budget, leave START_DATE and END_DATE blank.
var TIMEFRAME = "THIS_MONTH";
//But if you want to work with a specific timeframe, fill these in.
//Use the format yyyyMMdd, so for Jan 12th, 2014, you would put 20140112.
var START_DATE = '';
var END_DATE = '';
 
//Set this to true if you want to adjust budgets or
//keep set to false if you want to just pause all the campaigns
//when you hit your budget
var ADJUST_BUDGETS = false;
var DECIMAL_PLACES = 3;
 
function main() {
  var totalCostMTD = getTotalCost();
  var isFirstOfTheMonth = ((new Date()).getDate() == 1);
  if(START_DATE && END_DATE) {
    var today = new Date();
    today.setHours(0,0,0,0);
    var startDate = new Date(START_DATE.substring(0,4),
                             parseFloat(START_DATE.substring(4,6))-1,
                             START_DATE.substring(6,8));
    isFirstOfTheMonth = (startDate.getTime() == today.getTime());
  }
  //if you run this script more than once per day, uncomment the next line
  //isFirstOfTheMonth = (isFirstOfTheMonth && ((new Date()).getHour() == 0));
  Logger.log("Total cost: " + totalCostMTD + 
           ", Monthly budget:" + MONTHLY_BUDGET +
           ", isFirstOfTheMonth: "+isFirstOfTheMonth);
   
  if(ADJUST_BUDGETS) {
    if(isFirstOfTheMonth) {
      resetBudgets();
    } else {
      adjustCampaignBudget(totalCostMTD);
    }
  } else {
    if(totalCostMTD >= MONTHLY_BUDGET) {
      //If we have hit the limit, pause all ads
      enableOrDisableCampaigns(true);
    } else {
      // let's check if it's the first day of the month
      if((new Date()).getDate() == 1) {
        //enable all the campaigns
        enableOrDisableCampaigns(false);
      }
    }
  }
}
 
// Returns the total cost for the set TIMEFRAME
function getTotalCost() {
  var campIter = AdWordsApp.campaigns().get();
   
  var totalCost = 0;
  while(campIter.hasNext()) {
    if(START_DATE && END_DATE) {
      totalCost += campIter.next().getStatsFor(START_DATE,END_DATE).getCost();
    } else {
      totalCost += campIter.next().getStatsFor(TIMEFRAME).getCost();
    }
  }
  return totalCost;
}
 
// Enables or Disables All Campaigns In Account
function enableOrDisableCampaigns(shouldDisable) {
  var campIter = AdWordsApp.campaigns().get();
  while(campIter.hasNext()) { 
    if(shouldDisable) { 
      campIter.next().pause(); 
    } else { 
      campIter.next().enable(); 
    }
  }
}
 
// Calculates run rate and adjusts campaign bids as needed.
function adjustCampaignBudget(myTotalCost) {
  var today = new Date();
  // Accounting for December
  var eom;
  if(START_DATE && END_DATE) {
    eom = new Date(END_DATE.substring(0,4),
                   parseFloat(END_DATE.substring(4,2))-1,
                   END_DATE.substring(6,2));
  } else {
    eom = (today.getMonth() == 11) ? new Date(today.getFullYear()+1,0,1) : 
                                     new Date(today.getFullYear(),today.getMonth()+1,1);
  }
  var daysLeft = Math.round((eom-today)/1000/60/60/24);
  var daysSpent;
  if(START_DATE && END_DATE) {
    var startDate = new Date(START_DATE.substring(0,4),
                             parseFloat(START_DATE.substring(4,2))-1,
                             START_DATE.substring(6,2));
    daysSpent = Math.round((today-startDate)/1000/60/60/24);
  } else {
    daysSpent = today.getDate();
  }
  var runRate = round(myTotalCost/daysSpent);
  var projectedTotal = myTotalCost + (runRate * daysLeft);
  var percOver = round((MONTHLY_BUDGET-projectedTotal)/projectedTotal);
   
  changeSpend(percOver,myTotalCost);
}
 
//Adjusts the budget for a given campaign based on percentage of total spend
//Note: if the cost of a campaign is $0 mtd, the budget is not changed.
function changeSpend(percToChange,myTotalCost) {
  var campIter = AdWordsApp.campaigns().withCondition("Status = ENABLED").get();
   
  while(campIter.hasNext()) {
    var camp = campIter.next();
    var campCost = (START_DATE && END_DATE) ? camp.getStatsFor(START_DATE,END_DATE).getCost()
                                            : camp.getStatsFor(TIMEFRAME).getCost();
    var percOfTotal = round(campCost/myTotalCost);
    //If there is no cost for the campaign, let's not change it.
    var toChange = (percOfTotal) ? (percOfTotal*percToChange) : 0;
    camp.setBudget(camp.getBudget()*(1+toChange));
  }
}
 
// Resets the budget evenly across all campaigns
function resetBudgets() {
  Logger.log('Resetting budgets at the first of the period.');
  var campIter = AdWordsApp.campaigns().withCondition("Status = ENABLED").get();
  var campCount = 0;
  while(campIter.hasNext()) {
    campCount++;
    campIter.next();
  }
  campIter = AdWordsApp.campaigns().withCondition("Status = ENABLED").get();
  while(campIter.hasNext()) {
    campIter.next().setBudget(MONTHLY_BUDGET/campCount);
  }
}

// A helper function to make rounding a little easier
function round(value) {
  var decimals = Math.pow(10,DECIMAL_PLACES);
  return Math.round(value*decimals)/decimals;
}

Tuesday, February 26, 2013

Authenticating to OAuth Services Using AdWords Scripts

Many APIs today use OAuth in order for users to authenticate and call their service.  One very popular example is the Twitter REST API.  Digging through the AdWords Scripting reference, you'll notice that one of the cool things you can do with AdWords Scripts is to pull data from a URL using the UrlFetchApp.

So the question I asked was "Could I write a script to authenticate using OAuth and retrieve data from the Twitter REST API?"

Obviously, the first place I looked was in the OAuthConfig class of the UrlFetchApp.  I set up the configuration and tried to make a call but I kept getting an authentication error.  A little research showed that I wasn't the only one having this problem.  The issue stems from the fact that normally, users need to authenticate through some sort of dialog box before they can access data. See this example about connecting to Picasa Web Albums for more details.

But then I found a post about someone managing to get around this by re-implementing the OAuth authentication system in their script and using a standard UrlFetchApp.fetch() request.

I was up for a challenge so I recreated it myself.  It turned out to be quite a bit of code, but in the end, the only thing you really need to worry about is getting the correct keys from Twitter and calling _build_authorization_string().

Thanks,
Russ

//-----------------------------------
// Authenticate and Connect to OAuth Service
// Created By: Russ Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  //Define the Twitter Keys and Secrets
  //More info on obtaining these can be found at https://dev.twitter.com/docs/auth/tokens-devtwittercom
  var oauth_key_stuff = {
    "consumer_key" : "your consumer key",
    "consumer_secret" : "your consumer secret",
    "access_token" : "your access token",
    "access_token_secret" : "your access token secret"
  };

  // Update this with the REST url you want to call.  I only tested it with GET
  // but i don't think there is anything stopping a POST request from working.
  var url_stuff = {  
    "http_method" : 'GET',
    "base_url" : "https://api.twitter.com/1.1/statuses/user_timeline.json"
  };

  //Add the parameters for the REST url you want to call.
  var url_param_stuff = {
    "screen_name" : "russellsavage" //hey that's me!
  };
  
  // Don't touch this stuff
  var other_oauth_data = {
    "oauth_nonce" : Utilities.base64Encode(Math.random() +
          "secret_sauce" +
          (new Date()).getTime()).replace(/(?!\w)/g, ''),
    "oauth_signature_method" : "HMAC-SHA1",
    "oauth_timestamp" : Math.round((new Date()).getTime() / 1000.0),
    "oauth_version" : "1.0"
  };
  
  // Here is where the magic happens
  var auth_string = _build_authorization_string(oauth_key_stuff,url_stuff,url_param_stuff,other_oauth_data);

  var options = {
    "headers" : { "Authorization" :  auth_string }
  };
    
  var url = _build_url(url_stuff,url_param_stuff);
  var response = UrlFetchApp.fetch(url, options);
  var tweets = JSON.parse(response.getContentText());
  
  //now let's log my amazing tweets!
  for(var tweet in tweets) {
    var t = tweets[tweet];
    Logger.log(t.text);
  }
 
  // HELPER FUNCTIONS BELOW
  
  function _build_url(base_url,param_stuff){
    var url = base_url.base_url;
    if(param_stuff != {}) {
      url += '?';
    }
    for(var key in param_stuff) {
      url += key + "=";
      url += encodeURIComponent(param_stuff[key]);
      url += '&';
    }
    return url.slice(0,-1);
  }
  
  function _build_param_string(auth_keys,url_data,oauth_data) {
    var data_for_param_string = {
      "oauth_consumer_key" : auth_keys.consumer_key,
      "oauth_nonce" : oauth_data.oauth_nonce,
      "oauth_signature_method" : oauth_data.oauth_signature_method,
      "oauth_timestamp" : oauth_data.oauth_timestamp,
      "oauth_token" : auth_keys.access_token,
      "oauth_version" : oauth_data.oauth_version
    };
    
    // add additional url values
    for(var my_key in url_data) { 
      data_for_param_string[my_key] = url_data[my_key]; 
    }
    
    // find and sort the keys for later
    var keys = [];
    for(var key in data_for_param_string) {
      keys.push(key);
    }
    keys.sort();
    
    //finally build and return the param string
    var param_string = "";
    for(var i in keys) {
      param_string += keys[i] + "=" + encodeURIComponent(data_for_param_string[keys[i]]);
      if(i < keys.length - 1) {
        param_string += "&";
      }
    }
    
    return param_string;
  }
  
  function _build_sig_base_string(my_url_stuff,my_param_string) {
    return my_url_stuff.http_method +
      "&" + encodeURIComponent(my_url_stuff.base_url) +
      "&" + encodeURIComponent(my_param_string);
  }
  
  function _build_sigining_key(my_key_stuff) {
    return encodeURIComponent(my_key_stuff.consumer_secret) + 
      "&" + encodeURIComponent(my_key_stuff.access_token_secret);
  }
  
  function _build_oauth_signature(base_string,sign) {
    return Utilities.base64Encode(
      Utilities.computeHmacSignature(
        Utilities.MacAlgorithm.HMAC_SHA_1, 
        base_string, 
        sign
      )
    );
  }
  
  function _build_authorization_string(my_key_stuff,my_url_stuff,my_url_param_stuff,my_oauth_stuff) {
    var param_string = _build_param_string(my_key_stuff,my_url_param_stuff,my_oauth_stuff);
    var sig_base_string = _build_sig_base_string(my_url_stuff,param_string);
    var signing_key = _build_sigining_key(my_key_stuff);
    var oauth_signature = _build_oauth_signature(sig_base_string,signing_key);
    return "OAuth " +
           encodeURIComponent("oauth_consumer_key") + '="' + 
             encodeURIComponent(my_key_stuff.consumer_key) + '", ' +
           encodeURIComponent("oauth_nonce") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_nonce) + '", ' +
           encodeURIComponent("oauth_signature") + '="' + 
             encodeURIComponent(oauth_signature) + '", ' +
           encodeURIComponent("oauth_signature_method") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_signature_method) + '", ' +
           encodeURIComponent("oauth_timestamp") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_timestamp) + '", ' +
           encodeURIComponent("oauth_token") + '="' + 
             encodeURIComponent(my_key_stuff.access_token) + '", ' +
           encodeURIComponent("oauth_version") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_version) + '"';
    
  }
  
}