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..3cf94f4e276f565cd89d6f5bf9854eb37c04d521
--- /dev/null
+++ b/bin/GasAdmin.js
@@ -0,0 +1,294 @@
+#!/usr/bin/node
+
+var     port        =   14349;      // cloud
+port                =   16437;      // bc
+const   contractaddr=   '0x283bc55557c08dbc4f902b2b8479a2201a47e1c1';
+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;
+
+function    init()
+{
+    if ( process.env.BFAHOME == undefined )
+    {
+        console.log( "$BFAHOME not set. Did you source bfa/bin/env ?" );
+        process.exit( 1 );
+    }
+    web3            =   new Web3( "http://127.0.0.1:"+port );
+    //accounts      =   new Accounts( web3 );
+    var     abi     =   "";
+    var     abifile =   fs.createReadStream(
+        process.env.BFAHOME+"/network5445/contracts/"+contractaddr+"/abi" )
+        .on('readable', ()          => {
+            var     data;
+            while (data = abifile.read())
+                abi     +=  data;
+            })
+        .on('end',     ()           =>  {
+            GasWell     =   new web3.eth.Contract( JSON.parse(abi), contractaddr );
+            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){
+            console.log("Did you remember to allow 'personal' via the RPC port? " + err)
+            process.exit( 1 );
+        }
+    );
+}
+
+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
+    {
+        console.log("I don't know what to do with \""+entry+"\"." );
+        process.exit( 1 );
+    }
+    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){
+                    console.log("\nMaybe you are not authorized:\n"+b+"\n\n\nI think you should leave now.\n");
+                    process.exit( 1 );
+                }
+            )
+            ;
+        }
+        else
+        {
+            console.log( "I have no idea what to do with \""+answer+"\"." );
+            process.exit( 1 );
+        }
+        rl.close;
+    });
+}
+
+function    displayBalances( well )
+{
+    var     n       =   well.length;
+    var     i;
+    if ( well == undefined )
+    {
+        console.log( "Bank is not defined." );
+        process.exit( 1 );
+    }
+    well.sort(wellSort);
+    console.log("");
+    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("");
+    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/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 {
+    }
+}