[ { "title": "Kitchen Remodel", "url": "/kitchen-remodel/", "categories": "diy", "tags": "diy, kitchen, remodel, cabinet, cabinets, before after, white, modern", "date": "2026-10-13 12:00:00 -0400", "content": "My total kitchen gut and remodel. The design phase was difficult becuase i had to clear away the old wall, to add insulation into the wall cavity, there originally was none in the whole house so I took the opportunity to add some while I had no cabinets. I had to make a lot of measurements to make sure everythign would fit perfectly. I only had to take off one day of work, and was ablt to knock this out over a total of 4 days (demolition, removal of the wall, putting up the new wall and subfloor, then installation of the insulation, cabinets and electrical). I also took the opportunity to repaint the whole main floor for a refresh. On day 5 the countertop installers came to measure, and i had to wait 2 weeks for it to be cut and installed. Then i finikitchen it off in little pieces (thigns like backsplash i had to order, and that took a while). To be honest, the most annoying part of this whole build was reusing the original hole i made for the microwave 5 years ago. I got lucky and it was almost totally lined up with where it was supposed to be… almost. I had to build a custom vent piece to connect the microwave through the cabinet. View the full gallery The List Status Category Task Time Difficulty Notes ✅ 🧱 Demolition Remove old cabinets and prep the room 1-2 days Medium This was the first big step and made the space feel like a blank slate. ✅ 🏗️ Wall Work Remove the old wall and add insulation 1 day Medium The wall had to come down so the space could be insulated and the layout could be cleaned up. ✅ 🔨 Framing Rebuild the wall and subfloor area 1 day Medium This was a cleanup step that made the new layout consistent and solid. ✅ ⚡ Electrical Rework wiring and fit the cabinet layout 1 day Medium I had to make sure the microwave vent and cabinet spacing would still line up properly. ✅ 🏗️ Cabinets Install the new cabinetry and finish details 2 days Medium The main visual change came from the new white finish and tighter fit of the layout. ✅ 🔧 Countertops Measure and install the countertop 2 weeks total Medium There was a waiting period for fabrication, and it was one of the final big parts of the project. ✅ 🎨 Finish Paint, trim, and final cleanup 2-3 days Easy The room felt dramatically lighter and brighter once the new white finish went in. Construction Photos Demolition Framing + Drywall Cabinets Countertop + Backsplash Finish" }, { "title": "Building a Backyard Shed", "url": "/shed/", "categories": "diy", "tags": "diy, shed, carpentry, storage, backyard, exterior, build, tools", "date": "2026-10-04 12:00:00 -0400", "content": "This was a project i did in 2025. The original house came with a greenhouse that had been destroyed in a hailstorm at some point in the owners time. It has since been overgrown and left behind. I always had plans to use this area, and decided that a shed was the most fitting overtime. The project took from July 2025 to December 2025. I still have to build doors for it, but its been easy to put that off when its usable. I use this area for my tools and for material. It’s roughly 450 sqft, the gardenshed attached is still the original, I simply reroofed it and attached it to my new structure. The shed itself sits atop 4 inch concrete block. I had a structural engineer verify it can support the load of a single 2x4 wall and building with ease, The original footers were still intact. Clearing out the vegetation sucked, that was a big step. This was mostly I had to remove a large portion of the wall that was retaining soil, it had bowed and was destroyed. This was my first masonry job. Once the masonry was finished, I had to order 750$ of gravel to backfill the area, then more for the surrounding wall since i wanted to remove the dirt against the retaining wall portion of the structure (better for long term). The masonry was build with rebar and filled with concrete as i went, it should be far more structurally sound from here on. My brother and I spread the gravel, then I got to work on building the structure. I did it in 8 foot segments, this way when everything was prepared, i coudl have me and a few people (my family) help place the walls and we could secure them all without blowing out our backs, it worked fairly well. The trusses are king’s post trusses with light webbing support. They are secured with nails, and nailplates, the roof pitch is 4:12. After walls, and roof was up. I had a friend come up and help me get OSB onto the roof before setting up the roof, wrapping the house, and then did finishing touches like siding and fascia. View the full gallery Site Prep Foundation Framing Roofing Exterior Finish" }, { "title": "Front Porch Replacement", "url": "/front-porch/", "categories": "diy", "tags": "diy, porch, front porch, trex, deck, railing, exterior, remodel", "date": "2024-03-15 12:00:00 -0400", "content": "This project was done in early 2024 for a house that wasn’t mine, and the original front porch was a 20-year-old build that was rotting out. The owner wanted something that would last a lifetime, so the goal was to rebuild it properly rather than patch the old structure and hope for the best. The porch had no real footers, the framing was tired, and the stairs and landing were all part of the same failure point. I tore it down to the essentials and rebuilt it from the ground up with better drainage, better support, and a material choice that was built for long-term durability. View the full gallery The List Status Category Task Time Difficulty Notes ✅ 💣 Demolition Tear off the old porch and stairs 1-2 days Medium The rotten structure was failing in a few different spots, so it had to come out before anything new could be built. ✅ 🏗️ Foundation Pour new footers 2 days Hard There were no proper footers under the original porch, which was a major structural issue. ✅ 🔨 Framing Rebuild the deck framing and landing 3 days Hard New framing gave the porch a solid base and a better layout. ✅ 🧰 Weatherproofing Install butyl tape and flashing 1 day Medium This was important at the house connection to keep water out of the framing and ledger. ✅ 🔨 Decking Install Trex decking 2 days Medium Picture frame, standard trex full run layout ✅ 🔨 Stairs Build new stringers and stairs 3 day Hard The original stairs were part of the rot and had to be fully replaced. ✅ 🛡️ Railing Add railing and finish details 2 day Medium This made the porch safer and cleaned up the final look. ✅ 🎨 Finish Final cleanup and detail work 1 day Easy The new porch was set up to be a durable, practical entry instead of a quick repair. Key Notes The main issue was not just bad decking. The original porch had been built with little structural backup, and once we started tearing it apart, the rot and weak framing were obvious. It needed a real rebuild, not a repair. I paid close attention to water management. The new deck ledger, flashing, and butyl tape were all part of the plan because the porch sits right against the house. That kind of detailing matters a lot when a project is intended to last for decades. The final work included the new landing, stair layout, and rails, so the porch felt like a complete front-entry upgrade instead of just a replacement deck. It was a straightforward rebuild. Construction Photos I didn’t manage to snag a before photo, i’ll keep looking and update the article if i find one. After Photos" }, { "title": "Finishing 1000sqft Basement", "url": "/basement/", "categories": "diy", "tags": "diy, interior, house, 1950s, carpentry, remodel, windows, rustic, modern, basement, lvt, trim, siding", "date": "2024-03-03 12:00:00 -0500", "content": "I may do a mini-series of posts on this at some point, this was a long lived project, and will always have little touch-ups worth of work. If I do I’ll update the table below with links to the pages. This project was one I’ve wanted done for a long time, effectively doubling the square footage of this house, now up to 2800ish from 1500 when we bought the house. This was a very long and complicated project with a great many ups and downs, but all in all took about 1 full year to finish end to end with everything in between. This project required me to prepare everything for the future while working on it - I wanted to drywall the ceiling and have minimal access panels, this all therefore took a lot of work to get the basement into “finishing shape”. Basement Design The worst part of the design was positioning of everything we wanted. Comprimises had to be made several times due to the size of the basement. The unfinished basement had only the bathroom (already finished), and the closet at the bottom of the plan. The original garage was 30ft in size, so we will be capturing some of it back with a small office. We wanted to keep the laundry shoot, so the laundry room had to stay put where it was. The TV is hung directly in front of the window is the only flaw in the design. The TV could not be mounted facing the garage wall because of the support beam’s awkward placement in the imddle of the basement - right in front of where the seating would go. I had an option to seal the window, but I thought the extra light would be nice when not in use. I think this was probably a mistake tbh, but only time will tell. The List Status Category TODO Item Time taken Difficulty Notes ✔️ 🧰 General Clean out the basement 1 weeks Easy SO much crap had to be removed, a dumpster was rented for this. Another dumpster was later rented after drywall was completed. ✔️ 🧰 General Remediate water problems 2 weeks Medium Lots of painful manual labor, no help ✔️ 📐 Carpentry Basement Windows 1 week Easy Replaces single pane windows with double pane windows ✔️ 📔 Design Design basement 2-3 months Hard Concurrently happened while working on other things ✔️ 🧰 General Insulation 1 month Easy Foam board insulation, R14 ✔️ 🔨 Framing Subfloor 2 weeks Easy Drytek, R5, had help from a few friends ✔️ 🔨 Framing Office Framing 2 weeks Medium 30 foot garage turns into 20ft garage, small office added ✔️ 💣 Demolition Office door 3 days Hard Remove CMU between office Framing and basement ✔️ 💣 Demolition Remove Boiler and Concrete pad 3 days Hard Where old pad is locating becomes a bedroom, so must flatten the area. ✔️ 🔨 Framing Insulate office and install subfloor 1 day Easy R20 Insulation in floor joists, R14 rockwall and foamboard, for R28 surrounding office ✔️ ⚡ Electrical Rewire inlaw suite 1 month Hard Inlaw suite wired improperly, i had to run a new line over to the in law suite underground along with Plumbing ✔️ ⚡ Electrical Remove all junction boxes 3 weeks Medium Lots of wire tracing ✔️ 🔧 Plumbing Reroute all water lines 2 weeks Medium Pex manifold, condensing into one spot for bulkhead ✔️ ⚡ Electrical Add Subpanels 3 days Easy Rerouted a bunch of lines into 3 subpanels, this allows us to future expand for other remodels ✔️ 🔨 Framing Frame the basement 3 weeks Medium Large open room, 1 bedroom, 1 bathroom, 1 laundry room, 2 utility rooms, 1 closet ✔️ ⚡ Electrical (low voltage) Run lines for all speakers Easy 2 weeks 5.1.4 dolby atmos ✔️ ⚡ Electrical Install lights and switches 1 week -   ✔️ 🧰 General Reroute Radon Fan 1 week Part of demolition was to remove concrete floor around this small closet space. I instaled a french drain, sump pump, and radon fan.   ✔️ 🔧 Plumbing Rough in laundry room, and bar/kitchen area 1-2 days Easy   ✔️ 🔧 Plumbing Redo primary Septic stack 1-2 days Easy For piping consolidation into bulkhead ✔️ 🧰 General Insulate ceiling 3 days Easy Safe and sound to help prevent sound from traveling upstairs or downstairs. Applied to half the basement (home theater and under bedrooms) ✔️ 🔨 Framing Install Resilent Channel 1 days Easy From all the sound proofing advice i’ve found, a decoupling layer is the best, so this was done across the whole basement ceiling. ✔️ 🎨 Drywall Hang drywall 1-2 weeks Medium Had 2 batches of help do this. 93 sheets of drywall takes a toll on the body. Roughly 2 tonnes ✔️ 🎨 Drywall Spackle 4 weeks Hard No one wants to help with this lmao. It took forever, after work a few hours. Taping layer by far took the longest. ✔️ 🧰 General Paint 4 weeks Easy No one wants to help with this lmao. It took forever, after work a few hours. Taping layer by far took the longest. ✔️ 📐 Carpentry Trim 2 weeks Easy At the point where i was feeling done with the basement, so started taking it slow. Took forever to do the trim and caulk ✔️ 📐 Carpentry Install Cabinets 1 week Medium Basement is on a slope, so i had to level the cabinets. Butchers block ontop was stained and polyerathaned ✔️ ⚡ Electrical Install HVAC 1 week I got a pioneer minisplit that had a pre-charged compressor. All that was required was line evacuation. Hydronic heaters in office and bedroom.   👷 🧰 General Touchups Ongoing Easy Painting touch ups now that its lived in, painting some trim, gotta paint doors too - 🧰 General Finish storage area Did not start Easy Just want to hang some shelves and clean the floor in there so it isn’t just a “junk” closet After Photos Entertainment Area Theater Area Office Kitchen Area Bar Wine Cellar Murphy’s Door Bedroom Bathroom Ya it’s small, but it’s a full bath. Laundry Room The cabinet here is hiding 2 junction boxes, and a radon pipe. But is also used for storage. Mudroom Storage Closet The third photo is the second radon mitigation system I installed and a largely unnecessary sump pump." }, { "title": "S3GSecurity: A Simple Modern Successful Tech Stack", "url": "/modern-stack/", "categories": "development, computer-security", "tags": "software, architecture, full-stack, modern, mongo, mongodb, s3gsecurity, alterac, c#, csharp, javascript, react, react.js, .net", "date": "2023-04-24 12:00:00 -0400", "content": "A while ago I was asked by a friend (Corey Pritchard) at work to evaluate his application during beta testing to see if there was any problems. Noting a few small technical issues I ran into, it was technically sound. We talked about it for a while after that, and fast forward a year later and we have been working on this same project together ever since. S3G security is a training platform LMS (Learning Management System) that provides a business to business model to help train their employees on how to handle an active shooter situation. The course was architected by Jim Warwick, who has traveled across the United States providing different institutions with in-person training. Today I’m going to be discussing the small, but insanely powerful stack implemented under the hood on how we keep this website online with a 99.9% uptime. Requirements Engineering: Good software engineers cannot underestimate the power of communication with the customer, so let’s talk some Requirements Engineering. A Modern Sleek Agile Model Let’s not overcomplicate things, it’s a small team. Every week Corey meets with Jim to discuss new features and to live demo current features in development or testing. This is one of the coolest parts to me. Corey will ask about wording and styling of pages and change them on the fly for Jim, completely different relaxed feel from a typical customer demo. I wish more companies interactions with their clients were nearly as relaxed. Before we continue, let’s mention some core concepts of this application: Some Large Responsibilities of the Application: The application will have 3 primary user-facing roles. A “user” role who will be watching the videos and taking the training. A “management” role” for employers to keep track of whether users have completed their training, and an administrator role for Jim and his company to have complete control over the application and adjust as needed. The application will provided tracking of a video to the user role that will record whether or not the user has seen the videos in the training. The application will also quiz the user at the end of every video. Requirements Level Tools Gitlab is exclusively used to maintain all issues, and feature tracking. It’s important to not over complicate this step. The entire concept of requirements tracking boils down to a few simple core details: Effectively communicate requirements clearly to your team and the customers so everything is clear. Transparantly give deadline estimates - and be clear when estimates are falling behind or not tracking. Appropriately coordinate with customers with alternative viable options to accomplish their ultimate goals. It’s simple, so keep it simple. This is exactly what gitlab’s issue tracking offers, it’s all integrated with the development work flow so if you don’t need (and no one should) detailed metric tracking, you can ignore the concept. All that matters when you work with a customer is time estimates, money, and the features. The Company Stack When Corey first started he evaluated many different products on the market to come up with the most integrated approach to development. We both have worked at companys where this is an oversight: and you end up with 3 or four different poorly integrated developer tools that don’t synchronize effectively. The primary goal was to avoid this and make it so everything you need is in one spot while also being cost effective for his company. Concept Implementation Source Control Gitlab Issue and Feature Tracking Gitlab Deployments Gitlab Cloud architecture Fully Google Cloud (GCP) Developer Level Since S3Gs inception Corey has developed it with future developers in mind, which has made on-boarding simple. Let’s talk about the moving parts and what they mean to a Software Engineer: Backend When I present architectures, I like to start at the micro / software development level and work my way out, so I will be referencing the same pieces and we will work our way towards a macro scope of our full project C# is used as the backing language: starting in .net 6 and recently is in .net 7. The C# service is simple, effectively acting as a CRUD with fancy handling on the backend with a backing Mongo database. The Mongo integration is code-first. Providing the developers with the flexibility of adjusting the relatively simple models and collections overtime to accommodate the agile interactions he has with Jim. When a model needs to be altered a simple code change occurs. Each change to the code driven models is evaluated to be backwards compatible so as not to break the deployment. It will be discussed how breaking changes are handled during the deployment section. Front End The User Interface is a generated with React following their more modern functional programming dialect. The front end used to be decoupled from the backend, where requests are simply forward to the backend with a standard pass through reverse proxy that is integrated into the startup of the app. The point of this was an attempt to scale one of them in deployment but not the other. This was found to be relatively pointless as the load of the user interface was negligible during performance testing. The two (backend and front end) therefore are served together using SPA so only one docker container is used in production to maintain the front and backend. Testing The backend is tested using XUnit, a standard testing framework for .net core. There is 95% code coverage at the time of writing. When a feature is written it is a requirement to maintain coverage before it is submitted. The front end is unit tested minimally. Instead integration tests exists that cover the flow of the backend to front end using an awesome page object model integration that Selenium now provides. Most modern e2e frameworks are moving towards this paradigm. The lack of unit tests in the UI is a hot topic in the agile world. Your standard young software engineer would likely scoff at the thought of no unit tests in the user interface. When I was an intern it was a standard practice to slap some generic tests around your pages using Jest or Jasmine to make sure the UI is functioning as intended. But there really is no crazy logic going on, the logic is bound to the roles. This article will not go into too deep a dive on why I believe they (UI based tests) are an artifact of simple claiming a higher code coverage, but rest assured the core of the application is tested through the integration tests. Primary Backing Third Party Software Auth Firebase is used to keep track of authentication and authorization, this is because the stack is google cloud, roughly most user federations and SSO providers do the same thing so the choice isn’t complicated here. We simple go with what the stack supplies. Video provider Many video servicing softwares were evaluated during initial development. Ultimately the winner due to feature support was Vimeo. The primary downside to Vimeo is under the hood is has some whacky calls to it’s underlying CDN (content distribution network) that look like garbage. So we have to give the customers a whitelist for Vimeo specifically. Theming The theme is a third party supplied item built on-top of material ui. Branding and logo were all developers in-house, and the color palette is chosen based on the branding, everything else is built off the initial theme. Designing based on this prebuilt theme gave a solid foundation where theming and styling was never a concern during development. I would recommend this for any small company. UX development can be easy, but often incredibly tedious unless you live and breath the stuff. Simply choose a branding and stick with it. The important part is to make sure all subcomponents you import inherit from your theme, keep the experience consistent, and don’t retheme every page. These are the big ones (in my opinion) worth nothing. There are many smaller components that are used but have a smaller impact on the overall application. Devops As we have evolved our code base overtime, all of the features of gitlab have been fully unlocked. If you start your projects by using the full toolkit available to you, your life will be made easier overall. This is the methodology that we move forward with as we build and add more features to S3G. Continuous Integration Gitlab pipelines are leveraged for the build process. Each commit kicks off a multi stage process for build, testing, dockerizing,scanning, and an optional deployment. Displayed above are the first steps in the pipeline process. Leveraging all features of Gitlab And here are the remaining steps. Continuous Deployments Integration with GCP The docker containers are pushed to GCP in a private store associated with our account. We then have a helm chart in this single repository that contains the the configuration for how to orchestrate the deployment. The optional deployment uses the branch name slug as the subdomain and it is attached to the wildcard root domain. This domain is requested from google and is usually generated within a few seconds, however a dynamically generated certificate is requested from google that is slower. It takes roughly 30 minutes to provision. This is the only limitation we’ve run into for GCP since they don’t have wildcard certificates. The deployment is triggered through a manual step and this is used to verify features during our reviews and quality assurance testing. DAST scans are optionally applied after this manual step. Dynamic Domain Provisioning The deployment takes place using a helm chart. The modifications happen dynamically from some clever usages of integrated environment variables in gitlab. For these QA deployments the build is locked so you need a dynamically generated user and password to get in (in the event a crawler is trying to route to our private QA deployment). This is also done with some clever helm magic. Production Production deployments are done manually to prevent automation catastrophe. But the process is simple. We simply perform a helm upgrade on the production branch with the production gcp configuration. A tear down has never occurred. At the time of writing I believe it is on helm revision 60, all that happens is a simple chart change followed by the typical blue green deployment helm provides. There is no need to over engineer an application like this with canary or some other complicated deployment strategy at the time of writing since the customer base is all on the east coast. Deployments can be timed appropriately. In the event a catastrophe or a db migration script must be run, an alternative deployment configuration exists by toggling a helm deployment variable (the 0.01% downtime). This fails over to a simple static web page which displays a maintenance message while we work on the hot fix or db migration. Additionally, every day a backup is made of all data and stored in the event a disaster recovery needs to occur, this is a simple toggle in GCP. Scaling Scope and Load Balancing The application scope and load should always be determined by how the clientele will be using the application. GCP provide automatic DOS prevention, so this will be ignored when considering scaling parameters. The way our application will mostly work is a very low load day to day with intermittent massive spikes of network traffic from customers. The highest portion of bandwidth is not delivered by our content, that would be Vimeos CDN. Instead our content is all lightweight json from loading our pages. Our clients have at most had a thousand or so on at once. We were able to load test spikes of several thousand at a time with no crazy amount of cpu or memory usage. So it is likely we would not need to scale. Regardless, the deployment in production is scaled out so that 3 pods are running at once the standard round robin since least load in our case would be next to useless. As our customer base has grown we have been monitoring cpu and memory usage, however it is never enough that we have considered a dedicated load balancing solution. Thus our final Diagram: Conclusion The scope of this architecture is to help budding startups and smaller companies realize how much you can get done with a minimal team. This application has been developed over the course of 3.5 years to publishing and has a generous number of clients. If your architecture is simple from the start, you are setting yourself up for success. Shortcuts can be taken when your team is properly experienced, and nothing ever has to be “by-the-book”. This is an architecture that has worked for us, and has been relatively cost-effective when considering the full scope of the application and revenue." }, { "title": "Sunroom Extension", "url": "/sunroom-extension/", "categories": "diy", "tags": "diy, interior, house, 1950s, carpentry, remodel, windows, rustic, modern, sunroom, stove, wood-stove, alternative-heat", "date": "2022-02-25 12:00:00 -0500", "content": "When we bought this house there was an unused concrete deck that was gingerly sitting outside a door. This deck’s base was 4 inches of solid concrete, and it was supported by 8 inch concrete block walls which housed a garage. We looked at it when we first toured the house and said “that’s just unused space, we can extend it if the house is a little small”. Sure enough the living space was a tad too small. Overtime this idea grew and she wanted it to have a wood stove too. 🔨 As this was a larger project, I got some help. I had a structural engineer come out to tell me if the garage could bear the weight of an extension on top of it, he confirmed it could carry probably up to about 2 stories. There were indeed 18 inch footers in the ground; light footers, but they were deep enough and no structural error seemed to be present. After that we bided some time to save some money. We hired contractors at Prince Builders LLC to initiate our house building endeavor. The deal we worked out was they would be responsible for getting a subfloor, walls, windows, the roof, exterior wall leading into the sunroom knocked out, and exterior of the extension waterproofed. I would be doing the finishing: drywall, trim, electric, insulation, siding, wood stove, and hearth. The contractors and I worked at the same time on a few things; I took a week off while they were working to attempt and get a lot of the nitty gritty stuff done. Before long walls were up and roof was done, whole project took about 1 month until it was livable, and 3 months total to get it into the shape that it is in the pictures - had a few setbacks. Worst part of this extension is now that i have all the extra light i can see the dog hair all the time 💀. Worried a little bit about AC too, but haven’t had a hot enough week to know if its bad or not. This project was started in October, and ended in January TLDR Before/After Shots Inside Outside Google Drive of Photos Located here 🏚️ Difficulty List Usually I get asked about what the hardest part was, here is a table of what i thought was difficult and what wasnt Item Difficulty Reason Siding Easy Level it all out in the beginning, lots of cuts but not bad. Don’t fall off the ladder Flooring Easy Do it at the right time and you’ll have no problems, before trim after walls after paint Trim Medium This room was annoying because of the amount of trim i had to do, each piece of wood around the window was custom planed and made by me Hearth Hard Lots of measuring, lots of leveling, lots of time, while applying concrete easy to mess up Chimney Hard Even more measuring than hearth cause you’re now in 3 dimensions, also had to triple check everything to prevent fires Insulation Easy Takes forever, but easy and itchy, just had to remember baffles. Electrical Easy Always my favorite Wood Stove Medium Heavy as heck, had to be clever to avoid hurting my brand new sunroom Drywall Hard I ended up hanging all the drywall myself, hired someone to finish it, it was too time consuming and I found out its cheap For the wood stove, to get it over the stoop coming in i actually built like a makeshift ramp out of two-by fours. By some miracle nothing got injured. The thing weighs over 400lbs Injury There are photos in the drive about when I cut off the tip of my finger. Was just me being an idiot. I saw online people cutting these vinyl planks with their utility knives and thought “hey that looks easy” It wasn’t, it slipped while i was cutting with a lot of force. More After Photos \tLeft - Wood Stove with hearth, Center - stove in corner, Right - View from living room \tLeft - Window view of my back yard, Center - living room view from sun room, Right - the egress to the deck" }, { "title": "DIY Pantry Remodel", "url": "/pantry-remodel/", "categories": "diy", "tags": "diy, interior, house, 1950s, carpentry, remodel, windows, rustic, modern, pantry, cabinets, fridge, countertop", "date": "2021-08-30 12:00:00 -0400", "content": "Since we’ve owned the house there has been a small room to the right of our mudroom enterence taking up the corner of the house. The previous owners used this as an office space. It is about 45sqft of space, about 6 feet wide. We ended up using it as space to store food, but there was really no good mechanism of storage in there. We ended up deciding to transform it into a complete walk in pantry with our fridge included. This keeps the fridge out of our (smaller) kitchen and makes more dining space. The whole project took roughly 4 months, mainly wait time for cabinets to arrive, wait time for the tile, wait time for the countertops. Overall it was about 2 weeks worth of actual DIY work, where 1 full week of that work was demo and cleanup. TLDR Before/After Shot Before Floor plan This is the floor plan before. Wife forbade me from moving the bedroom closet, so we will be left with the closet space (non-load bearing) and the rest of the room. Annoyingly, everything in this house is two 3/8 piece of plaster that i’ll have to remove. Heavy. I will only be removing the walls, and the closet wall. I can work with the ceiling. I’ll be cutting a panel into the ceiling for any electrical work, and i’ll just nail it back up and spackle when done. Photos Below are pictures of what I’m working with. \tLeft - before floor plan, Center - From outside, Right - from inside Some more from all angles: \tLeft -before door closed, right - looking at door from other side (in the office) The Plan So we’re not left with much room in here. First step is to consult with the wife. We went through about 5 different iterations for how we wanted the floor plan to work out. Our primary goal was to use this as storage for our fridge and for the rest of our food. My secondary goal was to include a space to store our brooms and cleaning supplies. Her secondary goal was to give us a neat place to store appliances. The next step was to shop around and figure out what we could do with a reasonable amount of money. The most expensive part in this project is the cabinets. I will get into that in another section. But we really needed to work on cabinet configuration. Eventually this was the decided iteration. The Work By now i’ve remodeled 3 rooms, so i have strategies. Get everything out, turn off circuits, remove hardware i want to keep (nothing). Cut the radiator supply line, remove it Remove all doors, put up plastic sheet seperating this room from the other rooms to keep dust out. Tape it. Begin demolition, leave carpet for quick cleaning of dust. Start with closet wall. Use reciprocating saw for all demolition, nothing else besides hammer and crowbar are needed. Throw everything out the window into a garbage. Rince and repeat for the other walls that are connected to the exterior wall. The exterior walls are the only ones we demolish b/c i need to insulate those. The other walls and ceiling we can keep. Demolition I lied about removing everything, fridge was too heavy for me alone, i did it after demo. \tLeft - removing the door and studding, Center - removing the first wall (closet), Right - freakshow everything gone Framing, Electric, Plumbing, Insulation I ran a separate circuit for each outlet in this room, all 12AWG. That’s technically 4. 2 For the previous closet wall (now appliance station). One for the coffee corner, one for the fridge. One plumbing line to supply water to the fridge. Most time spent here was redoing all of the electric in this room. The wiring in this house had all lights in the entire first floor on a single circuit. So i traced it into the bedroom and had to remove another switch. \tLeft - the start of electric removal, i had to move this ceiling entry by 3 ft, Center - done one wall, Right - finishd the other. I use rockwool at the recommendation of Matt Risinger. My house is just stucco on block so water can seep from time to time. I’d rather it seep on something that doesn’t mold. Drywall \tLeft - First sheet of drywall, Center - Drywall all walls, Right - Drywall bedroom hole from door Spackle, Cementboard Like 3 days of work for patching all holes and spackle. Here we finally remove the carpet, and replace with cementboard after spackle is done for tile. \tLeft - Finished the bedroom wall with trim, Right - Zoom out for rest of room. Finish Bedroom before wrath of wife Did this in a day with hot mud + skim coat. Bought new trim. Painted with leftover. \tLeft - Spackling the rest of the room, Right - Cementboard finished in the rest of the room. Paint 2 Coats at 1 hr a piece. First time cutting instead of taping to save dry time. \tLeft - Painted the room, Right - Paint with white trimming electric to get a little more effect Tiling 3 Day job after work. One day to cut and lay them all out, two do place first and second half. \tLeft - Tile first half, Center - tile second half, Right - Finish tiling Cabinets, Countertops Installing cabinets alone sucks. Basically the trick is to grab 2 2x4s and cut them to the size of the area you’re hanging them. Make them like the floor of the cabinet. Haul the cabinet up, with predrilled screws, then smash cabinet against the wall and screw it in. I had to build out the wall slightly because i didn’t have any good studs to line up my cabinets as well. The worst part about all of this was jiggering a way for the small 9 inch floor cabinets to be stacked ontop of one another. They make a 8ft cabinet that is 18inches wide, but not 9. So i had to get creative. I made a small support for the cabinet to rest ontop of the other cabinet, keeping the weight on the sides of the cabinets. I then cut a large piece of white mdf painted board and put it on the side to hide the stud. \tRight - framing top of the fridge, center, right - cabinets The countertops were a little tricky. To get one done, you buy a piece of MDF board, cut it to the exact size you want it. This is called a template. Then you bring it into a countertop store and they will cut whatever you want to that size. Use labels on the mdf board so they know which sides to finish. I forgot to take photos of this process. Special Sliding Shelves I had to get creative (once again) with the sliding drawers that tyler wanted in the 9 inch cabinets. The brand is called “Rev-a-shelf”. To install it, I popped off the door of the cabinets, then shimmed the shelf so it was centered, I then nailed the door back to the face of the rev-a-shelf. I then placed a handle in the center of the shelfs, and filled the nail holes with chalk. Trim and Broom Nook The broom nook I got lazy with, but i trimmed it out, and spackled as needed. \tRight - finishing the closet, Center - view from outside (Before cabinets), Right - finished nook After Pantry Door This took longer than I care to admit to paint. Broom Nook Coffee Corner Appliance Station After Fridge &amp; Cabinets New fridge who dis? Later Thoughts Do not use marker to mark your drywall, its very hard to remove. When purchasing drawers for your cabinets, if you’re doing the install yourself, just build the drawers, its far cheaper. Each cabinet is around 1-2 hundred dollars depending on their size, then the sliding drawers idea we had to maximize the space were pricy to buy preconfigured as well, if i could go back i would just buy a router and build the drawers myself. The hardware is pretty standard and i can get at lowes for cheap." }, { "title": "Exterior Front Door Installation", "url": "/front-door/", "categories": "diy", "tags": "diy, interior, house, 1950s, carpentry, remodel, exterior, door, trim", "date": "2021-04-25 12:00:00 -0400", "content": "On the coldest day of march, I decided it was the perfect time to replace the front door. If you were to look at it you’d see light shine around all the sides and you’d see the dew condense on the single pane glass ancient luan door. This project involved removing a custom door frame that was made of solid 2 inch hard wood, and working a bunch of concrete. When I removed the frame, I found the most interesting installation technique i’ve ever seen: they mortared 3 inch common nails in reverse into the wall, then they took the custom frame and probably whacked it into the wall. Superb. Anyway here’s some photos. Door: 500$ (it took like 4 months for the door to arrive) Screen Door: 300$ (same day depot run) Exterior Trim and Jamb extension: 120$ - I opted for that new faux wood plastic stuff they sell at lowes. Rot proof and holds up. Extras (free): Interior Trim, spray foam, caulk Total: 920$ ish Front Door Before and After The area above the door I left to make my life easier. I will eventually be ripping it out for a portico. \tLeft - before, Center - Zoom on rot, Right - after The Adventure When I removed the door, it was about a week after the new door arrived. I set the new door against the house, and a strong gust of wind came and blew the door onto my railing. The railing impaled the door. I was able to fix this with Bondo all-purpose fiberglass patch in about an hour. I have yet to paint the door. \tLeft - when the railing destroyed the door, Center - the hole that i had in my house while I fixed the door. Right - Shimming the door with the hole during install." }, { "title": "One and a half years of DIY Remodeling Before/After", "url": "/1-5-year-progress/", "categories": "diy", "tags": "diy, interior, house, 1950s, carpentry, remodel, kitchen, bathroom, living-room, living, floor, tile, lvt, trim", "date": "2020-12-10 12:00:00 -0500", "content": "As 2020 comes to a close, we decided to bring together a collection of photos. This is some personal progress tracking for everything we’ve remodeled. My wife asked me to throw together a bunch of photos of before/after so her friends can see what we’ve done. The before photos are when we moved in, and the after is what they look like now from approximately the same perspective. Parts that are not remodeled yet are not included in this post. We plan to do much more :) With the remodels pictured here, our house went up by 100k in value from what we originally bought it for (got it appraised for a refinance). Yes, I plan to paint the remaining wood trim white, and replacing the rest of the luan doors. Open Floor Plan Should have seen the garbage pileup from this. Something like 30 bags had to be hauled by my brothers and I down the driveway. \tLeft - before, Right - after Kitchen Entry No more extra useless cabinet, fridge moved into the “pantry” which we have yet to remodel. For info on how i did that live-edge light you can see my post here. \tLeft - before, Right - after Kitchen Counter I really wanted (and still want) to redo these cabinets. The wife wanted them stay 🙄 \tLeft - before, Center - after, Right - extra pano shot Living room Living room, featuring a new bay window and part of our 3-zone ductless minisplit, which I think gives our house a more modern vibe. \tLeft - before, Right - after Bathroom For more photos and info you view my bathroom post here. This was quite an undertaking. \tLeft - before, Right - after Guest Bedroom These bedrooms light remodels. Redid carpet, doors, trim, paint. Still gotta do those windows, they taunt me. My ceilings are small (7.5 ft) so i also removed the ceiling fan, which would wobble whenever you turned it on. You’d be amazed how many things in this house were held in by a single screw. Believe it or not, the previous owners hooked up the fan to an old dimmer switch. You could hear the fan motor arc when you played with the dimmer. View from Entry \tLeft - before, Right - after View from Corners \tLeft - before, Center - after, Right - one more with the doors Main Bedroom View from Entry \tLeft - before, Right - after View from Corners No before shots, they were hiding some holes and bolts in the walls. Also hiding a really bad paint job. New Trim Perspective I just wanted to highlight the incredible trim that I found at Lowes. I’m a huge fan of low-width trim that does nothing more than add to the aesthetic of the house. It’s no secret that contractors will use larger trim to hide flaws in their work. If you have very large baseboard, its definitely hiding a garbage spackle job. Originally my trim in this house was 8 inches, and it was hiding many holes. Therefore, the downside of this low-width trim is just more prep work. The door trim is ~1.5” in width. Here are some close up shots of the trim after it was finished (before caulk). \tLeft - a perspective shot of how thin the trim is, Center - a Zoom on some fine trim cutting, Right - Zoom out of what it looks like together Some Notes We plan to do a whole lot more with this house. A never ending project. And I got a greenhouse to build soon, a basement to finish, a detatched in-law suite, and an attic to finish." }, { "title": "DIY Finishing an Unfinished Closet w/Access Panel like a Pro", "url": "/finishing-closet/", "categories": "diy", "tags": "diy, interior, house, 1950s, carpentry, drywall, door, access-panel, custom", "date": "2020-11-27 12:00:00 -0500", "content": "When I remodeled my bathroom, like so many contractors, I didn’t even bother to finish the closet that I completely destroyed. I managed to finish this project in about 2 days time and it turned out super nice. I did this to increase sqftage of the house before an appraisal. We’re refinancing, rates are too good. Too bad the appraiser didn’t even look at my closet 🙄. I wanted to add a nice access panel for anyone that does future work on the shower. Total price: ~162$. Money Estimated saved from professional install: 700$ 3/8s Drywall (2 slabs) - original construction was two 3/8s piled ontop of one another, so i continued the trend. - 11$ Spackle - 7$ Drywall Tape - 3$ Floor Trim - free, had some spare Door Trim - 32$, prefinished to increase speed Door - 40$, taken from a 48” byfold door. My access panel is a portion of this cut to 12 inches Hinges: 5$ Handle: 4$ Modular closet hangers - ~60$ Odds and ends - drywall screws, some spare 2x4s Before and After \tTotal before and after transformation perspective Before \t \t \tLeft - Before everything was installed, Right - Where we want to be able to modify, so these are access panel areas After \t \t \t \tLeft - After everything, with cloths, Center - Finished product without shelves, Right - Trim close up Why I did it Appraisal was happening soon and I wanted to beef up value by increasing sqft and including this closet that I destroyed from a remodel. How I did it Start by framing the access panel, i had some spare wood i could use. I had to plane the wood to fit around the shower control valve. Keep it plumb with the surrounding studs, if they aren’t plum shim them. - Drill, wood screws, level Paint the frame you just made to match your trim color, you do this because the wood could stand out a bit by itself and you want everything to jive. - paint and paint brush, 1 coat is fine it doesn’t need to be perfect, just so when you open up the closet you don’t see ugly unfinished wood While you got paint out, paint the access panel door or any trim that needs painting. I decided to insulate the left/right stud cavities just because I had some spare rockwool lying around. This will do nothing in terms of heating/cooling but it adds some mass for sound dampening from the tub/shower. I did this to my whole bathroom before to dampen any noise before too. Hang the drywall, give yourself enough room around the frame to fit hinges, around 1/4-1/2 an inch - drill, drywall screws, utility knife, P100 Mask Spackle, I set the heat to 80 degrees in the room to promote faster curing and ran a fan. This step usually takes several days but you can speed it up with a few tricks. Be sure to do thin layers of spackle, no thick build ups your life will suck. I always water down my spackle with about a table spoon of water until i get a smooth consistency. I want to see no bubbles of spackle as i apply it to the wall. This helps you apply thinner layers too. About the consistency of soft serve ice cream. I was able to get done spackling in 3 coats over 15 hours. - spackle, putty knives, fan, drywall tape, drywall fiber tape. Paint the walls - use Killz or some other thicc paint or you’ll have to do like 10 coats. Spackle and raw drywall will soak it up like a sponge. I had to do 2 coats with a thick primer, i didn’t bother painting a color overtop. Its just a closet. Trim the door and access panel door - I recommend nice thin trim, but that’s just my style. - mitre saw, measuring tape, nail gun or hammer/finishing nails Trim the floor - same as above Caulk the trim - Some DAP white caulk, caulk gun, paper towels Pro tip for cutting trim with mitre saw: Go big, like 1/4-&gt;1/2 an inch bigger than expected until you get the hang of it, cut back if its too big. It’s easy to mess up cutting trim like this, so cut larger than expected. Save yourself a trip to the depot. Pro tip for mudding: don’t fall for the cute metal inside corners they sell at the store, they make your job harder. Use drywall tape, fold it in half in about 2ft segments. Put a light coat of spackle in the corner, then put the tape up, squishing from the center out so you have no bubbles. If your hands are clean during this you’re doing something very wrong. Make sure 100% coverage exists underneath that tape, or throw it out. Spicy Construction Photos \t \t \t \tLeft - dryfitting the door with the new frame; Center - after second coat of spackle; Right - before the door was installed I also took the time to document inside that access panel every model number used, you can see it in the third photo." }, { "title": "DIY Live Edge Wooden Ceiling Light", "url": "/live-edge-light/", "categories": "diy", "tags": "diy, interior, electrical, house, light, 1950s, live-edge, slab, wood, carpentry", "date": "2020-09-21 12:00:00 -0400", "content": "Our ceiling light (4ft fluorescent tube) fell off our ceiling one day while I was playing with my dog and shattered across my freshly tiled kitchen floor. We went out to buy a new one that would fill the kitchen with light, but everything was horrible or overpriced. It’s amazing what people will pay for fancy lights. So we built one ourselves to match our style! This project was originally done around December of 2019 Total price: ~300$ Wooden slab (cherry wood) - 200$ Dimmable 4 Inch Lights - 60$ LED Strip - 16$ Dimmer AC/DC Inverter - 20$ Odds and ends (stain, wires, hot glue, etc) Money saved from etsy/bought equivalent: ~$1-2k Before \t \t \tLeft - Where it's being installed (before finished product), Right - Raw wooden slab before finishing After \t \t \t \tLeft - middle of the day glossy shot, Center - Light on at night, Right - Light off at night Why I did it Light fell out of ceiling because previous owner did not affix it to studs or use anchors. Needed stylish replacement. How I did it Measure location for lights Evenly space horizontally (wider) across the entire slab, mark the location. On each of those marks, take the measuring tape and mark the absolute center vertically (thinner). This will give you a perfect center for the holes - measuring tape and pencil Cut holes for lights - 4.25 inch hole saw (specification of light), drill Flip it over, and finish the wood Sand with 80 grit until even Sand with 120 grit until even Sand with 220 grit until even Fill holes, and apply a sand dust coating - this will make the surface glossy with varnish Sand with 300 + grit until even or until desired smoothness Stain if desired, then Polyerathane evenly (3 coats) If you mess up like I do with everything in my life, varnish stripper will take off the varnish. Then you’ll have to start over the whole process. from 120 grit. Flip it back over. Decide where the junction boxes where go so they will be hidden - keep them away from the absolute center, your led strip will go here Use a forstner bit (or more properly a router, but if you’re cheap like me a forstner bit) to go about half way down for the junction boxes in the wood, this will make them invisible when your slab floats from the wall. - forstner bit, drill, screws After junction box secure, run the wire through all of the junction boxes in parallel, the center most box will be the point of entry from your ceiling junction - wire secures, 14/2 awg wire. Install dimmer the same way you did the junction boxes, give extra space for the wire runs. - forstner bit, drill, screws Put the LED strips vertically centered across the wood. If your wood is curved like me, divide it into multiple strips, and link together with a small 20awg wire, solder and hot glue. - hot glue, 20 awg wire, soldering iron, solder Test that there are no shorts - multimeter Anchor to the ceiling: get 4 hook &amp; eye anchors, and find the studs in your ceiling. Take many measurements to get everything perfectly lined up. if you’re measuring correctly, this should take a while, remember your wood is not completely flat, so the anchor locations will be staggered. required - stud finder, pencil, measuring tape Use a small drill bit, drill into the studs on your marked locations, this will give the anchors an easier time, put the hooks in the ceiling Use a small drill bit (recommend drill press for this) drill half way down into your wood, then mark half way down on the eye with a sharpie, screw it by hand half way into the wood. Get another person to help you mount it to the ceiling, you don’t want your project to smash on the floor. For the junction connection, you can buy a “fan extender kit” from lowes or the depot. About 15$. Then cut the metal line on the extender kit. To get it to attach to the ceiling, i had to buy some pieces of metal, and bend it into shape with pliers, then attach with a self drill screw, but this was because i was being cheap and had metal laying around. Remember that no weight is barring on the decorative kit, just the wire is running through it to your junction box ingress. Spicy Construction Photos \t \t \t \tLeft - beautiful fornster hand drilling for junction boxes; Center - testing the lights before placement; Right - placement of wires and lights All Photos To view the entire process of building the light, go to the drive." }, { "title": "DIY Generator Inlet", "url": "/generator-inlet-install/", "categories": "diy", "tags": "diy, exterior, electrical, house, windows, 1950s, stucco", "date": "2020-09-19 12:00:00 -0400", "content": "A pretty easy DIY electrical install through an unfinished area. Total Price: ~435$ 6 gauge copper wire (150ft) - 250$ - my inlet location is roughly 100ft from my panel, just got some extra Inlet - 40$ Conduit (150ft) - 75$ Conduit fittings - 10$ Interlock kit - 70$ Money saved from professional install - ~1-2k. There are 3 ways to make a generator “to code”. The first is an interlock (piece of metal that keeps you from turning on the generator without disabling the main breaker), the second is a transfer switch (basically a sub panel of ~10 circuits that you can transfer power to the generator at will), and the third is the “whole house” transfer switch (similar to interlock, except this switch comes before the main breaker so you don’t need to flip that off). The latter 2 are $400+ just for parts. Some running up to 1.5k for an “automatic” transfer switch. Most electricians will talk you into (2) because it takes a good bit of time to install and is the most standard. You get charged per hour for an electrician to do this. Finished Product photos Interesting parts: \t \t \t \tLeft - Conduit inlet, Middle - perspective view with garage ft my old bathroom sink, Right - ingress into the electrical box Conduit: \t \t \t \tLeft - conduit on opposite side of inlet, Middle - conduit on opposite side of electrical panel, Right - interlock kit install Why I did it We lost power like 5 times within the first year living hear, more times than anywhere i’ve ever lived. The power lines run through a mass of trees so usually a tree falls on the line and disconnects it from the transformer. The longest we were without power was 3.5 days. Gotta love living in the country. After the 3rd time my dad bought a new generator and gave me his hand-me-down. I have a fair bit of knowledge of electrical work, so what I did was splice the cable and feed it into the panel with a breaker i had laying around. Worked, but i would have to run the line through a window and would let bugs in. This would take about 30 minutes to hook it up, and if it was wet outside it was a struggle. Needless to say this is not “to code” either and it freaked out my wife a bit. Some notes before how-to Most generator inlets are 30amps (or 50) with a “surge” which will allow more than 30 amps to pass through for a second or two. This is completely fine, your breaker will not trip, and wires can handle this surge for a second. Say the controller module breaks, and it surges for too long, then you will have heat build up in the line, which could cause a fire hazard. I know the likelihood of this is small, but i also wanted to make this “future proof” incase I want to install one of those big bad whole house automated generators at some point. Also go big or go home. You should use copper for this project because aluminum can corrode overtime, no matter how water tight your box is, water will always get in. So go with copper for exterior electrical projects. How I did it The worst part of this was boring the holes through the stucco and concrete block. I was very cheap and just used what i had laying around. I had 4 bits of increasing diameter, and got it up to about half an inch. I needed a full inch for conduit clearance. I took a chisel and broke apart bits of the wall after that, couldn’t get it even through to the other side of the block. I had a galvanized iron pipe laying around (courteous of previous owner). I took the pipe, and a sledge, and hammered it the rest of the way through until i was clear of the other side. Luckily living with 5 acres means i have no neighbors to question my idiocy. I did this twice, once for the panel, and once for the inlet install. I like to keep things identical with electrical code for future inspections. Before any electrical project i read about what i’ll be doing fully. For running electrical lines through an unfinished area you must have a conduit to protect the wire. Punch the holes for the inlet - drill, many drill bits, iron pipe (see above) - this would be easier if your house isn’t stucco or block. Measure length of wire needed, cut, then run through conduit. - electrical lubricant (or fishing wire), wire cutter, patience I didn’t bother with a fishing wire, i just forced it through the conduit fitting with lubricant, took some raw strength, and i hated my life for a solid hour Install inlet - level, conduit fitting, pliers, exacto knife, drill, caulk, some anchors choose where you want it, put the box up with a level, and drill the holes. put the anchors in the holes with some caulk, prevents water from getting in wall cavity, then fill anchor with some caulk too. screw the box into the anchors, caulk around the screws, then cleanup the caulk to give it a clean look attach the inlet conductors to the wire. close up box, pushing wires in first to prevent a fallout. Install Interlock - drill, interlock kit and assembly, pliers Directions come with interlock kits they’re all different. But something that no one ever notes is slapping some di-electric greese on the breaker in the back - it prevents corrosion of the bus bar to your breaker, and takes 1 second to do. Just be sure to slap that on before you do it Also because the gauge wire I had was so large I could not put my neutral wire into the neutral bus bar. Luckily i had a “double up” nut i was able to use to get it to attach to my busbar Wiring photo Here’s a bonus photo of the wiring, this kit by reliance was a chinese piece of crap that fell apart when i went to clamp down the wire. I had to reassemble the entire thing from scratch. By the time i got to the point where i got 1 wire to clamp i got excited and took a photo." }, { "title": "DIY Window Capping", "url": "/capping-windows/", "categories": "diy", "tags": "diy, exterior, house, windows, 1950s, stucco, capping", "date": "2020-09-18 12:00:00 -0400", "content": "Been entirely inactive for a long time on every social media platform. Just wanted to start posting about stuff i’ve been doing since we bought our house. Here we’ll talk about some window capping. Total Price: ~80$ Before Sorry for potato quality on before photos, i took some of them half way through. \t \t \t \tBefore Capping Photos - some of these are taken half way through demolition. After \t \t \t \tAfter Capping Windows Why I did it When we moved in we had 8/14 windows replaced. Wife didn’t trust me to do the window install because I was still a DIY noob. I wanted the windows to match. How I did it The exterior of your house does not matter for capping windows. You cap windows for aesthetics and to make it so you don’t have to paint anymore. With it comes a risk of trapping moisture which could end up rotting your wood if water is aloud into the space between your window and the capping material. I’ll probably uncap one in ~5 years to see how well I did. I don’t mind replacing them if they end up rotting. Remove caulking around window - utility knife and caulk scraper Remove Old trim of the window that does not match the new windows and any rotted wood - hammer, ugly stick, multitool with wood cutter attachment Sand down window - multitool with sander attachment Paint the wood - paint/brush Fill the area around the window with some spray insulation - apparently the previous installer did not. To get it to match the other windows, i measured the other windows the capping to match in “height” - the area of the capping that faces you; then Lots more measurements: “Height” for every window as mentioned before - this is where you will bend Inner length, the part that faces the window - this + height is the total “width” of the piece to cut Length - from where the stucco meats the window (or whatever material you have) - my windows have a small jutt out from the bottom, no measurement is a perfect square, so i use the longest for bending the metal, then trim later. Score and snap the pieces of metal off the roll with the total width and length Bend the metal with the jig - you can google metal brake jig to see one, costs about 40$ to make vs a 1000$+ metal brake. - jig (angle metal, wood, lots of clamps) Take the metal to the window, trim to fit, hammer in place with a max of 2 nails, any more and you’ll hurt the metal. Order is bottom first, then sides, then top. the side nails are hidden by that top part (seen in photots). The rest of the nails are hidden by caulk. - hammer, nails, finishing nail tap (so you don’t hurt the capping), tin snips Caulk - 2 tubes of caulk per window, seal everything - don’t hit the window weep. Photo of the Jig I recommend if you make a jig bending the metal with a long piece of wood so the bend is even and you get no kinks \t \t \tMetal bending Jig (metal brake?)" }, { "title": "DIY Bathroom Remodel", "url": "/bathroom-remodel/", "categories": "diy", "tags": "diy, interior, electrical, plumbing, bathroom, house, windows, 1950s, remodel, rustic, modern, floating-vanity", "date": "2020-01-19 12:00:00 -0500", "content": "A full 1950s bathroom remodel, took 4 months. Estimated contractor install: ~20-30k My install: ~7k I’m not going to do a writeup right now for this. I learned a lot and made plenty of mistakes, if people are interested i’ll write something, but here are the photos: Google Drive link Before and After Highlights Below are some and after shots that I believe bring together how much a transformation it was. These all can be found on the drive link above. Entry Had to widen the door by 6 inches, and increase entryway height by 5 inches. Ever frame a door by hand while trying to use the wood that’s there already? Yeah I hate myself too. \tLeft - before, Right - after Sink Hand made floating vanity with a bowl sink. I hope you think its beautiful, I think some of my tears are woven into the wood. \tLeft - before, Right - after Tub and Shower Vertically tiled 2-tone shower. Made a mistake and put a drop-in tub in instead of an alcove, we get some water buildup sometimes, but it’s not a really big deal, we wipe it down after showering. The tub is deep soaking, and extra long so you can sit down all the back of the tub acts like a little recliner of sorts. \tLeft - before, Right - after Close up If you look really closely at the shower niche, you can see the pain and suffering that went into tiling upside down. \tLeft - Rainfall showerhead, Center - Waterfall faucet and control valve, Right - Niche Some notes The bathroom is almost completely sound proofed. This was done because it exists in between two bedrooms, and i’m a light sleeper. When I have kids I want to be able to sleep if they want to take a shower at 10pm. The bathroom has a heated floor This project added 10sqft to the bathroom, we cut out a poorly designed closet Live edge wood vanity took 3 weeks to finish by hand You can thank my wife if you like the design of this bathroom - she also tiled 80% of the floor. You can send me a “F” to pay some respects for accomplishing her designs, 1 brick at a time." }, { "title": "Hacking Video Games: A Software Engineering Approach", "url": "/hacking-video-games/", "categories": "computer-security", "tags": "python, security, hacking, skyrim, modding, video-games", "date": "2018-04-22 12:00:00 -0400", "content": "We’re going to be doing a brief discussion on an approach to attacking client-side video games. I am going to make several assumptions about our reader: you’re experienced with binary (and hexadecimal), you understand basic computer science skills (can program and understand hash-tables and computational organization), and you hate losing games. Understanding File Parsing When video games first came out, this topic would be trivial. We would simply do a quick look to figure out where are save files are stored on our operating system, and then we would just modify the values in that file. Often times, XML or INI would be used to store the information. This wasn’t a big deal for developers because we often did not have to share the information with servers or vast networks like we do now, so there is no reason to secure the information. As the first online games were introduced, so too was the ability to manipulate the online content, and then security was put in place to prevent this: checksums, custom serialization, endianness, custom primitive storage, etc. This article will be talking primarily about client-side attacks to a video game, pertaining chiefly to custom, developer made save-files. Top Down Approach Let’s take a look at an example before we continue. A popular client side game we’ve all loved at one time or another is Skyrim. Generally the tools I use are restricted to a hex editor and some arbitrary language IDE open on the side to implement as I go. For Linux the hex editor I recommend is Bless and for Windows definitely use HxD. For this example I’m going to stick to python, it’s easy to translate into other languages. A Top Down approach is literally just that, we are going to start at the very top of this file and work our way down until we have successfully built our own implementation of an interpretor for this file format. Now, Skyrim has an enormous amount of data they store in their save files, so we’re going to primarily be focusing on the header information. The same skills can be extrapolated and applied to the rest of the save file. You have probably realized at this point that this seems a daunting task, especially with the currently exposed information. The problem that you have as the audience is a lack of info. We need more information if we’re even going to come close to dissecting this, a classic scientific method, we need controls. So let’s get a few more save files, and have all the saves readily available off to the side in Skyrim to load at well with any hypothesis we wish to test. TLDR Generalized Explicit Recap Thus far Take your current Save file and make a copy of it, put it in a save directory Do something in game, save again, make a copy of it, put it in a save directory Repeat n times (recommend ~5 to have a solid group of saves) Have the game open off to the side with all save games loadable. To the Code So now let’s get into the nitty-gritty details of our operation. We will be performing our topdown approach to the header of the Skyrim file. Observe the following files below: We can immediately see a few commonalities between them, and that is our wonderful human brain at work that has been trained to identify patterns all of our life. Let’s start with the file MAGIC (file signature). This is a commonality that all developers ubiquitously present when they make a customized file format. It serves as a marker for the reader to identify the file with easy to verify that it is, indeed, able to be read. Our signature looks like 54 45 53 56 5F 53 41 56 45 47 41 4D 45 or in ASCII TESV_SAVEGAME. Let’s move over to our python script now that we’ve identified the first feature. \"\"\" TESV Save game file editor example (Top Down Approach) :author Joe Bartelmo :filename tesv.py :version 3.6 \"\"\" class TESVSaveGame(): \"\"\" Wrapper to read and write our TESV Save game \"\"\" def __init__(self, filepath, open_immediately=False): \"\"\" Constructor for our file editor \"\"\" self.filepath = filepath self.stream = None self.opened = False if open_immediately: self.open_stream() def __del__(self): self.close_stream() def close_stream(self): \"\"\" Closes the initialized stream \"\"\" if self.opened: print('Closing Stream') self.opened = False self.stream.close() def open_stream(self): \"\"\" Opens the initialized stream \"\"\" if not self.opened: print('Opening Stream') self.opened = True self.stream = open(self.filepath, 'rb+') self.assert_magic() def assert_magic(self): \"\"\" Assert that the file signature is present \"\"\" self.stream.seek(0) expected = \"TESV_SAVEGAME\" actual = self.stream.read(13).decode('utf-8') assert expected == actual, expected + \" != \" + actual if __name__ == '__main__': import sys if len(sys.argv) != 2 and (len(sys.argv) != 3 or sys.argv[2] != '-d'): print('usage: python testv.py &lt;tesv_savegane&gt; [-d]') print('\\t&lt;tesv_savegame&gt; location of skyrim savefile') sys.exit() TESVSaveGame(sys.argv[1], True) So some advanced notes for development here: Never read in the whole file at once: parse the data, then write back. If anything we will read blocks of like-aligned data (eg: a zip file inside our file, or a checksum block). We do not read the whole file because it can be costly to our memory and there is no benefit from it because we are modifying this file anyway (generally). So our best bet is to keep a stream initialization open for the duration of our file. Here we do not even bother with a getter because the magic is useless information, we included the assert_magic function strictly so we can see whether or not the file we have open is a valid file. Let’s move on in our file. Continuation of Top Down This next set of bytes is a little more tricky and require intuition. We have a byte that varies across all four files, however the remaining 3 bytes does not vary, they are constantly 00. Bringing back some of our knowledge on binary, usually 24bit integers are not common, we see denominations of powers of 2, 4 bytes being the most common (integer). We’re going to make the assumption that this is an integer. It varies across all files. In general we make the assumption that if there is an arbitrary set of 4 bytes that does not seem to have any reference, we assume it is either going to be one of the following: Type How we make the assumption it is this type General likelihood length The given set of 4 bytes does not have all 4 bytes allocated. Eg: 32 00 00 00 or 19 4b 00 00 Usually this length refers to the next set of bytes High value The given set of 4 bytes does not have all 4 bytes allocated. Eg: 32 00 00 00 or 19 4b 00 00. This can be very similar to a length type, so we identify a value by whether or not we are in a block, or if we know what type of data we’re observing. High offset The given set of 4 bytes has a high number that exists in the file as an offset, and looks like the start of a block of information Eg: 32 40 b0 00 where the offset 0xb4032 contains a distinguishable block Medium checksum The given set of 4 bytes appears random, does not link to anywhere in the file, and appears to have no relevance, but it changes frequently between files. Eg: 9b 14 aa 90 Low Based on the above we can safely assume that our value is of a length type. Let’s check to validate for each save game. All 4 are XX 00 00 00. This number means absolutely nothing to the notes I took of the important numbers and facts in my gamesaves. So I will make the assumption this is a length and not a value. In addition to my assumption, if we read the next 0xXX bytes of save games, our offset looks to always bee at a very large block of data. Our read data also contains (almost always) a set of 00 00 leading up to the block of garbled bytes. File Structures Before we continue, you need to understand the assumptions that I am about to make for the rest of this save file. Generalizations are very good when it comes to data analytics because it helps us more quickly identify how a structure is probably going to look once we tear it apart. In general, if a save file is binarily encoded, it will follow a typical file system structure. Almost all file tables when it comes to storing simple information will follow this design pattern. There generally will always be 1) Versioning and metadata info 2) Data Table 3) Information that links from the datatable. Coincidentally this is exactly how the Xbox 360 and windows operating systems also store their information. Microsoft loves their encapsulation. The Xbox 360 encapsulates all games in a container coined the Secure Transaction File System (STFS) which simply stores files within itself and maintains a hashtable which hashes blocks of the data from the save file for integrity. This was implemented so that designers did not have to worry about tampering, because they would have to get through the Xbox 360 file system before they even got to modify their gamesaves. To read more about how the 360 is structured you can go to free60.org. Using File Structuring knowledge to our advantage In what I’m now going to call our header metadata, we have a variable number of bytes. Let’s read our header data for a little bit and see if we can get the hang of this. Our next 4 bytes are static across all files 09 00 00 00. Using our assumption table above, I’m going to test to see if this is a length. It does not appear so because there is no link to anything, also it is static. Usually a length will not be static across 5 different save games. This is probably a value then. I have no idea what type of value it could be, but my assumption would be that this is versioning information because we are still in the metadata section of the file. Usually developer include versioning information in the top of their file systems. The next 4 bytes increments by one in each of my save files 32 00 00 00 33 00 00 00 … This is very clearly the save number of the game. We now have a set of 2 bytes that are followed by an ASCII string (my character name) . It just so happens that these two bytes when converted to a uint16 is the exact length of my character’s name. This is a very common storage technique that C++ often uses for their string datatypes. We’re going to group this one into it’s own string category. Updated Code with Current Extrapolated Information Metadata reader: \"\"\" TESV Metadata :author Joe Bartelmo :filename tesv_header.py :version 3.6 \"\"\" import struct class TESVHeaderMetadata(): \"\"\" Analyzes and reads the TESV header metadata \"\"\" def __init__(self, stream, offset, length): \"\"\" All we need here is the stream and rely on the parent to open and close \"\"\" self.stream = stream self.offset = offset self.length = length def get_unknown1(self): \"\"\" Seems to be a static integer, it's probably a version, it doesn't seem to have any impact on the save game \"\"\" self.stream.seek(self.offset) return struct.unpack('i', self.stream.read(4)) def get_save_num(self): \"\"\" Reads back the save number in the tesv file \"\"\" self.stream.seek(self.offset + 4) return struct.unpack('i', self.stream.read(4)) def set_save_num(self, num): \"\"\" Sets the save number in the tesv file \"\"\" self.stream.seek(self.offset + 4) self.stream.write(struct.pack('&lt;I', int(num))) def get_character_name(self): \"\"\" Gets the current character's name \"\"\" self.stream.seek(self.offset + 8) size = struct.unpack('h', self.stream.read(2)) return self.stream.read(size).decode('utf-8') # ... Main Entry point: \"\"\" TESV Save game file editor example (Top Down Approach) :author Joe Bartelmo :filename tesv.py :version 3.6 \"\"\" from tesv_header import TESVHeaderMetadata class TESVSaveGame(): \"\"\" Wrapper to read and write our TESV Save game \"\"\" def __init__(self, filepath, open_immediately=False): \"\"\" Constructor for our file editor \"\"\" self.filepath = filepath self.stream = None self.opened = False if open_immediately: self.open_stream() def __del__(self): self.close_stream() def close_stream(self): \"\"\" Closes the initialized stream \"\"\" if self.opened: print('Closing Stream') self.opened = False self.stream.close() def open_stream(self): \"\"\" Opens the initialized stream \"\"\" if not self.opened: print('Opening Stream') self.opened = True self.stream = open(self.filepath, 'rb+') self.assert_magic() def assert_magic(self): \"\"\" Assert that the file signature is present \"\"\" self.stream.seek(0) expected = \"TESV_SAVEGAME\" actual = self.stream.read(13).decode('utf-8') assert expected == actual, expected + \" != \" + actual def get_header(self): \"\"\" returns meta data object \"\"\" self.seek(13) header_size = struct.unpack('i', self.stream.read(4)) return TESVHeaderMetadata(stream=self.stream, \\ offset=header_size, length=13) if __name__ == '__main__': import sys if len(sys.argv) != 2 and (len(sys.argv) != 3 or sys.argv[2] != '-d'): print('usage: python testv.py &lt;tesv_savegane&gt; [-d]') print('\\t&lt;tesv_savegame&gt; location of skyrim savefile') sys.exit() TESVSaveGame(sys.argv[1], True) Moving on By now I’m sure you get the point, this is a long an tedious process. The point of this article is to show you the proper software oriented approach, and not to do this entire save file. A team of us have already accomplished this for this exact save file. If you’d like you can practice and implement all of this information yourself with the data that has been previously established here. We are now going to briefly touch on different approaches to accomplish the same end goal. This usually is not the proper approach as we do not obtain the maximum information or properly discover the how the file system works inside the analyzed save game. Alternative Approaches In general, the above approach is how we map out an entire file without reverse engineering completely how the underlying game saves. This is sadly the fastest way to fully map out an entire save game. In general there are 2 more generalized approaches that I will mention: searching and decompiling. Decompilation Approach This is a little old school. When you think about it, all games are just a programs that sit on the hard drive. If we can go through and isolate the moment in time that the program saves in memory, we can analyze it and figure out which numbers align with what segment of the code. The problem with this approach is that it is messy and it would take longer than it would to simply produce a bunch of game saves, record data on a notepad and pencil, and do a little digging. If you however would like to learn more about this approach, I recommend taking a look at Boomerang for decompiling the executable to get the byte code locations. This may not be as fruitful however as an in-memory viewer where we can query information on the fly. My favourite application for this purpose is CheatEngine and for Linux scanmem. These will let you do queries in memory for your executable and even let you manipulate the current game in action (though for newer games you’ll probably just kill the executable). I recommend using this approach on flash games, indie games, and any smaller game (in terms of executable size) that does not have memory scanners (See below) Important Disclaimer: Modifying the memory on the fly is often considered a type of malware attack, some antivirus programs will freak out when you attempt to use cheat engine or any other memory modification program. Additionally, a good deal of games have built in failsafes that detect when the memory is being modified, and have a reporting system to ban you. This is especially true for Steam who has a very well known VAC system to secure their games. This is another reason I tend to avoid this approach. Searching Approach * * most efficient approach in terms of time This approach follows the same environment setup as the top down approach. We first obtain several gamesaves and record information about our save files just like our topdown approach and our decompilation approach. Now that we have our information we can search through the file and to find the offset of the target value to manipulate. Say for example in the given Skyrim file I wanted to modify my gold, and let’s say that I currently had 3302 gold. We have multiple ways that this gold could be represented in memory, so we’re going to use our Software Engineering reasoning to deduce that the value is going to be an unsigned integer (we can’t have negative gold, and the default max size for most values is 32 bits). Endian Type File 1 File 2 File 3 File 4 Little uint32 N/A N/A N/A N/A Big uint32 0x25663a 0x25a342 0x2562bc, 0x422a4d 0x25976b Above table is an offset chart linking where the gold was found in the file The above is an example of a dynamic value, we couldn’t find a fixed position for the gold. But at least we found it! Let’s take a moment and perform the following steps: 1) Attempt changing the value and running the game 2) Record whether or not this process worked, if it did you’re good to go for the Coding Search Approach section 3) If not we need to figure out if this was a compressed block we just modified or if there is a checksum. Go to the Checksum Hunting section Coding Search Approach The naive approach would be to simply search for the value and modify it. The problem with this approach is that there could be duplicates (as seen by the above table under File 3). So there are two possible legitimate approaches. We can either isolate a static reference and compute the offset from the static offset, or we can fall back to the top-down approach. Although the top-down approach is the formal approach, if we are using the search approach we are in the interest of time, so let’s look for a static value around our gold (note that this approach will not formally work on the Skyrim because this found value isn’t actually the real gold value, it’s just an artifact that reflects the gold I have). The static artifact that is a commonality among all of the files is that this value is prefixed with 00 00 00 00 00 00 33 00 00 00 00 33 00 00 00 So we’re going to use this to find our target gold value. You can probably see already that this approach is fragile and will not always work. Search Code \"\"\" TESV Save game file editor searching approach :author Joe Bartelmo :filename tesv_naive_search.py :version 3.6 \"\"\" from tesv_header import TESVHeaderMetadata class TESVSaveGame(): \"\"\" Wrapper to read and write our TESV Save game \"\"\" def __init__(self, filepath, open_immediately=False): \"\"\" Constructor for our file editor \"\"\" self.filepath = filepath self.stream = None self.opened = False self.gold_offset = None if open_immediately: self.open_stream() def __del__(self): self.close_stream() def close_stream(self): \"\"\" Closes the initialized stream \"\"\" if self.opened: print('Closing Stream') self.opened = False self.stream.close() def open_stream(self): \"\"\" Opens the initialized stream \"\"\" if not self.opened: print('Opening Stream') self.opened = True self.stream = open(self.filepath, 'rb+') self.assert_magic() def find_gold(self): \"\"\" Determins the offset of the gold \"\"\" if self.gold_offset is not None: self.stream.seek(0) data = self.stream.read() offset = data.find(b'\\x00\\x00\\x00\\x00\\x00\\x00\\x33\\x00\\x00\\x00' + \\ '\\x00\\x33\\x00\\x00\\x00') if offset == -1: raise Exception('Could not find static initializer for gold') self.gold_offset = offset + 15 def get_gold(self): \"\"\" Returns how much gold you have \"\"\" self.find_gold() self.stream.seek(self.gold_offset) return struct.unpack('i', self.stream.read(4)) def set_gold(self, amount): \"\"\" Assigns gold to a new value \"\"\" self.find_gold() self.stream.seek(self.gold_offset) self.stream.write(struct.pack('&lt;I', int(num))) if __name__ == '__main__': import sys if len(sys.argv) != 2 and (len(sys.argv) != 3 or sys.argv[2] != '-d'): print('usage: python tesv_naive_search.py &lt;tesv_savegane&gt; [-d]') print('\\t&lt;tesv_savegame&gt; location of skyrim savefile') sys.exit() savegame = TESVSaveGame(sys.argv[1], True) print(savegame.get_gold()) Checksum Hunting If we think there is a checksum, this raises a few concerns. We have to figure out 1) What data is being hashed to produce the checksum 2) What type of checksum are we looking at Deciding what Algorithm they used Literally just bytesize, and then it’s a guess or check game. You can either write a small program to compute the hash over a block of data (for all hash types) and compare, or just use HxD’s built in checksum computer. Wikipedia has an excellent set of hashtypes and their digest sizes you can use to help you along here. Deciding what data to hash We need to understand that there are 2 types of developers, those that go through and try to secure their data (minority) and those that include a checksum because their boss told them. We assume the latter. Once we identify what may or may not be a checksum, we attempt to compute the checksum on all data, not including the checksum. For the latter approach, you brute force according to blocks that you’ve found to narrow your approach (eg header was 54 bytes, checksum comes after, i would try computing the header)." }, { "title": "Understanding 3D `Mat::at<T>` Accessors with OpenCV 3.4", "url": "/opencv-accessors/", "categories": "computer-vision", "tags": "c++, c, opencv, opencv-3.4, accessor, vision, computer-vision", "date": "2018-03-19 12:00:00 -0400", "content": "Some things simply do not come naturally when we attempt to process data in OpenCV. In this article we’re going to focus on using at&lt;T&gt; in three dimensions and how I went about figuring out how to use it. Background Ideally in image processing we want to access pixel by pixel information as fast as possible. OpenCV has for loops configured in the backend such that they are roughly 10x faster when iterating by rows first, then columns (tested on 1 HPC cluster and 1 standard laptop). Typically we are all taught to use indexing to access elements as it is the most safe way (eg: Mat::at&lt;T&gt;(row, col)). This works find for a matrix that has a single channel, however when we want to access a matrix with multiple channels we need to use our quick math skills. Matrix used for reader reference: Bands Rows Columns 3 1 256 Note: that for this article, we are under the assumption that the cv::Vec3b is unacceptable when programming a solution because you are attempting to work around dynamic channels/bands. Naive Solutions Naive solution to indexing into a multi-dimensional matrix cv::Mat img = //process somehow for (unsigned int band = 0; band &lt; img.channels(); band++) { \tfor (unsigned int row = 0; row &lt; img.rows; row++) { \t\tfor (unsigned int col = band; \t\t\t col &lt; img.cols * img.channels(); \t\t\t col += img.channels()) { \t\t\t//process pixel: \t\t\timg.at&lt;double&gt;(row, col) \t\t} \t} } Or, alternatively split the matrix and access: cv::Mat img = //process somehow std::vector&lt;cv::Mat&gt; bands; cv::split(img, bands); for (cv::Mat&amp; band : bands) { \tfor (unsigned int row = 0; row &lt; img.rows; row++) { \t\tfor (unsigned int col = 0; col &lt; img.cols; col++) { \t\t\t//process pixel: \t\t\tband.at&lt;double&gt;(row, col) \t\t} \t} } Incorrect Attempts and Finding a Solution I think for most cases the above will perform fine, and you will not have an immense decrease in performance (though this remains untested). However I did some digging and found the little known at&lt;T&gt;(i, j, k) which supposedly processes the image as though there are 3 dimensions present. According to CV Docs: This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Parameters i0: Index along the dimension 0 i1: Index along the dimension 1 i2: Index along the dimension 2 Although there are no instances in the documentation of its use, so i figure we are meant to use it with the band as the third dimensional, like so: Incorrect Accessing cv::Mat img = //process somehow for (unsigned int band = 0; band &lt; img.channels(); band++) { \tfor (unsigned int row = 0; row &lt; img.rows; row++) { \t\tfor (unsigned int col = 0; col &lt; img.cols; col++) { \t\t\t//process pixel: \t\t\timg.at&lt;double&gt;(row, col, band); \t\t} \t} } The above will through a segmentation fault if there is more than 1 band present. So the ordering here is incorrect, our assumption because of the matrix I am using (see above) is that the last index is the row, because we have only 1 row in this matrix. My life is wonderful. Let’s try reordering: img.at&lt;double&gt;(band, col, row); This will compile and run successfully, but gives us complete garbage beyond the first band. We ended up with abstractly large double floating points, It turns out that we have the following layout for our dimensions: Matrix Information Bands Rows Columns 3 1 256 at(i0, i1) accessor output i0 i1 1 256 * 3 at(i0, i1, i2) accessor output i0 i1 i2 18 4422 1 Huh, well that’s kinda horribly awkward. Did some more playing around with this and I found that i1 is dependent on i0. The higher i0 is the fewer numbers we have available in i1, i2 is unaffected. They are linearly related by a subtraction of 256 in size except for the last index for i0 (in this case 17). Which means that the extra X bands i found and the extra X columns i found are also garbage. Freaking Fantastic. So all we know so far is that our 0th band is correct, we have to find out how to get bands 1 and 2. Digging Intensifies and Saddens After staring at this data for an increasingly depressing amount of time, I determined that only the first dimension is stored in this data buffer we are observing. Meaning that our channels are not contiguous. It appears that the rest of this data is garbage. I was unable to do any bit twiddling or engineering to determine the original data from the source. So, let’s look into how we can get the proper references to the real data. Defeated, I decided to look at their source code here template&lt;typename _Tp&gt; inline const _Tp&amp; Mat::at(int i0) const { CV_DbgAssert(dims &lt;= 2); CV_DbgAssert(data); CV_DbgAssert((unsigned)i0 &lt; (unsigned)(size.p[0] * size.p[1])); CV_DbgAssert(elemSize() == sizeof(_Tp)); if( isContinuous() || size.p[0] == 1 ) return ((const _Tp*)data)[i0]; if( size.p[1] == 1 ) return *(const _Tp*)(data + step.p[0] * i0); int i = i0 / cols, j = i0 - i * cols; return ((const _Tp*)(data + step.p[0] * i))[j]; } template&lt;typename _Tp&gt; inline _Tp&amp; Mat::at(int i0, int i1) { CV_DbgAssert(dims &lt;= 2); CV_DbgAssert(data); CV_DbgAssert((unsigned)i0 &lt; (unsigned)size.p[0]); CV_DbgAssert((unsigned)(i1 * DataType&lt;_Tp&gt;::channels) &lt; (unsigned)(size.p[1] * channels())); CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth&lt;_Tp&gt;::value) == elemSize1()); return ((_Tp*)(data + step.p[0] * i0))[i1]; } template&lt;typename _Tp&gt; inline _Tp&amp; Mat::at(int i0, int i1, int i2) { CV_DbgAssert( elemSize() == sizeof(_Tp) ); return *(_Tp*)ptr(i0, i1, i2); } Let’s take a look at the immense implementation differences between at(i0), at(i0,i1) and at(i0,i1,i2). Look past the obscure OpenCV debug assertions and take a look at the math to compute the point we are referencing. We’re simply accessing at the ptr which looks to be a reference to this line of code linking to this block of code (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]); Fantastic. Please end me. Now let’s Guess and check to find the answer figure out this scary math that requires knowledge of OpenCV’s internals. We can derive that the math is identical for at(i0, i1) take a look at the similarity: 2d: ((_Tp*)(data + step.p[0] * i0))[i1] 3d: (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]) So it’s completely dependent on the step size, our original incorrect ordering (row, col, band) is actually correct but we have an incorrect answer here. Let’s take a look at the step sizes: p[0] p[1] p[2] 6144 24 9223372036854775808 Well, from our Naive approach, that p[2] is wildly incorrect. Almost looks like unallocated space that someone left to play with me. I added the line step.p[2] = sizeof(double); and wouldn’t you know it, worked fine. Does this mean that OpenCV is not assigning the step size properly? Result lut.step.p[2] = sizeof(double); for (unsigned int band = 0; band &lt; lut.channels(); band++) { for (unsigned int row = 0; row &lt; lut.rows; row++) { for (unsigned int col = 0; col &lt; lut.cols; col++) { lut.at&lt;double&gt;(row, col, band); } } } **Note: See OpenCV Team Response Section, the above result is invalid, please use naive solution** Note: It’s possible that the above solution is improper, if you’re paranoid use one of the naive solutions, i will follow up with the OpenCV team to see if this is a possible bug. Lesson’s Learned Never trust open source documentation If you can look at the source code first Try not to hate yourself OpenCV Team Response Edit: 03/21/2018 I filed an open issue with the OpenCV Team and they got back to me fairly quickly (which is a super exciting thing if you know anything about the open source community). The solution provided is invalid. Apparently the 3d accessor is specifically an artifact from Mat3D and is not intended to be used in Mat (as it is considered an array). Well, I’m still glad I went through all this pain, I got to learn how CV stores it’s matricies under the hood. But if this were me I think I would remove this accessor to avoid a headache for someone else (or at least document it)." }, { "title": "Hello World", "url": "/hello-world/", "categories": "development", "tags": "development", "date": "2018-03-18 12:00:00 -0400", "content": "This is just a test to see if I linked everything together properly" } ]
