anchor.diff:  
   % Idempotent uninstall, if you uninstall a non-existant
   % plugin, you get an `ok`.
  -% -spec uninstall(string()) -> ok | {error, string()}.
  -% uninstall(Name) ->
  -%   % unload app
  -%   ok = unload_plugin(Name),
  -%   log("plugin unloaded"),
  -
  -%   % unload config
  -%   ok = unload_config(Name),
  -%   log("config unloaded"),
  -
  -%   % delete files
  -%   ok = delete_files(Name),
  -%   log("files deleted"),
  -
  -%   % remove code path
  -%   ok = remove_code_path(Name),
  -%   log("removed code path"),
  -
  -%   % unregister plugin
  -%   ok = unregister_plugin(Name),
  -%   log("unregistered plugin"),
  -
  -%   % done
  -%   ok.
  +-spec uninstall(plugin()) -> ok | {error, string()}.
  +uninstall({Name, _BaseUrl, Version, _Checksums}) ->
  +  % unload app
  +  ok = unload_plugin(Name),
  +  log("plugin unloaded"),
  +
  +  % unload config
  +  ok = unload_config(Name, Version),
  +  log("config unloaded"),
  +
  +  % delete files
  +  ok = delete_files(Name, Version),
  +  log("files deleted"),
  +
  +  % delete code path
  +  ok = del_code_path(Name, Version),
  +  log("deleted code path"),
  +
  +  % unregister plugin
  +  ok = unregister_plugin(Name),
  +  log("unregistered plugin"),
  +
  +  % done
  +  ok.
   
   %% * * *
   
  
positive.code:       Else
    end.
  
  -spec load_plugin(string()) -> ok | {error, atom()}.
  load_plugin(NameList) ->
    Name = list_to_atom(NameList),
    application:load(Name).
  
  
  -spec untargz(string()) -> {ok, string()} | {error, string()}.
  
negative.code: 
  
  %% Load Config
  %% Parses <plugindir>/priv/default.d/<pluginname.ini> and applies
  %% the contents to the config system, or removes them on uninstall
  
  -spec load_config(string(), string()) -> ok.
  load_config(Name, Version) ->
      loop_config(Name, Version, fun set_config/1).
  
  -spec unload_config(string(), string()) -> ok.
  unload_config(Name, Version) ->
      loop_config(Name, Version, fun delete_config/1).
  
  -spec loop_config(string(), string(), function()) -> ok.
  loop_config(Name, Version, Fun) ->
      lists:foreach(fun(File) -> load_config_file(File, Fun) end,
        filelib:wildcard(file_names(Name, Version))).
  
  -spec load_config_file(string(), function()) -> ok.
  load_config_file(File, Fun) ->
      {ok, Config} = couch_config:parse_ini_file(File),
      lists:foreach(Fun, Config).
  
  -spec set_config({{string(), string()}, string()}) -> ok.
  set_config({{Section, Key}, Value}) ->
      ok = couch_config:set(Section, Key, Value).
  
  -spec delete_config({{string(), string()}, _Value}) -> ok.
  delete_config({Section, Key}) ->
      ok = couch_config:delete(Section, Key).
  
  -spec file_names(string(), string()) -> string().
  file_names(Name, Version) ->
    filename:join(
      [plugin_dir(), get_file_slug(Name, Version),
       "priv", "default.d", "*.ini"]).
  
  %% * * *
  
  
  %% Code Path Management
  %% The Erlang code path is where the Erlang runtime looks for `.beam`
  %% files to load on, say, `application:load()`. Since plugin directories
  %% are created on demand and named after CouchDB and Erlang versions,
  %% we manage the Erlang code path semi-automatically here.
  
  -spec add_code_path(string(), string()) -> ok | {error, bad_directory}.
  add_code_path(Name, Version) ->
  