Jekyll2020-05-19T00:59:19-07:00https://jun711.github.io/feed.xmlJun711 blogSoftware development experience sharing using mainly JavaScript, Python and JavaJunAdd AWS Lambda Layers to a Lambda Function using AWS SAM2019-12-06T20:00:00-08:002019-12-06T20:00:00-08:00https://jun711.github.io/aws/attach-aws-lambda-layers-to-lambda-using-aws-sam-yaml-tutorial<p>Learn how to attach a Lambda Layer to a Lambda Function using AWS SAM (Serverless Application Model) and AWS console.</p>
<h2 id="create-lambda-layers">Create Lambda Layers</h2>
<p>If you haven’t created a Lambda Layer, you can read <a href="https://jun711.github.io/aws/create-aws-lambda-layers-using-aws-sam-yaml-tutorial/" target="view_window">Create AWS Lambda Layers article</a> to learn how to create a Lambda Layer.</p>
<h2 id="aws-console">AWS Console</h2>
<p>After creating a Lambda Layer, you can add it to a Lambda function via AWS console. Follow the steps below to add a Layer to your Lambda function. The screenshots below were taken on 2019/12/06.</p>
<ol>
<li>
<p>Go to AWS Console and open your Lambda function.</p>
</li>
<li>
<p>On the <code class="language-plaintext highlighter-rouge">Designer</code> panel, press <code class="language-plaintext highlighter-rouge">Layers</code>.</p>
</li>
<li>
<p>And, a new menu with <code class="language-plaintext highlighter-rouge">Add a Layer</code> button will appear.
<img src="/assets/images/2019-12-06-attach-aws-layers-to-lambda-using-aws-sam-yaml-tutorial/aws-console-lambda-add-a-layer.png" alt="AWS Lambda Layers Folder Structure" /></p>
</li>
</ol>
<ol start="5">
<li>
<p>Press on <code class="language-plaintext highlighter-rouge">Add a Layer</code> to open up a menu to add a Layer. On this menu, you can choose an existing Lambda Layer to add to your function.
<img src="/assets/images/2019-12-06-attach-aws-layers-to-lambda-using-aws-sam-yaml-tutorial/aws-console-add-layer-to-function-menu.png" alt="AWS Lambda Layers Folder Structure" /></p>
</li>
<li>
<p>Press <code class="language-plaintext highlighter-rouge">Add</code> to return to Lambda Console and then press <code class="language-plaintext highlighter-rouge">Save</code> on the top right corner to save this action.</p>
</li>
</ol>
<h2 id="aws-sam-lambda-entity">AWS SAM Lambda Entity</h2>
<p>To add Lambda Layers to a function, you can use <code class="language-plaintext highlighter-rouge">Layers</code> property of your <code class="language-plaintext highlighter-rouge">AWS::Serverless::Function</code> resource entity.</p>
<p>Let’s say the ARN of my layer is <code class="language-plaintext highlighter-rouge">arn:aws:lambda:us-east-2:1234567890:layer:AwsServices:16</code>. I can then add this a list item to Layers property.</p>
<p>You also need provide <code class="language-plaintext highlighter-rouge">lambda:GetLayerVersion</code> permission for your Lambda function to get Lambda Layer version.</p>
<p>AWS::Serverless::Function entity with a Lambda Layer.</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">UserManagementFunction</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::Serverless::Function</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">Handler</span><span class="pi">:</span> <span class="s">index.handler</span>
<span class="na">Runtime</span><span class="pi">:</span> <span class="s">python3.8</span>
<span class="na">FunctionName</span><span class="pi">:</span> <span class="s1">'</span><span class="s">lambda-with-layer'</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">lambda</span><span class="nv"> </span><span class="s">with</span><span class="nv"> </span><span class="s">layer'</span>
<span class="na">CodeUri</span><span class="pi">:</span> <span class="s">./</span>
<span class="na">Policies</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">Statement</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">Effect</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Allow"</span>
<span class="na">Action</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">lambda:GetLayerVersion'</span>
<span class="na">Resource</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">arn:aws:lambda:*:1234567890:layer:*:*'</span>
<span class="na">Layers</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">arn:aws:lambda:us-east-2:1234567890:layer:layer1:16</span>
</code></pre></div></div>
<h2 id="cloudformation-role-permission">CloudFormation Role Permission</h2>
<p>To enable CloudFormation to create Lambda Layers for you, the assumed role needs to have permission to access and manipulate AWS Lambda Layers. You can attach the following inline policies to your CloudFormation role in order for it to attach Lambda Layers to your Lambda functions for you.</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"Version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2012-10-17"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Statement"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"Sid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VisualEditor0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Effect"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Allow"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Action"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"lambda:GetLayerVersion"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:DeleteLayerVersion"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:ListLayerVersions"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:ListLayers"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:AddLayerVersionPermission"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:RemoveLayerVersionPermission"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"Resource"</span><span class="p">:</span><span class="w"> </span><span class="s2">"*"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to attach a Lambda Layer to a Lambda Function using AWS SAM (Serverless Application Model) and AWS console.Create AWS Lambda Layers Using AWS SAM2019-12-05T20:00:00-08:002019-12-05T20:00:00-08:00https://jun711.github.io/aws/create-aws-lambda-layers-using-aws-sam-yaml-tutorial<p>Learn how to create a Lambda Layer using AWS SAM (Serverless Application Model) and CloudFormation in YAML to reuse code, write zero redundant code and reduce Lambda deployment size.</p>
<h2 id="aws-lambda-layers">AWS Lambda Layers</h2>
<p>Lambda Layers can be thought of as additional code added on top of a Lambda function. A Lambda Layer is a ZIP archive / file that contains code and can be imported by Lambda functions.</p>
<p>In other words, you can extract and reuse common code by keeping the code in a Lambda Layer and attach it to multiple Lambda functions.</p>
<p>As for limit, a Lambda function can only use up to 5 layers at a time. And, the total size of unzipped code of Lambda plus the attached Layers cannot exceed 250MB.</p>
<p>You can create your own layers, or use layers published by AWS and other AWS customers.</p>
<h2 id="aws-cloudformation">AWS CloudFormation</h2>
<p>You can create a Lambda Layer using <code class="language-plaintext highlighter-rouge">AWS::Lambda::LayerVersion</code> entity by setting its content to point to a ZIP archive containing your code stored in an S3 bucket.</p>
<p>To keep older versions of your Lambda Layer, set your Lambda LayerVersion <code class="language-plaintext highlighter-rouge">UpdateReplacePolicy</code> and <code class="language-plaintext highlighter-rouge">DeletionPolicy</code> attribute value as <code class="language-plaintext highlighter-rouge">Retain</code>.</p>
<p>AWS::Lambda::LayerVersion example:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">MyLayer</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s2">"</span><span class="s">AWS::Lambda::LayerVersion"</span>
<span class="na">UpdateReplacePolicy</span><span class="pi">:</span> <span class="s">Retain</span>
<span class="na">DeletionPolicy</span><span class="pi">:</span> <span class="s">Retain</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">CompatibleRuntimes</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">python3.6</span>
<span class="pi">-</span> <span class="s">python3.7</span>
<span class="pi">-</span> <span class="s">python3.8</span>
<span class="na">Content</span><span class="pi">:</span>
<span class="na">S3Bucket</span><span class="pi">:</span> <span class="s">my-bucket-us-west-2-123456789012</span>
<span class="na">S3Key</span><span class="pi">:</span> <span class="s">layer.zip</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">My layer</span>
<span class="na">LayerName</span><span class="pi">:</span> <span class="s">my-layer</span>
<span class="na">LicenseInfo</span><span class="pi">:</span> <span class="s">MIT</span>
</code></pre></div></div>
<h2 id="aws-sam">AWS SAM</h2>
<p>AWS SAM provides a simpler syntax via <code class="language-plaintext highlighter-rouge">AWS::Serverless::LayerVersion</code> and additional function that allows us that help us package and deploy local code. <br />
When you develop your Lambda Layer, you can write your code in a file relative to SAM template by setting LayerVersion <code class="language-plaintext highlighter-rouge">ContentUri</code> property to point to a relative local path.</p>
<p>For example, if your code is inside <code class="language-plaintext highlighter-rouge">myFolder</code>, set ContentUri as <code class="language-plaintext highlighter-rouge">ContentUri: ./myFolder</code>.</p>
<p>AWS::Serverless::LayerVersion example:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Resources</span><span class="pi">:</span>
<span class="na">AwsServices</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::Serverless::LayerVersion</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">LayerName</span><span class="pi">:</span> <span class="s">my-layer</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">My layer</span>
<span class="na">ContentUri</span><span class="pi">:</span> <span class="s">./myLayer</span>
<span class="na">CompatibleRuntimes</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">python3.6</span>
<span class="pi">-</span> <span class="s">python3.7</span>
<span class="pi">-</span> <span class="s">python3.8</span>
<span class="na">LicenseInfo</span><span class="pi">:</span> <span class="s">MIT</span>
<span class="na">RetentionPolicy</span><span class="pi">:</span> <span class="s">Retain</span>
</code></pre></div></div>
<h3 id="lambda-layers-project-structure">Lambda Layers Project Structure</h3>
<p>Lambda Layers ZIP archives are extracted to <code class="language-plaintext highlighter-rouge">/opt</code> folder in a Lambda function execution environment. Each language runtime looks for libraries in a different location in /opt folder.</p>
<p>In other words, you should place your code within the required folder path - the folder path supported by the function runtime. Refer to <a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html#configuration-layers-path" target="view_window">AWS document</a> for more detailed information.</p>
<p>I tried Lambda Layers in Python and it seems that code placed within <code class="language-plaintext highlighter-rouge">python</code> folder would be import-able in a Lambda Function at Python runtime 3.X. If you want to limit your Lambda Layer to a specific runtime, let’s say Python3.8, then you can put it in <code class="language-plaintext highlighter-rouge">python/lib/python3.8/site-packages</code> folder.</p>
<p>For Python example, if your LayerVersion <code class="language-plaintext highlighter-rouge">ContentUri</code> is <code class="language-plaintext highlighter-rouge">./myLayer</code>, you need to create a folder named <code class="language-plaintext highlighter-rouge">python</code> and put your Python files within <code class="language-plaintext highlighter-rouge">./myLayer/python</code> folder.</p>
<p>In the Lambda Function that imports this Layer via <code class="language-plaintext highlighter-rouge">import file1</code>, you can print to see the location of your imported file from Layer. The output is <code class="language-plaintext highlighter-rouge"><module 'file1' from '/opt/python/file1.py'></code> as expected.</p>
<p>Lambda Layer Folder structure example:<br />
<img src="/assets/images/2019-12-05-create-aws-lambda-layers-using-aws-sam-yaml-tutorial/aws-lambda-layer-python-runtime-folder-structure.png" alt="AWS Lambda Layers Folder Structure" /></p>
<p>The following is the list the folders specifed on AWS Lambda Layers document.
<strong>Node.js</strong></p>
<ul>
<li>nodejs/node_modules</li>
<li>nodejs/node8/node_modules (NODE_PATH)</li>
</ul>
<p><strong>Python</strong></p>
<ul>
<li>python</li>
<li>python/lib/python3.8/site-packages</li>
</ul>
<p><strong>Java</strong></p>
<ul>
<li>java/lib (classpath)</li>
</ul>
<p><strong>Ruby</strong><br />
– ruby/gems/2.5.0 (GEM_PATH)</p>
<ul>
<li>ruby/lib (RUBY_LIB)</li>
</ul>
<p><strong>All</strong><br />
– bin (PATH)</p>
<ul>
<li>lib (LD_LIBRARY_PATH)</li>
</ul>
<h2 id="cloudformation-role-permission">CloudFormation Role Permission</h2>
<p>To enable CloudFormation to create Lambda Layers for you, the assumed role needs to have permission to access and manipulate AWS Lambda Layers. You can attach the following inline policies to your CloudFormation role in order for it to create Lambda Layers for you.</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"Version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2012-10-17"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Statement"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"Sid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VisualEditor0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Effect"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Allow"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Action"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"lambda:GetLayerVersion"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:PublishLayerVersion"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:DeleteLayerVersion"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:ListLayerVersions"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:ListLayers"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:AddLayerVersionPermission"</span><span class="p">,</span><span class="w">
</span><span class="s2">"lambda:RemoveLayerVersionPermission"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"Resource"</span><span class="p">:</span><span class="w"> </span><span class="s2">"*"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h2 id="caveat">Caveat</h2>
<p>There is no Lambda Layer alias that points to a specific version of a Lambda Layer. Thus, Lambda functions that uses a layer has to be updated to use the latest version of Layer. It is good that it won’t automatically use new code from new Layer version that may potentially break existing Lambda functionality.</p>
<h2 id="lambda-layers-on-aws-console">Lambda Layers On AWS Console</h2>
<p>To verify Lambda Layers are actually created, you can use AWS CLI or go to AWS Console (Lambda) to see your Lambda Layers.
<img src="/assets/images/2019-12-05-create-aws-lambda-layers-using-aws-sam-yaml-tutorial/aws-lambda-layers-on-aws-console.png" alt="AWS Lambda Layers Folder Structure" /></p>
<h2 id="add-to-lambda-function">Add to Lambda Function</h2>
<p>You can read <a href="https://jun711.github.io/aws/attach-aws-lambda-layers-to-lambda-using-aws-sam-yaml-tutorial/" target="view_window">Attach AWS Lambda Layers to Lambda Functions article</a> to learn how to add a Lambda Layer to a Lambda function.</p>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to create a Lambda Layer using AWS SAM (Serverless Application Model) and CloudFormation in YAML to reuse code, write zero redundant code and reduce Lambda deployment size.Best Exchange Rate and Cheapest International Wire Transfer Service2019-11-21T20:00:00-08:002019-11-21T20:00:00-08:00https://jun711.github.io/review/best-exchange-rate-and-cheapest-international-wire-transfer-service<p>Ever feel that it costs quite a bit to send money overseas. Check out this service and save money on your next international wire transfer.</p>
<h2 id="what-are-buy-sell-and-mid-market-rates">What are Buy, Sell and Mid Market Rates</h2>
<p>When we search on Google ‘USD to CAD’, we can see an exchange rate calculator similar to picture below.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/exchange-rate-on-google-search-morningstar.png" alt="Currency Exchange Rate Calculator by Google based on data provided by Morningstar" /></p>
<p>However, when we check currency exchange rates at banks, currency exchange shops or websites, we can see that each currency has “buy” and “sell” rates. These are the rates that currency exchange service providers willing to trade at. The rates they use affects the cost of our currency exchange and international wire transfer.</p>
<p>For example, you can check <a href="https://tool.td.com/fxcal/#/fxcalculator" target="view_window">TD Bank’s foreign exchange calculator</a>. The following screenshot shows USD and CAD exchange rates provided by TD Bank.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/td-bank-exchange-rate-calculator.png" alt="Currency Exchange Rate Calculator by TD Bank" /></p>
<p>The (approximate) exchange rate we get via Google search is <br />
1 USD = 1.33 CAD</p>
<p>However, on TD Bank page, we see<br />
1 USD = 1.3621 CAD</p>
<p>That means, if we want to buy USD from TD Bank, we pay 1.3621 CAD to get 1 USD. However, based on the exchange rate via Google search, it should be 1.33 CAD for 1 USD.</p>
<p>That means for every USD that we buy from TD Bank, TD Bank probably makes around <strong>0.0321 CAD</strong>(1.3621 - 1.33) for every USD that we buy using CAD. In other words, when we buy 1000 USD, TD Bank probably makes 32.1 CAD.</p>
<p>On the other hand, <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a> facilitates international currency exchange using mid market rate which is the rate we see on Google, XE and Yahoo Finance. <br />
Logically, then, mid market rate is then the middle rate between buying and selling prices of currency markets. To read more about <a href="https://transferwise.com/gb/mid-market-rate" target="view_window">mid market rate</a>.</p>
<h2 id="foreign-exchange-service">Foreign Exchange Service</h2>
<p>According to Wikipedia, <a href="http://bit.ly/jun-transferwise" target="_blank">TransferWise</a> is described as following:</p>
<blockquote>
<p>TransferWise is a British online money transfer service founded in January 2011 by Estonians Kristo Käärmann and Taavet Hinrikus and is based in London. The company supports more than 750 currency routes across the world including GBP, USD, EUR, AUD and CAD, and provides multi-currency accounts.</p>
</blockquote>
<h2 id="international-wire-transfer-steps">International Wire Transfer Steps</h2>
<p>This diagram summarizes the steps to use do internation wire transfer using TransferWise.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-steps-for-internationational-wire-transfer.png" alt="TransferWise Steps for Internation Wire Transfer" /></p>
<p>If you would like to get discount for your first international wire transfer with <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a>, feel free to message me.</p>
<h3 id="1-sign-up-for-an-account">1 Sign up for an account</h3>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-homepage-and-register.png" alt="TransferWise Homepage" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-signup-form.png" alt="TransferWise Register Form" /></p>
<h3 id="2-onboarding-survey">2 Onboarding Survey</h3>
<p>There is any onboarding survey that you have to answer to tell <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a> how you gonna use it.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-usage-survey.png" alt="TransferWise Usage Survey" /></p>
<h3 id="3-transfer-flow">3 Transfer Flow</h3>
<p>Next, you will fill out some information regarding your money transfer through a series of steps <code class="language-plaintext highlighter-rouge">(Amount - You - Recipient - Review - Pay)</code>. Follow the explanation and diagrams below for a walkthrough.</p>
<p><strong>Amount</strong><br />
Specify the currency and amount that you want to transfer. The exchange rate is guaranteed if your money arrives at <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a>account within the next set period of time (e.g. 96 hours in my case).</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-amount-to-send.png" alt="TransferWise Transfer Flow - Amount to Send" /></p>
<p><strong>You</strong></p>
<p>Fill out your personal information that is needed for money transfer.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-personal-or-business-transfer.png" alt="TransferWise Transfer Flow - Personal or Business Transfer" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-fill-in-personal-details.png" alt="TransferWise Transfer Flow - Personal Details" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-personal-details.png" alt="TransferWise Transfer Flow - Address and Occupation" /></p>
<p><strong>Recipient</strong></p>
<p>Fill out your money transfer recipient’s information such as name, address and bank details.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-recipient-list.png" alt="TransferWise Transfer Flow - Recipient List" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-recipient-information.png" alt="TransferWise Transfer Flow - Recipient Information" /></p>
<p>After you add a recipient, a recipient card will be added to the list of existing recipients.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-recipient-added.png" alt="TransferWise Transfer Flow - Existing Recipients" /></p>
<p>Next, you need to specify the reason for transferring money.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-transfer-reasons.png" alt="TransferWise Transfer Flow - Reasons for Transfer" /></p>
<p><strong>pay</strong></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-review-details-of-transfer.png" alt="TransferWise Transfer Flow - Review Details of Transfer" /></p>
<p>How do you transfer money / pay TransferWise? At the pay stage, <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a> lists a few payment methods and price for each payment methods is different. Based on two uses, I noticed that <code class="language-plaintext highlighter-rouge">online bill pay</code>, <code class="language-plaintext highlighter-rouge">domestic wire transfer</code> and <code class="language-plaintext highlighter-rouge">direct debit</code> are probably the cheapest options.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-pay-transferwise.png" alt="TransferWise Transfer Flow - Pay TransferWise" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-pay-transferwise-2.png" alt="TransferWise Transfer Flow - Pay TransferWise" /></p>
<h2 id="cheaper-payment-methods">Cheaper Payment Methods</h2>
<p>I find that direct debit and online bill pay are quite easy to set up. I believe it also depends on countries. Thus, choose the method that is most convenient for you.</p>
<h3 id="1-direct-debit">1 Direct Debit</h3>
<p>You can set up direct debit via the <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a> console by selecting direct debit and continue to payment.<br />
<img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-direct-debit-bank-list.png" alt="TransferWise Transfer Flow - Direct Debit Bank List" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-direct-debit-bank-list-2.png" alt="TransferWise Transfer Flow - Direct Debit Bank List" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-direct-debit-from-td-bank.png" alt="TransferWise Transfer Flow - Direct Debit From TD Bank" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-direct-debit-from-tangerine-bank.png" alt="TransferWise Transfer Flow - Direct Debit From Tangerine" /></p>
<h3 id="2-online-bill-pay--bill-payment">2 Online Bill Pay / Bill Payment</h3>
<p>The second option that I recommend is online bill pay. However, it seems to be working with fewer banks.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-online-bill-pay-bank-list.png" alt="TransferWise Transfer Flow - Online Bill Pay Bank List" /></p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/transferwise-transfer-flow-online-bill-pay-using-tangerine-bank.png" alt="TransferWise Transfer Flow - Online Bill Pay Bank List" /></p>
<p>However, on <a href="http://bit.ly/jun-transferwise" target="_blank">TransferWise</a> help page, it lists the steps needed to add TransferWise as a payee. I will list here for your convenience.</p>
<p>The usual steps for online bill pay are as following:</p>
<ol>
<li>Log in to your online bank</li>
<li>Select Bill Payment</li>
<li>Add a Payee</li>
<li>Enter the details of TransferWise:</li>
</ol>
<p>Payee Province - ON (Ontario)
Payee Name - TransferWise
Account number- Your TransferWise membership number (Starts with an uppercase P, no spaces or dashes)</p>
<ol start="5">
<li>Select Verify Payee</li>
</ol>
<p>After you’ve added <a href="http://bit.ly/jun-transferwise" target="_blank">TransferWise</a> as a bill payee with your bank, you can use this payment method again with ease.</p>
<p>For example, this is how my bill payment menu looks like after I added <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a> as my bill payee with my Tangerine account.</p>
<p><img src="/assets/images/2019-11-21-best-exchange-rate-and-cheapest-international-wire-transfer-service/tangerine-bill-payment-menu-after-adding-transferwise-as-bill-payee.png" alt="Pay TransferWise Using Tangerine Bill Pay" /></p>
<h2 id="compare-with-bank-exchange-rates">Compare with Bank Exchange Rates</h2>
<p>To verify that you will pay less fee or transfer money overseas at a better exchange rate, you can compare TransferWise rate with the <strong>foreign currency buying rate (TT - Telegraphic Transfer)</strong> that you can find on your bank website.</p>
<h2 id="freebie">Freebie</h2>
<p>Feel free to contact me if you would like to get discount for your first international wire transfer(about $800) with <a href="http://bit.ly/jun-forex" target="_blank">TransferWise</a>.</p>
<p>If you are interested in using <a href="https://www.tangerine.ca/en" target="view_window">Tangerine</a> Bank(online bank), you can use my Tangerine Orange Key: 47618967S1 to sign up for an account. Both of us would be able to get $50 once Tangerine is able to verify your account. Thank you.</p>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunEver feel that it costs quite a bit to send money overseas. Check out this service and save money on your next international wire transfer.Upgrade AWS SAM CLI using Homebrew2019-10-18T21:00:00-07:002019-10-18T21:00:00-07:00https://jun711.github.io/aws/how-to-upgrade-aws-sam-cli-using-homebrew<p>Learn how to upgrade your AWS SAM CLI using Homebrew.</p>
<p>If you haven’t had AWS SAM CLI installed, you can refer to my <a href="https://jun711.github.io/aws/aws-sam-invoke-local-to-execute-lambda-locally/" target="view_window">Install AWS SAM CLI article</a> to learn how to install AWS SAM CLI using Homebrew.</p>
<h2 id="current-version">Current Version</h2>
<p>You can get the version of the installed AWS SAM CLI by running the following command.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sam --version
SAM CLI, version 0.37.0
</code></pre></div></div>
<h2 id="latest-version">Latest Version</h2>
<p>You can get the information of the latest released version of AWS SAM CLI by using the this command.</p>
<p>The printed output shows the latest stable version of AWS SAM CLI.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew info aws-sam-cli
aws/tap/aws-sam-cli: stable 0.37.0 (bottled), HEAD
AWS SAM CLI 🐿 is a tool for local development
and testing of Serverless applications
https://github.com/awslabs/aws-sam-cli/
/usr/local/Cellar/aws-sam-cli/0.37.0 (4,567 files, 67.2MB) *
Poured from bottle on 2019-12-05 at 15:05:24
From:
https://github.com/aws/homebrew-tap/blob/master/
Formula/aws-sam-cli.rb
==> Dependencies
Required: python ✔
==> Options
--HEAD
Install HEAD version
</code></pre></div></div>
<h2 id="upgrade-version">Upgrade Version</h2>
<p>You can run this command to upgrade your AWS SAM CLI. It will first update Homebrew so it takes a bit of time if your Homebrew is not up to date.</p>
<p>If you already have the latest AWS SAM CLI installed, you will see this warning message.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew upgrade aws-sam-cli
Warning: aws/tap/aws-sam-cli 0.37.0 already installed
</code></pre></div></div>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to upgrade your AWS SAM CLI using Homebrew.Angular 8 Lazy Loading With Angular CLI2019-09-11T21:00:00-07:002019-09-11T21:00:00-07:00https://jun711.github.io/web/angular-8-lazy-loading-with-angular-cli<p>Learn how to create a lazy loading path with Angular 8 apps using Angular CLI.</p>
<h2 id="lazy-loading">Lazy Loading</h2>
<p>Lazy loading literally means loading your Angular app in a lazy manner. In other words, it means your Angular app doesn’t load a specific feature (JavaScript, HTML and CSS) bundle until it is needed. This is effective in keeping your app’s main bundle size small and thus also minimizing initial app load time / first paint time.</p>
<p>In this guide, I will walk you through steps to configure and create a lazy loading path by using Angular CLI.</p>
<h2 id="angular-cli">Angular CLI</h2>
<p>Run <code class="language-plaintext highlighter-rouge">ng --version</code> command to check if you have Angular CLI installed by . If you have it installed, it would print out your Angular CLI, related packages and system information.</p>
<pre class="code"><code>
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 8.3.3
Node: 11.0.0
OS: darwin x64
Angular:
...
Package Version
------------------------------------------------------
@angular-devkit/architect 0.803.3
@angular-devkit/core 8.3.3
@angular-devkit/schematics 8.3.3
@schematics/angular 8.3.3
@schematics/update 0.803.3
rxjs 6.4.0
</code></pre>
<h2 id="create-a-lazy-loading-path">Create A Lazy Loading Path</h2>
<p>Check out the steps below to create a lazy loading path.</p>
<h3 id="1-create-an-angular-app">1 Create An Angular App</h3>
<p>Use <code class="language-plaintext highlighter-rouge">ng new</code> command to create an Angular app with routing configured.</p>
<pre class="code"><code>
ng new lazyLoadingApp --routing --style=scss
</code></pre>
<ol>
<li><code class="language-plaintext highlighter-rouge">--routing</code> flag is to set up routing for your Angular app.</li>
<li><code class="language-plaintext highlighter-rouge">--style=scss</code> flag is to configure your app to process scss stylesheets.</li>
</ol>
<p>Run the following command to open the newly created Angular app directory.</p>
<pre class="code"><code>
cd lazyLoadingApp
</code></pre>
<h3 id="2-generate-a-lazy-loading-module">2 Generate A Lazy Loading Module</h3>
<p>To create a lazy loading path, you need to encapsulate the code used only for this path in an Angular module. To create a module with an entry component, use <code class="language-plaintext highlighter-rouge">ng generate module</code> command.</p>
<pre class="code"><code>
ng generate module ./lazy-path-one --route lazy-path-one --module app.module
</code></pre>
<p>The shorter command is</p>
<pre class="code"><code>
ng g m ./lazy-path-one --route lazy-path-one --module app.module
</code></pre>
<ol>
<li><code class="language-plaintext highlighter-rouge">--route</code> flag is used to specify the route / path name.</li>
<li><code class="language-plaintext highlighter-rouge">--module</code> flag is used to specify the parent module of this new module.</li>
</ol>
<p>Under the hood, Angular CLI creates a module with its base path points to an entry component. It also updates app-routing to create a lazy loading path.</p>
<pre class="code"><code>
CREATE src/app/lazy-path-one/lazy-path-one-routing.module.ts (366 bytes)
CREATE src/app/lazy-path-one/lazy-path-one.module.ts (388 bytes)
CREATE src/app/lazy-path-one/lazy-path-one.component.scss (0 bytes)
CREATE src/app/lazy-path-one/lazy-path-one.component.html (28 bytes)
CREATE src/app/lazy-path-one/lazy-path-one.component.spec.ts (665 bytes)
CREATE src/app/lazy-path-one/lazy-path-one.component.ts (296 bytes)
UPDATE src/app/app-routing.module.ts (370 bytes)
</code></pre>
<p>in <strong>app-routing.module.ts</strong>, Angular CLI adds a lazy loading path.</p>
<pre class="code"><code>
const routes: Routes = [
{
path: 'lazy-path-one',
loadChildren: () => import('./lazy-path-one/lazy-path-one.module')
.then(m => m.LazyPathOneModule)
}
];
</code></pre>
<h3 id="3-create-components-for-module">3 Create Components For Module</h3>
<p>Run <code class="language-plaintext highlighter-rouge">ng generate component</code> command to create more components for your lazy loading module.</p>
<pre class="code"><code>
ng generate component ./lazy-path-one/component1 --module lazy-path-one
</code></pre>
<p>The shorter command is</p>
<pre class="code"><code>
ng g c ./lazy-path-one/component1 --module lazy-path-one
</code></pre>
<p>Under the hood, Angular CLI creates a new component and imports the component in the respective module.</p>
<pre class="code"><code>
CREATE src/app/lazy-path-one/component1/component1.component.scss (0 bytes)
CREATE src/app/lazy-path-one/component1/component1.component.html (25 bytes)
CREATE src/app/lazy-path-one/component1/component1.component.spec.ts (656 bytes)
CREATE src/app/lazy-path-one/component1/component1.component.ts (286 bytes)
UPDATE src/app/lazy-path-one/lazy-path-one.module.ts (482 bytes)
</code></pre>
<h2 id="angular-commands-used">Angular Commands Used</h2>
<p>All the commands used in the steps above are listed here.</p>
<pre class="code"><code>
ng new lazyLoadingApp --routing --style=scss
cd lazyLoadingApp
ng g m ./lazy-path-one --route lazy-path-one --module app.module
ng g c ./lazy-path-one/component1 --module lazy-path-one
</code></pre>
<h2 id="verify-lazy-loading-on-localhost">Verify Lazy Loading On Localhost</h2>
<p>Run <code class="language-plaintext highlighter-rouge">ng serve --open</code> to run your Angular app on localhost. To inspect whether a module is loaded lazily, you can check when it is loaded via a browser DevTools.</p>
<p>1) On Chrome, you can open up Chrome DevTools by right click <code class="language-plaintext highlighter-rouge">inspect</code>. The shortcut keys to open DevTools is <code class="language-plaintext highlighter-rouge">Commandd + Option + j</code> on a Mac or <code class="language-plaintext highlighter-rouge">Ctrl + Shift + j</code> on a PC.</p>
<p>When DevTools is open, go to <code class="language-plaintext highlighter-rouge">Network</code> tab.</p>
<p>2) Type in your lazy loading path after ‘http://localhost:4200/’. <br />
In my case, I use <code class="language-plaintext highlighter-rouge">http://localhost:4200/lazy-path-one</code> to load my lazy loading module. <br />
Then, you can notice that a new module that is named after your lazy loading module will be loaded.</p>
<p><img src="/assets/images/2019-09-11-angular-8-lazy-loading-with-angular-cli/lazy-loading-module-on-network-tab.png" alt="Inspect Lazy Loaded Module On Chrome DevTools Network Tab" /></p>
<p>3) It would be easier to notice the download of a lazy loading module if you add a router link in your <code class="language-plaintext highlighter-rouge">app.component.html</code>. Then, you can click on <code class="language-plaintext highlighter-rouge">Lazy Load</code> button to load your lazy loading path.</p>
<p>In <strong>app.component.html</strong>, add the following button.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><button routerLink="/lazy-path-one">Lazy Load</button>
<router-outlet></router-outlet>
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>The sample repo is on my <a href="https://github.com/Jun711/Angular8LazyLoading" target="view_window">GitHub</a>.</p>
<p>Consider using lazy loading to load your app bundles that are not immediately needed to reduce your Angular app load time. With reduced app load time, you would be able to provide better user experience and thus retain more users.</p>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to create a lazy loading path with Angular 8 apps using Angular CLI.AWS DynamoDB Boto3 - No module named ‘boto3.dynamodb.conditions.Key’2019-09-01T21:00:00-07:002019-09-01T21:00:00-07:00https://jun711.github.io/aws/aws-dynamodb-boto3-module-not-found-error<p>Learn how to handle <code class="language-plaintext highlighter-rouge">ModuleNotFoundError: No module named 'boto3.dynamodb.conditions.Key';</code> error.</p>
<h2 id="solution">Solution</h2>
<p>The whole error message looks something like this.</p>
<pre class="code"><code>
ModuleNotFoundError: No module named 'boto3.dynamodb.conditions.Key';
'boto3.dynamodb.conditions' is not a package
</code></pre>
<p>This is probably due to import syntax is incorrect. You probably imported <code class="language-plaintext highlighter-rouge">conditions.Key</code> using the syntax below.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">boto3.dynamodb.conditions.Key</span>
</code></pre></div></div>
<p>The above import syntax is incorrect. You should import a module from a package using the following syntax.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># from boto3.dynamodb.conditions import Key
</span><span class="kn">from</span> <span class="nn">boto3.dynamodb.conditions</span> <span class="kn">import</span> <span class="n">Key</span><span class="p">,</span> <span class="n">Attr</span>
</code></pre></div></div>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to handle ModuleNotFoundError: No module named 'boto3.dynamodb.conditions.Key'; error.HTML Inline Frame - Iframe2019-08-25T21:00:00-07:002019-08-25T21:00:00-07:00https://jun711.github.io/web/html-iframe-101<p>Learn about HTML Inline Frame element (<iframe>) through some examples.</p>
<h2 id="what-is-iframe">What is Iframe</h2>
<p>HTML iframes are used to embed another webpage into a webpage. The embedded webpage can be from a different domain. However, for security reason, you will have limited control to the embedded webpage that is from a different origin.</p>
<h3 id="embed-a-local-webpage">Embed A Local Webpage</h3>
<p>You can embed your own webpages using an iframe. For example, you have a homepage and webpage1. You can then embed webpage1 on your homepage using an iframe.</p>
<p>You can give it a try by downloading <a href="/assets/html/homepage.html" download="homepage.html">homepage.html</a> and <a href="/assets/html/homepage.html" download="webpage1.html">webpage1.html</a>. Otherwise, you can save the following HTML in 2 files: homepage.html and webpage1.html. After you have these 2 HTML files, you can drag and drop homepage.html onto a browser window to open it.</p>
<p><strong>homepage.html</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
<span class="nt"><title></span>HomePage<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><h1></span>Homepage<span class="nt"></h1></span>
<span class="nt"><p></span>Webpages embedded in an Iframe below<span class="nt"></p></span>
<span class="nt"><iframe</span>
<span class="na">title=</span><span class="s">"Homepage Iframes"</span>
<span class="na">src=</span><span class="s">"webpage1.html"</span>
<span class="na">width=</span><span class="s">"350"</span> <span class="na">height=</span><span class="s">"350"</span><span class="nt">></span>
<span class="nt"><p></span>iframes are not supported by this browser.<span class="nt"></p></span>
<span class="nt"></iframe></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p><strong>Note</strong> <br />
1) The <p> element within iframe tags is used to notify users when iframe is not supported by the browser they are using. The text in the <p> element won’t appear if iframe is supported.</p>
<p>2) If the html files are in the same folder, you don’t have to specify <code class="language-plaintext highlighter-rouge">./</code> path.</p>
<p><strong>webpage1.html</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
<span class="nt"><title></span>WebPage 1<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><h1></span>Webpage 1<span class="nt"></h1></span>
<span class="nt"><p></span>My Webpage Content<span class="nt"></p></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p>You will see this when you open <code class="language-plaintext highlighter-rouge">homepage.html</code> file on Google Chrome.</p>
<p><img src="/assets/images/2019-08-25-html-iframe-101/embed-webpages-on-homepage.png" alt="Embed https://jun711.github.io Using An Iframe" /></p>
<h3 id="embed-jun711-blog-in-an-iframe">Embed Jun711 Blog In An Iframe</h3>
<p>You can download <a href="/assets/html/jun-iframe.html" download="jun-iframe.html">jun-iframe.html</a> or save the following HTML as <code class="language-plaintext highlighter-rouge">jun-iframe.html</code>. Then, open it using a browser to experience loading a webpage using an <iframe> first-hand. You can drag and drop the HTML file onto a browser window to open it.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
<span class="nt"><meta</span>
<span class="na">name=</span><span class="s">"viewport"</span>
<span class="na">content=</span><span class="s">"width=device-width, initial-scale=1.0"</span><span class="nt">></span>
<span class="nt"><meta</span>
<span class="na">http-equiv=</span><span class="s">"X-UA-Compatible"</span>
<span class="na">content=</span><span class="s">"ie=edge"</span><span class="nt">></span>
<span class="nt"><title></span>Jun711<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><h1></span>Jun's Blog<span class="nt"></h1></span>
<span class="nt"><p></span>My website embedded in an Iframe below<span class="nt"></p></span>
<span class="nt"><iframe</span>
<span class="na">title=</span><span class="s">"Jun711 Blog"</span>
<span class="na">src=</span><span class="s">"https://jun711.github.io"</span>
<span class="na">width=</span><span class="s">"500"</span> <span class="na">height=</span><span class="s">"500"</span><span class="nt">></span>
<span class="nt"></iframe></span>
<span class="nt"><style></span>
<span class="nt">iframe</span> <span class="p">{</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="no">black</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt"></style></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p>You will see this when you open the above HTML file on Google Chrome.</p>
<p><img src="/assets/images/2019-08-25-html-iframe-101/embed-jun711-blog-using-an-iframe.png" alt="Embed https://jun711.github.io Using An Iframe" /></p>
<h3 id="scripting---accessing-iframe-window-and-document-objects">Scripting - Accessing Iframe Window and Document Objects</h3>
<p>You can access embedded webpages Window and Document objects using <code class="language-plaintext highlighter-rouge">contentWindow</code> and <code class="language-plaintext highlighter-rouge">contentDocument</code> properties of an iframe DOM object(<code class="language-plaintext highlighter-rouge">HTMLIFrameElement</code>). You can also access document object via <code class="language-plaintext highlighter-rouge">contentWindow.document</code> object.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">myIframe</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">myIframe</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">function</span> <span class="nx">accessIframe</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">iframeWindow</span> <span class="o">=</span> <span class="nx">myIframe</span><span class="p">.</span><span class="nx">contentWindow</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">iframeDocument</span> <span class="o">=</span> <span class="nx">myIframe</span><span class="p">.</span><span class="nx">contentDocument</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">iframeWindow: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">iframeWindow</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">iframeWindow: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">iframeWindow</span><span class="p">.</span><span class="nb">document</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">iframeWindow: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">iframeDocument</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You can add an id <code class="language-plaintext highlighter-rouge">myIframe</code> to your iframe element and add the following JavaScript in <code class="language-plaintext highlighter-rouge">homepage.html</code> that is created earlier. Then, open up your browser DevTools and reload the page to see what’s printed on the console.</p>
<p><strong>homepage.html</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
<span class="nt"><title></span>HomePage<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><h1></span>Homepage<span class="nt"></h1></span>
<span class="nt"><p></span>Webpages embedded in an Iframe below<span class="nt"></p></span>
<span class="nt"><iframe</span>
<span class="na">id=</span><span class="s">"myIframe"</span>
<span class="na">title=</span><span class="s">"Homepage Iframes"</span>
<span class="na">src=</span><span class="s">"webpage1.html"</span>
<span class="na">width=</span><span class="s">"350"</span> <span class="na">height=</span><span class="s">"350"</span><span class="nt">></span>
<span class="nt"></iframe></span>
<span class="nt"><script></span>
<span class="kd">const</span> <span class="nx">myIframe</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">myIframe</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">function</span> <span class="nx">accessIframe</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">iframeWindow</span> <span class="o">=</span> <span class="nx">myIframe</span><span class="p">.</span><span class="nx">contentWindow</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">iframeDocument</span> <span class="o">=</span> <span class="nx">myIframe</span><span class="p">.</span><span class="nx">contentDocument</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">iframeWindow: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">iframeWindow</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">iframeWindow: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">iframeWindow</span><span class="p">.</span><span class="nb">document</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">iframeWindow: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">iframeDocument</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">accessIframe</span><span class="p">()</span>
<span class="nt"></script></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p>An embedded webpage(webpage loaded using iframe) can access its parent window using <code class="language-plaintext highlighter-rouge">window.parent</code> object.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">parentWindow</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">parent</span><span class="p">;</span>
</code></pre></div></div>
<h4 id="cross-origin-error">Cross-Origin Error</h4>
<p>You probably will see <code class="language-plaintext highlighter-rouge">DOMException</code> error if you try to access an iframe window properties or window.parent using local HTML files.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Uncaught</span> <span class="nx">DOMException</span><span class="p">:</span> <span class="nx">Blocked</span> <span class="nx">a</span> <span class="nx">frame</span> <span class="kd">with</span> <span class="nx">origin</span> <span class="dl">"</span><span class="s2">null</span><span class="dl">"</span>
<span class="k">from</span> <span class="nx">accessing</span> <span class="nx">a</span> <span class="nx">cross</span><span class="o">-</span><span class="nx">origin</span> <span class="nx">frame</span><span class="p">.</span>
</code></pre></div></div>
<p>This is because script access to an iframe’s content is controlled by the same-origin policy. Scripts cannot access other window objects’ properties if the parent webpage and embedded webpage have different origins.</p>
<p>Instead, you should use <code class="language-plaintext highlighter-rouge">Window.postMessage()</code> method for cross-origin communication.</p>
<h3 id="switching-iframe-webpages">Switching Iframe Webpages</h3>
<p>You can switch embedded webpages by using an anchor element(<a>). To switch iframe webpages, you should give the iframe element a name via its <code class="language-plaintext highlighter-rouge">name</code> attribute. Then, an anchor element can target an iframe element via its <code class="language-plaintext highlighter-rouge">target</code> attribute.</p>
<p>For example:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><a</span> <span class="na">href=</span><span class="s">"webpage1.html"</span> <span class="na">target=</span><span class="s">"myIframe"</span><span class="nt">></span>Webpage 1<span class="nt"></a></span>
<span class="nt"><iframe</span>
<span class="na">name=</span><span class="s">"myIframe"</span>
<span class="na">width=</span><span class="s">"500"</span> <span class="na">height=</span><span class="s">"500"</span><span class="nt">></span>
<span class="nt"></iframe></span>
</code></pre></div></div>
<p>To see a complete example, you can save the following HTML in an html file: homepage.html or download <a href="/assets/html/homepage.html" download="complete-homepage.html">homepage.html</a>. Then, you can drag and drop the HTML file onto a browser window to open it.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
<span class="nt"><meta</span>
<span class="na">name=</span><span class="s">"viewport"</span>
<span class="na">content=</span><span class="s">"width=device-width, initial-scale=1.0"</span><span class="nt">></span>
<span class="nt"><meta</span>
<span class="na">http-equiv=</span><span class="s">"X-UA-Compatible"</span>
<span class="na">content=</span><span class="s">"ie=edge"</span><span class="nt">></span>
<span class="nt"><title></span>Homepage<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><h1></span>Homepage<span class="nt"></h1></span>
<span class="nt"><a</span>
<span class="na">href=</span><span class="s">"https://jun711.github.io"</span>
<span class="na">target=</span><span class="s">"homepageIframe"</span><span class="nt">></span>Jun's blog<span class="nt"></a></span>
<span class="nt"><br</span> <span class="nt">/><br</span> <span class="nt">/></span>
<span class="nt"><a</span>
<span class="na">href=</span><span class="s">"webpage1.html"</span>
<span class="na">target=</span><span class="s">"homepageIframe"</span><span class="nt">></span>Webpage 1<span class="nt"></a></span>
<span class="nt"><br</span> <span class="nt">/></span>
<span class="nt"><p></span>My website embedded in an Iframe below<span class="nt"></p></span>
<span class="nt"><iframe</span>
<span class="na">title=</span><span class="s">"Homepage Iframes"</span>
<span class="na">name=</span><span class="s">"homepageIframe"</span>
<span class="na">src=</span><span class="s">"https://jun711.github.io"</span>
<span class="na">width=</span><span class="s">"500"</span> <span class="na">height=</span><span class="s">"500"</span><span class="nt">></span>
<span class="nt"><p></span>iframes are not supported by this browser.<span class="nt"></p></span>
<span class="nt"></iframe></span>
<span class="nt"><style></span>
<span class="nt">iframe</span> <span class="p">{</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="no">black</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt"></style></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<h3 id="embed-youtube-iframe">Embed Youtube Iframe</h3>
<p>To test using a real world example, you can get HTML iframe code for a YouTube video and include it in your webpage HTML.</p>
<ol>
<li>
<p>Open up a YouTube video that you want to embed.</p>
</li>
<li>
<p>Click <code class="language-plaintext highlighter-rouge">share</code> button and a list of share options will appear. <br />
<img src="/assets/images/2019-08-25-html-iframe-101/embed-youtube-video.png" alt="Embed YouTube Video Using An Iframe" /></p>
</li>
<li>
<p>Select <code class="language-plaintext highlighter-rouge">embed</code> and HTML to embed that video will be generated.<br />
<img src="/assets/images/2019-08-25-html-iframe-101/youtube-video-iframe-html.png" alt="Embed YouTube Video Using An Iframe" /></p>
</li>
<li>
<p>Click <code class="language-plaintext highlighter-rouge">COPY</code> to copy the video iframe.</p>
</li>
</ol>
<p>Iframe for a YouTube video looks like this:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><iframe</span>
<span class="na">width=</span><span class="s">"560"</span> <span class="na">height=</span><span class="s">"315"</span>
<span class="na">src=</span><span class="s">"https://www.youtube.com/embed/x0tz7nofFH4"</span>
<span class="na">frameborder=</span><span class="s">"0"</span>
<span class="na">allow=</span><span class="s">"accelerometer; autoplay; encrypted-media;
gyroscope; picture-in-picture"</span>
<span class="na">allowfullscreen</span><span class="nt">></iframe></span>
</code></pre></div></div>
<p>The following is an example of a YouTube video embedded on my blog using HTML iframe.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/x0tz7nofFH4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn about HTML Inline Frame element (<iframe>) through some examples.How to Update Python 3.6 to Python 3.7 on Mac OS2019-08-24T21:00:00-07:002019-08-24T21:00:00-07:00https://jun711.github.io/devop/how-to-update-python3.6-to-python3.7-on-mac-os<p>Learn how to upgrade Python 3.6 to Python 3.7 on Mac OS.</p>
<p>This post has been updated on <a href="https://jun711.github.io/devops/how-to-update-python3.6-to-python3.7-plus-on-mac-os/">How to Update Python 3.6 to Python 3.8 on Mac OS</a>. This post will be removed end of this month.</p>
<h2 id="python-official-site">Python Official Site</h2>
<p>1) Open up <a href="https://www.python.org/downloads/" target="view_window">Python official download site</a>. It looks something like the image below. Press <code class="language-plaintext highlighter-rouge">Download Python 3.7.4</code> or the version you would like to download.</p>
<p><img src="/assets/images/2019-08-22-how-to-install-python3-on-mac-os/python-official-download-site.png" alt="Python Official Site" /></p>
<p>2) Use the download installer to install Python 3.7. You can refer to <a href="https://jun711.github.io/devops/how-to-install-python3-on-mac-os/" target="view_window">How to Install Python3 article</a> for more information.</p>
<h2 id="homebrew">Homebrew</h2>
<p>If you use <a href="https://brew.sh/" target="view_window">Homebrew</a>, you can run <code class="language-plaintext highlighter-rouge">brew install</code> command to update Python to Python 3.7</p>
<pre class="code"><code>
brew install python3
</code></pre>
<h2 id="verification">Verification</h2>
<p>After you install, python3 command will point to <code class="language-plaintext highlighter-rouge">Python 3.7</code>. You can verify by using commands below.</p>
<pre class="code"><code>
python3 --version
# Python 3.7.4
</code></pre>
<p>You can use <code class="language-plaintext highlighter-rouge">which</code> command to find out the location of Python 3.7</p>
<pre class="code"><code>
which python3
# /Library/Frameworks/Python.framework/Versions/3.7/bin/python3
which python3.7
# /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7
</code></pre>
<h2 id="note">Note</h2>
<p>You can check out <a href="https://jun711.github.io/devops/how-to-install-pip-on-mac-os/" target="view_window">How to Install Pip article</a> to learn how to install Pip.</p>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to upgrade Python 3.6 to Python 3.7 on Mac OS.How to Update Python 3.6 to Python 3.7 or 3.8 on Mac OS2019-08-24T21:00:00-07:002019-08-24T21:00:00-07:00https://jun711.github.io/devops/how-to-update-python3.6-to-python3.7-plus-on-mac-os<p>Learn how to upgrade Python 3.6 to Python 3.7 or 3.8 on Mac OS.</p>
<h2 id="python-official-site">Python Official Site</h2>
<p>1) Open up <a href="https://www.python.org/downloads/" target="view_window">Python official download site</a>. It looks something like the image below. Press <code class="language-plaintext highlighter-rouge">Download Python 3.7.4</code>(release date was July 8, 2019) or <code class="language-plaintext highlighter-rouge">Download Python 3.8.0</code>(release date was Oct. 14, 2019) or the version you would like to download.</p>
<p><img src="/assets/images/2019-08-22-how-to-install-python3-on-mac-os/python-official-download-site.png" alt="Python Official Site" /></p>
<p>2) Use the download installer to install Python 3.7. You can refer to <a href="https://jun711.github.io/devops/how-to-install-python3-on-mac-os/" target="view_window">How to Install Python3 article</a> for more information.</p>
<h2 id="homebrew">Homebrew</h2>
<p>If you use <a href="https://brew.sh/" target="view_window">Homebrew</a>, you can run <code class="language-plaintext highlighter-rouge">brew install</code> command to update Python to Python 3.7</p>
<pre class="code"><code>
brew install python3
</code></pre>
<h2 id="verification">Verification</h2>
<p>After you install, python3 command will point to <code class="language-plaintext highlighter-rouge">Python 3.7</code>. You can verify by using commands below.</p>
<pre class="code"><code>
python3 --version
# Python 3.7.4
</code></pre>
<p>You can use <code class="language-plaintext highlighter-rouge">which</code> command to find out the location of Python 3.7</p>
<pre class="code"><code>
which python3
# /Library/Frameworks/Python.framework/Versions/3.7/bin/python3
which python3.7
# /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7
</code></pre>
<h2 id="note">Note</h2>
<p>You can check out <a href="https://jun711.github.io/devops/how-to-install-pip-on-mac-os/" target="view_window">How to Install Pip article</a> to learn how to install Pip.</p>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to upgrade Python 3.6 to Python 3.7 or 3.8 on Mac OS.How to Install Pip on Mac OSX2019-08-23T21:00:00-07:002019-08-23T21:00:00-07:00https://jun711.github.io/devops/how-to-install-pip-on-mac-os<p>Learn how to handle <code class="language-plaintext highlighter-rouge">bash: pip: command not found</code> error.</p>
<h2 id="reasons">Reasons</h2>
<p>1) One possible reason for this error could be pip was not installed or its path wasn’t configured correctly. In general, reinstalling pip can fix this error.</p>
<pre class="code"><code>
bash: pip: command not found
</code></pre>
<p>2) Another reason is you have Python3 installed and you could use <code class="language-plaintext highlighter-rouge">pip3</code> instead of pip. To check if you have pip3, you can run</p>
<pre class="code"><code>
pip3 --version
</code></pre>
<h2 id="install-pip">Install Pip</h2>
<p>As of 2019, you can install <code class="language-plaintext highlighter-rouge">pip</code> using a Python script
Download <a download="get-pip.py" href="https://bootstrap.pypa.io/get-pip.py">get-pip.py</a> provided by https://pip.pypa.io using the following command.</p>
<p>1) Run the following command via your terminal.</p>
<pre class="code"><code>
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
</code></pre>
<p>Output:</p>
<pre class="code"><code>
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1733k 100 1733k 0 0 3154k 0 --:--:-- --:--:-- --:--:-- 3152k
</code></pre>
<p>2) After you download <code class="language-plaintext highlighter-rouge">get-pip.py</code> Python file, run it using this command. You have to type in your password.</p>
<pre class="code"><code>
sudo python get-pip.py
</code></pre>
<p>Output:</p>
<pre class="code"><code>
Password:
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020.
Please upgrade your Python as Python 2.7 won't be maintained after
that date. A future version of pip will drop support for Python 2.7.
More details about Python 2 support in pip,
can be found at
https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting pip
Downloading https://files.pythonhosted.org/packages/30/db/
9e38760b32e3e7f40cce46dd5fb107b8c73840df38f0046d8e6514e675a1/
pip-19.2.3-py2.py3-none-any.whl (1.4MB)
|████████████████████████████████| 1.4MB 1.8MB/s
Installing collected packages: pip
Found existing installation: pip 19.2.3
Uninstalling pip-19.2.3:
Successfully uninstalled pip-19.2.3
Successfully installed pip-19.2.3
</code></pre>
<p>3) After you done installing, run this command to check if pip is installed.</p>
<pre class="code"><code>
pip --version
</code></pre>
<p>Possible output:</p>
<pre class="code"><code>
pip 19.2.3 from /Library/Frameworks/Python.framework/
Versions/3.7/lib/python3.7/site-packages/pip (python 3.7)
</code></pre>
<p>4) Remember to clean up after installing pip by removing the installer file, <code class="language-plaintext highlighter-rouge">get-pip.py</code>.</p>
<pre class="code"><code>
rm get-pip.py
</code></pre>
<h2 id="note">Note</h2>
<p>1) To install a package using pip, you can run <code class="language-plaintext highlighter-rouge">pip install package_name</code> or <code class="language-plaintext highlighter-rouge">pip3 install package_name</code>.</p>
<p>2) Note that Python 2.7 will not be maintained starting January 1st, 2020. Check out <a href="https://jun711.github.io/devops/how-to-install-python3-on-mac-os/" target="view_window">How to Install Python 3 on Mac OSX</a> article to install Python 3.</p>
<h2 id="support-jun">Support Jun</h2>
<p>Thank you for reading! <style>.bmc-button img{width: 27px !important;margin-bottom: 1px !important;box-shadow: none !important;border: none !important;vertical-align: middle !important;}.bmc-button{line-height: 36px !important;height:37px !important;text-decoration: none !important;display:inline-flex !important;color:#000000 !important;background-color:#FFFFFF !important;border-radius: 3px !important;border: 1px solid transparent !important;padding: 0px 9px !important;font-size: 17px !important;letter-spacing:-0.08px !important;box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;margin: 0 auto !important; !important;-webkit-box-sizing: border-box !important;box-sizing: border-box !important;-o-transition: 0.3s all linear !important;-webkit-transition: 0.3s all linear !important;-moz-transition: 0.3s all linear !important;-ms-transition: 0.3s all linear !important;transition: 0.3s all linear !important;}.bmc-button:hover, .bmc-button:active, .bmc-button:focus {-webkit-box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;text-decoration: none !important;box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5) !important;opacity: 0.85 !important;color:#000000 !important;}</style><a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/jun711"><img src="https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg" alt="Support Jun" /><span style="margin-left:5px">Support Jun</span></a></p>
<p><a target="_blank" href="https://amzn.to/38iEuPA">Support Jun on Amazon US</a><img src="//ir-na.amazon-adsystem.com/e/ir?t=jun71107-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><a id="support-on-amzn" href="https://www.amazon.ca/?&_encoding=UTF8&tag=jun7110a-20&linkCode=ur2&linkId=60b74555f1611d644d27d8b13f8b9418&camp=15121&creative=330641" target="_blank">Support Jun on Amazon Canada</a></p>
<p>If you are preparing for Software Engineer interviews, I suggest <a id="amzn-algo" href="https://amzn.to/2ljwZnc" target="_blank">Elements of Programming Interviews in Java</a> for algorithm practice. Good luck!</p>
<p>You can also support me by following me on <a id="follow-on-medium" href="https://medium.com/@jun711.g" target="view_window">Medium</a> or <a id="follow-on-twitter" href="https://twitter.com/Jun711_" target="view_window">Twitter</a>.</p>
<p>Feel free to contact me if you have any questions.</p>JunLearn how to handle bash: pip: command not found error.