Choose color scheme

Ben's blog

  • 2nd time in less than 6 months

    That we get hit with completely unforecast high winds; like last time, old timers tell me they’ve never seen something like this. We lost many trees, and among other things, the solar panels went flying. I will definitely take this new reality in consideration for future building projects.

    The only photo taken during, it didn’t last very long but it was completely insane.


    The aftermath, the forest is a mess of huge trees having domino’d on one another


    Right at the edge of the field, looks like the storm has made some decisions for me.

    IMG_5585Well fuckIMG_2797

    Fortunately, none of the panels were cracked. We were back online on battery the same evening and I brought back 2/3rd of the panels the next morning (which is plenty in the Summer). I bought ground anchors and will modify the panel holders for more strength. It’s amazing they moved, they weight a ton.

  • Shingling exterior walls


    It’s hard to keep up with posting about all the projects going on this Summer. This one however is very satisfying to go through for it gives you an idea of how beautiful the house will look when it’s finished.

  • It’s been a year, the impact that living off-grid has had

    WARNING: wall of text ahead

    It’s hard to believe we are already on the first anniversary of living in our small, off-grid, self-built rudimentary house. We’ve learned a lot since we moved to Vermont, this past year in particular saw a great expansion of newly acquired skills & knowledge. Some due to the necessity of the circumstances we shaped for ourselves, some due to the opportunities these circumstances yielded. 5 new categories saw the light of the day on this blog, nicely describing our expansion: building, water, solar power, maple syrup & foraging.

    This first year was obviously critical, whether or not we could make it through all seasons could have had disastrous consequences on our livelihoods. We didn’t really have the option not to make it either, so there’s that. As with many things we do in life, we calculated risks, and at some point pulled the trigger and put ourselves in a situation we couldn’t walk back from so we had to deal with forging ahead. This approach I realize is a pattern in our lives and critical to the most fruitful steps we’ve taken. So we planned for the worst case scenario, mentally, financially and physically. And truly, it wasn’t that bad. In fact it’s barely harder than what we had been doing so far, with some nice improvements to make things easier.

    I’d be lying if I said I didn’t have a rough time during construction, I wouldn’t recommend this to everyone. On the other hand, living in a small house with no grid utilities is not that bad at all. This I would recommend to anyone. We do have more chores as a result but they are offset to some extent by simplicity gains. They are more largely offset by optimizations we implement and experience we gain.

    Examples of simplicity gains:

    • no bills
    • no appliances to maintain
    • no impactful power outages

    Examples of optimization gains:

    • rudimentary plumbing to evacuate gray water
    • bringing water closer to the house
    • running a power cord from the solar shed to the house

    Examples of experience gains:

    • timing chores better
    • using less water for everything
    • slowly adapting what we eat


    One of the interesting side-effect of our new lifestyle is how weirdly frugal we have become. We always were, but it’s different now. When we heated with expensive propane, I used to worry about inside temperature being too high or doors being open too long. With wood heat, we now have a very warm house with open doors in the Winter, and I couldn’t care less about either. When we bought maple syrup we would barely use any and a jar would last us months. Having produced several gallons of our own syrup, we use it every day in quantities largely sufficient to achieve deliciousness.

    On the other hand, I have a hard time sharing this abundance with people who don’t realize how much work goes into producing it. I have no problem sharing with someone who can truly appreciate the gifts for what they represent. Such is the case for the growing list of consumables we produce ourselves: wood, maple syrup, honey, applesauce, veggies, soap, et cetera.

    Our perception is altered both by the abundance our land gives us, and by how it now translates not to money but rather to hard work.

    And our land does give us abundance. I’m always amazed by just how much of everything it gives us. Space for projects, Sun exposure, apples, field for hay, flowers, trees for lumber, trees for sap, trees for firewood, mushrooms, wild edibles. All in quantities that can keep our family satisfied for generations with no impact on the environment. But it’s not just the things we get, it’s also the opportunities presented. We get to entertain many ideas such as building cabins to rent out, selling a piece, growing pot, unposting the land to get a doe tag. It doesn’t matter how feasible or silly, these options are available now and they are added to the list of opportunities we can seize in life. I don’t like saying this for the connotations it evokes, but owning this much land is awesome for all it gives you in things and opportunities. We did not foresee how much abundance these acres would provide going in. We have every intention of leaving a large majority of this land untouched. of the ~50 acres, we’ll use 5 or 6 and let the rest be. This means a good piece of forest and a large marsh used by much wildlife. We feel privileged to have a say in the conservation of these natural resources and to be at the front row of the great spectacle that is watching them every day.

    Small space

    Back to more mundane matters, living in a small house is ok but ultimately it will need to grow a bit; we think that we’ll want to double our current 450 square feet to be happy. We’ve learned the importance of vertical space; having 8 feet walls helps in making the space feel bigger and in being able to store things. A few nails up walls will go a long way in the absence of shelving. Custom shelving which fills nooks and crannies is invaluable. What we lack now is a place to hangout that isn’t a path, more storage, a bedroom for a growing kid, a shower room, and, above all things, a mud room. So we’ll grow the house.

    The effects of this lifestyle

    We’re definitely more self-reliant there is no question there. I’ll speak only for myself here but for me, this means 2 things. First I feel a lot freer to think. The best way that I can describe it is that by depending less on something or not at all, I feel like I can view it more impartially. For example, we depend wayyyyy less on industrial food production, so it’s much easier to judge it as the shit system producing shit food at the cost of the environment that it is. I can say this without feeling guilty because I don’t participate. Simply put, living in accordance to your principles gives you the moral high ground to judge with no restraint from subjective guilt. Not the humblest thing to say but it’s true. Fortunately or unfortunately, given the rebellious tendencies I’ve dragged with me since my teenage years, this often leads me to say “fuck the system” whatever that may be at the time of the conversation. Industrial food, banks, some corporations, most politicians, stupid laws, globalization, greed, you name it. I don’t need to tone down my thinking anymore because the less I participate, the less interest I have in preserving a status quo I don’t like.

    Adding to this, I’m also making a conscious effort to not engage any information that isn’t local. I’ve been pretty successful at turning off the myriad of ways in which world events can get to my brain. It’s liberating. Somehow today we are expected to worry and have opinions about everything happening around world. It’s unsustainable for my sanity to do this. This ties into many other discussions about globalization, the local movement and competition for attention in the information age. But for me right now, I call it quits. The same way we are successfully refocusing the cycles that sustain us to be more local, I am doing so with information. My new rules for news are: Can I verify the information? Could I do something about it? Letting myself be convinced that we need to bomb some new place certainly does not qualify as “doing something about it”. The same way I’m closing the door on the global world and all its global issues, I’m also making a conscious effort to open up to my community. Talking to people, helping, participating in community events, definitely having opinions on issues, et cetera. It’s not always easy because my week ends are precious time for projects but I try.

    Another effect this lifestyle has on us is how much more rewarding we think everything is. We work a lot  harder to get anything and it’s often in the context of lifetime accomplishments. For example, a warm house is the reward not only of wood that was cut, split & moved; it also means developing the ability, tools and strength to do it.

    Remaining work

    This is a still work in progress, we took a giant step last year but we still need to bring home more than a few cycles. We need to use the hay in the fields for the chickens, dig a root cellar, start seed saving. We need to plant more low maintenance edibles which could potentially bring in money down the road. Our vision is that in 3 years, the land is payed off. In 5 years, the house is finished. In 10 years we have all the edibles in the ground, and finally in 20 years we can cruise and consolidate everything into the least amount of work it would take to keep things going the way they are. At this point the land taxes are payed by projects on the land (selling blueberries? AirBNB cabin?), which also supplement our income. All our basic needs are covered by ourselves or trading locally and we don’t need much else. If we don’t have bills and don’t need to come up with money for taxes or basic needs, we’ll get to consider how much of an income we really need. I’ll be in my mid-50s, Nicole in her late 40s. But who knows, a lot can happen in 20 years.

  • Shelving

    We were in such dire need of storage I didn’t even get to finish the shelves before they were filled. Having custom made shelves is amazingly efficient. I even cut around the 2x4s of the wall behind to gain 3.5″ which is a lot of room in a small house. The finish work is small and will likely happen in the next week to 30 years.


  • Looks like there was an attempt at replacing me with a robot

    Following the robot son, an attempt was made to replace me, Dad, with a robot.IMG_1926

  • All right, all right, the stupid septic is in

    State mandated expense of $5500, I’ll avoid bitching too much about it but it’s hard to swallow for the expense and the lifestyle it enforces.

    Concentrate excretions in a huge tank buried where no one can see it.IMG_0002

    Scar your land with giant trenches dug by an excavator the size of your house.IMG_4957

    Replace your great soil with stones and plastic to process a few gallons of effluent. IMG_0010 IMG_0023

    Thankfully, Vermont abounds with great people. I rode the bucket down the tank pit 😀 I wouldn’t say that the ride was worth $5500 but maybe if I could drive the excavator a bit we’d be there. I got to decrease my bill and learn the ins and outs of my septic system by working alongside Eric & E.J.. I hope people like them never go away.


  • Adding collaborative editing to the Ace web code editor with web sockets

    Using Ace‘s excellent API, it is relatively easy to enhance it to allow for live collaborative editing.

    The gist of what we’re doing here is to use Ace’s API for extracting and applying delta when changes occur in the editor. Then we simply transmit them over a websocket that all clients are connected to. This example is functional but in no way comprehensive to what a full code editing collaboration could be. It’s meant to be simple thus understandable. It’s a great starting point for whatever other pieces of functionality you want to send across web sockets.

    Loading Ace in a webpage with some custom Javascript

    This is what your web page looks like, load Ace as instructed and add Javascript to handle interaction with the websocket server.

    <!DOCTYPE html>
    <html lang="en">
            <title>Collaborative Ace Coding!</title>
            <style type="text/css" media="screen">
                #editor { 
                    position: absolute;
                    top: 0;
                    right: 0;
                    bottom: 0;
                    left: 0;
            <script src="https://<?=$_SERVER['HTTP_HOST']?>:1337/"></script>
            <script src="ace-builds/src/ace.js" type="text/javascript" charset="utf-8"></script>
            <script src="ace-builds/src/ext-language_tools.js"></script>
                var session_id = null ;
                var editor = null ;
                var collaborator = null ;
                var buffer_dumped = false ;
                var last_applied_change = null ;
                var just_cleared_buffer = null ;
                function Collaborator( session_id ) {
                    this.collaboration_socket = io.connect( "", {query:'session_id=' + session_id} ) ;
                    this.collaboration_socket.on( "change", function(delta) {
                        delta = JSON.parse( delta ) ;
                        last_applied_change = delta ;
                        editor.getSession().getDocument().applyDeltas( [delta] ) ;
                    }.bind() ) ;
                    this.collaboration_socket.on( "clear_buffer", function() {
                        just_cleared_buffer = true ;
                        console.log( "setting editor empty" ) ;
                        editor.setValue( "" ) ;
                    }.bind() ) ;
                Collaborator.prototype.change = function( delta ) {
                    this.collaboration_socket.emit( "change", delta ) ;
                Collaborator.prototype.clear_buffer = function() {
                    this.collaboration_socket.emit( "clear_buffer" ) ;
                Collaborator.prototype.dump_buffer = function() {
                    this.collaboration_socket.emit( "dump_buffer" ) ;
                function body_loaded() {
                    session_id = "meow" ;
                    editor = ace.edit( "editor" ) ;
                    collaborator = new Collaborator( session_id ) ;
                    // registering change callback
                    editor.on( "change", function( e ) {
                        // TODO, we could make things more efficient and not likely to conflict by keeping track of change IDs
                        if( last_applied_change!=e && !just_cleared_buffer ) {
                            collaborator.change( JSON.stringify(e) ) ;
                        just_cleared_buffer = false ;
                    }, false );
                    editor.setTheme( "ace/theme/monokai") ;
                    editor.$blockScrolling = Infinity ;
                    collaborator.dump_buffer() ;
                    document.getElementsByTagName('textarea')[0].focus() ;
                    last_applied_change = null ;
                    just_cleared_buffer = false ;
        <body onLoad="body_loaded()">
            <div id="editor"></div>

    Parallel to this, run the following Node.js server script

    Following is the Node.js websocket server which must be instantiated on the same server serving the web page above. It needs to be up for the page above to work.

    1. Make sure to have port 1337 open in the same capacity as ports 80 & 443, this is what this listens on.
    2. Make sure to update the paths to SSL certs, we use SSL on the websocket server. We do SSL here so browsers can run the websocket Javascript regardless of whether their original context it SSL or not.
    3. You need to have Socket.IO installed
    // config variables
    verbose = false ;
    session_directory = "/tmp" ; // it has to exist
    /* https specific */
    var https = require('https'),
        fs =    require('fs');
    var options = {
        key:    fs.readFileSync('/path/to/your/ssl.key'),
        cert:   fs.readFileSync('/path/to/your/ssl.crt'),
        ca:     fs.readFileSync('/path/to/your/CA.crt')
    var app = https.createServer(options);
    io = require('').listen(app);     // server listens to https connections
    app.listen(1337, "");
    // will use the following for file IO
    var fs = require( "fs" ) ;
    //io = require('').listen(2015) ;
    if( verbose ) { console.log( "> server launched" ) ; }
    collaborations = [] ;
    socket_id_to_session_id = [] ;
    io.sockets.on('connection', function(socket) {
        var session_id = socket.manager.handshaken[].query['session_id'] ;
        socket_id_to_session_id[] = session_id ;
        if( verbose ) { console.log( session_id + " connected on socket " + ) ; }
        if( !(session_id in collaborations) ) {
            // not in memory but is is on the filesystem?
            if( file_exists(session_directory + "/" + session_id) ) {
                if( verbose ) { console.log( "   session terminated previously, pulling back from filesystem" ) ; }
                var data = read_file( session_directory + "/" + session_id ) ;
                if( data!==false ) {
                    collaborations[session_id] = {'cached_instructions':JSON.parse(data), 'participants':[]} ;
                } else {
                    // something went wrong, we start from scratch
                    collaborations[session_id] = {'cached_instructions':[], 'participants':[]} ;
            } else {
                if( verbose ) { console.log( "   creating new session" ) ; }
                collaborations[session_id] = {'cached_instructions':[], 'participants':[]} ;
        collaborations[session_id]['participants'].push( ) ;
        socket.on('change', function( delta ) {
            if( verbose ) { console.log( "change " + socket_id_to_session_id[] + " " + delta ) ; }
            if( socket_id_to_session_id[] in collaborations ) {
                collaborations[socket_id_to_session_id[]]['cached_instructions'].push( ["change", delta,] ) ;
                for( var i=0 ; i<collaborations[session_id]['participants'].length ; i++ ) {
                    if(!=collaborations[session_id]['participants'][i] ) {
                        io.sockets.socket(collaborations[session_id]['participants'][i]).emit( "change", delta ) ;
            } else {
                if( verbose ) { console.log( "WARNING: could not tie socket_id to any collaboration" ) ; }
        socket.on('change_selection', function( selections ) {
            if( verbose ) { console.log( "change_selection " + socket_id_to_session_id[] + " " + selections ) ; }
            if( socket_id_to_session_id[] in collaborations ) {
                for( var i=0 ; i<collaborations[session_id]['participants'].length ; i++ ) {
                    if(!=collaborations[session_id]['participants'][i] ) {
                        io.sockets.socket(collaborations[session_id]['participants'][i]).emit( "change_selection", selections ) ;
            } else {
                if( verbose ) { console.log( "WARNING: could not tie socket_id to any collaboration" ) ; }
        socket.on('clear_buffer', function() {
            if( verbose ) { console.log( "clear_buffer " + socket_id_to_session_id[] ) ; }
            if( socket_id_to_session_id[] in collaborations ) {
                collaborations[socket_id_to_session_id[]]['cached_instructions'] = [] ;
                for( var i=0 ; i<collaborations[session_id]['participants'].length ; i++ ) {
                    if(!=collaborations[session_id]['participants'][i] ) {
                        io.sockets.socket(collaborations[session_id]['participants'][i]).emit( "clear_buffer" ) ;
            } else {
                if( verbose ) { console.log( "WARNING: could not tie socket_id to any collaboration" ) ; }
        socket.on('dump_buffer', function() {
            if( verbose ) { console.log( "dump_buffer " + socket_id_to_session_id[] ) ; }
            if( socket_id_to_session_id[] in collaborations ) {
                for( var i=0 ; i<collaborations[socket_id_to_session_id[]]['cached_instructions'].length ; i++ ) {
                    socket.emit( collaborations[socket_id_to_session_id[]]['cached_instructions'][i][0], collaborations[socket_id_to_session_id[]]['cached_instructions'][i][1] ) ;
            } else {
                if( verbose ) { console.log( "WARNING: could not tie socket_id to any collaboration" ) ; }
            socket.emit( "buffer_dumped" ) ;
        socket.on('disconnect', function () {
            console.log( socket_id_to_session_id[] + " disconnected" ) ;
            var found_and_removed = false ;
            if( socket_id_to_session_id[] in collaborations ) {
                //var index = collaborations[socket_id_to_session_id[]].participants.indexOf( ) ;
                var index = collaborations[socket_id_to_session_id[]]['participants'].indexOf( ) ;
                if( index>-1 ) {
                    //collaborations[socket_id_to_session_id[]].participants.splice( index, 1 ) ;
                    collaborations[socket_id_to_session_id[]]['participants'].splice( index, 1 ) ;
                    found_and_removed = true ;
                    //if( collaborations[socket_id_to_session_id[]].participants.length==0 ) {
                    if( collaborations[socket_id_to_session_id[]]['participants'].length==0 ) {
                        if( verbose ) { console.log( "last participant in collaboration, committing to disk & removing from memory" ) ; }
                        // no one is left in this session, we commit it to disk & remove it from memory
                        write_file( session_directory + "/" + socket_id_to_session_id[], JSON.stringify(collaborations[socket_id_to_session_id[]]['cached_instructions']) ) ;
                        delete collaborations[socket_id_to_session_id[]] ;
            if( !found_and_removed ) {
                console.log( "WARNING: could not tie socket_id to any collaboration" ) ;
            console.log( collaborations ) ;
    function write_file( path, data ) {
        try {
            fs.writeFileSync( path, data ) ;
            return true ;
        } catch( e ) {
            return false ;
    function read_file( path ) {
        try {
            var data = fs.readFileSync( path ) ;
            return data ;
        } catch( e ) {
            return false
    function file_exists( path ) {
        try {
            stats = fs.lstatSync( path ) ;
            if (stats.isFile()) {
                return true ;
        } catch( e ) {
            return false ;
        // we should not reach that point
        return false ;
  • Cool Duplo Project #37 – Vertical Axis Wind Spinner Failed Prototype

    The tower is cool but not super stable and the “spoons” are very heavy to move. Trial outside was a failure.IMG_1991