<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Jonathan Eckman]]></title><description><![CDATA[The portfolio and personal blog of Jonathan Eckman.]]></description><link>https://jonathaneckman.io</link><generator>RSS for Node</generator><lastBuildDate>Sat, 21 Dec 2019 18:40:05 GMT</lastBuildDate><item><title><![CDATA[Bring DevOps to your O365 Development Team]]></title><description><![CDATA[In my latest blog post I describe how you can enable successful DevOps practices by taking advantage of advancements made in the SharePoint…]]></description><link>https://jonathaneckman.io/advancements-in-sharepoint-framework-and-devops-for-office-365/</link><guid isPermaLink="false">https://jonathaneckman.io/advancements-in-sharepoint-framework-and-devops-for-office-365/</guid><pubDate>Fri, 20 Dec 2019 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;In my latest blog post I describe how you can enable successful DevOps practices by taking advantage of advancements made in the SharePoint Framework and O365. Manage your O365 configuration as code, add test automation to your SharePoint Framework solution, and deploy it all to test, staging, and production environments with a Continuous Integration and Delivery (CI/CD) pipeline. Check it out &lt;a href=&quot;https://www.appliedis.com/advancements-in-sharepoint-framework-and-devops-for-office-365/&quot;&gt;on the Applied Information Science’s website&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Failed to decode %PUBLIC_PATH%]]></title><description><![CDATA[Problem I’ve been dabbling in React and recently discovered the amazing   tool. Here’s a unique problem I ran into when using it, and my…]]></description><link>https://jonathaneckman.io/failed-to-decode-public-path/</link><guid isPermaLink="false">https://jonathaneckman.io/failed-to-decode-public-path/</guid><pubDate>Tue, 06 Feb 2018 07:03:47 GMT</pubDate><content:encoded>&lt;h2&gt;Problem&lt;/h2&gt;
&lt;p&gt;I’ve been dabbling in React and recently discovered the amazing &lt;a href=&quot;https://github.com/facebook/create-react-app&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;create-react-app&lt;/code&gt;&lt;/a&gt; tool. Here’s a unique problem I ran into when using it, and my solution.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In &lt;a href=&quot;https://www.visualstudio.com/team-services/&quot;&gt;Visual Studio Team Services&lt;/a&gt; (VSTS), I created a new project called “My Project”. The space is important. &lt;/li&gt;
&lt;li&gt;VSTS will create a default git repository using the same name as the project.&lt;/li&gt;
&lt;li&gt;I pushed the React app to source control.&lt;/li&gt;
&lt;li&gt;The repo URL is &lt;code class=&quot;language-text&quot;&gt;https://myaccount.visualstudio.com/_git/My%20App&lt;/code&gt; (notice the encoded space), so cloning it will put it into a &lt;code class=&quot;language-text&quot;&gt;My%20App&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;Run &lt;code class=&quot;language-text&quot;&gt;npm start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In terminal, you’ll see the error:
&lt;code class=&quot;language-text&quot;&gt;&amp;quot;Failed to decode param &amp;#39;/%PUBLIC_URL%/favicon.ico&amp;#39;&lt;/code&gt;
and 400 bad request errors in the developer console.  &lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;p&gt;The solution is simple, but not immediatley obvious. The &lt;code class=&quot;language-text&quot;&gt;%&lt;/code&gt; in the file path was breaking the build task searching for the &lt;code class=&quot;language-text&quot;&gt;%PUBLIC_URL%&lt;/code&gt; tokens in &lt;code class=&quot;language-text&quot;&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My fix was to rename the project folder. I also renamed the repo to spare the rest of the devs on my team. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Handling .NET Core Web API Exceptions with an Aurelia Interceptor]]></title><description><![CDATA[Problem: Failed to Fetch In my teams Aurelia app, I wanted an easy way to handle all HTTP response errors coming from our .NET Core Web API…]]></description><link>https://jonathaneckman.io/handling-net-core-web-api-exceptions-with-an-aurelia-fetch-interceptor/</link><guid isPermaLink="false">https://jonathaneckman.io/handling-net-core-web-api-exceptions-with-an-aurelia-fetch-interceptor/</guid><pubDate>Sun, 14 Jan 2018 07:03:47 GMT</pubDate><content:encoded>&lt;h2&gt;Problem: Failed to Fetch&lt;/h2&gt;
&lt;p&gt;In my teams Aurelia app, I wanted an easy way to handle all HTTP response errors coming from our .NET Core Web API. This is easily done with the &lt;code class=&quot;language-text&quot;&gt;requestError&lt;/code&gt; method on Aurelia’s &lt;a href=&quot;http://aurelia.io/docs/api/fetch-client/interface/Interceptor&quot;&gt;Interceptor&lt;/a&gt; interface. This method acts as a Promise reject handler so when working properly, I’d expect to recieve the failed Response as an argument. Instead, a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError&quot;&gt;TypeError&lt;/a&gt; was thrown with the message “Failed to fetch”. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f00df191b31268b93d378a5df643335a/2b215/failed-to-fetch.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block;  max-width: 675px; margin-left: auto; margin-right: auto;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 56.148148148148145%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABXElEQVQoz4WS626EIBCFff+X6t8+QJt0d21tu+5FkYuAFxQ9HaybuOlqJ/kkIBxmhhMJLiClBGMFrLG4njKwyxX58QiWpshobOoafdfBEW3bwjm3SmQSCcUMDrGAKCw606MREk2eYdB6wlcVvGvhhwEdiYYYx/EhkWUala6hVIum6TD6Ab736L3HGA7OhBhIsF8IPopIMQmZcWhh6HZ/93N5800wsJlh+Cilpj6GHqxtvgl67+/2/MlwoMXG1pCpRG3bTcEg9tvDcT3Dm7InsaH12IrpELYjctQ3LjQKYemVc1zSd3CyUlhTpUHB5YyCLkuU7IKm5LCCoVYFKskmLNF1PSJWjojjCs9PBV5eGXa7BIeE4e2DY/9pEH8Z7BOO77NFzjvyqwEje+XzOM2JMM+lv5VMpZgWOjc4nSVKpcnkJYwxqCpHN7uFef4puQ+emwlnZlc86N+6VZb8APfAWmecyfCnAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;TypeError: Failed to fetch&quot;
        title=&quot;&quot;
        src=&quot;/static/f00df191b31268b93d378a5df643335a/2b215/failed-to-fetch.png&quot;
        srcset=&quot;/static/f00df191b31268b93d378a5df643335a/860d3/failed-to-fetch.png 293w,
/static/f00df191b31268b93d378a5df643335a/946db/failed-to-fetch.png 585w,
/static/f00df191b31268b93d378a5df643335a/2b215/failed-to-fetch.png 675w&quot;
        sizes=&quot;(max-width: 675px) 100vw, 675px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Aurelia Interceptor&lt;/h2&gt;
&lt;p&gt;The problem was not with Aurelia nor the underlying fetch library. Both were doing their jobs given the configuration I provided. The final &lt;code class=&quot;language-text&quot;&gt;responseError&lt;/code&gt; code simply receives the failed response, does something with the payload, then rejects the promise. The &lt;code class=&quot;language-text&quot;&gt;ServerError&lt;/code&gt; interface shown in the example below provides typings for our custom error payload. You will see where this object is created in a moment.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;responseError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; any&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Promise&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Response&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ServerError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        
            &lt;span class=&quot;token comment&quot;&gt;// Do something with the error here.&lt;/span&gt;
            
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reject&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Response&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverError&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;.NET Core Exception Handling Middleware&lt;/h2&gt;
&lt;p&gt;I already knew something was failing in our API code. On the client, I was receiving a 500 error with a message indicating a CORS problem. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ’&lt;a href=&quot;https://localhost:44303&quot;&gt;https://localhost:44303&lt;/a&gt;’ is therefore not allowed access. The response had HTTP status code 500. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There was a problem, but the CORS error is misleading. Checking the server logs, I found that the real problem was an unhandled SQL exception. In &lt;code class=&quot;language-text&quot;&gt;Startup.cs&lt;/code&gt;, my API was configured to handle errors with the &lt;a href=&quot;https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling#the-developer-exception-page&quot;&gt;UseDeveloperExceptionPage&lt;/a&gt; middleware:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler(&amp;quot;/Home/Error&amp;quot;);
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I suspected the root cause had to do with this middleware. Searching around, I found a &lt;a href=&quot;https://github.com/aspnet/Diagnostics/issues/247&quot;&gt;discussion on GitHub&lt;/a&gt; that proved it. This middleware strips everything it can from the response headers which causes the CORS and “Failed to fetch” errors. &lt;/p&gt;
&lt;p&gt;My solution was to add my own error handling middleware to the API called &lt;code class=&quot;language-text&quot;&gt;ErrorHandlingMiddleware&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate next;

    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        var code = HttpStatusCode.InternalServerError;

        var result = JsonConvert.SerializeObject(new { 
             error = &amp;quot;An internal server error has occurred.&amp;quot; 
        });
        context.Response.ContentType = &amp;quot;application/json&amp;quot;;
        context.Response.StatusCode = (int)code;
        return context.Response.WriteAsync(result);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then registered that middleware in the &lt;code class=&quot;language-text&quot;&gt;Configure&lt;/code&gt; method of &lt;code class=&quot;language-text&quot;&gt;Startup.cs&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;app.UseMiddleware&amp;lt;ErrorHandlingMiddleware&amp;gt;();
app.UseStaticFiles();
app.UseMvc();&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After this change, &lt;code class=&quot;language-text&quot;&gt;responseError&lt;/code&gt; received the response with everything I needed to know how to handle it, such as a status code and error message. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d3132b65a76e5bb21405dccc3fe237de/64252/failed-to-fetch-resolved.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block;  max-width: 468px; margin-left: auto; margin-right: auto;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 64.74358974358975%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACIUlEQVQ4y3VTy47cIBD0/39OTrlEyjWHHCJFyo7tyXhm/AS/wTYG40qD11G02W2pBWqgurq7CKqqAmMMnHMwTmvDIScJXnO4Mykl1nWFUupDX5bF3zHGIBBCHAG9Yh4m1FeGWcwok9InknKC3Xfs5Nbad11r7X3bNgRu48xsBnrRUM0M2Un0txFTKdHUI9J88Nkd6Hvmzhyws8BRdcgO0IKYUFB0Au1zBCskRiF92WpR/p6z/ZXxmeDfZJ6h6wNnHB1r0XCJRa4YM4E6JeByQdtr6qv5D+wEcaR4XaNrm4Ohs6Wd0EYc+YVjlgrDfcCYC7BshnYM8LE5hmelQfg8aqd06IXF/TcxHAgwGyFZB1UxWHpATcLuemU0LD12e++uXVThSSxoh2MoJ4N11RhagblbsDQdpqJAm+dokwSKZGXaFitJTFOJmkrUJC/V914JDiUw+kDe7DEYNwBNoNZYbNpSzFL/JszEwn5UMrH8O2WlDkCzGmzLRmDGXzg4v+ncm4Hsu/WxjUr3CthfGfoDYrILEui8eqnckgeiMEQUhYidx5Hfh1GEMI4RkV/CCBm1Y6TPcVogZw0xrSh5j4JEXDUEdvmJ5Nc35HmFvGzwTCvcHzlKGlJTZmDJBfUzRnF7QXUP0aRXCJ5CNxmCJNd4sA3ff/T4/KnE1y8NXmKG+73CLVuRFAbXVCF6zH6fkS4z+jl5IfB49nikPf2k0a85xf8AeWnqdEmbSfwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Response object&quot;
        title=&quot;&quot;
        src=&quot;/static/d3132b65a76e5bb21405dccc3fe237de/64252/failed-to-fetch-resolved.png&quot;
        srcset=&quot;/static/d3132b65a76e5bb21405dccc3fe237de/61bc6/failed-to-fetch-resolved.png 293w,
/static/d3132b65a76e5bb21405dccc3fe237de/64252/failed-to-fetch-resolved.png 468w&quot;
        sizes=&quot;(max-width: 468px) 100vw, 468px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Your First Open Source Contribution]]></title><description><![CDATA[I recently had the opportunity to contribute to the Aurelia framework. Aside from a handful of small changes made using GitHub’s in-browser…]]></description><link>https://jonathaneckman.io/contributing-to-aurelia/</link><guid isPermaLink="false">https://jonathaneckman.io/contributing-to-aurelia/</guid><pubDate>Sun, 07 Jan 2018 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;I recently had the opportunity to contribute to the Aurelia framework. Aside from a handful of small changes made using GitHub’s in-browser code editor, this was my first experience contributing to an open source project. I’m hoping that documenting what I’ve learned will help those who have wanted to contribute to an open source project but aren’t sure where to start or how the pieces fit together.&lt;/p&gt;
&lt;h2&gt;Planning&lt;/h2&gt;
&lt;p&gt;Before doing anything, look through the active issues to see if your idea is already being tracked. If not, create a new issue describing the bug you’d like to fix or the feature you wish to add. Discuss the proposed changes with someone on the projects core team. In my case, I seeked to start the conversation on the GitHub issue, in &lt;a href=&quot;https://gitter.im/aurelia/Discuss&quot;&gt;Aurelia’s Gitter&lt;/a&gt;, or in &lt;a href=&quot;https://discourse.aurelia.io/&quot;&gt;Aurleia’s Discourse&lt;/a&gt;. I found that the core team members were &lt;a href=&quot;https://github.com/orgs/aurelia/people&quot;&gt;listed in GitHub&lt;/a&gt; but most are already easy to spot by the Aurelia logo in their profile picture, such as in Rob Eisenberg’s picture shown below.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/cee3ff11154d581b7496d89e58f3784c/50e52/rob.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block;  max-width: 460px; margin-left: auto; margin-right: auto;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAAEw0lEQVQ4yx1SaVATBxjdht1kN7vZ7JVrQxJESEIaKxAUIYJggJBDIFEEhHgh4IgS0HIJRBQMXoBWitTaWkZhdKrVOtYKttOORW0diuNUR7G1atVWPGih4oygTVdn3rw/33vz5n3fB3wu91aI0n3YAh/m5LBJ5GgQ2prEjn1q925FViNu24RbOTQS1kbS6iOt9bTVx9iqJKkn1UXAWqkDgAAQ4fMQEBRCPBgSE1hClGqp3RhtYHkIHxYhkFDACYJgPk8AAgIQFEAAHyhlEoENrIsHgVKEkCEEx+GUdEFkhE2vtUwPj1SqgjFCR8tYlJIJuamYY07GCkkEhmuYFKBclQXyg2QowQjFoRSzwRXb5bVl6JRzlaxWRKdFhNmNWqWIkqKERCjmmIMcJQWIoIq2AGUaFySAFBjFIOQ8vXLg48rA7/3Xv9h1oi73SO2S1iJnVVb83NBQOULJMOKtmZSjxBszZQHWhLghCFRgDMknnNHqB991BJ7ffv3n4OTl3pGzHYfeX9yUl+iK0sth8m0mIRWK5ULODFeTFqBkmlsAgUqMpgVE6rvy+/07A3/f+G9k6OWPR+70NO1Ybl3vnJ0fFzFTItNSEgnXGSOUKI2gwmrCAqyavpAPBwXjtBSlYtTMLz2VE4OHLuxY9eizymNep8ekLbPMKEw2VifOSA/XEEJCRdAaQiLCRbVECrA8bKGAH8TitIiHVLgtLy7uH7vc3VtsvXeitbfSU2OLO1Dq8tqjSmL1UaxcjOIsTqpwLhmpEacAnvCFApDHYjQFYYkG/XhfR+DxT1M3+wL3fviqsaTNbT7nW1aTFbNklj4YJyVva3OXg4XwG3O+dhHypjOjFkuId4QfVBcHng897u+aunLsbF1+udnYUWDekm2KUslZEaWhJCGEdBq3cjFaS6YBubpFMARyySxGBYtoBSLu6978amj/+ED3nc6Nu+xzWnLjN2dHh9Lcn5AhDE0yWDDFKMWMn8oAciJycD5fhUvUOKPAaCkfL3UkT145MDl8ery/67x/pT/PnGvSyBGSRAkNxdbI7H3Uul/JTSNEM5BtyKVgmLuzBCEsYeFlyeZ1sTEH1i4K3Dp690v/yfpsb5JOR9AIjCaihgtBGyah9hdI65hg2yi+DVhszBOBIA0Ty2ZH7XJZfelJ1fPiM3WGx9dO/9Zb2ZyqXm0Kj5QrzKj+RkR74ODNf1aceqrfN6rtfCbaBtj1OaEU3mBP7syxtbnTSmJNGTpdglThL1sZeHL+ZmfhRqvJEqo9F1I3Wvz1xPDIxP6hqaFHr64/eSZpAxZHew4V2g6vcO/MTG13pxXHRPvtSc2O+Ukse2pf/evhM+YwpZtJGjZ03q3rG+u5OnV/bPL26L/FZ57B24G9BXWDDZ6P8jK2OpJbHPPXJ8QdXubq9mTaw/Q+Z2pXeaFMIP7QWHHFsPfBnoFAIDBx6Y+Xgw9Hk3ue8ncAjRne40WWgwXWupSYFkf8xpRZn+Rbu5emNzsTiubMjFEw0zDmqMl/MbLjam7vw90Dd5cfH//m9pP8E3/xtwO1GS0NjtUtmd5665qtjtJm65qOzIquzPJPXesrTAVVszyVxoKTc/Z8G9f5/Xvtl/StP+vark1vu6Vpv8e2/w+qBn7nsJ9BsgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Rob Eisenberg&apos;s GitHub Picture&quot;
        title=&quot;&quot;
        src=&quot;/static/cee3ff11154d581b7496d89e58f3784c/50e52/rob.png&quot;
        srcset=&quot;/static/cee3ff11154d581b7496d89e58f3784c/c81cd/rob.png 293w,
/static/cee3ff11154d581b7496d89e58f3784c/50e52/rob.png 460w&quot;
        sizes=&quot;(max-width: 460px) 100vw, 460px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Read the contribution guidelines. Aurelia’s &lt;a href=&quot;https://github.com/DurandalProject/about/blob/master/CONTRIBUTING.md#feature&quot;&gt;contribution guidelines&lt;/a&gt; state that small changes can be crafted and submitted, but large changes should be coordinated with the team. I chose to create an issue even though my change was small. In my experience, lack of coordination often leads to wasted time so I wanted the team to be aware of my idea before I started working on it. I’ve also gotten into the habit of associating my changes with a work item. By creating an issue now, I’ll have it ready to reference when I submit a pull request.&lt;/p&gt;
&lt;h2&gt;Project Setup&lt;/h2&gt;
&lt;p&gt;Create an isolated copy of the repository by &lt;a href=&quot;https://help.github.com/articles/fork-a-repo/&quot;&gt;forking&lt;/a&gt; it. This is as simple as clicking the fork button in the top right corner of the repository you wish to contribute to.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e6c9426ea42ce1d8384152d422505980/c38f1/aurelia-binding-repo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block;  max-width: 994px; margin-left: auto; margin-right: auto;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 3.8229376257545273%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAYAAADeko4lAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAPUlEQVQI12O4+/zb/6/ff///9fvP/5+/IDQuDJIH4d9//v5/+vzl/4dPnv3/9PnL/w8fP/1/9OzF/89AGgBRH01mWffVVQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;GitHub Fork Button&quot;
        title=&quot;&quot;
        src=&quot;/static/e6c9426ea42ce1d8384152d422505980/c38f1/aurelia-binding-repo.png&quot;
        srcset=&quot;/static/e6c9426ea42ce1d8384152d422505980/b3c2c/aurelia-binding-repo.png 293w,
/static/e6c9426ea42ce1d8384152d422505980/e1423/aurelia-binding-repo.png 585w,
/static/e6c9426ea42ce1d8384152d422505980/c38f1/aurelia-binding-repo.png 994w&quot;
        sizes=&quot;(max-width: 994px) 100vw, 994px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://help.github.com/articles/cloning-a-repository/&quot;&gt;Clone&lt;/a&gt; the forked repository to your local workstation and open it in your IDE or text editor of choice. I use &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;. It’s good practice to work in topic branches instead of directly in master. Create and checkout a topic branch with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git checkout -b my-new-feature&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From here, each project will be different. In my case, all of Aurelia projects contain a &lt;code class=&quot;language-text&quot;&gt;readme.md&lt;/code&gt; file that describe how to set up the project. Usually this includes downloading dependencies, running a build script, and executing tests. Complete all steps to ensure the project builds and is working as expected. &lt;/p&gt;
&lt;h2&gt;Develop and Test&lt;/h2&gt;
&lt;p&gt;Instead of blindly modifying an API and hoping for the best, I need to see my changes in the wild. To do this, I needed a front end application to test with. I chose to generate a new one using the &lt;a href=&quot;http://aurelia.io/docs/build-systems/aurelia-cli#creating-a-new-aurelia-project&quot;&gt;Aurelia CLI&lt;/a&gt; but you may use an existing app if you have one handy. Using the CLI is as simple as running the following from your destination directory:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm install aurelia-cli -g
au new --here&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next I created a link between the cloned Aurelia source code and my front end app. Think of this as referencing a package on your workstation instead of the one downloaded to &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt;. Navigate to the root of the Aurelia project and run: &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm link&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Navigate to the root of the front end app and run the command below. In my case, I was testing a change to &lt;code class=&quot;language-text&quot;&gt;aurelia-binding&lt;/code&gt;. Change this to whatever module you’re working with. &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm link aurelia-binding&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make your changes to the Aurelia library, build the project, then jump over to your front end app to test the change. Repeat until perfect. &lt;/p&gt;
&lt;p&gt;To ensure you didn’t introduce a regression bug, run the same test script you did during project setup. This usually looks something like &lt;code class=&quot;language-text&quot;&gt;karma start&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;jest&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Submit&lt;/h2&gt;
&lt;p&gt;As you &lt;a href=&quot;https://git-scm.com/docs/git-commit&quot;&gt;commit&lt;/a&gt; changes, make sure to follow the projects commit message guidelines. As an example, you can find Aurelia’s guidelines &lt;a href=&quot;https://github.com/DurandalProject/about/blob/master/CONTRIBUTING.md#commit&quot;&gt;here&lt;/a&gt;. For examples on how to craft the perfect commit message, refer to the commit history of your projects repository. Push your changes to the server then create a &lt;a href=&quot;https://help.github.com/articles/about-pull-requests/&quot;&gt;pull request&lt;/a&gt; by clicking the big green “new pull request” button on the destination repository.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9a4cc960e1d550c0fb45a66573745c13/1bf3b/aurelia-binding-pr.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block;  max-width: 998px; margin-left: auto; margin-right: auto;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 15.030060120240481%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAp0lEQVQI1x2OSxLCIBBEc2BP4cJtFh7GI7jzEi6smMifgQFCO0BVV3fBzKMX5Qi7SXjvBBsycnSIRiF5g5wZScSlTs9cUWrDth84lIYPEd+fAiWGNn76UmSYmVFERAnRW/gBDAImkiUSYJGcJrgKsJ0drZ2ooiZ37tig1Qa7f7AoY6Gtn785F6TBGOzTR5vRMkaSNzfzOL130TkzB4/1ecfldcP6uOIPEe3lijkl59QAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;GitHub Pull Request Button&quot;
        title=&quot;&quot;
        src=&quot;/static/9a4cc960e1d550c0fb45a66573745c13/1bf3b/aurelia-binding-pr.png&quot;
        srcset=&quot;/static/9a4cc960e1d550c0fb45a66573745c13/bc87a/aurelia-binding-pr.png 293w,
/static/9a4cc960e1d550c0fb45a66573745c13/96d95/aurelia-binding-pr.png 585w,
/static/9a4cc960e1d550c0fb45a66573745c13/1bf3b/aurelia-binding-pr.png 998w&quot;
        sizes=&quot;(max-width: 998px) 100vw, 998px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Include the id of the issue you are working from to associate it with your pull request. Provide a helpful description so the code reviewer understands your changes then click submit. &lt;/p&gt;
&lt;h2&gt;Cleanup&lt;/h2&gt;
&lt;p&gt;Optionally, you may want to remove the symlink we created with &lt;code class=&quot;language-text&quot;&gt;npm link&lt;/code&gt; so that your front end references the library it downloaded from the npm registry instead of the local copy. To do this, simply run the following from the root of your front end app.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm unlink aurelia-binding&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And from the root of the Aurelia project:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm unlink&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item></channel></rss>