<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cohan Robinson</title>
    <description>The latest articles on DEV Community by Cohan Robinson (@cohan).</description>
    <link>https://dev.to/cohan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F68262%2F87420563-970e-41de-bd65-54c3dc73bb51.jpeg</url>
      <title>DEV Community: Cohan Robinson</title>
      <link>https://dev.to/cohan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cohan"/>
    <language>en</language>
    <item>
      <title>Defeating Form Spam Bots</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Tue, 18 Feb 2020 06:38:48 +0000</pubDate>
      <link>https://dev.to/cohan/defeating-form-spam-bots-3019</link>
      <guid>https://dev.to/cohan/defeating-form-spam-bots-3019</guid>
      <description>&lt;p&gt;Bonus: You’re gonna wind up the nerds that disable Javascript with this one.&lt;/p&gt;

&lt;p&gt;Alright so lets take my &lt;a href="https://cohan.dev/contact/"&gt;contact&lt;/a&gt; page. It was receiving probably 50 to 100 spam submissions every day. Not the worst I’ve seen, but still annoying. Moreso when the spam actually gets through.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I was doing
&lt;/h2&gt;

&lt;p&gt;I was doing the standard honeypot element, y’know where you have a text  that’s hidden somehow using CSS, which if filled you discard the submission. It was relatively effective, I’d probably give it a solid 75% effectiveness. The problem with 75% effectiveness if you were getting 100 spam submissions a day, you’re still getting 25 spam messages a day. Dammit.&lt;/p&gt;

&lt;p&gt;I then changed the name of this input to other-name, in a hopes that it would trip up the spammer scripts that had a mild amount of smarts behind them - I dunno maybe they ignore fields named ‘honeypot’ or anything super obvious. I also added an aria-label &lt;code&gt;aria-label="Don't fill this one out mate, it's the spam honeypot one"&lt;/code&gt; so that hopefully if anyone with visual difficulties could still send me message. This change of input name did help, and I’d say we got to around 90% success, or 10 spam messages a day depending on whether you’re a glass full or glass empty sort of person.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’m doing now
&lt;/h2&gt;

&lt;p&gt;The same thing, I have not removed the above, this is in addition to. You’re going to need a &lt;a href="https://cohan.dev/that-needs-js/"&gt;page that addresses people that disable javascript&lt;/a&gt;, because they’ll whinge and whine about it loudly on the internet if you don’t. The internet Amish are much more noisy than the real Amish.&lt;/p&gt;

&lt;p&gt;No you can’t fall back and accept inputs on this URL, because that defeats the entire point of this. It’s important that that page &lt;strong&gt;does not&lt;/strong&gt; accept any form submissions.&lt;/p&gt;

&lt;p&gt;Next up, send your form there. &lt;code&gt;&amp;lt;form action='https://cohan.dev/that-needs-js/'&amp;gt;&lt;/code&gt; - Yup. You’ve just broken your form entirely. Well done.&lt;/p&gt;

&lt;p&gt;Nah, we wanted to do that. Next up we’ll use Javascript to fix what we just broke. Spam bots will eventually start using javascript if people do this enough, but for now I’ve found that barely any of them (if any at all) are doing so.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;form id='myContactForm' action='https://cohan.dev/that-needs-js/' data-action='https://cohan.dev/your/actual/form/submit/url'&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next it’s a case of having the browser substitute in that data-action for the regular action before submitting the form. Bung this in the page somewhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    function updateContactFormDestination() {
        var contactForm = document.getElementById("myContactForm");
        var realSubmitUrl = contactForm.getAttribute('data-action');

        contactForm.setAttribute('action', realSubmitUrl);
    }

    document.addEventListener("DOMContentLoaded", function(event) { 
        updateContactFormDestination();
    });
&amp;lt;/script&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can avoid getting messages from robots and nerds with javascript disabled! :D&lt;/p&gt;

&lt;p&gt;Currently this has, for me, had a 100% success rate. 0 spam emails coming from my form per day.&lt;/p&gt;

&lt;p&gt;I give it a week.&lt;/p&gt;




&lt;p&gt;Maybe you should &lt;a href="https://cohan.dev/subscribe/"&gt;subscribe to my mail list&lt;/a&gt; for when I publish my next bot-thwarter! :D&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>spam</category>
      <category>form</category>
      <category>javascript</category>
    </item>
    <item>
      <title>We Hate Captchas!</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Sun, 29 Dec 2019 18:01:25 +0000</pubDate>
      <link>https://dev.to/cohan/we-hate-captchas-3n19</link>
      <guid>https://dev.to/cohan/we-hate-captchas-3n19</guid>
      <description>&lt;p&gt;As part of the &lt;a href="https://cohan.dev/more"&gt;Year of More&lt;/a&gt; I’ve decided this year to do 12 projects over 12 months. I might have already cheated a bit.&lt;/p&gt;

&lt;p&gt;I bought a website. Not something I’ve done.. ever before, but this one I liked the look of. The site is called &lt;a href="https://wehatecaptchas.com/"&gt;We Hate Captchas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A little while back I posted an ask on Hacker News “&lt;a href="https://news.ycombinator.com/item?id=21642808"&gt;Are there any viable alternatives to reCAPTCHA?&lt;/a&gt;” and didn’t get much of a response outside of “There are other services”. My desire however was not to bring back the old solve-the-words thing that generally got in the way or proved completely impossible for some users with disabilities, I wanted the invisibility of Google’s reCAPTCHA but without the Google part.&lt;/p&gt;

&lt;p&gt;Earlier today I happened across a tweet from Dalton Edwards, who’s created such a product. He’s selling up so that he can focus on other projects and was looking for a buyer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Project for Sale: &lt;a href="https://wehatecaptchas.com/"&gt;https://wehatecaptchas.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sale includes ownership of all source code and the wehatecaptchas.com domain.&lt;/p&gt;

&lt;p&gt;Please DM me if you have any questions or wish to make an offer. Thanks 😃— Dalton Edwards (&lt;a href="https://twitter.com/DaltonEdwards"&gt;@DaltonEdwards&lt;/a&gt;) &lt;a href="https://twitter.com/DaltonEdwards/status/1210660551233343493"&gt;December 27, 2019&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Normally I imagine you should throw down a load of red tape for your standard website purchase but heck, I had a bit of cash knocking about and a need for a reCAPTCHAless CAPTCHAless CAPTCHA (what?). I figured the juice is worth the squeeze if I can ensure there’s an alternative to reCAPTCHA out there. Anyway short story shorter, I went and bought it.&lt;/p&gt;

&lt;p&gt;In case anyone’s actively using it as-is I’m going to keep it online and working. In future I’ll rework some of it, change some things here and there, maybe even change domain? Admittedly the first thing I did once we’d sorted the payment/code exchange was grab nocaptcha.net. Aside from that, you keep doing you.&lt;/p&gt;

&lt;p&gt;The site will stay up and running, if there are any changes made they’ll be done in a manner that doesn’t break anyone’s current use of the site.&lt;/p&gt;

&lt;p&gt;Does this count as a project for The Year of More? I’m not sure yet, I guess if I give it at least a month’s worth of time throughout the year I can count it as the 13th project! Sweet!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Year of More</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Sun, 22 Dec 2019 05:05:13 +0000</pubDate>
      <link>https://dev.to/cohan/the-year-of-more-31f2</link>
      <guid>https://dev.to/cohan/the-year-of-more-31f2</guid>
      <description>&lt;p&gt;The year of more. As if spinning plates all through 2019 wasn’t exhausting enough?!&lt;/p&gt;

&lt;p&gt;Well, yeah.. tires were spun, the engine was revved, gears were ground.. but what was there to show for it? A bunch of abandoned projects and &lt;a href="https://cohan.dev/project/hosted"&gt;Hosted&lt;/a&gt; sort of coming together in the last month or so! Ooooh well done, me. So proud.&lt;/p&gt;

&lt;p&gt;In 2020, the year of the future, I’m going to release something. Multiple somethings. Publicly. It don’t count if nobody sees it.&lt;/p&gt;

&lt;p&gt;Each project has 1 month before going public. If it sucks, it sucks. Do it better next time. Release date is 18:00 on the last day of each month. Time for previous months’ projects to be maintained and supported needs to be factored in.&lt;/p&gt;

&lt;p&gt;If any take off*, the year of more may (but isn’t obliged to) end.&lt;/p&gt;

&lt;p&gt;* ‘take off’ defined as &lt;code&gt;yearly revenue &amp;gt; current salary&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Get the latest on the current project over on the &lt;a href="https://cohan.dev/now"&gt;/now/&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;Things to do in 2020:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hosted MVP (Release end of Jan 2020)&lt;/li&gt;
&lt;li&gt;Next project tbc (Release end of Feb 2020)&lt;/li&gt;
&lt;li&gt;and so on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personal podcast (Ep 1 to release 1st Jan 2020)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cohan.dev/live/"&gt;Live stream a bunch of it!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Blog it, all of it. Something like once a week.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.patreon.com/join/cohan/checkout?rid=4353410"&gt;Embrace failure&lt;/a&gt; on &lt;a href="https://cohan.dev/patreon"&gt;Patreon&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets see how this goes eh!&lt;/p&gt;

&lt;p&gt;Heavily inspired by (read: it’s basically the exact same thing as) &lt;a href="https://twitter.com/levelsio"&gt;@levelsio&lt;/a&gt;’s &lt;a href="https://levels.io/12-startups-12-months/"&gt;12 Startups in 12 Months&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;“Yearly theme” comes from &lt;a href="https://www.thethemesystem.com/"&gt;Cortex’s Theme System&lt;/a&gt; and related &lt;a href="https://relay.fm/cortex"&gt;podcast&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Automate Your Slack Status</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Sat, 07 Sep 2019 14:14:57 +0000</pubDate>
      <link>https://dev.to/cohan/automate-your-slack-status-1abk</link>
      <guid>https://dev.to/cohan/automate-your-slack-status-1abk</guid>
      <description>&lt;p&gt;Automating your Slack status. Why would you want to do that? Well for one thing it stops people asking what you’re up to. Actually that’s the only reason to do it.&lt;/p&gt;

&lt;p&gt;I recently went remote, work from home, the whole shebang. Nice.&lt;/p&gt;

&lt;p&gt;One of the first problems we discovered with this however was that it wasn’t really possible to see what I am working on. Not in the micro-manage screenshot every 5 minutes sense but a general gist. The way I worked around this was to tie in my Slack status to display what I was doing. Lets jump in!&lt;/p&gt;

&lt;h2&gt;
  
  
  You will need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Zapier&lt;/li&gt;
&lt;li&gt;Everhour.. or Harvest, or Toggl, or some form of time tracking that integrates with;&lt;/li&gt;
&lt;li&gt;Basecamp.. or Asana, or Jira, or something else that integrates with the time tracker you picked&lt;/li&gt;
&lt;li&gt;Slack (Duh)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Set it up
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Time tracker integration (Everhour and Basecamp in my case)
&lt;/h2&gt;

&lt;p&gt;This one I’m not going to be so much help with. I personally use Everhour and Basecamp. You use whatever you’re using, the key point is that you need to be able to start and stop timers that includes the title of the task you’re working on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zapier setup
&lt;/h2&gt;

&lt;p&gt;If you’re a smart cookie you’ll only need this screenshot to set it all up. So here it is. Get on it champ.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-home.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-home.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes. In this you’ll need a paid Zapier account. Get your employer to pay for it or something. No I’ve not figured out a decent way to make it work without the multi-step zaps.&lt;/p&gt;

&lt;p&gt;If you do figure out a way to do this free, please do blog about it and send me the link - I’ll give you some shoutouts here!&lt;/p&gt;

&lt;p&gt;Choose Everhour as the starting trigger, with a trigger event of a timer starting&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leave the project section blank if you want it to work for everything!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next up we need to make sure we’re setting our own status, rather than claiming credit for someone else’s work&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we do the bit where we update Slack&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;Pop over to Basecamp (or whatever you use, etc, etc)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-basecamp-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-basecamp-1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;boop&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-basecamp-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-basecamp-2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look over at the Slack, what’s this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hover the computer icon&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-slack-4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bosh!&lt;/p&gt;

&lt;h1&gt;
  
  
  Unset it when you’re done
&lt;/h1&gt;

&lt;p&gt;Same again really, set up all the same except trigger on the timer stopped event and leave the slack status empty, this unsets your status.&lt;/p&gt;

&lt;p&gt;Keep the only continue if in place, otherwise you’ll stop working whenever someone else stops a timer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcohan.io%2Fimages%2Fautomateslackstatus%2Fzapier-everhour-6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No more “are you busy” messages on Slack, noice!&lt;/p&gt;

</description>
      <category>slack</category>
      <category>basecamp</category>
      <category>zapier</category>
      <category>everhour</category>
    </item>
    <item>
      <title>Make Slack a Little Less Distracting</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Tue, 21 May 2019 09:23:51 +0000</pubDate>
      <link>https://dev.to/cohan/make-slack-a-little-less-distracting-470k</link>
      <guid>https://dev.to/cohan/make-slack-a-little-less-distracting-470k</guid>
      <description>&lt;p&gt;In the browser version of Slack the favicon shows up white if any message appears. This disables that, keeping the red new-message icon intact&lt;/p&gt;

&lt;p&gt;You’ll need a browser blocker to do this (I highly recommend &lt;a href="https://getublock.com/"&gt;uBlock Origin&lt;/a&gt; but any that support the Adblock-style personal blocking lists will work)&lt;/p&gt;

&lt;h2&gt;
  
  
  For a specific Slack server
&lt;/h2&gt;

&lt;p&gt;In your personal filter list, add the following URL - replacing INSTANCE with your Slack server’s name&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://INSTANCE.slack.com/img/ico/app_icon_32px_online_unreads.png&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  For all Slack servers
&lt;/h2&gt;

&lt;p&gt;Same thing but in your personal filter add the URL&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://a.slack-edge.com/5d94d/img/ico/app_icon_32px_online_unreads.png&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Done
&lt;/h2&gt;

&lt;p&gt;Now when a message that doesn’t need your attention comes in you don’t get the distracting white favicon, but will still get the red version of the icon to indicate you’ve got a new direct message. Noice.&lt;/p&gt;

</description>
      <category>slack</category>
    </item>
    <item>
      <title>Dynamic blocklist with Twilio</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Wed, 24 Apr 2019 18:35:35 +0000</pubDate>
      <link>https://dev.to/cohan/dynamic-blocklist-with-twilio-1h91</link>
      <guid>https://dev.to/cohan/dynamic-blocklist-with-twilio-1h91</guid>
      <description>&lt;p&gt;For those moments where you wish you could dynamically block incoming calls within Twilio.. We all have them, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Desired end result
&lt;/h2&gt;

&lt;p&gt;I have a file on my site that lists phone numbers. Any number in that list will be blocked from calling me.&lt;/p&gt;

&lt;h2&gt;
  
  
  You will need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A json file that contains an array of phone numbers&lt;/li&gt;
&lt;li&gt;A Twilio number that receives calls from numbers you wish to block&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First thing’s first, we’re going to pop over to a completely different site (I will write this up here if the source ever vanishes, ping me on the &lt;a href="https://cohan.io/contact"&gt;contact form&lt;/a&gt; if that’s the case)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://support.twilio.com/hc/en-us/articles/223180548-How-Can-I-Stop-Receiving-or-Block-Incoming-Phone-Calls-#blacklistNumbers"&gt;Have a read of this article on Twilio’s help site&lt;/a&gt;. The section you’re after is under “Reject Calls from Specific Phone Numbers” if the anchor doesn’t work.&lt;/p&gt;

&lt;p&gt;Come back here when you get to the “CODE” part.&lt;/p&gt;

&lt;p&gt;…&lt;/p&gt;

&lt;h2&gt;
  
  
  That JSON file I mentioned
&lt;/h2&gt;

&lt;p&gt;Simple enough, upload it somewhere public, it should look something like this (but with real numbers of course)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    "+441234567891",
    "+441234567893",
    "+441234567892"
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to not put the comma on that last number listed. JSON doesn’t like that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now for some code
&lt;/h2&gt;

&lt;p&gt;Done the setup part? Sweet. Now in Twilio, under the &lt;strong&gt;&lt;em&gt;Runtime -&amp;gt; Functions&lt;/em&gt;&lt;/strong&gt; section go to &lt;strong&gt;&lt;em&gt;Configure&lt;/em&gt;&lt;/strong&gt; on the sidebar and under &lt;strong&gt;&lt;em&gt;Dependencies&lt;/em&gt;&lt;/strong&gt; add a new NPM module &lt;code&gt;request&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Version shouldn’t be required but in case you’re after it, at the time of writing it’s 2.88.0.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Just to note: For me, the form input was hidden under the save button. Bit weird.. Click the version of the last one you can see and tab into it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you hit the Save button it should pop up a message about saving, then deploying, then deployed.&lt;/p&gt;

&lt;p&gt;Go back to the &lt;strong&gt;&lt;em&gt;Manage -&amp;gt; Your function&lt;/em&gt;&lt;/strong&gt;. Insert this code below, making three replacements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https://cohan.io/blocked-numbers.json&lt;/code&gt;: Replace with the URL to your blocked numbers file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;https://ic4.io/twilio-voicemail&lt;/code&gt;: The URL to whatever was previously handling your inbound flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Personally I use a &lt;a href="https://www.twilio.com/labs/twimlets"&gt;Twimlet&lt;/a&gt; to just dump everyone into voicemail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.handler = function(context, event, callback) {

    var request = require('request');

    request('https://cohan.io/blocked-numbers.json', function (error, response, body) {

        let twiml = new Twilio.twiml.VoiceResponse();
        let blocked = true;

        if (error) {
            twiml.redirect("https://ic4.io/twilio-voicemail");
        }
        else {
            let blocklist = JSON.parse(body);

            if (blocklist.length &amp;gt; 0) {
                if (blocklist.indexOf(event.From) === -1) {
                    blocked = false;
                }
            }
            if (blocked) {
                twiml.reject();
            }
            else {
                twiml.redirect("https://ic4.io/twilio-voicemail");
            }
            callback(null, twiml);
        }

    });

};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running through this, when we receive a new inbound call we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make a request to fetch our blocklist&lt;/li&gt;
&lt;li&gt;If that fails we’re going to assume we don’t have a blocklist, proceed as normal&lt;/li&gt;
&lt;li&gt;If it succeeds we parse the JSON into &lt;code&gt;blocklist&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We then check if the number calling us right now against the list&lt;/li&gt;
&lt;li&gt;If it is not listed, proceed as normal&lt;/li&gt;
&lt;li&gt;If it is in the blocklist, reject the call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For curiosity purposes; When you reject a call, to the caller there’s an automated message that says the number is not in use then it instantly hangs up on them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Make it so
&lt;/h1&gt;

&lt;p&gt;To apply your newly created function to your phone number(s), check out the article &lt;a href="https://support.twilio.com/hc/en-us/articles/223135027-Configuring-Phone-Numbers-to-Receive-Voice-Calls"&gt;Configuring Phone Numbers to Receive Voice Calls&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Dun
&lt;/h1&gt;

&lt;p&gt;That was easy enough… right? Hit up the discussion forum if you need a hand :)&lt;/p&gt;

</description>
      <category>twilio</category>
      <category>showdev</category>
      <category>serverless</category>
    </item>
    <item>
      <title>The Problem with Luminary and Other Exclusive "Podcast" Hosts</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Mon, 22 Apr 2019 20:21:34 +0000</pubDate>
      <link>https://dev.to/cohan/the-problem-with-luminary-and-other-exclusive-podcast-hosts-21o4</link>
      <guid>https://dev.to/cohan/the-problem-with-luminary-and-other-exclusive-podcast-hosts-21o4</guid>
      <description>&lt;p&gt;“heh guess people just don’t like paying for things”&lt;/p&gt;

&lt;p&gt;Dammit, no. That’s not the problem.&lt;/p&gt;

&lt;p&gt;More news of Luminary, Spotify, The BBC, etc doing their exclusive lockdown of the podcast ecosystem popping up as Luminary readies to go live.&lt;/p&gt;

&lt;p&gt;The problem these companies don’t seem to grasp, and indeed the tech blogs that report on them, is the problem with them is &lt;em&gt;not&lt;/em&gt; that they’re paid content. It’s that they’re &lt;em&gt;not podcasts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Podcasts have RSS feeds. Podcasts can be played in any podcast client. Podcasts can be played &lt;em&gt;on iPods&lt;/em&gt;, dammit. There needs to be a way to download the episodes and play them on any device.&lt;/p&gt;

&lt;p&gt;Patreon for example gets this. You can set up an exclusive-to-patrons podcast feed on their system and Patreon will give your patrons a unique link that they can use to access the content. &lt;em&gt;This is all it needs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If Luminary, Spotify, The BBC, whoever else, were to provide users with a unique RSS URL they can subscribe to in their client of choice we’re all on the same page.&lt;/p&gt;

&lt;p&gt;It is &lt;em&gt;not&lt;/em&gt; an issue with paying for podcasts. It’s an issue with their podcasts not being podcasts. Open up your doors, podcasting is inclusive - not exclusive.&lt;/p&gt;

&lt;p&gt;Let the market decide if your podcasts are worth paying for, don’t try to lock down the ecosystem that’s been around since before you were a startup sparkle in some nerd’s eye. Quit trying to wall everything off. Ya dinguses.&lt;/p&gt;

</description>
      <category>podcast</category>
    </item>
    <item>
      <title>Podcast Chapter-o-tron</title>
      <dc:creator>Cohan Robinson</dc:creator>
      <pubDate>Sat, 20 Apr 2019 19:00:00 +0000</pubDate>
      <link>https://dev.to/cohan/podcast-chapter-o-tron-337g</link>
      <guid>https://dev.to/cohan/podcast-chapter-o-tron-337g</guid>
      <description>&lt;p&gt;I wanted a simple way to add chapters to my podcast episodes.&lt;/p&gt;

&lt;p&gt;I know there’s other software out there that does this - it’s mostly all Mac software (grumble grumble) - but I wanted a nice simple web interface to adding podcast chapters. Naturally I couldn’t find one.&lt;/p&gt;

&lt;p&gt;Enter the Podcast Chapter-o-tron. Select your podcast file, specify where your chapters need to be, hit Go. Give it a moment to upload and process and it’ll chuck you back a file with your chapters encoded in to the file.&lt;/p&gt;

&lt;p&gt;These chapters have tested working with Overcast so far, but I imagine any player that supports chapters will display them.&lt;/p&gt;

&lt;p&gt;To note this is the very most basic initial build of this sort of thing, so it’s missing a few things. No file upload or processing progress bar yet and if there’s an error it’ll just chuck you your file back (I know, that’s not the best).&lt;/p&gt;

&lt;p&gt;Also because I’m just hosting it on my standard tinkering server for now if the disk fills up it’ll probably just completely fall over spectacularly. I’ll keep an eye on that for now and set it up to clean up old files automatically soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.podhex.com/tools/chapters"&gt;Podcast Chapter-o-tron&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.podhex.com/tools/chapters"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ckvsIIDE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cohan.io/images/podhex/chapters.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>podcast</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
