<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Collective Idea Blog</title>
<link href="https://collectiveidea.com/blog/feed" rel="self"/>
<link href="https://collectiveidea.com/blog"/>
<id>https://collectiveidea.com/blog</id>
<updated>2024-07-24T14:25:31+00:00</updated>
<entry>
<title>Let&#39;s make Twirp and Protobufs easier with Ruby</title>
<link href="https://collectiveidea.com/blog/archives/2024/07/24/generating-twirp-ruby-protobuf-integration-using-ruby"/>
<id>https://collectiveidea.com/blog/archives/2024/07/24/generating-twirp-ruby-protobuf-integration-using-ruby</id>
<updated>2024-07-24T14:25:31+00:00</updated>
<published>2024-07-24T10:16:10-04:00</published>
<content type="html">
<![CDATA[
<div>
<p>At Collective Idea, we’re fans of <a href="https://protobuf.dev/">Protocol Buffers</a>. We love <a href="https://github.com/twitchtv/twirp">Twirp</a> for it’s ease-of-use and simplicity, and have multiple production clients and servers using it.</p>
<p>As Rubyists, we use <a href="https://github.com/arthurnn/twirp-ruby">Twirp-Ruby</a>, and have <a href="https://github.com/collectiveidea/twirp-rails">open-sourced both how we integrate it into our rails apps with our <code>twirp-on-rails</code> gem</a> and how we <a href="https://github.com/collectiveidea/twirp-kmm">leverage Twirp in our mobile apps with our twirp-kmm kotlin multiplatform mobile client library.</a> (Editor’s Note: Expect more posts on these… we’ve been lazy.)</p>
<p>We want to make our toolchain even better, but first some background explanation:</p>
<p>Twirp-Ruby is comprised of two distinct parts: 1) A <a href="https://rubygems.org/gems/twirp"><code>twirp</code> Ruby gem</a> that provides <code>Twirp::Service</code> and <code>Twirp::Client</code> DSLs for runtime use and 2) a plugin to the <code>protoc</code> protobuf compiler, <a href="https://github.com/arthurnn/twirp-ruby/tree/main/protoc-gen-twirp_ruby"><code>protoc-gen-twirp_ruby</code> written in Go</a>, that generates services and clients from .proto files.</p>
<p>The <code>protoc</code> plugin is mostly fine. It works, but has some issues and can be a headache for folks in the Ruby ecosystem not used to working with Go.</p>
<p>So, we started asking ourselves… what if?</p>
<p>What if we made the code generator more accessible to Rubyists? What if installing the <code>protoc</code> plugin was as simple as installing a gem? What if we could rapidly iterate on it to address community needs, fix longstanding bugs, and add quality-of-life improvements?</p>
<p>We scratched that itch and explored the possibilities. Today we’re happy to announce the result of this effort, the <a href="https://github.com/collectiveidea/protoc-gen-twirp_ruby"><code>protoc-gen-twirp_ruby</code> gem</a>: a <code>protoc</code> plugin, written in Ruby, for generating Twirp-Ruby clients and/or services.</p>
<p>Our gem is a drop-in replacement for the Go module. It generates similar code, but fixes some things and adds helpful new features along the way. The gem is covered with a comprehensive test suite, allowing us to iterate quickly without worrying about breakage.</p>
<p>We’ve switched our projects over to it. Integration is simple: Add<code>gem install protoc-gen-twirp_ruby</code> or add it to your <code>Gemfile</code>:</p>
<pre><code class="language-ruby">gem "protoc-gen-twirp_ruby"
</code></pre>
<p>If you previously installed the Go extension from Twirp-Ruby, you have to run one command:</p>
<pre><code class="language-bash">rm `go env GOPATH`/bin/protoc-gen-twirp_ruby
</code></pre>
<p>Now when you run <code>protoc</code>, it will use the Ruby version.</p>
<p>We hope you find it as useful as we have!</p>
</div>
]]>
</content>
<author>
<name>
Darron Schall
</name>
</author>
</entry>
<entry>
<title>Job Queues</title>
<link href="https://collectiveidea.com/blog/archives/2024/03/26/job-queues"/>
<id>https://collectiveidea.com/blog/archives/2024/03/26/job-queues</id>
<updated>2024-03-26T14:55:43+00:00</updated>
<published>2024-03-26T09:41:47-04:00</published>
<content type="html">
<![CDATA[
<div>
<p>I <a href="https://mastodon.cc/@jgarber/112157039228408751">saw a question</a> yesterday about async jobs in Rails and thought I’d expand my thoughts here.</p>
<h2>Quick History</h2>
<p>First, some background. Our team has led maintenance of <a href="https://github.com/collectiveidea/delayed_job">Delayed Job</a>, the biggest background job gem in the Rails world since 2008ish. We didn’t write it, that honor goes to <a href="https://github.com/tobi">Tobi</a> at <a href="https://www.shopify.com">Shopify</a>, back when they were a much smaller organization. For reasons that probably had to do with Tobi’s job taking up more time, we ended up being the group publishing gems and maintaining it.</p>
<p>Delayed Job is still great. It has been battle-tested and remains solid. It can handle any ActiveRecord database and also MongoDB via Mongoid. It can even work outside of a Rails app.</p>
<p>There’s nothing wrong with it, and I don’t think anyone needs to move away from it. It works. It’ll continue to work.</p>
<p>However, we haven’t added it to new projects in years. Why? Better options came up that fit us better. I’ll explain.</p>
<h2>Sidekiq</h2>
<p><a href="https://sidekiq.org">Sidekiq</a> came out, backed by Redis, and a dedicated maintainer in Mike Perham. Mike’s done a fantastic job. We’ve been able to use the Pro and Enterprise versions over the years and they are very mature and well-built. It can handle anything you throw at it.</p>
<p>Sidekiq is still a favorite. Especially for heavy users, who will have millions of jobs and need reliability and/or support. I don’t think any of the teams we worked with ever needed support, which is testament to the product.</p>
<p>We also build a lot of small apps and would often deploy to <a href="https://www.heroku.com/">Heroku</a>. Heroku made it easy to use Sidekiq by having multiple add-ons with free Redis plans.</p>
<p>Redis has been solid for us, but it is one more moving piece that needs to be managed, and often comes with added cost. That makes sense for some teams, but not all. Sometimes we’ve used Redis for other things too (caching and rack-attack come to mind) but not every app needs that.</p>
<p>Free plans started to go away, so Sidekiq wasn’t as easy of a sell for these small projects. We started looking elsewhere.</p>
<h3>Active Job</h3>
<p>Somewhere along the line, <a href="https://guides.rubyonrails.org/active_job_basics.html">Active Job</a> was added to Rails. Active Job isn’t a job runner, but a standard API to different job queues. It is a good idea, and Delayed Job and Sidekiq both added support. We use Active Job’s API for everything these days.</p>
<h2>Back to the Database</h2>
<p>A big benefit of Delayed Job was that it used your app’s database. That both made it easier to run locally, and easier to deploy.</p>
<p>When we first worked on Delayed Job, multiple database support was important. We had clients already using MySQL, and MongoDB was in our arsenal for a while. <a href="http://postgresql.org">PostgreSQL</a> was always our favorite (before it was cool) and these days it is rare we need to touch another DB (at least for an app’s primary).</p>
<p>I long thought about what a re-imagining of Delayed Job that targeted PostgreSQL would look like. It would ditch all the other database support, only support Active Job, and do some other magic. Fortunately for all of us, someone else had an even better version of this idea and actually built it.</p>
<h2>GoodJob</h2>
<p><a href="https://github.com/bensheldon/good_job">GoodJob</a> is that better re-imagining. It only cares about PostgreSQL and takes advantage of many of its unique features. It is also Active Job only, so a simple API.</p>
<p>GoodJob also builds in many things you’d need Sidekiq Pro or Enterprise (or a Delayed Job plugin) to use: web UI, cron<sup><a href="#fn1" id="source1">1</a></sup> jobs, batches, unique jobs, etc.</p>
<p>We’ve moved many projects to GoodJob over the past couple years, and it is our go-to for new projects. It is actively developed and continually improving.</p>
<h2>What about Solid Queue?</h2>
<p><a href="https://github.com/rails/solid_queue">Solid Queue</a> came out at the end of 2023 to be a new default choice for Rails apps. It uses your database, and focuses on Active Job. It can use any database Rails can support, but doesn’t get some of the fancy PostgreSQL features we get in GoodJob.</p>
<p>We haven’t spent real time looking at Solid Queue yet. From the outside, it looks to be a good default for most people. A modern version of Delayed Job, without some of the pre-Active Job stuff that 99% of people won’t need.</p>
<h2>Other job queues</h2>
<p><a href="https://github.com/resque/resque">Resque</a> has a long history and is still going strong. I haven’t used it in a while, so can’t really comment intelligently.</p>
<p><a href="https://github.com/brandonhilkert/sucker_punch">Sucker Punch</a> got some use in our office, to avoid using a separate job worker. It works well, but can lose jobs, which is a non-starter for many of our projects.</p>
<p>There are many more, some listed in the <a href="https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html">Active Job</a> docs. I don’t have enough experience with any to comment.</p>
<h2>Moving between Queue systems</h2>
<p>I should note that Active Job makes it easy to switch queue systems. Having moved a Sidekiq project to GoodJob recently, you do have to pay attention to a few things, like concurrency and error handling, but it is a fairly quick process. So try something new, stick to the Active Job API, and you can always switch later.</p>
<h2>Summary</h2>
<ul>
<li>Delayed Job is still great and will keep working. Don’t change if you don’t need to.</li>
<li>Sidekiq is great, especially Pro and Enterprise. No notes.</li>
<li>GoodJob is our new primary pick. PostgreSQL-only which is a feature, not a bug, for us. Works great, and has great features.</li>
<li>Solid Queue looks like it’ll be a good default for most people.</li>
<li>There are others that might be great. I only know so much.</li>
<li>Active Job makes it pretty easy to move between.</li>
</ul>
<p><small><sup><a href="#source1" id="fn1">1</a></sup> One of these days I’ll write up how we monitor GoodJob cron using <a href="https://deadmanssnitch.com">Dead Man’s Snitch</a>.</small></p>
</div>
]]>
</content>
<author>
<name>
Daniel Morrison
</name>
</author>
</entry>
<entry>
<title>Collapsing old Rails Migrations</title>
<link href="https://collectiveidea.com/blog/archives/2023/09/06/collapsing-old-rails-migrations"/>
<id>https://collectiveidea.com/blog/archives/2023/09/06/collapsing-old-rails-migrations</id>
<updated>2023-09-06T17:18:25+00:00</updated>
<published>2023-09-06T13:05:22-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/29694808950_f18e6e6df2_k.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>Earlier today, Jason Garber <a href="https://mastodon.cc/@jgarber/111018810071623367">asked</a>,</p>
<blockquote cite="https://mastodon.cc/@jgarber/111018810071623367"><a href="https://mastodon.cc/tags/RubyOnRails">#RubyOnRails</a> folks: hit me with your hot takes on how to manage/archive/delete your app’s “old” migrations.</blockquote>
<p>My quick response was, “Why bother?” and I generally stand by that. Sure the directory gets large, but it doesn’t hurt anything. New ones always go the the end anyway. In large apps, a new developer might not want to run all of them from the beginning and do a <code>rails db:schema:load</code> on setup. That’s fine. But you get extra nerd points if all migrations still work years later!</p>
<p>But what if you still <em>wanted</em> to clean them up? Here’s how I’d do it.</p>
<h3>1. Add a new migration</h3>
<p><code>$ rails generate migration collapse_old_migrations</code></p>
<p>Then, I’d copy everything from <code>schema.rb</code> into there. Easy. Mostly done.</p>
<h3>2. Add some quick &amp; dirty cleverness</h3>
<p>Now, this migration will bomb if you try to run it, as you already have all these tables. Same on coworkers’ machines, and your production environment. In each environment, the migration number is tracked to know if it has run before.</p>
<p>So what I’d do is <strong>immediately comment out everything in this migration</strong>. Make it look empty.</p>
<p>Commit it and let it run everywhere.</p>
<h3>3. Clean up</h3>
<p>Now, come back some time later and uncomment everything in that migration. Anyone who’s already run it won’t re-run it, so we’re “safe” now. Finally, delete all the old migrations that you just obsoleted.</p>
<p>That’s it, done! A new coworker will pick up the project and only see this migration (and any newer) and not know what they’ve missed. An existing coworker won’t know anything happened.</p>
</div>
<p>Photo credit: <small><p>“Wildebeests on charred grass.” Photo by Susan Jane Golding. Used under a Creative Commons CC BY 2.0 License. https://flickr.com/photos/sjgolding/29694808950</p>
</small></p>
]]>
</content>
<author>
<name>
Daniel Morrison
</name>
</author>
</entry>
<entry>
<title>Five O&#39;Clock  Somewhere</title>
<link href="https://collectiveidea.com/blog/archives/2023/03/18/five-o-clock-somewhere"/>
<id>https://collectiveidea.com/blog/archives/2023/03/18/five-o-clock-somewhere</id>
<updated>2023-03-18T14:10:38+00:00</updated>
<published>2023-03-18T10:08:19-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/6302542008_bcd9ed119f_k.jpeg?size=2015_blogpost_small" alt=""/>
<div>
<p>I came across an interesting problem yesterday. I have a PostgreSQL table full of users with a time_zone column stored as a string like “America/Detroit”. I needed to find all the users where it was the 5:00 hour<sup>1</sup>.</p>
<p>Chris and I got playing with some queries and found how easy it is to grab the local time for a user:</p>
<pre><code># SELECT id, time_zone, now()::timestamp at time zone time_zone 
#   FROM users 
#   WHERE time_zone IS NOT NULL;

                  id                  |    time_zone    |           timezone            

--------------------------------------+-----------------+-------------------------------

 5d1c0abb-0c35-4454-9e19-6e50ccc6c37e | America/Detroit | 2023-03-17 15:48:44.17624

 dddbca1f-f30e-4997-80f8-c996c6008fac | America/Phoenix | 2023-03-17 12:48:44.17624

(2 rows)</code></pre>
<p>You can do a bit more to get the current hour:</p>
<pre><code># select id, now()::timestamp with time zone at time zone time_zone, 
#   date_part('hour', now()::timestamp with time zone at time zone time_zone) AS local_hour 
#   FROM users 
#   WHERE time_zone IS NOT NULL;

                  id                  |         timezone          | local_hour 

--------------------------------------+---------------------------+------------

 5d1c0abb-0c35-4454-9e19-6e50ccc6c37e | 2023-03-17 15:48:44.17624 |         15

 dddbca1f-f30e-4997-80f8-c996c6008fac | 2023-03-17 12:48:44.17624 |         12

(2 rows)</code></pre>
<p>Now to select those users were it is 5:00 (I used 15 or 3:00 here, but you get the idea). Move the date_part to a WHERE:</p>
<pre><code># select id FROM users 
#   WHERE date_part('hour', now()::timestamp with time zone at time zone time_zone) = 15;

                  id                  

--------------------------------------

 5d1c0abb-0c35-4454-9e19-6e50ccc6c37e

(1 row)</code></pre>
<p>And that’s it!</p>
<p>In a Rails app, I could use this like this:</p>
<pre><code># Who's in the 5:00 PM (17:00) hour?
User.where("date_part('hour', now()::timestamp with time zone at time zone time_zone) = ?", 17)
</code></pre>
<p>Enjoy!</p>
<p><sup>1</sup>Okay, I really wanted a different time, but I was working on this at 4:00 on a Friday.</p>
</div>
<p>Photo credit: <small><p>Photo by John Seb Barber on Flickr https://www.flickr.com/photos/johnseb/6302542008<br/>
Licensed under Creative Commons CC BY 2.0: https://creativecommons.org/licenses/by/2.0/</p>
</small></p>
]]>
</content>
<author>
<name>
Daniel Morrison
</name>
</author>
</entry>
<entry>
<title>Fix for Heroku Breaking Ancient Apps</title>
<link href="https://collectiveidea.com/blog/archives/2023/03/02/fix-for-heroku-breaking-ancient-cedar-14-apps"/>
<id>https://collectiveidea.com/blog/archives/2023/03/02/fix-for-heroku-breaking-ancient-cedar-14-apps</id>
<updated>2023-05-18T15:55:40+00:00</updated>
<published>2023-03-02T10:12:18-05:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/21828243446_b0c9278cf2_k.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>Have a really old Heroku app that recently broke? We still help with more cedar-14 apps, mostly Rails, than I’d like to admit, and they all seemed to break this week.</p>
<p>Heroku has been doing some database maintenance, and has been “helpfully” upgrading old databases to Postgres 14. Normally, I might be excited about that, but these old apps can’t handle it. We see an error like this:</p>
<pre><code>PG::InvalidParameterValue: ERROR:  invalid value for parameter "client_min_messages": "panic"
HINT:  Available values: debug5, debug4, debug3, debug2, debug1, log, notice, warning, error.
: SET client_min_messages TO 'panic'
</code></pre>
<p>The fix is straightforward, at least for now:</p>
<p>1. Add a new database, the same size, but with Postgres 11. Note: you can only do this from the command line.</p>
<pre><code>heroku addons:create heroku-postgresql:basic --version=11 --app your-app-here
</code></pre>
<p>2. Find the ENV var name, in my case today it was <code>HEROKU_POSTGRESQL_MAUVE</code>.</p>
<p><img src="/assets/Screenshot 2023-03-02 at 10.00.31 AM.png" alt="Screenshot 2023-03-02 at 10.00.31 AM.png"/></p>
<p>3. Copy the data, like normal. </p>
<pre><code>heroku pg:copy DATABASE_URL HEROKU_POSTGRESQL_MAUVE --app your-app-here
</code></pre>
<p>4. Promote the database</p>
<pre><code>heroku pg:promote HEROKU_POSTGRESQL_MAUVE --app your-app-here
</code></pre>
<p>5. Delete the old DB </p>
<p>Save yourself some money.</p>
<p>That’s it!</p>
<p>…at least until these really old apps or DBs no longer run. But that’s a harder upgrade path. <a href="/contact">Contact us</a> if you need help with that.</p>
</div>
<p>Photo credit: <small><p>Photo by Christophe BENOIT on Flickr https://www.flickr.com/photos/christophebenoit/21828243446<br/>
Licensed under Creative Commons CC BY 2.0: https://creativecommons.org/licenses/by/2.0/</p>
</small></p>
]]>
</content>
<author>
<name>
Daniel Morrison
</name>
</author>
</entry>
<entry>
<title>Keep Your Certificates Current Using Cron &amp; Dead Man&#39;s Snitch</title>
<link href="https://collectiveidea.com/blog/archives/2018/08/20/keep-your-certificates-current-using-cron-and-dead-mans-snitch"/>
<id>https://collectiveidea.com/blog/archives/2018/08/20/keep-your-certificates-current-using-cron-and-dead-mans-snitch</id>
<updated>2022-03-18T19:49:35+00:00</updated>
<published>2018-08-20T11:25:18-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/33292061925_6b45ef2b7d_o.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>In 2015 I wrote about <a href="https://collectiveidea.com/blog/archives/2015/08/24/keep-your-certificates-current-with-your-test-suite">Keep Your Certificates Current Using Your Test Suite</a>. That’s still good but has a couple problems that bug me:</p>
<ol>
<li>It can block development. Suddenly, your test suite is red until you fix these certificates, even though you have a week to fix it.</li>
<li>It can block deployment. If you require green tests to deploy, suddenly you can’t deploy and don’t know why (I’ve been bit by this).<br/>
I still like getting notifed of certificates that are due to expire, so let’s come up with something even better. Leveraging <a href="https://cron.help">cron</a> and <a href="https://deadmanssnitch.com/">Dead Man’s Snitch</a>.</li>
</ol>
<p>I’m working on an app today that has four certificates, all for Apple Push Notifications (<abbr title="Apple Push Notification Service">APNS</abbr>). They’re all in a folder <code>config/certificates</code></p>
<h2>Step 1: Build a rake task</h2>
<p>Here’s a rake task I wrote up in Ruby to check each certificate:</p>
<pre class="ruby"><code>task :check_certificates do
  expiring = []
  path = Rails.root.join("config/certs/*.pem")

  Dir.glob(path).each do |file|
    certificate = OpenSSL::X509::Certificate.new(File.read(file))
    if certificate.not_after.to_time &lt;= 1.week.from_now
      expiring &lt;&lt; file
    end
  end

  if expiring.any?
    # abort is more graceful than raising an exception
    # it also gives us a non-zero status code
    # which is useful for Dead Man's Snitch
    abort "Certificate(s) will expire in less than 1 week: #{expiring.join(", ")}"
  end
end
</code></pre>
<h2>Step 2: Add it to cron</h2>
<p>Using cron, I run this task once per day. For example, if I wanted it run at <a href="https://cron.help/#0_8_*_*_*" title="View info at cron.help">7am every day</a>, my crontab entry might look like this:</p>
<pre class="bash"><code># Every day at 11:00AM UTC (7:00AM EST)
# https://cron.help/#0_11_*_*_*
0 11 * * * bundle exec rake check_certificates</code></pre>
<h2>Step 3: Get Notified with Dead Man’s Snitch</h2>
<p>I’m assuming you already know how to use <a href="https://deadmanssnitch.com">Dead Man’s Snitch</a> to get alerted when something doesn’t happen. If not, go read the <a href="https://deadmanssnitch.com/docs">Getting Started documentation</a>.</p>
<p>The most common way to use Dead Man’s Snitch for <a href="https://deadmanssnitch.com/docs/cron-job-monitoring">cron job monitoring</a> is to add a curl to the end:</p>
<pre class="bash"><code># Every day at 11:00AM UTC (7:00AM EST)
# https://cron.help/#0_11_*_*_*
0 11 * * * bundle exec rake check_certificates &amp;&amp; curl http://nosnch.in/c2354d53d2 &amp;&gt; /dev/null</code></pre>
<p>I’m going to go a step farther and use Dead Man’s Snitch’s <a href="https://deadmanssnitch.com/docs/field-agent">Field Agent</a>. That way I get notified immediately, and get other great stuff like error messages.</p>
<pre class="bash"><code># Every day at 11:00AM UTC (7:00AM EST)
# https://cron.help/#0_11_*_*_*
0 11 * * * dms c2354d53d2 bundle exec rake check_certificates</code></pre>
<p>That’s it! Now when my certificates are a week away from expiration, my team will get notified through <a href="https://deadmanssnitch.com">Dead Man’s Snitch</a> and I can fix them.</p>
<p>Have a different method you like for tracking expiration? Let me know in the comments.</p>
</div>
<p>Photo credit: <small><p>Photo © AJS Pimentel. Licensed under Creative Commons. https://flic.kr/p/SHUw8F</p>
</small></p>
]]>
</content>
<author>
<name>
Daniel Morrison
</name>
</author>
</entry>
<entry>
<title>Part 3: ARKit Wall and Plane Detection for iOS 11.3</title>
<link href="https://collectiveidea.com/blog/archives/2018/07/12/part-3-arkit-wall-and-plane-detection-for-ios-11.3"/>
<id>https://collectiveidea.com/blog/archives/2018/07/12/part-3-arkit-wall-and-plane-detection-for-ios-11.3</id>
<updated>2019-10-10T12:56:37+00:00</updated>
<published>2018-07-12T11:11:18-04:00</published>
<content type="html">
<![CDATA[
<div>
<p>In <a href="https://collectiveidea.com/blog/archives/2018/04/30/part-1-arkit-wall-and-plane-detection-for-ios-11.3">Part 1</a> of this series on ARKit wall and plane detection we ended with the ability to detect planes. (<a href="https://github.com/collectiveidea/ARPlaneDetector/releases/tag/Part1">Final Part 1 Project File</a>). And in <a href="https://collectiveidea.com/blog/archives/2018/05/08/part-2-arkit-wall-and-plane-detection-for-ios-11.3">Part 2</a> we added a grid to visualize the planes. (<a href="https://github.com/collectiveidea/ARPlaneDetector/releases/tag/Part2">Final Part 2 Project File</a>)</p>
<p>Now, in Part 3 we’re going to place an object at the plane’s position. When I pulled the <a href="https://github.com/collectiveidea/ARPlaneDetector">master</a>, I had some fun and added the ability to shoot a “blunt object” from your screen and have it bounce off the 3D objects ;)</p>
<p>Here’s what we’re building today.</p>
<p><img src="/assets/AR-Kit-wall-detection.gif" alt="AR-Kit-wall-detection.gif"/></p>
<p>As a note, if you’re starting with Part 3, download the <a href="https://github.com/collectiveidea/ARPlaneDetector/releases/tag/Part2">starter project here</a>.</p>
<p>The first thing we need to do is add a tap gesture to the view. In <code>viewDidLoad()</code> add this to the bottom.</p>
<pre><code class="language-swift">let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapScene(_:)))
        view.addGestureRecognizer(tapGesture)
</code></pre>
<h2>Creating the action</h2>
<p>Now let’s create our <code>didTapScene(_:)</code> action. Add this below <code>viewDidLoad()</code>.</p>
<pre><code class="language-swift">@objc func didTapScene(_ gesture: UITapGestureRecognizer) {
        switch gesture.state {
        case .ended:
            //1
            let location = gesture.location(ofTouch: 0,
                                            in: sceneView)

            //2
            let hit = sceneView.hitTest(location,
                                        types: .existingPlaneUsingGeometry)
            //3
            if let hit = hit.first {
                placeBlockOnPlaneAt(hit)
            }
        default:
            break
        }
    }
</code></pre>
<p>1) First, convert the tap location to <code>ARSCNView</code>.</p>
<p>2) <code>ARSCNView</code> has a <code>hitTest</code> method that checks if a point in a scene intersects another object, defined by the <code>types</code> parameter. In this step we use <code>.existingPlaneUsingGeometry</code> because we are using planes that have already been found. Check out the other options of <code>ARHitTestResult.ResultType</code> as there are some neat things in there. For instance, <code>estimatedVerticalPlane</code> speeds up the placement of objects by not waiting for an <code>ARPlaneAnchor</code> to be found first. As planes are located, you can update the position of your objects to align more precisely.</p>
<p>3) Find the first plane that was tapped, and call <code>placeBlockOnPlaneAt(_ hit: ARHitTestResult)</code> passing in our <code>ARHitTestResult</code>.</p>
<h2>Defining the method</h2>
<p>Now we’re going to define that method. Add this below <code>didTapScene</code>.</p>
<pre><code class="language-swift">func placeBlockOnPlaneAt(_ hit: ARHitTestResult) {
       //1
        let box = createBox()
        position(node: box, atHit: hit)
        //2
        sceneView?.scene.rootNode.addChildNode(box)
    }
</code></pre>
<p>1) Here we need to call a helper method to create and position a 3D box node. We will define that later.</p>
<p>2) Add the box to the scene’s rootNode.</p>
<h2>Defining the helper methods</h2>
<p>This is where we define the helper methods.</p>
<pre><code class="language-swift">private func createBox() -&gt; SCNNode {
        let box = SCNBox(width: 0.15, height: 0.20, length: 0.02, chamferRadius: 0.02)
        let boxNode = SCNNode(geometry: box)

        return boxNode
    }
</code></pre>
<h2>Creating the box</h2>
<p>Here we create a box and round its edges.</p>
<pre><code class="language-swift">private func position(node: SCNNode, atHit hit: ARHitTestResult) {
        //1
        node.transform = SCNMatrix4(hit.anchor!.transform)
        //2
        node.eulerAngles = SCNVector3Make(node.eulerAngles.x + (Float.pi / 2), node.eulerAngles.y, node.eulerAngles.z)
        //3
        let position = SCNVector3Make(hit.worldTransform.columns.3.x + node.geometry!.boundingBox.min.z, hit.worldTransform.columns.3.y, hit.worldTransform.columns.3.z)
        node.position = position
    }
</code></pre>
<p>1) Transform the box to match the ARPlaneAnchor’s transform.</p>
<p>2) Next we want to rotate our box so it lies long ways on top of our plane. Adjust its <code>eulerAngles</code> by rotating it 90 degrees along its x axis.</p>
<p>3) Now we need to figure out the position by using the <code>ARHitTestResult</code>’s columns property’. (Figuring out how to place something in a 3D world can be quite confusing!) And we just take into account the height of the node so it looks like it’s resting on top/in front of the surface.</p>
<h2>Testing your app</h2>
<p>Finally, run your app to see if you can tap on a plane and see a box plopped at that position.</p>
<p>If all is working correctly, you’ll notice that once you place an object, the plane itself will continue to adjust as it learns more about its surface, which may make your box object no longer look as its sitting directly on the plane.</p>
<p>The boxes are completely white, so let’s quickly add a light to the scene to give them some dimension. After that, we can call it good!</p>
<p>Open up <code>ARSceneManager.swift</code> and add <code>self.sceneView?.autoenablesDefaultLighting = true</code> inside <code>attach(to sceneView: ARSCNView)</code>. Run again and you should see some definition to your boxes!</p>
<p>A look at the <a href="https://github.com/collectiveidea/ARPlaneDetector">current version.</a></p>
<p><img src="/assets/ShootingObjects.gif" alt="ShootingObjects.gif"/></p>
</div>
]]>
</content>
<author>
<name>
Ben Lambert
</name>
</author>
</entry>
<entry>
<title>Sketch Plugins, Baby!</title>
<link href="https://collectiveidea.com/blog/archives/2018/06/28/plugins-baby"/>
<id>https://collectiveidea.com/blog/archives/2018/06/28/plugins-baby</id>
<updated>2019-10-10T12:56:37+00:00</updated>
<published>2018-06-28T09:20:57-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - Graphic Header - Blue 7.png?size=2015_blogpost_small" alt=""/>
<div>
<p>At Collective Idea we use Sketch for wireframing and UI design. That’s not all we use though. One of our designers breaks down his current favorite plugins.</p>
<h1>Craft by InVision Labs</h1>
<p>I once used this religiously for all manner of things– adding dummy content, repeating elements, and the like. These days, its main use is for syncing <a href="https://www.invisionapp.com/">InVision</a> prototypes. There are a number of features that have saved my ass on multiple occasions, however. The ability to quickly spin up a shared remote whiteboard should not be underestimated and <a href="https://www.invisionapp.com/feature/freehand">Freehand</a> (a new-ish addition to the InVision family) gives you just that. All you have to do is click the button in the Craft panel, add the emails of the people you’d like to share it with, and off you go.</p>
<p><img src="/assets/Collective Idea - craft-example.gif" alt="Collective Idea - craft-example.gif"/></p>
<h1>/Runner</h1>
<p>So… let’s get something straight. Managing plugins is kind of a nightmare. <a href="https://www.sketchapp.com/">Sketch</a> itself has made great strides on this front, but it doesn’t get easier than /Runner. All you need to do is launch <a href="https://sketchrunner.com/">/Runner</a> (using the <code>⌘-“</code> key command), type install, then hit <code>tab</code>, and search for a plug-in. Double-click the one you’d like to install and you’re done.</p>
<p>If that’s all /Runner did, it would still be cool. BUT IT DOES SO MANY OTHER THINGS. Inserting a symbol? It can do that. Navigating to a page or art board? It can do that, too. Oh, and if you want to run another plugin, you bet your ass it can do that too! I love /Runner. If it was a human-person it would wear a leather jacket and not sweat no matter how hot it was outside. It’s that cool.</p>
<p><img src="/assets/Collective Idea - runner-example.gif" alt="Collective Idea - runner-example.gif"/></p>
<h1>Butter</h1>
<p>What is <a href="https://github.com/pberrecloth/butter-sketch-plugin">Butter</a>? Aside from the main ingredient in literally everything I eat, it’s going to be your new best friend. Have you ever wanted to align the edges of shapes or elements without having to drag and move each one hoping that Sketch’s fickle snap-to operation kicks in at the right moment? Sure. We all have. But what about spacing evenly by a set value? You know you’ve wanted to. Don’t lie. Stop lying to me and yourself about wanting to evenly space things out in your documents. It’s time to accept the truth and use Butter which is the easiest way to do either of those things (and a few more, but you’ll just have to use it to find out what those are ~wink~).</p>
<p><img src="/assets/Collective Idea - butter-example.gif" alt="Collective Idea - butter-example.gif"/></p>
<h1>Rename It</h1>
<p>If you’re anything like me, layer management is not your strongest skill. Bordering on fireable offense, really (not really…). <a href="https://rodi01.github.io/RenameIt/">Rename It</a> solves all your problems and makes you look like an attractive superhero in the process. It of course easily handles renaming layers and art boards. However, what if you have to do several at a time? Oh yeah. It can do that. In the dialog there are a litany of options from numbering to lettering as well as reusing the current layer name. No more “Rectangle 12 copy 1 copy”.</p>
<p><img src="/assets/Collective Idea - RenameIt-Example.gif" alt="Collective Idea - RenameIt-Example.gif"/></p>
<p>Alright, so what are some plugins that you use? I know I didn’t list all the tremendously cool ones here. Drop a comment to let me know what plugins I’m missing out on.</p>
</div>
]]>
</content>
<author>
<name>
Patrick O'Dell
</name>
</author>
</entry>
<entry>
<title>Batch downloading analytic events from Google Analytics</title>
<link href="https://collectiveidea.com/blog/archives/2018/06/26/batch-downloading-analytic-events-from-google-analytics"/>
<id>https://collectiveidea.com/blog/archives/2018/06/26/batch-downloading-analytic-events-from-google-analytics</id>
<updated>2019-10-10T12:56:37+00:00</updated>
<published>2018-06-26T11:22:33-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - Google Analytics - Setup.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>The Ruby on Rails web application, <a href="http://www.projectpresenter.com">Project Presenter</a>, is a tool that allows companies to distribute and post Project News, case studies, and project stories to news sites, trade journals, and other sites relating to that project.</p>
<p>To prove the value of Project Presenter, the application needs to be able to send analytics information back to the end user. For example: “Project X, was click 27 times on example-news-site.com“. However, the clicks, combined with all of the impressions, soon became a significant load on the server and database. What we’ve done to remedy that though is to move live clicks and impressions directly to the Project Presenter Google Analytics account. They’re sent as ‘events’ and are then downloaded as a batch and analyzed. This is how we did it:</p>
<p>On the remote site, you need to namespace your Google Analytics code like this:</p>
<pre>
&lt;script&gt;
    (function(i,s,o,g,r,a,m){i[‘GoogleAnalyticsObject’]=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
            m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,‘script’,’//www.google-analytics.com/analytics.js','ga');

    ga(‘create’, ‘UA-99999999-1’, ‘auto’, ‘projectPresenterTracker’);
&lt;/script&gt;
</pre>
<p>Then to record an event:</p>
<pre>
&lt;script&gt;
    ga(‘projectPresenterTracker.send’, {
        hitType: ‘event’,
        eventCategory: “example-news-site”,
        eventAction: ‘presentation_preview’,
        eventLabel: “12312",
        eventValue: 1
    });
&lt;/script&gt;
</pre>
<p>Then to get a weekly job, we pull down the data as and put it in the Project Presenter database. We’ll then put it in a format that we need. To do that, we need a couple gems to interact with Google Analytics:</p>
<pre>
gem ‘google-api-client’, ‘0.8.2’, require: ‘google/api_client’
gem ‘googleauth’
</pre>
<p>This is setup in a rake task that gets triggered with Heroku Scheduler (and monitored by <a href="http://www.deadmanssnitch.com">Dead Man’s Snitch</a>). For full disclosure here, part of the reason I have did not make this post 18 months ago when I did the work is because I don’t fully understand everything for this. For example, the access_token of ‘123’ just simply had to be “something” and not blank. And, the cert_path is was another tricky area that my understanding is limited.</p>
<pre>
scopes =  [’https://www.googleapis.com/auth/analytics']
cert_path = Gem.loaded_specs[‘google-api-client’].full_gem_path+‘/lib/cacerts.pem’
ENV[‘SSL_CERT_FILE’] = cert_path
authorization = Google::Auth.get_application_default(scopes)
client = Google::APIClient.new
client.authorization = authorization
api_method = client.discovered_api(‘analytics’,‘v3’).data.ga.get
client.authorization.access_token = ‘123’
</pre>
<p>So now the Google client is setup and can be chatted with.</p>
<pre>
result = client.execute(:api_method =&gt; api_method, :parameters =&gt; { ‘ids’ =&gt; “ga:999999999”, ‘start-date’ =&gt; 7.days.ago.to_date.to_s, ‘end-date’ =&gt; Date.today.to_s, ‘dimensions’ =&gt; ‘ga:eventCategory, ga:eventLabel, ga:eventValue’, ‘metrics’ =&gt; ‘ga:totalEvents’})

array_of_data = eval(result.response.env.body)[:rows]
</pre>
<p>This gives you the event data in an array to do whatever you need. In our case, we are bundling the data into week long segments to display in charts.</p>
<pre>
# [[“building-great-homes”, “2532", “presentation_preview”, “1"], [“building-great-homes”, “2633", 
“presentation_preview”, “1"],...
</pre>
<p><img src="/assets/Collective Idea - Google Analytics Chart.png" alt="Collective Idea - Google Analytics Chart.png"/></p>
<p>And that’s it! Now you have your data without loading down your servers!</p>
</div>
<p>Photo credit: <small><p><a href="https://pixabay.com/en/analytics-charts-traffic-marketing-925379/">Analytics Chart</a> by <a href="https://pixabay.com/en/users/StockSnap-894430/">StockSnap</a> is licensed under <a href="https://pixabay.com/en/service/terms/#usage">CC0 Creative Commons</a></p>
</small></p>
]]>
</content>
<author>
<name>
Jason Carpenter
</name>
</author>
</entry>
<entry>
<title>Unpacking opportunities behind tech buzzwords: IoT</title>
<link href="https://collectiveidea.com/blog/archives/2018/06/22/unpacking-opportunities-behind-tech-buzzwords-iot"/>
<id>https://collectiveidea.com/blog/archives/2018/06/22/unpacking-opportunities-behind-tech-buzzwords-iot</id>
<updated>2019-10-02T03:36:14+00:00</updated>
<published>2018-06-22T11:55:09-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - Smart Watch - IoT.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>I was recently driving, doing my best to dodge the potholes on I-196, and listening to NPR. As they were reading off some of their sponsors between shows, I heard this:</p>
<p>“Additional funding is provided by C3IoT. Providing a software platform that brings artificial intelligence, big data, cloud computing, and IoT to industrial-scale digital transformations.”</p>
<p>I found myself shaking my head. What does that even mean? If I think it sounds silly (this is my world, after all) what does the rest of the audience think?</p>
<p>Let’s be honest, tech buzzwords can confuse and confound. I can help translate though. Let’s break down a few terms, look at the hype, talk about what they really are, and bring them back down to earth. More importantly, let’s look at how you can use the actual tech to innovate in your businesses.</p>
<p>Over the next few blog posts, I’ll unpack a few buzzy buzzwords, starting with IoT.</p>
<h1>IoT</h1>
<p>IoT, or the Internet of Things, is probably pretty familiar to you. Our thermostats talk to the internet, there are smart speakers in our homes, and maybe that new doorbell of yours has a camera built-in.</p>
<p>We’re only at the start of this trend. We hear about “smart devices”, but a lot of them seem pretty stupid.</p>
<p>Like this <a href="https://press.griffintechnology.com/release/griffin-technology-unveils-griffin-home-a-collection-of-smart-apppowered-appliances-that-simplify-and-enhance-everyday-routines-at-ces-2017/">$100 smart toaster</a> that alerts you when your toast is done to its desired level of crispiness.</p>
<p>Or a <a href="https://www.amazon.com/HAPILABS-103-HAPIfork-Bluetooth-Enabled-Smart/dp/B00FRPCQ9Q?tag=bisafetynet2-20">$65 dollar fork that vibrates</a> when it senses you’re eating too fast.</p>
<p>Or this <a href="https://shopus.furbo.com/">$242 dog camera</a>, that not only keeps tab on your dog while you’re away, but allows you to shoot treats out of it via your smart phone.</p>
<p>A lot of IoT devices substitute real smarts for forcing me to think about them. The more things we connect, the more they can fade into the background. Right now, I don’t have to think much about my smart thermostat. It knows when I’m home, out for the day, or on vacation. It can also save me money without thinking about it. However, the house itself isn’t smart. For instance, If I’m gone for Spring Break, my water heater is still keeping a tank hot in hopes that I’m about to hop in the shower. My house also can’t tell the post office to hold my mail.</p>
<p>Arther C. Clarke once said “Any sufficiently advanced technology is indistinguishable from magic.” I love that quote because, to me, it sums up where were going with IoT, but aren’t there yet. IoT gets interesting when it fades into the background and feels like magic.</p>
<p>The real reason behind the IoT buzz is cheap. It’s just ubiquitous sensors and connectivity. Something as simple as a Nest thermostat is so much more than a simple temperature sensor. It also has humidity, ambient light, and motion sensors. Plus two different radios, a screen, processor, etc. And that’s nothing compared to a new smartphone.</p>
<p>A new Apple Watch has an Accelerometer, gyroscope, heart rate sensor, microphone, speaker, vibraton motor, barometric altimeter, ambient light sensor. LTE and UMTS, built in GPS/GLONASS, NFC, Wi-FI, Bluetooth!</p>
<h2>How are businesses using IoT</h2>
<p>It’s easy to see how you might work with IoT if you’re a product company. Just add more sensors and connectivity to whatever it is you are building. There are other opportunities too. For example, <a href="https://www.caterpillar.com/">Caterpillar</a> added sensors to heavy equipment, to help them detect wear and tear. This assists with planned maintenance which really helps keep those expensive machines running.</p>
<p>Local manufacturers are starting to look at what additional data they can get from their machines as well. For example, some office buildings utilize occupancy sensors. This can show space utilization, which then ties into HVAC and lighting to reduce usage. Desks and seats are getting sensors too. This helps offices learn more about who is using space, when, and how.</p>
<p>In Holland, where our office is located, the city uses something called Smart Brick. The brick monitors Holland’s Board of Public Works <a href="https://www.cityofholland.com/streets/snowmelt">snowmelt system</a>. (Humblebrag: Our snowmelt system is the <a href="http://www.mlive.com/business/west-michigan/index.ssf/2018/02/utility_shows_off_largest_snow.html">largest one in North America</a>) The brick, <a href="https://www.iotforall.com/holland-michigans-smart-snowmelt-system/">created by our friend Pete Hoffswell</a>, measures the temperature at the bottom, and surface, so it can tell if the snowmelt system is working and how well. It then reports this data using a very low powered radio that lets the battery last a few months or more. This started as a fun side project by our friends at BPW, but now they’re considering improving the design and building more. These bricks can let them know about problems faster, and get them fixed before they cause problems. A few smart bricks could pay for themselves with new insights.</p>
<p><img src="/assets/collective idea - smart brick.jpeg" alt="collective idea - smart brick.jpeg"/></p>
<p>On a more personal note, we recently worked with local educators to build small air quality monitors. They measure CO2, ozone, and particulate matter in the air. The EPA has air quality monitors around the country, but they are massive and cost hundreds of thousands of dollars. The monitors we helped build are only hundreds of dollars. While their accuracy is also a bit less, they can easily be deployed in many classrooms and get much more data than students would otherwise have access to.</p>
<p>Those are just a few examples of how you can quickly connect the things around you. As you look around your business, stop and ask what if they walls could literally talk? What decisions could you make faster with more data. What problems could you avoid or time could you save? That’s the promise of the internet of things.</p>
<p>In the next buzzword blog post, we’re going to talk about Machine Learning.</p>
</div>
<p>Photo credit: <small><p><a href="https://pixabay.com/en/smart-watch-apple-technology-style-821565/">Smart Watch</a> by <a href="https://pixabay.com/en/users/fancycrave1-1115284/">Fancycrave1</a> is licensed under <a href="https://pixabay.com/en/service/terms/#usage">Creative Commons Zero</a></p>
</small></p>
]]>
</content>
<author>
<name>
Daniel Morrison
</name>
</author>
</entry>
<entry>
<title>What&#39;s in a Templating Language, Part 2</title>
<link href="https://collectiveidea.com/blog/archives/2018/06/12/what-s-in-a-templating-language-part-2"/>
<id>https://collectiveidea.com/blog/archives/2018/06/12/what-s-in-a-templating-language-part-2</id>
<updated>2019-10-10T12:56:37+00:00</updated>
<published>2018-06-12T13:15:00-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - Templating Language.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>In <a href="https://collectiveidea.com/blog/archives/2018/03/06/what-s-in-a-templating-language-part-1">Part 1</a> of this series, I introduced my newest project: <a href="https://github.com/jasonroelofs/late">Late</a>, the Language Agnostic Templating Engine. This is my first real foray into compilers and interpreters, often the most complex and esoteric aspects of Computer Science, and I’m documenting what I learn as I go. Today, we will cover the three main aspects of most any language: lexing, parsing, and compilation/evaluation.</p>
<p>When it comes to building your own language, one can easily get overwhelmed by the sheer quantity of research papers, blog posts, and tools that exist today. Should you use <a href="http://dinosaur.compilertools.net/lex/index.html">lex</a>, <a href="http://dinosaur.compilertools.net/flex/index.html">flex</a>, <a href="http://dinosaur.compilertools.net/bison/index.html">bison</a>, or <a href="http://dinosaur.compilertools.net/yacc/index.html">yacc</a>? Or what about things like <a href="http://www.antlr.org/">ANTLR</a>? And where does <a href="https://llvm.org/">LLVM</a> fit into all of this? And if you happen to run into descriptions of <abbr title="Abstract Syntax Tree">AST</abbr> rewriting, optimization passes, <abbr title="Static Single Assignemnt">SSA</abbr>, and tools like a <a href="https://en.wikipedia.org/wiki/Just-in-time_compilation">Just-In-Time compilation</a>, it can be enough for anyone to just say “Nope! This is all over my head” and move on. The trick is to start with one piece at a time. At its core, compilation is a pipeline, where each step has explicitly defined inputs and outputs. To understand how languages are built we go one step at a time and eventually the whole picture suddenly makes sense!</p>
<p>Now it would be rude of me to not give credit where credit is due. The only reason I’ve been able to dive into Late and the entire world of templating languages like this is because I found and read Thorsten Ball’s fantastic book “<a href="https://interpreterbook.com/">Writing an Interpreter In Go</a>.” In this book, Thorsten does a great job of distilling the magic of interpreters into simple, well explained, and understandable pieces. By the end, you end up with a working and quite capable interpreted language. These posts, and Late itself, probably wouldn’t exist without this book, so thanks Thorsten!</p>
<p>Almost every language out there is designed around three main phases:</p>
<ul>
<li>Tokenization and lexicographical analysis (often called lexing)</li>
<li>Applying meaning to the resulting tokens (parsing)</li>
<li>Compiling and/or evaluating the results of the parser</li>
</ul>
<p>It sounds like a lot, but as I said earlier, we are going to take this one step at a time. If you would prefer a more hands-on example, please go grab <a href="https://interpreterbook.com/">Thorsten’s book</a>!</p>
<h2>Tokenizing and Lexing</h2>
<p>First up is the Lexer. While this is technically two pieces (tokenizing and lexicographical analysis), almost every language combines the two into one step. The Lexer takes the source input (the template, the scripting language file, etc) and splits it into tokens, often with accompanying metadata like line numbers and raw input. These tokens are intended to be mostly context free, but meaningful to the language.</p>
<p>As an example, say you have the following source code</p>
<pre><code>a = b * 2
</code></pre>
<p>Lexing this will provide a list of tokens much like:</p>
<pre><code>IDENTIFIER("a")
OPERAND("=")
IDENTIFIER("b")
OPERAND("*")
INTEGER(2)
</code></pre>
<p>For a more complex example, say you were lexing the following Ruby-esque code.</p>
<pre><code>def add(x, y)
  x + y
end
</code></pre>
<p>The lexer result will look something like this:</p>
<pre><code>KEYWORD("def")
IDENTIFIER("add")
LPAREN("(")
IDENTIFIER("x")
COMMA(",")
IDENTIFIER("y")
RPAREN(")")
IDENTIFIER("x")
OPERAND("+")
IDENTIFIER("y")
KEYWORD("end")
</code></pre>
<p>It’s important to note here that the tokens are very generic, providing only the most basic information about each token. It’s not the lexer’s job to determine if the syntax is correct, and in many cases the only errors a lexer will throw is if it finds a character it doesn’t know how to handle, or an unexpected <abbr title="End of File or End of Input">EOF</abbr> marker when tokenizing things like strings.</p>
<p>While lexers for most programming languages are stateless, reading through the input and processing every character, templating engines like Late need a little bit of state to work properly. Templating engines expect the templating code itself to be secondary to the main content of the input. As such, the lexer should happily accept anything up until the point of reaching an “open code” token (in Liquid and Late that would be <code>{{</code> or <code>{%</code>). However, we do need to keep around the non-Late code for generation of the final file, so all non-Late code gets tokenized into special RAW tokens.</p>
<p>You can see how this is implemented in Late’s <a href="https://github.com/jasonroelofs/late/tree/master/template/lexer">template/lexer</a> package. With our list of tokens now done, it’s time to move onto the parser and give these tokens meaning.</p>
<h2>Parsing and ASTs</h2>
<p>Parsing is where we take the list of tokens from the lexer and build a structure that gives actionable meaning to the input. For most languages, including Late, the structure we build is called an Abstract Syntax Tree, or AST. Using a tree structure (specifically a binary tree, where each node has at most two children) is powerful because it lets us encode not only order-of-operation, but also operator precedence in the same structure (ensuring that <code>2 + 3 * 5</code> is 17 and not 25). Also, tree structures are trivial to iterate through using well known algorithms, making the evaluation step easy to implement.</p>
<p>Parsing is a huge topic and one that has received many decades worth of research. I recently ran into a detailed <a href="https://jeffreykegler.github.io/personal/timeline_v3">history of parsing</a> timeline that may give you an idea of the depth and breadth of this topic. There is far too much to try to cover in a single blog post, so today I’m going to go over how Late’s parser works at a high level. You can see the full details in <a href="https://github.com/jasonroelofs/late/blob/master/template/parser/parser.go">parser.go</a>. There’s a lot here so we’ll take it step-by-step.</p>
<p>Building up a parser to handle complex languages can seem like a sizable task, but like everything else with compilers, we can start at the simplest possible point and build up complexity from there. We start with two definitions: Expression and Statement. Expressions result in values (such as <code>1</code>, <code>"this"</code>, and <code>1 + 2</code>) while Statements are, in Late’s case, how we keep track of raw input: variables (<code>{{ }}</code>) and tags (<code>{% %}</code>). With this, we start with parsing literal expressions (ones that evaluate to themselves): strings, numbers, identifiers, and booleans. When the parser sees these tokens from the lexer, it applies a one-to-one mapping from the lexer token to the appropriate AST node. See <code>parseIdentifier</code>, <code>parseNumberLiteral</code>, <code>parseStringLiteral</code>, and <code>parseBooleanLiteral</code> for the details.</p>
<p>We can now move onto simple compound expressions like <code>1 + 2</code>. It’s important to view this code snippet not as “number + number” but “expression operator expression”. This is where recursion comes into play and is why this type of parser is called Recursive Decent. To handle this code, we step through the tokens, parsing expressions as we see them and finishing by linking them together with the operator. Through that we end up with an AST that looks like:</p>
<p><img src="/assets/1 2.png" alt="1 2.png"/></p>
<p>Once we have this this working, expanding to parse other expressions gets easier. For example, take <code>1 + 2 + 3 + 4</code>. You may wonder if the parser needs to have cases to handle up to a certain number of chained operators. Thankfully this is not required, as every operator expression can be represented in a [left expression]-[operator]-[right expression] tree format. To do this, we take the expression one operator at a time: <code>1 + 2</code>, then add <code>+ 3</code>, and then <code>+ 4</code>. In explicit grouping, the expression looks like this <code>(((1 + 2) + 3) + 4)</code> to the parser giving us the following AST:</p>
<p><img src="/assets/1 2 3 4.png" alt="1 2 3 4.png"/></p>
<p>Now, this gets a little more complicated when it comes to operator precedence. With a pure left-to-right parser, the statement <code>1 + 2 * 3</code> will parse and evaluate to be <code>9</code> (e.g. <code>(1 + 2) * 3</code>), vs applying the rules of mathematics and operator precedence, in which the right answer is <code>7</code> (e.g. <code>1 + (2 * 3)</code>). There are many algorithms available to handle operator precedence and it is the source of much of the research into parsers. Late, through the recommendation in Thorsten’s book, uses a <a href="https://en.wikipedia.org/wiki/Pratt_parser">Pratt parser</a> to handle this. While this type of parser is much easier to explain and implement than many others, it’s still too much to cover here. I’ll go into more detail in the next blog post, but for now here’s the core of a Pratt parser:</p>
<ul>
<li>Each operator is given a precedence level, where a higher number means greater precedence (e.g. <code>*</code> &gt; <code>+</code>)</li>
<li>Each input token is linked to a “prefix” function (<code>-a</code>), an “infix” function (<code>1 + 2</code>), or both (<code>[</code> in definition <code>[1,2,3]</code> and access <code>array[1]</code>).</li>
<li>Parsing starts at a given precedence, normally the lowest possible, and iterates through tokens until it finds the end of the expression or a token with a lower precedence than the current.</li>
</ul>
<p>These three rules make for a surprisingly simple yet powerful parser. The entire logic for this can be found in <code>parseExpression</code>, and I’ll go into more detail on how this all works in my next post.</p>
<p>With all of the above in place, parsing more complex expressions, especially heavily nested expressions like <code>[1, 1 + 1, "three", [1, 2, 3, "four"][3]]</code> becomes automatic. The parser will see this input as nothing more than <code>[expression, expression, expression, expression]</code> and recursion takes care of the rest. You can see this happening in <code>parseArrayLiteral</code>, where we handle the empty case <code>[]</code>, one element arrays <code>[1]</code>, and then many element arrays in about 15 lines of code.</p>
<p>The parser runs through the whole list of tokens, building ASTs for each Late section. It’s now time to evaluate these trees and return the results!</p>
<h2>Compiling and Evaluation</h2>
<p>The third step of the toolchain is one that can range from almost trivial (iterating through and evaluating an AST) to complex (generating optimized machine code for the fastest execution possible), but just like the rest of this article, learning how to process the ASTs generated by the parser begins with the simplest steps. Whether you’re working on a templating language evaluator, a language interpreter (like Ruby pre 1.9), or compiling all the way to machine code, it’s important to start as simple and small as possible. The complexity will come naturally as long as you focus on building small, simple steps towards your goal. Remember, <a href="http://llvm.org/">LLVM</a> didn’t just instantly appear as the behemoth it is today. LLVM has been in development for over fifteen years (the first white paper was published in 2002) and even then was already building on decades of compiler research and knowledge that came before it.</p>
<p>With Late, and most templating languages, we aren’t building a full-fledged programming language which affords us a lot of leeway in how we implement this last step. Also as templating is a one-pass evaluation tool, execution speed isn’t a super high priority, so focusing on the simplest and most readable implementation is a great way to start. As such, Late’s evaluator runs through each AST with a depth-first algorithm, making use of a large <code>switch</code> statement to know how to handle each type of AST node. You can see this in the <code>eval</code> function in <a href="https://github.com/jasonroelofs/late/blob/master/template/evaluator/evaluator.go">evaluator.go</a>. Depth-first means we iterate through the tree, moving onto children nodes and evaluating from the absolute bottom of the tree first. Those results then propogate back up the tree and when we are back at the root of the tree, we know evaluation for that tree is done. Here’s a visual of how this works for <code>1 + 2 + 3 + 4</code>:</p>
<p><img src="/assets/eval-depth-first.png" alt="eval-depth-first.png"/></p>
<p>Once every tree has been evaluated, the results are then concatenated back into a single string and returned as the output document. This logic can be found in <a href="https://github.com/jasonroelofs/late/blob/master/template/template.go">template.go</a>, which ties the whole process together.</p>
<p>The last piece required to understand Late’s evaluation is how it handles the values and data that users will want to use and expose in their templates. Late has a simple, dynamically-typed data model, where a variable can hold any data type and an array can contain any mix of variables, e.g. <code>[1, "two", [3]]</code>). This data model is implemented in Late’s <a href="https://github.com/jasonroelofs/late/tree/master/object">object</a> package, where you can see how Late maps built-in Go types into and out of a dynamic wrapper.</p>
<p>And that’s the basic run-down of how Late works! There’s a lot here and it can seem overhelming, but as long as you take each piece on its own, and only move on to the next once you’re comfortable, understanding the full system is possible. Hopefully this has provided enough guidance to not only help understand Late’s code, but also to whet your appetite for learning how other languages work, or even writing your own!</p>
<p>In my next post I’ll be doing a deep dive into the Pratt parser algorithm, because this thing is slick and a great example of how simple rules can solve complex problems.</p>
</div>
<p>Photo credit: <small><p><a href="https://www.pexels.com/photo/abstract-business-code-coder-270348/">Abstract Business Code</a> by <a href="https://pixabay.com/en/code-coding-web-development-944499/">Pixabay</a> is licensed under <a href="https://www.pexels.com/photo-license/">Creative Commons Zero</a></p>
</small></p>
]]>
</content>
<author>
<name>
Jason Roelofs
</name>
</author>
</entry>
<entry>
<title>Getting Ready for GDPR at Collective Idea</title>
<link href="https://collectiveidea.com/blog/archives/2018/05/24/getting-ready-for-gdpr-at-collective-idea"/>
<id>https://collectiveidea.com/blog/archives/2018/05/24/getting-ready-for-gdpr-at-collective-idea</id>
<updated>2019-04-24T16:20:41+00:00</updated>
<published>2018-05-24T14:43:29-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - GDPR - Regulation.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>Does this look familiar?</p>
<p><img src="/assets/Screen Shot 2018-05-23 at 12.21.16 PM.png" alt="Screen Shot 2018-05-23 at 12.21.16 PM.png"/></p>
<p>Yup, a little something called GDPR, or the <a href="https://www.eugdpr.org">General Data Protection Regulation</a>, is responsible for all of those emails. GDPR is a new European Union law for data protection and privacy for everyone within the EU and the European Economic Area. If you want a good break down of it all, <a href="http://money.cnn.com/2018/05/21/technology/gdpr-explained-europe-privacy/index.html">CNN Money actually has a great explanation</a>.</p>
<p>Just because this is a European law, it doesn’t mean we’re not affected here in the United States. If there’s a chance that someone from the EU might navigate to your website and your website is capturing data on visitors, you could end up capturing data you’re not allowed to.</p>
<p>On May 25, 2018, everyone that does business with the EU or has marketing campaigns that may be seen by EU residents, needs to be compliant. As the Marketing Manager at Collective Idea, I’ve been charged with making sure we’re compliant in terms of the information we capture through Google Analytics. Both <a href="http://collectiveidea.com">collectiveidea.com</a> and <a href="https://deadmanssnitch.com/">deadmanssnitch.com</a> have visitors from around the world, so I needed to do a few tweaks to Google Analytics to make sure we’re respecting people’s data.</p>
<p>Because analytics data is stored on Google servers, Google already went through and made a bunch of changes so that they’re compliant. However, since we use their service we’re still personally responsible for the data we track. The rest of this post will be a walk through a few changes I made on our Google Analytics account to make sure we’re compliant with GDPR as well.</p>
<h2>User and event data retention</h2>
<p><img src="/assets/Screen Shot 2018-05-23 at 12.16.22 PM.png" alt="Screen Shot 2018-05-23 at 12.16.22 PM.png"/></p>
<p>Upon logging into Google Analytics, I was met with a pop-up asking me about “User and event data retention”. This is one of the new tools Google has added so that the service it provides is GDPR compliant. The default is 26 months and I’m going to leave it there. If I ever need to change it, I can go to Admin&gt;Tracking Info&gt;Data Retention.</p>
<h2>Tracking Info</h2>
<p>Next, I went under Admin&gt;Tracking Info and then combed through that whole section, looking for PII data. PII data is short for Personally Identifiable Information. I had to make sure we weren’t sending names, emails, phone numbers etc in URLs with form submits or destination urls. Any values submitted need to be alpha-numeric only.</p>
<h2>Google Tag Manager</h2>
<p>Since we use Google Analytics with Google Tag Manager I then had to make sure we weren’t capturing or sending IP addressed out in the open with no protection around it. To do that, I looked at every tag in GTM that used GA and just anonymized the IP.</p>
<p><img src="/assets/Screen Shot 2018-05-23 at 3.28.12 PM.png" alt="Screen Shot 2018-05-23 at 3.28.12 PM.png"/></p>
<p>To do that, you’ll:</p>
<ul>
<li>Open the tag and click the pencil to edit</li>
<li>Check the box where it says “ Enable overriding settings in this tag “</li>
<li>Once you click that checkbox, you’ll see some new things populate, one of them being a drop down arrow next to the words “More Settings”. Click that.</li>
<li>Under “More Settings” and go to “Fields to Set”</li>
<li>Click “Add Field”</li>
<li>Under “Field Name” type in anonymizeIp and under “Value” put true.</li>
<li>Hit “Save”</li>
</ul>
<p>And voila!</p>
<p>I made a few other changes here and there, but these are the biggest and most simple ones to tackle from a marketing standpoint. In reality, GDPR doesn’t just affect marketing. It affects any area of your business that touches personal data. To make sure we touch all those areas, we have designated teams dispatched to make sure the work they do is compliant.</p>
<p>How have you gotten your business ready for GDPR? Are you ready? If you’re not, <a href="https://www.theverge.com/2018/5/22/17378688/gdpr-general-data-protection-regulation-eu">you can take solace in the fact that you’re not alone</a>.</p>
</div>
<p>Photo credit: <small><p><a href="https://pixabay.com/en/regulation-gdpr-data-protection-3246979/#_=_">GDPR</a> by <a href="https://pixabay.com/en/users/TheDigitalArtist-202249/">The Digital Artis</a> is licensed under <a href="https://pixabay.com/en/service/terms/#usage">CC0 Creative Commons</a></p>
</small></p>
]]>
</content>
<author>
<name>
Sasha Wolff
</name>
</author>
</entry>
<entry>
<title>We&#39;re Green Commuters and We Cannot Lie</title>
<link href="https://collectiveidea.com/blog/archives/2018/05/22/we-re-green-commuters-and-we-cannot-lie"/>
<id>https://collectiveidea.com/blog/archives/2018/05/22/we-re-green-commuters-and-we-cannot-lie</id>
<updated>2019-09-27T07:15:17+00:00</updated>
<published>2018-05-22T13:27:44-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - Green Commute Week.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>For the third year in a row Collective Idea took home the Green Commute Week Award for the Small Employer category. Every year, the <a href="http://www.the-macc.org/green-commute/">Macatawa Area Coordinating Council</a> holds an area-wide competition to see who can rack up the most “green commute miles”.</p>
<p><img src="/assets/33245649_2050152388333093_6887480809373040640_o.jpg?size=2015_blogpost_medium" alt="33245649_2050152388333093_6887480809373040640_o.jpg"/></p>
<p>The purpose of the challenge is to not only get people to find alternative forms of transportation, but to think about various ways to improve air quality.</p>
<p>There are a few methods of transportation that count towards “green commute miles”. They are:</p>
<ul>
<li>Walking</li>
<li>Biking</li>
<li>Riding the bus</li>
<li>Carpooling</li>
<li>Electric vehicle</li>
<li>Telecommute</li>
</ul>
<p>The addition of the electric vehicle and telecommute is new this year and we were really excited to see that. A lot of us here at Collective Idea telecommute on a regular basis. One reason for that is because we have team members that work in other states ( 👋 Eric and Ryan!) and as far as we know, there’s no way to teleport. Another reason is because we’re big into working where you feel most comfortable. If you’re more productive at home or in a coffee shop, then by all means, work from those locations. Lastly, we’re big into leaving things better than they are which means we like to take care of the earth. We know that telecommuting cuts down on the number of greenhouse gases and this is our little way of helping out.</p>
<p>As administrator of the Green Commute Challenge, I’m always excited to see how many miles we can put in. We’re pretty green already. There are a few of us that carpool from Grand Rapids pretty regularly and a few others, like our president Daniel, bike in as often as they can. With the Macatawa Area Coordinating Council’s decision to add two new “green methods” of telecommuting and electric vehicles, I knew we would get a TON of miles. As I mentioned before, a lot of us already telecommute, plus one of our team members has a Chevy Volt.</p>
<p>Turns out I was right. We ended up putting in over 1,700 green commute miles from May 14 to 18. That’s up from 1,066 miles last year! Not only was I super proud of what we did, but I knew we were a shoe-in to win. However, it turns out that the winners aren’t decided upon miles alone. The miles are just used in case there is a tie. The determining factor for winning is the percentage of employees that participate.</p>
<iframe src="https://giphy.com/embed/LHKlWJ0DsYOQw" width="480" height="420" frameborder="0" class="giphy-embed" allowfullscreen=""></iframe>
<p>
<br/>
Well then.
<br/>
<br/>
Thankfully, I didn't have to sweat it for too long. We've got a rockstar team here and close to 50% of our crew participated.
<br/>
<br/>
That's. Awesome.
<br/>
<br/>
It's not easy to change people's habits, especially ones that have been ingrained in us. I didn't have to change anyone's traveling habits at Collective Idea though. We literally just did what we always do when it comes to commuting and I think that's because we truly have a culture of making things better than they were.
<br/>
<br/>
So a huge shout out goes to my team for our third Green Commute Week win in a row.
<br/>
<br/>
<iframe src="https://giphy.com/embed/wFOC9RazP97i0" width="480" height="260" frameborder="0" class="giphy-embed" allowfullscreen=""></iframe><p>
</p></p>
</div>
]]>
</content>
<author>
<name>
Sasha Wolff
</name>
</author>
</entry>
<entry>
<title>Part 2: ARKit Wall and Plane Detection for iOS 11.3</title>
<link href="https://collectiveidea.com/blog/archives/2018/05/08/part-2-arkit-wall-and-plane-detection-for-ios-11.3"/>
<id>https://collectiveidea.com/blog/archives/2018/05/08/part-2-arkit-wall-and-plane-detection-for-ios-11.3</id>
<updated>2019-10-10T12:56:37+00:00</updated>
<published>2018-05-08T11:38:30-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - ARKit iOS.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>In <a href="https://collectiveidea.com/blog/archives/2018/04/30/part-1-arkit-wall-and-plane-detection-for-ios-11.3">Part 1</a>, we ended with the ability to detect planes. Next, we’re going to work on visually displaying those planes on screen using an SCNPlane. We’ll then apply a SCNMaterial with a grid texture.</p>
<p>Here’s what we’re building:</p>
<p><img src="/assets/AR-Kit-wall-detection.gif" alt="AR-Kit-wall-detection.gif"/></p>
<p>If you’re starting with Part 2, download the <a href="https://github.com/collectiveidea/ARPlaneDetector/releases/tag/Part1">starter project on GitHub here</a>.</p>
<p>In the <code>ARSCNViewDelegate</code> method,</p>
<pre><code class="language-swift">func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { ... }
</code></pre>
<p>we left off printing information about the <code>ARPlaneAnchor</code> we found.</p>
<p>What we want to do is add some geometry to that plane and update it as the <code>ARPlaneAnchor</code> changes. Let’s make a <code>Plane</code> class that inherits from <code>SCNNode</code>, so we can add it to the <code>node: SCNNode</code> that is provided from the above <code>ARSCNViewDelegate</code> method.</p>
<p>In the Xcode project, choose file -&gt; new -&gt; file. Choose <code>Swift File</code>, click <code>next</code>, and save it as <code>Plane.swift</code>.</p>
<p>Next, add this code to define your Plane class.</p>
<pre><code class="language-Swift">// 1
import ARKit

class Plane: SCNNode {

    let plane: SCNPlane

    init(anchor: ARPlaneAnchor) {
        // 2
        plane = SCNPlane(width: CGFloat(anchor.extent.x), height: CGFloat(anchor.extent.z))

        super.init()

        // 3
        plane.cornerRadius = 0.005

        // 4
        let planeNode = SCNNode(geometry: plane)
        planeNode.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z)

        // 5
        planeNode.eulerAngles.x = -.pi / 2

        // 6
        planeNode.opacity = 0.15

        // 7
        addChildNode(planeNode)
    }

    // 8
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
</code></pre>
<p>1) Make sure to import ARKit.</p>
<p>2) We store a reference to the SCNPlane geometry and set its size to the anchor’s extent property. This way we can adjust it later.</p>
<p>3) Here we just round the plane’s corners to get rid of the sharp corners. Not necessary, but it looks nice.</p>
<p>4) A SCNNode is created, assigned our plane geometry, and positioned to the anchor’s position.</p>
<p>5) Planes in SceneKit are vertical by default so we need to rotate 90 degrees to match the ARPlaneAnchor.</p>
<p>6) Lower the opacity so we can see the camera view behind it.</p>
<p>7) Add it to our Plane node.</p>
<p>8) Since we’re creating a designated Init, init(coder:) needs to be overridden as well. We’ll just let it fail. Since we’re not coding/decoding or instantiating our Plane class from a Storyboard, it wont be called. If, down the line things change and init(coder:) is called, we’ll be notified with that fatal error.</p>
<p>Now let’s go back to our <code>ARSceneManager</code> class and update the <code>renderer(renderer: node: for anchor:)</code> method with a few calls to create our Plane.</p>
<pre><code class="language-Swift">func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        // we only care about planes
        guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

        // 1        
        let plane = Plane(anchor: planeAnchor)

        // 2
        planes[anchor.identifier] = plane

        // 3
        node.addChildNode(plane)
    }
</code></pre>
<p>1) Create a <code>Plane</code> and pass in the <code>ARPlaneAnchor</code>.</p>
<p>2) We will store a local array of <code>Planes</code> to make it easier to reference and update later. This is a Dictionary with the anchors UUID as the key.</p>
<p>3) Add it as a child to the node being passed in.</p>
<p>Now, let’s add that Dictionary to the top of the class.</p>
<pre><code class="language-Swift">  private var planes = [UUID: Plane]()
</code></pre>
<p>If you run the app now, you’ll see our <code>Planes</code> being added when they are found by ARKit. However, we’re not updating the planes when changes are found. ARKit continually updates and “merges” planes as it sorts out the world.</p>
<p>Let’s add another <code>ARSCNViewDelegate</code> delegate method to handle updates to the plane anchors.</p>
<pre><code class="language-Swift">func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

        // 1
        if let plane = planes[planeAnchor.identifier] {
            //2
            plane.updateWith(anchor: planeAnchor)
        }
    }
</code></pre>
<p>1) Here we find the <code>Plane</code> that matches the anchor’s ID.</p>
<p>2) Next, we call a function to update that plane based on the anchor. Let’s add that method to our <code>Plane</code> class.</p>
<p>Open <code>Plane.swift</code> and add this method below our inits.</p>
<pre><code class="language-Swift">func updateWith(anchor: ARPlaneAnchor) {
        // 1
        plane.width = CGFloat(anchor.extent.x)
        plane.height = CGFloat(anchor.extent.z)
        // 2
        position = SCNVector3Make(anchor.center.x, 0, anchor.center.z)
    }
</code></pre>
<p>1) This adjusts our plane geometry to equal the plane anchor’s size.</p>
<p>2) Position the plane <code>SCNNode</code> instance to the anchor’s position.</p>
<p>If you run the app now, you should see your Planes being rendered and their sizes being updated. Cool!</p>
<p>Sometimes you’ll notice that two planes will be “merged” together when ARKit realizes they are part of the same surface.<br/>
What’s actually happening is ARKit is removing one plane and updating the other. Currently, we are adding to our Dictionary of Planes, but are not removing them when ARKit removes its nodes. For that let’s implement another <code>ARSCNViewDelegate</code> method.</p>
<pre><code class="language-Swift">func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
        planes.removeValue(forKey: anchor.identifier)
    }
</code></pre>
<p>Looking good!</p>
<h3>Adding a Grid Material</h3>
<p>One last thing we can do to make it easier to visualize the perspective and distance of the planes, is add a grid texture.</p>
<p>You can find the grid texture I used on <a href="https://github.com/collectiveidea/ARPlaneDetector/tree/master/grid_material">GitHub here</a>. Just place it in your xcassets folder.</p>
<p>Add a new Swift file, name it <code>GridMaterial</code>, and add this code.</p>
<pre><code class="language-Swift">class GridMaterial: SCNMaterial {

    override init() {
        super.init()
        // 1
        let image = UIImage(named: "Grid")

        // 2
        diffuse.contents = image
        diffuse.wrapS = .repeat
        diffuse.wrapT = .repeat
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}
</code></pre>
<p>Our GridMaterial inherits from <code>SCNMaterial</code>. When we initialize we:</p>
<p>1) Create a <code>UIImage</code> with our Grid.png file stored in our asset catalogue.</p>
<p>2) Set its diffuse property to the image and tell it to repeat in both directions.</p>
<p>Now head back to the <code>Plane</code> class to apply our material to its plane geometry.</p>
<pre><code class="language-Swift">init(anchor: ARPlaneAnchor) {
        // ...
        plane.cornerRadius = 0.008
        // 1
        plane.materials = [GridMaterial()]
        // ...
        // 2 delete this...
        planeNode.opacity = 0.15
        // ...
      }
</code></pre>
<p>1) Update to plane’s materials to be an array of just <code>GridMaterial</code>.</p>
<p>2) Delete the opacity setting since the grid texture I provided you with is semi-transparent.</p>
<p>If you run the project now, you’ll see the grid on top of our plane. However, you may notice it can get stretched when the plane updates. We also need to update our texture when that happens.</p>
<p>Update the <code>updateWith(anchor:)</code> method in our <code>Plane</code> class to update our texture as well.</p>
<pre><code class="language-Swift">func updateWith(anchor: ARPlaneAnchor) {
        // ...
        if let grid = plane.materials.first as? GridMaterial {
            grid.updateWith(anchor: anchor)
        }
    }
</code></pre>
<p>Head back to <code>GridMaterial</code> and implement that method.</p>
<pre><code class="language-Swift">func updateWith(anchor: ARPlaneAnchor) {
        // 1
        let mmPerMeter: Float = 1000
        let mmOfImage: Float = 65
        let repeatAmount: Float = mmPerMeter / mmOfImage

        // 2
        diffuse.contentsTransform = SCNMatrix4MakeScale(anchor.extent.x * repeatAmount, anchor.extent.z * repeatAmount, 1)
    }
</code></pre>
<p>1) Scene Kit uses meters for its measurements. In order to get the texture looking good, we need to decide the amount of times we want it to repeat per meter. If we inspect our image in an editing program we can see it’s 65mm.</p>
<p>2) Update the transform of the material’s diffuse property where our grid image is used.</p>
<p>That should do the trick. Run your app and see the grid on the growing planes!</p>
<p>In Part 3 we will place an object on the plane when a user taps the screen!</p>
<p>Download the final project of <a href="https://github.com/collectiveidea/ARPlaneDetector/releases/tag/Part2">Part 2 here</a>.</p>
</div>
<p>Photo credit: <small><p><a href="https://www.pexels.com/photo/abstract-architecture-building-business-227675/">Abstract Architecture</a> by <a href="https://www.pexels.com/@snapwire">Snapwire</a> is licensed under <a href="https://www.pexels.com/photo-license/">Creative Commons Zero</a></p>
</small></p>
]]>
</content>
<author>
<name>
Ben Lambert
</name>
</author>
</entry>
<entry>
<title>Working with JavaScript Objects</title>
<link href="https://collectiveidea.com/blog/archives/2018/05/02/working-with-javascript-objects"/>
<id>https://collectiveidea.com/blog/archives/2018/05/02/working-with-javascript-objects</id>
<updated>2018-05-02T15:05:59+00:00</updated>
<published>2018-05-02T11:05:58-04:00</published>
<content type="html">
<![CDATA[
<img src="https://collectiveidea.com/assets/Collective Idea - variable instances.jpg?size=2015_blogpost_small" alt=""/>
<div>
<p>TIL that when you have a plain object and store instance variables on it, you’re actually setting a class variable across all instances.</p>
<p>For example:</p>
<pre><code class="language-javascript">utils.fancyForm = {
    $element: null,
    $fields: null,
    init: function(element) {
        this.$element = $(element);
        this.$fields = $(":input", this.$element);
        return this;
    }
}
</code></pre>
<p>If you attempt to save and reference that object more than once on the page, the variables <code>$element</code> and <code>$fields</code> will always be set from the latest call to <code>init</code>. This happens no matter what instance you’re working with. In order to have truly separate instances with their own instance variables, you need to make an object with a prototype, i.e.:</p>
<pre><code class="language-javascript">FancyForm = function(element) {
    this.$element = $(element);
    this.$fields = $(":input", this.$element);
}

FancyForm.prototype = {
    $element: null,
    $fields: null,
}

utils.fancyForm = {
    init: function(element) {
        return new FancyForm(element);
    }
}
</code></pre>
<p>The first item is the object’s constructor, and it is simply the <code>init</code> function from the original version. The prototype is effectively all the things that were in the original object. In order to maintain backwards compatibility in the rest of the codebase, we keep the <code>utils.fancyForm</code> helper around with the <code>init</code> method that simply returns an instantiation of the new <code>FancyForm</code> object.</p>
<p>Now, when we call <code>utils.fancyForm.init(element)</code> and bind them multiple times on the same page, each one will act completely independent of one another, as we want and expect.</p>
</div>
<p>Photo credit: <small><p><a href="https://www.pexels.com/photo/apple-code-coding-computer-574069/">Coding Computer</a> by <a href="https://www.pexels.com/@goumbik">Lukas</a> is licensed under <a href="https://www.pexels.com/photo-license/">Creative Commons Zero</a></p>
</small></p>
]]>
</content>
<author>
<name>
Joshua Kovach
</name>
</author>
</entry>
</feed>
