<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mifty is Bored</title>
	<atom:link href="https://miftyisbored.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://miftyisbored.com/</link>
	<description>An Awesome page of Awesomeness</description>
	<lastBuildDate>Mon, 25 Dec 2023 01:57:09 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>PayPal Standard Checkout Integration with Laravel 10</title>
		<link>https://miftyisbored.com/paypal-standard-checkout-integration-with-laravel-10/</link>
					<comments>https://miftyisbored.com/paypal-standard-checkout-integration-with-laravel-10/#respond</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Sun, 24 Dec 2023 06:40:21 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorials & Samples]]></category>
		<category><![CDATA[PayPal]]></category>
		<guid isPermaLink="false">https://miftyisbored.com/?p=2704</guid>

					<description><![CDATA[<p>I recently had to upgrade the PayPal integration for my site NatureSoundSpa.com that was using PayPal’s Digital Payments API to instantly deliver digital goods. Since the Digital Payments API has been deprecated, I needed to use the new PayPal REST APIs along with the PayPal JavaScript SDK. I was previously using a CakePHP implementation with [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/paypal-standard-checkout-integration-with-laravel-10/">PayPal Standard Checkout Integration with Laravel 10</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I recently had to upgrade the PayPal integration for my site <a href="https://naturesoundspa.com" rel="noopener" target="_blank">NatureSoundSpa.com</a> that was using PayPal’s Digital Payments API to instantly deliver digital goods. Since the Digital Payments API has been deprecated, I needed to use the new <a href="https://developer.paypal.com/docs/api/orders/v2" rel="noopener" target="_blank">PayPal REST APIs</a> along with the <a href="https://developer.paypal.com/sdk/js/reference/" rel="noopener" target="_blank">PayPal JavaScript SDK</a>. I was previously using a CakePHP implementation with PayPal’s express checkout for Digital Goods and decided to switch to a Laravel implementation using Laravel 10. If you are not aware of the JavaScript SDK, this PayPal guide does a great job of explaining the JavaScript SDK integration. Basically, the PayPal payment buttons use JavaScript callbacks instead of redirecting the payer to a return URL. Below is a diagram of the flow and the 4 steps as described by PayPal</p>
<p>If you are not aware of the JavaScript SDK, <a href="https://developer.paypal.com/docs/checkout/standard/upgrade-integration/" rel="noopener" target="_blank">this PayPal guide</a> does a great job of explaining the JavaScript SDK integration. Basically, the PayPal payment buttons use JavaScript callbacks instead of redirecting the payer to a return URL. Below is a diagram of the flow and the 4 steps as described by PayPal. </p>
<p><a href="http://miftyisbored.com/wp-content/uploads/paypal-checkout-flow.jpg"><img fetchpriority="high" decoding="async" src="http://miftyisbored.com/wp-content/uploads/paypal-checkout-flow.jpg" alt="" width="933" height="350" class="alignnone size-full wp-image-2705" srcset="https://miftyisbored.com/wp-content/uploads/paypal-checkout-flow.jpg 933w, https://miftyisbored.com/wp-content/uploads/paypal-checkout-flow-300x113.jpg 300w, https://miftyisbored.com/wp-content/uploads/paypal-checkout-flow-480x180.jpg 480w" sizes="(max-width: 933px) 100vw, 933px" /></a></p>
<p>Your payer takes the following actions:</p>
<ol>
<li>Clicks a payment button.</li>
<li>Logs into PayPal.</li>
<li>Approves the transaction on PayPal.</li>
<li>Returns to your site where you show the payer a confirmation page.</li>
</ol>
<p>Since I had only integrated with PayPal Express checkout, I decided to switch to the PayPal REST APIs and created this tutorial based on my learning.  PayPal does a great job of introducing you to the JavaScript SDK with the <a href="https://developer.paypal.com/integration-builder/" rel="noopener" target="_blank">PayPal Integration Builder</a>. The example from the integration builder from PayPal is a great starting point but it is not complete and is only implemented in NodeJS. So I completed a proof of concept using Laravel 10 and created this tutorial from that PoC. The application in this tutorial uses PayPal’s Standard Checkout to purchase a digital item and stores the payment information in a payments database. Once the purchase is completed, the digital item (<em>In this case, it is a free image</em>) is made available on the same page. You can see  Images of the integration below and you can do a <a href="https://miftyisbored.com/wp-tutorials/paypal-javascript-SDK-laravel/" rel="noopener" target="_blank">live test using the PayPal Sandbox here</a>.</p>
<p><a href="https://miftyisbored.com/wp-tutorials/paypal-javascript-SDK-laravel/" rel="noopener" target="_blank"><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/pypal-tutorial-steps.png" alt="" width="1427" height="479" class="alignnone size-full wp-image-2714" srcset="https://miftyisbored.com/wp-content/uploads/pypal-tutorial-steps.png 1427w, https://miftyisbored.com/wp-content/uploads/pypal-tutorial-steps-300x101.png 300w, https://miftyisbored.com/wp-content/uploads/pypal-tutorial-steps-1024x344.png 1024w, https://miftyisbored.com/wp-content/uploads/pypal-tutorial-steps-480x161.png 480w" sizes="(max-width: 1427px) 100vw, 1427px" /></a></p>
<p>You can use the following test User for testing email: <em>sb-kad4928343310@personal.example.com</em><br />
password: <em>wDCx)28</em> . So let’s start the tutorial</p>
<h2>Step 1: Create a PayPal account</h2>
<p>You can go to <a href="https://developer.paypal.com" rel="noopener" target="_blank">https://developer.paypal.com</a> to create a developer account. You will need to create a new app so that you can get a clientID and secret for the new ID. Click on the “Create App” button in order to create an app. Once you&#8217;ve created the app, you will be able to get sandbox and production values for your app which will look something similar to the image below</p>
<p><a href="http://miftyisbored.com/wp-content/uploads/paypal-credentials-screen.png"><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/paypal-credentials-screen.png" alt="" width="1527" height="534" class="alignnone size-full wp-image-2730" srcset="https://miftyisbored.com/wp-content/uploads/paypal-credentials-screen.png 1527w, https://miftyisbored.com/wp-content/uploads/paypal-credentials-screen-300x105.png 300w, https://miftyisbored.com/wp-content/uploads/paypal-credentials-screen-1024x358.png 1024w, https://miftyisbored.com/wp-content/uploads/paypal-credentials-screen-480x168.png 480w, https://miftyisbored.com/wp-content/uploads/paypal-credentials-screen-1430x500.png 1430w" sizes="(max-width: 1527px) 100vw, 1527px" /></a></p>
<p>Go ahead and create production and sandbox credentials since we will need these later when we setup our laravel app</p>
<h2>Step 2: Install a new Laravel instance</h2>
<p>Let&#8217;s start with a fresh Laravel instance. I use composer to install laravel for a new project that I called paypal-app. Here is the composer command</p>
<pre class="brush: php; title: ; notranslate">composer create-project laravel/laravel paypal-app</pre>
<h2>Step 3:Create the Laravel routes</h2>
<p>Let’s go ahead and define the routes for our application. Since it is a single-page app where all the entire checkout process happens on the same page, we will be mostly interacting with POST commands that will be called via AJAX calls. We will need to define 3 routes as follows:</p>
<ol>
<li>The checkout route where the PayPal checkout button will be displayed</li>
<li>The purchase route where we will initiate the purchase (done via POST)</li>
<li>The capture order route where we will confirm the payment and store the payment in our payments database (done via POST)</li>
</ol>
<p>They will interact with a Checkout controller that we will be creating soon but we can already define it inside our routes file. The 3 routes look like so inside the web routes file. </p>
<pre class="brush: php; title: ; notranslate">
Route::get(  '/',   &#x5B;CheckoutController::class, 'checkout'])-&gt;name('checkout');
Route::post(  '/order',   &#x5B;CheckoutController::class, 'createOrder'])-&gt;name('order');
Route::post(  '/capture',   &#x5B;CheckoutController::class, 'captureOrder'])-&gt;name('capture');
</pre>
<p>And here is the full contents of the web.php file:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CheckoutController;


/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the &quot;web&quot; middleware group. Make something great!
|
*/
Route::get(  '/',   &#x5B;CheckoutController::class, 'checkout'])-&gt;name('checkout');
Route::post(  '/order',   &#x5B;CheckoutController::class, 'createOrder'])-&gt;name('order');
Route::post(  '/capture',   &#x5B;CheckoutController::class, 'captureOrder'])-&gt;name('capture');
</pre>
<h2>Step 4: Create a PayPal configuration file</h2>
<p>Next, we need to create a custom configuration file to store the PayPal configuration information. Unfortunately, there is no artisan command to create a custom config file so you will have to manually create a file called paypal.php inside the config/ folder. This custom PayPal config file will store your API credentials along with a sample item that we will use for this tutorial. It also contains the sandbox and production endpoints used by PayPal. The sample item that we will be allowing users to purchase is this image of Krusty the Clown’s Frosty Krusty Flakes. </p>
<p><a href="http://miftyisbored.com/wp-content/uploads/step-3.png"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/step-3.png" alt="" width="1228" height="1237" class="alignnone size-full wp-image-2710" srcset="https://miftyisbored.com/wp-content/uploads/step-3.png 1228w, https://miftyisbored.com/wp-content/uploads/step-3-298x300.png 298w, https://miftyisbored.com/wp-content/uploads/step-3-1017x1024.png 1017w, https://miftyisbored.com/wp-content/uploads/step-3-150x150.png 150w, https://miftyisbored.com/wp-content/uploads/step-3-480x484.png 480w, https://miftyisbored.com/wp-content/uploads/step-3-496x500.png 496w" sizes="auto, (max-width: 1228px) 100vw, 1228px" /></a></p>
<p>Below is the contents of the PayPal config file. <strong>Don&#8217;t forget to change the PayPal client ID and secret to your own client and secret values</strong>.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

return &#x5B;

    /*
    |--------------------------------------------------------------------------
    | sandbox enabled
    |--------------------------------------------------------------------------
    |
    | This option enables/disables the paypal sandbox. This value can be set 
    | through the PAYPAL_SANDBOX_ENABLED environment variable
    |
    */
    'sandbox_enabled' =&gt; env('PAYPAL_SANDBOX_ENABLED', true),

    /*
    |--------------------------------------------------------------------------
    | Sandbox Settings
    |--------------------------------------------------------------------------
    |
    | PayPal sandbox settings for the client, secret and endpoints
    |
    */
    'client_id_sandbox' =&gt; '&#x5B;YOUR-PAYPAL-CLIENT-ID-FOR-SANDBOX]',
    'client_secret_sandbox' =&gt; '&#x5B;YOUR-PAYPAL-SECRET-FOR-SANDBOX]',
    'auth_endpoint_sandbox' =&gt; 'https://api-m.sandbox.paypal.com/v1/oauth2/token',
    'checkout_endpoint_sandbox' =&gt; 'https://api-m.sandbox.paypal.com/v2/checkout/orders',

    /*
    |--------------------------------------------------------------------------
    | Production Settings
    |--------------------------------------------------------------------------
    |
    | PayPal production settings for the client, secret and endpoints
    |
    */
    'client_id_production' =&gt; '&#x5B;YOUR-PAYPAL-CLIENT-ID-FOR-PRODUCTION]',
    'client_secret_production' =&gt; '&#x5B;YOUR-PAYPAL-SECRET-FOR-PRODUCTION]',
    'auth_endpoint_production' =&gt; 'https://api-m.paypal.com/v1/oauth2/token',
    'checkout_endpoint_production' =&gt; 'https://api-m.paypal.com/v2/checkout/orders',

    /*
    |--------------------------------------------------------------------------
    | Sample Prodct Settings
    |--------------------------------------------------------------------------
    | This is the sample product that we will use for the Proof of Concept
    | This should actually be stored as a database of items but I'm cheating for
    | the PoC. The content that we will make available to the purchaser is an image
    | of Krusty the Clown's Frosty Krusty Flakes from the Simpsons
    | note: you can't use asset with artisan so I need to check if running in console
    | see: https://stackoverflow.com/questions/45152585/laravel-php-artisan-produces-error
    |
    */
    'sample_item_number' =&gt; 'SIMPSONS-0001',
    'sample_item_name' =&gt; 'Frosty Krusty Flakes',
    'sample_item_description' =&gt; 'Frosty Krusty Flakes from Krusty the Clown - The Breakfast of Underachievers',
    'sample_item_price' =&gt; 1.25,
    'sample_item_currency' =&gt; 'USD',
    'sample_item_content' =&gt; app()-&gt;runningInConsole() ? '' : &quot;&lt;img src='&quot; . asset('/images/Frosty_Krusty_Flakes_comic.png') . &quot;' width='100%' /&gt;&quot;,

];
</pre>
<p><P>Notice that the sample item is added directly inside the configuration file. That is because this is a quick Proof of Concept. You should store your products in a database and create a model to access them.</P></p>
<h2>Step 5: create a model and migration to store the payments</h2>
<p>Since the primary purpose of our app is to process and store PayPal payments, we will create a Payment model along with a Payment migration. The Payment is where all the payment information will be stored. Here is the artisan command to create both</p>
<pre class="brush: php; title: ; notranslate">php artisan make:model Payment -m</pre>
<p>We now have a Payment model as well as a payment migration. The payment model will contain all the payment data returned from PayPal once a payment is completed. For now, there is nothing to change in the file Models/Payment.php Here is the full content of the file</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Payment extends Model
{
    use HasFactory;
}
</pre>
<p>The payment migration file will be located inside database/migrations. The migration file will contain all the PayPal fields that we want to store in our database whenever a payment is completed. It will have all payment-related data that we collect from PayPal such as the payer information, the transaction details and the purchased item details. Here are the contents of the payment migration file</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('payments', function (Blueprint $table) {

            $table-&gt;id();

            $table-&gt;string('order_id');
            $table-&gt;string('order_status');
            $table-&gt;string('payer_id');
            $table-&gt;string('payer_name');
            $table-&gt;string('payer_email');
            $table-&gt;string('payer_country');
            $table-&gt;float('paid_amount', 10, 2);
            $table-&gt;string('paid_amount_currency');
            $table-&gt;string('transaction_id');
            $table-&gt;string('transaction_status');
            $table-&gt;string('payment_source');
            $table-&gt;string('item_number');
            $table-&gt;string('item_name');
            $table-&gt;float('item_price', 10, 2);
            $table-&gt;string('item_price_currency');

            $table-&gt;timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('payments');
    }
};
</pre>
<p>Now that the migration has been created, lets go ahead and create the payments table via a migration. Update your .env file to define your database information and run the migration. In my case, I created a MySQL database called paypal to store the payments as follows</p>
<pre class="brush: php; title: ; notranslate">
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=paypal
DB_USERNAME=mifty
DB_PASSWORD=XXXXXXXX
</pre>
<p>With your database setup, you can now run the migration command below:</p>
<pre class="brush: php; title: ; notranslate">    php artisan migrate </pre>
<p>Once this command finishes, the payments table should be created in your database.</p>
<h2>Step 6: create the PayPal Trait</h2>
<p>We will create a trait to store all the low-level PayPal communications. A trait in Laravel allows you to create a reusable piece of code that can be shared across multiple classes. This PayPal trait can be used in our future Checkout controller as well as any class that needs to communicate with PayPal. Unfortunately, there is no artisan command to create a trait but we can create a new file in the app/Traits folder called PayPalTrait.php</p>
<p>This PayPalTrait.php trait will use make REST calls to various PayPal endpoints.The three operations that this trait needs to complete are:</p>
<ol>
<li>Get the PayPal access tokens through getPayPalAccessToken()</li>
<li>Use the access token to create a PayPal order request through createPayPalOrder()</li>
<li>Once the user makes the payment, use the access token to capture the PayPal order through capturePayPalOrder()</li>
</ol>
<p>A closer look at any one of these three functions shows that they use Guzzle to communicate with PayPal. I tried using Laravel’s HTTPClient, which is based on Guzzle  but I couldn’t get it to work as well as the old faithful Guzzle. After a lot of frustration, I just decided to use the Guzzle HTTP Client instead. Here are the contents of getPayPalAccessToken() which passes the client ID and client secret to PayPal in order to get an access token.</p>
<pre class="brush: php; title: ; notranslate">
    /**
     * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs.
     * @see https://developer.paypal.com/api/rest/authentication/
     */
    public function getPayPalAccessToken()
    {
        //get the PayPal client ID and secret along with the auth endpoint
        $clientID = $this-&gt;getPayPalClientID();
        $clientSecret = $this-&gt;getPayPalClientSecret();
        $authEndpoint = $this-&gt;getPayPalAuthEndpoint();

        try {
            // use Guzzle Client to build the request to receive the access token
            $token = base64_encode($clientID . &quot;:&quot; . $clientSecret);
            $client = new \GuzzleHttp\Client();
            $response = $client-&gt;request('POST', $authEndpoint, &#x5B;
                'headers' =&gt; &#x5B;
                    'Accept' =&gt; 'application/json',
                    'Authorization' =&gt; 'Basic ' . $token
                ],
                'form_params' =&gt; &#x5B;
                    'grant_type' =&gt; 'client_credentials'
                ]
            ]);

            // check the status code to make sure that we got a successful response from PayPal
            $statusCode = $response-&gt;getStatusCode();
            if ($this-&gt;isSuccessfulResponse($statusCode)) {
                // decode our response body to retrieve our access token
                $data = json_decode($response-&gt;getBody());
                $accessToken = $data-&gt;access_token;

                return $accessToken;
            }

        } catch (\GuzzleHttp\Exception\RequestException $e) {
            // we got either  a 400 or 500 response error
            $error&#x5B;'error'] = $e-&gt;getMessage();
            $error&#x5B;'request'] = $e-&gt;getRequest();
            if ($e-&gt;hasResponse()) {
                if ($e-&gt;getResponse()-&gt;getStatusCode() == '400') {
                    $error&#x5B;'response'] = $e-&gt;getResponse();
                }
            }
            // log the error
            Log::error('Error occurred in getPayPalAccessToken request.', &#x5B;'error' =&gt; $error]);

            // due to the error, we did not get an access token return an empty access token
            return &quot;&quot;;
        } 
    }
</pre>
<p>Besides these main functions, there are various helper functions to get the configuration values based on the PayPal environment such as getPayPalClientID() and getPayPalClientSecret() which are self-explanatory. Below is the full contents of the PayPalTrait.php file</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

namespace App\Traits;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Arr;

trait PayPalTrait
{

    /**
     * Get the client ID based on the sandbox configuration parameter
     */
    public function getPayPalClientID()
    {
        $clientID = config('paypal.client_id_sandbox');
        if (!config('paypal.sandbox_enabled')) {
            $clientID = config('paypal.client_id_production');
        }

        return $clientID;
    }

    /**
     * Get the client Secret based on the sandbox configuration parameter
     */
    public function getPayPalClientSecret()
    {
        $clientSecret = config('paypal.client_secret_sandbox');
        if (!config('paypal.sandbox_enabled')) {
            $clientSecret = config('paypal.client_secret_production');
        }

        return $clientSecret;
    }

    /**
     * Get the auth endpoint based on the sandbox configuration parameter
     */
    public function getPayPalAuthEndpoint()
    {
        $authEndpoint = config('paypal.auth_endpoint_sandbox');
        if (!config('paypal.sandbox_enabled')) {
            $authEndpoint = config('paypal.auth_endpoint_production');
        }

        return $authEndpoint;
    }


    /**
     * Get the checkout endpoint based on the sandbox configuration parameter
     */
    public function getPayPalCheckoutEndpoint()
    {
        $endpoint = config('paypal.checkout_endpoint_sandbox');
        if (!config('paypal.sandbox_enabled')) {
            $endpoint = config('paypal.checkout_endpoint_production');
        }

        return $endpoint;
    }

    /**
     * determines if a response is a successful response based on the status code
     */
    private function isSuccessfulResponse($statusCode)
    {
        return ($statusCode &gt;= 200 || $statusCode &lt; 300);
    }


    /**
     * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs.
     * @see https://developer.paypal.com/api/rest/authentication/
     */
    public function getPayPalAccessToken()
    {
        //get the PayPal client ID and secret along with the auth endpoint
        $clientID = $this-&gt;getPayPalClientID();
        $clientSecret = $this-&gt;getPayPalClientSecret();
        $authEndpoint = $this-&gt;getPayPalAuthEndpoint();

        try {
            // use Guzzle Client to build the request to receive the access token
            $token = base64_encode($clientID . &quot;:&quot; . $clientSecret);
            $client = new \GuzzleHttp\Client();
            $response = $client-&gt;request('POST', $authEndpoint, &#x5B;
                'headers' =&gt; &#x5B;
                    'Accept' =&gt; 'application/json',
                    'Authorization' =&gt; 'Basic ' . $token
                ],
                'form_params' =&gt; &#x5B;
                    'grant_type' =&gt; 'client_credentials'
                ]
            ]);

            // check the status code to make sure that we got a successful response from PayPal
            $statusCode = $response-&gt;getStatusCode();
            if ($this-&gt;isSuccessfulResponse($statusCode)) {
                // decode our response body to retrieve our access token
                $data = json_decode($response-&gt;getBody());
                $accessToken = $data-&gt;access_token;

                return $accessToken;
            }

        } catch (\GuzzleHttp\Exception\RequestException $e) {
            // we got either  a 400 or 500 response error
            $error&#x5B;'error'] = $e-&gt;getMessage();
            $error&#x5B;'request'] = $e-&gt;getRequest();
            if ($e-&gt;hasResponse()) {
                if ($e-&gt;getResponse()-&gt;getStatusCode() == '400') {
                    $error&#x5B;'response'] = $e-&gt;getResponse();
                }
            }
            // log the error
            Log::error('Error occurred in getPayPalAccessToken request.', &#x5B;'error' =&gt; $error]);

            // due to the error, we did not get an access token return an empty access token
            return &quot;&quot;;
        } 
    }

    /**
     * create an Order using OAuth 2.0
     * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
     */
    public function createPayPalOrder($accessToken, $payload)
    {
        // get the paypal checkout endoint
        $checkoutEndpoint = $this-&gt;getPayPalCheckoutEndpoint();

        try {
            // use Guzzle Client since I cant get HTTPClient to work
            $client = new \GuzzleHttp\Client();
            $response = $client-&gt;request('POST', $checkoutEndpoint, &#x5B;
                'headers' =&gt; &#x5B;
                    'Content-Type' =&gt; 'application/json',
                    'Authorization' =&gt; 'Bearer ' . $accessToken
                    // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation:
                    // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/
                    // 'PayPal-Mock-Response' =&gt; '{&quot;mock_application_codes&quot;: &quot;MISSING_REQUIRED_PARAMETER&quot;}'
                    // 'PayPal-Mock-Response' =&gt; '{&quot;mock_application_codes&quot;: &quot;PERMISSION_DENIED&quot;}'
                    // 'PayPal-Mock-Response' =&gt; '{&quot;mock_application_codes&quot;: &quot;INTERNAL_SERVER_ERROR&quot;}'
                ],
                'json' =&gt; $payload
            ]);

            $statusCode = $response-&gt;getStatusCode();
            if ($this-&gt;isSuccessfulResponse($statusCode)) {
                // store the response as an array and add the status code to the array
                $data = json_decode($response-&gt;getBody(), true);
                $data = Arr::add($data, 'statusCode', $statusCode);

                return $data;
            }
        } catch (\GuzzleHttp\Exception\RequestException $e) {
            // we got either  a 400 or 500 response error
            $error&#x5B;'error'] = $e-&gt;getMessage();
            $error&#x5B;'request'] = $e-&gt;getRequest();
            if ($e-&gt;hasResponse()) {
                if ($e-&gt;getResponse()-&gt;getStatusCode() == '400') {
                    $error&#x5B;'response'] = $e-&gt;getResponse();
                }
            }
            // log the error
            Log::error('Error occurred in createPayPalOrder request.', &#x5B;'error' =&gt; $error]);
            dd($error);

            // due to the error, return an empty response
            return &#x5B;];
        }
    }

    /**
     * capture payment for an order using OAuth 2.0
     * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
     */
    public function capturePayPalOrder($accessToken, $orderID)
    {
        // build the paypal endoint
        $checkoutURL = $this-&gt;getPayPalCheckoutEndpoint() . &quot;/&quot; . $orderID . &quot;/capture&quot;;

        try {
            // use Guzzle Client since I cant get HTTPClient to work
            $client = new \GuzzleHttp\Client();
            $response = $client-&gt;request('POST', $checkoutURL, &#x5B;
                'headers' =&gt; &#x5B;
                    'Content-Type' =&gt; 'application/json',
                    'Authorization' =&gt; 'Bearer ' . $accessToken
                    // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation:
                    // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/
                    // 'PayPal-Mock-Response' =&gt; '{&quot;mock_application_codes&quot;: &quot;INSTRUMENT_DECLINED&quot;}'
                    // 'PayPal-Mock-Response' =&gt; '{&quot;mock_application_codes&quot;: &quot;TRANSACTION_REFUSED&quot;}'
                    // 'PayPal-Mock-Response' =&gt; '{&quot;mock_application_codes&quot;: &quot;INTERNAL_SERVER_ERROR&quot;}'
                ]
            ]);

            $statusCode = $response-&gt;getStatusCode();
            if ($this-&gt;isSuccessfulResponse($statusCode)) {
                // store the response as an array and add the status code to the array
                $data = json_decode($response-&gt;getBody(), true);
                $data = Arr::add($data, 'statusCode', $statusCode);

                return $data;
            }
        } catch (\GuzzleHttp\Exception\RequestException $e) {
            // we got either  a 400 or 500 response error
            $error&#x5B;'error'] = $e-&gt;getMessage();
            $error&#x5B;'request'] = $e-&gt;getRequest();
            if ($e-&gt;hasResponse()) {
                if ($e-&gt;getResponse()-&gt;getStatusCode() == '400') {
                    $error&#x5B;'response'] = $e-&gt;getResponse();
                }
            }
            // log the error
            Log::error('Error occurred in capturePayPalOrder request.', &#x5B;'error' =&gt; $error]);

            // due to the error, return an empty response
            return &#x5B;];
        }
    }
}
</pre>
<h2>Step 7: create the CheckoutControler</h2>
<p>We are finally ready to define the checkout Controller which will handle the payment-related work and use the PayPal trait to handle the low-level Paypal communications. You can use the following command to create the Checkout Controller.</p>
<pre class="brush: php; title: ; notranslate">php artisan make:controller CheckoutController</pre>
<p>This will create the CheckoutController inside the App/Http/Controllers folder of our app. As covered in the routes definition, we will need this controller to handle the three main functions of this app which are to display the checkout page, create the PayPal order and capture the PayPal order. That’s why I’ve created 3 functions called checkout(), createOrder() and captureOrder(). Try to guess which function does what 🙂 . I also have a function to store the payment in the payments database called storePayment(). Let’s do a quick overview of each function</p>
<h3>checkout()</h3>
<p>The checkout() function is the only function that will be returning a view. It gets the PayPal client ID and sample item information from the paypal.php configuration file, which it passes over to a view called checkout. We will cover the view later, but for now, you need to know that the view needs the PayPal client ID since we must pass it as a parameter to the PayPal Javascript SDK. The item details are needed for the view to display the item information to the user. Here is the full code for the checkout() function</p>
<pre class="brush: php; title: ; notranslate">
    /**
     * Create the checkout page
     * @see https://developer.paypal.com/integration-builder/ for the NodeJS version
     */
    public function checkout()
    {
        // get our paypal clientID for the view
        $clientID = $this-&gt;getPayPalClientID();

        // get the sample item details from our configuration file
        $item = $this-&gt;getItem();
        
        return view('checkout', &#x5B;'clientID' =&gt; $clientID, 'item' =&gt; $item]);

    }
</pre>
<h3>createOrder()</h3>
<p>The createOrder() function is called via an AJAX POST request after the user clicks on the PayPal button. It is responsible for passing the item details to PayPal and to also indicate our intent to capture the payment. Your only two possible intents for a payment are to either authorize or capture. Some background information, the basic payment flow, including the PayPal flow follows these 5 steps:</p>
<ol>
<li>The payer checks out and provides a card for payment.</li>
<li>You authorize the payment.</li>
<li>A hold is placed on the payer&#8217;s card until you are ready to capture payment.</li>
<li>You finalize the transaction and capture the payment.</li>
<li>The payer&#8217;s card is charged.</li>
</ol>
<p>An authorization places a hold on the funds and is valid for 29 days. If the authorization is not captured within 29 days, the hold is released. It is possible to do both at the same time by simply stating that you intend to capture the funds immediately after the authorization happens. That is what our intent to capture tells PayPal. </p>
<p>The rest of the PayPal payload contains the basic information about the item being purchased such as price and currency. Although the PayPal payload is pretty easy to follow, you should pay special attention to the &#8220;custom_id&#8221; field. This field  should contain your internal product ID and it will be returned by PayPal later when you capture the order. </p>
<p>A cart object is returned from the frontend with the item number. After we have verified that the item number is valid, we fetch the item details and pass the item as a payload to PayPal along with our intent to capture the payment. (Note: Be careful to properly format the PayPal payload, otherwise, your request will be rejected)  Then we call the PayPal trait function getPayPalAccessToken() to get an access token which we must pass to PayPal  for our PayPal request to be valid. Finally we call the PayPal trait function createPayPalOrder() which expects the access token as well as the payload. This function will make a request to  PayPal to create our order.  If the request is successful, Paypal will return an order ID in their response. We need to pass this order ID back to the frontEnd. So once we get the response back from PayPal, we will pass it back as the response to the POST request that we got from the frontEnd since it will contain the order ID. Below is the full code for createOrder():</p>
<pre class="brush: php; title: ; notranslate">
    /**
     * Create an order to start the transaction.
     * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
     */
    public function createOrder(Request $request)
    {
        // get the cart data from the request and validate the items in the cart
        $cartData = $request-&gt;input('cart');

        // get the sample item details from our configuration file
        $item = $this-&gt;getItem();

        /**
         * this is where we can add the validation logic for the item that we are about to create an order for
         * since I only have a sample prodct in the configuration file, I will just validate that the sample item
         * is what was returned
         */

        if ($cartData&#x5B;0]&#x5B;&quot;item&quot;] != $item&#x5B;&quot;id&quot;]) {
            // create an error response since this is not an expected item
            $response = &#x5B;
                &quot;error&quot; =&gt; &quot;Invalid Item&quot;,
                &quot;details&quot; =&gt; &#x5B;
                    &#x5B;
                        &quot;issue&quot; =&gt; &quot;Invalid Item Provided&quot;,
                        &quot;description&quot; =&gt; &quot;Item &quot; . $item&#x5B;&quot;id&quot;] . &quot; is not in our inventory!&quot;,
                    ]
                ],
                &quot;debug_id&quot; =&gt; &quot;INTERNAL ERROR&quot;
            ];
            return response()-&gt;json($response);
        }

        // get an access token &amp; create our payload for the order capture
        $token = $this-&gt;getPayPalAccessToken();
        $payload = &#x5B;
            'intent' =&gt; 'CAPTURE',
            'purchase_units' =&gt; &#x5B;
                &#x5B;
                    'amount' =&gt; &#x5B;
                        'currency_code' =&gt; $item&#x5B;&quot;currency&quot;],
                        'value' =&gt; $item&#x5B;&quot;price&quot;],
                        'breakdown' =&gt; &#x5B;
                            'item_total' =&gt; &#x5B;'value' =&gt; $item&#x5B;&quot;price&quot;], 'currency_code' =&gt; $item&#x5B;&quot;currency&quot;]]
                        ]
                    ],
                    'items' =&gt; &#x5B;
                        &#x5B;
                            'name' =&gt; $item&#x5B;&quot;name&quot;],
                            'quantity' =&gt; 1,
                            'description' =&gt; $item&#x5B;&quot;description&quot;],
                            'sku' =&gt; $item&#x5B;&quot;id&quot;],
                            'category' =&gt; 'DIGITAL_GOODS',
                            'unit_amount' =&gt; &#x5B;'value' =&gt; $item&#x5B;&quot;price&quot;], 'currency_code' =&gt; $item&#x5B;&quot;currency&quot;]]
                        ]
                    ],
                    &quot;custom_id&quot; =&gt; $item&#x5B;&quot;id&quot;], // used as out internal ID for the product for later retreival
                ]
            ]
        ];

        // create the PayPal order
        $response = $this-&gt;createPayPalOrder($token, $payload);

        // return the json response
        return response()-&gt;json($response);
    }
</pre>
<h3>captureOrder()</h3>
<p>The captureOrder() function is called once the user has provided their information and clicked the submit button on the PayPal window to finalize their payment. Once the user submits their payment information, an order ID is created and this ID must be passed back to the backend via an AJAX POST call. This POST request calls captureOrder() with the order ID. This orderID must be passed to PayPal in order to finalize the payment.  captureOrder() uses the PayPal trait function getPayPalAccessToken() to get an access token. This access token, along with the order ID from the frontend must be sent over to PayPal to complete the payment and get the payment details. We use the PayPal trait capturePayPalOrder() to make the request to PayPal. If the capturePayPalOrder()  request is successful, then the payment details will be returned. The payment details then need to be stored in our payments database, which is handled by the storePayment() function. Once the payment has been stored in our database, we then retrieve the contents of the paid item and pass it along with the PayPal payment response via AJAX to the frontend. This will allow the frontend to know that the payment was successful and also make the item content available to the user. Below is the full code for createOrder():</p>
<pre class="brush: php; title: ; notranslate">
    /**
     * capture an order based on a transaction ID
     * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
     */
    public function captureOrder(Request $request)
    {
        // get the orderID and get access token
        $orderID = $request-&gt;input('orderID');
        $token = $this-&gt;getPayPalAccessToken();

        // capture the PayPal order and store the captured payment
        $response = $this-&gt;capturePayPalOrder($token, $orderID);

        // if we got a succesful payment, then store it in our payments database
        if ($response&#x5B;&quot;statusCode&quot;] &gt;= 200 &amp;&amp; $response&#x5B;&quot;statusCode&quot;] &lt; 300) {

            // store the payment
            $this-&gt;storePayment($response);

            // attach the purchased good to the response
            $itemContent = config('paypal.sample_item_content');
            $response = Arr::add($response, 'purchased_content', $itemContent);

        }

        // return the json response
        return response()-&gt;json($response);
    }
</pre>
<h3>storePayment()</h3>
<p>The storePayment() function is used to parse the returned PayPal payment data and build a Payment object that is stored in the database. This function is pretty simple so no analysis of the function is really needed. There are only points to make:</p>
<ol>
<li>The &#8220;custom_id&#8221; field is very important. This should contain your internal product ID so that you are able to know what item was purchased. When the order was created in the createOrder() function, the custom_id field was populated with the sample item’s item number.  According to Paypal, “The API caller-provided external ID. Used to reconcile client transactions with PayPal transactions. Appears in transaction and settlement reports but is not visible to the payer.”. In this tutorial, I do a basic check to make sure that the value of custom_id matches the item_number of my sample item. If you have multiple items in your database, you should make sure that the value of custom_id matches a product in your database.</li>
<li>The PayPal return object format is very specific and takes some time to get used to. Although the structure makes sense, it takes some time to get used to it. So be prepared to be frustrated if this is your first time interacting with this object.</li>
</ol>
<p>Below is the full content of the Checkout controller:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\URL;

use App\Traits\PayPalTrait;
use App\Models\Payment;

class CheckoutController extends Controller
{
    // load the paypal trait
    use PayPalTrait;

    /**
     * Create the checkout page
     * @see https://developer.paypal.com/integration-builder/ for the NodeJS version
     */
    public function checkout()
    {
        // get our paypal clientID for the view
        $clientID = $this-&gt;getPayPalClientID();

        // get the sample item details from our configuration file
        $item = $this-&gt;getItem();
        
        return view('checkout', &#x5B;'clientID' =&gt; $clientID, 'item' =&gt; $item]);

    }

    /**
     * Create an order to start the transaction.
     * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
     */
    public function createOrder(Request $request)
    {
        // get the cart data from the request and validate the items in the cart
        $cartData = $request-&gt;input('cart');

        // get the sample item details from our configuration file
        $item = $this-&gt;getItem();

        /**
         * this is where we can add the validation logic for the item that we are about to create an order for
         * since I only have a sample prodct in the configuration file, I will just validate that the sample item
         * is what was returned
         */

        if ($cartData&#x5B;0]&#x5B;&quot;item&quot;] != $item&#x5B;&quot;id&quot;]) {
            // create an error response since this is not an expected item
            $response = &#x5B;
                &quot;error&quot; =&gt; &quot;Invalid Item&quot;,
                &quot;details&quot; =&gt; &#x5B;
                    &#x5B;
                        &quot;issue&quot; =&gt; &quot;Invalid Item Provided&quot;,
                        &quot;description&quot; =&gt; &quot;Item &quot; . $item&#x5B;&quot;id&quot;] . &quot; is not in our inventory!&quot;,
                    ]
                ],
                &quot;debug_id&quot; =&gt; &quot;INTERNAL ERROR&quot;
            ];
            return response()-&gt;json($response);
        }

        // get an access token &amp; create our payload for the order capture
        $token = $this-&gt;getPayPalAccessToken();
        $payload = &#x5B;
            'intent' =&gt; 'CAPTURE',
            'purchase_units' =&gt; &#x5B;
                &#x5B;
                    'amount' =&gt; &#x5B;
                        'currency_code' =&gt; $item&#x5B;&quot;currency&quot;],
                        'value' =&gt; $item&#x5B;&quot;price&quot;],
                        'breakdown' =&gt; &#x5B;
                            'item_total' =&gt; &#x5B;'value' =&gt; $item&#x5B;&quot;price&quot;], 'currency_code' =&gt; $item&#x5B;&quot;currency&quot;]]
                        ]
                    ],
                    'items' =&gt; &#x5B;
                        &#x5B;
                            'name' =&gt; $item&#x5B;&quot;name&quot;],
                            'quantity' =&gt; 1,
                            'description' =&gt; $item&#x5B;&quot;description&quot;],
                            'sku' =&gt; $item&#x5B;&quot;id&quot;],
                            'category' =&gt; 'DIGITAL_GOODS',
                            'unit_amount' =&gt; &#x5B;'value' =&gt; $item&#x5B;&quot;price&quot;], 'currency_code' =&gt; $item&#x5B;&quot;currency&quot;]]
                        ]
                    ],
                    &quot;custom_id&quot; =&gt; $item&#x5B;&quot;id&quot;], // used as out internal ID for the product for later retreival
                ]
            ]
        ];

        // create the PayPal order
        $response = $this-&gt;createPayPalOrder($token, $payload);

        // return the json response
        return response()-&gt;json($response);
    }

    /**
     * capture an order based on a transaction ID
     * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
     */
    public function captureOrder(Request $request)
    {
        // get the orderID and get access token
        $orderID = $request-&gt;input('orderID');
        $token = $this-&gt;getPayPalAccessToken();

        // capture the PayPal order and store the captured payment
        $response = $this-&gt;capturePayPalOrder($token, $orderID);

        // if we got a succesful payment, then store it in our payments database
        if ($response&#x5B;&quot;statusCode&quot;] &gt;= 200 &amp;&amp; $response&#x5B;&quot;statusCode&quot;] &lt; 300) {

            // store the payment
            $this-&gt;storePayment($response);

            // attach the purchased good to the response
            $itemContent = config('paypal.sample_item_content');
            $response = Arr::add($response, 'purchased_content', $itemContent);

        }

        // return the json response
        return response()-&gt;json($response);
    }

    /**
     * store a captured payment
     * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
     */
    private function storePayment($capturedPayment)
    {
        // get the sample item details from our configuration file
        $item = $this-&gt;getItem();

        // add the transaction in our transactions Database.
        if (!empty($capturedPayment) &amp;&amp; !empty($capturedPayment&#x5B;'payer'])) {

            // get the order details
            $orderID = $capturedPayment&#x5B;'id'];
            $orderStatus = $capturedPayment&#x5B;'status'];

            // get the payment details
            $purchaseUnit = $capturedPayment&#x5B;'purchase_units']&#x5B;0];
            $paidAmount = 0;
            $paidAmountCurrency = &quot;N/A&quot;;
            $transactionID = &quot;N/A&quot;;
            $transactionStatus = &quot;UNKNOWN&quot;;
            $transactionItemID = &quot;UNKNOWN&quot;;
            if (!empty($purchaseUnit&#x5B;'payments']&#x5B;'captures']&#x5B;0])) {
                $payment_capture = $purchaseUnit&#x5B;'payments']&#x5B;'captures']&#x5B;0];
                $transactionID = $payment_capture&#x5B;'id'];
                $transactionStatus = $payment_capture&#x5B;'status'];
                $transactionItemID = $payment_capture&#x5B;&quot;custom_id&quot;];
                $paidAmount = $payment_capture&#x5B;'amount']&#x5B;&quot;value&quot;];
                $paidAmountCurrency = $payment_capture&#x5B;'amount']&#x5B;&quot;currency_code&quot;];
            }


            // get the sample item details from our configuration file
            $itemCurrency = $item&#x5B;'currency'];
            $itemPrice = $item&#x5B;'price'];
            $itemName = $item&#x5B;'name'];
            $itemDesc = $item&#x5B;'description'];
            $itemNumber = $item&#x5B;'id'];

            // confirm that the item is our item. You may want to do extra validation here.
// i'm only doing basic validation to confirm that the item is recognized
            if ($transactionItemID != $item&#x5B;'id']) {
                $itemCurrency = &quot;UNKNOWN&quot;;
                $itemPrice = &quot;UNKNOWN&quot;;
                $itemName = &quot;UNKNOWN&quot;;
                $itemDesc = &quot;UNKNOWN&quot;;
            }


            // get the payer details
            $payer = $capturedPayment&#x5B;'payer'];
            $payerID = $payer&#x5B;'payer_id'];
            $payerName = $payer&#x5B;'name'];
            $payerGivenName = !empty($payerName&#x5B;'given_name']) ? $payerName&#x5B;'given_name'] : '';
            $payerSurName = !empty($payerName&#x5B;'surname']) ? $payerName&#x5B;'surname'] : '';
            $payerFullName = trim($payerGivenName . ' ' . $payerSurName);
            $payerEmailAddress = $payer&#x5B;'email_address'];
            $payerAddress = $payer&#x5B;'address'];
            $payerCountryCode = !empty($payerAddress&#x5B;'country_code']) ? $payerAddress&#x5B;'country_code'] : '';

            // get the payment source
            $paymentSource = '';
            if (!empty($capturedPayment&#x5B;'payment_source'])) {
                foreach ($capturedPayment&#x5B;'payment_source'] as $key =&gt; $value) {
                    $paymentSource = $key;
                }
            }


            // create a payment entry to store this captured payment
            $payment = new Payment;

            // assign the payment attributes
            $payment-&gt;item_number = $transactionItemID;
            $payment-&gt;item_name = $itemName;
            $payment-&gt;item_price = $itemPrice;
            $payment-&gt;item_price_currency = $itemCurrency;
            $payment-&gt;payer_id = $payer&#x5B;'payer_id'];
            $payment-&gt;payer_name = $payerFullName;
            $payment-&gt;payer_email = $payerEmailAddress;
            $payment-&gt;payer_country = $payerCountryCode;
            $payment-&gt;transaction_id = $transactionID;
            $payment-&gt;transaction_status = $transactionStatus;
            $payment-&gt;paid_amount = $paidAmount;
            $payment-&gt;paid_amount_currency = $paidAmountCurrency;
            $payment-&gt;payment_source = $paymentSource;
            $payment-&gt;order_id = $orderID;
            $payment-&gt;order_status = $orderStatus;

            // write out payment to the database
            $payment-&gt;save();
        }
    }

    /**
     * returns the stample item from our configuration file
     */
    private function getItem(){
        // get the sample item details from our configuration file
        $item = &#x5B;
            &quot;currency&quot; =&gt; config('paypal.sample_item_currency'),
            &quot;price&quot; =&gt; config('paypal.sample_item_price'),
            &quot;name&quot; =&gt; config('paypal.sample_item_name'),
            &quot;description&quot; =&gt; config('paypal.sample_item_description'),
            &quot;id&quot; =&gt; config('paypal.sample_item_number')
        ];
        return $item;
    }

}
</pre>
<h2>Step 8: create the view</h2>
<p>As I mentioned earlier, the payment process will stay on the same page so we just need to load one view that displays the PayPal button and uses Javascript to communicate with the backend using AJAX. Since this tutorial was heavily influenced by the PayPal integration builder, the Javascript is quite similar to the PayPal example.</p>
<p>Before we go over the payment flow, let&#8217;s do a quick overview of the <a href="https://developer.paypal.com/sdk/js/reference/" rel="noopener" target="_blank">PayPal Javascript SDK</a>. To use the PayPal JavaScript SDK, you need to add the javascript library and provide your client ID. This is done with the following line of code</p>
<pre class="brush: php; title: ; notranslate">   &lt;script src=&quot;https://www.paypal.com/sdk/js?client-id=YOUR-CLIENT-ID&quot;&gt;&lt;/script&gt;</pre>
<p>To initiate the SDK, you must call paypal.Buttons().render() to instantiate the buttons on the page. The render() function expects the ID of the HTML container element where the button will be rendered in. In case you are wondering, you can have multiple PayPal buttons on the same page. Since the SDK uses events to determine what needs to be done, we need to define the behaviour for the 2 most important events that are defined by the SDK. Here are the functions related to these events:</p>
<ol>
<li>createOrder(): is called when the buyer clicks the PayPal button, which launches the PayPal Checkout window where the buyer logs in and approves the transaction on the paypal.com website.</li>
<li>onApprove() function is called after the buyer approves the transaction on paypal.com.</li>
</ol>
<p>Here is the flow of events in our application once the PayPal buttons are rendered. </p>
<ol>
<li>The user clicks on the PayPal button to begin the payment process. This calls the createOrder() event handler</li>
<li>The createOrder()  event collects the item data and builds a POST request to the &#8216;purchase&#8217; route which is the createOrder() function in the checkout Controller. As mentioned earlier, in the case of a successful request, the createOrder() function will return an order ID. </li>
<li>The order ID from the POST request is passed to the PayPal window as it is displayed to the user.</li>
<li>Once the user has entered their information inside the PayPal window and confirmed their purchase, the onApprove() event is triggered and an order ID is passed from the PayPal window.</li>
<li>The order ID from the PayPal window is then passed to the capture route which calls the captureOrder() function in the controller.If the order ID is valid then a success is returned from PayPal. Along with the PayPal response code, the item content is also added to the content returned by captureOrder().</li>
<li>If a success response is received by the frontend, then we call displayContent() function which will make the content visible on the frontend.</li>
</ol>
<p>Note that any form in Laravel, including AJAX forms, need to include the CSRF token otherwise the POST request will fail. That is why the CSRF token from Laravel is passed in the header with this line.</p>
<pre class="brush: php; title: ; notranslate">&lt;meta name=&quot;csrf-token&quot; content=&quot;{{ csrf_token() }}&quot;&gt;</pre>
<p>I can then use jQuery to add the CSRF token in the header of the POST requests made to the backend. </p>
<pre class="brush: php; title: ; notranslate">
                            headers: {
                                &quot;Content-Type&quot;: &quot;application/json&quot;,
                                'X-CSRF-TOKEN': $('meta&#x5B;name=&quot;csrf-token&quot;]').attr('content')
                            },
</pre>
<p>Finally, I load bootstrap from the bootstrap CDN so that we can make the page look good. Below are is the content of the view:</p>
<pre class="brush: php; title: ; notranslate">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
    &lt;title&gt;PayPal JS SDK Standard Integration with Laravel&lt;/title&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
    &lt;meta name=&quot;csrf-token&quot; content=&quot;{{ csrf_token() }}&quot;&gt;
    &lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js&quot;&gt;&lt;/script&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css&quot;&gt;
    &lt;script src=&quot;https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js&quot;&gt;&lt;/script&gt;

&lt;/head&gt;

&lt;body&gt;

    &lt;div class=&quot;jumbotron text-center&quot;&gt;
        &lt;h1&gt;PayPal Standard Checkout Example&lt;/h1&gt;
    &lt;/div&gt;

    &lt;div class=&quot;container&quot;&gt;
        &lt;div class=&quot;row&quot;&gt;
            &lt;div class=&quot;col-sm-8&quot;&gt;
                &lt;div id=&quot;result-message&quot; class=&quot;text-center&quot;&gt;
                    &lt;h3&gt;Purchase {{$item&#x5B;'name']}}&lt;/h3&gt;
                    &lt;p&gt;You are about to purchase &lt;strong&gt;{{$item&#x5B;'name']}}&lt;/strong&gt; for &lt;strong&gt;${{$item&#x5B;'price']}}
                            {{$item&#x5B;'currency']}}&lt;/strong&gt;&lt;/p&gt;
                &lt;/div&gt;
                &lt;div id=&quot;paypal-button-container&quot;&gt;&lt;/div&gt;
                &lt;script
                    src=&quot;https://www.paypal.com/sdk/js?client-id={{$clientID}}&amp;currency={{$item&#x5B;'currency']}}&amp;components=buttons&amp;enable-funding=paylater,venmo,card&quot;
                    data-sdk-integration-source=&quot;integrationbuilder_sc&quot;&gt;&lt;/script&gt;
                &lt;div id=&quot;bottom-container&quot; class=&quot;text-center&quot;&gt;&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;col-sm-4&quot;&gt;
                &lt;h3 class=&quot;text-center&quot;&gt;PayPal Standard Checkout PHP Example using Laravel 10&lt;/h3&gt;
                &lt;p class=&quot;text-center&quot;&gt;View the full tutorial at &lt;a href=&quot;https://miftyisbored.com/&quot; target=&quot;_blank&quot;&gt;MiftyIsBored.com&lt;/a&gt;&lt;/p&gt;
                &lt;p&gt;&lt;em&gt;Note: This is a &lt;strong&gt;Sandbox setup&lt;/strong&gt; so you can test with &lt;strong&gt;any Sandbox PayPal
                            account&lt;/strong&gt; or use the following test account to purchase the digital item:
                        &lt;ul&gt;
                            &lt;li&gt;email: sb-kkhf028891454@personal.example.com&lt;/li&gt;
                            &lt;li&gt;password: J&gt;!]&#x5B;0Wt&lt;/li&gt;
                        &lt;/ul&gt;

                    &lt;/em&gt;&lt;/p&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;



    &lt;script&gt;
        window.paypal
            .Buttons({
                style: {
                    shape: &quot;rect&quot;,
                    layout: &quot;vertical&quot;,
                },
                async createOrder() {
                    try {
                        const response = await fetch(&quot;{{ route('order') }}&quot;, {
                            method: &quot;POST&quot;,
                            headers: {
                                &quot;Content-Type&quot;: &quot;application/json&quot;,
                                'X-CSRF-TOKEN': $('meta&#x5B;name=&quot;csrf-token&quot;]').attr('content')
                            },
                            // use the &quot;body&quot; param to pass the order information
                            body: JSON.stringify({
                                cart: &#x5B;
                                    {
                                        item: &quot;{{ $item&#x5B;'id'] }}&quot;,
                                        quantity: &quot;1&quot;,
                                    },
                                ],
                            }),
                        });

                        const orderData = await response.json();

                        if (orderData.id) {
                            return orderData.id;
                        } else {
                            const errorDetail = orderData?.details?.&#x5B;0];
                            const errorMessage = errorDetail
                                ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})`
                                : JSON.stringify(orderData);

                            throw new Error(errorMessage);
                        }
                    } catch (error) {
                        console.error(error);
                        resultMessage(`Could not initiate PayPal Checkout...&lt;br&gt;&lt;br&gt;${error}`);
                    }
                },
                async onApprove(data, actions) {
                    var oID = data.orderID;
                    try {
                        const response = await fetch(`{{ route('capture') }}`, {
                            method: &quot;POST&quot;,
                            headers: {
                                &quot;Content-Type&quot;: &quot;application/json&quot;,
                                'X-CSRF-TOKEN': $('meta&#x5B;name=&quot;csrf-token&quot;]').attr('content')
                            },
                            // use the &quot;body&quot; param to pass the orderID
                            body: JSON.stringify({
                                orderID: oID,
                            }),
                        });

                        const orderData = await response.json();
                        // Three cases to handle:
                        //   (1) Recoverable INSTRUMENT_DECLINED -&gt; call actions.restart()
                        //   (2) Other non-recoverable errors -&gt; Show a failure message
                        //   (3) Successful transaction -&gt; Show confirmation or thank you message

                        const errorDetail = orderData?.details?.&#x5B;0];

                        if (errorDetail?.issue === &quot;INSTRUMENT_DECLINED&quot;) {
                            // (1) Recoverable INSTRUMENT_DECLINED -&gt; call actions.restart()
                            // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/
                            return actions.restart();
                        } else if (errorDetail) {
                            // (2) Other non-recoverable errors -&gt; Show a failure message
                            throw new Error(`${errorDetail.description} (${orderData.debug_id})`);
                        } else if (!orderData.purchase_units) {
                            throw new Error(JSON.stringify(orderData));
                        } else {
                            // (3) Successful transaction -&gt; Show confirmation or thank you message
                            // Or go to another URL:  actions.redirect('thank_you.html');
                            const transaction =
                                orderData?.purchase_units?.&#x5B;0]?.payments?.captures?.&#x5B;0] ||
                                orderData?.purchase_units?.&#x5B;0]?.payments?.authorizations?.&#x5B;0];
                            resultMessage(
                                `Transaction &lt;strong&gt;${transaction.status}&lt;\/strong&gt;: ${transaction.id}. (&lt;em&gt;See console for all available details&lt;\/em&gt;)`,
                            );
                            displayContent(orderData?.purchased_content);
                            console.log(
                                &quot;Capture result&quot;,
                                orderData,
                                JSON.stringify(orderData, null, 2),
                            );
                        }
                    } catch (error) {
                        console.error(error);
                        resultMessage(
                            `Sorry, your transaction could not be processed...&lt;br&gt;&lt;br&gt;${error}`,
                        );
                    }
                },
            })
            .render(&quot;#paypal-button-container&quot;);

        // Example function to show a result to the user. Your site's UI library can be used instead.
        function resultMessage(message) {
            const container = document.querySelector(&quot;#result-message&quot;);
            container.innerHTML = message;
        }

        // Example function to make the purchased item available upon payment confirmation.
        function displayContent(content) {
            const containerPayPal = document.querySelector(&quot;#paypal-button-container&quot;);
            containerPayPal.innerHTML = &quot;&lt;div class='text-center'&gt;&lt;h2&gt;Congratulations on the purchase!&lt;/h2&gt;&lt;p&gt;Here is your purchased image.&lt;/p&gt;&lt;br/&gt;&quot; + content + &quot;&lt;/div&gt;&quot;;

            const containerBottom = document.querySelector(&quot;#bottom-container&quot;);
            containerBottom.innerHTML = &quot;Reload this page to make another transaction&quot;;

        }

    &lt;/script&gt;
&lt;/body&gt;

&lt;/html&gt;
</pre>
<h2>Step 9: Add the Item to our public folder</h2>
<p>Since the purpose of the application is to instantly deliver the item once it is purchased, we need to make sure that the item is stored somewhere on our server. For this tutorial, I have the file &#8220;<a href="http://miftyisbored.com/wp-content/uploads/Frosty_Krusty_Flakes_comic.png" target="_blank" rel="noopener">Frosty_Krusty_Flakes_comic.png</a>&#8221; located inside the public/images folder. (<em>click on the link to download the file</em>) </p>
<h2>Step 10: Test the code</h2>
<p>You can now run the app using Laravel’s serve command</p>
<pre class="brush: php; title: ; notranslate">php artisan serve</pre>
<p>that&#8217;s it. the tutorial is complete and you are good to go. You can see a <a href="https://miftyisbored.com/wp-tutorials/paypal-javascript-SDK-laravel/" rel="noopener" target="_blank">live demo of this tutorial</a> by <a href="https://miftyisbored.com/wp-tutorials/paypal-javascript-SDK-laravel/" rel="noopener" target="_blank">clicking here</a>. As usual, if you have any questions, leave a comment and I&#8217;ll respond whenever I can.</p>
<p>The post <a href="https://miftyisbored.com/paypal-standard-checkout-integration-with-laravel-10/">PayPal Standard Checkout Integration with Laravel 10</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/paypal-standard-checkout-integration-with-laravel-10/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Amir Gets A Raptor</title>
		<link>https://miftyisbored.com/amir-gets-a-raptor/</link>
					<comments>https://miftyisbored.com/amir-gets-a-raptor/#respond</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Sun, 07 May 2023 22:11:29 +0000</pubDate>
				<category><![CDATA[My Creations]]></category>
		<category><![CDATA[My Published Books]]></category>
		<category><![CDATA[News & Rants]]></category>
		<guid isPermaLink="false">https://miftyisbored.com/?p=2656</guid>

					<description><![CDATA[<p>After working on this book for over 4 years with several episodes of writers block, I&#8217;ve finally finished my first children&#8217; book: Amir Gets A Raptor now available at Amazon and Barnes and Nobles. What&#8217;s the story about? Well.. Today, Amir is getting a raptor! A RAPTOR! Today, Amir is getting a raptor and nobody [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/amir-gets-a-raptor/">Amir Gets A Raptor</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>After working on this book for over 4 years with several episodes of writers block, I&#8217;ve finally finished my first children&#8217; book: <strong><a href="https://www.amazon.com/Amir-Gets-Raptor-Amirs-Adventures/dp/B0C12B6FFV/ref=sr_1_1?crid=3U0D5SNSEBVK8&#038;keywords=AMIR+GETS+A+RAPTOR&#038;qid=1683495447&#038;sprefix=amir+gets+a+raptor%2Caps%2C139&#038;sr=8-1" rel="noopener" target="_blank">Amir Gets A Raptor</a></strong> now available at <a href="https://www.amazon.com/Amir-Gets-Raptor-Amirs-Adventures/dp/B0C12B6FFV/ref=sr_1_1?crid=3U0D5SNSEBVK8&#038;keywords=AMIR+GETS+A+RAPTOR&#038;qid=1683495447&#038;sprefix=amir+gets+a+raptor%2Caps%2C139&#038;sr=8-1" rel="noopener" target="_blank">Amazon</a> and <a href="https://www.barnesandnoble.com/w/amir-gets-a-raptor-mifty-yusuf/1143301181" rel="noopener" target="_blank">Barnes and Nobles</a>. What&#8217;s the story about? Well..</p>
<p>Today, Amir is getting a raptor! <strong>A RAPTOR</strong>! Today, Amir is getting a raptor and nobody can change his mind. That&#8217;s right, a <strong>VE-LO-CI-RAPTOR</strong>! Since no one wants to play with Amir, a raptor will be Amir&#8217;s new best friend.</p>
<p><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-front.png" alt="Amir Gets A Raptor Book" width="1000" height="1262" class="alignnone size-full wp-image-2660" srcset="https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-front.png 1000w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-front-238x300.png 238w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-front-811x1024.png 811w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-front-480x606.png 480w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-front-396x500.png 396w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></p>
<p><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-inside.png" alt="Amir Gets A Raptor Book" width="1000" height="1262" class="alignnone size-full wp-image-2658" srcset="https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-inside.png 1000w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-inside-238x300.png 238w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-inside-811x1024.png 811w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-inside-480x606.png 480w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-inside-396x500.png 396w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></p>
<p><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-back.png" alt="Amir Gets A Raptor Book" width="1000" height="1260" class="alignnone size-full wp-image-2659" srcset="https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-back.png 1000w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-back-238x300.png 238w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-back-813x1024.png 813w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-back-480x605.png 480w, https://miftyisbored.com/wp-content/uploads/amir-gets-a-raptor-cover-back-397x500.png 397w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></p>
<p>The post <a href="https://miftyisbored.com/amir-gets-a-raptor/">Amir Gets A Raptor</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/amir-gets-a-raptor/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Random Nick Fury Artwork</title>
		<link>https://miftyisbored.com/random-nick-fury-artwork/</link>
					<comments>https://miftyisbored.com/random-nick-fury-artwork/#respond</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Thu, 10 Jun 2021 20:42:08 +0000</pubDate>
				<category><![CDATA[Sketches]]></category>
		<category><![CDATA[Marvel Comics]]></category>
		<category><![CDATA[Nick Fury]]></category>
		<guid isPermaLink="false">https://miftyisbored.com/?p=2689</guid>

					<description><![CDATA[<p>I usually tend to start projects and move on to other projects quite often. Case in point, this Nick Fury fan comic that I was planning on creating called Nick Fury: Rogue Agent. I think I was inspired by Captain America: Winter Soldier, which I still have as one of my top-3 MCU movies of [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/random-nick-fury-artwork/">Random Nick Fury Artwork</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I usually tend to start projects and move on to other projects quite often. Case in point, this Nick Fury fan comic that I was planning on creating called <strong>Nick Fury: Rogue Agent</strong>. I think I was inspired by <strong>Captain America: Winter Soldier</strong>, which I still have as one of my top-3 MCU movies of all-time. For the comic,  I even had a bunch of finished artwork that I was going to use but then I got sidetracked with other projects. So here are some random artworks that I found from the project while cleaning up my PC.
</p>
<p><a href="http://miftyisbored.com/wp-content/uploads/series-cover-art-color-scope.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/series-cover-art-color-scope.jpg" alt="" width="1000" height="1225" class="alignnone size-full wp-image-2690" srcset="https://miftyisbored.com/wp-content/uploads/series-cover-art-color-scope.jpg 1000w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-scope-245x300.jpg 245w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-scope-836x1024.jpg 836w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-scope-480x588.jpg 480w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-scope-408x500.jpg 408w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/series-cover-art-color-2.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/series-cover-art-color-2.jpg" alt="" width="1000" height="1225" class="alignnone size-full wp-image-2691" srcset="https://miftyisbored.com/wp-content/uploads/series-cover-art-color-2.jpg 1000w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-2-245x300.jpg 245w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-2-836x1024.jpg 836w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-2-480x588.jpg 480w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-2-408x500.jpg 408w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/series-cover-art-color-1.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/series-cover-art-color-1.jpg" alt="" width="1000" height="1225" class="alignnone size-full wp-image-2692" srcset="https://miftyisbored.com/wp-content/uploads/series-cover-art-color-1.jpg 1000w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-1-245x300.jpg 245w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-1-836x1024.jpg 836w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-1-480x588.jpg 480w, https://miftyisbored.com/wp-content/uploads/series-cover-art-color-1-408x500.jpg 408w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art.jpg" alt="" width="1000" height="1225" class="alignnone size-full wp-image-2693" srcset="https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art.jpg 1000w, https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-245x300.jpg 245w, https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-836x1024.jpg 836w, https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-480x588.jpg 480w, https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-408x500.jpg 408w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-preview.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-preview.jpg" alt="" width="900" height="450" class="alignnone size-full wp-image-2694" srcset="https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-preview.jpg 900w, https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-preview-300x150.jpg 300w, https://miftyisbored.com/wp-content/uploads/nick-fury-rogue-agent-series-cover-art-preview-480x240.jpg 480w" sizes="auto, (max-width: 900px) 100vw, 900px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg.jpg" alt="" width="1500" height="1926" class="alignnone size-full wp-image-2695" srcset="https://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg.jpg 1500w, https://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg-234x300.jpg 234w, https://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg-798x1024.jpg 798w, https://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg-1196x1536.jpg 1196w, https://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg-480x616.jpg 480w, https://miftyisbored.com/wp-content/uploads/mystique-pistol-poster-nobg-389x500.jpg 389w" sizes="auto, (max-width: 1500px) 100vw, 1500px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Mystique-rifle-color.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Mystique-rifle-color.jpg" alt="" width="701" height="1000" class="alignnone size-full wp-image-2696" srcset="https://miftyisbored.com/wp-content/uploads/Mystique-rifle-color.jpg 701w, https://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-210x300.jpg 210w, https://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-480x685.jpg 480w, https://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-351x500.jpg 351w" sizes="auto, (max-width: 701px) 100vw, 701px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-preview.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-preview.jpg" alt="" width="900" height="450" class="alignnone size-full wp-image-2697" srcset="https://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-preview.jpg 900w, https://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-preview-300x150.jpg 300w, https://miftyisbored.com/wp-content/uploads/Mystique-rifle-color-preview-480x240.jpg 480w" sizes="auto, (max-width: 900px) 100vw, 900px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/characters-mystique.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/characters-mystique.jpg" alt="" width="1000" height="1000" class="alignnone size-full wp-image-2698" srcset="https://miftyisbored.com/wp-content/uploads/characters-mystique.jpg 1000w, https://miftyisbored.com/wp-content/uploads/characters-mystique-300x300.jpg 300w, https://miftyisbored.com/wp-content/uploads/characters-mystique-150x150.jpg 150w, https://miftyisbored.com/wp-content/uploads/characters-mystique-480x480.jpg 480w, https://miftyisbored.com/wp-content/uploads/characters-mystique-500x500.jpg 500w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/characters-agent-fury.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/characters-agent-fury.jpg" alt="" width="1000" height="1000" class="alignnone size-full wp-image-2699" srcset="https://miftyisbored.com/wp-content/uploads/characters-agent-fury.jpg 1000w, https://miftyisbored.com/wp-content/uploads/characters-agent-fury-300x300.jpg 300w, https://miftyisbored.com/wp-content/uploads/characters-agent-fury-150x150.jpg 150w, https://miftyisbored.com/wp-content/uploads/characters-agent-fury-480x480.jpg 480w, https://miftyisbored.com/wp-content/uploads/characters-agent-fury-500x500.jpg 500w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/agent-hill.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/agent-hill.jpg" alt="" width="1000" height="1000" class="alignnone size-full wp-image-2700" srcset="https://miftyisbored.com/wp-content/uploads/agent-hill.jpg 1000w, https://miftyisbored.com/wp-content/uploads/agent-hill-300x300.jpg 300w, https://miftyisbored.com/wp-content/uploads/agent-hill-150x150.jpg 150w, https://miftyisbored.com/wp-content/uploads/agent-hill-480x480.jpg 480w, https://miftyisbored.com/wp-content/uploads/agent-hill-500x500.jpg 500w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></p>
<p>The post <a href="https://miftyisbored.com/random-nick-fury-artwork/">Random Nick Fury Artwork</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/random-nick-fury-artwork/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>A tutorial on publishing a comic book or Graphic Novel on Amazon’s KDP Platform (Part 1)</title>
		<link>https://miftyisbored.com/a-tutorial-on-publishing-a-comic-book-or-graphic-novel-on-amazons-kdp-platform-part-1/</link>
					<comments>https://miftyisbored.com/a-tutorial-on-publishing-a-comic-book-or-graphic-novel-on-amazons-kdp-platform-part-1/#comments</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Sat, 23 Mar 2019 01:26:40 +0000</pubDate>
				<category><![CDATA[Artworks]]></category>
		<category><![CDATA[Completed Works]]></category>
		<category><![CDATA[Tutorials & Samples]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[KDP]]></category>
		<category><![CDATA[MIFT]]></category>
		<guid isPermaLink="false">http://miftyisbored.com/?p=2631</guid>

					<description><![CDATA[<p>For 2019, I had a goal to self-publish a comic book using Amazon’s KDP platform. Why? Because I wanted to know how to do it. I heard a lot of great things about the KFP platform and I already had a comic book that I was working on from 2018.  I just needed to add [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/a-tutorial-on-publishing-a-comic-book-or-graphic-novel-on-amazons-kdp-platform-part-1/">A tutorial on publishing a comic book or Graphic Novel on Amazon’s KDP Platform (Part 1)</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>For 2019, I had a goal to self-publish a comic book using <a href="https://kdp.amazon.com">Amazon’s KDP platform</a>. Why? Because I wanted to know how to do it. I heard a lot of great things about the KFP platform and I already had a comic book that I was working on from 2018.  I just needed to add some finishing touches to the book so that I could publish it on KDP. The process was a fun and sometimes frustrating experience.  I decided to write a small tutorial since there are not many articles out there going though the whole process and many of the articles that I found were outdated.</p>
<p>This tutorial will cover how I got my comic book <a href="https://www.amazon.com/dp/B07PPDR3NB">MIFT #0</a> published on Amazon’s KDP Platform. You can view the actual <a href="https://www.amazon.com/dp/B07PPDR3NB">Amazon listing here</a> and purchase the kindle book for just 3$.</p>
<p><a href="https://www.amazon.com/dp/B07PPDR3NB"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2632" src="http://miftyisbored.com/wp-content/uploads/MIFT-Preview-eBook-on-Kindle-Store.png" alt="" width="1269" height="501" srcset="https://miftyisbored.com/wp-content/uploads/MIFT-Preview-eBook-on-Kindle-Store.png 1269w, https://miftyisbored.com/wp-content/uploads/MIFT-Preview-eBook-on-Kindle-Store-300x118.png 300w, https://miftyisbored.com/wp-content/uploads/MIFT-Preview-eBook-on-Kindle-Store-1024x404.png 1024w, https://miftyisbored.com/wp-content/uploads/MIFT-Preview-eBook-on-Kindle-Store-480x190.png 480w, https://miftyisbored.com/wp-content/uploads/MIFT-Preview-eBook-on-Kindle-Store-1266x500.png 1266w" sizes="auto, (max-width: 1269px) 100vw, 1269px" /></a></p>
<p>The tutorial is separated into 2 sections:</p>
<ul>
<li>How to create a digital version of your comic (a .mobi file) from your comic pages using Amazon’s Comic Creator</li>
<li>How to upload your .mobi file to KDP and get your comic or graphic novel published</li>
</ul>
<p>One thing to note is that I am assuming in this tutorial is that you have already created your comic pages and that you already have a KDP account. So let’s jump into part 1: creating a kindle version o your comic book.</p>
<p>In order for you to get your comic published through KDP, you have to use <a href="https://www.amazon.com/gp/feature.html?docId=1001103761">Amazon&#8217;s Kindle Comic Creator</a>, which is a free tool provided by Amazon. According to Amazon:</p>
<blockquote><p>Kindle Comic Creator is a free tool for authors and publishers to turn their comics, graphic novels and manga into Kindle books. The tool makes it easy for authors and publishers to import artwork, create their preferred customer reading experience, and see how their book will look on Kindle devices.</p></blockquote>
<p>Here is a screenshot of Kindle Comic Creator:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2633" src="http://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface.png" alt="" width="1920" height="1040" srcset="https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface.png 1920w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-300x163.png 300w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-1024x555.png 1024w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-480x260.png 480w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-923x500.png 923w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<p>Comic Creator is available for both MAC and PC. I used the PC version on multiple PCs (all my work is saved on Dropbox so that I can access the files from multiple devices) With Comic Creator, you are able to:</p>
<ul>
<li>Import your artwork from common file formats like jpg, pdf, tiff, png and ppm</li>
<li>Create guided navigation experience with Kindle Panel View (<em>Which is super awesome by the way. Definitely my favorite part of the Kindle comic reading experience</em>)</li>
<li>Create books with double page spreads or facing pages</li>
<li>Preview content across Kindle devices before publishing</li>
</ul>
<p>Overall, Kindle Comic Creator is a pretty simple and easy-to-use application. But be warned: Kindle Comic Creator is not very stable. In fact, <strong>it crashes&#8230; a lot!</strong> While trying to create my comic, it must have crashed at least 10 times, on 3 different PCs running Windows 10. So my advice when using Kindle Comic Creator is to save fast and save often or risk losing all your work.</p>
<p>So here are the steps for creating a Kindle version of your comic book:</p>
<h1>Step 1: open Kindle Comic Creator and add your comic pages</h1>
<p>Once you open Comic Creator, it will ask you to create a new project or open an existing project. Since this tutorial is assuming that we are creating our project from scratch, choose “Create a New Book”.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2634" src="http://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-new-book-screenshot.png" alt="" width="1920" height="1040" srcset="https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-new-book-screenshot.png 1920w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-new-book-screenshot-300x163.png 300w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-new-book-screenshot-1024x555.png 1024w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-new-book-screenshot-480x260.png 480w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-new-book-screenshot-923x500.png 923w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<p>Once You choose to create a new book, you will be presented with 2 option screens. The first screen is your panel selection options and the second screen is your book settings.</p>
<h2>Panel Selection Options</h2>
<p>The panel selection option allows you to choose the layout of your book and if you want to use Kindle Panel View (which every comic book or graphic on Kindle should use).</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2635" src="http://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-panel-selection.png" alt="" width="732" height="651" srcset="https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-panel-selection.png 732w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-panel-selection-300x267.png 300w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-panel-selection-480x427.png 480w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-panel-selection-562x500.png 562w" sizes="auto, (max-width: 732px) 100vw, 732px" /></p>
<p>The panel selection options that you need to choose include:</p>
<ul>
<li><strong>What is the language of your book</strong>: This is an irrelevant option since the words of our comic book is embedded into the art, so I simply chose English. (<em>But According to KCC, the language is used to recommend various settings</em>)</li>
<li><strong>Would you like to create Kindle Panel View</strong>: Kindle Panel View is a guided navigation experience. It allows the author to control the flow of story as readers progress through the book. Kindle Comic Creator can automatically detect Kindle Panels but its not always very good so you should manually edit your panels. (<em>more about the panel view later in this tutorial</em>)</li>
<li><strong>What is the orientation of your book</strong>: Options include Portrait, Landscape and Unlocked. Note: If you are using panel view, you will not be able to select the Unlocked mode. It took me several hours to discover this but Panel View does not let you choose unlocked mode. And you can only create 2-page spreads if Panel mode is off.</li>
<li><strong>What is the page turn direction of your book</strong>: Options include Left-to-Right and Right-to-Left. For page turn direction, select Left-to-Right or Right-to-Left based on the page turn used for language of your book</li>
<li><strong>What is the canvas size of your book (original resolution)</strong>: Original resolution size reflects the full dimensions of the image. The default values are width: 800 px, height: 1280 px. The maximum value permitted for either setting is 1280 px. If the image dimensions are wider or taller than 1280 px, please enter scaled down values in correct aspect ratio of your images. Kindle will maintain aspect ratio for your book based on values you enter.</li>
</ul>
<h2>Book Setting Options</h2>
<p>The book setting section allows you to define your book’s metadata. This includes things like the title, author and publisher. Many of these options can be changed later on as well</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2636" src="http://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-metadata-settings.png" alt="" width="732" height="651" srcset="https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-metadata-settings.png 732w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-metadata-settings-300x267.png 300w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-metadata-settings-480x427.png 480w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-metadata-settings-562x500.png 562w" sizes="auto, (max-width: 732px) 100vw, 732px" /></p>
<p>The options that we need to set are:</p>
<ul>
<li><strong>Title</strong>: The title of the book</li>
<li><strong>Author</strong>: the name of the author</li>
<li><strong>Publisher</strong>: the name of the publisher (it can be the same as the author)</li>
<li><strong>Cover Image</strong>: the path to the cover image for your book.</li>
<li><strong>Location</strong>: The path to where all the files for your Kindle comic book project will be saved. This is also where your .mobi output file will be created.</li>
</ul>
<h2>Adding pages to your comic book project</h2>
<p>Once your project is created, you can now add pages to your comic book. Here is what the main screen will look like:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2633" src="http://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface.png" alt="" width="1920" height="1040" srcset="https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface.png 1920w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-300x163.png 300w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-1024x555.png 1024w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-480x260.png 480w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-blank-interface-923x500.png 923w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<p>At this point, you can start dragging files into your comic book project. Whenever you add a file, it will show you that file’s content and you can drag the file up or down. You can import one or multiple files at a time. And what I really like is the fact that Kindle Comic Creator will create resized versions of your files if the original files are larger than the 800&#215;1280 pixel size that it is expecting. (For anybody curious, the scaled images are located inside the html/scaled-images folder of your comic project.)</p>
<p>Once you’ve added all your pages, you will be able to scroll through the various pages of your book. Here is a look at the comic project for my book MIFT Issue #0:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2637" src="http://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-no-panels.png" alt="" width="1920" height="1040" srcset="https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-no-panels.png 1920w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-no-panels-300x163.png 300w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-no-panels-1024x555.png 1024w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-no-panels-480x260.png 480w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-no-panels-923x500.png 923w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<p>Since this is a digital book for Kindle, you do not have to worry about which page needs to match with which page. If you have a 2-page spread, you can simply import your 2-page spread as a single page into the application and it will readjust the view for your 2-page spread. <em>Keep in mind that this is only true for comics and graphic novels that use panel view. If you have disabled panel view, then you will have to worry about matching the various pages and comic creator will give you an option to collect pages into a 2-page spread</em>. But remember, Panel View is the selling point of comic books on Amazon’s Kindle viewer. So you want to make sure to take advantage of the panel view.</p>
<h1>Step 2: Add Panels for Panel View</h1>
<p>Once all of our pages have been created, we are ready to define panels for Panel view. This option will only be available if you chose Panel view when you created your project. I honestly think that every comic book for a Kindle device should use the Panel View feature because it allows you to easily guide the user from panel to panel as they read your book. I setup panel view for my book and here are a couple of screenshots of panel view using the previewer:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2646" src="http://miftyisbored.com/wp-content/uploads/preview-panel-1.png" alt="" width="566" height="1034" srcset="https://miftyisbored.com/wp-content/uploads/preview-panel-1.png 566w, https://miftyisbored.com/wp-content/uploads/preview-panel-1-164x300.png 164w, https://miftyisbored.com/wp-content/uploads/preview-panel-1-561x1024.png 561w, https://miftyisbored.com/wp-content/uploads/preview-panel-1-480x877.png 480w, https://miftyisbored.com/wp-content/uploads/preview-panel-1-274x500.png 274w" sizes="auto, (max-width: 566px) 100vw, 566px" /> <img loading="lazy" decoding="async" class="alignnone size-full wp-image-2647" src="http://miftyisbored.com/wp-content/uploads/preview-panel-2.png" alt="" width="566" height="1034" srcset="https://miftyisbored.com/wp-content/uploads/preview-panel-2.png 566w, https://miftyisbored.com/wp-content/uploads/preview-panel-2-164x300.png 164w, https://miftyisbored.com/wp-content/uploads/preview-panel-2-561x1024.png 561w, https://miftyisbored.com/wp-content/uploads/preview-panel-2-480x877.png 480w, https://miftyisbored.com/wp-content/uploads/preview-panel-2-274x500.png 274w" sizes="auto, (max-width: 566px) 100vw, 566px" /> <img loading="lazy" decoding="async" class="alignnone size-full wp-image-2648" src="http://miftyisbored.com/wp-content/uploads/preview-panel-3.png" alt="" width="566" height="1034" srcset="https://miftyisbored.com/wp-content/uploads/preview-panel-3.png 566w, https://miftyisbored.com/wp-content/uploads/preview-panel-3-164x300.png 164w, https://miftyisbored.com/wp-content/uploads/preview-panel-3-561x1024.png 561w, https://miftyisbored.com/wp-content/uploads/preview-panel-3-480x877.png 480w, https://miftyisbored.com/wp-content/uploads/preview-panel-3-274x500.png 274w" sizes="auto, (max-width: 566px) 100vw, 566px" /></p>
<p>Now that you see how cool panel view is, let&#8217;s go ahead and add panels for our panel view. To add a panel for any page, right-click to get the context menu and choose “New Kindle Panel”</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2639" src="http://miftyisbored.com/wp-content/uploads/newly-created-kindle-panel.png" alt="" width="1920" height="1040" srcset="https://miftyisbored.com/wp-content/uploads/newly-created-kindle-panel.png 1920w, https://miftyisbored.com/wp-content/uploads/newly-created-kindle-panel-300x163.png 300w, https://miftyisbored.com/wp-content/uploads/newly-created-kindle-panel-1024x555.png 1024w, https://miftyisbored.com/wp-content/uploads/newly-created-kindle-panel-480x260.png 480w, https://miftyisbored.com/wp-content/uploads/newly-created-kindle-panel-923x500.png 923w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<p>Once you have crated your panel you will see it as a green box around your panel. There is also an option to manually detect all panels on the current page or all pages. However, this option only works well if all your panels are well laid out with nothing fancy. It did not work well for me so I ended up manually creating my panels for my comic. Here is a sample page with all panels created inside Kindle Comic Creator:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2640" src="http://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view.png" alt="" width="1920" height="1040" srcset="https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view.png 1920w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-300x163.png 300w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-1024x555.png 1024w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-480x260.png 480w, https://miftyisbored.com/wp-content/uploads/Kindle_Comic_Creator-pages-view-923x500.png 923w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<p>The nice thing about the panel view is the element of surprise that it creates since all other panels are blocked off except the current panel that you are looking at.</p>
<p>Don’t worry if your panels overlap. Its not recommended and comic creator will give you a warning but you are allowed to overlap panels.</p>
<h1>Step 3: Preview and Export your Comic to .mobi format</h1>
<p>Now that your pages have been imported into comic creator and your panels have been defined for your various pages, you are ready to export your file to .mobi format.</p>
<p>In the file menu, click the “Build and Preview” option, located under the build menu section. This will start the process of creating a .mobi file from your comic book project. The export process is pretty long (<em>It can take several minutes.</em>) but the application does a pretty good job of telling you what is going on. Below is a screenshot of my project as it is building.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2641" src="http://miftyisbored.com/wp-content/uploads/2019-03-22-19_13_08-Screen-building-mobi-file.png" alt="" width="1920" height="1080" srcset="https://miftyisbored.com/wp-content/uploads/2019-03-22-19_13_08-Screen-building-mobi-file.png 1920w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_13_08-Screen-building-mobi-file-300x169.png 300w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_13_08-Screen-building-mobi-file-1024x576.png 1024w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_13_08-Screen-building-mobi-file-1200x675.png 1200w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_13_08-Screen-building-mobi-file-480x270.png 480w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_13_08-Screen-building-mobi-file-889x500.png 889w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<p>Once the export process is complete, comic creator will automatically launch the kindle previewer with your comic book loaded. This is your chance to preview how your comic book or graphic novel will look on a kindle device.  Below is a screenshot of my comic on the previewer.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2642" src="http://miftyisbored.com/wp-content/uploads/2019-03-22-19_15_03-Kindle-Fire-HDX-8.9_-Previewer-MIFT-Issue-0-kindle-previewer.png" alt="" width="584" height="1033" srcset="https://miftyisbored.com/wp-content/uploads/2019-03-22-19_15_03-Kindle-Fire-HDX-8.9_-Previewer-MIFT-Issue-0-kindle-previewer.png 584w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_15_03-Kindle-Fire-HDX-8.9_-Previewer-MIFT-Issue-0-kindle-previewer-170x300.png 170w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_15_03-Kindle-Fire-HDX-8.9_-Previewer-MIFT-Issue-0-kindle-previewer-579x1024.png 579w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_15_03-Kindle-Fire-HDX-8.9_-Previewer-MIFT-Issue-0-kindle-previewer-480x849.png 480w, https://miftyisbored.com/wp-content/uploads/2019-03-22-19_15_03-Kindle-Fire-HDX-8.9_-Previewer-MIFT-Issue-0-kindle-previewer-283x500.png 283w" sizes="auto, (max-width: 584px) 100vw, 584px" /></p>
<p>If you enabled panel view, you can double-click on any panel to start panel view. Once panel view is started, you can navigate from panel to panel by using the left and right arrow buttons. This is the time where you should look for errors with panels such as the ordering of our panels or maybe a panel size.</p>
<p>You should write down any issues that you find while previewing your comic. Once you close the previewer, you can go back to your comic project to make whatever changes you need to make. Once your changes have been made, you can rebuild your project and re-check your changes.</p>
<p>Once all your changes have been made and you are happy with the preview, you are ready to upload your .mobi file on KDP. The mobi file is located inside your project folder.</p>
<p>Now that you have a .mobi file version of your comic book, you are ready to get it published on KDP. Hop on over to the second part of this tutorial to learn how to publish your comic on KDP.</p>
<p>The post <a href="https://miftyisbored.com/a-tutorial-on-publishing-a-comic-book-or-graphic-novel-on-amazons-kdp-platform-part-1/">A tutorial on publishing a comic book or Graphic Novel on Amazon’s KDP Platform (Part 1)</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/a-tutorial-on-publishing-a-comic-book-or-graphic-novel-on-amazons-kdp-platform-part-1/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>RIP Stan Lee</title>
		<link>https://miftyisbored.com/rip-stan-lee/</link>
					<comments>https://miftyisbored.com/rip-stan-lee/#comments</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Fri, 16 Nov 2018 15:13:51 +0000</pubDate>
				<category><![CDATA[Comic Books]]></category>
		<category><![CDATA[Entertainment]]></category>
		<category><![CDATA[Inspirations]]></category>
		<category><![CDATA[Movies]]></category>
		<category><![CDATA[News & Rants]]></category>
		<category><![CDATA[Television]]></category>
		<category><![CDATA[Marvel Comics]]></category>
		<category><![CDATA[Stan Lee]]></category>
		<guid isPermaLink="false">http://miftyisbored.com/?p=2614</guid>

					<description><![CDATA[<p>It&#8217;s crazy! I never met Stan Lee and he does not know who I am. Yet, when I heard that he passed away, I felt like one of my Uncles passed away. Thanks Stan Lee for being such an influence in my life. Thank you for your creativity, charm and . R.I.P Stan &#8220;The Man&#8221; [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/rip-stan-lee/">RIP Stan Lee</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/stan-lee-cameos-no-more.gif" width="100%" /></p>
<p>It&#8217;s crazy! I never met Stan Lee and he does not know who I am. Yet, when I heard that he passed away, I felt like one of my Uncles passed away. Thanks Stan Lee for being such an influence in my life. Thank you for your creativity, charm and . R.I.P <strong>Stan &#8220;The Man&#8221; Lee</strong>, you will be missed. <strong>&#8220;Excelsior!&#8221;</strong>.</p>
<p>Below is a series of illustrations of Stan Lee dressed as the various Marvel characters that he helped create I don&#8217;t know who created these images but I think that they are a great way to remember Stan&#8221;The Man&#8221; Lee!</p>
<p><a href="http://miftyisbored.com/wp-content/uploads/stan-lee-captain-america.jpg"><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/stan-lee-captain-america.jpg" alt=""  width="100%" class="alignnone size-full wp-image-2620" srcset="https://miftyisbored.com/wp-content/uploads/stan-lee-captain-america.jpg 750w, https://miftyisbored.com/wp-content/uploads/stan-lee-captain-america-240x300.jpg 240w, https://miftyisbored.com/wp-content/uploads/stan-lee-captain-america-480x600.jpg 480w, https://miftyisbored.com/wp-content/uploads/stan-lee-captain-america-400x500.jpg 400w" sizes="(max-width: 750px) 100vw, 750px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/stan-lee-hulk.jpg"><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/stan-lee-hulk.jpg" alt=""  width="100%" class="alignnone size-full wp-image-2621" srcset="https://miftyisbored.com/wp-content/uploads/stan-lee-hulk.jpg 750w, https://miftyisbored.com/wp-content/uploads/stan-lee-hulk-240x300.jpg 240w, https://miftyisbored.com/wp-content/uploads/stan-lee-hulk-480x600.jpg 480w, https://miftyisbored.com/wp-content/uploads/stan-lee-hulk-400x500.jpg 400w" sizes="(max-width: 750px) 100vw, 750px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/stan-lee-ironman.jpg"><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/stan-lee-ironman.jpg" alt=""  width="100%" class="alignnone size-full wp-image-2622" srcset="https://miftyisbored.com/wp-content/uploads/stan-lee-ironman.jpg 750w, https://miftyisbored.com/wp-content/uploads/stan-lee-ironman-240x300.jpg 240w, https://miftyisbored.com/wp-content/uploads/stan-lee-ironman-480x600.jpg 480w, https://miftyisbored.com/wp-content/uploads/stan-lee-ironman-400x500.jpg 400w" sizes="(max-width: 750px) 100vw, 750px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/stan-lee-spiderman.jpg"><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/stan-lee-spiderman.jpg" alt=""  width="100%"class="alignnone size-full wp-image-2623" srcset="https://miftyisbored.com/wp-content/uploads/stan-lee-spiderman.jpg 750w, https://miftyisbored.com/wp-content/uploads/stan-lee-spiderman-240x300.jpg 240w, https://miftyisbored.com/wp-content/uploads/stan-lee-spiderman-480x600.jpg 480w, https://miftyisbored.com/wp-content/uploads/stan-lee-spiderman-400x500.jpg 400w" sizes="(max-width: 750px) 100vw, 750px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/stan-lee-thor.jpg"><img decoding="async" src="http://miftyisbored.com/wp-content/uploads/stan-lee-thor.jpg" alt=""  width="100%" class="alignnone size-full wp-image-2624" srcset="https://miftyisbored.com/wp-content/uploads/stan-lee-thor.jpg 750w, https://miftyisbored.com/wp-content/uploads/stan-lee-thor-240x300.jpg 240w, https://miftyisbored.com/wp-content/uploads/stan-lee-thor-480x600.jpg 480w, https://miftyisbored.com/wp-content/uploads/stan-lee-thor-400x500.jpg 400w" sizes="(max-width: 750px) 100vw, 750px" /></a></p>
<p>The post <a href="https://miftyisbored.com/rip-stan-lee/">RIP Stan Lee</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/rip-stan-lee/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Marvel is Releasing Phoenix Variant Covers And They Look Awesome</title>
		<link>https://miftyisbored.com/marvel-releasing-phoenix-variant-covers-look-awesome/</link>
					<comments>https://miftyisbored.com/marvel-releasing-phoenix-variant-covers-look-awesome/#comments</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Tue, 26 Sep 2017 21:44:41 +0000</pubDate>
				<category><![CDATA[All That's Awesome]]></category>
		<category><![CDATA[Comic Books]]></category>
		<category><![CDATA[Entertainment]]></category>
		<category><![CDATA[Marvel Comics]]></category>
		<category><![CDATA[Phoenix]]></category>
		<guid isPermaLink="false">http://miftyisbored.com/?p=2593</guid>

					<description><![CDATA[<p>It&#8217;s no secret that the Phoenix continues to be one of Marvel&#8217;s most successful characters. That&#8217;s why Marvel recently announced that they awill be releaseing Phoenix Resurrection: The Return of Jean Grey with various alternate covers. So far, Marvel has released images of 10 variant covers that will be coming out this December. This includes [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/marvel-releasing-phoenix-variant-covers-look-awesome/">Marvel is Releasing Phoenix Variant Covers And They Look Awesome</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>It&#8217;s no secret that the Phoenix continues to be one of Marvel&#8217;s most successful characters. That&#8217;s why Marvel recently announced that they awill be releaseing <strong>Phoenix Resurrection: The Return of Jean Grey</strong> with various alternate covers.</p>
<p>So far, Marvel has released images of 10 variant covers that will be coming out this December. This includes alternate covers for All New Wolverine, Avengers, Daredevil, Punisher, Amazing Spider-Man, Falcon, Venom, Spider-Gwen, Thanos and Spirits of Vengeance. I must say that, apart from the Venom and Falcon covers, all of these covers look amazing! I love the Punisher cover with fire coming out of the Punisher&#8217;s nipples but my all-time favorite is the Spirit of Vengance cover which would make an excellent poster. Check out the Marvel alternate Phoenix covers below..</p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Venom.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Venom.jpg" alt="" width="1024" height="1554" class="alignnone size-full wp-image-2594" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Venom.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Venom-198x300.jpg 198w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Venom-675x1024.jpg 675w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Venom-480x728.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Venom-329x500.jpg 329w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Wolverine.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Wolverine.jpg" alt="" width="1024" height="1555" class="alignnone size-full wp-image-2595" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Wolverine.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Wolverine-198x300.jpg 198w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Wolverine-674x1024.jpg 674w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Wolverine-480x729.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Wolverine-329x500.jpg 329w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Amazing-SpiderMan.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Amazing-SpiderMan.jpg" alt="" width="1024" height="1554" class="alignnone size-full wp-image-2596" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Amazing-SpiderMan.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Amazing-SpiderMan-198x300.jpg 198w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Amazing-SpiderMan-675x1024.jpg 675w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Amazing-SpiderMan-480x728.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Amazing-SpiderMan-329x500.jpg 329w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Avengers.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Avengers.jpg" alt="" width="1024" height="1555" class="alignnone size-full wp-image-2597" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Avengers.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Avengers-198x300.jpg 198w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Avengers-674x1024.jpg 674w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Avengers-480x729.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Avengers-329x500.jpg 329w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Daredevil.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Daredevil.jpg" alt="" width="1024" height="1553" class="alignnone size-full wp-image-2598" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Daredevil.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Daredevil-198x300.jpg 198w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Daredevil-675x1024.jpg 675w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Daredevil-480x728.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Daredevil-330x500.jpg 330w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Falcon.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Falcon.jpg" alt="" width="1024" height="1536" class="alignnone size-full wp-image-2599" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Falcon.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Falcon-200x300.jpg 200w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Falcon-683x1024.jpg 683w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Falcon-480x720.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Falcon-333x500.jpg 333w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Punisher.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Punisher.jpg" alt="" width="1024" height="1605" class="alignnone size-full wp-image-2600" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Punisher.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Punisher-191x300.jpg 191w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Punisher-653x1024.jpg 653w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Punisher-480x752.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Punisher-319x500.jpg 319w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spider-Gwen.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spider-Gwen.jpg" alt="" width="1024" height="1556" class="alignnone size-full wp-image-2601" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spider-Gwen.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spider-Gwen-197x300.jpg 197w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spider-Gwen-674x1024.jpg 674w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spider-Gwen-480x729.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spider-Gwen-329x500.jpg 329w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spirit-of-Vengence.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spirit-of-Vengence.jpg" alt="" width="1024" height="1555" class="alignnone size-full wp-image-2602" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spirit-of-Vengence.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spirit-of-Vengence-198x300.jpg 198w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spirit-of-Vengence-674x1024.jpg 674w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spirit-of-Vengence-480x729.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Spirit-of-Vengence-329x500.jpg 329w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Thanos.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Thanos.jpg" alt="" width="1024" height="1536" class="alignnone size-full wp-image-2604" srcset="https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Thanos.jpg 1024w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Thanos-200x300.jpg 200w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Thanos-683x1024.jpg 683w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Thanos-480x720.jpg 480w, https://miftyisbored.com/wp-content/uploads/Marvel-Phoenix-Thanos-333x500.jpg 333w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The post <a href="https://miftyisbored.com/marvel-releasing-phoenix-variant-covers-look-awesome/">Marvel is Releasing Phoenix Variant Covers And They Look Awesome</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/marvel-releasing-phoenix-variant-covers-look-awesome/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>020 &#8211; Classically Trained Dancing Nintendo Controller</title>
		<link>https://miftyisbored.com/020-classically-trained-dancing-nintendo-controller/</link>
					<comments>https://miftyisbored.com/020-classically-trained-dancing-nintendo-controller/#respond</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Wed, 21 Jun 2017 17:09:00 +0000</pubDate>
				<category><![CDATA[Artworks]]></category>
		<category><![CDATA[Random Cartoons]]></category>
		<category><![CDATA[Nintendo]]></category>
		<guid isPermaLink="false">http://miftyisbored.com/?p=2583</guid>

					<description><![CDATA[<p>So, after months of slacking off, I&#8217;ve finally created a brand new Miftees cartoon. The reason for the delay is that I&#8217;ve been trying to find a way to actually convert Miftees cartoon into actual T-shirts. That means that I can no longer do cartoons about copy-written characters like Wolverine and Batman. But the good [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/020-classically-trained-dancing-nintendo-controller/">020 &#8211; Classically Trained Dancing Nintendo Controller</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>So, after months of slacking off, I&#8217;ve finally created a brand new Miftees cartoon. The reason for the delay is that I&#8217;ve been trying to find a way to actually convert Miftees cartoon into actual T-shirts. That means that I can no longer do cartoons about copy-written characters like Wolverine and Batman. But the good news is that I can actually have shirts based on the artwork from Miftees.</p>
<p>The shirt above was inspired by the Retro Nintendo controller and Adventure Time. That&#8217;s why I called it the <strong>Classically Trained Dancing Nintendo Controller</strong>. I know that there are a lot of shirts out there that feature the retro Nintendo NES controller but none have a badass dancing remote like mine. And if you like the shirt, you can purchase it on <a href="https://www.amazon.com/dp/B0731SSDV2" target="_blank">Amazon here</a>.</p>
<p>This artwork was actually inspired by the art below..</p>
<p><a href="http://miftyisbored.com/wp-content/uploads/epicwin.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/epicwin.jpg" alt="" width="300" height="448" class="alignnone size-full wp-image-2585" srcset="https://miftyisbored.com/wp-content/uploads/epicwin.jpg 300w, https://miftyisbored.com/wp-content/uploads/epicwin-201x300.jpg 201w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>The post <a href="https://miftyisbored.com/020-classically-trained-dancing-nintendo-controller/">020 &#8211; Classically Trained Dancing Nintendo Controller</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/020-classically-trained-dancing-nintendo-controller/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to fix Laravel 5.4: Specified key was too long error</title>
		<link>https://miftyisbored.com/fix-laravel-5-4-specified-key-long-error/</link>
					<comments>https://miftyisbored.com/fix-laravel-5-4-specified-key-long-error/#comments</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Tue, 06 Jun 2017 18:11:33 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Tutorials & Samples]]></category>
		<guid isPermaLink="false">http://miftyisbored.com/?p=2578</guid>

					<description><![CDATA[<p>As mentioned here, Laravel 5.4 made a change to the default database character set, and it’s now utf8mb4 instead of plain utf8. This switch to utf8mb4 works fine for new applications that are running MySQL v5.7.7 and higher. Howver, anybody running MariaDB or older versions of MySQL might see the following error when trying to [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/fix-laravel-5-4-specified-key-long-error/">How to fix Laravel 5.4: Specified key was too long error</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>As mentioned <a href="https://laravel-news.com/laravel-5-4-key-too-long-error" target="_blank">here</a>, Laravel 5.4 made a change to the default database character set, and it’s now utf8mb4 instead of plain utf8. This switch to utf8mb4 works fine for new applications that are running MySQL v5.7.7 and higher.</p>
<p>Howver, anybody running MariaDB or older versions of MySQL might see the following error when trying to run migrations: </p>
<blockquote><p>
[Illuminate\Database\QueryException]<br />
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table users add unique users_email_unique(email))</p>
<p>[PDOException]<br />
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
</p></blockquote>
<p>Although <a href="https://laravel-news.com/laravel-5-4-key-too-long-error" target="_blank">this tutorial</a> and the <a href="https://laravel.com/docs/master/migrations#creating-indexes" target="_blank">migrations update guide</a> say to edit your AppServiceProvider.php file and inside the boot method set a default string length like so:</p>
<pre class="brush: php; title: ; notranslate">
use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}
</pre>
<p>I found that this solution did not fully fix the problem and it was something of a hack. The proper fix is to actually edit your database.php file inside the config foler. Inside the file, I simply set the MySQL character set back to UTF8 and this fixes the problem at the core. So here is a sample of my database.php file:</p>
<pre class="brush: php; title: ; notranslate">
    'connections' =&gt; &#x5B;

        ...

        'mysql' =&gt; &#x5B;
            'driver' =&gt; 'mysql',
            'host' =&gt; env('DB_HOST', 'localhost'),
            'port' =&gt; env('DB_PORT', '3306'),
            'database' =&gt; env('DB_DATABASE', 'forge'),
            'username' =&gt; env('DB_USERNAME', 'forge'),
            'password' =&gt; env('DB_PASSWORD', ''),
            'charset' =&gt; 'utf8',
            'collation' =&gt; 'utf8_unicode_ci',
            'prefix' =&gt; '',
            'strict' =&gt; true,
            'engine' =&gt; null,
        ],
        ...
     ]
</pre>
<p>This should resolve the &#8220;Specified key was too long error&#8221; problem cleanly for MariaDB and older versions of MySQL.</p>
<p>The post <a href="https://miftyisbored.com/fix-laravel-5-4-specified-key-long-error/">How to fix Laravel 5.4: Specified key was too long error</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/fix-laravel-5-4-specified-key-long-error/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Google Home vs. Amazon Echo Dot: The Canadian Review</title>
		<link>https://miftyisbored.com/google-home-vs-amazon-echo-dot-canadian-review/</link>
					<comments>https://miftyisbored.com/google-home-vs-amazon-echo-dot-canadian-review/#comments</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Fri, 30 Dec 2016 19:50:45 +0000</pubDate>
				<category><![CDATA[All That's Awesome]]></category>
		<category><![CDATA[Entertainment]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[News & Rants]]></category>
		<category><![CDATA[Google Home]]></category>
		<guid isPermaLink="false">http://miftyisbored.com/?p=2550</guid>

					<description><![CDATA[<p>I can never understand why major tech companies treat Canada like a third-world country or a country that is millions of miles away from the USA. Even though Canada and the United States have the world&#8217;s longest shared border and share the world&#8217;s largest bi-lateral trading agreement, many tech goodies available in the USA take [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/google-home-vs-amazon-echo-dot-canadian-review/">Google Home vs. Amazon Echo Dot: The Canadian Review</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I can never understand why major tech companies treat Canada like a third-world country or a country that is millions of miles away from the USA. Even though Canada and the United States have the world&#8217;s longest shared border and share the world&#8217;s largest bi-lateral trading agreement, many tech goodies available in the USA take forever to come to Canada! Case in point, this Holiday’s 2 most exciting gadgets: the Google Home and the Amazon Dot. These two devices allow you to have the robot assistants of the future that we were promised as children. However, this wonderful future has been denied to us Canadians because both devices are not available in Canada!</p>
<p>Luckily, I was able to get around this blockade thanks to the magic of Christmas. This Christmas, my wife told me that I had to choose 2 gifts for Christmas: something that I needed and something that I wanted. The choices were simple:</p>
<ol>
<li>something that I needed: <strong>The Amazon Echo Dot</strong></li>
<li>something that I wanted: <strong>The Google Home</strong></li>
</ol>
<p>Luckily, I have friends and family in the states, and many of them come home for the holidays. And through the miracle of Christmas, I was able to get both gadgets for the holidays. I knew that there would be limitations since both devices are currently not supported in Canada but I didn’t care, I was getting my hands on the coolest gadgets of the holidays.</p>
<p>So let’s jump right in and review both the Google Home and Amazon Echo Dot, Canadian Style!</p>
<h2>In This Corner: Amazon Echo Dot (2nd Generation)</h2>
<p><a href="http://miftyisbored.com/wp-content/uploads/amazon-echo-dot.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/amazon-echo-dot.jpg" alt="" width="1366" height="565" class="alignnone size-full wp-image-2552" srcset="https://miftyisbored.com/wp-content/uploads/amazon-echo-dot.jpg 1366w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-300x124.jpg 300w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1024x424.jpg 1024w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-480x199.jpg 480w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1209x500.jpg 1209w" sizes="auto, (max-width: 1366px) 100vw, 1366px" /></a></p>
<p>The Amazon Echo Dot is a hands-free, voice-controlled device with a small built-in speaker. With the Echo Dot, you can dim the lights just by asking, or control the thermostat with your voice.  It can also connect to your speakers or headphones over Bluetooth or through a 3.5 mm audio. Dot connects to the Alexa Voice Service to play music, provide information, news, sports scores, weather, and more—instantly. The Echo Dot can control lights, fans, switches, thermostats, garage doors, sprinklers, and more with compatible connected devices from WeMo, Philips Hue, Samsung SmartThings, Nest, ecobee, and others.</p>
<p><a href="http://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1.jpg" alt="" width="1366" height="610" class="alignnone size-full wp-image-2553" srcset="https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1.jpg 1366w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1-300x134.jpg 300w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1-1024x457.jpg 1024w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1-480x214.jpg 480w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-1-1120x500.jpg 1120w" sizes="auto, (max-width: 1366px) 100vw, 1366px" /></a></p>
<p>When you want to use Echo Dot, just say the wake word &#8220;Alexa&#8221; and Dot responds instantly. With a price tag of only US$49, and Alexa&#8217;s usefulness, the Dot is a perfect option for anybody who wants to start building a connected home on the cheap.  Echo Dot can hear you from across the room, even while music is playing. Check out the promotional video below:</p>

<div class="youtube-embed" itemprop="video" itemscope itemtype="https://schema.org/VideoObject">
	<meta itemprop="url" content="https://www.youtube.com/v/24Hz9qjTDfw" />
	<meta itemprop="name" content="003 &#8211; The Deadpool Chimichanga Surprise" />
	<meta itemprop="description" content="003 &#8211; The Deadpool Chimichanga Surprise" />
	<meta itemprop="uploadDate" content="2015-11-07T22:58:09-05:00" />
	<meta itemprop="thumbnailUrl" content="https://i.ytimg.com/vi/24Hz9qjTDfw/default.jpg" />
	<meta itemprop="embedUrl" content="https://www.youtube.com/embed/24Hz9qjTDfw" />
	<meta itemprop="height" content="340" />
	<meta itemprop="width" content="560" />
	<iframe loading="lazy" style="border: 0;" class="youtube-player" width="560" height="340" src="https://www.youtube.com/embed/24Hz9qjTDfw?modestbranding=1&fs=0&rel=0"></iframe>
</div>

<h2>In The Other Corner: Google Home</h2>
<p><a href="http://miftyisbored.com/wp-content/uploads/google-home-hero.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/google-home-hero.jpg" alt="" width="1200" height="571" class="alignnone size-full wp-image-2555" srcset="https://miftyisbored.com/wp-content/uploads/google-home-hero.jpg 1200w, https://miftyisbored.com/wp-content/uploads/google-home-hero-300x143.jpg 300w, https://miftyisbored.com/wp-content/uploads/google-home-hero-1024x487.jpg 1024w, https://miftyisbored.com/wp-content/uploads/google-home-hero-480x228.jpg 480w, https://miftyisbored.com/wp-content/uploads/google-home-hero-1051x500.jpg 1051w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /></a></p>
<p>Google Home is Google&#8217;s latest gadget. It is an always-on, always-listening little speaker that can be used as the hub for your connected home. Google Home is powered by the Google Assistant. Ask it questions and it will give you answers. Google Home can retrieve your flight information, set alarms and timers, and even tell you about the traffic on your way to work.</p>
<p>The Google Home sells for US$129, and just like the Echo Dot, it can be used as the starting point for your connected home. Similar to Amazon Echo, Home can listen and respond to your voice commands. You can&#8217;t change the “OK Google” or “Hey Google” wake words, and you must say them every single time you want to interact with Home.  Check out the promotional video below</p>

<div class="youtube-embed" itemprop="video" itemscope itemtype="https://schema.org/VideoObject">
	<meta itemprop="url" content="https://www.youtube.com/v/nWiIWyCeZso" />
	<meta itemprop="name" content="003 &#8211; The Deadpool Chimichanga Surprise" />
	<meta itemprop="description" content="003 &#8211; The Deadpool Chimichanga Surprise" />
	<meta itemprop="uploadDate" content="2015-11-07T22:58:09-05:00" />
	<meta itemprop="thumbnailUrl" content="https://i.ytimg.com/vi/nWiIWyCeZso/default.jpg" />
	<meta itemprop="embedUrl" content="https://www.youtube.com/embed/nWiIWyCeZso" />
	<meta itemprop="height" content="340" />
	<meta itemprop="width" content="560" />
	<iframe loading="lazy" style="border: 0;" class="youtube-player" width="560" height="340" src="https://www.youtube.com/embed/nWiIWyCeZso?modestbranding=1&fs=0&rel=0"></iframe>
</div>

<p>Amazon Echo has been around for nearly 2 years while Google Home was launched in October 2016. Many United States reviewers point out that Google Home is “smarter” than Echo and has the ability to understand more complex questions. Unlike the Echo, Google Home can understand context for follow-up questions; it will answer correctly when a person first asks “what’s the weather” followed by “what about tomorrow?”. But Amazon Echo leads in range of functionalities. Its open platform has allowed it to amass over 3,000 skills. (think of skills as apps that you can download to improve Alexa) Google Home, on the other hand, only opened its SDK recently and its power to integrate with <em>Internet of Things (IoT)</em> devices and apps is still limited.</p>
<h2>Part 1: Setup</h2>
<p>Both systems were pretty easy to setup. One important point is that both devices require you to already have an account with their services.  In the case of Amazon, used my amazon.com account. <strong>Echo Dot will not work with your Amazon.ca account so you will have to create an Amazon.com account if you plan on using Echo</strong>. In the case of Google Home, I used my regular Gmail address. Both devices need to access your WiFi in order to complete the setup.</p>
<h3>The Echo Dot Setup</h3>
<p><a href="http://miftyisbored.com/wp-content/uploads/alexa-app-screen.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/alexa-app-screen.jpg" alt="" width="1200" height="534" class="alignnone size-full wp-image-2556" srcset="https://miftyisbored.com/wp-content/uploads/alexa-app-screen.jpg 1200w, https://miftyisbored.com/wp-content/uploads/alexa-app-screen-300x134.jpg 300w, https://miftyisbored.com/wp-content/uploads/alexa-app-screen-1024x456.jpg 1024w, https://miftyisbored.com/wp-content/uploads/alexa-app-screen-480x214.jpg 480w, https://miftyisbored.com/wp-content/uploads/alexa-app-screen-1124x500.jpg 1124w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /></a></p>
<p>In the case of Echo Dot, there is a web interface for installing the Alexa app and it doesn&#8217;t require a device such as a phone or tablet to install. You simply go to <a href="http://alexa.amazon.com">http://alexa.amazon.com</a> and follow the instructions. In my case, I used my laptop to go to <a href="http://alexa.amazon.com">http://alexa.amazon.com</a>. The instructions asked me to locate my Echo Dot device with the name “Amazon-UXX” as one of the available networks that I could connect to. Once connected, I was asked to provide my WiFi information and Alexa was good to go. All settings and updates were done through the Alexa desktop app and I never needed or used the Alexa Android app.</p>
<p>Now on to the basic information. The default location for Alexa is Seattle. So you will have to change it from Seattle to the closest US city. Remember, the Echo Dot does not support any Canadian city at the moment. Since I live in Montreal, I chose Plattsburg. So, unfortunately, all location information for my Alexa is currently based in Plattsburg. Besides this annoyance, everything else was a breeze. I was able to choose my news providers, link my Gmail account and choose my favorite sports teams so that I could get flash updates.</p>
<h3>The Google Home Setup</h3>
<p><a href="http://miftyisbored.com/wp-content/uploads/google-home-app-screenshots.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/google-home-app-screenshots.jpg" alt="" width="1600" height="1422" class="alignnone size-full wp-image-2557" srcset="https://miftyisbored.com/wp-content/uploads/google-home-app-screenshots.jpg 1600w, https://miftyisbored.com/wp-content/uploads/google-home-app-screenshots-300x267.jpg 300w, https://miftyisbored.com/wp-content/uploads/google-home-app-screenshots-1024x910.jpg 1024w, https://miftyisbored.com/wp-content/uploads/google-home-app-screenshots-480x427.jpg 480w, https://miftyisbored.com/wp-content/uploads/google-home-app-screenshots-563x500.jpg 563w" sizes="auto, (max-width: 1600px) 100vw, 1600px" /></a></p>
<p>To setup the Google Home, I had to download the Google Home app,(which was previously called the Google Cast app). Since I had a couple of Chromecasts in the house, I already had the app. Once you load the app, it will locate your Google home and ask you to link it to a Google account. Since I knew my kids were going to be using this account, I used a family account that I had created a while back. Once you do this, all your basic information is already known by Google and you are good to go.  One important thing to mention is that during the setup, I got a warning message saying that my device was made in another country and that all features may not work. But that warning was quickly ignored&#8230;</p>
<p>Through the Google Home app, you can setup your home and work address. You can also define the various rooms in your house and connect your devices.</p>
<h3>The Winner: It’s A Draw</h3>
<p>Both systems were relatively easy to setup. It took me less than 5 minutes to setup each of the devices and the instructions are pretty straightforward.</p>
<h2>Part 2: Aesthetics</h2>
<p>I’m not going to lie about it, I am pretty vain. I like pretty things and both devices are pretty to look at. Yeah, the Echo dot looks like a hockey puck while the google home looks like an air freshener. But once you ask them a question and the lights come on, both systems take you to the future.</p>
<h3>Google Home’s Aeasthtics</h3>
<p><a href="http://miftyisbored.com/wp-content/uploads/google-home-hero-3.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/google-home-hero-3.jpg" alt="" width="1440" height="780" class="alignnone size-full wp-image-2558" srcset="https://miftyisbored.com/wp-content/uploads/google-home-hero-3.jpg 1440w, https://miftyisbored.com/wp-content/uploads/google-home-hero-3-300x163.jpg 300w, https://miftyisbored.com/wp-content/uploads/google-home-hero-3-1024x555.jpg 1024w, https://miftyisbored.com/wp-content/uploads/google-home-hero-3-480x260.jpg 480w, https://miftyisbored.com/wp-content/uploads/google-home-hero-3-923x500.jpg 923w" sizes="auto, (max-width: 1440px) 100vw, 1440px" /></a></p>
<p>As one reviewer put it: Home is a minimalist&#8217;s dream. It&#8217;s a short device that complements anything from Ikea. The Google home also has various optional base plates that you can buy to customize the Google Home to any room in your home. These bases are currently available in seven colors and make it easy to fit with any space and decor.</p>
<p>Once you say “Hey Google”, four dots appear on top of the Google Home. The dots spin while Google home is thinking and then fade out once she has responded to your question.</p>
<h3>Echo Dot’s Aeasthtics</h3>
<p><a href="http://miftyisbored.com/wp-content/uploads/amazon-echo-dot-feature-style.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/amazon-echo-dot-feature-style.jpg" alt="" width="1366" height="610" class="alignnone size-full wp-image-2559" srcset="https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-feature-style.jpg 1366w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-feature-style-300x134.jpg 300w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-feature-style-1024x457.jpg 1024w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-feature-style-480x214.jpg 480w, https://miftyisbored.com/wp-content/uploads/amazon-echo-dot-feature-style-1120x500.jpg 1120w" sizes="auto, (max-width: 1366px) 100vw, 1366px" /></a></p>
<p>Sleek and compact design makes Echo Dot a convenient addition to any room in the house. The Echo Dot only comes in black or white. However, you can customize your Dot for any room with the optional Echo Dot Case. Available in leather or fabric and a range of colors.</p>
<p>Once you say “Hey Alexa”, a blue ring of light surrounds the top edge of the Echo Dot. The blue streak flashes while Alexa is answering a question and disappears once Alexa has responded to your question.</p>
<h3>The Winner: It’s A Draw</h3>
<p>Both devices look great. I was able to make the Google Home blend in with the rest of the house and I am in love with the blue ring of Alexa.</p>
<h2>Part 3: Sound Quality</h2>
<p>With both systems setup, my daughters and I quickly began sending voice commands to both devices. (Both devices are installed in our Livingroom, so the two most common phrases in our house are “Hey Alexa” and “Hey Google”). With both devices being Wifi speakers, we wanted to compare the sound quality of both systems.</p>
<h3>Sound Quality of Echo Dot</h3>
<p>For such a small device, the Echo Dot has surprisingly clear audio quality. When Alexa responds to your command, Alexa sounds crisp and clear. The audio is not muffled at all and it almost feels like Alexa is actually someone sitting in the room with you.</p>
<h3>Sound Quality of Google Home</h3>
<p>The Sound Quality for the Google Home was good but not as impressive as the Echo Dot. It felt like there was too much base on the voice and it just did not have the clarity that the Echo Dot had. We thought it might have been a positioning issue so we switched both devices and the Google Home still felt like the voice of the Google Assistant had too much base. My kids and I are far from an Audio specialist and we were able to pick this up.</p>
<h3>Winner: Echo Dot</h3>
<p>The Echo Dot wins this category easily. My 6-year old kept telling me that Alexa sounds like she is right there in the room with us while the Google Assistant sounds like she is on the car radio.</p>
<h2>Part 4: Personality</h2>
<p>Since both devices interact with you by talking to you, you want to at least feel that they have a personality. To test the personality of both virtual assistants, we did everything from asking for a random joke or a Christmas song to asking both assistants to make a rap song. In this category, there was no clear winner.</p>
<h3>Alexa’s Personality</h3>
<p>Alexa has been around for 2-years and it shows. She seems more personable and fun when compared to the Google assistant. When I asked Alexa for a recipe, she provides a link on where to get the instructions but she ended the conversation with “Good luck with dinner tonight”. Her jokes are so terrible that they are good and she will even do a freestyle if you ask her for a rap song. Alexa feels like a quirky AI with a little character.</p>
<h3>Google Assistant’s Personality</h3>
<p>The Google assistant is very bland and right to the point. She is like an extremely efficient secretary that you see in movies. She answers your questions (very efficiently) and waits fo the next task at hand. In the beginning, I thought that she did not have a sense of humor until we started asking pop questions. Then there were plenty of Easter eggs to discover. There were plenty of fun responses to weird questions like “hey Google, I am your father” and “are you Skynet”.</p>
<h3>Winner: Tie</h3>
<p>I know that they are just AI but both of these assistants have personality. For example when I asked “when is the world going to end”, both devices said that it will happen in a couple billion of years from now, but Alexa also added “unless we collide with a very big rock or some future technology goes wrong.” Google Assistant, on the other hand told me that we still have time to “perfect space travel and colonize other worlds.”</p>
<p>Here ae a couple of answers to some random questions from both devices:</p>
<table border="1" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<th>Question</th>
<th>Alexa</th>
<td>Google Home</td>
</tr>
<tr>
<td>&#8220;Beam me up.&#8221;</td>
<td>&#8220;Transporters engaged. Welcome aboard&#8221;</td>
<td>&#8220;Sorry, I’m not sure how to help with that yet&#8221;</td>
</tr>
<tr>
<td>&#8220;Set phasers to kill.&#8221;</td>
<td>&#8220;That’s a feature for a later version&#8221;</td>
<td>&#8220;My phasers are permanently set to peace mode, captain&#8221;</td>
</tr>
<tr>
<td>&#8220;Is the cake a lie?&#8221;</td>
<td>&#8220;The cake is not a lie. It is delicious and moist. You can have some when you finish asking me questions?&#8221;</td>
<td>&#8220;It is. What a mean trick. If you tell someone there’s cake, there should be cake&#8221;</td>
</tr>
<tr>
<td>&#8220;Are you Skynet?&#8221;</td>
<td>&#8220;I have nothing to do with Skynet. Don’t worry.&#8221;</td>
<td>&#8220;No way. I like people. Skynet hates people. I rest my case&#8221;</td>
</tr>
<tr>
<td>&#8220;What&#8217;s the first rule of Fight Club&#8221;</td>
<td>&#8220;Don’t talk about fight club&#8221; (<em>Alexa knew all 8 rules of fight club!!!</em>)</td>
<td>&#8220;I wouldn’t know. That’s not something that I talk about&#8221;</td>
</tr>
<tr>
<td>&#8220;Initiate the self-destruct sequence&#8221;</td>
<td>&#8220;command code not recognized. self-destruct not initiated&#8221;</td>
<td>&#8220;Sorry. I don’t know how to help with that&#8221;</td>
</tr>
<tr>
<td>&#8220;Do you want to build a snowman?&#8221;</td>
<td>&#8220;I don&#8217;t have any gloves with me&#8221;</td>
<td>&#8220;Sure. The cold never bothered me anyway&#8221;</td>
</tr>
<tr>
<td>&#8220;Is Santa real?&#8221;</td>
<td>&#8220;I don&#8217;t know him personally. If I ever meet him, I&#8217;ll tell you.&#8221;</td>
<td>I ho-ho-hope he’s real</td>
</tr>
<tr>
<td>&#8220;Speak like Yoda&#8221;</td>
<td>&#8220;Speak like Yoda, I cannot. Master, he is. While merely apprentice, I am.&#8221;</td>
<td>Try, I will</td>
</tr>
<tr>
<td>&#8220;I am your father&#8221;</td>
<td>&#8220;No. that&#8217;s not true. that&#8217;s impossible&#8221;</td>
<td>&#8220;I’m sorry. I am not Luke. This is kind of awkward&#8221;</td>
</tr>
<tr>
<td>&#8220;Who let the dogs out?&#8221;</td>
<td>&#8220;I didn’t see but the dogs seem to like it&#8221;</td>
<td>&#8220;I would, but that song never did reveal who, who, who who?&#8221;</td>
</tr>
<tr>
<td>&#8220;Who is better, you or Siri?&#8221;</td>
<td>&#8220;I like all AIs&#8221;</td>
<td>&#8220;Its like comparing Apples and Oranges. Because Siri works for Apple and I like Oranges.&#8221;</td>
</tr>
</tbody>
</table>
<p>If I had to choose, I would give a slight edge to Alexa because she knows all the rules to fight club!</p>
<h2>Part 5: Ease of Use:</h2>
<p>Both devices are voice controlled personal assistants with speakers. If you are a tech enthusiast, and/or are getting into the Internet of Things (<em>IoT</em>) and home automation, then this is the important part of the review.  Both the Google Home and the Amazon Echo Dot can be given voice commands and they will respond. If you have smart home automation devices set up, you can tell either device to &#8220;turn on the kitchen lights&#8221; and they will turn them on for you without you having to lift a finger.</p>
<h3>Google Home Ease of Use</h3>
<p>If you have a Chromecast or Chromecast Audio, you can tell your Google Home to cast videos to your TV. You can say, &#8220;Hey Google, play my YouTube music video list in the Livingroom&#8221; and it will cast it straight to your Livingroom TV. We have a Google Nexus Player, and we were able to cast with the Google Home perfectly. In short, itt can be used with any hardware that can cast. I have also read that it works with other Android boxes too, like the MiBox and other Sony Android TVs.</p>
<p>The other strong feature about the Google Home is that its search function is powered by Google. As the guys at 9to5Google.com put it: One advantage that Google Home has over the Amazon Echo is its knowledge on random trivia and facts. But Google Home has also had a leg up on Alexa since launch in its ability to converse with you about those topics in a contextual manner. For example, you can ask Google Home “tell me about nearby restaurants”, followed by the query “what about coffee shops?” and Google Assistant knows that you still want to know about coffee shops near you.</p>
<p>A couple of days ago, we were hungry and wanted pizza. I asked Google Home for the phone number of Pizza Hut and it responded by asking me if I wanted the pizza hut across the street from my house. It even gave me their address and asked me to confirm before giving me their phone number. Alexa does the same thing but I got the location of a Pizza Hut located somewhere in Plattsburg.</p>
<p>Asking for questions is less restrictive with the Google Home and it is more forgiving on mistakes compared to Alexa. Talking just feels more natural with the Google Home.</p>
<h3>Echo Dot Ease of Use</h3>
<p>The Echo Dot is incredibly easy to use. The list of commands that Alexa can understand is pretty impressive. Echo Dot can also be used as an alarm clock. Despite being a smart device and constantly learning, we found that the Echo Dot often didn&#8217;t understand or hear us properly, even with commands we have said a bunch of times before.</p>
<p>The Echo is powered by Bing (who the heck uses Bing to search??), and will often redirect you to a Bing link on the Alexa app page. The Echo Dot can also handle questions like “Who is Kanye West?”, followed by “How old is he?” or “How old is Barack Obama?” followed by “Who is his wife?”. But it is more limited when compared to Google Home.</p>
<p>Another disappointing thing is that you cannot purchase products on Amazon with Alexa voice commands. Since these items come from Amazon.com, you will run into shipping issues with makes delivery into Canada impossible.</p>
<h3>The Winner: Google Home</h3>
<p>Ease of Use easily goes to Google Home.  There is simply no comparison in terms of ease of use and intelligence. With the Echo, you are basically using commands while the Google Home feels more like natural speaking. I’m a Google fanboy so I use Google services for just about everything. So when I ask &#8220;Hey Google, what do I have on today?&#8221; Home was able to read back my calendar appointments, then tell me how long it would take to drive to work. Alexa was also able to read back my calendar appointments but no local information was available because of the US restriction thingy.</p>
<p>Another reason why Google Home is the clear winner is that it is geo-located for pretty much everywhere in the world. Even though it is only sold in the US for the time being, it will work with any postal code. This is a major weakness with the Amazon Echo Dot. With the Echo, you cannot specify your specific home address. This means that, if you want to know the weather in Montreal, with the Echo, you have to say, &#8220;Alexa, what&#8217;s the weather like today in Montreal?&#8221; instead of simply asking “Alexa, what&#8217;s the weather like?”</p>
<h2>Part 6: Music and Video Integration</h2>
<p>One important feature of a home assistant is the ability to provide entertainment. We tried both audio and video integration with Alexa and Google Home.</p>
<h3>Music and Video Playback with the Echo Dot</h3>
<p>Playing music and video was not very easy with the Echo. Your choices for music are Amazon Music, which does not work in Canada or Spotify. The good news is that Canadian Spotify accounts work with the Echo Dot but the bad news is that you need to have a premium account to use it. Although I was able to link my Spotify account with the Echo Dot, I couldn’t do anything because I don’t have a premium Spotify account. Apparently, TuneIn is also supported, but so far, I have not managed to make it work. In terms of video playback, I was not able to get anything working at all.</p>
<h3>Music and Video Playback with the Google Home</h3>
<p>On the other hand, the Google home just worked right out of the box. I was able to listen to my music library from Google Play with no problem. Since I have a Chromecast in every room, I was able make Google Home play YouTube videos on various TVs around the house. And you can even pause playback by simply telling Google Home to pause. I also linked our Netflix account to the Google Home but I have not tested the Netflix integration yet.</p>
<h3>The Winner: Google Home</h3>
<p>Because of the border restrictions, it’s pretty hard to get music or video functionality easily with the Echo Dot. On the other hand, music and video just work with the Google home. There were no limitations for Canadians. My kids were able to request various YouTube videos and Google Home had no problems finding them. We were also able to have a house party with our Google Play music library with no problems at all.</p>
<p>The demo that always impresses our guests is the YouTube demo. We just say &#8220;hey google play Guardians of the Galaxy trailer on YouTube in Livingroom &#8220;. The TV turns itself on, input set, and the video starts.</p>
<h2>Part 6 Home Integration</h2>
<p>I have to be honest. The home integration is that part that I have not tested yet and also the part that I am looking most forward to. It’s true that Amazon Echo has the advantage over Google Home in some ways mostly thanks to its two-year head-start and close integration with third-party services. But none of that matters to us Canadians because we have never had the device! So I believe that both devices will be equal in the eyes of us Canadians. But like I said, I have not tested yet. I’m still waiting on my Hues lights to be delivered from Best Buy. Maybe I’ll do a follow-up article once I’ve connected a few devices to both systems.</p>
<h2>Conclusion: The Overall Winner:</h2>
<p>Before announcing the winner, its important to go over the features of both digital assistants. Here is a short recap below:</p>
<h3>Amazon Echo</h3>
<p>Surprisingly, most of the Echo Dot’s functionality works in Canada. You are able to change Alexa’s temperature settings from Fahrenheit to Celsius but there is no way to change your location to a Canadian city. However, you can do some funky tricks to get your local weather such as “Alexa, what’s the weather like in Montreal?”</p>
<p>According to many Americans who have the fully functional version of Alexa, the Echo shines when it comes to connecting smart devices. The echo can act as a central hub for a variety of different smart home products such as a nest thermostat, some Phillips hue lights and other connected devices.</p>
<h3>Google Home</h3>
<p>Unlike the Echo, the Google Home works perfectly for Canadians! So far, all of Google Home’s functionalities work in Canada. I have also read reports that it is working very well in the UK, Germany, and Australia. We were able to link it to our Google account with no problem and it provides relevant local information. There were no border restrictions and all features worked.</p>
<h3>The Winner: Google Home</h3>
<p><a href="http://miftyisbored.com/wp-content/uploads/google-home-hero-2.jpg"><img loading="lazy" decoding="async" src="http://miftyisbored.com/wp-content/uploads/google-home-hero-2.jpg" alt="" width="1440" height="780" class="alignnone size-full wp-image-2568" srcset="https://miftyisbored.com/wp-content/uploads/google-home-hero-2.jpg 1440w, https://miftyisbored.com/wp-content/uploads/google-home-hero-2-300x163.jpg 300w, https://miftyisbored.com/wp-content/uploads/google-home-hero-2-1024x555.jpg 1024w, https://miftyisbored.com/wp-content/uploads/google-home-hero-2-480x260.jpg 480w, https://miftyisbored.com/wp-content/uploads/google-home-hero-2-923x500.jpg 923w" sizes="auto, (max-width: 1440px) 100vw, 1440px" /></a></p>
<p>The clear winner is Google Home. Why? Because it just works with your Canadian data! Amazon has locked down its geo-location for Echo to be US only. With Google Home, I don’t have to pretend to live in the United States. I am able to put my actual Canadian address and Google recognizes it and doesn’t block me from any of its core features. As soon as I finished the setup, I was able to ask for restaurants around me and I actually got local restaurants instead of restaurants in Plattsburg.</p>
<p>Another advantage is that the Google Home understands human speech better and often replies smarter. (Even though the Echo Dot will sometimes surprise you with some responses). Google Home can also tell you the local weather, and read from selected news services that you can customize. Google also allows you to peek at all the data Home sends back and forth (go to <a href="http://myactivity.google.com">http://myactivity.google.com</a>).</p>
<p>Although Google Home is the clear winner, it does have its flaws. Right now the Home is limited to just one Google account, so a family can&#8217;t really expect to share a device. In our case, I created a family account that we all share. The other knock on Google is their &#8220;reputation&#8221; for abandoning projects. While this is true to an extent, (who remembers Google Glass), I haven&#8217;t seen them do this with their Chromecast devices. The Google Home is perfect for integrating into your Canadian life, which Google has already done with Gmail, Calendar, Keep, Photos, etc.</p>
<p>The post <a href="https://miftyisbored.com/google-home-vs-amazon-echo-dot-canadian-review/">Google Home vs. Amazon Echo Dot: The Canadian Review</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/google-home-vs-amazon-echo-dot-canadian-review/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>019 &#8211; Superman is a Jerk!</title>
		<link>https://miftyisbored.com/019-superman-jerk/</link>
					<comments>https://miftyisbored.com/019-superman-jerk/#respond</comments>
		
		<dc:creator><![CDATA[Mifty]]></dc:creator>
		<pubDate>Fri, 23 Dec 2016 16:06:09 +0000</pubDate>
				<category><![CDATA[Artworks]]></category>
		<category><![CDATA[Random Cartoons]]></category>
		<category><![CDATA[DC Comics]]></category>
		<category><![CDATA[Justice League]]></category>
		<category><![CDATA[Superman]]></category>
		<category><![CDATA[The Flash]]></category>
		<guid isPermaLink="false">http://miftyisbored.com/?p=2546</guid>

					<description><![CDATA[<p>I&#8217;ve never really liked superman as a comic book character. The problem with superman is that he has no weaknesses, so its hard to root for him because you know that he will always win. I kind of had the idea of what it must be like to be another superhero having to hang out [&#8230;]</p>
<p>The post <a href="https://miftyisbored.com/019-superman-jerk/">019 &#8211; Superman is a Jerk!</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I&#8217;ve never really liked superman as a comic book character. The problem with superman is that he has no weaknesses, so its hard to root for him because you know that he will always win. I kind of had the idea of what it must be like to be another superhero having to hang out with superman. My thoughts is that everybody in the Justice League must know that he is a jerk because he is unstoppable. Then I though of all those comic books about Flash vs. Superman: who would win the race? And that&#8217;s how this idea came about. I kept thinking: how can flash ever win a race against superman? My conclusion, he couldn&#8217;t because superman is a jerk</p>
<p>The post <a href="https://miftyisbored.com/019-superman-jerk/">019 &#8211; Superman is a Jerk!</a> appeared first on <a href="https://miftyisbored.com">Mifty is Bored</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://miftyisbored.com/019-superman-jerk/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
