• Sass Bootstrap 4 in Phoenix 1.3

    Add dependencies to assets/package.json

    • Add font-awesome, bootstrap, jquery to dependencies
    • Add sass-brunch and copycat-brunch to devDependencies
      "dependencies": {
       "phoenix": "file:../deps/phoenix",
       "bootstrap": "4.0.0",
       "font-awesome": "4.7.0",
       "popper.js": "1.12.9",
       "jquery": "3.3.1"
      "devDependencies": {
       "babel-brunch": "6.1.1",
       "brunch": "2.10.9",
       "clean-css-brunch": "2.10.0",
       "uglify-js-brunch": "2.10.0",
       "sass-brunch": "2.10.4",
       "copycat-brunch": "1.0.9"

    Change the app.css to app.scss

    • Delete assets/css/app.css
    • Add assets/css/app.scss
    • Include font-awesome and bootstrap
    $icon-font-path: "/fonts/"; /* use fonts from priv/static/fonts/ */
    @import "font-awesome";
    @import "bootstrap";
    // Overrides 

    Watch for changes in config/dev.exs

    Add scss to the patterns config

      live_reload: [
        patterns: [

    Update brunch-config.js

    1. We need to make sure app.scss loads last
    2. Add copycat config for the font-awesome fonts
    3. Configure scss to include bootstrap and font-awesome
    4. Add $, jQuery, and bootstrap to the globals
        stylesheets: {
          joinTo: "css/app.css",
          order: {
            after: ["../priv/static/css/app.scss"]
        babel: {
          // Do not use ES6 compiler in vendor code
          ignore: [/vendor/]
          "fonts" : ["node_modules/font-awesome/fonts"],
          onlyChanged: true
        sass: {
          options: {
            includePaths: ["node_modules/bootstrap/scss",
              "node_modules/font-awesome/scss"], // tell sass-brunch where to look for files to @import
            precision: 8 // minimum precision required by bootstrap-sass
      npm: {
        enabled: true,
        globals: { // bootstrap-sass' JavaScript requires both '$' and 'jQuery' in global scope
          $: 'jquery',
          jQuery: 'jquery',
          bootstrap: 'bootstrap' // require bootstrap-sass' JavaScript globally

    I think that’s it. Might have to cd assets && npm install and restart Phoenix.

  • Getting started with Elixir

    Phoenix is a web framework build on Elixir, which runs on the Erlang VM. Why check out another web framework & language?

    IDK… the grass is always greener. There are new ideas in new frameworks. Maybe one will fit more with my personal development opinions.

    So here we are. So far I like it. Both Elixir and Phoenix. Have only started some very basic hobby apps. Elixir is very Ruby looking, but pretty different in most regards. It’s functional for one big one. And immutable.


    brew install elixir


    Like Lein & Rake

    mix help
    mix new PROJECT_NAME --sup


    Like Gems https://hex.pm is the place to find then and see how popular they are.

    List of Elixir libs

    CRON scheduler


    Web development

    mix phx.new PROJECT_NAME


    Slack: elixir.slackin


    Plug 'elixir-editors/vim-elixir'
    Plug 'slashmili/alchemist.vim'
  • CES 2018


    CES was about robots this year. There were a lot of toy focused robot kits that were cool. I like the Jimu kit the most.


    And there were robots for automating tasks, like laundry, one’s for playing ping pong, which was more about reaction time and appropriate force. I’m sure there is always robot stuff, but felt like they took it up a level. My favorite was a 3d printing arm, which produces filimate prints as good as the box style printers.


    As always there were TVs, drones, and phones. The codrone was cool in that it had a programable interface that would let you control the drone however you wanted, for example with you computer camera and hand motions.


    But the coolest stuff was again in Eureka Park.

    Tons of home automation stuff, personal data trackers, and AR/VR stuff. AR/VR stuff still seems early, but also like huge progress from last year. I liked the Swidget outlet with it’s swapable modules for different types of automation technologies. They have dev boards for making your own modules and an API coming in the future.


    The coolest looking thing for me was a new motorcycle from Yamaha. Electric, self driving functions, and heads up display. Also, amazing looking design.


    Business wise, the BLE 5 chips are a big jump forward and offer some pretty awesome tech. Looking forward to playing with those dev kits! Of course, we had good meetings with a bunch of folks, parties, and networking, which is where the value really is.

  • GoBuffalo Nested Resources

    Buffalo is a web framework written in Go by Mark Bates. I’ve been working more with Go and started using Buffalo. Mark has done an awesome job with it! Thanks Mark!

    Pretty quickly into my app I wanted nested resources. Support for them seems pretty much there. It takes some work, but all in all it was pretty easy to get going. Here are some notes about how I approached it.

    Getting started

    I started following some of the videos on the Buffalo site. From there I generated some resources; User, Org, Index. I wanted Indexes to be nested under Orgs.



    indices := app.Resource("/orgs/{org_id}/indices", IndicesResource{&buffalo.BaseResource{}})

    There we grab a reference to the resource group, named indices and then add the LoadOrg middleware.


    Every action in the Indices resource should have the Org available. I was looking for some BeforeAction hook or something, but didn’t find any. Enter middleware.


    func LoadOrg(next buffalo.Handler) buffalo.Handler {
    	return func(c buffalo.Context) error {
    		tx := c.Value("tx").(*pop.Connection)
    		user := c.Value("current_user").(*models.User)
    		o := &models.Org{}
    		if err := tx.BelongsToThrough(user, "org_users").Find(o, c.Param("org_id")); err != nil {
    			c.Error(404, err)
    		c.Set("org", o)
    		return next(c)

    This does two things…

    1. Make sure the Org is available to the User.
    2. Set org in the Context


    The actions need some updating, mostly updating them to scope the queries to the Org, make sure new Indexes get added to the Org, and changing some of the redirect URLs.


    func (v IndicesResource) scope(c buffalo.Context) *pop.Query {
    	tx := c.Value("tx").(*pop.Connection)
    	org := c.Value("org").(*models.Org)
    	return tx.BelongsTo(org)
    func (v IndicesResource) newIndex(c buffalo.Context) *models.Index {
    	orgID, err := uuid.FromString(c.Param("org_id"))
    	if err != nil {
    		c.Error(404, err)
    	return &models.Index{OrgID: orgID}

    Those two helper functions help scope the queries and set the OrgID on new model instances.

    I’m not showing all the changes needed, they’ll be pretty obvious.


    I was kinda worried about this, but it turned out to already be supported. I’m not sure if it’s part of Mux or Buffalo yet, but either way it works.

    What works? You’re wondering… links!


    <!-- Generated Version -->
    <li><a href="<%= newIndicesPath() %>" class="btn btn-primary">Create New Index</a></li>
    <!-- Nested Version -->
    <li><a href="<%= newOrgIndicesPath({org_id: org.ID}) %>" class="btn btn-primary">Create New Index</a></li>

    Adding Org or org to the path function and passing in the org_id value was all that was needed. And the org is in the Context already thanks to out middleware above!

    Would love to know if I missed something already built in to the generators or a better way to handle any of this, but pretty happy with the results.

  • Starting cloudsh search project


    I’m starting a new side project to learn Golang and use AWS Lambda.

    The basic idea is an API that will index a website and provide a searching interface using JavaScript.

    The target users are those creating static / generated sites. Sites where having a database setup doesn’t make sense.

    I’m gonna run the API and processing on AWS Lambda using the awesome Apex and Up projects. I really like the serverless idea and am looking forward to trying it out.

    If it sounds interesting, join the mailing list at cloudsh

  • jQuery welcome mat

    Welcome mat for getting email addresses or promoting other things to recent visitors to your site. Hides the form after the first view for 14 days.

    Needs jQuery before the following code.

    jQuery(document).ready(function($) {
      var setCookie = function(key, value, days) {
        var expires = new Date();
        expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
        document.cookie = key + '=' + value + ';expires=' + expires.toUTCString() +';path=/';
      var getCookie = function(key) {
        var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
        return keyValue ? keyValue[2] : null;
      var visitedBefore = getCookie('welcome-mat-1');
      var el = $(".welcome-mat");
      if (visitedBefore !== '1') {
        $("body").prepend( el );
        $("div.welcome-mat").hide().css("height", $(window).height()).slideDown(750);
        $("div.welcome-mat-content").css("margin-top", ($(window).height() - $(".welcome-mat-content").outerHeight()) / 2);
        $(window).bind("resize", function() {
          $("div.welcome-mat").css("height", $(window).height());
          $("div.welcome-mat-content").css("margin-top", ($(window).height() - $(".welcome-mat-content").outerHeight()) / 2);
        $('.close-welcome-mat').on('click', function(e){
          $("div.welcome-mat").slideUp(500, function() { 
        setCookie('welcome-mat-1', '1', 14);

    Add the following style and HTML to the page. Doesn’t matter where, but I put it near the bottom of the page. It will vertically center the welcome-mat-content.

      .welcome-mat {
        height: 0px;
        z-index: 1100;
        display: none;
        position: relative;
        background: white;
    <div class="welcome-mat container">
      <div class="row welcome-mat-content">
        Whatever content you want here
  • Who's Got Your Back

    Explores the idea of creating a few deep relationships to help you get farther in your goals then you could by yourself. Basically, creating relationships where you can get and give honest feedback to overcome obstacles and roadblocks, some that you probably can’t see yourself.



    The 4 mind sets: Candor < Vulnerability < Accountability < Generosity

    9 steps

    1. Articulate your vision
    2. Find your lifeline relationships
    3. Practice the art of the long slow dinner
    4. Broaden your goal-setting strategy (learning and performance goals)
    5. Create your Personal Success Wheel
    6. Learn to fight
    7. Diagnose your weaknesses
    8. Commit to improvement
    9. Fake it till you make it then make it stick

    Starting point for staring your own group: How to Conduct a Meeting (Kindle Locations 3793-3794).

    Who’s Got Your Back Author: Keith Ferrazzi