<?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: Gavin Rehkemper</title>
    <description>The latest articles on DEV Community by Gavin Rehkemper (@gavinr).</description>
    <link>https://dev.to/gavinr</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%2F90314%2F61997039-39b7-444d-b6fc-e820a6c2dbf3.jpeg</url>
      <title>DEV Community: Gavin Rehkemper</title>
      <link>https://dev.to/gavinr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gavinr"/>
    <language>en</language>
    <item>
      <title>Clean Pull Request Diffs</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Fri, 27 Jan 2023 14:46:00 +0000</pubDate>
      <link>https://dev.to/gavinr/clean-pull-request-diffs-19n9</link>
      <guid>https://dev.to/gavinr/clean-pull-request-diffs-19n9</guid>
      <description>&lt;p&gt;When collaborating on code with others using Git, keeping the overall list of code changes (the "diff") in a pull request as small as possible - not including lots of unnecessary changes like quotes and tabbing - is an important and considerate thing to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why lots of unrelated changes suck
&lt;/h2&gt;

&lt;p&gt;A pull request (aka merge request) represents a request to merge a branch that has multiple outstanding commits, with each of those commits representing a variety of lines of code changes.  These code changes are shown on the pull request summary and is one of the main things someone who reviews the pull request reviews.&lt;/p&gt;

&lt;p&gt;For those reviewers, it takes time and mental energy to understand what code change you're proposing: what it intends to do, what it actually does, and if there are any obvious bugs. When you have many un-related changed lines in the diff, that forces the reviewer to &lt;em&gt;also&lt;/em&gt; analyze which lines are "actual" changed lines and which are unnecessary and can be ignored.&lt;/p&gt;

&lt;p&gt;&lt;a href="/posts/images/dirty-diff.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgavinr.com%2Fposts%2Fimages%2Fdirty-diff.png" title="Dirty diff" alt="Dirty diff" width="800" height="236"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A diff that's hard to see what are the significant changes&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It discourages (good) reviews
&lt;/h2&gt;

&lt;p&gt;The review process is already difficult enough. In many situations the reviewer is taking time out of his/her busy schedule to change contexts and review your code. Changing mind contexts then fully understanding the code changes takes a lot of effort, and adding any additional challenge to this process makes it that much harder. If a reviewer sees a large PR with a bunch of unnecessary code changes, it may influence him or her to just skip the review or perform a "low value review."&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid it
&lt;/h2&gt;

&lt;p&gt;So, create change requests that contain only the minimum necessary code changes to fix the bug or add the feature that your pull request is trying to do. Any additional lines are detrimental to the software creation process.&lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
    </item>
    <item>
      <title>Query All Features from a Feature Service</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Tue, 31 May 2022 19:34:18 +0000</pubDate>
      <link>https://dev.to/gavinr/query-all-features-from-a-feature-service-2i1g</link>
      <guid>https://dev.to/gavinr/query-all-features-from-a-feature-service-2i1g</guid>
      <description>&lt;p&gt;When querying an ArcGIS Feature Service, there is typically a maximum number of features (records) that will be returned from any query – usually set to 1000. If you want to query for &lt;strong&gt;all&lt;/strong&gt; the features in the service, ArcGIS REST JS does not currently do this (see &lt;a href="https://github.com/Esri/arcgis-rest-js/issues/690"&gt;this discussion&lt;/a&gt;) - you’ll need to make multiple REST calls to get them all. Use the package &lt;a href="https://www.npmjs.com/package/query-all-features"&gt;query-all-features&lt;/a&gt; to do this.&lt;/p&gt;

&lt;p&gt;First install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;query-all-features
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use it in your code. It takes as input the same object as the &lt;a href="https://developers.arcgis.com/arcgis-rest-js/api-reference/arcgis-rest-feature-service/queryFeatures"&gt;queryFeatures endpoint of ArcGIS REST JS&lt;/a&gt;.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;queryAllFeatures&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query-all-features&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;queryAllFeatures&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;results&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&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;err&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="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;err&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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;You can also use it in &lt;a href="https://github.com/gavinr/query-all-features#node-js"&gt;NodeJS&lt;/a&gt;, in the &lt;a href="https://github.com/gavinr/query-all-features#browser---es-modules-via-cdn"&gt;browser via ES Modules (via CDN)&lt;/a&gt;, and in the &lt;a href="https://github.com/gavinr/query-all-features#browser---script-tag-via-umd-cdn"&gt;browser via a script tag&lt;/a&gt;. Here's a full code sample in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codepen.io/gavinr/pen/ExQYegd"&gt;https://codepen.io/gavinr/pen/ExQYegd&lt;/a&gt; &lt;/p&gt;

</description>
      <category>arcgis</category>
      <category>javascript</category>
      <category>geodev</category>
    </item>
    <item>
      <title>Svelte + Vite Web Mapping App in 3 Steps</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Tue, 14 Sep 2021 14:34:26 +0000</pubDate>
      <link>https://dev.to/gavinr/svelte-vite-web-mapping-app-in-3-steps-5heg</link>
      <guid>https://dev.to/gavinr/svelte-vite-web-mapping-app-in-3-steps-5heg</guid>
      <description>&lt;p&gt;&lt;em&gt;Using the ArcGIS API for JavaScript&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Getting started building a web mapping app is quick and easy with Svelte and Vite. Here are the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Run the &lt;a href="https://vitejs.dev/guide/#scaffolding-your-first-vite-project"&gt;Vite init workflow&lt;/a&gt; choosing the Svelte template:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init vite@latest esri-svelte-project &lt;span class="nt"&gt;--template&lt;/span&gt; svelte
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;or if you prefer TypeScript:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init vite@latest esri-svelte-project &lt;span class="nt"&gt;--template&lt;/span&gt; svelte-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then install the dependencies and run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;esri-svelte-project
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @arcgis/core &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy contents of &lt;a href="https://github.com/gavinr/esri-svelte-example/blob/master/src/App.svelte"&gt;&lt;code&gt;App.svelte&lt;/code&gt; in this repository&lt;/a&gt; into your &lt;code&gt;App.svelte&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is a simple, interactive map on the page like &lt;a href="https://esri-svelte-example.gavinr.com/"&gt;this&lt;/a&gt;, but you can do a lot more. For example, a &lt;a href="https://gavinr.github.io/stl-live-crime/"&gt;full page emergency call mapping application&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Info
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/gavinr/esri-svelte-example"&gt;Esri Svelte Example GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.arcgis.com/javascript/"&gt;ArcGIS API for JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>maps</category>
      <category>svelte</category>
      <category>vite</category>
      <category>arcgis</category>
    </item>
    <item>
      <title>Support Software Developers</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Tue, 14 Sep 2021 13:44:34 +0000</pubDate>
      <link>https://dev.to/gavinr/support-software-developers-2j69</link>
      <guid>https://dev.to/gavinr/support-software-developers-2j69</guid>
      <description>&lt;p&gt;Support what you use and enjoy. This is true in all aspects of life, including software. Especially open source software.&lt;/p&gt;

&lt;p&gt;Here are a few simple ways to do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. "Star" the project on GitHub (FREE)
&lt;/h2&gt;

&lt;p&gt;Giving a project a "star" tells the developer that you appreciate their effort. It costs you nothing, but is quite encouraging to the developer when it appears in the feed.&lt;/p&gt;

&lt;p&gt;This encouragement is important because open source projects generally do not get any feedback when the software works well -- the developer only hears about problems and bugs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GD8evLdV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://gavinr.com/posts/images/github-star.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GD8evLdV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://gavinr.com/posts/images/github-star.gif" alt="Click the GitHub Star"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Send a personal thank you message (FREE)
&lt;/h2&gt;

&lt;p&gt;Find the developer's email address via GitHub or their personal website, and send a quick note of thanks and appreciation. It need not be long or complex. Taking a small amount of time out of your day to do this is very meaningful and really encourages the developer.&lt;/p&gt;

&lt;p&gt;This can be done using social media, but I encourage doing it via email because it's more personal and feels more direct. If you're big into social media, do via social media &lt;em&gt;and&lt;/em&gt; email!&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Send money
&lt;/h2&gt;

&lt;p&gt;If you have the means, taking a small portion of your donation budget each year to send it to software developers who work on the software you enjoy is a great way of saying thanks. Sending a donation is easier than ever.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the software has an Info or About page, it might mention ways to donate there.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the project has a GitHub page, check the "Sponsor this project" section.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jDF-Qiby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://gavinr.com/posts/images/mac-dev-playbook-sponsort.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jDF-Qiby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://gavinr.com/posts/images/mac-dev-playbook-sponsort.png" alt="sponsor github"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find a contributor by going to the GitHub repository "Insights &amp;gt; Contributors" page and see if they have a GitHub Sponsors or other sponsorship link on their user page.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Posl6K7J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://gavinr.com/posts/images/github-find-contributor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Posl6K7J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://gavinr.com/posts/images/github-find-contributor.png" alt="github insights contributors"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find their personal homepage to see if they accept donations via an alternative method.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GeZLPxnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://gavinr.com/posts/images/jeff-geerling-personal-site-donation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GeZLPxnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://gavinr.com/posts/images/jeff-geerling-personal-site-donation.png" alt="jeff geerling personal website"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If none of these steps led you to a donation page, go back to option two above, and ask if they have a way to donate directly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>Map Stream - Live view of ArcGIS Online Maps</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Fri, 21 May 2021 02:22:12 +0000</pubDate>
      <link>https://dev.to/gavinr/map-stream-live-view-of-arcgis-online-maps-i6h</link>
      <guid>https://dev.to/gavinr/map-stream-live-view-of-arcgis-online-maps-i6h</guid>
      <description>&lt;p&gt;&lt;a href="https://map-stream.gavinr.com/"&gt;Map Stream&lt;/a&gt; is a web app showing a live stream of newly-updated public maps on ArcGIS Online. &lt;/p&gt;

&lt;p&gt;The interesting thing about watching everything stream by is the variety: topic, location, age, popularity. Just about anything can pop up.&lt;/p&gt;

&lt;p&gt;Built with Svelte, the source code is public: &lt;a href="https://github.com/gavinr/map-stream"&gt;github.com/gavinr/map-stream&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check it out: &lt;a href="https://map-stream.gavinr.com/"&gt;&lt;strong&gt;map-stream.gavinr.com&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>maps</category>
      <category>arcgis</category>
    </item>
    <item>
      <title>Find the Coordinates for a Location</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Mon, 08 Mar 2021 05:51:49 +0000</pubDate>
      <link>https://dev.to/gavinr/find-the-coordinates-for-a-location-4p2c</link>
      <guid>https://dev.to/gavinr/find-the-coordinates-for-a-location-4p2c</guid>
      <description>&lt;p&gt;Finding the latitude and longitude coordinates of a particular location is not as easy as it should be. You can get it from Google Maps, but it requires 3 or 4 clicks. There are also a bunch of sites devoted to the task - most with ads and invasive spyware slowing down the page.&lt;/p&gt;

&lt;p&gt;We need something better - that's why I created &lt;a href="https://latlonlocate.com/"&gt;Latitude Longitude Locate&lt;/a&gt;. Latitude Longitude Locate is a simple mapping app designed for geo developers. Click on a location where you want to get the coordinates, and click the "copy" icon. Those coordinates are now on your clipboard - &lt;strong&gt;two clicks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are also a few more features, like the ability to swap the &lt;a href="https://macwright.com/lonlat/"&gt;order&lt;/a&gt; of latitude/longitude.&lt;/p&gt;

&lt;p&gt;It's meant to be simple and quick. I hope it helps you out. &lt;a href="https://gavinr.com/contact/"&gt;Let me know&lt;/a&gt; if you have any ideas or suggestions to make it even better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://latlonlocate.com"&gt;LatLonLocate.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>latitude</category>
      <category>longitude</category>
      <category>geo</category>
      <category>location</category>
    </item>
    <item>
      <title>Export or Import Issues from GitHub</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Wed, 29 Apr 2020 04:34:02 +0000</pubDate>
      <link>https://dev.to/gavinr/export-or-import-issues-from-github-1caj</link>
      <guid>https://dev.to/gavinr/export-or-import-issues-from-github-1caj</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/gavinr/github-csv-tools" rel="noopener noreferrer"&gt;GitHub CSV Tools&lt;/a&gt; now supports exporting issues! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose what columns you want in the exported CSV with &lt;code&gt;--exportAttributes&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Export all the comments per issue with &lt;code&gt;--exportComments&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Importing issues via a CSV is also possible, just pass a CSV file like &lt;code&gt;githubCsvTools myFile.csv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get started, just run &lt;code&gt;npm install -g github-csv-tools&lt;/code&gt; and then export with the command &lt;code&gt;githubCsvTools&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/gavinr" rel="noopener noreferrer"&gt;
        gavinr
      &lt;/a&gt; / &lt;a href="https://github.com/gavinr/github-csv-tools" rel="noopener noreferrer"&gt;
        github-csv-tools
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Import and export GitHub issues via CSV
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/gavinr/github-csv-tools/blob/master/banner.jpg?raw=true"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgavinr%2Fgithub-csv-tools%2Fraw%2Fmaster%2Fbanner.jpg%3Fraw%3Dtrue" alt="GitHub CSV Tools banner" title="GitHub CSV Tools"&gt;&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Import and export GitHub issues via CSV&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
  &lt;a href="https://github.com/gavinr/github-csv-tools/actions?query=workflow%3ATest+branch%3Amaster" rel="noopener noreferrer"&gt;
    &lt;img alt="Build" src="https://github.com/gavinr/github-csv-tools/workflows/Test/badge.svg"&gt;
  &lt;/a&gt;
  &lt;a href="https://github.com/gavinr/github-csv-tools/actions?query=workflow%3ARelease+branch%3Amaster" rel="noopener noreferrer"&gt;
    &lt;img alt="Release" src="https://github.com/gavinr/github-csv-tools/workflows/Release/badge.svg"&gt;
  &lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/github-csv-tools" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="npm latest version" src="https://camo.githubusercontent.com/8395d10b325605c844cfafe715fdfae07b96792924deb9054b1bcc4becf5f82b/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f6769746875622d6373762d746f6f6c732f6c61746573742e737667"&gt;
  &lt;/a&gt;
  &lt;a href="https://repoio.com" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="npm latest version" src="https://camo.githubusercontent.com/cade9ed458c8178eb39dd9be362f2f932782e342d71aa1ad8b35e6fe6a6856f6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f686f737465642d7265706f696f2e636f6d2d6f72616e6765"&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Prerequisite: &lt;a href="https://nodejs.org/en/" rel="nofollow noopener noreferrer"&gt;Install Node.js&lt;/a&gt;, then run this to install:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install -g github-csv-tools&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After install, &lt;code&gt;githubCsvTools --help&lt;/code&gt; for info on how to use, or see below.&lt;/p&gt;

&lt;p&gt;Instructions for exporting or importing:&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;To Import Issues&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;Currently imports title, body, labels, status (closed or open) and milestones. See the &lt;a href="https://github.com/gavinr/github-csv-tools/test" rel="noopener noreferrer"&gt;test&lt;/a&gt; folder for example input formats.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;githubCsvTools myFile.csv&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;To Export Issues&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;githubCsvTools&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;-f, --exportFileName&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;YYYY-MM-DD-hh-mm-ss-issues.csv&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;The name of the CSV you'd like to export to.&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;-a, --exportAttributes&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;number, title, labels, state, assignees, milestone, comments, created_at, updated_at, closed_at, body&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Comma-separated list of attributes (columns) in the export**.&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;-c, --exportComments&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Include comments in the export. If using in combination with &lt;code&gt;--exportAttributes&lt;/code&gt;, &lt;code&gt;id&lt;/code&gt; must be included.&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;-e, --exportAll&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Export all possible values from the GitHub API. If not included, a subset of attributes (see &lt;code&gt;--exportAttributes&lt;/code&gt; above) that are known to be compatible&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/p&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/gavinr/github-csv-tools" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>github</category>
      <category>csv</category>
    </item>
    <item>
      <title>How to open a GTFS Bus Feed in the Browser</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Sun, 05 Apr 2020 20:57:27 +0000</pubDate>
      <link>https://dev.to/gavinr/how-to-open-a-gtfs-bus-feed-in-the-browser-kgo</link>
      <guid>https://dev.to/gavinr/how-to-open-a-gtfs-bus-feed-in-the-browser-kgo</guid>
      <description>&lt;p&gt;The &lt;a href="https://developers.google.com/transit/gtfs-realtime" rel="noopener noreferrer"&gt;GTFS Real-time feed&lt;/a&gt; is a data specification for sharing real-time transit data. In other words, many transit systems share a public feed in this format for developers to use to build apps, websites, and more.&lt;/p&gt;

&lt;p&gt;The most basic way to get going with this type of feed is to show the current locations on a map in a browser. This is not too tough, but there are a few things you need to get correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoding the PBF Feed
&lt;/h2&gt;

&lt;p&gt;The GTFS Specification says that the data feed will be encoded using &lt;a href="https://developers.google.com/protocol-buffers/" rel="noopener noreferrer"&gt;Protocol Buffers&lt;/a&gt; (aka protobuf or PBF). There are a few JavaScript libraries for decoding protobufs - I used the &lt;a href="https://github.com/mapbox/pbf" rel="noopener noreferrer"&gt;pbf library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The thing about protobuf is that the "schema" of the data is not sent when the data is sent - your client that reads the data must "already know" the schema. Luckily, we know our feed is in the GTFS scheme and they even provide the &lt;a href="https://developers.google.com/transit/gtfs-realtime/gtfs-realtime-proto" rel="noopener noreferrer"&gt;schema file&lt;/a&gt; (protobuf schema files, when published, are usually named &lt;code&gt;___.proto&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;We must convert that &lt;code&gt;.proto&lt;/code&gt; file into something our JavaScript library (pbf) can use. The library provides a &lt;a href="https://github.com/mapbox/pbf#proto-schema-to-javascript" rel="noopener noreferrer"&gt;command-line interface to do this&lt;/a&gt;, but I've already done that for you and published the files onto npm so we can use them &lt;a href="https://unpkg.com/browse/gtfs-realtime-pbf-js-module@1.0.0/" rel="noopener noreferrer"&gt;via a CDN&lt;/a&gt;. In other words, the first step is to import these JS files into your file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://unpkg.com/pbf@3.0.5/dist/pbf.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://unpkg.com/gtfs-realtime-pbf-js-module@1.0.0/gtfs-realtime.browser.proto.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we must write some code to actually get the data feed and decode it. That will look like this:&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://my-transit-agency.org/path/to/feed.pb?cacheBust=&lt;/span&gt;&lt;span class="dl"&gt;"&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;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// if HTTP-status is 200-299&lt;/span&gt;
  &lt;span class="c1"&gt;// get the response body (the method explained below)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bufferRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&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;pbf&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;Pbf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bufferRes&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;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FeedMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pbf&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the data!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&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;The keys to the above code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We're using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="noopener noreferrer"&gt;fetch API&lt;/a&gt;, but you could use plain XMLHttpRequest or any other request library just as easily, as long as you do the following:&lt;/li&gt;
&lt;li&gt;We grab the data as an arrayBuffer (&lt;code&gt;await response.arrayBuffer()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;.. then put the data into a Uit8Array (&lt;code&gt;new Uint8Array(bufferRes)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;new Pbf(...)&lt;/code&gt; and &lt;code&gt;FeedMessage.read(...)&lt;/code&gt; are functions provided in the &lt;a href="https://dev.topbf#proto-schema-to-javascript"&gt;pbf package&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You then just use &lt;code&gt;obj.entity&lt;/code&gt; to loop through your data and do what you want with it. In our case, add it to a Leaflet GeoJSON layer and map it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping the Data
&lt;/h2&gt;

&lt;p&gt;To convert the GTFS feed data to GeoJSON to map it, loop through the array of data and return back a GeoJSON feature for each item:&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;gtfsArrayToGeojsonFeatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gtfsArray&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;gtfsArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;gtfsObject&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="c1"&gt;// console.log("gtfsObject", gtfsObject);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Feature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Depending on your data source, the properties available on "gtfsObject" may be different:&lt;/span&gt;
        &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gtfsObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;route_start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gtfsObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;vehicle_label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gtfsObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Point&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;coordinates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="nx"&gt;gtfsObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;gtfsObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&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;Place those features into a &lt;a href="https://leafletjs.com/reference-1.6.0.html#geojson" rel="noopener noreferrer"&gt;Leaflet GeoJSON layer&lt;/a&gt;, add it to a map, and you've got your mapped locations!&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%2Fi.imgur.com%2Fxdi63kD.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%2Fi.imgur.com%2Fxdi63kD.png" title="Mapped GTFS Locations" alt="Mapped GTFS Locations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Full Code
&lt;/h2&gt;

&lt;p&gt;Putting it all together, &lt;a href="https://codepen.io/gavinr/pen/oNXrYGw?editors=0010" rel="noopener noreferrer"&gt;here's what the code would look like&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/gavinr/embed/oNXrYGw?height=600&amp;amp;default-tab=js,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  CORS
&lt;/h2&gt;

&lt;p&gt;Your GTFS feed must have a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" rel="noopener noreferrer"&gt;CORS header&lt;/a&gt; to allow your webpage to access the feed. If it doesn't, you may be able to use a proxy to add that header, or talk to the data owner asking them to add the CORS header to allow easier usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codepen.io/gavinr/pen/XWbzGMW?editors=0010" rel="noopener noreferrer"&gt;More feature-filled live-updating example using the ArcGIS API for JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gavinr.com/protocol-buffers-protobuf-browser/" rel="noopener noreferrer"&gt;More info on using Protobuf in a browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What public GTFS feeds are you using, and how are you using them? Let me know in the comments! Thanks!&lt;/p&gt;

</description>
      <category>gtfs</category>
      <category>transit</category>
      <category>protobuf</category>
      <category>leaflet</category>
    </item>
    <item>
      <title>How to use GitHub Actions to Automatically deploy a Sapper PWA to GitHub Pages </title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Wed, 26 Feb 2020 04:34:10 +0000</pubDate>
      <link>https://dev.to/gavinr/how-to-use-github-actions-to-automatically-deploy-a-sapper-pwa-to-github-pages-46p9</link>
      <guid>https://dev.to/gavinr/how-to-use-github-actions-to-automatically-deploy-a-sapper-pwa-to-github-pages-46p9</guid>
      <description>&lt;p&gt;&lt;a href="https://sapper.svelte.dev/"&gt;Sapper&lt;/a&gt; is a framework for building web applications, where every page is a &lt;a href="https://svelte.dev"&gt;Svelte&lt;/a&gt; component.&lt;/p&gt;

&lt;p&gt;You may want to setup your GitHub repository to use &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; to automatically build and deploy your site to GitHub Pages website hosting every time you check in your code. &lt;strong&gt;This is great because the build/deploy step happens automatically for you - no need to manually do it yourself!&lt;/strong&gt; Here's how to set that up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new GitHub Repository and copy the &lt;a href="https://github.com/sveltejs/sapper-template/archive/master.zip"&gt;Sapper template files&lt;/a&gt; to it.&lt;/li&gt;
&lt;li&gt;Ensure gh-pages is enabled by going to the repository setting tab and enabling it.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To enable Sapper to live at a subdirectory (yourname.github.io/repo-name), modify the &lt;code&gt;export&lt;/code&gt; task in &lt;code&gt;package.json&lt;/code&gt; to include &lt;code&gt;--basepath repo-name&lt;/code&gt; (replacing &lt;code&gt;repo-name&lt;/code&gt; with the name of your GitHub repository). It should look like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"export"&lt;/span&gt;: &lt;span class="s2"&gt;"sapper export  --basepath repo-name --legacy"&lt;/span&gt;,
                          ^^^^^ add this ^^^^^
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In &lt;code&gt;src/server.js&lt;/code&gt;, right after &lt;code&gt;polka().use(&lt;/code&gt;, add a string as the first parameter with the repository name, so it will look like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;polka&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;repo-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Add this line&lt;/span&gt;
  &lt;span class="nx"&gt;compression&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nx"&gt;sirv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;static&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;dev&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nx"&gt;sapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&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;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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;err&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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;/li&gt;
&lt;li&gt;&lt;p&gt;Create a GitHub Access Token by going to &lt;a href="https://github.com/settings/tokens"&gt;github.com/settings/tokens&lt;/a&gt; (scopes: &lt;code&gt;repo&lt;/code&gt; access)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Place that GitHub Access Token into the repository "Secrets" by going to the repository settings tab, then clicking the &lt;code&gt;Secrets&lt;/code&gt; page. I named mine &lt;code&gt;github_pat&lt;/code&gt; (used below)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new file, &lt;code&gt;.github/workflows/main.yml&lt;/code&gt;, with the contents below. Replace &lt;code&gt;secrets.github_pat&lt;/code&gt; with the name you gave to your GitHub Token in step 5. Replace &lt;code&gt;FOLDER: __sapper__/export/repo-name&lt;/code&gt; with the name of your repository (used above in step 3 and 4).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Deploy&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;persist-credentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js '12.x'&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;12.x'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run export&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Deploy&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JamesIves/github-pages-deploy-action@releases/v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ACCESS_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.github_pat }}&lt;/span&gt;
        &lt;span class="na"&gt;BRANCH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh-pages&lt;/span&gt;
        &lt;span class="na"&gt;FOLDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;__sapper__/export/repo-name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this is all setup, any time you commit to the master branch (or whichever branch you configured), the code will get built and deployed to GitHub Pages website hosting. &lt;a href="https://github.com/gavinr/sapper"&gt;Here is an example repository&lt;/a&gt; where you can see this in action. Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://gavinr.com/svelte-sapper-github-pages-actions/"&gt;Originally posted on gavinr.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sapper</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Publish a Svelte Web App with GitLab Pages</title>
      <dc:creator>Gavin Rehkemper</dc:creator>
      <pubDate>Sat, 15 Feb 2020 19:35:20 +0000</pubDate>
      <link>https://dev.to/gavinr/publish-a-svelte-web-app-with-gitlab-pages-409i</link>
      <guid>https://dev.to/gavinr/publish-a-svelte-web-app-with-gitlab-pages-409i</guid>
      <description>&lt;p&gt;If you've built a &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; web application and would like to host it, you can do so easily using &lt;a href="https://about.gitlab.com/stages-devops-lifecycle/pages/"&gt;GitLab Pages&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create and clone a new GitLab repository.&lt;/li&gt;
&lt;li&gt;Download and extract the &lt;a href="https://github.com/sveltejs/template/archive/master.zip"&gt;Svelte Starter Template&lt;/a&gt; into the repository.&lt;/li&gt;
&lt;li&gt;Since your URL will be at a subdirectory (&lt;code&gt;https://username.gitlab.io/repository-name&lt;/code&gt;), make the references to the JS and CSS files in your &lt;code&gt;public/index.html&lt;/code&gt; file relative. In other words, remove the leading &lt;code&gt;/&lt;/code&gt; from the &lt;code&gt;/global.css&lt;/code&gt;, &lt;code&gt;/build/bundle.css&lt;/code&gt;, and &lt;code&gt;/build/bundle.js&lt;/code&gt; URLs.&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file at the top-level of the repository, with the following contents:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   image: node:latest
    pages:
      stage: deploy
      script:
        - npm install
        - npm run build
      artifacts:
        paths:
          - public
      only:
        - master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This says, when there's a new commit on master (last line), use the &lt;code&gt;node:latest&lt;/code&gt; docker image to check-out the code and run &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm run build&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;Your site will now be live - find the URL under GitLab &lt;code&gt;Settings&lt;/code&gt; &amp;gt; &lt;code&gt;Pages&lt;/code&gt;. Check the &lt;code&gt;CI/CD&lt;/code&gt; status page of your GitLab repository to see the status of the build process if you ever have issues with that. Unlike GitHub, the site is not public by default. To make it publicly accessible, go into GitLab &lt;code&gt;Settings&lt;/code&gt; &amp;gt; &lt;code&gt;General&lt;/code&gt; &amp;gt; &lt;code&gt;Visibility, project features, permissions&lt;/code&gt; and set &lt;code&gt;Pages&lt;/code&gt; to &lt;code&gt;Everyone&lt;/code&gt;. Your site is now available!&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://dev.to/bryce/how-to-automatically-deploy-to-gitlab-pages-w-ci-4iko"&gt;https://dev.to/bryce/how-to-automatically-deploy-to-gitlab-pages-w-ci-4iko&lt;/a&gt; for help on this process.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://gavinr.com/svelte-publish-gitlab-pages/"&gt;Originally posted on gavinr.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gitlab</category>
      <category>svelte</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
