| Index: chrome/common/extensions/feature.cc | 
| diff --git a/chrome/common/extensions/feature.cc b/chrome/common/extensions/feature.cc | 
| index 9f7543574dd9dc8e6acd70cd5a137d28b62d4418..66aa818ede8454224e977e6279a801d9f274ba00 100644 | 
| --- a/chrome/common/extensions/feature.cc | 
| +++ b/chrome/common/extensions/feature.cc | 
| @@ -11,6 +11,8 @@ | 
| #include "base/stringprintf.h" | 
| #include "chrome/common/chrome_switches.h" | 
|  | 
| +namespace extensions { | 
| + | 
| namespace { | 
|  | 
| struct Mappings { | 
| @@ -44,9 +46,9 @@ static base::LazyInstance<Mappings> g_mappings = | 
|  | 
| // TODO(aa): Can we replace all this manual parsing with JSON schema stuff? | 
|  | 
| -void ParseSet(const DictionaryValue* value, | 
| -              const std::string& property, | 
| -              std::set<std::string>* set) { | 
| +void ParseSetImpl(const DictionaryValue* value, | 
| +                  const std::string& property, | 
| +                  std::set<std::string>* set) { | 
| ListValue* list_value = NULL; | 
| if (!value->GetList(property, &list_value)) | 
| return; | 
| @@ -103,7 +105,7 @@ void ParseEnumSet(const DictionaryValue* value, | 
| } | 
|  | 
| std::set<std::string> string_set; | 
| -  ParseSet(value, property, &string_set); | 
| +  ParseSetImpl(value, property, &string_set); | 
| for (std::set<std::string>::iterator iter = string_set.begin(); | 
| iter != string_set.end(); ++iter) { | 
| T enum_value = static_cast<T>(0); | 
| @@ -114,8 +116,6 @@ void ParseEnumSet(const DictionaryValue* value, | 
|  | 
| }  // namespace | 
|  | 
| -namespace extensions { | 
| - | 
| Feature::Feature() | 
| : location_(UNSPECIFIED_LOCATION), | 
| platform_(UNSPECIFIED_PLATFORM), | 
| @@ -124,7 +124,8 @@ Feature::Feature() | 
| } | 
|  | 
| Feature::Feature(const Feature& other) | 
| -    : whitelist_(other.whitelist_), | 
| +    : name_(other.name_), | 
| +      whitelist_(other.whitelist_), | 
| extension_types_(other.extension_types_), | 
| contexts_(other.contexts_), | 
| location_(other.location_), | 
| @@ -137,7 +138,8 @@ Feature::~Feature() { | 
| } | 
|  | 
| bool Feature::Equals(const Feature& other) const { | 
| -  return whitelist_ == other.whitelist_ && | 
| +  return name_ == other.name_ && | 
| +      whitelist_ == other.whitelist_ && | 
| extension_types_ == other.extension_types_ && | 
| contexts_ == other.contexts_ && | 
| location_ == other.location_ && | 
| @@ -146,6 +148,12 @@ bool Feature::Equals(const Feature& other) const { | 
| max_manifest_version_ == other.max_manifest_version_; | 
| } | 
|  | 
| +bool Feature::IsEmpty() const { | 
| +  Feature test; | 
| +  test.set_name(name()); | 
| +  return Equals(test); | 
| +} | 
| + | 
| // static | 
| Feature::Platform Feature::GetCurrentPlatform() { | 
| #if defined(OS_CHROMEOS) | 
| @@ -163,8 +171,15 @@ Feature::Location Feature::ConvertLocation(Extension::Location location) { | 
| return UNSPECIFIED_LOCATION; | 
| } | 
|  | 
| +// static | 
| +void Feature::ParseSet(const DictionaryValue* value, | 
| +                       const std::string& property, | 
| +                       std::set<std::string>* set) { | 
| +  ParseSetImpl(value, property, set); | 
| +} | 
| + | 
| void Feature::Parse(const DictionaryValue* value) { | 
| -  ParseSet(value, "whitelist", &whitelist_); | 
| +  ParseSetImpl(value, "whitelist", &whitelist_); | 
| ParseEnumSet<Extension::Type>(value, "extension_types", &extension_types_, | 
| g_mappings.Get().extension_types); | 
| ParseEnumSet<Context>(value, "contexts", &contexts_, | 
|  |