diff --git a/README.md b/README.md
index 309c1918127a0caf60f1c7982280c9175d2af983..41eb652f63a749861c6938bcf5089953857ea44f 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,13 @@
       - If the text can not be found, it is because your insert transaction still isn't in the blockchain. Wait a bit and try again.
     - Try the basic `explorer.sh`. It follows "latest" by default, but you can specify a block number as argument, e.g. `explorer.sh 0` to see genesis (block 0).
     - Try out `walker.pl`
+12. Install node.js so you can do better scripts locally:
+    `sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 68576280`
+    `sudo apt-add-repository "deb https://deb.nodesource.com/node_7.x $(lsb_release -sc) main"`
+    `sudo apt-get update`
+    `sudo apt-get install nodejs`
+    `npm init -y`
+    `npm install web3`
 
 There are other "interesting" programs in the bin/ and src/ directories.
 
diff --git a/bin/GasAdmin.js b/bin/GasAdmin.js
new file mode 100755
index 0000000000000000000000000000000000000000..048d33896454672fa1c60ca2d634ecddebc73104
--- /dev/null
+++ b/bin/GasAdmin.js
@@ -0,0 +1,293 @@
+#!/usr/bin/node
+
+var     port        =   14349;      // cloud
+port                =   16437;      // bc
+const   networkdir  =   'network5445';
+const   readline    =   require('readline');
+const   rl          =   readline.createInterface( { input: process.stdin, output: process.stdout } );
+const   Web3        =   require('web3');
+const   fs          =   require('fs');
+const   Personal    =   require('web3-eth-personal');
+var     web3;
+var     GasWell;
+var     from;
+var     contractbalance;
+var     contractaddr;
+
+function    fatal( txt )
+{
+    console.log( txt );
+    process.exit( 1 );
+}
+
+function    init()
+{
+    if ( process.env.BFAHOME == undefined )
+        fatal( "$BFAHOME not set. Did you source bfa/bin/env ?" );
+    web3            =   new Web3( "http://127.0.0.1:"+port );
+    //accounts      =   new Accounts( web3 );
+    var     abi     =   "";
+    contractaddr    =   fs.realpathSync([ process.env.BFAHOME, networkdir, 'contracts', 'GasWell' ].join('/'));
+    if ( contractaddr == undefined )
+        fatal( "I can't seem to find the contract directory containing the Gas Well's ABI" );
+    contractaddr    =   contractaddr.replace(/^.*\//, '');
+    var     abipath =   [ process.env.BFAHOME, networkdir, 'contracts', contractaddr, 'abi' ].join('/');
+    var     abifile =   fs.createReadStream( abipath )
+        .on('readable', ()          => {
+            var     data;
+            while (data = abifile.read())
+                abi     +=  data;
+            })
+        .on('end',     ()           =>  {
+            GasWell     =   new web3.eth.Contract( JSON.parse(abi), contractaddr );
+            web3.eth.getBalance( contractaddr ).then( function(v){contractbalance=v} );
+            getlist();
+            })
+        ;
+    getAccount();
+}
+
+function    isNumeric(n) {
+    return !isNaN(parseFloat(n)) && isFinite(n);
+}
+
+function    isAddr(n) {
+    return n.length == 42 && n.substring(0,2) == "0x";
+}
+
+
+function    getAccount()
+{
+    var personal        =   new Personal( web3 );
+    personal.getAccounts().then(
+        function gotPersonalAccounts(obj) {
+            console.log("Setting default account to "+ obj[0]);
+            from        =   obj[0];
+            web3.eth.defaultAccount = obj[0];
+        },
+        function failedGettingPersonalAccounts(err){
+            fatal ("Did you remember to allow 'personal' via the RPC port? " + err)
+        }
+    );
+}
+
+function    getpos(i)
+{
+    var arr;
+    var p           =   GasWell.methods.atPosition(i).call()
+    .then(
+        function gotOneAccount(result) {
+            console.log( "CC: "+result);
+            console.log( "C1: "+result[0]);
+            arr     =   result;
+        },
+        function gotOneAccountError(err) {
+            console.log( "DD: "+err);
+            console.log(err);
+        }
+    );
+    return arr;
+}
+
+function    wellSort(a,b)
+{
+    if ( b == undefined )
+    {
+        if ( a == undefined )
+            return 0;
+        else
+            return -1;
+    }
+    if ( a == undefined )
+        return 1;
+    var strA    =   a[0].toLowerCase();
+    var strB    =   b[0].toLowerCase();
+    if ( strA < strB )
+        return -1;
+    if ( strA > strB )
+        return 1;
+    return 0;
+}
+
+function    requestBalances( count )
+{
+    var     well    =   new Array;
+    var     proms   =   new Array;
+    var     i;
+    for ( i=0; i<count; i++ )
+    {
+        proms.push(
+            GasWell.methods.atPosition(i).call( {} )
+                .then(
+                    function(res){
+                        well.push(res);
+                    },
+                    function(err) { console.log("Fetching position data failed: "+err) }
+                )
+        );
+    }
+    Promise.all( proms ).then(
+        function(x) {
+            // The Well has now been filled out
+            // so we will ask for the balances of the found accounts
+            var     p2          =   new Array();
+            for ( i=0; i<count; i++ )
+            {
+                var     cb      =   setBal.bind(null,well,i);
+                p2.push( web3.eth.getBalance( well[i][0] ).then(cb) );
+            }
+            Promise.all( p2 ).then(
+                function allbalances(a) { displayBalances( well ) },
+                function(err) { console.log("Getting balances failed: "+err) }
+            );
+        },
+        function(err) { console.log("Getting account list failed: "+err) }
+    );
+}
+
+function    setBal( arr, idx, val )
+{
+    arr[idx][2]=val;
+}
+
+function    editAccount( entry, well )
+{
+    if ( entry == undefined )
+        return;
+    var     acct;
+    var     value;
+    // it is an existing account address?
+    if ( isAddr(entry) )
+    {
+        var     i       =   0;
+        var     n       =   well.length;
+        while ( i < n )
+        {
+            if ( (""+well[i][0]).toLowerCase() == (""+entry).toLowerCase() )
+                entry   =   i;
+            i++;
+        }
+    }
+    // it is a new account address?
+    if ( isAddr(entry) )
+    {
+        acct            =   entry;
+        value           =   0;
+    }
+    else
+    if  ( isNumeric(entry) && entry < well.length )
+    {
+        acct            =   well[entry][0];
+        value           =   well[entry][1];
+    }
+    else
+    if ( entry == "x" )
+    {
+        // trigger Gas Well distribution
+        GasWell.methods.distribute().send( {"from": from, "gas": 1000000 } )
+        .then(
+            function distOK(x) {
+                console.log("Distribute returned succesfully in block# "+x.blockNumber+" using "+x.gasUsed+" gas.");
+                getlist();
+            },
+            function distFail(x) {
+                console.log("Distribute returned errors in block# "+x.blockNumber+" using "+x.gasUsed+" gas.");
+                console.log(x);
+                process.exit( 1 );
+            }
+        );
+        return;
+    }
+    else
+        fatal("I don't know what to do with \""+entry+"\"." );
+    rl.question("Adjust the Mwei fill value of "+acct+" (setting to 0 is the same as deleting)\nAmount?: ", (answer) => {
+        if ( isNumeric(answer) )
+        {
+            answer      *=  1000000;
+            console.log("Sending update to the Gas Well...");
+            GasWell.methods.setEtherAllowance(acct,answer).send( {"from": from } )
+            .then(
+                function(a){
+                    console.log("Update accepted.")
+                    getlist();
+                },
+                function(b){
+                    fatal("\nMaybe you are not authorized:\n"+b+"\n\n\nI think you should leave now.\n");
+                }
+            )
+            ;
+        }
+        else
+            fatal( "I have no idea what to do with \""+answer+"\"." );
+        rl.close;
+    });
+}
+
+function    displayBalances( well )
+{
+    var     n       =   well.length;
+    var     i;
+    if ( well == undefined )
+        fatal( "Bank is not defined." );
+    well.sort(wellSort);
+    console.log("The contract's account ("+contractaddr+") has "+Math.floor(contractbalance/1000000)+" Mwei.\n");
+    var     longestbefore   =   1;
+    var     longestafter    =   9;
+    for ( i=0; i<n; i++ )
+    {
+        var len =   Math.floor(well[i][1]/1000000).toString().length;
+        if ( len > longestbefore )
+            longestbefore = len;
+    }
+    for ( i=0; i<n; i++ )
+    {
+        var     entry   =   well[i];
+        if ( entry == undefined )
+            console.log( i+": <undef>" );
+        else
+        {
+            var     numstr  =   ""+well[i][1]/1000000;
+            var     before  =   numstr;
+            var     after   =   "";
+            if ( numstr.search(/\./) > -1 )
+            {
+                before      =   numstr.replace(/\.[0-9]+$/, '');
+                after       =   numstr.replace(/^[0-9]*\./, '');
+            }
+            while ( before.length < longestbefore )
+                before      =   " "+before;
+            while ( after.length < longestafter )
+                after       +=  "0";
+            numstr          =   before+"."+after;
+            var     has     =   well[i][2].toString();
+            if ( has.length > 9 )
+                has         =   has.replace(/[0-9]{9}$/, ".$&");
+            console.log( i+": "+well[i][0]+" fills to "+numstr+" Mwei (has "+has+")." );
+        }
+    }
+    console.log("\n[ Q=quit x=distribute ]");
+    rl.question("Which account to edit (enter index number of full account number)?: ",
+        (answer) => {
+            if ( answer != undefined )
+            {
+                if ( (""+answer).toUpperCase() == 'Q' )
+                    process.exit( 0 );
+                else
+                    editAccount(answer, well);
+            }
+            rl.close;
+        }
+    )
+}
+
+function    getlist()
+{
+    GasWell.methods.numberOfBeneficiaries()
+    .call()
+    .then(
+        requestBalances,
+        function beneficiaryFail(x){console.log(x)}
+    );
+}
+
+init();
diff --git a/bin/GasAdmin.sh b/bin/GasAdmin.sh
new file mode 100755
index 0000000000000000000000000000000000000000..bf24c32a84cd632aae916f4dacb4a210103e63a5
--- /dev/null
+++ b/bin/GasAdmin.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+if [ -z "${BFAHOME}" ]; then echo "\$BFAHOME not set. Did you source bfa/bin/env ?" >&2; exit 1; fi
+source ${BFAHOME}/bin/libbfa.sh || exit 1
+
+# get number of accounts
+# get limit of every account
+# allow scroll up/down to select an account
+# press enter to edit an account's limit
+# press ins to add an account
+# press del to delete an account (set limit = 0)
+# press Q to quit.
+
+js=$(   mktemp  )
+out=$(  mktemp  )
+cleanup $js $out
+yes | head -1000
+
+function    admin
+{
+    while :
+    do
+        (
+            echo var contract = $( contract GasWell )
+            echo "var pos = contract.numberOfBeneficiaries.call();"
+            echo "while (pos-- > 0) { var r=contract.atPosition(pos); console.log(r[0]+':'+r[1]);}"
+        ) > $js
+cat $js
+        geth_attach < $js > $out
+cat $out
+        readarray -t < $out
+        # Delete last entry, because that's the "return value from our call to geth".
+        unset MAPFILE[$(( ${#MAPFILE[*]} - 1 ))]
+        if [ ${#MAPFILE[*]} -gt 0 ]
+        then
+            printf "%5s %-42s %10s\n" Index "Account address" Value
+            echo ''
+            for key in ${!MAPFILE[*]}
+            do
+                val=${MAPFILE[$key]}
+                printf "%5d %-42s %10s\n" $key ${val%:*} ${val#*:}
+            done
+            echo
+            echo '["+"=New entry, Q=quit, index number]'
+            read -p "Change which one of these: "
+        else
+            echo "No accounts found."
+            REPLY="+"
+        fi
+        if   [ "${REPLY^^}" = "Q" -o -z "${REPLY}" ]
+        then
+            return
+        elif [ "${REPLY}" = "+" ]
+        then
+            read -p "Enter new account address: " acct
+            if [ ${#acct} -eq 40 -a "${acct:0:2}" != "0x" ]
+            then
+                acct="0x${acct}"
+            fi
+            amount=0
+        elif [ "${REPLY}" != '+' ]; REPLY=$( echo ${REPLY} | sed 's/[^0-9]//' ); [ -n "${REPLY}" ]
+        then
+            if [ ${#MAPFILE[*]} -gt "${REPLY}" ]
+            then
+                amount=${MAPFILE[${REPLY}]}
+                acct=${amount%:*}
+                amount=${amount#*:}
+            fi
+        else
+            return
+        fi
+        echo '["DEL"=delete]'
+        read -i "${amount}" -p "Set value for account ${acct}: " amount
+        if [ "${amount^^:0:3}" = "DEL" ]
+        then
+            amount=0
+        fi
+        contractSendTx GasWell setEtherAllowance \"$acct\" ${amount} | geth_attach
+    done
+}
+
+admin
+
+#void                setEtherAllowance(      address, uint256    )
+#uint256             numberOfBeneficiaries(                      )
+#void                distribute(                                 )
+#uint256             getEtherAllowance(      address             )
diff --git a/bin/bfalog.sh b/bin/bfalog.sh
new file mode 100755
index 0000000000000000000000000000000000000000..69701e18e3be634005fd28e595aaaed6d058161c
--- /dev/null
+++ b/bin/bfalog.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+# Robert Martin-Legene <robert@nic.ar>
+
+if [ -z "${BFAHOME}" ]; then echo "\$BFAHOME not set. Did you source bfa/bin/env ?" >&2; exit 1; fi
+source ${BFAHOME}/bin/libbfa.sh || exit 1
+
+bfaconfig node
+exec tail -n 100 -F ${BFANODEDIR}/log
diff --git a/bin/selfDestructGasWell.sh b/bin/selfDestructGasWell.sh
new file mode 100755
index 0000000000000000000000000000000000000000..462305e8af671dfe0ff64e0318ca63265417a61c
--- /dev/null
+++ b/bin/selfDestructGasWell.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+if [ -z "${BFAHOME}" ]; then echo "\$BFAHOME not set. Did you source bfa/bin/env ?" >&2; exit 1; fi
+source ${BFAHOME}/bin/libbfa.sh || exit 1
+
+bfaconfig network
+contract="${BFANETWORKDIR}/contracts/GasWell"
+realdir=$(  realpath "${contract}"      )
+test    -r "${realdir}"
+address=$(  basename "${realdir}"       )
+test    -n "${address}"
+
+contractSendTx GasWell selfDestruct | tee /dev/tty | geth_attach
diff --git a/bin/triggerGasWell.sh b/bin/triggerGasWell.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a05234d90681d2a9e0712bbd5e44eb0fc646c213
--- /dev/null
+++ b/bin/triggerGasWell.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+if [ -z "${BFAHOME}" ]; then echo "\$BFAHOME not set. Did you source bfa/bin/env ?" >&2; exit 1; fi
+source ${BFAHOME}/bin/libbfa.sh || exit 1
+
+bfaconfig network
+contract="${BFANETWORKDIR}/contracts/GasWell"
+realdir=$(  realpath "${contract}"      )
+test    -r "${realdir}"
+address=$(  basename "${realdir}"       )
+test    -n "${address}"
+
+contractSendTx GasWell distribute | tee /dev/tty | geth_attach
diff --git a/src/contract.GasWell.solc b/src/contract.GasWell.solc
new file mode 100644
index 0000000000000000000000000000000000000000..0b7ca9d984162e9cc3d551761994fec12c972266
--- /dev/null
+++ b/src/contract.GasWell.solc
@@ -0,0 +1,114 @@
+// vim:filetype=javascript
+pragma solidity ^0.4.24;
+
+contract GasWell {
+    address     owner;
+    struct      Allowances {
+        address         beneficiary;
+        uint256         value;
+    }
+    Allowances[]        thelist;
+    // We use distpos to remember where we were stopped processing last time
+    // we were called. The idea is, that if we have too many accounts to take
+    // care of, and too little gasleft, then we stop before we run out of
+    // gas, since that would undo all the transactions we had already handled.
+    // Also, we don't want to favour anyone in particular in the list, such
+    // that some would have first priority in getting ether at every invocation
+    // So we continue checking the list from the same place where we left off
+    // at the previous invocation of distribute()
+    uint256             distpos;
+
+    constructor() public payable {
+        owner = msg.sender;
+    }
+    modifier onlyOwner {
+        require( msg.sender == owner );
+        _;
+    }
+    // Using this function, you can find out how long thelist is.
+    function numberOfBeneficiaries() public view returns (uint256) {
+        return thelist.length;
+    }
+    // Using this function, you get the address and "value" at a given position in thelist.
+    function atPosition( uint256 idx ) public view returns (address,uint256) {
+        require( idx <= thelist.length, "There are not that many addresses in the list." );
+        return (thelist[idx].beneficiary,thelist[idx].value);
+    }
+    // Returns a (signed) position of where an address can be found in thelist.
+    // Or returns -1  if the address is not found in thelist.
+    function _beneficiaryPosition( address beneficiary ) internal view returns (int256) {
+        uint256 pos =   thelist.length & 0x7fffffffffffffffffffffffffffffff;
+        while ( pos-- > 0 )
+            if ( beneficiary == thelist[pos].beneficiary )
+                return int256( pos & 0x7fffffffffffffffffffffffffffffff );
+        return -1;
+    }
+    // This function returns the "allowance" that a given address is set to.
+    // Using this function, you don't have to cycle through atPosition() until
+    // you find the address you want to know about.
+    function    getEtherAllowance( address beneficiary ) public view returns (uint256) {
+        int256  pos =   _beneficiaryPosition( beneficiary );
+        if ( pos == -1 )
+            return 0;
+        return thelist[uint256(pos)].value;
+    }
+    // This admin (ownerOnly) function allows the creator of the contract to
+    // add/change/delete "allowances" per address.
+    function    setEtherAllowance( address beneficiary, uint256 value ) public onlyOwner {
+        int256  pos =   _beneficiaryPosition( beneficiary );
+        if ( value > 0 ) {
+            if ( pos == -1 )
+                // Add the address to thelist if it was not already there
+                thelist.push( Allowances(beneficiary, value) );
+            else
+                // Simple update the value of this address
+                thelist[uint256(pos)].value    =   value;
+            return;
+        } else {
+            // The beneficiary is set to have 0 Ether, so we
+            // delete the beneficiary from the list
+            uint    i   =   uint256(pos) + 1;
+            while ( i++ < thelist.length )
+                thelist[i] = thelist[i+1];
+            // If distpos was past the position that we removed,
+            // then move that back one.
+            if ( distpos > uint256(pos) )
+                distpos--;
+            // Shorten the list
+            thelist.length--;
+        }
+    }
+    function    selfDestruct() public onlyOwner {
+        selfdestruct( owner );
+    }
+    function distribute() external {
+        uint256 listlength  =   thelist.length;
+        // Is there anything to do at all
+        if ( listlength == 0 )
+            return;
+        // Has the list gotten shorter since we we were last time?
+        // This shouldn't happen, but it's better to be safe than to be sorry.
+        if ( distpos >= listlength )
+            distpos         =   0;
+        uint256 wheretostop =   distpos;
+        while ( gasleft() > 54321 ) {
+            // Did we get to the end of the list, then start over
+            if ( ++distpos >= listlength )
+                distpos     =   0;
+            uint256 balance =   thelist[distpos].beneficiary.balance;
+            uint256 value   =   thelist[distpos].value;
+            if ( balance < value && (value+diff) > 0 )
+            {
+                uint256 diff                =   value - balance;
+                // we use send() instead of transfer(), because
+                // transfer() can throw(), and we don't want
+                // to stop processing because of a single error.
+                thelist[distpos].beneficiary.send( diff ) || true;
+            }
+            if ( wheretostop == distpos )
+                return;
+        }
+    }
+    function () external payable {
+    }
+}
diff --git a/src/contract.Sealers.solc b/src/contract.Sealers.solc
index 03804744d7b7758a192b1e2c1f34a38271955344..47ae489fe24a48ddaea4b76ad6316d1e142cac45 100644
--- a/src/contract.Sealers.solc
+++ b/src/contract.Sealers.solc
@@ -1,15 +1,21 @@
 pragma solidity ^0.4.22;
 
+// This contract is supposed to maintain the list of authorized sealers.
+// For this to work, a sealer must deploy the contract and then all sealers
+// must occasionally (every 5 minutes) run the related SealerSync.js
+
 contract Sealers {
 
+    // This struct contains a list of votes and who has voted for each victim/beneficiary.
+    // Votes taking longer than 30K blocks, will have to restart.
     struct Proposal {
 	address         victim;     // Whom are we voting about.
-        uint            votestart;  // In which block did this vote begin?
+        uint256         votestart;  // In which block did this vote begin?
 	bool		promotion;  // true=promotion, false=demotion
 	address[]	voters;     // List of voters.
     }
-    Proposal[]          public	adminproposals;
     address[]           public  sealers;
+    Proposal[]          public	sealerproposals;
 
     event               vote( address voter, address victim, bool promotionOrDemotion );
     event               adminChange( address admin, bool promotionOrDemotion );
@@ -18,107 +24,139 @@ contract Sealers {
         sealers[0] = msg.sender;
     }
 
-    function isSealer( address subj ) public view returns (bool) {
-        for (uint i=sealers.length; i>0; i--)
-        {
-            if (subj == sealers[i-1])
-                return true;
-        }
-        return false;
-    }
-    modifier onlySealersTX {
-        require( isSealer( tx.origin ), "tx.origin is not a known sealer and can not call this function." );
-        _;
+    // Public utility, works on any list needle and haystack given.
+    //
+    // Returns an index to the position of the needle inside haystack.
+    // 0 is first position. -1 means not found.
+    function findAddressInList( address[] haystack, address needle ) public pure returns (int256) {
+        uint256 i   =   haystack.length;
+        while ( i-- > 0 )
+            if ( needle == haystack[i] )
+                return int256(i & 0x7fffffffffffffffffffffffffffffff);
+        return -1;
     }
-    modifier onlySealers {
-        require( isSealer( msg.sender ), "msg.sender is not a known sealer and can not call this function." );
-        _;
+    function sealerIdx( address needle ) public view returns (int256) {
+        return findAddressInList( sealers, needle );
     }
-
-    function sealerLength() public view returns (uint) {
+    // This function is to be used to know how many sealers are in the sealers list.
+    function sealerLength() public view returns (uint256) {
         return sealers.length;
     }
-
-    function sealerPosition( uint idx ) public view returns (address) {
-        require( idx <= sealers.length, "There are not that many sealers registered in the list." );
+    // This function is to be used to get the address from a specific position in the sealers list.
+    // Remember first position is 0.
+    // Last position is sealers.length-1.
+    function sealerPosition( uint256 idx ) public view returns (address) {
+        require( idx < sealers.length, "There are not that many sealers registered in the list." );
         return sealers[idx];
     }
+    function isSealer( address subject ) public view returns (bool) {
+        return ( sealerIdx(subject) > -1 ); 
+    }
+    function requireSealer( address subject ) public view {
+        require( isSealer(subject), "Not sealer" );
+    }
 
+    function _remove_entry( uint256 idx, list alist ) private returns (list) {
+        uint256 pos     =   idx;
+        // Move all items in the list (after idx) one step closer to the
+        // front of the list.
+        while ( ++pos < list.length )
+            alist[pos-1] = alist[pos];
+        // "pop" the end of the list, making the list shorter.
+        alist.length--;
+        return alist;
+    }
+
+    // This function sees if any proposals have overstayed their welcome and thus
+    // needs to be removed.
     function _trimProposals() private {
-        uint    i   =   adminproposals.length;
-        while ( i-- > 0 )
+        for ( uint256 i = sealerproposals.length-1; i>=0; i-- )
         {
-            if ( adminproposals[i].votestart < block.number+30000 )
-            {
-                while ( i < adminproposals.length )
-                {
-                    adminproposals[i] = adminproposals[i+1];
-                    i--;
-                }
-                adminproposals.length--;
-            }
+            // If a proposal is more than 30K blocks old, then remove it from the list.
+            if ( sealerproposals[i].votestart + 30000 <= block.number )
+                sealerproposals = _remove_entry( i, sealerproposals );
         }
     }
 
-    function admin_promote( address victim, bool promotion ) public onlySealersTX {
-        // Janitor
-        _trimProposals();
-        bool    isS =   isSealer(victim);
+    function    promotionIdx( address victim, bool promotion ) public view return (int256) {
+	uint256	idx     =   sealerproposals.length;
+	while ( idx-- > 0)
+            if ( sealerproposals[idx].victim == victim && sealerproposals[idx].promotion == promotion )
+                return idx;
+        return -1;
+    }
+
+    // You can call this for free and know if your promote call
+    // will get accepted. Save the network, call this first.
+    function mayVote( address voter, address victim, bool promotion ) public view returns (bool)
+    {
+        // Is caller a sealer?
+        if ( !isSealer(voter) )
+            return false;
+
         // Is already Sealer and want to promote him?
-        if ( isS && promotion )
-            revert("You can't promote someone who is already a sealer.");
+        // Can't promote someone who is already a sealer.
+        if ( isSealer(victim) && promotion )
+            return false;
+
         // Is not Sealer and want to demote him?
-        if ( !isS && !promotion )
-            revert("You can't demote someone who is not a sealer.");
-        // First see if we can find the index of an already running proposal for this victim,promotion tupple.
-	uint	proppos =   adminproposals.length;
-	while ( proppos>0 && adminproposals[proppos-1].victim != victim && adminproposals[proppos-1].promotion != promotion)
-		proppos--;
-        // If we found no matching proposals, we will add it, so we can now vote on it.
-	if (proppos == 0)
+        // Can't demote someone who is not a sealer.
+        if ( !isSealer(victim) && !promotion )
+            return false;
+
+        // See if the voter is already in the list of voters for this [victim,promotion] tupple
+        int256  proppos     =   promotionIdx( victim, promotion );
+        if ( proppos > -1 && findAddressInList( sealerproposals[proppos].voters, voter ) > -1 )
+            return false;
+        return true;
+    }
+
+    // Calling this function will vote for adding an additional or
+    // removing an existing member of "the inner circle".
+    // As per usual, this requires n/2+1 votes.
+    // The boolean must be true if you want to add a sealer
+    // and false if you want to remove one.
+    function promote( address victim, bool promotion ) public {
+        if ( ! mayVote(msg.sender, victim, promotion))
+            revert("That seems redundant.");
+        _trimProposals();
+
+        // Send notification of the vote
+        emit vote( msg.sender, victim, promotion );
+
+        // signed as opposed to unsigned (int)
+        int256  signedretval    =   promotionIdx( victim, promotion );
+        uint    proppos;
+        if ( signedretval == -1 )
         {
-            address[] memory sillycompiler;
-	    proppos = adminproposals.push( Proposal(victim, block.number, promotion, sillycompiler ) );
+            // This is a new proposal, so we will add it, so we can vote on it.
+            address[] memory emptyAddressList;
+	    proppos = sealerproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
         }
-        // substract one, to make proppos actually reflect the position in the index.
-        proppos--;
+        else
+            proppos = uint256( signedretval & 0x7fffffffffffffffffffffffffffffff );
+
         // Make things a bit more easy to read by using a shorter variable name
-        Proposal memory prop = adminproposals[proppos];
-        // Now look through the proposal and see if this sender already voted.
-        uint    voterpos   =  prop.voters.length;
-        while ( voterpos>0 && prop.voters[voterpos-1] != msg.sender )
-            voterpos--;
-        // Return if sender already voted
-        if ( voterpos > 0 )
-            revert("You can not vote twice.");
-        // Send notification of the valid vote
-        emit vote( msg.sender, victim, promotion );
-        // Do we have enough votes to perform the operation?
+        Proposal memory prop = sealerproposals[proppos];
+
+        // Add our vote
+        prop.voters.push( msg.sender );
+
+        // Stop here if we do not have enough votes to perform the actual promotion/demotion
         if ( prop.voters.length < sealers.length/2+1 )
             return;
-        //
+
+        // Remove the proposal because the voting is complete.
+        sealerproposals =   _remove_entry( proppos, sealerproposals );
+
         // Is it a promotion or a demotion?
-        if ( prop.promotion )
-        {
+        if ( promotion )
+            // Add victim to sealer list
             sealers.push( victim );
-        }
         else
-        {
-            uint    i = sealers.length;
-            // Delete all occurences of the victim from the sealer list (should be just a single occurence)
-            while ( i-- > 0 ) {
-                if (sealers[i] == victim )
-                {
-                    for (uint j=i; j<sealers.length-1; j--)
-                        sealers[j] = sealers[j+1];
-                    sealers.length--;
-                }
-            }
-        }
-        // Remove the proposal, as the voting is complete.
-        for (i=proppos; i<adminproposals.length-1; i--)
-            adminproposals[i] = adminproposals[i+1];
-        adminproposals.length--;
+            // Remove victim from sealer list
+            sealers     =   _remove_entry( sealerIdx(victim), sealers );
+
         // Send notification
         emit adminChange( victim, promotion );
     }