Implement `setRemote`, `multiSet()` and `freeze()`

This PR contains a lot of cleanup but it also contains
    three new features


You can now get and set remote keys in the config
    instance. The remote keys are backed by a different
    in memory configuration object and are meant to
    be used for dynamic keys that are mutable at runtime.


With the addition of `.getRemote()` there is a difference
    between the purpose of `.get()` and `.getRemote()`

 - `.get()`, immutable, static, local to the process.
 - `.getRemote()`, mutable, dynamic, remotely controlled.

To enforce the immutability of `.get()` you can now
    call `.freeze()` once you are done loading the
    configuration. This means all future `.set()`
    calls will throw an exception.

By using `.freeze()` it should be easier for developers
    to catch the "bug" of setting local configuration
    keys when they really wanted to set remote configuration
    keys.


For convenience you can now call `config.set({ ... })`
    which will set all top level key / value pairs.

Note that the rest of the commits are purely cleanup,
    a lot of code has changed.

It's recommended that you review commit by commit.

cc @sh1mmer

cc @Matt-Esch @jskelchy @tomuber See implementation of `getRemote()`

cc @lxe See implementation of `multiSet()`