• Next month, I’m taking my test to get a ham radio licence here in the UK. This is not my first licence. I’ve got LU5ARC years ago, as I was leaving Argentina, so, I never really got to use it. Years before that I’ve got a Yaesu FT411E, but I never transmitted with it due to lack of licence.

    I don’t want that to happen again, so, as soon as I get my licence I want to hit the ground running and start using it. My plan right now is:

    1. Get a VHF/UHF hand held radio.
    2. Learn about antennas by reading:
    3. Get an antenna for VHF/UHF on my car (probably magnetic).
    4. Attempt to install a VHF/UHF vertical antenna in my house.
    5. Decide based on the information I have so far whether I can go for HF.
    6. Set up an HF base station.

    Right now, I’m concerned about step 1. These are the things I’m after, in this order of preference:

    1. VHF
    2. UHF
    3. Ability to use a stationary vertical antenna
    4. Weather proofing
    5. D-Star (with GPS)
    6. APRS (with GPS)

    I could try to get everything now, or maybe do it in stages. I’m not sure yet. I narrowed down my selection to these 5 radios:

    • Kenwood TH-D74
    • Icom ID-51 PLUS2
    • Icom IC-E91
    • Yaesu FT-60E
    • A Baofeng

    Kenwood TH-D74

    The ideal radio seems to exist and it’s the Kenwood TH-D74 (Buy: US). From what I’m seeing this piece of equipment is insane. It does everything and it does almost everything well (except maybe battery life). The price is also insane. If money was no object I would just get this radio and I’m done. I’d probably use it for many, many years.

    Kenwood TH-D74

    Icom ID-51 PLUS2

    The runner up is the Icom ID-51 PLUS2 (Buy: US, UK). It’s more than 35% cheaper than the TH-D74 and it does everything but APRS. From this list it probably has the most bang for the buck since there are two ways of doing APRS: through D-Star repeaters that have it enabled or with an extra piece of kit that you plug to it. The audio quality seems not to be as good as the TH-D74 but it still is great. Like the TH-D74, this is a radio to buy, keep and don’t think about equipment for many years (at least not hand-helds).

    Icom ID-51A PLUS2

    After these two, we get into the get a radio now with the intention of upgrading later.

    Icom IC-E91

    Icom IC-E91The Icom IC-E91 cost less than half of the TH-D74 but I’m a bit puzzled by it. I cannot find a lot of reviews or information about it. It doesn’t seem to be a popular unit. It can do D-Star but to transmit GPS it requires an external GPS module that would put it close to the cost of an ID-51 PLUS2. When it comes to APRS, it’s the same story as for the other Icom on this list.

    Yaesu FT-60

    Yaesu FT-60The Yaesu FT-60 is a good solid radio. It cost about a sixth of the TH-D74 and it only ticks the VHF/UHF boxes on my requirements so this is definitely one to get started and upgrade later.

    A Yaesu FT-411E was my first radio and I always had a soft spot for Yaesu, so it saddens me that they decided to make their own proprietary protocol for digital radio. This is why you don’t see any higher end Yaesu models, I don’t want to use nor support System Fusion. I really hope one day Yaesu will start producing equipment with D-Star, then I will consider again buying their higher end models.

    A Baofeng

    baofeng's messy product line in the uk

    This would cost me the same as a pizza. It’s definitely in the buy something to get started and upgrade later. From a cost point of view, this is a no-brainier. I could just go ahead and buy one or two just for the lolz. I do have two issues with it:

    The first is quality. Obviously I don’t expect high end quality, but I read some reports of horrible things. I don’t want to buy a paperweight.

    The second issue is that I don’t know which one to get. Their line of products is a mess. In the UK they have a gazillion different models. They changed names three times (Pofang, Misuta). Their website is confusing and once I drill down on all the models, they seem to be all the same. If you look at their American presence, there they offer two radios with clear pros and cons, none of which are available in the UK.

    Conclusion

    Well, I don’t have one. I haven’t made a decision yet. I’d like to just buy a Baofeng now and upgrade later, but it sounds like I’m buying a problem. Getting the Yaesu seems a bit expensive for an upgrade-later path (but not too bad). Getting any of the high ends feel like throwing money for a toy instead of taking on a new hobby in a sensible manner.

    Any word of advice?

  • My main computer was an Apple MacBook Pro for about 8 or 9 years. That is, until last January, when I said good-bye to Apple. It wasn’t easy, but the last iteration of the MacBook Pro is terrible.

    I’m not against the touch bar. I think keyboards need more innovation and I applaud the effort. But aside from the touch bar, the keyboard feels weird because they tried to make their power-user product super thin.

    Let me repeat that: for their power user product Apple favors a bit of thinness over usability.

    I don’t know how much of that also pushed them to produce an underpowered product with not a lot of RAM, very expensive hard drive, very expensive in general.

    At the same time as I was in need of a new laptop, I was putting together a gaming computer and I decided instead to add some more funding to that project and turn it into a proper workstation. For the price of a MacBook Pro, I got the most amazing workstation I could ever want. Granted, it’s not mobile, but I need my nice keyboard and monitors to work anyway, so, it suits me well.

    I’m really surprised to be back using Microsoft Windows as my main operating system; something that hasn’t happened since Windows NT 4.0. And I’m happy about it.

    Goodbye Apple, it was fun while it lasted.

  • Searching online for how to set up the credentials to access the database (or any other service) while in development leads to a lot of articles that propose something that works, but it’s wrong: putting your credentials in the application.properties file that you then commit to the repository.

    The source code repository should not have any credentials, ever:

    • You should be able to make your project open source without your security being compromised.
    • You should be able to add another developer to your team without them knowing any credentials to your own development machine.
    • You should be able to hire a company that does a security analysis of your application, give them access to your source code and they shouldn’t gain access to your database.
    • You should be able to use a continuous integration service offered by a third party without that third party learning your database credentials.

    If you want to see what happens when you commit your credentials to your repo, check out these news articles:

    That’s probably enough. I hope I convinced you.

    In an effort to find a solution for this, I asked in Stack Overflow and I got pointed in the right direction.

    Leave application.properties where it is, in your resources of code folder, commit it to the repository. Instead, create a new file in ${PROJECT_ROOT}/config/application.properties and also add it to your version control ignore file (.gitignore, .hgignore, etc). That file will contain the credentials and other sensitive data:

    # This should be used only for credentials and other local-only config.
    spring.datasource.url = jdbc:postgresql://localhost/database
    spring.datasource.username = username
    spring.datasource.password = password

    Then, to help onboard new developers on your project (or yourself in a new computer), add a template for that file, next to it. Something like ${PROJECT_ROOT}/config/application.template.properties that will contain:

    # TODO: copy this to application.properties and set the credentials for your database.
    # This should be used only for credentials and other local-only config.
    spring.datasource.url = jdbc:postgresql://localhost/database
    spring.datasource.username =
    spring.datasource.password =

    And voila! No credentials on the repo  but enough information to set them up quickly.

    Disclaimer: I’m new to Spring Boot, I only started working with it a few days ago, so, I may be missing something big here. If I learn something new that invalidates this post, I’ll update it accordingly. One thing I’m not entirely sure about is how customary it would be to have ${PROJECT_ROOT}/config/application.properties on the ignore list. Please, leave a comment with any opinions or commentary.

  • There’s already an AJAX re-frame effect handler provided by Day8, the same guy who made re-frame and there’s nothing wrong with it. From the documentation, this is how you use it:

    [code lang=”clojure”]
    (re-frame/reg-event-fx ::http-post
    (fn [_world [_ val]]
    {:http-xhrio {:method :post
    :uri "https://httpbin.org/post"
    :params data
    :format (ajax/json-request-format)
    :response-format (ajax/json-response-format {:keywords? true})
    :on-success [::good-post-result]
    :on-failure [::bad-post-result]}}))
    [/code]

    That felt a little to verbose for my taste, so I made my own that you use like this:

    [code lang=”clojure”]

    (re-frame/reg-event-fx ::http-post
    (fn [_world [_ val]]
    {:ajax {:post "https://httpbin.org/post"
    :params data
    :on-success [::good-post-result]
    :on-failure [::bad-post-result]}}))
    [/code]

    If you are familiar with cljs-ajax, you’ll notice the pattern. Day8’s solution uses the raw cljs-ajax API, while I use the higher level one. Day8’s is more versatile, mine is more compact.

    This is my solution:

    [code lang=”clojure”]
    (ns ajax-fx-handler
    (:require [ajax.core :as ajax]
    [re-frame.core :as re-frame]
    [clojure.set :as set]))

    (re-frame/reg-fx :ajax
    (fn http-effect [request]
    (let [request-verb (set/intersection #{:get :post :put :patch :delete :head :options :trace :purge}
    (set (keys request)))]
    (if (not= 1 (count request-verb))
    (throw (js/Error (str "When specifying an AJAX request, one and only one verb should be specified. Found: " request-verb)))
    (let [request-verb (first request-verb)
    url (get request request-verb)
    request (if (contains? request :on-success)
    (assoc request :handler #(re-frame/dispatch (conj (:on-success request) %)))
    request)
    request (if (contains? request :on-failure)
    (assoc request :error-handler #(re-frame/dispatch (conj (:on-failure request) %)))
    request)
    request (-> request
    (dissoc request-verb)
    (dissoc :on-success)
    (dissoc :on-failure))
    ajax-fn (cond
    (= request-verb :get) ajax/GET
    (= request-verb :post) ajax/POST
    (= request-verb :put) ajax/PUT
    (= request-verb :patch) ajax/PATCH
    (= request-verb :delete) ajax/DELETE
    (= request-verb :head) ajax/HEAD
    (= request-verb :options) ajax/OPTIONS
    (= request-verb :trace) ajax/TRACE
    (= request-verb :purge) ajax/PURGE)]
    (ajax-fn url request))))))
    [/code]

    Feel free to use it, but, is it worth releasing it as a library? does anybody want that?

  • For those cases in which there can be one and only one record on the database with certain fields and I don’t just want to get the first one and silently get the wrong one. I want to make sure there’s one and only one, so, I wrote this little extension to ActiveRecord that does exactly that:

    [code lang=”ruby”]
    module ActiveRecordExtension
    extend ActiveSupport::Concern

    class_methods do
    def one_and_only
    records = limit(2).all.to_a
    if records.count > 1
    raise "#{self} generated more than one record when expecting only one."
    else
    records.first
    end
    end

    def one_and_only!
    one_and_only.tap do |record|
    if record.nil?
    raise "#{self} didn’t generate any records."
    end
    end
    end
    end
    end

    ActiveRecord::Base.send(:include, ActiveRecordExtension)
    [/code]
    The first method, one_and_only, will raise an exception if there’s more than one item but it’ll return null if there aren’t any. one_and_only! will fail if there isn’t exactly one and only one record in the database.

    If you don’t know why I’m calling this The Highlander query, you should go and watch Christopher Lambert’s masterpiece.

  • I’m a tech entrepreneur and that has not changed, but after six or seven years of trying to have at least moderate success, I’m starting to hedge my bets.

    On the side, I want to have some passive income and it looks to me like buy and hold properties, that is, buying them and renting them out, also known as buy to let, is the way to move forward. I identified some very profitable areas and they are in the least expected places. For example, in London you can expect a return on investment of around 3% while I’m getting something around 16%.

    If you want to listen to my journey, I’m documenting it as I go with Clayton Morris on his podcast about investing in property. He just published the second episode in which I talk about getting the money for my first two deals.  I just pulled the trigger on starting the business. I’m super excited and I can’t wait to share more good news in the next episode. 

  • Emacs is a very powerful text editor and its popularity amongst Clojurians is easily understood. Emacs has a long tradition in the Lisp communities as it’s written, in a big part, in a flavor of Lisp called Emacs Lisp.

    Because of its history, it handles Lisp code wonderfully, with automatic correct indentation, paraedit, integration with REPLs, etc. But Emacs is really hard to use.

    Yeah, most Clojurians know how to use it by now and they suffer from bias: “it’s not that hard” they say. Learning Emacs or Clojure is hard enough. Combining them is insane.

    Many Clojurians also say it’s worth it. And again, I think they are biased. Human brains are very good at forgetting pain. Other editors these days are also very powerful and although not as much as Emacs, their usage is intuitive so you can achieve a higher level of proficiency just by using it, without spending time and effort in becoming better at it.

    The way Emacs is hurting Clojure is by Clojurians maintaining this myth that you need to use Emacs for Clojure. This is not done by simple statements but by a general culture of jokes saying things such as “you are wrong if you don’t use emacs”.

    Me, personally, I don’t care what editor you use. If you want to learn Emacs, go for it. Intellij and Cursive is much easier to use and almost as powerful. When I compare myself to another clojurian, productivity is generally decided by knowledge of the language and libraries, not the editor. If you want to use another editor, so be it. It’s better if they understand Lisp code but it’s not a deal breaker for learning Clojure.

    I do care about the success and popularity of Clojure. Coupling the growth of the language to the use of an editor that is hard to use and non intuitive makes no sense. It’s hurting us. Even if you are an Emacs power user, when you talk to a Clojure newbie, please, don’t push it down their throats.

    Thank you.

  • Call to Buzz, like many applications I developed before, sends emails. Lot’s of emails. To avoid accidentally emailing a customer or random person I use mail_safe. It’s one of the first gems I install on a Rails project and you should too. mail_safe re-writes the to-header so you end up receiving all the emails that you sent.

    Once you are receiving all these emails, there’s another problem. They are likely to have exactly the same subject, so, mail clients are likely to group them in threads, which can be annoying. To avoid that, I added this to my ApplicationMailer class and voila! all emails have a unique subject:

    [code language=”ruby”]
    if Rails.env.development?
    after_action :uniq_subjects_in_development

    def uniq_subjects_in_development
    mail.subject += " #{SecureRandom.uuid}"
    end
    end
    [/code]

  • I’ve been using both Active Admin and Delayed::Job for years now and both have served me very well. It’s very common for me to want to display job records in the admin tool and have some extra tools around them such as:

    • the ability to mark them all for re-run
    • the ability to run one manually (not recommended for production)
    • the ability to run them all manually (also not recommended for production)
    • an easy way to delete them all
    • a good view of the data inside the job

    To achieve this, over the years, my admin/delayed_job.rb grew and I took it from project to project. Today I want to share it with you in case you are doing the same:

    ActiveAdmin.register Delayed::Job, as: "DelayedJob" do
      collection_action :run_all, method: :post do
        successes, failures = Delayed::Worker.new.work_off
        if failures > 0
          flash[:alert] = "#{failures} failed delayed jobs when running them."
        end
        if successes > 0
          flash[:notice] = "#{successes} delayed jobs run successfully"
        end
        if failures == 0 && successes == 0
          flash[:notice] = "Yawn... no delayed jobs run"
        end
        redirect_to admin_delayed_jobs_url
        I18n.locale = :en # Running delayed jobs can mess up the locale.
      end
    
      if Rails.env.development?
        collection_action :delete_all, method: :post do
          n = Delayed::Job.delete_all
          redirect_to admin_delayed_jobs_url, notice: "#{n} jobs deleted."
        end
      end
    
      collection_action :mark_all_for_re_run, method: :post do
        n = Delayed::Job.update_all("run_at = created_at")
        redirect_to admin_delayed_jobs_url, notice: "Marked all jobs (#{n}) for re-running."
      end
    
      member_action :run, method: :post do
        delayed_job = Delayed::Job.find(params[:id])
        begin
          delayed_job.invoke_job
          delayed_job.destroy
          redirect_to admin_delayed_jobs_url, notice: "1 delayed job run, apparently successfully, but who knows!"
        rescue => e
          redirect_to admin_delayed_jobs_url, alert: "Failed to run a delayed job: #{e.to_s}"
        end
        I18n.locale = :en # Running delayed jobs can mess up the locale.
      end
    
      action_item do
        links = link_to("Run All Delayed Jobs", run_all_admin_delayed_jobs_url, method: :post)
        links += (" " + link_to("Mark all for re-run", mark_all_for_re_run_admin_delayed_jobs_url, method: :post)).html_safe
        links += (" " + link_to("Delete All Delayed Jobs", delete_all_admin_delayed_jobs_url, method: :post)).html_safe if Rails.env.development?
        links
      end
    
      index do
        selectable_column
        id_column
        column "P", :priority
        column "A", :attempts
        column("Error", :last_error, sortable: :last_error) { |post| post.last_error.present? ? post.last_error.split("\n").first : "" }
        column(:created_at, sortable: :created_at) { |job| job.created_at.iso8601.gsub("T", " ") }
        column(:run_at, sortable: :run_at) { |post| post.run_at.present? ? post.run_at.iso8601.gsub("T", " ") : nil }
        column :queue
        column("Running", sortable: :locked_at) { |dj| dj.locked_at.present? ? "#{(Time.now - dj.locked_at).round(1)}s by #{dj.locked_by}" : "" }
        actions
      end
    
      show title: ->(dj) { "Delayed job #{dj.id}" } do |delayed_job|
        panel "Delayed job" do
          attributes_table_for delayed_job do
            row :id
            row :priority
            row :attempts
            row :queue
            row :run_at
            row :locked_at
            row :failed_at
            row :locked_by
            row :created_at
            row :updated_at
          end
        end
    
        panel "Handler" do
          begin
            pre delayed_job.handler
          rescue => e
            div "Couldn't render handler: #{e.message}"
          end
        end
    
        panel "Last error" do
          begin
            pre delayed_job.last_error
          rescue => e
            div "Couldn't render last error: #{e.message}"
          end
        end
    
        active_admin_comments
      end
    
      form do |f|
        f.inputs("Delayed job") do
          f.input :id, input_html: { readonly: true }
          f.input :priority
          f.input :attempts
          f.input :queue
          f.input :created_at, input_html: { readonly: true }, as: :string
          f.input :updated_at, input_html: { readonly: true }, as: :string
          f.input :run_at, input_html: { readonly: true }, as: :string
          f.input :locked_at, input_html: { readonly: true }, as: :string
          f.input :failed_at, input_html: { readonly: true }, as: :string
          f.input :locked_by, input_html: { readonly: true }
        end
    
        f.buttons
      end
    
      controller do
        def update
          @delayed_job = Delayed::Job.find(params[:id])
          @delayed_job.assign_attributes(params[:delayed_job], without_protection: true)
          if @delayed_job.save
            redirect_to admin_delayed_jobs_url, notice: "Delayed job #{@delayed_job} saved successfully"
          else
            render :edit
          end
          I18n.locale = :en # Running delayed jobs can mess up the locale.
        end
      end
    end
  • Ruby on Rails has a very convenient way of presenting a dialog for potentially dangerous tasks that require some confirmation before proceeding. All you have to do is add

    [code language=”ruby”]
    data: {confirm: "Are you sure?"}
    [/code]

    A problem with those, though, is that most (all?) browsers make the dialogs quite ugly:

    Call to Buzz - ugly dialog

    For Call to Buzz, I wanted to finally have something better. Thankfully, there’s a very simple solution, as long as you are using Bootstrap: Twitter::Bootstrap::Rails::Confirm. You just add it to your project and the dialog now looks like this:

    Call to Buzz - bootstrap dialog

    That looks much better, but it’d be nice if it had a nice title, better matching buttons, etc. It’s easy to do by adding some data attributes to the link and the documentation for this gem recommends creating a new method to use instead of link_to when deleting something. I wasn’t very happy with this approach so I resolved it with pure JavaScript so my links remain oblivious to the fact that I’m using this gem:

    [code language=”javascript”]
    $(document).ready(function () {
    $("a[data-confirm]").data({
    "confirm-fade": true,
    "confirm-title": "Call to Buzz"
    });
    $("a[data-method=delete]").data({
    "confirm-title": "Warning",
    "confirm-cancel": "Cancel",
    "confirm-cancel-class": "btn-cancel",
    "confirm-proceed": "Delete",
    "confirm-proceed-class": "btn-danger"
    });
    });
    [/code]

    And with that, the dialog now looks like this:

    Call to Buzz - much better bootstrap dialog

    Update: Later on I wanted to be able to define some extra parameters on a link, such as:

    [code language=”ruby”]
    data: {confirm: "Are you sure you want to disconnect?", confirm_proceed: "Disconnect"}
    [/code]

    To achieve that I re-wrote the code that dynamically adds the extra confirm parameters to look like this (this uses jQuery 3, on earlier version you’d have to do confirm-fade instead of confirmFade):

    [code language=”javascript”]
    $("a[data-confirm]").each(function (_, link) {
    var $link = $(link);
    var data = $link.data();
    data = $.extend({}, {
    "confirmFade": true,
    "confirmTitle": "Call to Buzz"
    }, data);
    if ($link.data("method") == "delete") {
    data = $.extend({}, {
    "confirmTitle": "Warning",
    "confirmCancel": "Cancel",
    "confirmCancelClass": "btn-cancel",
    "confirmProceed": "Delete",
    "confirmProceedClass": "btn-danger"
    }, data);

    }
    $link.data(data);
    });
    [/code]