<?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: Kyle J. Kemp</title>
    <description>The latest articles on DEV Community by Kyle J. Kemp (@seiyria).</description>
    <link>https://dev.to/seiyria</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%2F5233%2F763609.jpeg</url>
      <title>DEV Community: Kyle J. Kemp</title>
      <link>https://dev.to/seiyria</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/seiyria"/>
    <language>en</language>
    <item>
      <title>A Better Deployment Process (Monorepos, CapRover, and Netlify)</title>
      <dc:creator>Kyle J. Kemp</dc:creator>
      <pubDate>Sat, 12 Dec 2020 19:56:07 +0000</pubDate>
      <link>https://dev.to/seiyria/a-better-deployment-process-monorepos-caprover-and-netlify-3ckl</link>
      <guid>https://dev.to/seiyria/a-better-deployment-process-monorepos-caprover-and-netlify-3ckl</guid>
      <description>&lt;p&gt;Deployment, one of the first pipelines to set up and one of the most important pipelines to have. I recently set up a really handy deployment process with Github Actions and wanted to share more, for anyone who finds themselves in a similar situation. Here's an overview of my situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have a monorepo, which makes deployment somewhat harder than I had hoped&lt;/li&gt;
&lt;li&gt;I wanted to deploy the backend to a private server with CapRover (this post will assume that CapRover is set up already)&lt;/li&gt;
&lt;li&gt;I wanted to deploy the frontend to Netlify, without building every time the backend updates&lt;/li&gt;
&lt;li&gt;I wanted the ability to deploy independently, together, manually, and automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For reference, I'll share &lt;a href="https://github.com/LandOfTheRair/LandOfTheRair"&gt;a link to my project&lt;/a&gt; so it'll be easy to look up the finer points of my implementation.&lt;/p&gt;

&lt;p&gt;A few problems I ran into upfront:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CapRover makes deployment somewhat difficult if you have a monorepo, and I personally dislike vendor-specific files&lt;/li&gt;
&lt;li&gt;Netlify makes deployment somewhat difficult if you have a monorepo (as well), and I simply could not get their &lt;code&gt;build.ignore&lt;/code&gt; settings to work, and the vendor-specific files too&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Client Action
&lt;/h1&gt;

&lt;p&gt;So, first, lets work on the manual process for Netlify w/ GitHub Actions, since it's so much easier. Thankfully, there's a Netlify action that makes this easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Deploy to Netlify
  uses: nwtgck/actions-netlify@v1.1
  with:
    publish-dir: './client/dist'
    production-branch: master
    github-token: ${{ secrets.GITHUB_TOKEN }}
    deploy-message: "Deploy from GitHub Actions"
    enable-pull-request-comment: false
    enable-commit-comment: true
    overwrites-pull-request-comment: true
  env:
    NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
    NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, this assumes the app is built to &lt;code&gt;client/dist&lt;/code&gt; first, but from there, it's straightforward - turn off Netlify auto deploys, since this will cover it.  &lt;a href="https://github.com/LandOfTheRair/LandOfTheRair/blob/master/.github/workflows/manual-deploy-client.yml"&gt;Here's my full action&lt;/a&gt; for client side manual deployments.&lt;/p&gt;

&lt;h1&gt;
  
  
  Server Action
&lt;/h1&gt;

&lt;p&gt;The server action, for me, was much more difficult since I'm not well-versed with Docker. First, I had to come up with a Dockerfile (this is the easiest way to deploy to CapRover, IMO). I had some issues trying to find one that would work with my old version of cWS, turns out I had to use node 13.14 specifically. But that's neither here nor there, here's the Dockerfile I came up with (&lt;a href="https://github.com/LandOfTheRair/LandOfTheRair/blob/master/Dockerfile"&gt;current version here&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:13.14.0-alpine
RUN apk add --no-cache libc6-compat
RUN ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ADD https://www.google.com /time.now
COPY ./package.json /usr/src/app
COPY ./package-lock.json /usr/src/app
COPY ./tsconfig.json /usr/src/app
COPY ./server /usr/src/app/server
COPY ./shared /usr/src/app/shared
RUN npm install
RUN cd server &amp;amp;&amp;amp; npm run setup &amp;amp;&amp;amp; npm cache clean --force
RUN cd server/content &amp;amp;&amp;amp; npm install --unsafe-perm
RUN cd server &amp;amp;&amp;amp; npm run build
ENV NODE_ENV production
ENV PORT 80
EXPOSE 80
CMD cd server &amp;amp;&amp;amp; npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was running into some weird issues with needing a particular native function from &lt;code&gt;ld-linux-x86-64.so.2&lt;/code&gt;, which &lt;code&gt;alpine&lt;/code&gt; doesn't have. I searched around and found that I can symlink a different &lt;code&gt;.so&lt;/code&gt; file and make this work, so that was one problem sorted out.&lt;/p&gt;

&lt;p&gt;After that, I ran into some issues installing a sub-repo that gets cloned, which threw some weird error that ended up being an npm issue, fixed by adding &lt;code&gt;--unsafe-perm&lt;/code&gt; to that npm install. Everything else is pretty straightforward for people who use docker, I imagine. &lt;/p&gt;

&lt;p&gt;One might notice I structure things a bit differently than most. I think in other Dockerfiles I've seen copying a single &lt;code&gt;package.json&lt;/code&gt; file, installing, and going from there. Here, I had to copy &lt;code&gt;server/&lt;/code&gt;, &lt;code&gt;shared/&lt;/code&gt;, and the root &lt;code&gt;package.json&lt;/code&gt; file to get the install process correct.&lt;/p&gt;

&lt;p&gt;From there, the action is really straightforward, but note that it &lt;em&gt;must&lt;/em&gt; be run on linux. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Deploy Server
  uses: AlexxNB/caprover-action@v1
  with:
    server: 'https://captain.server.rair.land'
    password: '${{ secrets.CAPROVER_PASSWORD }}'
    appname: 'game'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This action is yet a bit more convoluted because it does a build before it starts doing anything in the Dockerfile, then it does it again in the Dockerfile, but the time overhead isn't significant enough for me to want to fix it. &lt;a href="https://github.com/LandOfTheRair/LandOfTheRair/blob/master/.github/workflows/manual-deploy-server.yml"&gt;Here's my full action&lt;/a&gt; for server deployments.&lt;/p&gt;

&lt;h1&gt;
  
  
  Automatically Deploying
&lt;/h1&gt;

&lt;p&gt;The two actions above handle the manual deployments, if needed. Seeing the full files shows how to set up manual deployments with GitHub Actions, but the tl;dr is &lt;code&gt;on: workflow_dispatch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, that's nice to have for testing, hotfixing, or whatever the case may be, but in general this is something worth automating. Thankfully, GitHub Actions is super flexible! It's really easy to compose the two manual tasks above into something that only deploys on tags (&lt;a href="https://github.com/LandOfTheRair/LandOfTheRair/blob/master/.github/workflows/release-tags.yml"&gt;the full action is here&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Release New Tags

on:
  push:
    tags:
      - 'v*' # Any pushed tag

jobs:
  build:
    name: Create Release

    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        # os: [macos-latest, ubuntu-latest, windows-latest]
        os: [ubuntu-latest]
        node-version: [15.x]

    steps:
    - uses: actions/checkout@v2

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}

    - run: npm install

    - run: npm run lint

    - run: npm run build

    - name: Deploy Server
      uses: AlexxNB/caprover-action@v1
      with:
        server: 'https://captain.server.rair.land'
        password: '${{ secrets.CAPROVER_PASSWORD }}'
        appname: 'game'

    - name: Deploy to Netlify
      uses: nwtgck/actions-netlify@v1.1
      with:
        publish-dir: './client/dist'
        production-branch: master
        github-token: ${{ secrets.GITHUB_TOKEN }}
        deploy-message: "Deploy from GitHub Actions"
        enable-pull-request-comment: false
        enable-commit-comment: true
        overwrites-pull-request-comment: true
      env:
        NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
        NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would automate client and server deployments on tags, but it could easily be changed to on push, or on any event GitHub Actions supports.&lt;/p&gt;

</description>
      <category>deployment</category>
      <category>netlify</category>
      <category>caprover</category>
      <category>monorepo</category>
    </item>
    <item>
      <title>Making a Reddit Reply Bot</title>
      <dc:creator>Kyle J. Kemp</dc:creator>
      <pubDate>Thu, 25 Apr 2019 15:57:55 +0000</pubDate>
      <link>https://dev.to/seiyria/making-a-reddit-reply-bot-f55</link>
      <guid>https://dev.to/seiyria/making-a-reddit-reply-bot-f55</guid>
      <description>&lt;p&gt;There's a lot of documentation on writing a reddit bot in Python, but I had a lot of trouble finding even basic documentation for Node - even some of the libraries that are listed on reddits official wiki are dead or 5 years old (read: don't support new reddit very well). So, I wanted to write about a simple and common use-case: &lt;em&gt;replying to a user who tags you&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Reddit Application
&lt;/h3&gt;

&lt;p&gt;First, head on over to &lt;a href="https://www.reddit.com/prefs/apps" rel="noopener noreferrer"&gt;https://www.reddit.com/prefs/apps&lt;/a&gt; and hit "create app" - you need to do this so reddit isn't using your personal user account. You should also sign up for a new reddit account for your bot (especially if it can be summoned). Make sure you add your main account and bot account as developers on this application.&lt;/p&gt;

&lt;p&gt;When creating an app, you need to fill in the field similarly to this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5s2a5u5zwl03uq3m81v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5s2a5u5zwl03uq3m81v.png" width="525" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You don't need to worry about the &lt;code&gt;about uri&lt;/code&gt; or &lt;code&gt;redirect uri&lt;/code&gt; fields, as you won't be using them, so you can put in whatever you would like.&lt;/p&gt;

&lt;p&gt;Once in, you'll see a screen like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flanataai3b965mmh1238.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flanataai3b965mmh1238.png" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of this, because you'll need this information in just a second.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting the Node Project
&lt;/h3&gt;

&lt;p&gt;For something like this, I found it very easy to use &lt;a href="https://www.npmjs.com/package/snoostorm" rel="noopener noreferrer"&gt;&lt;code&gt;snoostorm&lt;/code&gt;&lt;/a&gt; (a wrapper around &lt;a href="https://www.npmjs.com/package/snoowrap" rel="noopener noreferrer"&gt;&lt;code&gt;snoowrap&lt;/code&gt;&lt;/a&gt;). This library makes it exceptionally simple to get comments as they come in.&lt;/p&gt;

&lt;p&gt;You first need to make a &lt;code&gt;snoowrap&lt;/code&gt; object, then use that to make a &lt;code&gt;CommentStream&lt;/code&gt; object. To do that, you'll need your reddit bot username, password, application secret, and application id. You must specify a unique user-agent, so call it something like &lt;code&gt;my-node-js-bot&lt;/code&gt;. So, configure it like so (mine is configured based on the picture above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Snoowrap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;snoowrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CommentStream&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;snoostorm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Snoowrap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-node-js-bot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;qR6rJnQ7sEJZDw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OCoo9pYnlC2K6fxQQxbcIPQ5MA4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myusernamebutactuallybot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mypasswordbutactuallybot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this client object, you can finally start listening for new comments! Head over to &lt;a href="https://www.reddit.com/r/testingground4bots" rel="noopener noreferrer"&gt;/r/testingground4bots&lt;/a&gt; and hop into a thread or make your own. Then, add some code to start watching for comments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pollTime is 10000 because reddit is very strict on posting too frequently&lt;/span&gt;
&lt;span class="c1"&gt;// at first, you'll only be able to post once every 10 minutes, so make sure you get it right!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;subreddit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testingground4bots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;pollTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the bot up, and you'll see a flood of comments in your terminal. You may be wondering why that is - you haven't even seen any new ones come in yet! Well, the &lt;code&gt;client&lt;/code&gt; will always give you the first X entries (in this case, 10) when you start your bot up, and then it will track from there.&lt;/p&gt;

&lt;p&gt;We can fix that pretty easily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// reddits api doesn't use millis&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BOT_START&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;subreddit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testingground4bots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;pollTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;created_utc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;BOT_START&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, now you only see the newest comments as they come in. Hopefully you have an established enough reddit account to make some posts on this subreddit. If you do so, you'll see your terminal fill with them fairly quickly after posting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making It Interact
&lt;/h3&gt;

&lt;p&gt;So far, you've got a bot and it reads comments - that's a great start! But you want it to interact with your audience, right? So, how about a good ol' hello world? Check it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BOT_START&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;subreddit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testingground4bots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;pollTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;created_utc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;BOT_START&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There, any time a comment comes in, the bot will reply to it with "hello world!" Wait... that might talk a bit often, won't it? It might get &lt;em&gt;just a little bit annoying.&lt;/em&gt; Reddit recommends replying specifically when your bot is mentioned, so, there's a fairly easy way to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BOT_START&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canSummon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/u/myusernamebutactuallybot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;subreddit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testingground4bots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;pollTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;created_utc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;BOT_START&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;canSummon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There! So, what this does is make sure that the comment your bot finds &lt;em&gt;actually&lt;/em&gt; refers to the bot itself. This &lt;code&gt;canSummon&lt;/code&gt; function will do basic checking to make sure your bot doesn't erroneously spam a bunch of peoples comments. Make a comment now that says &lt;code&gt;/u/myusernamebutactuallybot&lt;/code&gt; (rather, you should check for &lt;em&gt;your own bots name&lt;/em&gt;), and you should see a reply shortly afterwards that says "hello world!" in reply. &lt;/p&gt;

&lt;p&gt;That's all you gotta do! 🎉&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>reddit</category>
      <category>bot</category>
      <category>node</category>
    </item>
    <item>
      <title>Introducing: Inveinta - Another Inventory Management Tool</title>
      <dc:creator>Kyle J. Kemp</dc:creator>
      <pubDate>Wed, 31 Jan 2018 16:46:48 +0000</pubDate>
      <link>https://dev.to/seiyria/introducing-inveinta---another-inventory-management-tool-12hp</link>
      <guid>https://dev.to/seiyria/introducing-inveinta---another-inventory-management-tool-12hp</guid>
      <description>&lt;p&gt;A few weeks ago I was feeling unproductive, and for me the best way to quash that feeling is to hammer out a small project from start to finish. A few people were talking about needing a solution to manage large amounts of inventory + some other features like collaborative editing and checking in and out their stuff. I've wanted to make this for a while but now was the time to hammer out it. So I spun up a quick Ionic project and started to learn how to use the new Firestore tech (a vast improvement over the old Realtime Database IMO) and got to work.&lt;/p&gt;

&lt;p&gt;My idea was to make it so you use or create "mixins" to categorize your lists of items, using sets of fields to define your list. So, if you want to have a list of MTG trading cards for sale, you'd pick "Magic the Gathering" "for sale". If you wanted to have a check in/check out system for video games, you'd pick "Video Games" "Library". Of course, you can make your own mixins as well - there's no way to cover every possible need.&lt;/p&gt;

&lt;p&gt;You can see the end result &lt;a href="https://inveinta.netlify.com"&gt;here&lt;/a&gt;, but since that's just the app (I haven't gotten time to make a "proper" site for it), here's some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://inveinta.netlify.com/#/p/9XjlXJGeM3AuP8LlBwBp"&gt;My board game collection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://inveinta.netlify.com/#/p/k9iaUn0iA1rCp5wN6cKx"&gt;My recipe storage list&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As well, &lt;a href="https://imgur.com/a/TW34N"&gt;here are some pics&lt;/a&gt; of the tool in action.&lt;/p&gt;

&lt;p&gt;What do you think?&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>firebase</category>
      <category>ionic</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
