text: 
  $(function() {
    getSettings(["awsCreds", "gcpCreds"])
      .then(function(items) {
        if (items.awsCreds) {
          $("#aws-access-key-id").val(obsfucate(items.awsCreds.accessKeyId));
          $("#aws-secret-access-key").val(obsfucate(items.awsCreds.secretAccessKey));
        }
        if (items.gcpCreds) {
          $("#gcp-api-key").val(obsfucate(items.gcpCreds.apiKey));
        }
      })
    $(".status").hide();
    $("#aws-save-button").click(awsSave);
    $("#gcp-save-button").click(gcpSave);
  })
  
  function obsfucate(key) {
    return key.replace(/./g, function(m, i) {
      return i < key.length-5 ? "*" : m;
    })
  }
  
  
  function awsSave() {
    $(".status").hide();
    var accessKeyId = $("#aws-access-key-id").val().trim();
    var secretAccessKey = $("#aws-secret-access-key").val().trim();
    if (accessKeyId && secretAccessKey) {
      $("#aws-progress").show();
      testAws(accessKeyId, secretAccessKey)
        .then(function() {
          $("#aws-progress").hide();
          updateSettings({awsCreds: {accessKeyId: accessKeyId, secretAccessKey: secretAccessKey}});
          $("#aws-success").text("Amazon Polly voices are enabled.").show();
        })
        .catch(function(err) {
          $("#aws-progress").hide();
          $("#aws-error").text("Test failed: " + err.message).show();
        })
    }
    else if (!accessKeyId && !secretAccessKey) {
      clearSettings(["awsCreds"])
        .then(function() {
          $("#aws-success").text("Amazon Polly voices are disabled.").show();
        })
    }
    else {
      $("#aws-error").text("Missing required fields.").show();
    }
  }
  
  function testAws(accessKeyId, secretAccessKey) {
        var polly = new AWS.Polly({
          region: "us-east-1",
          accessKeyId: accessKeyId,
          secretAccessKey: secretAccessKey
        })
        return polly.describeVoices().promise();
  }
  
  
  function gcpSave() {
    $(".status").hide();
    var apiKey = $("#gcp-api-key").val().trim();
    if (apiKey) {
      $("#gcp-progress").show();
      testGcp(apiKey)
        .then(function() {
          $("#gcp-progress").hide();
          updateSettings({gcpCreds: {apiKey: apiKey}});
          $("#gcp-success").text("Google Wavenet voices are enabled.").show();
        })
        .catch(function(err) {
          $("#gcp-progress").hide();
          $("#gcp-error").text("Test failed: " + err.message).show();
        })
    }
    else {
      clearSettings(["gcpCreds"])
        .then(function() {
          $("#gcp-success").text("Google Wavenet voices are disabled.").show();
        })
    }
  }
  
  function testGcp(apiKey) {
        return ajaxGet("https://texttospeech.googleapis.com/v1beta1/voices?key=" + apiKey);
  }
  