tag:blogger.com,1999:blog-64538574541259435272024-03-28T14:14:07.782+07:00My GeeksHung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.comBlogger221125tag:blogger.com,1999:blog-6453857454125943527.post-76651421687611709552020-03-03T17:55:00.001+07:002020-03-03T17:57:37.375+07:00Setup Gitea on Windows<a href="https://github.com/go-gitea/gitea">Gitea</a> is an open source project that supports to make a self-hosted Git service. There are many free Git services like Github but when you host a private Git project, you must pay. So Gitea is one of the best choices when you need to manage private Git projects on your own on-prem version control server.<br />
<br />
In previous article, I show <a href="https://vivavivugeek.blogspot.com/2020/02/git-server-on-windows-with-openssh.html">howto setup Git Server on Windows with OpenSSH</a>. In this article, I will show howto setup Gitea on Windows.<br />
<br />
<b>1. Download & Install Gitea</b><br />
Select a latest Gitea built for Windows and download it from: <a href="https://dl.gitea.io/gitea">https://dl.gitea.io/gitea</a> (e.g. <a href="https://dl.gitea.io/gitea/1.9.6/gitea-1.9.6-windows-4.0-386.exe">gitea-1.9.6-windows-4.0-386.exe</a> depending on your Windows).<br />
Copy this file to a folder (e.g. <i>C:\Gitea</i>) and rename it to <i>gitea.exe</i>.<br />
Run <i>C:\Gitea\gitea.exe</i> from Windows cmd:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3KaO4NBACIX0Bc0YWWiIuoFOnlecxSS28XYbncwR0iNZPKNS42PCc6EhWyRYgHIfMs_X4gX6xZFUyQXNDQLZVInF1zTvl4hyWCNjh4lzKwOvJjiZeoA3-MS6Jpbak45nkf8bYMdQigdw5/s1600/win-gitea-setup-1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="392" data-original-width="1090" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3KaO4NBACIX0Bc0YWWiIuoFOnlecxSS28XYbncwR0iNZPKNS42PCc6EhWyRYgHIfMs_X4gX6xZFUyQXNDQLZVInF1zTvl4hyWCNjh4lzKwOvJjiZeoA3-MS6Jpbak45nkf8bYMdQigdw5/s640/win-gitea-setup-1.PNG" width="640" /></a></div>
<br />
Go to http://127.0.0.1:3000/ to configure initial configuration database. Gitea supports Microsoft SQL, MySQL, PostgreSQL and SQLite databases. Click "<i>Sign In</i>" button on the top left, then choose a database type you had, for me I select MSSQL:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQDipCfptRzuNkV5-caytnhFjj2ST6PYuNXt6Xe4vEweufl4MKGbRLbs4cC2-6GNHkvobJf4VchcYgIq9tmirEudkcQ7dGC4YJp3bKDjHS2tTMwOiEzNpmfqIy7VtGNVjGLXVEIL-uYFaV/s1600/win-gitea-setup-2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="809" data-original-width="1452" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQDipCfptRzuNkV5-caytnhFjj2ST6PYuNXt6Xe4vEweufl4MKGbRLbs4cC2-6GNHkvobJf4VchcYgIq9tmirEudkcQ7dGC4YJp3bKDjHS2tTMwOiEzNpmfqIy7VtGNVjGLXVEIL-uYFaV/s640/win-gitea-setup-2.PNG" width="640" /></a></div>
<br />
Fill in necessary info. In <b><i>Optional Settings</i></b> >> <b><i>Administrator Account Settings,</i></b> let add an username (e.g. <i>giteaadmin</i>), it will be used as the administrator account for Gitea.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDoQCeLUHry9wpdsaBca3emN65e7aX8U76yv1p-SMNWJz4rMCFL-97mppAxG7qDd7sOLQurRS5QdFG5XMqd42mPrcTM8lv3So4lAv7WF7ILumtxuy8_Njwx2Hiaq8bGLrR5YyasutqsKvO/s1600/win-gitea-setup-3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="739" data-original-width="1066" height="442" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDoQCeLUHry9wpdsaBca3emN65e7aX8U76yv1p-SMNWJz4rMCFL-97mppAxG7qDd7sOLQurRS5QdFG5XMqd42mPrcTM8lv3So4lAv7WF7ILumtxuy8_Njwx2Hiaq8bGLrR5YyasutqsKvO/s640/win-gitea-setup-3.PNG" width="640" /></a></div>
Then click "<b><i>Install Gitea</i></b>" button. After that you can sign in to the Gitea portal.<br />
To change settings, you can modify the file <i>C:\Gitea\custom\conf\app.ini</i>, for example I add below lines to make English as default language for the Gitea portal:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">[i18n]<br />LANGS = en-US<br />NAMES = English</span></blockquote>
<b>2. Run Gitea as Windows service</b><br />
To start Gitea portal, you must run <i>C:/Gitea/gitea.exe</i> from Windows cmd or PowerShell. For convinient, let create a Windows service to start it automatically.<br />
Terminate <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">C:/Gitea/gitea.exe</span> if it is running, open Windows cmd as Administrator and run the following command:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">sc create GiteaService start= auto binPath= ""C:\Gitea\gitea.exe" web --config "C:\Gitea\custom\conf\app.ini""</span></blockquote>
Open Windows Services and start GiteaService, then open website http://localhost:3000/ to check if working.<br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<b>3. Create project repo and add user (collaborator)</b><br />
Sign-in with admin user, on the <b><i>Dashboard</i></b> >> <i><b>Repository</b></i> area click <b>+ button</b> to add new project repo:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaUk-cb4yBqSlnIqiIDzCyI8oS0R_vxSErWTCcexUeiudaO6LMiswlLKy6Vl5EQG19CQTk18e5RW7NEmMJOC1QerU23622StQv8miOLxrfqhecr8E6dl3_ThOXkpaNpizSPyuUVRLlYwjm/s1600/win-gitea-setup-5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="398" data-original-width="1600" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaUk-cb4yBqSlnIqiIDzCyI8oS0R_vxSErWTCcexUeiudaO6LMiswlLKy6Vl5EQG19CQTk18e5RW7NEmMJOC1QerU23622StQv8miOLxrfqhecr8E6dl3_ThOXkpaNpizSPyuUVRLlYwjm/s640/win-gitea-setup-5.PNG" width="640" /></a></div>
Fill in project info:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEialXmkxESGkbPxh8glbqiWKaWbipzgKIXjc3OwTeohM8Gwwb6VeThKRFQRhjQglZtAK8Nd2FDvG6PG8pQ-fHuc7ky5zBkBxCy2L7dMgFzI4PIqaDCaGBdbE2cTQUjL8zt-vAwYREbHLSAT/s1600/win-gitea-setup-4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="827" data-original-width="944" height="560" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEialXmkxESGkbPxh8glbqiWKaWbipzgKIXjc3OwTeohM8Gwwb6VeThKRFQRhjQglZtAK8Nd2FDvG6PG8pQ-fHuc7ky5zBkBxCy2L7dMgFzI4PIqaDCaGBdbE2cTQUjL8zt-vAwYREbHLSAT/s640/win-gitea-setup-4.PNG" width="640" /></a></div>
Click "<i><b>Create Repository</b></i>" button. Now you have a repo for your project. Creator will be administrator for this repo as default.<br />
Next let create user and add it to the project. Go to <b><i>Site Administration</i></b> >> <b><i>User Accounts</i></b> >> click <b><i>Create User Account</i></b> button to create new user:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZ3elnoDBryIhLb3ADbpK2c4WuAFjSsxHsGNOBxQmTwzkpHXfST2-2Nz2GMbxYP46gwIu1EGxFaPUdyfZgnNcYkEB-sb0XdX4nT8JwN99Dga2YDFePtysntJbDl3WkujFmYo4aW-Y7OO_/s1600/win-gitea-setup-6.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="454" data-original-width="270" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZ3elnoDBryIhLb3ADbpK2c4WuAFjSsxHsGNOBxQmTwzkpHXfST2-2Nz2GMbxYP46gwIu1EGxFaPUdyfZgnNcYkEB-sb0XdX4nT8JwN99Dga2YDFePtysntJbDl3WkujFmYo4aW-Y7OO_/s320/win-gitea-setup-6.PNG" width="190" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7oruGJ2Ks7_8sklOhqbiuLzkP7_wam_b38QLXaPn8VkADCiJhKUtEd-tl1bbycSCVZrneFnn9HzNKns9jhyEd3MObTRDm05f5G1wS3CbE7O8Thb0tJsV5mLqSO0yr6dFbSF5At6v_o049/s1600/win-gitea-setup-7.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="207" data-original-width="1451" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7oruGJ2Ks7_8sklOhqbiuLzkP7_wam_b38QLXaPn8VkADCiJhKUtEd-tl1bbycSCVZrneFnn9HzNKns9jhyEd3MObTRDm05f5G1wS3CbE7O8Thb0tJsV5mLqSO0yr6dFbSF5At6v_o049/s640/win-gitea-setup-7.PNG" width="640" /></a></div>
<br />
Open the project, from its <b><i>Settings</i></b> >> <b><i>Collaborators</i></b> >> key the username of <span style="background-color: white;">c<span style="color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">ollaborator then click <b><i>Add Collaborator</i></b> button: </span></span><span style="background-color: white;"><span style="color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span></span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQFBCC5RxhR1gEN1Ua1kyggk5nflnMQ4Hv1KhvX72N6oFRYpRbOA1ZPzPwSXNcLuIyByryEBLDFx8011kMIXpYrgNfR-hG1sgienIn0QCWcHPzgn0wpzvKR1FaEskVmlL7lL5zGxwugMhM/s1600/win-gitea-setup-8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="507" data-original-width="1600" height="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQFBCC5RxhR1gEN1Ua1kyggk5nflnMQ4Hv1KhvX72N6oFRYpRbOA1ZPzPwSXNcLuIyByryEBLDFx8011kMIXpYrgNfR-hG1sgienIn0QCWcHPzgn0wpzvKR1FaEskVmlL7lL5zGxwugMhM/s640/win-gitea-setup-8.PNG" width="640" /></a></div>
<br />
<b>4. Work as a collaborator on Git portal</b><br />
Create user for each collaborator (developer). On the PC of collaborator, open Gitea portal via link: <i>http://<IP server>:3000/</i> (e.g. <i>http://192.168.10.101:3000/</i>).<br />
In case of you want to access your projects via Internet, you can setup https with a domain. See guidelines here: <a href="https://docs.gitea.io/en-us/https-setup/">https://docs.gitea.io/en-us/https-setup/</a><br />
In case of you just want to access your projects within your LAN/VPN, you can simply use server IP.<br />
After login, each developer will see projects joined. For example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqksnvLWHEWejyvpxJopPd3MvV58tvGhcmm9qWG-niEDNVQHBShbl1G6HJhxbR47ntpgrjUSFwJ5obHPr25RublFo-d7Ll36P5UfbU34QDSH8_UXZsPSrUbhRvIlvR-jn8I_ugiyQXClkc/s1600/win-gitea-setup-9.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="826" data-original-width="1600" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqksnvLWHEWejyvpxJopPd3MvV58tvGhcmm9qWG-niEDNVQHBShbl1G6HJhxbR47ntpgrjUSFwJ5obHPr25RublFo-d7Ll36P5UfbU34QDSH8_UXZsPSrUbhRvIlvR-jn8I_ugiyQXClkc/s640/win-gitea-setup-9.PNG" width="640" /></a></div>
Pay attention on the http link of Git project, e.g.: <i>http://localhost:3000/itgitad/TestProject.git</i><br />
Replace localhost by server IP (e.g. <i style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">http://192.168.10.101:3000/itgitad/TestProject.git</i>) ==> you will have the right link of this Git project for working in local repo.<br />
<br />
On this portal, developer can use functions like on GitHub.com. Oh lala...<br />
<br />
<b>5. Work on local repo</b><br />
On your computer, open <i><b>Windows cmd</b></i>, cd to the folder that you want to make a local repo for your project, run the following commands:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git init</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git remote add origin http://192.168.10.101:3000/itgitad/TestProject.git</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git pull origin master</span></blockquote>
After above commands, it will download latest info + source from remote repo to your local repo. Change/add a file, then push to the server:
<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git add NewFile.txt</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git commit -m "add NewFile"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git push origin master</span></blockquote>
It will pop up to ask username & password ==> enter username & passowrd created ont the Gitea web portal. Now open the Gitea portal, you will see <i>NewFile.txt</i>.<br />
<br />
You can <a href="https://vivavivugeek.blogspot.com/2016/03/visual-studio-code-how-to-work-with.html">use Visual Studio Code for working with your Git project</a>.<br />
Have a fun when reading. Bye!<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com3tag:blogger.com,1999:blog-6453857454125943527.post-14453492819149892312020-02-24T17:51:00.002+07:002020-02-24T17:53:21.546+07:00Git Server on Windows with OpenSSH, Remote and Local Repository<b>1. What is Git Server?</b><br />
It is a server installed Git service. In which, Git is a distributed version control system designed to handle everything from small to very large projects with speed and efficiency.<br />
In this article, I will guide you step by step to setup a Git Server on Windows with OpenSSH.<br />
<br />
<b>2. What is Remote & Local Repository?</b><br />
Remote <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Repository is a r<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">epository on a server where source codes from developers are centralized. While Local <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Repository is a <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">r</span><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">epository cloned (copied) from <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Remote </span><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Repository to developer's computer (client).</span></span></span></span></span><br />
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">The following picture will illustrate how repositories working.</span></span></span></span></span><br />
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span></span></span></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNQRUBQiGeV7SID1DIuRQIxzliaylW-4KT3qEqt9aLlxoXNQBbmV-2MysMEw_DyhcvnsbVpm4Jaic_D2NG0Zx6viKjy-JwLFJoGIky100mytr_xPx2O2aBul0H0gK7kX7rXaEt7AkVbwhx/s1600/git-remote-and-local-repository.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="859" data-original-width="1018" height="335" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNQRUBQiGeV7SID1DIuRQIxzliaylW-4KT3qEqt9aLlxoXNQBbmV-2MysMEw_DyhcvnsbVpm4Jaic_D2NG0Zx6viKjy-JwLFJoGIky100mytr_xPx2O2aBul0H0gK7kX7rXaEt7AkVbwhx/s400/git-remote-and-local-repository.png" width="400" /></a></div>
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b>3. Required tools</b></span></span></span></span></span><br />
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">+<a href="https://github.com/PowerShell/Win32-OpenSSH/releases">Win32 OpenSSH</a></span></span></span></span></span><br />
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">+<span id="goog_194273142"></span><a href="https://git-scm.com/download/win">Git for Windows<span id="goog_194273143"></span></a></span></span></span></span></span><br />
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><a href="https://www.blogger.com/"></a><br /></span></span></span></span></span>
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b>4. Install Git for Windows</b></span></span></span></span></span><br />
<span style="background-color: white;">Go to <span id="goog_194273142" style="color: black; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"></span><a href="https://git-scm.com/download/win" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Git for Windows<span id="goog_194273143"></span></a>, select & download suitable version for your Windows (32-bit or 64-bit).</span><br />
<span style="background-color: white;">Installing it with option "<i>Use Git and optional Unix tools from the Command Prompt</i>" and "<i>Use the OpenSSL library</i>".</span><br />
<span style="background-color: white;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiERd8DcjsVJKVIfN0rAyveicIpvJIGvWuPQRg3OjdnqWFBkiA87akhmi303KZRaE45Hu2EiYNiMiiXd4i_ls_RcBTbqxtr2fnq4BUqfZvMbxVLv2B9EwptaLOYggA5-U9iQxxzZ_MurZpG/s1600/git-for-windows-installation-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="476" data-original-width="582" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiERd8DcjsVJKVIfN0rAyveicIpvJIGvWuPQRg3OjdnqWFBkiA87akhmi303KZRaE45Hu2EiYNiMiiXd4i_ls_RcBTbqxtr2fnq4BUqfZvMbxVLv2B9EwptaLOYggA5-U9iQxxzZ_MurZpG/s320/git-for-windows-installation-1.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN87e2wWnmMIWFW7KBYBcK9KsjKGC-Bouzx9lEBP5DTCijw0RqGJcQVBYkc2kcw7PFnUe0dpgHV7Prxa29ck2FnhoJ-38IacNckQa6cPe2KRZ6MQP5sSxStSE1Ub5CRIzuwLGR8MyUdwGq/s1600/git-for-windows-installation-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="476" data-original-width="582" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN87e2wWnmMIWFW7KBYBcK9KsjKGC-Bouzx9lEBP5DTCijw0RqGJcQVBYkc2kcw7PFnUe0dpgHV7Prxa29ck2FnhoJ-38IacNckQa6cPe2KRZ6MQP5sSxStSE1Ub5CRIzuwLGR8MyUdwGq/s320/git-for-windows-installation-2.png" width="320" /></a></div>
<span style="background-color: white;"><br /></span>
<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">After installing, open Windows cmd or Git bash run below command to check if it is installed ok:</span></span></span></span></span><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git --version</span></blockquote>
<span style="background-color: white;"><b>5. Install OpenSSH</b></span><br />
Go to <a href="https://github.com/PowerShell/Win32-OpenSSH/releases" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Win32 OpenSSH</a>, select & download a suitable version for your Windows. Unpack it to a folder (e.g. <i>C:\OpenSSH</i>).<br />
Run <b><i>Windows PowerShell</i></b> as <b><i>Administrator</i></b> right, change to the OpenSSH folder, then run below command to install:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">powershell -ExecutionPolicy ByPass -File install-sshd.ps1</span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace;"></span><span style="font-size: x-small;"></span>See the following picture for more details:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPJ-kbbhZQnYebfTQK21Bo2E6oA3rVHLtTPambpPSwaU-ab2enbcSWAnXdA5OM_sLlOwNDZ5hVbOPOuy1Zm2ZspOblQLnU_p4wrlk-9z2Pyu0Drg_-Ve0cWZTznEgXgxegEtaZze4U68X/s1600/win-openssh-installation-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="268" data-original-width="981" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPJ-kbbhZQnYebfTQK21Bo2E6oA3rVHLtTPambpPSwaU-ab2enbcSWAnXdA5OM_sLlOwNDZ5hVbOPOuy1Zm2ZspOblQLnU_p4wrlk-9z2Pyu0Drg_-Ve0cWZTznEgXgxegEtaZze4U68X/s640/win-openssh-installation-1.png" width="640" /></a></div>
<br />
Open <b><i>Windows Services</i></b> then set <b><i>OpenSSH SSH Server</i></b> & <b><i>OpenSSH Authetication Agent</i></b> to <b><i>Automatic</i></b> and start them.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhBfzNezDosAhZ0eTSVNlcHgIxOKIlGcuop-zArPc-qtaYpGciz4XWyDNJVYp52IbBuXV2y5F_JmkC6KxDkmdOGF_bXV5lmRyofgbLJHYPy_RZprpmL72ziBXpqfzg68wPHhUjb9PIV5eS/s1600/win-openssh-installation-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="816" data-original-width="1018" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhBfzNezDosAhZ0eTSVNlcHgIxOKIlGcuop-zArPc-qtaYpGciz4XWyDNJVYp52IbBuXV2y5F_JmkC6KxDkmdOGF_bXV5lmRyofgbLJHYPy_RZprpmL72ziBXpqfzg68wPHhUjb9PIV5eS/s320/win-openssh-installation-2.png" width="320" /></a></div>
Because OpenSSH use port 22 by default, so you must open this port on your Windows firewall. You can change the SSH service port value (e.g. Port 1235) in its config file: <i>C:\OpenSSH\sshd_config_default</i>. If you change the port, remember open the firewall for new port and restart SSH services.<br />
<br />
To check if the OpenSSH server is working, on a client computer download <a href="https://www.putty.org/">PuTTY tool</a> and connect to the SSH server via its IP and a Windows user on the server.<br />
In case your client computer already had ssh client, you can use Windows cmd to connect to the server. If your client doesn't have, you can install Win32 OpenSSH on the client. See below picture for <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">sample of </span>checking SSH connection.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYT2pRsYqEQHX-mFfyAzp34CplfuvDRVHLkM_WgQQCcg5ow0Hze6DZtqzVikUN-EVsAyXgiCp7bnwbtCFVh8R6z_1n-VWP4NW0H76HJho0MkAEIdZa4Dn873i1IdhV-MG2yjW7gxMNJs-6/s1600/win-openssh-installation-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="229" data-original-width="501" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYT2pRsYqEQHX-mFfyAzp34CplfuvDRVHLkM_WgQQCcg5ow0Hze6DZtqzVikUN-EVsAyXgiCp7bnwbtCFVh8R6z_1n-VWP4NW0H76HJho0MkAEIdZa4Dn873i1IdhV-MG2yjW7gxMNJs-6/s320/win-openssh-installation-3.png" width="320" /></a></div>
Every time you connect to the SSH server, it requires to input password. To avoid password, you can use Public & Private keys for authenticating. Let generate these keys on your clients by using <i><a href="https://www.ssh.com/ssh/keygen">ssh-keygen</a></i> tool, for example:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ssh-keygen -t rsa -b 4096</span></blockquote>
It will generate 2 files: <i>id_rsa</i> and <i>id_rsa.pub</i> in SSH folder of Windows user on the client (<i>C:\Users\<username>\.ssh</i>). Remember let <i>passphrase</i> as empty (key enter) when it asks you key in, it will help you skip to enter <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">passphrase every time you connect to the server. Copy <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">id_rsa.pub</span> file to the <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">SSH folder of Windows user on the server</span> (<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">C:\Users\<username>\.ssh</span>) </span>and rename it to <i>authorized_keys</i>. Then on the server, right click on this file and make sure removing rights of all users except Administrators and SYSTEM, for example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimhkxdFrTBym9fPORoCUArcmvj4ET9Dfjb7TE_6TYpK5Ngmt9kbsT1aKCkeRxaNQsHhUsJiZZyqcsYK4m3jORzB3QazbBez6ppX3DhUF1fyK-cZL9zajpN0rgxfZPj05S7TJ7hqjeqxd7s/s1600/win-openssh-setup-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="651" data-original-width="1022" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimhkxdFrTBym9fPORoCUArcmvj4ET9Dfjb7TE_6TYpK5Ngmt9kbsT1aKCkeRxaNQsHhUsJiZZyqcsYK4m3jORzB3QazbBez6ppX3DhUF1fyK-cZL9zajpN0rgxfZPj05S7TJ7hqjeqxd7s/s400/win-openssh-setup-1.png" width="400" /></a></div>
<br />
On the server, verify if file <i>C:\ProgramData\ssh\sshd_config</i> (file config of SSH service) has below lines <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">uncommented:</span><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">PubkeyAuthentication yes<br />AuthorizedKeysFile .ssh/authorized_keys</span></blockquote>
If not, let uncomment them then restart <b><i>OpenSSH SSH Server</i></b>. Try again with <i><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ssh username@computername_or_IP</span></i>, it will login to SSH Server without entering any password/<span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">passphrase.</span><br />
<br />
<b>6. Create <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Remote </span><span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Repository (central repo)</span></b><br />
On the server, for existing source folder, you can run below commands from <b><i>Windows cmd</i></b>:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">cd D:\mygit\my_central_repo</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git init --bare</span></blockquote>
Or create new central repo by command:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git clone --bare D:\mygit\my_central_repo</span></blockquote>
On the client, create a folder and add remote repository into:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">cd E:\local_repo</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git init</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git remote add origin hunglv@192.168.10.101:D:/mygit/my_centro_repo</span></blockquote>
In which <i>origin</i> is a name standfor remote repo. Next you must run 2 below work arround commands to set powershell as default Shell in registry:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git config --local remote.origin.uploadpack "powershell git-upload-pack"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git config --local remote.origin.receivepack "powershell git-receive-pack"</span></blockquote>
Now you can fetch remote repo to your local repo for working:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git fetch origin</span></blockquote>
OK, you have done the setup for Git Server on Windows with OpenSSH, Remote and Local Repository. Next is common Git commands that are often used.<br />
<br />
<b>7. Basic Git commands</b><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git fetch <remote name> <branch></span>: fetching repo versioning data from remote repo to local repo<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git pull <remote name> <brannch>:</span> get all (included new files & merge updated files) from remote repo to local<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git add <file>:</span> add new file to local repo<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git commit -m <"message">:</span> commit all updates / news to your local repo<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git push <remote> <branch>:</span> push <span style="background-color: white; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">all updates / news from your local repo to remote repo</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git remote -v</span>: see remote repo linked<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">git status</span>: check status / changes in local repo<br />
<br />
The end for this article. Hope you can start your projects on Git easily.<br />
<b><i>Any comment is welcome. Bye!</i></b>Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com2tag:blogger.com,1999:blog-6453857454125943527.post-82837753927305728262019-03-17T22:29:00.002+07:002019-03-17T22:36:35.440+07:00Learning Ionic 4 - Part 3In this Part 3, we will focus on adding a component into page, working with ionic components, using SCSS, and rolling numbers to play games.<br />
<br />
According to the mockup, we have an array of numbers which appears on pages: Games (Home), Play Games and History. Below is my Home page after finishing:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_CHdd-WEGzgVEVJij4HvIp46mZb1sA5TQRc7tmiU3lhRtECKmAsVoG0ZlAE_qrA2jX7hagmrW-tCZXiByna69HXfDRABxmPUzjW7RdbY-WL0ax7wVF0YjY34yimkDrr2ftExFisVRMplw/s1600/app_game_lot_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="614" data-original-width="349" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_CHdd-WEGzgVEVJij4HvIp46mZb1sA5TQRc7tmiU3lhRtECKmAsVoG0ZlAE_qrA2jX7hagmrW-tCZXiByna69HXfDRABxmPUzjW7RdbY-WL0ax7wVF0YjY34yimkDrr2ftExFisVRMplw/s400/app_game_lot_4.png" width="226" /></a></div>
So creating a component presenting array of numbers for reusing in pages is a good idea. Let generate this component:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g component components/NumbersPanel</span></blockquote>
It will generate files:<br />
<i>src/app/components/numbers-panel/<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span>-panel.component.html<br />src/app/components/<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span>-panel/<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span>-panel.component.spec.ts<br />src/app/components/<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span>-panel/<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span>-panel.component.ts<br />src/app/components/<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span>-panel/<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span>-panel.component.scss</i><br />
<i></i><br />
Modify <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>numbers</i></span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>-panel.component.ts</i> as below:</span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">import { Component, OnInit, Input } from '@angular/core';</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Component({<br /> selector: 'app-numbers-panel',<br /> templateUrl: './numbers-panel.component.html',<br /> styleUrls: ['./numbers-panel.component.scss']<br />})<br />export class NumbersPanelComponent implements OnInit {<br /> @Input() numbers: any = [];<br /> @Input() minval: number;<br /> @Input() maxval: number;</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constructor() {<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ngOnInit() {<br /> }<br />}</span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Modify <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">numbers</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">-panel.component.html</span> as below:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<div>
<blockquote class="tr_bq">
<span style="background-color: transparent; color: black; display: inline; float: none; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><div class="box-number-outline"><br /> <div class="box-number" *ngFor="let n of numbers">{{n}}</div><br /></div></span></span></blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Modify <i>numbers</i><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">-panel.component.scss</span> <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">as below:</span></span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">.box-number-outline {<br /> text-align: center;<br />}<br />.box-number {<br /> width: 35px;<br /> height: 25px;<br /> background-color: purple;<br /> display: inline-block;<br /> border: solid 1px white;<br /> color: white;<br /> padding-top: 2px;<br />}</span></span></blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">To allow this component used in pages, let create a file <b><i>src\app\components\components.module.ts</i></b> and add below code (this file can be created with the command <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g module components/components</span>, however I got error <i>'Tree type is not supported'</i> - ng cli error so I created it manually):</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">import { NgModule } from '@angular/core';<br />import { NumbersPanelComponent } from './numbers-panel/numbers-panel.component';<br />import { IonicModule } from '@ionic/angular';<br />import { CommonModule } from '@angular/common';</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@NgModule({<br /> declarations: [NumbersPanelComponent],<br /> imports: [CommonModule , IonicModule],<br /> exports: [NumbersPanelComponent]<br />})</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">export class ComponentsModule {}</span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">OK, we already had our component, let use it in Home page by declaring some things in <b><i>src\app\home\home.module.ts</i></b>:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">...<br />import { ComponentsModule } from '../components/components.module';</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">...</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@NgModule({<br /> imports: [<br /> ...<br /> ComponentsModule,<br /> …</span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Below is new code of <b><i>src\app\home\home.page.ts</i></b>:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">import { Component, OnInit } from '@angular/core';<br />import { AuthService } from '../services/auth.service';<br />import { MyTablesService } from '../services/my-tables.service';<br />import { NavController, AlertController } from '@ionic/angular';</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Component({<br /> selector: 'app-home',<br /> templateUrl: './home.page.html',<br /> styleUrls: ['./home.page.scss'],<br />})<br />export class HomePage implements OnInit {<br /> games: any = [];<br /> history: any = [];</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constructor(<br /> private auth: AuthService,<br /> private tableService: MyTablesService,<br /> private navCtrl: NavController,<br /> private alertCtrl: AlertController<br /> ) { }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ngOnInit() {<br /> this.auth.loggedin().then(isLoggedin => {<br /> if (!isLoggedin) {<br /> this.navCtrl.goRoot('/login');<br /> }<br /> });<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ionViewWillEnter() {<br /> this.loadGames();<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> loadGames() {<br /> this.tableService.getItems('games').then((d) => {<br /> this.games = d;<br /> this.tableService.getItems('history').then((h) => {<br /> this.history = h;<br /> for(let game of this.games) {<br /> let gh = this.tableService.getItemByField(this.history, 'game_id', game.id);<br /> if(gh.length > 0) {<br /> gh.sort(this.tableService.sortDescByField('play_time'));<br /> game.last_play_time = new Date(gh[0].play_time).toLocaleString('vi-VN');<br /> game.last_result = JSON.parse(gh[0].result);<br /> }<br /> }<br /> });<br /> });<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> newGame() {<br /> this.navCtrl.goForward('/new-game');<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> playGame(game_id) {<br /> this.navCtrl.goForward(`/play-game/${game_id}`);<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> async deleteGame(game_id) {<br /> let alert = await this.alertCtrl.create({<br /> message: 'Do you want to delete this game?',<br /> buttons: [<br /> {<br /> text: 'Cancel',<br /> role: 'cancel',<br /> handler: () => {<br /> }<br /> },<br /> {<br /> text: 'OK',<br /> handler: () => {<br /> this.tableService.setItem('games', game_id, 'deleted', true);<br /> }<br /> }<br /> ]<br /> });<br /> await alert.present();<br /> }<br />}</span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">And new code of <b><i>src\app\home\home.page.html</i></b>:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-header><br /> <ion-toolbar><br /> <ion-buttons slot="start"><br /> <ion-menu-button></ion-menu-button><br /> </ion-buttons><br /> <ion-title>Games</ion-title><br /> </ion-toolbar><br /></ion-header></span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-content padding><br /> <ion-grid *ngFor="let game of games; let i = index;"><br /> <div [ngClass]="(i % 2 == 0) ? 'grid_odd' : 'grid_even'" *ngIf="!game.deleted"><br /> <ion-row><br /> <ion-col size="11"><br /> <b>{{game.name}}</b><br /> </ion-col><br /> <ion-col size="1"><br /> <div class="play_icon"><br /> <ion-icon name="arrow-dropright-circle" style="zoom:1.2;" (click)=playGame(game.id)></ion-icon><br /> </div><br /> </ion-col><br /> </ion-row><br /> <ion-row><br /> <ion-col size="11"><br /> <div class="last_play_time" *ngIf="game.last_play_time"><br /> Last time: {{game.last_play_time}}<br /> </div><br /> <div class="last_play_time" *ngIf="!game.last_play_time"><br /> Haven't been played yet. Let play.<br /> </div><br /> </ion-col><br /> <ion-col size="1"><br /> <div class="delete_icon"><br /> <ion-icon name="close-circle" style="zoom:1.2;" (click)=deleteGame(game.id)></ion-icon><br /> </div><br /> </ion-col><br /> </ion-row><br /> <ion-row><br /> <ion-col size="3"><br /> <div class="last_result" *ngIf="game.last_play_time"><br /> Last result: <br /> </div><br /> </ion-col><br /> <ion-col size="9"><br /> <app-numbers-panel [numbers]="game.last_result"></app-numbers-panel><br /> </ion-col><br /> </ion-row><br /> </div><br /> </ion-grid><br /> <br /> <ion-fab vertical="bottom" horizontal="end" slot="fixed"><br /> <ion-fab-button color="danger" (click)="newGame()"><br /> <ion-icon name="add"></ion-icon><br /> </ion-fab-button><br /> </ion-fab><br /></ion-content></span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Pay your attention on the code <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><app-numbers-panel [numbers]="game.last_result"></app-numbers-panel></span> : ==> it will show the <b><i>NumbersPanel</i></b> component and put the last result of game to the component for displaying.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">On above html file, I also make alternate color for game rows, watch the code: <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">[ngClass]="(i % 2 == 0) ? 'grid_odd' : 'grid_even'"</span>.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">At this time, your Home page can list games but won't have any info about last playing result of games. So let generate PlayGame page and play, run the command:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g page PlayGame</span></span></blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace;"></span>Modify <b><i>src\app\play-game\play-game.page.ts</i></b> as below:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">import { Component, OnInit } from '@angular/core';<br />import { ActivatedRoute } from '@angular/router';<br />import { History, MyTablesService } from '../services/my-tables.service';<br />import { delay } from 'q';</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Component({<br /> selector: 'app-play-game',<br /> templateUrl: './play-game.page.html',<br /> styleUrls: ['./play-game.page.scss'],<br />})<br />export class PlayGamePage implements OnInit {<br /> game: any;<br /> numbers: any = [];<br /> history: History;<br /> curTime: any;<br /> played: boolean = false;</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constructor(<br /> private activeRoute: ActivatedRoute, <br /> private tableService: MyTablesService) {<br /> this.curTime = new Date().toLocaleString('vi-VN');<br /> this.history = new History();<br /> let game_id = this.activeRoute.snapshot.paramMap.get('id');<br /> this.tableService.getItem('games', game_id).then((d) => {<br /> this.game = d;<br /> for(let i=0; i < this.game.numbers; i++) {<br /> this.numbers.push(-1);<br /> }<br /> });<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ngOnInit() {<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> async startGame() {<br /> for(let i = 1; i < 3; i++) {<br /> for(let j = this.game.min_number; j <= this.game.max_number; j++) {<br /> for(let k=0; k < this.game.numbers; k++) {<br /> this.numbers[k] = j;<br /> }<br /> await delay(200);<br /> }<br /> }<br /> <br /> for(let i=0; i < this.game.numbers; i++) {<br /> this.numbers[i] = Math.floor(Math.random() * this.game.max_number) + this.game.min_number;<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> this.saveHistory();<br /> this.played = true;<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> saveHistory() {<br /> this.history.play_time = new Date();<br /> this.history.game_id = this.game.id;<br /> this.history.result = JSON.stringify(this.numbers);<br /> this.tableService.addItem('history', this.history);<br /> }<br />}</span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Modify <b><i>src\app\play-game\play-game.page.html</i></b> as below:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-header><br /> <ion-toolbar><br /> <ion-buttons slot="start"><br /> <ion-menu-button></ion-menu-button><br /> </ion-buttons><br /> <ion-title>Play Game</ion-title><br /> </ion-toolbar><br /></ion-header></span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-content padding><br /> <div *ngIf="game" style ="text-align: center; padding: 10px;"><br /> <b>{{game.name}}</b><br><br /> <i>{{curTime}}</i><br><br /> </div><br /> <app-numbers-panel [numbers]="numbers"></app-numbers-panel><br /> <div style ="text-align: center; padding: 10px;"><br /> <ion-button size="default" shape="round" color="secondary" (click)="startGame()" [disabled]="played"><br /> Start<br /> </ion-button><br /> </div><br /></ion-content></span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">In the function <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">startGame()</span>, I roll numbers from its min to max and delay 200ms when changing numbers. It is done 2 times and finished by randomizing numbers between its min & max. This is how I make the animation for rolling numbers -:)</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Yeah! Now we can create games, play them and have a fun. See how I play a game:</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUqKzwqetgn12yY7tFjYstjbXLOI2_QliTK2GANW6LT30JFIK3PVvqeW8QffhPj01JLMKmP-gMBgmkR7jw0OfkmIwxGrYI8-2Z1yeR_tYTRZgFVdJRFA-r7gUG5vlikiGElFRH4LAfi3NR/s1600/app_game_lot_5.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="618" data-original-width="348" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUqKzwqetgn12yY7tFjYstjbXLOI2_QliTK2GANW6LT30JFIK3PVvqeW8QffhPj01JLMKmP-gMBgmkR7jw0OfkmIwxGrYI8-2Z1yeR_tYTRZgFVdJRFA-r7gUG5vlikiGElFRH4LAfi3NR/s400/app_game_lot_5.gif" width="225" /></a></span></div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">After playing, we may need to see the history of playing games. It's time to code the History page.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Modify <b><i>src\app\history\history.page.ts</i></b> as below:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">import { Component, OnInit } from '@angular/core';<br />import { AuthService } from '../services/auth.service';<br />import { MyTablesService } from '../services/my-tables.service';<br />import { NavController } from '@ionic/angular';</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Component({<br /> selector: 'app-history',<br /> templateUrl: './history.page.html',<br /> styleUrls: ['./history.page.scss'],<br />})<br />export class HistoryPage implements OnInit {<br /> games: any = [];<br /> history: any = [];<br /> items: any = [];<br /> keywords: string = '';<br /> showSearchBar: boolean = true;</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constructor(<br /> private auth: AuthService,<br /> private tableService: MyTablesService,<br /> private navCtrl: NavController) { }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ngOnInit() {<br /> this.auth.loggedin().then(isLoggedin => {<br /> if (!isLoggedin) {<br /> this.navCtrl.goRoot('/login');<br /> }<br /> });<br /> }<br /> <br /> ionViewWillEnter() {<br /> this.loadGames();<br /> }<br /> <br /> loadGames() {<br /> this.tableService.getItems('games').then((d) => {<br /> this.games = d;<br /> this.items = d;<br /> this.tableService.getItems('history').then((h) => {<br /> this.history = h;<br /> for(let game of this.games) {<br /> let gh = this.tableService.getItemByField(this.history, 'game_id', game.id);<br /> game.pcount = gh.length;<br /> }<br /> });<br /> });<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> searchGames() {<br /> this.items = this.games.filter((item) => {<br /> return item.name.toLowerCase().indexOf(this.keywords.toLowerCase()) > -1;<br /> });<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> toggleSarchBar() {<br /> this.showSearchBar = !this.showSearchBar;<br /> }</span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> showGameHistory(game_id) {<br /> this.navCtrl.goForward(`/game-history/${game_id}`);<br /> }<br />}</span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Modify <b><i>src\app\history\history.page.html</i></b> as below:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-header><br /> <ion-toolbar><br /> <ion-buttons slot="start"><br /> <ion-menu-button></ion-menu-button><br /> </ion-buttons><br /> <ion-title>History</ion-title><br /> <ion-buttons slot="end"><br /> <div class="button"><br /> <ion-icon name="search" style="zoom:1.2;" (click)="toggleSarchBar()"></ion-icon><br /> </div><br /> </ion-buttons><br /> </ion-toolbar><br /></ion-header></span></span></div>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-content padding><br /> <div *ngIf="showSearchBar" [hidden]="!showSearchBar"><br /> <ion-searchbar [(ngModel)]="keywords" (ionChange)="searchGames()" placeholder="Filter games" debounce="1000"></ion-searchbar><br /> </div><br /> <ion-grid *ngFor="let game of items; let i = index;"><br /> <div [ngClass]="(i % 2 == 0) ? 'grid_odd' : 'grid_even'" *ngIf="!game.deleted" (click)="showGameHistory(game.id)"><br /> <b>{{game.name}}</b><br/><br /> <i>Created time: {{game.created_time}}</i><br/><br /> Played: {{game.pcount}} times<br /> </div><br /> </ion-grid><br /></ion-content></span></span></div>
</blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">There is a tricky that I used to make the icon search can be clicked on the tool bar, that is wrapping the icon with <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><div class="button"></span>. Without <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">class="button"</span>, we cannot click on the icon. I don't know if it is normal behavior of Ionic 4 or a bug.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">The search bar (<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">ion-searchbar</span>) also is set <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">debounce="1000"</span> to avoid filter immediately when keying. This <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">debounce="1000"</span> means if you stop keying in 1 second, the input value will be fired to <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">ionChange </span>event.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">The last page is GameHistory page to show all playing history of a game. Let generate it:</span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span><br />
<blockquote class="tr_bq">
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g page GameHistory</span></span></blockquote>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">This page will use the NumbersPanel component, so let import <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">ComponentsModule</span> to its module file <b><i>src\app\game-history\game-history.module.ts</i></b>.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Basically, coding of this page is nearly same with other pages we done, except that it has new component for rating playing results. But I want to keep this for next article.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">In next article, we may study how to make general CSS applied for all pages and code a rating component.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">I hope that through <a href="https://vivavivugeek.blogspot.com/2018/10/learning-ionic-4-part-1.html">Part 1</a> - <a href="https://vivavivugeek.blogspot.com/2019/03/learning-ionic-4-part-2.html">Part 2</a> - Part 3, you can start to code your real application with Ionic 4. In case you want grab the source code, let check <a href="https://github.com/vnheros/GameLot">https://github.com/vnheros/GameLot</a> on my GitHub.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "times new roman";">See you. Any comment is welcome!</span></span></div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
</span>
<div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-family: "times new roman";"></span><br /></span></div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike>Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-63887076866840295702019-03-09T18:00:00.000+07:002019-03-17T22:32:16.626+07:00Learning Ionic 4 - Part 2After long time I'm busy with the projects in my company, now I have a time to write this Part 2.<br />
In <a href="https://vivavivugeek.blogspot.com/2018/10/learning-ionic-4-part-1.html">Part 1</a>, we finished the login & sign-up page. In this part, we will focus on how to create pages with main menu (side menu), how to deal with local storage (use local storage as DB with tables).<br />
<br />
The main menu has 2 submenu Games menu & History menu. Because we will Home page for Games menu, so we jus generate new page called <b><i>History</i></b> for History menu:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g page History</span></blockquote>
Next, we add a side menu. Open file <b><i>src/app/app.component.ts</i></b> and add <b><i>menuPages</i></b>:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">export class AppComponent {<br /> public menuPages = [<br /> {<br /> title: 'Games',<br /> url: '/home',<br /> icon: 'logo-usd'<br /> },<br /> {<br /> title: 'History',<br /> url:'/history',<br /> icon: 'list'<br /> }<br /> ];<br /> constructor(<br />...</span></blockquote>
Then open file <b><i>src/app/app.component.html</i></b> and change as below:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-app><br /> <ion-split-pane><br /> <ion-menu><br /> <ion-header><br /> <ion-toolbar><br /> <ion-title>Menu</ion-title><br /> </ion-toolbar><br /> </ion-header><br /> <ion-content padding><br /> <ion-list><br /> <ion-menu-toggle *ngFor="let p of menuPages"><br /> <ion-item [routerLink]="p.url" [routerDirection]="'root'"><br /> <ion-icon slot="start" [name]="p.icon"></ion-icon><br /> <ion-label>{{p.title}}</ion-label><br /> </ion-item><br /> </ion-menu-toggle><br /> </ion-list><br /> </ion-content><br /> </ion-menu><br /> <ion-router-outlet main></ion-router-outlet><br /> </ion-split-pane><br /></ion-app></span></blockquote>
This change will add <b><i>ion-split-pane</i></b> into <b><i>ion-app</i></b>, and it will hold <b><i>ion-menu</i></b> (for menu content) and <b><i>ion-router-outlet</i></b> (for routing).<br />
To display menu button on any page, let add <b><i>ion-menu-button</i></b> into its html. We need to add it into Home page & History page, for example <b><i>src/app/home/home.page.html</i></b> of Home page:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-header><br /> <ion-toolbar><br /> <ion-buttons slot="start"><br /> <ion-menu-button></ion-menu-button><br /> </ion-buttons><br /> <ion-title>Games</ion-title><br /> </ion-toolbar><br /></ion-header><br />…</span></blockquote>
OK, now we had the menu.<br />
In Login page, we use a remote DB for authenticating, however we will use local storage to store the content of Games & History. In the real app, what is needed to store in centralized remote DB and what is needed to save on local storage depending on your strategy for your app. Here I want to show you a way to deal with the local storage like we work with tables. For beginning, let generate a MyTablesService service:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g service services/MyTables</span></blockquote>
Open <i><b>src/app/services/my-tables.service.ts</b></i> and add the codes like the following:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">import { Injectable } from '@angular/core';<br />import { Storage } from '@ionic/storage';</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">export class Game {<br /> public id: number;<br /> public name: string;<br /> public numbers: number;<br /> public min_number: number;<br /> public max_number: number;<br /> public created_time: Date;<br /> public deleted: boolean;<br /> public deleted_time: Date;<br />}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">export class History {<br /> public id: number;<br /> public game_id: number;<br /> public play_time: Date;<br /> public result: string;<br /> public rating: number;<br />}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Injectable({<br /> providedIn: 'root'<br />})<br />export class MyTablesService {<br /> table = 'table_';<br /> seedkey = 'seed_table';<br /> items: any = [];<br /> seed = 0;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constructor(private storage: Storage) { }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private getKeyFormat(id) {<br /> return this.table + id;<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private _addItem(item) {<br /> item.id = this.seed;<br /> this.storage.set(this.getKeyFormat(item.id), JSON.stringify(item));<br /> this.seed++;<br /> this.storage.set(this.seedkey, this.seed);<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private setTable(table_name: string) {<br /> this.table = table_name + '_';<br /> this.seedkey = 'seed_' + table_name;<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getItems(table_name: string) {<br /> this.setTable(table_name);<br /> this.items = [];<br /> var promise = new Promise((resolve, reject) => {<br /> this.storage.forEach((v, k, i) => {<br /> let a = this.table;<br /> if (k.indexOf(a) > -1) {<br /> this.items.push(JSON.parse(v));<br /> }<br /> }).then(() => {<br /> resolve(this.items);<br /> });<br /> });<br /> return promise;<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> addItem(table_name: string, item: any) {<br /> this.setTable(table_name);<br /> this.storage.get(this.seedkey).then((value) => {<br /> if (value) this.seed = value;<br /> else this.seed = 1;<br /> this._addItem(item);<br /> }, (error) => {<br /> this.seed = 1;<br /> this._addItem(item);<br /> });<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getItem(table_name: string, id: any) {<br /> this.setTable(table_name);<br /> var promise = new Promise((resolve, reject) => {<br /> this.storage.get(this.getKeyFormat(id)).then((value) => {<br /> resolve (JSON.parse(value));<br /> }, (error) => {<br /> reject (false);<br /> });<br /> });<br /> return promise;<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getItemByField(data: any, field: string, value: string) {<br /> return data.filter(i => i[field] == value);<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> sortAscByField(field: string) {<br /> return function(a,b){<br /> if( a[field] > b[field]){<br /> return 1;<br /> }else if( a[field] < b[field] ){<br /> return -1;<br /> }<br /> return 0;<br /> }<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> sortDescByField(field: string) {<br /> return function(a,b){<br /> if( a[field] > b[field]){<br /> return -1;<br /> }else if( a[field] < b[field] ){<br /> return 1;<br /> }<br /> return 0;<br /> }<br /> }<br />}</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"></span></span></blockquote>
Basically the local storage will store data in form of key & value, the <span style="font-family: "times new roman";"><i>MyTable</i><span style="background-color: transparent; color: black; display: inline; float: none; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>sService</i> service </span></span>above will help to work with local storage as tables. In which, Game class and History class present for the structure of <b><i>games</i></b> table & <b><i>history</i></b> tables. We will see on later code.<br />
<br />
Next, we will generate "<i>New Game</i>" page for adding new game:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g page "New Game"</span></blockquote>
Here are codes for <b><i>src/app/new-game/new-game.page.ts</i></b>:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">import { Component, OnInit } from '@angular/core';<br />import { Game, MyTablesService } from '../services/my-tables.service';<br />import { NavController } from '@ionic/angular';</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Component({<br /> selector: 'app-new-game',<br /> templateUrl: './new-game.page.html',<br /> styleUrls: ['./new-game.page.scss'],<br />})<br />export class NewGamePage implements OnInit {<br /> game: Game;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constructor(private gameService: GamesService, private navCtrl: NavController) {<br /> this.game = new Game();<br /> this.game.numbers = 5; //default value<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ngOnInit() {<br /> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> save() {<br /> this.game.created_time = new Date();<br /> this.gameService.addItem('games', this.game);<br /> this.navCtrl.goRoot('/home');<br /> }<br />}</span></blockquote>
And codes for <b><i>src/app/new-game/new-game.page.html</i></b>:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-header><br /> <ion-toolbar><br /> <ion-buttons slot="start"><br /> <ion-menu-button></ion-menu-button><br /> </ion-buttons><br /> <ion-title>New Game</ion-title><br /> </ion-toolbar><br /></ion-header></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><ion-content padding><br /> <ion-list><br /> <ion-item><br /> <ion-label>Name:</ion-label><br /> <ion-input [(ngModel)]="game.name" type="text"></ion-input><br /> </ion-item><br /> <ion-item><br /> <ion-label>Quantity of numbers (1-10):</ion-label><br /> <ion-select [(ngModel)]="game.numbers" value="5" okText="Ok" cancelText="Cancel"><br /> <ion-select-option value="1">1</ion-select-option><br /> <ion-select-option value="2">2</ion-select-option><br /> <ion-select-option value="3">3</ion-select-option><br /> <ion-select-option value="4">4</ion-select-option><br /> <ion-select-option value="5">5</ion-select-option><br /> <ion-select-option value="6">6</ion-select-option><br /> <ion-select-option value="7">7</ion-select-option><br /> <ion-select-option value="8">8</ion-select-option><br /> <ion-select-option value="9">9</ion-select-option><br /> <ion-select-option value="10">10</ion-select-option><br /> </ion-select><br /> </ion-item><br /> <ion-item><br /> <ion-label>Random # between:</ion-label><br /> <ion-input [(ngModel)]="game.min_number" type="number"></ion-input><br /> <ion-label>and</ion-label><br /> <ion-input [(ngModel)]="game.max_number" type="number"></ion-input><br /> </ion-item><br /> </ion-list><br /> <ion-button expand="full" shape="round" color="secondary" (click)="save()">Save</ion-button><br /></ion-content></span></blockquote>
To invoke this New Game page, let add a FAB (floating action button) into the html of Home page:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">...<br /><ion-fab vertical="bottom" horizontal="end" slot="fixed"><br /> <ion-fab-button color="danger" (click)="newGame()"><br /> <ion-icon name="add"></ion-icon><br /> </ion-fab-button><br /></ion-fab><br />...</span></blockquote>
<span style="font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace;"></span>Add function <b><i>newGame()</i></b> into <b><i>src/app/home/home.page.ts</i></b>:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">newGame() {<br /> this.navCtrl.goForward('/new-game');<br />}</span></blockquote>
<span style="font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace;"></span>Below are new screenshots of our app until now after login:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3VHLVWkX65c-2hm7FzrfzqCOUJuq-GfRlHHCqulN7aV4ZH8YFo-p3yYM1zIaTAexlv7Chs_zB7qC42PJ7n0xi5ALIfm8zmD3BGoT5gqZrNNj1McIqIemHzbx10kGSMUrcwIZ8kRYQHsMN/s1600/app_game_lot_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="577" data-original-width="328" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3VHLVWkX65c-2hm7FzrfzqCOUJuq-GfRlHHCqulN7aV4ZH8YFo-p3yYM1zIaTAexlv7Chs_zB7qC42PJ7n0xi5ALIfm8zmD3BGoT5gqZrNNj1McIqIemHzbx10kGSMUrcwIZ8kRYQHsMN/s400/app_game_lot_1.png" width="226" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG2LZZEWjZIeeg6KvvpqYwlV8boW_Y4EAEiMtqOZOpkVodOyvGOijxaZ6g0zKczAxpgHqajItcglV7BQMhP_BlpMDGJv7uy8N87MZ0vJcIV3PzUv7zE3HPK9F2uQjI2xmbo_jrGAYMc5Mp/s1600/app_game_lot_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="576" data-original-width="330" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG2LZZEWjZIeeg6KvvpqYwlV8boW_Y4EAEiMtqOZOpkVodOyvGOijxaZ6g0zKczAxpgHqajItcglV7BQMhP_BlpMDGJv7uy8N87MZ0vJcIV3PzUv7zE3HPK9F2uQjI2xmbo_jrGAYMc5Mp/s400/app_game_lot_2.png" width="228" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhibx2BFRwPcgkEbLIDaF_Kme4O7XPuMhwZYpu2GoiNE5GLy-AqzOCi8Nfo4QSHt6Z7pnPgdoC71B3yGNUMLhBwK3Q8QeGPuisQZqqaXk3q8_sToycfVjnNw2did4ADVXEucSDbrDPzSrmp/s1600/app_game_lot_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="260" data-original-width="348" height="149" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhibx2BFRwPcgkEbLIDaF_Kme4O7XPuMhwZYpu2GoiNE5GLy-AqzOCi8Nfo4QSHt6Z7pnPgdoC71B3yGNUMLhBwK3Q8QeGPuisQZqqaXk3q8_sToycfVjnNw2did4ADVXEucSDbrDPzSrmp/s200/app_game_lot_3.png" width="200" /></a></div>
<br />
Through this part, we have known how to add a menu, work with local storage and create a new game. In next <a href="https://vivavivugeek.blogspot.com/2019/03/learning-ionic-4-part-3.html">Part 3</a>, we will code remain things & finish the app. See you!<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-45989567137708273002018-10-11T17:44:00.000+07:002018-10-11T17:45:39.905+07:00CentOS + MS Bot Framework: Solving error "ChatConnector: receive - invalid token"When I deploy my chat bot written with MS Bot Framework on CentOS, I got the error "<i>ERROR: ChatConnector: receive - invalid token. Check bot's app ID & Password</i>", although I provide exactly my bot's app ID & Password.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGM8UYfZajKZwcU-Vmwc7vVlTQYKkHg-HCwLVu45D3T_X1Wz4L76bO3IptLWiYFwNRDRLyu8197ldceR6w6tBXqA3nFUgMxlEVE66oZ2sUo2wbMKVAOUXayQBDl8__i0SMYjkPG33WEUA/s1600/MS_BotFrameWork_Connection_Error.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="418" data-original-width="661" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGM8UYfZajKZwcU-Vmwc7vVlTQYKkHg-HCwLVu45D3T_X1Wz4L76bO3IptLWiYFwNRDRLyu8197ldceR6w6tBXqA3nFUgMxlEVE66oZ2sUo2wbMKVAOUXayQBDl8__i0SMYjkPG33WEUA/s400/MS_BotFrameWork_Connection_Error.png" width="400" /></a></div>
<br />
After googling, I know the problem is server time not corrected (in my case, it is late ~ 20 minutes), so the security token is invalid.<br />
<br />
You can solve this easily by syncing your server time with a standard NTP (Network Time Protocol) server. Below are steps.<br />
<br />
<b>1. Install ntp and ntpdate</b><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># yum install ntp ntpdate</span></blockquote>
<b>2. Enable ntpd service</b><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># systemctl start ntpd<br /># systemctl enable ntpd</span></blockquote>
Check its status:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># systemctl status ntpd</span></blockquote>
<div>
<b>3. Add some CentOS NTP servers</b></div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># ntpdate -u -s 0.centos.pool.ntp.org 1.centos.pool.ntp.org 2.centos.pool.ntp.org</span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span><b>4. Restart ntpd service</b></div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># systemctl restart ntpd</span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span><b>5. Check again</b></div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># timedatectl</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># date</span></blockquote>
</div>
<br />
Addition, let set hardware clock to the current server time:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># hwclock -w</span></blockquote>
Now you can start your bot without this error. Cheers!<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-88491540671562486052018-10-02T01:00:00.000+07:002019-03-09T18:05:15.769+07:00Learning Ionic 4 - Part 1At the point I'm writing this article, Ionic 4 is going to official release, it is an innovation of Ionic Framework. Ionic 4 is the beginning version of the Framework to completely support modern Web APIs such as <a href="https://developers.google.com/web/fundamentals/web-components/customelements">Custom Elements</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables">CSS Variables</a> and <a href="https://developers.google.com/web/fundamentals/web-components/shadowdom">Shadow DOM</a>.<br />
<br />
Different with past versions, Ionic 4 can work as a standalone <a href="https://www.webcomponents.org/introduction">Web Component</a> library. Although it still supports Angular as its root part, now it can be used with other JavaScript frameworks like React or Vue. The core components can work standalone with just a script tag in a web page. It means you can use Ionic as a standalone library in a single page even in a context like WordPress.<br />
<br />
With many changes in the core, however the migration from Ionic 3 to Ionic 4 is very easy (almost change nothing in your code except the structure of source code) than from Ionic 1 to Ionic 2. You can read here for <a href="https://beta.ionicframework.com/docs/building/migration/">migrating from Ionic 3 to Ionic 4</a>.<br />
<br />
In this article, I will play with Ionic 4 by coding a game (lottery program) that you can use for mini games in marketing campaigns (e.g. on Facebook fan page). I call it as "<b>GameLot</b>". Through coding this game, I hope you can learn how to create a real application with Ionic 4.<br />
<br />
<b><u>Design the game</u></b><br />
<b></b><u></u><br />
Before developing any app, we should have a clear idea what we want and design it at least in wireframes. Below are my ideas about the game and its wireframes.<br />
<div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
Basically my GameLot will have:</div>
<ul>
<li><div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
A login page</div>
</li>
<li><div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
A signup page</div>
</li>
<li><div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
A side menu navigate to pages:</div>
</li>
<ul>
<li><div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Games page: it is default page, it lists games created and have functions to new game, play game, delete game (and its history?).</span></div>
</li>
<li><div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
History page: it list games and their history (results of every time playing games), and may have a function for rating a result.</div>
</li>
</ul>
</ul>
And here are wireframes which I painted by MS Visio 💪.<br />
Login page:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbSfArzXtJMLewGQqPPxegneCArmh7Gx6bAEOxrxoLfRSeElmwNPS5cFUl28Sg_AQwqI6Bqt-cJan5-cfHHbtR8dl8zJd-EKtsdgPlpUS9fa-nYF1j7tnMwflea1b33YxMmukBeGpCV01f/s1600/GameLot_Login.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="323" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbSfArzXtJMLewGQqPPxegneCArmh7Gx6bAEOxrxoLfRSeElmwNPS5cFUl28Sg_AQwqI6Bqt-cJan5-cfHHbtR8dl8zJd-EKtsdgPlpUS9fa-nYF1j7tnMwflea1b33YxMmukBeGpCV01f/s320/GameLot_Login.png" width="195" /></a></div>
Signup page:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihapABL8yTxm1C0Hk7GqXBie92zFpgszIzAsaCeYhlFHlz2EzhyvJxwCNSfscDBf8i4lBuBSa3R5x2RUS2z-3JnWzEjxM5z_JYFrB0LF38rL1dRF6yUoDLu-IQqDQkffsazJ7JdPfwzvah/s1600/GameLot_Signup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="323" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihapABL8yTxm1C0Hk7GqXBie92zFpgszIzAsaCeYhlFHlz2EzhyvJxwCNSfscDBf8i4lBuBSa3R5x2RUS2z-3JnWzEjxM5z_JYFrB0LF38rL1dRF6yUoDLu-IQqDQkffsazJ7JdPfwzvah/s320/GameLot_Signup.png" width="195" /></a></div>
<div>
Side menu:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6D2kkb-5XdVzxa6eTUvMrVw4ms7XL1nbcddhLnGErF5In6BxGS9LWytO2EmMQwVWUW5YfGX0mUbIZTm6JNKbVTok7yjhV3FnpVfmMAPiULKlH4t8xuzin8C6CnTmVs9unfb-vTJvwRGuL/s1600/GameLot_SideMenu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="323" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6D2kkb-5XdVzxa6eTUvMrVw4ms7XL1nbcddhLnGErF5In6BxGS9LWytO2EmMQwVWUW5YfGX0mUbIZTm6JNKbVTok7yjhV3FnpVfmMAPiULKlH4t8xuzin8C6CnTmVs9unfb-vTJvwRGuL/s320/GameLot_SideMenu.png" width="195" /></a></div>
<div>
Games page:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirKdAkKRf8mKoDyBLyWk0Q5cuzvyt4FWj_0ebFqWDsQevLhA3uFpYJuDFs0IibKSLfOrPsKyZHwzF8sXwVXhKsj80lTq_ggplkxBllfoZXn_V-O4z0BTyl26oS4QP6UxOs4NdYLcQiO30D/s1600/GameLot_Games.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="323" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirKdAkKRf8mKoDyBLyWk0Q5cuzvyt4FWj_0ebFqWDsQevLhA3uFpYJuDFs0IibKSLfOrPsKyZHwzF8sXwVXhKsj80lTq_ggplkxBllfoZXn_V-O4z0BTyl26oS4QP6UxOs4NdYLcQiO30D/s320/GameLot_Games.png" width="195" /></a></div>
<div>
New game page:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYPOHggJkhobOvWnnI7wpbWnlBhUb365YQuaEjWzm59aUoKSlzqqhHE669Z9zQ6aJMR1IIbrdwkQxPVUbo_rLij9tc4wJQALphr_iKsaM6mrvk7wuyA_AdOS19Fw7VKCxLZ0namWqHNkNG/s1600/GameLot_NewGame.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="323" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYPOHggJkhobOvWnnI7wpbWnlBhUb365YQuaEjWzm59aUoKSlzqqhHE669Z9zQ6aJMR1IIbrdwkQxPVUbo_rLij9tc4wJQALphr_iKsaM6mrvk7wuyA_AdOS19Fw7VKCxLZ0namWqHNkNG/s320/GameLot_NewGame.png" width="195" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
Play game page:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwY944grfqegzYj6DI-DdIXGEu3v14hMcsyFR_SR7ycyC-k28NTrVgTKs0w9ykJ2X-fcjpYDA3t08j-JOzkTPyiXV1aKO2hhh0cUY5B4GjDucZZuHfaROp9wWTc933hkTprjuPtVi6AvAr/s1600/GameLot_PlayGame.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="323" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwY944grfqegzYj6DI-DdIXGEu3v14hMcsyFR_SR7ycyC-k28NTrVgTKs0w9ykJ2X-fcjpYDA3t08j-JOzkTPyiXV1aKO2hhh0cUY5B4GjDucZZuHfaROp9wWTc933hkTprjuPtVi6AvAr/s320/GameLot_PlayGame.png" width="195" /></a></div>
<div>
History page:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5A-uNgN4QxauDQ-tnUmpRjoJ7m0llupP85Ro2tFgB_jmCxL_OQg28cY2GWfihI27WiloaN41Z9ITL33ZcnzHucTvT8N4ODKUtiDhKN-S8ehAB9VJECgV-QbSg3cYg_G__wr8PlNWcjTdb/s1600/GameLot_History.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="363" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5A-uNgN4QxauDQ-tnUmpRjoJ7m0llupP85Ro2tFgB_jmCxL_OQg28cY2GWfihI27WiloaN41Z9ITL33ZcnzHucTvT8N4ODKUtiDhKN-S8ehAB9VJECgV-QbSg3cYg_G__wr8PlNWcjTdb/s320/GameLot_History.png" width="219" /></a></div>
<div>
History of a game:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDdE4ZPoEHwDiyOt15AXWeS1P7v0sui_USd2g7G3Xr4s_6lDF1dzhbkjOyhdL3X9eR6Zz2Yjz8oatmCM2wO-hvx3fF6zlM1ULJJhlLNNPcAsTjgoFcQeQyZxoDoH0fK-cH2kaOhB74XX8_/s1600/GameLot_History_of_a_game.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="323" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDdE4ZPoEHwDiyOt15AXWeS1P7v0sui_USd2g7G3Xr4s_6lDF1dzhbkjOyhdL3X9eR6Zz2Yjz8oatmCM2wO-hvx3fF6zlM1ULJJhlLNNPcAsTjgoFcQeQyZxoDoH0fK-cH2kaOhB74XX8_/s320/GameLot_History_of_a_game.png" width="195" /></a></div>
<div>
<br /></div>
<div>
We have total 8 pages for this game. Next steps we will go to details how to code it.</div>
<br />
<b><u>Code it</u></b><br />
<b></b><u></u><b></b><u></u><br />
For the login of this game, I <a href="https://vivavivugeek.blogspot.com/2016/09/build-jwt-authentication-server-with.html">build a JWT authentication server with Node.js, Express and MySQL</a> (click on the link to see how to build it).<br />
<br />
Now in this article, I will focus on building the game on Ionic 4.<br />
<br />
If you don't have Ionic 4, let install it:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">npm install -g ionic</span></blockquote>
Start new blank app:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic start GameLot blank --type=angular</span></blockquote>
You can jump to the folder GameLot generated to see what inside. Almost of the code will be in the <b><i>src/app</i></b> folder. You can <a href="https://beta.ionicframework.com/docs/building/scaffolding/">read here for more details</a>.<br />
<br />
From Ionic 2, you can generate new app features by using the command <b><i>ionic generate</i></b>, see my example in the article "<i><a href="https://vivavivugeek.blogspot.com/2016/10/simple-starter-kit-for-building.html">Simple starter kit for building realistic app with Ionic 2</a></i>". In Ionic 4, it has a little change, you can use the command <b><i>ionic g --help</i></b> for more details.<br />
<br />
OK, let generate a service to work with authentication server for login:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g service services/Auth</span></blockquote>
It will generate 2 files <b><i>auth.service.spec.ts</i></b> and <i><b>auth.service.ts</b></i> in the foder <b><i>src/app/services</i></b>. Next, let generate a page for login:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g page Login</span></blockquote>
It will generate the following files:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">src/app/login/login.module.ts<br />src/app/login/login.page.html<br />src/app/login/login.page.spec.ts<br />src/app/login/login.page.ts<br />src/app/login/login.page.scss<br />src/app/app-routing.module.ts</span></blockquote>
Now we have <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">files</span> <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">generated </span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"></span>for coding a login page. We need change the default route to login page. When you generate any new page, it will add a new route to this file <b><i>src/app/app-routing.module.ts,</i></b> for example after above command, this file will have a content like the following:<br />
<br />
<span style="font-size: xx-small;"><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">NgModule</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@angular/core'</span><span style="color: #d4d4d4;">;</span></span><br />
<span style="font-size: xx-small;"><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">Routes</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">RouterModule</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@angular/router'</span><span style="color: #d4d4d4;">;</span></span><br />
<span style="font-size: xx-small;"><span style="color: #569cd6;">const</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">routes</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Routes</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> [</span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">path:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">''</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">redirectTo:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'home'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">pathMatch:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'full'</span><span style="color: #d4d4d4;"> },</span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">path:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'home'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">loadChildren:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'./home/home.module#HomePageModule'</span><span style="color: #d4d4d4;"> },</span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">path:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'Login'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">loadChildren:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'./login/login.module#LoginPageModule'</span><span style="color: #d4d4d4;"> },</span></span><br />
<span style="color: #d4d4d4; font-size: xx-small;">];</span><br />
<br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;">@</span><span style="color: #dcdcaa;">NgModule</span><span style="color: #d4d4d4;">({</span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">imports:</span><span style="color: #d4d4d4;"> [</span><span style="color: #9cdcfe;">RouterModule</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">forRoot</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">routes</span><span style="color: #d4d4d4;">)],</span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">exports:</span><span style="color: #d4d4d4;"> [</span><span style="color: #9cdcfe;">RouterModule</span><span style="color: #d4d4d4;">]</span></span><br />
<span style="color: #d4d4d4; font-size: xx-small;">})</span><br />
<span style="font-size: xx-small;"><span style="color: #c586c0;">export</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">class</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">AppRoutingModule</span><span style="color: #d4d4d4;"> { }</span></span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><span style="font-size: x-small;"></span><span style="font-size: xx-small;"></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Here, Ionic 4 use Angular 6 Router and lazy loading for page and each page has its own routing module. </span>Let change const routes to:<br />
<br />
<span style="font-size: xx-small;"><span style="color: #569cd6;">const</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">routes</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Routes</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> [</span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">path:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">''</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">redirectTo:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'login'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">pathMatch:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'full'</span><span style="color: #d4d4d4;"> }, </span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> { <span style="background-color: transparent; color: #9cdcfe; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;">path:</span><span style="background-color: transparent; color: #d4d4d4; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;"> </span><span style="background-color: transparent; color: #ce9178; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;">'home'</span><span style="background-color: transparent; color: #d4d4d4; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;">, </span><span style="background-color: transparent; color: #9cdcfe; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;">loadChildren:</span><span style="background-color: transparent; color: #d4d4d4; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;"> </span><span style="background-color: transparent; color: #ce9178; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;">'./home/home.module#HomePageModule'</span><span style="background-color: transparent; color: #d4d4d4; font-family: "quot"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;"> },</span><b><i></i><u></u><sub></sub><sup></sup><strike></strike> </b></span></span><br />
<span style="font-size: xx-small;"><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">path:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'login'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">loadChildren:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'./login/login.module#LoginPageModule'</span><span style="color: #d4d4d4;"> },</span></span><br />
<span style="color: #d4d4d4; font-size: xx-small;">];</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><span style="font-size: xx-small;"></span><br />
Before coding the login page, we need to code the authentication service first. Create a folder named helpers (<i><b>src/app/helpers</b></i>) and copy <a href="https://github.com/vnheros/ionic2-todos-example/blob/master/src/helpers/jwt-helper.ts">this file from my old article</a> (<a href="https://vivavivugeek.blogspot.com/2016/10/simple-starter-kit-for-building.html">Simple starter kit for building realistic app with Ionic 2</a>) into.<br />
Because we will use Ionic storage to store authentication token, so we need to install ionic storage (<a href="https://beta.ionicframework.com/docs/building/storage">read here for more info on Ionic storage</a>):<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">npm install --save @ionic/storage</span></blockquote>
The authentication service will use HTTP to get/post, so we need to add HttpModule into the file <b><i>src/app/app.module.ts</i></b>, below is the code of this file after adding <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">HttpModule:</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">HttpModule</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@angular/http'</span><span style="color: #d4d4d4;">;</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">IonicStorageModule</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@ionic/storage'</span><span style="color: #d4d4d4;">;</span></span></span> <br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"><br /></span></span></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;">@</span><span style="color: #dcdcaa;">NgModule</span><span style="color: #d4d4d4;">({</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">declarations:</span><span style="color: #d4d4d4;"> [</span><span style="color: #9cdcfe;">AppComponent</span><span style="color: #d4d4d4;">],</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">entryComponents:</span><span style="color: #d4d4d4;"> [],</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">imports:</span><span style="color: #d4d4d4;"> [</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">BrowserModule</span><span style="color: #d4d4d4;">, </span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">IonicModule</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">forRoot</span><span style="color: #d4d4d4;">(), </span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">HttpModule</span><span style="color: #d4d4d4;">,</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">IonicStorageModule</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">forRoot</span><span style="color: #d4d4d4;">(),</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">AppRoutingModule</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="color: #d4d4d4; font-size: xx-small;"> ],</span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">…</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="color: #d4d4d4; font-size: xx-small;"><br /></span></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="color: #d4d4d4; font-size: xx-small;">})</span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="font-size: xx-small;"><span style="color: #c586c0;">export</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">class</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">AppModule</span><span style="color: #d4d4d4;"> {}</span></span></span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></span><br />
Then modify the file <b><i>src/app/services/auth.service.ts </i></b>generated above as the following:<br />
<br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> {</span><span style="color: #9cdcfe;">JwtHelper</span><span style="color: #d4d4d4;">} </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'../helpers/jwt-helper'</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">Injectable</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@angular/core'</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">Http</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">Headers</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@angular/http'</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">Storage</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@ionic/storage'</span><span style="color: #d4d4d4;">;</span><br />
<br />
<span style="color: #d4d4d4;">@</span><span style="color: #dcdcaa;">Injectable</span><span style="color: #d4d4d4;">({</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">providedIn:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'root'</span><br />
<span style="color: #d4d4d4;">})</span><br />
<span style="color: #c586c0;">export</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">class</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">AuthService</span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">jwtHelper</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">JwtHelper</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">new</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">JwtHelper</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">LOGIN_URL</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">string</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">"http://<SERVER_AUTH:PORT>/user/login"</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">SIGNUP_URL</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">string</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">"http://<span style="background-color: transparent; color: #ce9178; display: inline; float: none; font-family: "consolas" , "courier new" , monospace; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;"><SERVER_AUTH:PORT></span>/user/create"</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">CHECK_URL</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">"http://<span style="background-color: transparent; color: #ce9178; display: inline; float: none; font-family: "consolas" , "courier new" , monospace; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px;"><SERVER_AUTH:PORT></span>/user/check/"</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">headers</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Headers</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">new</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Headers</span><span style="color: #d4d4d4;">({ </span><span style="color: #ce9178;">"Content-Type"</span><span style="color: #9cdcfe;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">"application/json"</span><span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">any</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">user</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">string</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">constructor</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">private</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">http</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Http</span><span style="color: #d4d4d4;">, </span><span style="color: #569cd6;">private</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">storage</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Storage</span><span style="color: #d4d4d4;">) {</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">loggedin</span><span style="color: #d4d4d4;">() {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">return</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">storage</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">get</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">'id_token'</span><span style="color: #d4d4d4;">).</span><span style="color: #dcdcaa;">then</span><span style="color: #d4d4d4;">((</span><span style="color: #9cdcfe;">value</span><span style="color: #d4d4d4;">) </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">value</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">return</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">&&</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">!</span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">jwtHelper</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">isTokenExpired</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;">, </span><span style="color: #569cd6;">null</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }, (</span><span style="color: #9cdcfe;">error</span><span style="color: #d4d4d4;">) </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">return</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">false</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">check</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">user</span><span style="color: #d4d4d4;">) {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">return</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">new</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Promise</span><span style="color: #d4d4d4;">((</span><span style="color: #9cdcfe;">resolve</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">reject</span><span style="color: #d4d4d4;">) </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">http</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">get</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">CHECK_URL</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">+</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">user</span><span style="color: #d4d4d4;">, { </span><span style="color: #9cdcfe;">headers:</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">headers</span><span style="color: #d4d4d4;"> })</span><br />
<span style="color: #d4d4d4;"> .</span><span style="color: #dcdcaa;">subscribe</span><span style="color: #d4d4d4;">(</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">resolve</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> },</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">reject</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<span style="color: #d4d4d4;"> );</span><br />
<span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">login</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">credentials</span><span style="color: #d4d4d4;">) {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">return</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">new</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Promise</span><span style="color: #d4d4d4;">((</span><span style="color: #9cdcfe;">resolve</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">reject</span><span style="color: #d4d4d4;">) </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">http</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">post</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">LOGIN_URL</span><span style="color: #d4d4d4;">, </span><span style="color: #4ec9b0;">JSON</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">stringify</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">credentials</span><span style="color: #d4d4d4;">), { </span><span style="color: #9cdcfe;">headers:</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">headers</span><span style="color: #d4d4d4;"> })</span><br />
<span style="color: #d4d4d4;"> .</span><span style="color: #dcdcaa;">subscribe</span><span style="color: #d4d4d4;">(</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">res</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">const</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">res</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">json</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">authSuccess</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">id_token</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">resolve</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> },</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">reject</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<span style="color: #d4d4d4;"> ); </span><br />
<span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">signup</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">credentials</span><span style="color: #d4d4d4;">) {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">return</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">new</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Promise</span><span style="color: #d4d4d4;">((</span><span style="color: #9cdcfe;">resolve</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">reject</span><span style="color: #d4d4d4;">) </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">http</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">post</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">SIGNUP_URL</span><span style="color: #d4d4d4;">, </span><span style="color: #4ec9b0;">JSON</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">stringify</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">credentials</span><span style="color: #d4d4d4;">), { </span><span style="color: #9cdcfe;">headers:</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">headers</span><span style="color: #d4d4d4;"> })</span><br />
<span style="color: #d4d4d4;"> .</span><span style="color: #dcdcaa;">subscribe</span><span style="color: #d4d4d4;">(</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">res</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">const</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">res</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">json</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">authSuccess</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">id_token</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">resolve</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">data</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> },</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">reject</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<span style="color: #d4d4d4;"> );</span><br />
<span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">authSuccess</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;">) {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">setAuth</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">storage</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">set</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">'id_token'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">setAuth</span><span style="color: #d4d4d4;">() {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">user</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">jwtHelper</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">decodeToken</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;">).</span><span style="color: #9cdcfe;">username</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">headers</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">append</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">'Authorization'</span><span style="color: #d4d4d4;">, </span><span style="color: #ce9178;">'Bearer '</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">+</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">token</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">logout</span><span style="color: #d4d4d4;">() {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">storage</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">set</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">'id_token'</span><span style="color: #d4d4d4;">, </span><span style="color: #ce9178;">''</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">user</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">null</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<span style="color: #d4d4d4;">}</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
The first version of login page has 2 files as below.<br />
<b><i>src/app/login/login.page.ts</i></b>:<br />
<br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">Component</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">OnInit</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@angular/core'</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">AuthService</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'../services/auth.service'</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">LoadingController</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">NavController</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@ionic/angular'</span><span style="color: #d4d4d4;">;</span><br />
<br />
<span style="color: #d4d4d4;">@</span><span style="color: #dcdcaa;">Component</span><span style="color: #d4d4d4;">({</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">selector:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'app-login'</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">templateUrl:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'./login.page.html'</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">styleUrls:</span><span style="color: #d4d4d4;"> [</span><span style="color: #ce9178;">'./login.page.scss'</span><span style="color: #d4d4d4;">],</span><br />
<span style="color: #d4d4d4;">})</span><br />
<span style="color: #c586c0;">export</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">class</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">LoginPage</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">implements</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">OnInit</span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">username</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">string</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">password</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">string</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">loading</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">any</span><span style="color: #d4d4d4;">;</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">constructor</span><span style="color: #d4d4d4;">(</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">private</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">auth</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">AuthService</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">private</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">navCtrl</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">NavController</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">private</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">loadingCtrl</span><span style="color: #d4d4d4;">:</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">LoadingController</span><span style="color: #d4d4d4;">) { }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">ngOnInit</span><span style="color: #d4d4d4;">() {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">auth</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">loggedin</span><span style="color: #d4d4d4;">().</span><span style="color: #dcdcaa;">then</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">isLoggedin</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> (</span><span style="color: #9cdcfe;">isLoggedin</span><span style="color: #d4d4d4;">) {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">auth</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">setAuth</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">navCtrl</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">goRoot</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">'/home'</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">async</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">login</span><span style="color: #d4d4d4;">() {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">showLoader</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">let</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">credentials</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">username:</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">username</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">password:</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">password</span><br />
<span style="color: #d4d4d4;"> };</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">auth</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">login</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">credentials</span><span style="color: #d4d4d4;">).</span><span style="color: #dcdcaa;">then</span><span style="color: #d4d4d4;">((</span><span style="color: #9cdcfe;">result</span><span style="color: #d4d4d4;">) </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">loading</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">dismiss</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">console</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">log</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">"OK: "</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">+</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">result</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">navCtrl</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">goRoot</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">'/home'</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> }, (</span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;">) </span><span style="color: #569cd6;">=></span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">loading</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">dismiss</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">console</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">log</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">"ERROR: "</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">+</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">err</span><span style="color: #d4d4d4;">);</span><br />
<span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">launchSignup</span><span style="color: #d4d4d4;">() {</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">async</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">showLoader</span><span style="color: #d4d4d4;">() {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">loading</span><span style="color: #d4d4d4;"> </span><span style="color: #d4d4d4;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">loadingCtrl</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">create</span><span style="color: #d4d4d4;">({</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">content:</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'Authenticating...'</span><br />
<span style="color: #d4d4d4;"> });</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">return</span><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">this</span><span style="color: #d4d4d4;">.</span><span style="color: #9cdcfe;">loading</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">present</span><span style="color: #d4d4d4;">();</span><br />
<span style="color: #d4d4d4;"> }</span><br />
<br />
<span style="color: #d4d4d4;">}</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<b><i>src/app/login/login.page.html</i></b>:<br />
<br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-header</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-toolbar</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-title</span><span style="color: grey;">></span><span style="color: #d4d4d4;">GameLot Login</span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-title</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-toolbar</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-header</span><span style="color: grey;">></span><br />
<br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-content</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">padding</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-row</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">class</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"login-form"</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-col</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-list</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">inset</span><span style="color: grey;">></span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">><</span><span style="color: #569cd6;">ion-icon</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">name</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"person"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-icon</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-input</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">[(ngModel)]</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"username"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">placeholder</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"username"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">type</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"text"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-input</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"> <</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">><</span><span style="color: #569cd6;">ion-icon</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">name</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"lock"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-icon</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">></span><br />
<span style="color: grey;"> <</span><span style="color: #569cd6;">ion-input</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">[(ngModel)]</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"password"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">placeholder</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"password"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">type</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"password"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-input</span><span style="color: grey;">></span><br />
<span style="color: grey;"> </</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"> </</span><span style="color: #569cd6;">ion-list</span><span style="color: grey;">></span><br />
<span style="color: grey;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-button</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">expand</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"full"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">shape</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"round"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">color</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"secondary"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">class</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"login-button"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">(click)</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"login()"</span><span style="color: grey;">></span><span style="color: #d4d4d4;">Login</span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-button</span><span style="color: grey;">></span><br />
<span style="color: grey;"> </span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-col</span><span style="color: grey;">></span><br />
<span style="color: grey;"> </span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-row</span><span style="color: grey;">></span><br />
<br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-row</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-col</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"><</span><span style="color: #569cd6;">ion-button</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">expand</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"clear"</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">(click)</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">"launchSignup()"</span><span style="color: grey;">></span><span style="color: #d4d4d4;">Sign up</span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-button</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-col</span><span style="color: grey;">></span><br />
<span style="color: #d4d4d4;"> </span><span style="color: grey;"></</span><span style="color: #569cd6;">ion-row</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-content</span><span style="color: grey;">></span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<b><i>src/app/login/login.page.scss</i></b>:<br />
<br />
<span style="color: #569cd6;">ion-scroll</span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">display</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">none</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;">}</span><br />
<span style="color: #569cd6;">ion-col</span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">text-align</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">center</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">align-items</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">center</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;">}</span><br />
<span style="color: #d7ba7d;">.login-button</span><span style="color: #d4d4d4;"> {</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">width</span><span style="color: #d4d4d4;">: </span><span style="color: #b5cea8;">50%</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">margin-left</span><span style="color: #d4d4d4;">: </span><span style="color: #b5cea8;">25%</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #d4d4d4;">}</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
Run the command <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic serve</span>, you will have the following login page:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvmY-cSqI70UClDCBi1j7mddJ6vYLOs7AoZrg0sR9ppmtyxcOS5fjHr-eu9HCRVw6axeeoTEdXjmAyV_z4jWKSfCWbnv8-mtCj5YZqtDsMhltQ6mO5gDG3CI4yXoE30kb-IeHK02Bhwhjl/s1600/gamelot_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="470" data-original-width="423" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvmY-cSqI70UClDCBi1j7mddJ6vYLOs7AoZrg0sR9ppmtyxcOS5fjHr-eu9HCRVw6axeeoTEdXjmAyV_z4jWKSfCWbnv8-mtCj5YZqtDsMhltQ6mO5gDG3CI4yXoE30kb-IeHK02Bhwhjl/s320/gamelot_1.PNG" width="288" /></a></div>
<br />
You can test login page and see log info in console. Run below command to create Signup page:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic g page Signup</span></blockquote>
We will create a simple signup form with validations (it is nearly similar with old Ionic version, you can read here for <a href="https://vivavivugeek.blogspot.com/2016/07/ionic-2-formbuider-and-validator.html">form validation on Ionic 2</a>). For using <b><i>FormGroup</i></b>, we must add <b><i>ReactiveFormsModule</i></b> into NgModule of sign up page. Open file <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 700; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">src/app/signup/signup.module.ts</span>, add <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b><i>ReactiveFormsModule</i></b> </span>as below:<br />
<br />
<span style="color: #c586c0;">…</span><br />
<span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> { </span><span style="color: #9cdcfe;">FormsModule</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">ReactiveFormsModule</span><span style="color: #d4d4d4;"> } </span><span style="color: #c586c0;">from</span><span style="color: #d4d4d4;"> </span><span style="color: #ce9178;">'@angular/forms'</span><span style="color: #d4d4d4;">;</span><br />
<span style="color: #c586c0;">…</span><br />
<br />
<span style="color: #d4d4d4;">@</span><span style="color: #dcdcaa;">NgModule</span><span style="color: #d4d4d4;">({</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">imports:</span><span style="color: #d4d4d4;"> [</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">CommonModule</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">FormsModule</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">ReactiveFormsModule</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">IonicModule</span><span style="color: #d4d4d4;">,</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">RouterModule</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">forChild</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">routes</span><span style="color: #d4d4d4;">)</span><br />
<span style="color: #d4d4d4;"> ],</span><br />
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">declarations:</span><span style="color: #d4d4d4;"> [</span><span style="color: #9cdcfe;">SignupPage</span><span style="color: #d4d4d4;">]</span><br />
<span style="color: #d4d4d4;">})</span><br />
<span style="color: #c586c0;">export</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">class</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">SignupPageModule</span><span style="color: #d4d4d4;"> {}</span><br />
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
Then create a file <b><i>/src/app/validators/password.ts</i></b> for validating password input. The password must be between 4 and 10 characters and must have at least 1 number. Below is its code:</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<br />
<span style="color: #c586c0;">import</span> { <span style="color: #9cdcfe;">FormControl</span> } <span style="color: #c586c0;">from</span> <span style="color: #ce9178;">"@angular/forms"</span>;<br />
<br />
<span style="color: #c586c0;">export</span> <span style="color: #569cd6;">class</span> <span style="color: #4ec9b0;">PasswordValidator</span> {<br />
<span style="color: #569cd6;">static</span> <span style="color: #dcdcaa;">checkPassword</span>(<span style="color: #9cdcfe;">control</span>: <span style="color: #4ec9b0;">FormControl</span>) {<br />
<span style="color: #c586c0;">if</span> (<span style="color: #9cdcfe;">control</span>.<span style="color: #9cdcfe;">value</span>.<span style="color: #dcdcaa;">match</span>(<span style="color: #d16969;">/</span><span style="color: #dcdcaa;">^</span><span style="color: #ce9178;">(?=</span><span style="color: #d16969;">.</span><span style="color: #d7ba7d;">*</span><span style="color: #ce9178;">[</span><span style="color: #d16969;">0-9</span><span style="color: #ce9178;">])[</span><span style="color: #d16969;">a-zA-Z0-9!@#$%^&*</span><span style="color: #ce9178;">]</span><span style="color: #d7ba7d;">{4,10}</span><span style="color: #dcdcaa;">$</span><span style="color: #d16969;">/</span>)) {<br />
<span style="color: #c586c0;">return</span> <span style="color: #569cd6;">null</span>;<br />
} <span style="color: #c586c0;">else</span> {<br />
<span style="color: #c586c0;">return</span> { <span style="color: #ce9178;">'invalidPassword'</span><span style="color: #9cdcfe;">:</span> <span style="color: #569cd6;">true</span> };<br />
}<br />
}<br />
}</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
Then modify files <span style="font-size: 16px; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700;">src/app/signup/signup.page.ts</span> and <span style="font-size: 16px; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700;">src/app/signup/signup.page.html</span> as the following:</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<br />
<span style="color: #c586c0;">import</span> { <span style="color: #9cdcfe;">Component</span>, <span style="color: #9cdcfe;">OnInit</span> } <span style="color: #c586c0;">from</span> <span style="color: #ce9178;">'@angular/core'</span>;<br />
<span style="color: #c586c0;">import</span> { <span style="color: #9cdcfe;">PasswordValidator</span> } <span style="color: #c586c0;">from</span> <span style="color: #ce9178;">'../validators/password'</span>;<br />
<span style="color: #c586c0;">import</span> { <span style="color: #9cdcfe;">AuthService</span> } <span style="color: #c586c0;">from</span> <span style="color: #ce9178;">'../services/auth.service'</span>;<br />
<span style="color: #c586c0;">import</span> { <span style="color: #9cdcfe;">Validators</span>, <span style="color: #9cdcfe;">FormBuilder</span>, <span style="color: #9cdcfe;">FormGroup</span>, <span style="color: #9cdcfe;">FormControl</span> } <span style="color: #c586c0;">from</span> <span style="color: #ce9178;">'@angular/forms'</span>;<br />
<span style="color: #c586c0;">import</span> { <span style="color: #9cdcfe;">LoadingController</span>, <span style="color: #9cdcfe;">NavController</span> } <span style="color: #c586c0;">from</span> <span style="color: #ce9178;">'@ionic/angular'</span>;<br />
<br />
@<span style="color: #dcdcaa;">Component</span>({<br />
<span style="color: #9cdcfe;">selector:</span> <span style="color: #ce9178;">'app-signup'</span>,<br />
<span style="color: #9cdcfe;">templateUrl:</span> <span style="color: #ce9178;">'./signup.page.html'</span>,<br />
<span style="color: #9cdcfe;">styleUrls:</span> [<span style="color: #ce9178;">'./signup.page.scss'</span>],<br />
})<br />
<span style="color: #c586c0;">export</span> <span style="color: #569cd6;">class</span> <span style="color: #4ec9b0;">SignupPage</span> <span style="color: #569cd6;">implements</span> <span style="color: #4ec9b0;">OnInit</span> {<br />
<span style="color: #9cdcfe;">signupCreds</span>: <span style="color: #4ec9b0;">FormGroup</span>;<br />
<span style="color: #9cdcfe;">usernameIsValid</span>: <span style="color: #4ec9b0;">boolean</span> = <span style="color: #569cd6;">false</span>;<br />
<span style="color: #9cdcfe;">loading</span>: <span style="color: #4ec9b0;">any</span>;<br />
<br />
<span style="color: #569cd6;">constructor</span>(<br />
<span style="color: #569cd6;">private</span> <span style="color: #9cdcfe;">auth</span>: <span style="color: #4ec9b0;">AuthService</span>,<br />
<span style="color: #569cd6;">private</span> <span style="color: #9cdcfe;">formBuilder</span>: <span style="color: #4ec9b0;">FormBuilder</span>,<br />
<span style="color: #569cd6;">private</span> <span style="color: #9cdcfe;">navCtrl</span>: <span style="color: #4ec9b0;">NavController</span>,<br />
<span style="color: #569cd6;">private</span> <span style="color: #9cdcfe;">loadingCtrl</span>: <span style="color: #4ec9b0;">LoadingController</span>) { }<br />
<br />
<span style="color: #dcdcaa;">ngOnInit</span>() {<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">signupCreds</span> = <span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">formBuilder</span>.<span style="color: #dcdcaa;">group</span>({<br />
<span style="color: #9cdcfe;">username:</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">FormControl</span>(<span style="color: #ce9178;">''</span>, <span style="color: #9cdcfe;">Validators</span>.<span style="color: #dcdcaa;">compose</span>([<span style="color: #9cdcfe;">Validators</span>.<span style="color: #9cdcfe;">required</span>,<br />
<span style="color: #9cdcfe;">Validators</span>.<span style="color: #dcdcaa;">minLength</span>(<span style="color: #b5cea8;">4</span>), <span style="color: #9cdcfe;">Validators</span>.<span style="color: #dcdcaa;">maxLength</span>(<span style="color: #b5cea8;">20</span>), <span style="color: #9cdcfe;">Validators</span>.<span style="color: #dcdcaa;">pattern</span>(<span style="color: #ce9178;">'[a-zA-Z]*'</span>)])),<br />
<span style="color: #9cdcfe;">password:</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">FormControl</span>(<span style="color: #ce9178;">''</span>, <span style="color: #9cdcfe;">Validators</span>.<span style="color: #dcdcaa;">compose</span>([<span style="color: #9cdcfe;">Validators</span>.<span style="color: #9cdcfe;">required</span>, <span style="color: #9cdcfe;">PasswordValidator</span>.<span style="color: #9cdcfe;">checkPassword</span>])),<br />
<span style="color: #9cdcfe;">email:</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">FormControl</span>(<span style="color: #ce9178;">''</span>, <span style="color: #9cdcfe;">Validators</span>.<span style="color: #dcdcaa;">compose</span>([<span style="color: #9cdcfe;">Validators</span>.<span style="color: #9cdcfe;">required</span>,<br />
<span style="color: #9cdcfe;">Validators</span>.<span style="color: #dcdcaa;">pattern</span>(<span style="color: #ce9178;">'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:</span><span style="color: #d7ba7d;">\.</span><span style="color: #ce9178;">[a-zA-Z0-9-]+)*$'</span>)]))<br />
});<br />
}<br />
<br />
<span style="color: #dcdcaa;">checkUsername</span>(<span style="color: #9cdcfe;">username</span>) {<br />
<span style="color: #4ec9b0;">console</span>.<span style="color: #dcdcaa;">log</span>(<span style="color: #ce9178;">"Check user name:"</span> + <span style="color: #9cdcfe;">username</span>);<br />
<span style="color: #c586c0;">if</span> (<span style="color: #9cdcfe;">username</span>.<span style="color: #9cdcfe;">length</span> < <span style="color: #b5cea8;">4</span>) {<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">usernameIsValid</span> = <span style="color: #569cd6;">false</span>;<br />
<span style="color: #4ec9b0;">console</span>.<span style="color: #dcdcaa;">log</span>(<span style="color: #ce9178;">"NG"</span>);<br />
<span style="color: #c586c0;">return</span>;<br />
}<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">auth</span>.<span style="color: #dcdcaa;">check</span>(<span style="color: #9cdcfe;">username</span>.<span style="color: #dcdcaa;">toLowerCase</span>()).<span style="color: #dcdcaa;">then</span>(<br />
(<span style="color: #9cdcfe;">success</span>) <span style="color: #569cd6;">=></span> {<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">usernameIsValid</span> = <span style="color: #569cd6;">true</span>;<br />
<span style="color: #4ec9b0;">console</span>.<span style="color: #dcdcaa;">log</span>(<span style="color: #ce9178;">"OK"</span>);<br />
},<br />
(<span style="color: #9cdcfe;">err</span>) <span style="color: #569cd6;">=></span> {<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">usernameIsValid</span> = <span style="color: #569cd6;">false</span>;<br />
<span style="color: #4ec9b0;">console</span>.<span style="color: #dcdcaa;">log</span>(<span style="color: #ce9178;">"Existed"</span>);<br />
}<br />
);<br />
}<br />
<br />
<span style="color: #569cd6;">async</span> <span style="color: #dcdcaa;">signup</span>(<span style="color: #9cdcfe;">credentials</span>){<br />
<span style="color: #c586c0;">await</span> <span style="color: #569cd6;">this</span>.<span style="color: #dcdcaa;">showLoader</span>();<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">auth</span>.<span style="color: #dcdcaa;">signup</span>(<span style="color: #9cdcfe;">credentials</span>).<span style="color: #dcdcaa;">then</span>((<span style="color: #9cdcfe;">result</span>) <span style="color: #569cd6;">=></span> {<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">loading</span>.<span style="color: #dcdcaa;">dismiss</span>();<br />
<span style="color: #4ec9b0;">console</span>.<span style="color: #dcdcaa;">log</span>(<span style="color: #9cdcfe;">result</span>);<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">navCtrl</span>.<span style="color: #dcdcaa;">goRoot</span>(<span style="color: #ce9178;">'/home'</span>);<br />
}, (<span style="color: #9cdcfe;">err</span>) <span style="color: #569cd6;">=></span> {<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">loading</span>.<span style="color: #dcdcaa;">dismiss</span>();<br />
});<br />
}<br />
<br />
<span style="color: #569cd6;">async</span> <span style="color: #dcdcaa;">showLoader</span>(){<br />
<span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">loading</span> = <span style="color: #c586c0;">await</span> <span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">loadingCtrl</span>.<span style="color: #dcdcaa;">create</span>({<br />
<span style="color: #9cdcfe;">content:</span> <span style="color: #ce9178;">'Creating new account...'</span><br />
});<br />
<span style="color: #c586c0;">return</span> <span style="color: #c586c0;">await</span> <span style="color: #569cd6;">this</span>.<span style="color: #9cdcfe;">loading</span>.<span style="color: #dcdcaa;">present</span>();<br />
}<br />
<br />
}</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-header</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-toolbar</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-title</span><span style="color: grey;">></span>Signup<span style="color: grey;"></</span><span style="color: #569cd6;">ion-title</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-buttons</span> <span style="color: #9cdcfe;">slot</span>=<span style="color: #ce9178;">"start"</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-back-button</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-back-button</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-buttons</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-toolbar</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-header</span><span style="color: grey;">></span><br />
<br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-content</span> <span style="color: #9cdcfe;">padding</span><span style="color: grey;">></span><br />
<br />
<span style="color: grey;"><</span><span style="color: #569cd6;">form</span> <span style="color: #9cdcfe;">[formGroup]</span>=<span style="color: #ce9178;">"signupCreds"</span> <span style="color: #9cdcfe;">(submit)</span>=<span style="color: #ce9178;">"signup(signupCreds.value)"</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">><</span><span style="color: #569cd6;">ion-icon</span> <span style="color: #9cdcfe;">name</span>=<span style="color: #ce9178;">"person"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-icon</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-input</span> <span style="color: #9cdcfe;">type</span>=<span style="color: #ce9178;">"text"</span> <span style="color: #9cdcfe;">(ionBlur)</span>=<span style="color: #ce9178;">"checkUsername($event.target.value)"</span> <span style="color: #9cdcfe;">placeholder</span>=<span style="color: #ce9178;">"User Name"</span> <span style="color: #9cdcfe;">formControlName</span>=<span style="color: #ce9178;">"username"</span> <span style="color: #9cdcfe;">required</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-input</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('username').hasError('required') && signupCreds.get('username').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>Username is required<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('username').hasError('minlength') && signupCreds.get('username').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>Username must have at least 4 characters<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('username').hasError('maxlength') && signupCreds.get('username').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>Username must have maximum 20 characters<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('username').hasError('pattern') && signupCreds.get('username').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>Username must contain only letters<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('username').touched && !usernameIsValid"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>User is invalid or taken<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"!signupCreds.get('username').hasError('maxlength') && !signupCreds.get('username').hasError('pattern') && signupCreds.get('username').touched && usernameIsValid"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"success"</span><span style="color: grey;">></span> User is OK<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">><</span><span style="color: #569cd6;">ion-icon</span> <span style="color: #9cdcfe;">name</span>=<span style="color: #ce9178;">"lock"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-icon</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-input</span> <span style="color: #9cdcfe;">type</span>=<span style="color: #ce9178;">"password"</span> <span style="color: #9cdcfe;">placeholder</span>=<span style="color: #ce9178;">"Password"</span> <span style="color: #9cdcfe;">formControlName</span>=<span style="color: #ce9178;">"password"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-input</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"!signupCreds.get('password').valid && signupCreds.get('password').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>Password is not met standards<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('password').valid && signupCreds.get('password').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"success"</span><span style="color: grey;">></span>Password is OK<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">><</span><span style="color: #569cd6;">ion-icon</span> <span style="color: #9cdcfe;">name</span>=<span style="color: #ce9178;">"mail"</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-icon</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-label</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-input</span> <span style="color: #9cdcfe;">type</span>=<span style="color: #ce9178;">"email"</span> <span style="color: #9cdcfe;">placeholder</span>=<span style="color: #ce9178;">"Your email"</span> <span style="color: #9cdcfe;">formControlName</span>=<span style="color: #ce9178;">"email"</span> <span style="color: #9cdcfe;">required</span><span style="color: grey;">></</span><span style="color: #569cd6;">ion-input</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-item</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('email').hasError('required') && signupCreds.get('email').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>Email is required<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<span style="color: grey;"><</span><span style="color: #569cd6;">p</span> <span style="color: #9cdcfe;">*ngIf</span>=<span style="color: #ce9178;">"signupCreds.get('email').hasError('pattern') && signupCreds.get('email').touched"</span> <span style="color: #9cdcfe;">class</span>=<span style="color: #ce9178;">"error"</span><span style="color: grey;">></span>Email is wrong format<span style="color: grey;"></</span><span style="color: #569cd6;">p</span><span style="color: grey;">></span><br />
<br />
<span style="color: grey;"><</span><span style="color: #569cd6;">ion-button</span> <span style="color: #9cdcfe;">expand</span>=<span style="color: #ce9178;">"block"</span> <span style="color: #9cdcfe;">type</span>=<span style="color: #ce9178;">"submit"</span> <span style="color: #9cdcfe;">color</span>=<span style="color: #ce9178;">"secondary"</span> <span style="color: #9cdcfe;">[disabled]</span>=<span style="color: #ce9178;">"!signupCreds.valid"</span><span style="color: grey;">></span>Sign up<span style="color: grey;"></</span><span style="color: #569cd6;">ion-button</span><span style="color: grey;">></span><br />
<span style="color: grey;"></</span><span style="color: #569cd6;">form</span><span style="color: grey;">></span><br />
<br />
<span style="color: grey;"></</span><span style="color: #569cd6;">ion-content</span><span style="color: grey;">></span></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
And <span style="font-size: 16px; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700;">src/app/signup/signup.page.scss</span>:</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<br />
<span style="color: #d7ba7d;">.error</span> {<br />
<span style="color: #9cdcfe;">color</span>: <span style="color: #ce9178;">red</span>;<br />
}<br />
<span style="color: #d7ba7d;">.success</span> {<br />
<span style="color: #9cdcfe;">color</span>: <span style="color: #ce9178;">green</span>;<br />
}</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
Now you can sign up and login. That's all for Part 1. <a href="https://vivavivugeek.blogspot.com/2019/03/learning-ionic-4-part-2.html">In Part 2</a>, we will code some things new.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<b><i>See you!</i></b></div>
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-77240138580530064452018-09-06T13:37:00.000+07:002018-09-06T13:52:42.192+07:00MS SQL Server: How to copy a standby DB (logs shipped) to another instanceWhy we need to copy a standby database? The main reasons are the location & time. Normally the online DB will be in a server on datacenter/clouding, while the standby DB (<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">logs </span>shipped) will be in a local server. So if you have a big size DB, you may take time & traffic to transfer the backup of online DB to a local server for doing your needs. However, if you can copy the standby DB, it will be faster and save your traffic. After copying, your standby DB can <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">still receive logs shipped from the online DB.</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
Below are steps to do this on the standby server.<br />
<br />
<b>1. Take offline the standby DB</b><br />
Run the following command:<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">USE MASTER<br />GO<br />ALTER DATABASE [DBNAME] SET OFFLINE</span></blockquote>
<br />
<b>2. Disable restoring job</b><br />
On MS SQL Server Management Studio, go to <b><i>SQL Server Agent</i></b> >> <b><i>Jobs</i></b> >> right click on the restoring job >> select <i><b>Disable</b></i>, see the following for example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPS3Hv1lsuMiBuy1glB8UYPEmA79PkQ0EURUZt_J9b8ocuI4Iwail4mk1Cb87ddWjx_8sRB4Q-xT4ySC2OW_6x0siYmrDV0iZCaa9eSHlynA7J9MfAzg-VumiT7q9vGaN_h3h5FdfGMkwg/s1600/Copy_Standby_DB_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="402" data-original-width="289" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPS3Hv1lsuMiBuy1glB8UYPEmA79PkQ0EURUZt_J9b8ocuI4Iwail4mk1Cb87ddWjx_8sRB4Q-xT4ySC2OW_6x0siYmrDV0iZCaa9eSHlynA7J9MfAzg-VumiT7q9vGaN_h3h5FdfGMkwg/s320/Copy_Standby_DB_1.PNG" width="230" /></a></div>
<br />
<b>3. Copy data file (<i>.mdf</i>) and log file (<i>.ldf</i>) of the standby DB to another place</b><br />
To know where, you can right click on DB >> select <b><i>Properties</i></b> >> select tab <b><i>Files</i></b> >> see <b><i>Path</i></b> column.<br />
<br />
<b>4. Take online the standby DB</b><br />
Now, we take it back for continuing receiving logs shipped. Run the following command:<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">USE MASTER<br />GO<br />ALTER DATABASE [DBNAME] SET ONLINE</span></blockquote>
<b>5. Enable restoring job again</b><br />
<br />
After this step, you standby DB will run normally again.<br />
<br />
Now we can create new DB and copy files in step 3 above to. Below are steps on the server which will run this copied DB.<br />
<br />
<b>6. Create new DB (same name with standby DB)</b><br />
Run the following command (m<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">ake sure new DB same names DBNAME_Data and DBNAME_Log with standby DB</span>):<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">CREATE DATABASE [DBNAME]<br />ON <br />(NAME = 'DBNAME_Data', FILENAME = 'C:\SQL-Data-Folder\DBNAME.mdf')<br />LOG ON<br />(NAME = 'DBNAME_Log', FILENAME = '<span style="background-color: transparent; color: black; display: inline; float: none; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">C:\SQL-Data-Folder\DBNAME</span>.ldf')</span></blockquote>
<br />
<b>7. Take this new DB offline</b><br />
<b></b><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ALTER DATABASE [DBNAME] SET OFFLINE</span></blockquote>
<br />
<b>8. Copy files in step 3 overwrite files of new DB created</b><br />
<br />
<b>9. Grant permission for MSSQLSERVER working on copied files</b><br />
On file explorer, right click on the file name >> select <b><i>Properties</i></b> menu >> select tab <b><i>Security</i></b> >> click <b><i>Advanced</i></b> button:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL-rlI4aokjEkUGm8frP-ca5i0XEvEsqOJ1xdM1683fmWBix0rrUrBC-tpEw3EXacE96NLyjq41HVfMtX3rf_lfjHnItG5SIFqtuJaptpkLetFP01yQpsr3ncvHARMNOh8FsD0uZFlGVtM/s1600/Copy_Standby_DB_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="520" data-original-width="767" height="432" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL-rlI4aokjEkUGm8frP-ca5i0XEvEsqOJ1xdM1683fmWBix0rrUrBC-tpEw3EXacE96NLyjq41HVfMtX3rf_lfjHnItG5SIFqtuJaptpkLetFP01yQpsr3ncvHARMNOh8FsD0uZFlGVtM/s640/Copy_Standby_DB_2.PNG" width="640" /></a></div>
<br />
Change the owner and add full permissions on these files copied for user running SQL service (normally it is <b><i>NT Service\MSSQLSERVER</i></b>). S<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">ee red boxes on above picture for example.</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<b>10. Take this new DB online</b><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ALTER DATABASE [DBNAME] SET ONLINE</span></blockquote>
<br />
OK, now you have a copied DB of standby DB running. Have fun.Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-28010337727299957622018-08-14T16:57:00.001+07:002018-08-14T16:57:42.451+07:00Using Chocolatey for managing NodeJSWhat is Chocolatey? Let read here: <a href="https://chocolatey.org/about"><span id="goog_256624276"></span>https://chocolatey.org/about<span id="goog_256624277"></span></a><br />
Install & Upgrade <span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Chocolatey => read here: <a href="https://chocolatey.org/install">https://chocolatey.org/install</a></span><br />
<span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<div style="text-align: center;">
<span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-variant: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaLgKjbKBFcrZOxzWXElAvsaIP9_EaVYOOYsdRtYbycF8g9FOfGDJBVFaZQt27R8JI5jtX1k0JyWs5PEBPoJajUg4RdKvZ3xpubTjUAFYrnTg4twUaxw_c2Of1qnOcGr-SyP9LV-SQBw9q/s1600/choco_logo_square.png" imageanchor="1" style="-webkit-text-stroke-width: 0px; background-color: transparent; color: #0066cc; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-left: 16px; margin-right: 16px; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="155" data-original-width="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaLgKjbKBFcrZOxzWXElAvsaIP9_EaVYOOYsdRtYbycF8g9FOfGDJBVFaZQt27R8JI5jtX1k0JyWs5PEBPoJajUg4RdKvZ3xpubTjUAFYrnTg4twUaxw_c2Of1qnOcGr-SyP9LV-SQBw9q/s1600/choco_logo_square.png" /></a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></span></div>
<span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br /></span><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b><u>1. Install NodeJS</u></b></span><br />
Open CMD and the following command:<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">choco install nodejs -y</span></blockquote>
<br />
It will install latest NodeJS version and npm together.<br />
For installing long term support (<span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">LTS)</span> version of NodeJS, run the command:<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">choco install nodejs-lts -y</span></blockquote>
<br />
<b><u>2. Upgrade NodeJS</u></b><br />
Run the command:<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">choco upgrade nodejs -y</span></blockquote>
<br />
It will upgrade to latest NodeJS + npm. In case you want to upgrade npm only, let run PowerShell as Administrator and execute below commands:<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force<br />npm install -g npm-windows-upgrade<br />npm-windows-upgrade</span></blockquote>
Or<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">npm-windows-upgrade -p -v latest</span></blockquote>
<br />
<b><u>3. Uninstall NodeJS</u></b><br />
Run the command:<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">choco uninstall nodejs -y</span></blockquote>
<br />
I love chocolatey ❤<br />
<br />
Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-70350466514425317392018-07-25T17:59:00.001+07:002018-07-25T17:59:40.313+07:00MS SQL: How to configure log shipping with FreeFileSync over FTP/SFTPIn MS SQL, log shipping is a popular technique for:<br />
<ul>
<li>Copy and sync a database to multiple servers</li>
<li>H<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">igh availability / <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">failover / disaster recovery / backup plan</span></span></li>
<li><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Data warehouse / reporting server</span></span></li>
</ul>
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike>Comparing with <a href="https://vivavivugeek.blogspot.com/2015/11/ms-sql-2014-mirroring-and-trouble.html">mirroring technique</a>, although log shipping has late time (10-15 minutes) bigger than mirroring (few seconds) but we can use the secondary database(s) of log shipping for reading while we can not do anything with mirrored database (only one <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">mirrored database</span>). So depending on how your system wants, you can use both of these techniques or one of them.<br />
<br />
Normally, log shipping is configured natively with a shared folder which the secondary server can access via private / public network. You can configure the shared folder to limit for some users or some IP addresses (by firewall). However, the disadvantages of shared folder are security issues when sharing over Internet and we cannot control bandwidth when transferring file data.<br />
<br />
In this article, I want to introduce you another way to do the log shipping via FTP/SFTP by using<br />
by using <a href="https://freefilesync.org/">FreeFileSync</a> which can solve above disadvantages.<br />
<b></b><u></u><br />
<b><u>1. Prepare environment</u></b><br />
<br />
On the secondary server:<br />
<ul>
<li><div style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Setup FTP server (can use <a href="https://filezilla-project.org/">FileZilla Server</a>) on the secondary server. Then configuring a FTP folder for receiving transaction log files from the primary server. For example, the FTP folder is configured with a local folder <i>C:\FTP\FileSync</i>.</span></div>
</li>
<li>Create a folder (e.g. <i>C:\Translog</i>) for copying log files synced from <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>C:\FTP\FileSync</i> to.</span></li>
<li><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Grant full permission for user running <i>SQL Server Agent</i> service (normally it is <i>NT Service\SQLSERVERAGENT</i>, let check in <b><i>Services</i></b> tool) and user running <i>SQL Server</i> service (<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">normally it is </span><i>NT Service\MSSQLSERVER</i>) to control the folder <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">C:\Translog</span>.</span></li>
<li><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Open <i>C:\Windows\System32\drivers\etc\host</i> with Administrator right then add a line with IP to point the primary server name, for example: <i>192.168.72.100 PRIMARY_SERVER_NAME</i> (to know the host name, open CMD on the primary server then run command <i><b>hostname</b></i>).<i></i></span></li>
</ul>
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><i></i><i></i>On the primary server:<br />
<ul>
<li>Create a folder save log files exported (e.g. <i>Z:\Translog</i>). Grant <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">full permission for user running </span><i style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">SQL Server Agent</i><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> service </span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">and user running </span><i style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">SQL Server</i><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> service <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">to control the folder <i>Z</i></span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>:\Translog</i></span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">.</span></span></li>
<li><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Open </span><i style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">C:\Windows\System32\drivers\etc\host</i><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> with Administrator right then add a line with IP to point the secondary server name, for example: </span><i style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">192.168.72.101 SECONDARY_SERVER_NAME</i></span></span></li>
<li>Download <a href="https://freefilesync.org/download.php">FreeFileSync</a> and install it on the p<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">rimary sever.</span></li>
<li>Create a batch job on FreeFileSync for syncing files (Mirror way) from <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>Z</i></span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>:\Translog</i></span> to the FTP folder on secondary primary. See the tutorial video on <a href="https://freefilesync.org/tutorials.php">https://freefilesync.org/tutorials.php</a> and the following pictures for how to.</li>
<li>Setup RealTimeSync for the batch job for watching on <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>Z</i></span><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>:\Translog </i></span>and syncing files real time. <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">See the tutorial video on </span><a href="https://freefilesync.org/tutorials.php" style="-webkit-text-stroke-width: 0px; background-color: transparent; color: #0066cc; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">https://freefilesync.org/tutorials.php</a><span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> and the following pictures for how to.</span></li>
</ul>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4RCkdoVEZYmoKh52vRp7IMvT651xT_QpbIupUdCuzAW5dP9To5nL7xt2kho3v7pvB5Y-ItxNP5PZ0eMkho_RKrbPYdUaOX3mVrtIAFpWCRMRRiKIuD3q6AfVS1QEHsfFVrcinTHw96mg6/s1600/FreeFileSync_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="731" data-original-width="1366" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4RCkdoVEZYmoKh52vRp7IMvT651xT_QpbIupUdCuzAW5dP9To5nL7xt2kho3v7pvB5Y-ItxNP5PZ0eMkho_RKrbPYdUaOX3mVrtIAFpWCRMRRiKIuD3q6AfVS1QEHsfFVrcinTHw96mg6/s640/FreeFileSync_1.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHa2TZUA7Qv-MBwUhN792-8UUNs74kxlR_AjnZVY6Gk94V_UA_i4aFN2bzhMHEF6zCn2bLGtjiFrFrISv6qeddnluB-0L2VTJGKEcXZM4I1lzS66yMLnris5fvO2oaGCt9NGqPUHZiE_qi/s1600/FreeFileSync_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="483" data-original-width="679" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHa2TZUA7Qv-MBwUhN792-8UUNs74kxlR_AjnZVY6Gk94V_UA_i4aFN2bzhMHEF6zCn2bLGtjiFrFrISv6qeddnluB-0L2VTJGKEcXZM4I1lzS66yMLnris5fvO2oaGCt9NGqPUHZiE_qi/s400/FreeFileSync_2.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFxsGSf4E8aHfNtCo__jJEtJ5nIzx4YhGbQWZI6vVjNThcniMba4nbSomcZuMtKD9WhEQncWiNuacysxnvJr16te8dNFA-WTW6RssBvEuLRxg9XfyKBFw4ulzGUUIKxGuTGUz9GKxEQxg2/s1600/FreeFileSync_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="436" height="281" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFxsGSf4E8aHfNtCo__jJEtJ5nIzx4YhGbQWZI6vVjNThcniMba4nbSomcZuMtKD9WhEQncWiNuacysxnvJr16te8dNFA-WTW6RssBvEuLRxg9XfyKBFw4ulzGUUIKxGuTGUz9GKxEQxg2/s320/FreeFileSync_3.png" width="320" /></a></div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b></b><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b><u>2. Setup log shipping on the primary server by using MS SQL Management Studio</u></b></span><br />
<u></u><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Make sure your DB is <b><i>Full</i></b> recovery model (or <b><i>Bulk-logged</i></b>). Right click on your DB >> select <b><i>Properties</i></b> menu and check & change in <b><i>Options</i></b> section:</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_fPtCE5jkbs2cld4r7O4DZVZnV7xPc3PvCXbbzQd8bg6uiZWb3ACZpDLoxg6g-8Hcw8CHUHD5Xl7IyD091GTVkISeXuUFt0bzQKBVJr5Lub71P7OcYfdHdG93so9dK0NG5q_rupYd-g-Y/s1600/SQL_LS_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="421" data-original-width="469" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_fPtCE5jkbs2cld4r7O4DZVZnV7xPc3PvCXbbzQd8bg6uiZWb3ACZpDLoxg6g-8Hcw8CHUHD5Xl7IyD091GTVkISeXuUFt0bzQKBVJr5Lub71P7OcYfdHdG93so9dK0NG5q_rupYd-g-Y/s400/SQL_LS_1.png" width="400" /></a></div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="font-family: "times new roman";">Move to <b><i>Transaction Log Shipping</i></b> section and tick <b><i>Enable this as a primary database...</i></b>:</span><br />
<span style="font-family: "times new roman";"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9iio-pd32HXOAju3DpXq2s_H5wTiqtjnIvdZe2uYyTcbqIcgQfm2VzTGKb3h-1IzaGGpcrEmqKhLaNN-Rc1i3P2lgtb-77kleKViDPjGTkP8SJEaIkQmi4JGq6jvIXmlkH-Ee3eEZMf4n/s1600/SQL_LS_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="421" data-original-width="469" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9iio-pd32HXOAju3DpXq2s_H5wTiqtjnIvdZe2uYyTcbqIcgQfm2VzTGKb3h-1IzaGGpcrEmqKhLaNN-Rc1i3P2lgtb-77kleKViDPjGTkP8SJEaIkQmi4JGq6jvIXmlkH-Ee3eEZMf4n/s400/SQL_LS_2.png" width="400" /></a></div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Then click <b><i>Backup Settings</i></b> button to pop up below form:</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW0LJ9mFAc204-Q2bS2QJq0qI80aM3UxBlX0rBjRdQXGIn2OYCj7xBheE78ClPpZbGZcs0GUsZ6G8zcTHlwg0qp9yjlk5FDz1hN74FtA5KXY9kRzWMcYPuOTpZFtcogzCktK4ZKM0HaiT_/s1600/SQL_LS_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="476" data-original-width="475" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW0LJ9mFAc204-Q2bS2QJq0qI80aM3UxBlX0rBjRdQXGIn2OYCj7xBheE78ClPpZbGZcs0GUsZ6G8zcTHlwg0qp9yjlk5FDz1hN74FtA5KXY9kRzWMcYPuOTpZFtcogzCktK4ZKM0HaiT_/s400/SQL_LS_3.png" width="398" /></a></div>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="font-family: "times new roman";">In the box <b><i>Network path to backup folder...</i></b>, let key <i>\\YOURSERVER\SF</i> or any kind of shared folder you want. That is a fake folder which we won't use, just key in for enabling <b><i>OK</i></b> button. The second box, let key in the folder <span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Z:\Translog</span> which you prepared. You can change the other parameters according your need. I recommend to use <b><i>Compress backup</i></b> option for saving bandwidth when transferring logs via Internet. Click <b><i>OK</i></b> button to finish this form.</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">In <b><i>Monitor server instance</i></b> area, tick <b><i>Use a monitor server instance</i></b> then click <b><i>Settings</i></b> button to bring up the following form:</span><br />
<span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv43PuDQFp5pZsNFMyhpERDFDJXJp_r21K7Z1fGl1CtEiDtw-y6VkeNuv1kOIhoGZ6n9ukHp39_cvNVl7qwcjiKMLHmHXftcO062VEerNpnHvOMevozogFnhAsyD_jooyLaG294U_t0P52/s1600/SQL_LS_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="602" data-original-width="651" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv43PuDQFp5pZsNFMyhpERDFDJXJp_r21K7Z1fGl1CtEiDtw-y6VkeNuv1kOIhoGZ6n9ukHp39_cvNVl7qwcjiKMLHmHXftcO062VEerNpnHvOMevozogFnhAsyD_jooyLaG294U_t0P52/s400/SQL_LS_4.png" width="400" /></a></div>
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
Click <b><i>Connect</i></b> button then connect to the secondary server, you can change the value of <b><i>Delete history after</i></b> and click <b><i>OK</i></b> button to finish.<br />
<br />
Back to <b><i>Transaction Log Shipping</i></b><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> section</span>, click <b><i>OK</i></b> button to establish configurations for the primary server. It will enable the primary database for log shipping and create 2 jobs: <b><i>LSBackup_XXX</i></b> in <b><i>SQL Server Agent</i></b><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> >> </span><b style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 700; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>Jobs</i></b><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> of the primary server and <b><i>LSAlert_XXX</i></b> <span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">in </span><b style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 700; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>SQL Server Agent</i></b><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> >> </span><b style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 700; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>Jobs</i></b><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> of the secondary server.</span></span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
Right click your DB, select menu <b><i>Task >> Back Up</i></b>... select <b><i>Backup type</i></b> as <b><i>Full</i></b>. Then backup your DB to disk. This backup file will be copied to the secondary server for initializing secondary database.<br />
<br />
Before going to the secondary server and configuring, we will do a trick to get a script for running on that server. Open back <b><i>Transaction Log Shipping</i></b><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline; float: none; font-family: &quot; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> section, on <b><i>Secondary databases</i></b> click <b><i>Add</i></b> button to open below form:</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKsrNw1zQR1gvrxvAwmZCQM08kBvbAcmWxe3GVe4k_oRf3IY_bPmBLq5ZdOXZ12lZpwzqXWPcEqvlA55tjfzcyI_HedAiu18brDqYB8KCxxD3PYzk3R0Q4BZWhAs9EC_hg-osRn2XX2i80/s1600/SQL_LS_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="611" data-original-width="726" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKsrNw1zQR1gvrxvAwmZCQM08kBvbAcmWxe3GVe4k_oRf3IY_bPmBLq5ZdOXZ12lZpwzqXWPcEqvlA55tjfzcyI_HedAiu18brDqYB8KCxxD3PYzk3R0Q4BZWhAs9EC_hg-osRn2XX2i80/s400/SQL_LS_5.png" width="400" /></a></div>
<br />
Click <b><i>Connect</i></b> button and connect to the <b><i>Secondary server instance</i></b> and <b><i>Secondary database</i></b> (e.g. <i>TestDB</i>). Select option "<b><i>No, the secondary database is initialized</i></b>" then move to <b><i>Copy Files</i></b> tab:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0IZtZrRF9oAZTPXw0Hand-uSU85BqrZJe3BAqzQH0uG7OpBsw1R5lloDomy7neQjsCabfb4YjbxBd35Mv8El_YaIZpdBLigcV56NWrpXX73OQ0_bJBwvgEBBQwW0uYTgZRggNk3r4prDD/s1600/SQL_LS_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="611" data-original-width="726" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0IZtZrRF9oAZTPXw0Hand-uSU85BqrZJe3BAqzQH0uG7OpBsw1R5lloDomy7neQjsCabfb4YjbxBd35Mv8El_YaIZpdBLigcV56NWrpXX73OQ0_bJBwvgEBBQwW0uYTgZRggNk3r4prDD/s400/SQL_LS_6.png" width="400" /></a></div>
<br />
Key in the folder in the secondary server for copying transaction log files (e.g. <i>C:\Translog_Copy</i>). Move to <b><i>Restore Transaction Log</i></b> tab:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9mP0rOdWPqxaX3ufEAU3ck4U5zKRvW6X0mu30Wt-YttVu2bP6BdKIWZ2DvZECf5Bpb5OgnjpLhzOrSOqyh-HWNs4HE6jWxvOyfZmvjF5R1-kmHMJHDluB3G7dxxzzNMgu7bUhXy0Ez1QC/s1600/SQL_LS_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="611" data-original-width="726" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9mP0rOdWPqxaX3ufEAU3ck4U5zKRvW6X0mu30Wt-YttVu2bP6BdKIWZ2DvZECf5Bpb5OgnjpLhzOrSOqyh-HWNs4HE6jWxvOyfZmvjF5R1-kmHMJHDluB3G7dxxzzNMgu7bUhXy0Ez1QC/s400/SQL_LS_7.png" width="400" /></a></div>
<br />
Select <b><i>Standby mode</i></b> and tick "<b><i>Disconnect user...</i></b>" to put the secondary database into read only mode and disconnect users when restoring. Then click <b><i>OK</i></b> button.<br />
<span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Back to </span><b style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 700; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><i>Transaction Log Shipping</i></b><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline; float: none; font-family: &quot; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"> section</span><span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">, in the bottom click <b><i>Script Configuration</i></b> >> <b><i>Script Configuration to New Query Window</i></b>, ah ha let see the script generated. Before viewing this script, let click <b><i>Cancel</i></b> button to close <span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 700; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Transaction Log Shipping</span> without doing any thing.</span><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuLuaB8F3TI5e18OL2rxu3vSYxkw2PH3dijD1iHK8-l53JXARntdVqtE-_YP2wQ1pgbrB16r-oOlUwyuCHytrbt3-kwvoqPPniVsKZlwDc26swNOzjSEdeLrFsQJx5krhh_bYu-bUbE9mE/s1600/SQL_LS_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="200" data-original-width="641" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuLuaB8F3TI5e18OL2rxu3vSYxkw2PH3dijD1iHK8-l53JXARntdVqtE-_YP2wQ1pgbrB16r-oOlUwyuCHytrbt3-kwvoqPPniVsKZlwDc26swNOzjSEdeLrFsQJx5krhh_bYu-bUbE9mE/s400/SQL_LS_8.png" width="400" /></a></div>
<br />
Go to the query window opened and copy the script between "<i>Begin: Script to be run at Secondary</i>" and "<i>End: Script to be run at Secondary</i>" to run on the secondary server later.<br />
<u></u><br />
<b><span style="font-family: "times new roman";"><u>3<span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">. Setup log shipping on the secondary server</span></u></span></b><i></i><sub></sub><sup></sup><strike></strike><br />
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><b></b><span style="font-family: "times new roman";"></span><u></u><br />
First of all, let restore the full backup of primary database on the secondary server by using RESTORE WITH STANDBY (you should restore before generating the script on the step above):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDlT7a1fAqMJqI3azRGCPuarfqD7g9gN0x2sk-UfgXB8jH3ye7fXz4AOYTbzPqJirnvYp7nBqtSEJ1vcC_Wwl7XPA0eDsZp2dLgsDHtAEQflj_DjF8X2mLtwrSlJEjeoUIpl94t20dKHgU/s1600/SQL_LS_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="721" data-original-width="864" height="333" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDlT7a1fAqMJqI3azRGCPuarfqD7g9gN0x2sk-UfgXB8jH3ye7fXz4AOYTbzPqJirnvYp7nBqtSEJ1vcC_Wwl7XPA0eDsZp2dLgsDHtAEQflj_DjF8X2mLtwrSlJEjeoUIpl94t20dKHgU/s400/SQL_LS_10.png" width="400" /></a></div>
<br />
After restoring, you will see the DB with text <b><i>(Standby / Read-Only).</i></b> Open new query windows and paste copied script above into here (remember to choose <b><i>msdb</i></b> for running the script later):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRzT0tYwbU4ON43ES0NGptyzTioK7gTRCPLAUbIghzXVMSCNLRweUd2pucrjtdeuDi1KFQvW7Yx79n_pH6vY_RgIooRLErecKc2ydPe1-ir6Zm4pNP6LOL_zTlmlb0gTKEYGD4gqF7kCHp/s1600/SQL_LS_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="196" data-original-width="598" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRzT0tYwbU4ON43ES0NGptyzTioK7gTRCPLAUbIghzXVMSCNLRweUd2pucrjtdeuDi1KFQvW7Yx79n_pH6vY_RgIooRLErecKc2ydPe1-ir6Zm4pNP6LOL_zTlmlb0gTKEYGD4gqF7kCHp/s400/SQL_LS_11.png" width="400" /></a></div>
<br />
Yes, nearly done! We just modify the script a little bit to change the fake shared folder (<i>\\YOURSERVER\FORDER</i>) to the local folder (<i>C:\Translog</i>) on the secondary server which is the FTP folder to receive log files transferred from the primary server, see below for your idea:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga6K0FhzUtn5rVsS_picdweVYc2LRbLsRQs_BeYGLEkKS8On0f-Z8_8aWze1vHS4IDmHgimqYnT6TpvCjspACkVj3CxG6JilBh8ilVvF0y6NK9FU9gxkNi9xGGsMosO3R5PuPn3qS4I7df/s1600/SQL_LS_9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="417" data-original-width="668" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga6K0FhzUtn5rVsS_picdweVYc2LRbLsRQs_BeYGLEkKS8On0f-Z8_8aWze1vHS4IDmHgimqYnT6TpvCjspACkVj3CxG6JilBh8ilVvF0y6NK9FU9gxkNi9xGGsMosO3R5PuPn3qS4I7df/s640/SQL_LS_9.png" width="640" /></a></div>
<br />
That's it. Run the script. It will create 2 scheduled jobs: <b><i>LSCopy_XXX</i></b> (for copying file from <i>C:\Translog</i> to <i>C:\Translog_Copy</i> per 15 minutes) and <i><b>LSRestore_XXX</b></i> (for restoring transaction logs in <i>C:\Translog_Copy </i>to the secondary database per 15 minutes) in <b><i>SQL Server Agent</i></b> >> <b><i>Jobs</i></b>. You can go there to change the schedule of 2 these jobs.<br />
<br />
Voila! You got the secondary database synced with primary database with interval 15-30 minutes (depending the time between <span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 700; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">LSCopy_XXX </span>and <span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: Times New Roman; font-size: 16px; font-style: italic; font-variant: normal; font-weight: 700; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">LSRestore_XXX</span>).<br />
<b></b><i></i><span style="color: blue;"></span><br />
<b><span style="color: blue;">That's all. Any comment is welcome.</span></b>Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-7459966657845304112018-07-16T14:38:00.001+07:002018-07-16T14:38:19.991+07:00Windows RDP: Solving the error "This could be due to CredSSP encryption oracle remediation"Do you get the error as below when remoting your server?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuh_wyATQwxAiTqhjSeZCW6t9WjoAE-ttcODghkSFsw6vvv2Xv6Xsl-aqK7CVUYNrKrn60IRz0fEGTY3uYaWAPIWKnX_5xgt3gdz5HxtaBnfwqILbilF-f4UJsyMx-ZjQZ8VfKrVmjvfVp/s1600/CredSSP.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="333" data-original-width="802" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuh_wyATQwxAiTqhjSeZCW6t9WjoAE-ttcODghkSFsw6vvv2Xv6Xsl-aqK7CVUYNrKrn60IRz0fEGTY3uYaWAPIWKnX_5xgt3gdz5HxtaBnfwqILbilF-f4UJsyMx-ZjQZ8VfKrVmjvfVp/s400/CredSSP.PNG" width="400" /></a></div>
<br />
It is normally caused by your Windows client getting new update on CredSSP but your Windows server is not.<br />
For long term, you should update your server for more security.<br />
For temporary solution, you can do the following steps on your Windows client to able to remote your server:<br />
<br />
<b>1.</b> Open <b><i>Run</i></b> box, key <b><i>gpedit.msc</i></b> to open <b><i>Local Group Policy Editor</i></b>.<br />
<br />
<b>2.</b> Navigate to <b><i>Computer Configuration >> Administrative Templates >> System >> Credentials Delegation >> Encryption Oracle Remediation</i></b>. Then select <b><i>Enable >> Vulnerable >> OK</i></b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPTS3GnZ8dzuJVmnVShMAIJ6EeUxvXH6EhpE4WpP6hYpW5jSd9ANl0QGr7Qpfu_-_ly749qmGO_QcHBP6-j1lLrh4Ov_oYaKooyRQZm7WS0ix7ZmKDWzbBdkJLCIe5D6WaM4nzN_7NFruo/s1600/CredSSP_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="632" data-original-width="681" height="370" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPTS3GnZ8dzuJVmnVShMAIJ6EeUxvXH6EhpE4WpP6hYpW5jSd9ANl0QGr7Qpfu_-_ly749qmGO_QcHBP6-j1lLrh4Ov_oYaKooyRQZm7WS0ix7ZmKDWzbBdkJLCIe5D6WaM4nzN_7NFruo/s400/CredSSP_2.PNG" width="400" /></a></div>
<br />
<b>3.</b> Finally, open <b><i>CMD</i></b> (run as Administrator), run the command: <b><i>gpupdate /force</i></b><br />
to update the policy immediately.<br />
<br />
Hope you can remote your server and update it. Have a nice day.Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-80915472445910546842018-01-15T23:57:00.003+07:002018-01-15T23:59:16.473+07:00Integrate Facebook comment plugin into your website and notify via email<a href="https://developers.facebook.com/docs/plugins/comments">Facebook comments plugin</a> allows Facebooker comment on a content on your website. The comments of customers or users (guests) are very important for almost website owners. To encourage guests leave their comments, beside the content must be attractive, the responds for comments also should be quickly.<br />
<br />
In this article, I'll show you how to integrate Facebook comment plugin into your website and receive the notification via email when a comment is dropped on your website. Let go through below steps.<br />
<br />
<b>1. Create a Facebook page</b><br />
<b></b><br />
If you still don't have a Facebook page, let create one soon. Facebook page is representative for your website or your business on Facebook. Increasing number of Facebookers who likes or follows your Facebook page will increase the chance to broadcast your website / business on Facebook. Facebook page also is used as an official account to response to comments. Especially when you have many administrators or moderators for your Facebook page.<br />
To create a Facebook page, let go to: <a href="https://www.facebook.com/pages/create">https://www.facebook.com/pages/create</a><br />
<br />
<b>2. Create a Facebook app</b><br />
<b></b><br />
Facebook app is a gateway to interact with Facebook's assets. If you want to do any things with Facebook, you should have a Facebook app.<br />
If you still don't have a Facebook app, let create one via: <a href="https://developers.facebook.com/docs/apps/register">https://developers.facebook.com/docs/apps/register</a><br />
<br />
<b>3. Embed Facebook comments plugin into your website</b><br />
<b></b><br />
Link your website with your Facebook app & page. To do this, let add meta tags <b><i>fb:app_id</i></b> & <b><i>fb:pages</i></b> into all pages of your website, for example:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><meta property="fb:app_id" content="645919975544702" /></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><meta property="fb:pages" content="174460585975791" /></span></blockquote>
To get your Facebook app id, go to the Dashboard of your app, see the following sample:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-Pa91HBD1pp1REMbrhx9U67zAmW0gsqQ9LILf_88o8QKPu-dOrfjvykq9n8BtpOoUJK-1b7cDxgsEr1bTJ8cgtSjM7cAxEcH72m-4PwelhX3HiLxnK6gc7F4IywyeoTZ5U6yoq90imNq2/s1600/fb_tools_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="354" data-original-width="898" height="157" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-Pa91HBD1pp1REMbrhx9U67zAmW0gsqQ9LILf_88o8QKPu-dOrfjvykq9n8BtpOoUJK-1b7cDxgsEr1bTJ8cgtSjM7cAxEcH72m-4PwelhX3HiLxnK6gc7F4IywyeoTZ5U6yoq90imNq2/s400/fb_tools_1.PNG" width="400" /></a></div>
<br />
To get your Facebook page id, go to <b><i>Page >> About</i></b> and find Page ID at the bottom:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUvGblVERwfatUSh-N8LzzIVEb_aQhoE0zwt18yHpmBG1aydMfaGB0SmLbky7pg-__1YIklQ1VuBPLv9tK_mDyYdPqkYHdRk1LWpzSKS6S8DyvHFrp-ms6U0dQggY15ScJKqZ6OF9GlVIJ/s1600/fb_tools_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="524" data-original-width="636" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUvGblVERwfatUSh-N8LzzIVEb_aQhoE0zwt18yHpmBG1aydMfaGB0SmLbky7pg-__1YIklQ1VuBPLv9tK_mDyYdPqkYHdRk1LWpzSKS6S8DyvHFrp-ms6U0dQggY15ScJKqZ6OF9GlVIJ/s320/fb_tools_2.PNG" width="320" /></a></div>
<br />
Next, let add Facebook's JavaScript SDK and comment box into each page on your website where you want to guests leave comments. To get the code and comment box, you can go to <a href="https://developers.facebook.com/docs/plugins/comments">https://developers.facebook.com/docs/plugins/comments</a>, find <b><i>Comments Plugin Code Generator</i></b> section and put your parameters into boxes then click <b><i>Get Code</i></b> button. See below picture for example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw8s3T0ADfDa1G3B9xDH9b3ta7fI0aP79Gsqd7_sWN0q-ikwXt1UbrRlOEgYvBaB9T3LFN5FfUO7y2arDzxWTJ6BHIg3iCFOMwRYUcjGgMTvcw6F6ISvvuiNfU_Vo78zKDS1QA-2QEzs06/s1600/fb_tools_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="543" data-original-width="749" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw8s3T0ADfDa1G3B9xDH9b3ta7fI0aP79Gsqd7_sWN0q-ikwXt1UbrRlOEgYvBaB9T3LFN5FfUO7y2arDzxWTJ6BHIg3iCFOMwRYUcjGgMTvcw6F6ISvvuiNfU_Vo78zKDS1QA-2QEzs06/s400/fb_tools_3.PNG" width="400" /></a></div>
You can change the settings of comment box based on your need, for example I want to show 10 newest comments, I do:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div class="fb-comments" data-href="https://baby.shopqua.com/ba-lo-tui-cap-xach/ba-lo-cho-be" data-numposts="10" data-order-by="reverse_time" data-width="100%"></div></span></blockquote>
For counting number of comments of an URL, let use <b><i>fb-comments-count</i></b>:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="fb-comments-count" data-href="https://baby.shopqua.com/ba-lo-tui-cap-xach/ba-lo-cho-be"></span>comments</span></blockquote>
The above are important settings that I think you should do, for other settings & how to monitor comments, please see more on: <a href="https://developers.facebook.com/docs/plugins/comments">https://developers.facebook.com/docs/plugins/comments</a><br />
<br />
<b>4. Set up your Facebook app</b><br />
<b></b><br />
If you need a page profile for your app, let go to your app >> <b><i>Settings >> Advanced >> App Page</i></b> and click <b><i>Create New Page</i></b> button.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgip8NQHk9ycvHvWS5YS63uAfRBcwkhd-hgvSNViKbUjrdAMugMt05ZxWNgGUYZZM2yHVGzTI-CDlVw-uby9U80W_dNrUNUFHwwjVvO42DKtKP5zIg0kX5Kxva0CalDXa-mKPyLPm4_nobG/s1600/fb_tools_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="238" data-original-width="692" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgip8NQHk9ycvHvWS5YS63uAfRBcwkhd-hgvSNViKbUjrdAMugMt05ZxWNgGUYZZM2yHVGzTI-CDlVw-uby9U80W_dNrUNUFHwwjVvO42DKtKP5zIg0kX5Kxva0CalDXa-mKPyLPm4_nobG/s400/fb_tools_4.PNG" width="400" /></a></div>
<br />
Or you can select an existing page there if the page has same name with the app and categorized as <b><i>App Page</i></b>. To change Category or Name of the existing page, click About menu of the page and click Edit link of Category or Name:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO_7vBEkW0Vx-Z22aAYDOAjg64JT4xGu3Jgo5leRBMWuBS1HcAriTDEJAboD0g1AtBAzGDVf-tUsklMja0QXzN24pjNP2kcxGU72K5etOlMZKoMkhF2NT_kWoJo5rPln7_uqztSWhujyDg/s1600/fb_tools_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="351" data-original-width="642" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO_7vBEkW0Vx-Z22aAYDOAjg64JT4xGu3Jgo5leRBMWuBS1HcAriTDEJAboD0g1AtBAzGDVf-tUsklMja0QXzN24pjNP2kcxGU72K5etOlMZKoMkhF2NT_kWoJo5rPln7_uqztSWhujyDg/s320/fb_tools_5.PNG" width="320" /></a></div>
<br />
The guide on <a href="https://developers.facebook.com/docs/plugins/comments">https://developers.facebook.com/docs/plugins/comments</a> has a section to enable comment mirroring which allows comments from your webpage will also appear as comments on your Facebook Page post and vice-versa. Using comment mirroring, you can receive a notification on <b><i>Facebook Pages Manager</i></b> mobile app when you got a comment on your web page. However it will be deprecated soon according to the post <a href="https://developers.facebook.com/blog/post/2017/11/07/changes-developer-offerings">https://developers.facebook.com/blog/post/2017/11/07/changes-developer-offerings</a>. So you won't receive the notification on <b><i>Facebook Pages Manager</i></b> mobile app more.<br />
<br />
Don't worry, I'll show you a way to get this notification via email. For beginning, let setup a webhook when a new comment is posted. See <b><i>Webhooks</i></b> section on <a href="https://developers.facebook.com/docs/plugins/comments">https://developers.facebook.com/docs/plugins/comments</a> for how to. More than thousands of words, I post here my pictures:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQyW70gQMXvXFg60Pbezu7v_cgsipZLENOXvUZ2a1nfZU20apO1zJkoKGgyFPR5rHgSf-0zIq01aKSuby_2GFgK3U-LFlERb7w1NUqICaTopjvPTxLeWsTlSGG_GB773TZEnFp3kQpbUbD/s1600/fb_tools_6.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="380" data-original-width="930" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQyW70gQMXvXFg60Pbezu7v_cgsipZLENOXvUZ2a1nfZU20apO1zJkoKGgyFPR5rHgSf-0zIq01aKSuby_2GFgK3U-LFlERb7w1NUqICaTopjvPTxLeWsTlSGG_GB773TZEnFp3kQpbUbD/s400/fb_tools_6.PNG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhslaGb6_r_o5cbWRtX4fC8G_WSBVC5vgpwpbNk9aCdRwDx-w19IQE-SSe9smB2KgmmIxI5ZsoWbqrWRLpa2BRmXqnfEGnNgwoOH1061DET_XATN9ziMuUYoc75TnAc5NoKWe70z-WegMhW/s1600/fb_tools_7.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="245" data-original-width="828" height="117" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhslaGb6_r_o5cbWRtX4fC8G_WSBVC5vgpwpbNk9aCdRwDx-w19IQE-SSe9smB2KgmmIxI5ZsoWbqrWRLpa2BRmXqnfEGnNgwoOH1061DET_XATN9ziMuUYoc75TnAc5NoKWe70z-WegMhW/s400/fb_tools_7.PNG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2MpM5GuKv9NoQIWJj0NyD_6ij1YZnt7JqmZUAXgf6lgxQMn4pULoec3Lrc03yg9HFD8DNxiObMAVXvtPO3XLPsXVA8VfIGF6_LkZjn4HEF1smAwLPJMoadFKvR9EEpugsdiJr3jl0cbG7/s1600/fb_tools_8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="565" data-original-width="923" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2MpM5GuKv9NoQIWJj0NyD_6ij1YZnt7JqmZUAXgf6lgxQMn4pULoec3Lrc03yg9HFD8DNxiObMAVXvtPO3XLPsXVA8VfIGF6_LkZjn4HEF1smAwLPJMoadFKvR9EEpugsdiJr3jl0cbG7/s400/fb_tools_8.PNG" width="400" /></a></div>
In the <b><i>Webhooks</i></b> section, Facebook also gives a sample <b><i>mywebhook.php</i></b> in PHP. Let rename it to <b><i>commentwebhook.php</i></b> and modify it in next step to do what we want.<br />
<br />
<b>5. Modify <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">commentwebhook.php</span></b><br />
<div>
<b></b><i></i><u></u><sub></sub><sup></sup><strike><b></b><br /></strike></div>
<div>
The message sent to this webhook file has the format of JSON, however it lacks some important info. So we need to get this info via Facebook API.</div>
<div>
To access Facebook API, you need an <b><i>access_token</i></b>. You can get it via <b><i>Facebook Graph API Explorer</i></b>: <a href="https://developers.facebook.com/tools/explorer">https://developers.facebook.com/tools/explorer</a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgocXG5hUVFFaLvKWJqYtTK0gDhyphenhyphenex7SnNw7RiMAW_krSksCacL5vHvN4uhHWByKoxAFDYkFoP1-1mhRaFPoVYfNl22nt6C0CVyyBxHbKZLOEXVw8zsuxk-BHNnGAMDOxXFJ2qfsiPvZ8BF/s1600/fb_tool_9.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="253" data-original-width="1101" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgocXG5hUVFFaLvKWJqYtTK0gDhyphenhyphenex7SnNw7RiMAW_krSksCacL5vHvN4uhHWByKoxAFDYkFoP1-1mhRaFPoVYfNl22nt6C0CVyyBxHbKZLOEXVw8zsuxk-BHNnGAMDOxXFJ2qfsiPvZ8BF/s640/fb_tool_9.PNG" width="640" /></a></div>
<div>
<br /></div>
You can test APIs in this tool to get experience on data returned. If you want to have a sample code, let scroll down and click <b><i>Get Code</i></b> button at the bottom. The sample code is one among of kinds: Android SDK, iOS SDK, JavaScript SDK, PHP SDK, cURL.<br />
Below is the source code of my <span style="background-color: transparent; color: black; display: inline; float: none; font-family: "times new roman"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><b><i>commentwebhook.php</i></b> file:</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">if ($_GET['hub_verify_token'] === 'XXXXXXXXX-123456789-ABCdef') {<br /> echo $_GET['hub_challenge'];<br />}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">$entry = file_get_contents('php://input');<br />file_put_contents('commentwebhook.log', "\n" . $entry, FILE_APPEND);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">//get input message<br />$input = json_decode($entry, true);<br />$message = $input['entry'][0]['changes'][0]['value']['message'];<br />$fb_comment_id = $input['entry'][0]['changes'][0]['value']['id'];<br />$created_time = $input['entry'][0]['changes'][0]['value']['created_time'];<br />$from_name = $input['entry'][0]['changes'][0]['value']['from']['name'];<br />$from_id = $input['entry'][0]['changes'][0]['value']['from']['id'];</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">//get more details<br />$access_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";<br />$url = "https://graph.facebook.com/v2.6/$fb_comment_id?access_token=$access_token&fields=permalink_url";//fields=permalink_url,message,from,created_time<br />$ch = curl_init();<br />curl_setopt($ch, CURLOPT_URL, $url); <br />curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);<br />curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);<br />$resp = curl_exec($ch);<br />curl_close($ch);<br />$output = json_decode($resp, true);<br />$permalink_url = $output['permalink_url'];</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">//send email<br />$bodyHtml = <br />"<h1><a href='https://www.facebook.com/$from_id'>$from_name</a></h1><br /><h2>$message</h2><br /><h3>On: <a href='$permalink_url'>$permalink_url</a></h3>";<br />$bodyText = "$from_name:\n $message\n On: $permalink_url";<br />$url = 'https://api.elasticemail.com/v2/email/send';<br />try {<br /> $post = array('from' => 'youremail@yourdomain.com',<br /> 'fromName' => 'Your Website Name',<br /> 'apikey' => '00000000-0000-0000-0000-000000000000',<br /> 'subject' => 'You have a comment',<br /> 'to' => 'recipient1@gmail.com;recipient2@gmail.com',<br /> 'bodyHtml' => $bodyHtml,<br /> 'bodyText' => $bodyText,<br /> 'isTransactional' => true);<br /><br /> $ch = curl_init();<br /> curl_setopt_array($ch, array(<br /> CURLOPT_URL => $url,<br /> CURLOPT_POST => true,<br /> CURLOPT_POSTFIELDS => $post,<br /> CURLOPT_RETURNTRANSFER => true,<br /> CURLOPT_HEADER => false,<br /> CURLOPT_SSL_VERIFYPEER => false<br /> ));<br /><br /> $result=curl_exec ($ch);<br /> curl_close ($ch);<br /><br /> file_put_contents('commentwebhook.log', "\n" . $result, FILE_APPEND);<br />}<br />catch(Exception $ex){<br /> file_put_contents('commentwebhook.log', "\n" . $ex->getMessage(), FILE_APPEND);<br />}</span><br />
<span style="font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace;"></span><br />
You can also get the source code from my GitHub: <a href="https://github.com/vnheros/facebookcomment">https://github.com/vnheros/facebookcomment</a><br />
<div>
<br /></div>
<div>
In the code, I use ElasticEmail for sending notification email without worrying about email server and inbox. If you like, <a href="https://elasticemail.com/account#/create-account?r=3b0dec84-a1b3-11e0-a69b-12313b0611f6">you can register here for an ElasticEmail free account</a> (can send up to 5000 emails free per day).</div>
<br />
OK, now you have a power tool for notifying you immediately when getting a comment on your webpage. Happy?<br />
That's all for today. Any comment is welcome!<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com59tag:blogger.com,1999:blog-6453857454125943527.post-29083138858958471752017-12-22T20:16:00.002+07:002018-01-06T23:08:45.991+07:00C# SEO Tools for Google PageSpeedPageSpeed is very important for ranking of your website on Google as also as it will get better experience for your customers when surfing your website. So Google provides its <a href="https://developers.google.com/speed/pagespeed/insights/">PageSpeed Insights tool</a> which will give advices for optimizing your website. When you optimize your website meeting Google's requirements, you website will have higher score and may be your ranking will be higher. The acceptable score should be from 80 points (80 / 100).<br />
<br />
There are many things which you need to do for meeting Google's requirements. However 2 things which impacts to your score most are image optimization and minifying JavaScript + CSS.<br />
<br />
In this article, I'll introduce my SEO Tools (written by C#) for solving above matters. You can checkout the source code here: <a href="https://github.com/vnheros/c-seotools">https://github.com/vnheros/c-seotools</a><br />
<br />
The tool uses the following tools:<br />
<ul>
<li>C# command line parser for .NET: <a href="https://github.com/commandlineparser/commandline">https://github.com/commandlineparser/commandline</a> (Nuget package: <b><i>CommandLineParser</i></b>)</li>
<li>AjaxMin: <a href="http://ajaxmin.codeplex.com/">http://ajaxmin.codeplex.com</a> (Nuget package: <b><i>AjaxMin</i></b>)</li>
<li>Caesium CommandLineTools: <a href="https://github.com/Lymphatus/caesium-clt">https://github.com/Lymphatus/caesium-clt</a></li>
<li>Convert tool of ImageMagick: <a href="https://www.imagemagick.org/script/convert.php">https://www.imagemagick.org/script/convert.php</a> as <a href="https://developers.google.com/speed/docs/insights/OptimizeImages">recommendation of Google PageSpeed Insights</a></li>
</ul>
Below is the guideline for using this SEO Tools.<br />
<b><br /></b>
<b>1. File XML configuration</b><br />
Below is an example:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlo-eVyjKpM9vfdehidHmdPhFtJDaJqUonwh-yhvdOSELF5iK6EWMpm5zNs71gK5zHhjI7wju-2SUr_vPj8Heqvs-SpcZT0H2D49-A9h1FCLLd-Ux6nOkV1HLYD7Ea7SGwGZQO9YkGiwSw/s1600/seo_tools.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="194" data-original-width="595" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlo-eVyjKpM9vfdehidHmdPhFtJDaJqUonwh-yhvdOSELF5iK6EWMpm5zNs71gK5zHhjI7wju-2SUr_vPj8Heqvs-SpcZT0H2D49-A9h1FCLLd-Ux6nOkV1HLYD7Ea7SGwGZQO9YkGiwSw/s640/seo_tools.PNG" width="640" /></a></div>
<b><i>BackupSuffix</i></b> is for copying the original .CSS or . JS file. For example: <b><i>E:\test\big.js</i></b> after optimizing ==> <b><i>E:\test\big_Copy.js</i></b> (containing original source code) and <b><i>E:\test\big.js</i></b> (minified code).<br />
<b><i>BackupOverwrite</i></b> = 0 means every time running this tool, it will check and create a backup file with different suffix starting from <b><i>_Copy1</i></b> to <b><i>_Copy999</i></b>; = 1 means all times running this tool, it only creates a backup file with suffix <b><i>_Copy</i></b> and overwrites it if existing.<br />
<b><i>DefaultOutPath</i></b> is for out put folder (containing optimized images) in terms of you don't specify output folder in command.<br />
<b></b><br />
<b>2</b><b>. Optimize only files listed in input file</b><br />
You can use the following command:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">SEOTools.exe -i input_file</span></blockquote>
For example: input_file is <b><i>E:\test\files.txt</i></b>. Output to a folder (e.g. <b><i>E:\test\output</i></b>), let use:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">SEOTools.exe -i input_file -s subfolder -o output_folder</span></blockquote>
Subfolder is the folder containing image files for compressing, it is used for creating subfolders in backup folder.<br />
<br />
<b>3. Optimize all files in input folder (recursively)</b><br />
You can use the command:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">SEOTools.exe -i input_folder -t I -m FO</span></blockquote>
By default the tool will use Caesium, you can change to use ImageMagick by option <b><i>-t I</i></b>. As my experience Caesium gives smaller file size vs. ImageMagick, however ImageMagick runs faster than Caesium. Both also meets Google PageSpeed Insights.<br />
With this tool, you can run after uploading images to your website or modifying CSS file / JavaScript file. <b><span style="color: blue;">Any comment is welcome.</span></b><i></i><br />
<i><span style="color: red;">Merry Christmas and Happy New Year!</span></i>Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com5tag:blogger.com,1999:blog-6453857454125943527.post-68516144792662187102017-12-06T12:11:00.002+07:002017-12-06T15:58:07.596+07:00Quick Start ElasticSearch on Windows<b>What is ElasticSearch?</b><b></b><br />
<a href="https://www.elastic.co/">ElasticSearch</a> is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases. It is built on top of Apache Lucene. It is commonly used for log analytics, full-text search, and operational intelligence use cases. As the heart of the <a href="https://www.elastic.co/products">Elastic Stack</a>, it centrally stores your data so you can discover the expected and uncover the unexpected.<br />
<b><u><br /></u></b>
<b><u>What will you get from this article?</u></b><br />
In this article, I'll guide you how to install it on Windows, publish it with your domain, secure it. I also introduce to you first steps to combined it with Kibana and Logstash, so you can create a ELK system which can analyze a huge log data near real time.<br />
<br />
Let's go!<br />
<b><u><br /></u></b>
<b><u>Install Java Runtime</u></b><br />
ElasticSearch requires Java runtime to run. To check if having Java on your Windows, let open <b><i>cmd</i></b> and key:<br />
<blockquote>
<i><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">java -version</span></i></blockquote>
<i></i><span style="font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace;"></span>If you have no Java or the version < 8.x, let go to <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">Oracle Java website</a> for downloading and installing the latest version or from 8.x.<br />
<br />
After installing, let create / update <b><i>JAVA_HOME</i></b> system environment variable, set it to the new folder installed Java runtime. For example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRe3S1YKdKjtOt4Yq-LZ2GvfJOr1udWHZSjTIHIAoysYFFe4RywqjHG6lU9npN0erof75HZZ36WymXm7Dvwq63Mo5xexGMkpGzkkRhzMUO3tvOjtCUyzp66GYJmorEo5HCp_-2FCGgua8v/s1600/ElasticSearch_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="585" data-original-width="618" height="377" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRe3S1YKdKjtOt4Yq-LZ2GvfJOr1udWHZSjTIHIAoysYFFe4RywqjHG6lU9npN0erof75HZZ36WymXm7Dvwq63Mo5xexGMkpGzkkRhzMUO3tvOjtCUyzp66GYJmorEo5HCp_-2FCGgua8v/s400/ElasticSearch_1.png" width="400" /></a></div>
<br />
<b><u>Install & Configure ElasticSearch</u></b><br />
Go to <a href="https://www.elastic.co/downloads/elasticsearch">https://www.elastic.co/downloads/elasticsearch</a> and download the zip file. Unpack into a folder, e.g. <b><i>C:\ES</i></b><br />
<br />
By default ElasticSearch is configured with a 1 GB heap. For real enviroment, this number is not enough. To set new heap size, you must create a system environment variable <b><i>ES_HEAP_SIZE</i></b> and set its value, e.g. 4g. This value depends on the memory size (RAM) of your server, <i><span style="color: red;">it should be less than half of RAM</span></i> (<a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html">reference</a>).<br />
<i><b><br /></b></i>
After setting new heap size, open <b><i>C:\ES\config\elasticsearch.yml</i></b>, set values for important parameters as the following:<br />
<blockquote>
<span style="color: #274e13; font-family: "courier new" , "courier" , monospace; font-size: x-small;"># Path to directory where to store the data (separate multiple locations by comma).</span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">path.data: F:\data</span><br />
<span style="color: #274e13; font-family: "courier new" , "courier" , monospace; font-size: x-small;"># Path to log files.</span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">path.logs: F:\logs</span><br />
<span style="color: #274e13; font-family: "courier new" , "courier" , monospace; font-size: x-small;"># Lock the memory on startup.</span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">bootstrap.memory_lock: true</span><br />
<span style="color: #274e13; font-family: "courier new" , "courier" , monospace; font-size: x-small;"># Upper limit on the fielddata. Old data will be evicted to make space for the new values if it is over the limit size. Can be set to a percentage of the heap size, or a concrete value like 5gb.</span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">indices.fielddata.cache.size: 40%</span><br />
<span style="color: #274e13; font-family: "courier new" , "courier" , monospace; font-size: x-small;"># Set the bind address to a specific IP (IPv4 or IPv6).</span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">network.bind_host: ["192.168.2.12", "localhost"]</span><span style="color: #274e13; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /># For ReadonlyREST</span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">rest.action.multi.allow_explicit_index: false</span></blockquote>
Change the values of parameters upon your server. In which, parameter <span style="color: blue; font-family: "courier new"; font-size: x-small;">rest.action.multi.allow_explicit_index</span> is reserved for <b><i>ReadonlyREST</i></b> tool which will be used for securing queries.<br />
<br />
Start ElasticSearch by running <b><i>bin\elasticsearch.bat</i></b> file (e.g. <i><b>C:\ES\bin\elasticsearch.bat</b></i>). To set up ElasticSearch as a Windows service, run <b><i>bin\elasticsearch-service.bat install</i></b> then go to Windows services manager , find ElasticSearch service and change its <b><i>Startup Type</i></b> to <b><i>Automatic</i></b>.<br />
<b><i><u><sub><br /></sub></u></i></b>
After starting, let open a browser and check URL <b><i>http://localhost:9200/</i></b> to see if it is working.<br />
<br />
<u><b>Install Logstash</b></u><br />
Go to <a href="https://www.elastic.co/downloads/logstash">https://www.elastic.co/downloads/logstash</a> and download the zip file. Unpack into a folder, e.g. <b><i>C:\LS</i></b><br />
<br />
Create a simple config file (e.g. <b><i>logstash-simple.conf</i></b>) in <b><i>bin</i></b> folder (e.g. <b><i>C:\LS\bin</i></b>) with a content as the following example to run Logstash.<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">input { stdin { } }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">output {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> elasticsearch { hosts => ["localhost:9200"] }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> stdout { codec => rubydebug }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></blockquote>
Then open <b><i>cmd</i></b>, go to <b><i>bin</i></b> folder & key below command for starting Logstash:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">logstash.bat -f logstash-simple.conf</span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace;"></span><span style="font-size: x-small;"></span>To make a Windows service for Logstash, you can use <a href="http://nssm.cc/download">Non-Sucking Service Manager</a> (NSSM) tool. Download latest NSSM from its download page, unzip it into a folder, e.g. <b><i>F:\soft\nssm</i></b>. Use <b><i>cmd</i></b> go to <b><i>F:\soft\nssm\win64</i></b> and run the command:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">nssm.exe install Logstash</span></blockquote>
Then you may fill in values as below and click <b><i>Install service</i></b> button:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEy73ItrWOPmdjOfOMqmlrjQ60pOh_wBSDb__qJr8e0JDGU0HE7imuSEQCb1grIGv1nxlQ-8lh3Mz11QuSZqJyM79awmx6g_aQUXdozrvO2ugkLT5qeHLulvkqjjymufqgZBmNFInKmfhl/s1600/ElasticSearch_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="431" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEy73ItrWOPmdjOfOMqmlrjQ60pOh_wBSDb__qJr8e0JDGU0HE7imuSEQCb1grIGv1nxlQ-8lh3Mz11QuSZqJyM79awmx6g_aQUXdozrvO2ugkLT5qeHLulvkqjjymufqgZBmNFInKmfhl/s400/ElasticSearch_2.png" width="400" /></a></div>
<br />
After that, you can open Windows services manager to start Logstash service.<br />
<b></b><u></u><br />
<b><u>Install Kibana</u></b><br />
Go to <a href="https://www.elastic.co/downloads/kibana">Kibana download page</a>, download and unzip Kibana into a folder, e.g. <b><i>C:\KB</i></b><br />
Open <b><i>config/kibana.yml file</i></b> and configure some important parameters like:<br />
# The URL of the Elasticsearch instance to use for all your queries.<br />
elasticsearch.url: "http://localhost:9200"<br />
# Time in milliseconds to wait for responses from the back end or Elasticsearch. This value<br />
# must be a positive integer.<br />
elasticsearch.requestTimeout: 30000<br />
<br />
Run <b><i>bin\kibana.bat</i></b> in the installation folder (e.g. <b><i>C:\KB\bin\kibana.bat</i></b>) to start Kibana. Check <b><i>http://localhost:5601</i></b> to see if Kibana works.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlg6eRxCWa0iSjyT4loy8AWaPHnYLZQofdo56N4xNXlI-oC5gCmzAcMmpLhyphenhypheneOd3Dn2WLX21KiSHD1RAepcrblCbX8Iv4ksSlVTXRQcYNuswRKSSY7Q8WCpViG0elcJYzSQyXwLAQrYuxA/s1600/ElasticSearch_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="487" data-original-width="943" height="329" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlg6eRxCWa0iSjyT4loy8AWaPHnYLZQofdo56N4xNXlI-oC5gCmzAcMmpLhyphenhypheneOd3Dn2WLX21KiSHD1RAepcrblCbX8Iv4ksSlVTXRQcYNuswRKSSY7Q8WCpViG0elcJYzSQyXwLAQrYuxA/s640/ElasticSearch_3.png" width="640" /></a></div>
<br />
You can use NSSM to create a Windows service for Kibana. The above picture means no data has been shipped to Kibana yet. For shipping sample data into Kibana, you can try <a href="https://www.elastic.co/downloads/beats/winlogbeat">Winlogbeat</a> which sends Windows event logs such as application events, security events, system events, etc. to Logstash.<br />
<br />
<u><b>Setup nginx to access ElasticSearch via a domain</b></u><br />
With above configuration, you can only access ElasticSearch via localhost or IP 192.168.2.12. To access ElasticSearch via a domain, we can use nginx forward request to localhost (you can read <a href="https://vivavivugeek.blogspot.com/2017/10/setup-chat-bot-wrriten-by-ms-bot-builder-nodejs-with-nginx-https-windows-server.html">my article on this link for how to installing nginx</a>). Of course you can configure ElasticSearch directly on file <b><i>C:\ES\config\elasticsearch.yml</i></b> to allow to access it via a domain / public IP without using nginx, but I want to use nginx for allowing read only request to my ElasticSearch, for writing request I will setup for IP 192.168.2.12. This security will be done on <b><i>ReadonlyREST</i></b> tool in next step.<br />
<br />
Below the configuration for nginx:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">server {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> listen *:80;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> server_name yourdomain.com www.yourdomain.com;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> location / {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> root your_web_site_root_folder;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> index index.html index.htm;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> location /es {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> proxy_pass http://localhost:9200;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> proxy_http_version 1.1;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> proxy_set_header Upgrade $http_upgrade;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> proxy_set_header Connection 'upgrade';</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> proxy_set_header Host $host;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> proxy_cache_bypass $http_upgrade;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> rewrite ^/es/(.*) /$1 break;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }
</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></blockquote>
Now you can access ElasticSearch via yourdomain.com/es.<br />
<b><u><br /></u></b>
<b><u>Setup ReadonlyREST tool</u></b><br />
Go to <a href="https://readonlyrest.com/download.html">https://readonlyrest.com/download.html</a>, select your ElasticSearch version and download.<br />
Open <b><i>cmd</i></b>, <b><i>cd</i></b> to the ElasticSearch home and run the command:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">bin/elasticsearch-plugin install file:///download-folder/readonlyrest-<version>.zip</span></blockquote>
For example, download-folder is <b><i>C:\ES</i></b>. After that, let create <b><i>readonlyrest.yml</i></b> file in the config folder of ElasticSearch (e.g. <b><i>C:\ES\config/readonlyrest.yml</i></b>). Then add rules in this file. For example, I want to allow anything from 192.168.2.12 and other hosts can read only, I can add the following rules:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">readonlyrest:<br /> access_control_rules:</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> - name: "Rule 1 - Allowing anything from localhost"<br /> hosts: [192.168.2.12]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> - name: "Rule 2 - Other hosts can only read certain indices"<br /> actions: ["indices:data/read/*"]<br /> indices: ["logstash-*"] # aliases are taken in account!</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span></blockquote>
For more examples, you can <a href="https://github.com/sscarduzio/elasticsearch-readonlyrest-plugin">read here to add configuration snippets</a> into this file.<br />
<br />
Finally, your ELK is ready for using in real life. Let enjoy it :)<br />
<b><span style="color: blue;"><i>Any comment is welcome!</i></span></b><br />
<div>
See you next time.</div>
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com0tag:blogger.com,1999:blog-6453857454125943527.post-54790527427128049232017-10-28T00:02:00.005+07:002017-10-28T00:02:51.634+07:00Setup chat bot (wrriten by MS Bot Builder NodeJS) with Nginx + HTTPS on Windows ServerContinuing with my series of articles on chat bot:<br />
<ul>
<li><a href="https://vivavivugeek.blogspot.com/2017/05/create-luis-chat-bot-on-azure-bot-part-1.html">Create a Luis Chat Bot on Azure Bot Service - Part 1</a></li>
<li><a href="https://vivavivugeek.blogspot.com/2017/06/create-luis-chat-bot-on-azure-bot-part-2.html"><span id="goog_1843814771"></span>Create a Luis Chat Bot on Azure Bot Service - Part 2<span id="goog_1843814772"></span></a></li>
</ul>
In this article, I will cover a solution to set up an production environment for your chat bot written by MS Bot Builder NodeJS with <a href="http://nginx.org/">Nginx</a> & HTTPS on Windows Server. In which, you can register your chat bot hosted on any server (not on Azure) with <a href="http://botframework.com/">MS Bot Framework</a>.<br />
<br />
<u><b>1. Install Nginx</b></u><br />
<u><b><br /></b></u>
Download the latest version for Windows from: <b><i>http://nginx.org/en/download.html</i></b><br />
Unpack it on a folder (e.g. <b><i>C:\nginx</i></b> ) and click <b><i>nginx.exe</i></b> to run nginx. Open your browser, run <b><i>http://localhost/</i></b>. If you see a screen like below, it means Nginx is running well.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG1zFaBQqYaaP4gXz592VUhYzsZy2v9Rk_T5aRvRa_kVmSCMvGRxmrPI60ZZHjyqdhr6aBUrSvwohsLSK9rLBzk4HYgu7OkVdUkekeo7C9Fyyt_sSf0DbLsDyWkdbaY23fI9MyupVvFWKn/s1600/chatbot_nginx_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="261" data-original-width="847" height="122" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG1zFaBQqYaaP4gXz592VUhYzsZy2v9Rk_T5aRvRa_kVmSCMvGRxmrPI60ZZHjyqdhr6aBUrSvwohsLSK9rLBzk4HYgu7OkVdUkekeo7C9Fyyt_sSf0DbLsDyWkdbaY23fI9MyupVvFWKn/s400/chatbot_nginx_1.PNG" width="400" /></a></div>
<br />
<b><u>2. Run your chat bot</u></b><br />
<b></b><u></u><br />
Assuming that you've coded a wonderful chat bot, let run it. For example, I have a <i>super</i> chat bot by echoing what user says, it is in <b><i>app.js</i></b> file as the following:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">var restify = require('restify');<br />var builder = require('botbuilder');</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">// Create chat bot<br />var connector = new builder.ChatConnector({<br /> appId: '<i>app id of your bot on MS Bot Framework'</i>,<br /> appPassword: '<i>password of your bot on MS Bot Framework</i>'<br /> });</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">// Receive messages from the user and respond<br />var bot = new builder.UniversalBot(connector, function(session) {<br /> session.send("You said: %s", session.message.text);<br />});</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">// Setup Restify Server<br />var server = restify.createServer();<br />server.listen(process.env.port || process.env.PORT || 5678, function() {<br /> console.log('%s listening to %s', server.name, server.url);<br />});</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">// Listen for messages from users <br />server.post('/api/messages', connector.listen());</span><br />
<br /></blockquote>
Run <b><i>app.js</i></b>:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">node app.js</span></blockquote>
Note that appId and appPassword will be replaced by your real values when you register your bot on MS Bot Framework.<br />
<b><u><br /></u></b>
<b><u>3. Set up Nginx as proxy for your chat bot</u></b><br />
<b></b><u></u><br />
Assuming that you want to run your chat bot on the link: <b><i>yourdomain.com/bot</i></b>. Open <b><i>nginx.conf</i></b> file (e.g. <b><i>C:\nginx\conf\nginx.conf</i></b>) and add a server configuration for your domain:<br />
<blockquote class="tr_bq">
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">server {<br /> listen *:80;<br /> server_name yourdomain.com www.yourdomain.com;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> location / {<br /> root your_web_site_root_folder;<br /> index index.html index.htm;<br /> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> location /bot {<br /> proxy_pass http://localhost:5678/api/messages;<br /> proxy_http_version 1.1;<br /> proxy_set_header Upgrade $http_upgrade;<br /> proxy_set_header Connection 'upgrade';<br /> proxy_set_header Host $host;<br /> proxy_cache_bypass $http_upgrade;<br /> }<br />}</span></div>
</blockquote>
Now you can open the chat emulator for testing with the link <b><i>http://yourdomain.com/bot</i></b> to see if it works (see section 3 of <a href="https://vivavivugeek.blogspot.com/2017/05/create-luis-chat-bot-on-azure-bot-part-1.html">Create a Luis Chat Bot on Azure Bot Service - Part 1</a> for setting the emulator with <b><i>ngrok</i></b>):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw9pS5dMqJPheGTXjJw-3YSEvgJ3ANhZFqhkgmaM9i5yaIm_I6nc9RGOOHl6o309qHEvpvv-xzSX6DlTyLWhLE82h-mciOmrhghwdRZWyFYXFKuc7t5sSjmS_4dZ3uO6CqMA4bWGL-CaRG/s1600/chatbot_nginx_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="651" data-original-width="957" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw9pS5dMqJPheGTXjJw-3YSEvgJ3ANhZFqhkgmaM9i5yaIm_I6nc9RGOOHl6o309qHEvpvv-xzSX6DlTyLWhLE82h-mciOmrhghwdRZWyFYXFKuc7t5sSjmS_4dZ3uO6CqMA4bWGL-CaRG/s400/chatbot_nginx_2.PNG" width="400" /></a></div>
<b><u><br /></u></b>
<b><u>4. Set up HTTPS</u></b><br />
<b><u><br /></u></b>
MS Bot Framework just allows to register a bot with HTTPS end point message. So that's why we need to set up HTTPS. Luckily, we can setup HTTPS with free SSL Certificate from <a href="https://letsencrypt.org/">Let's Encrypt</a>. You can read my article <a href="https://vivavivugeek.blogspot.com/2017/09/wamp-64-bit-free-ssl-lets-encrypt.html">WAMP 64 Bits + Free SSL</a> (section 5) for how to create a free SSL certificate.<br />
<br />
Below is the configuration on nginx for a server with SSL:<br />
<blockquote class="tr_bq">
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">server {<br /> listen 443 ssl;<br /> server_name yourdomain.com www.yourdomain.com;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ssl_certificate C:/ProgramData/letsencrypt-win-simple/httpsacme-v01.api.letsencrypt.org/www.yourdomain.com-crt.pem;<br /> ssl_certificate_key C:/ProgramData/letsencrypt-win-simple/httpsacme-v01.api.letsencrypt.org/www.yourdomain.com-key.pem;<br /> ssl_trusted_certificate C:/ProgramData/letsencrypt-win-simple/httpsacme-v01.api.letsencrypt.org/ca-<hex number>-crt.pem;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ssl_session_cache shared:SSL:50m;<br /> ssl_session_timeout 1d;<br /> ssl_ciphers EECDH+AESGCM:EECDH+AES;<br /> ssl_prefer_server_ciphers on;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> location / {<br /> root your_web_site_root_folder;<br /> index index.html index.htm;<br /> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> location /bot {<br /> proxy_pass http://localhost:5678/api/messages;<br /> proxy_http_version 1.1;<br /> proxy_set_header Upgrade $http_upgrade;<br /> proxy_set_header Connection 'upgrade';<br /> proxy_set_header Host $host;<br /> proxy_cache_bypass $http_upgrade;<br /> }<br />}</span></div>
</blockquote>
Test again on the emulator with <b><i>https://yourdomain.com/bot</i></b><br />
<b><u><br /></u></b>
<b><u>5. Register your bot</u></b><br />
<b><u><br /></u></b>
Go to <b><i>https://dev.botframework.com</i></b>, sign in and click <b><i>My bots</i></b> menu for registering your bot. Remember to select <b><i>Register an existing bot built using Bot Builder SDK</i></b> when creating new bot.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHEkVUSOLi44HbfNoUn3isPZ3TpRkgIlZ0mIi36tSDDI8n-ZUIMBeUnvPOhptO3Txw4vjjd0Aa-vEG-wKwqNm0wslOSLk_ukrlnQfREvfdJS-DqyfnQqnQrPD9Xs6lewCQRoaYc7bX_qpH/s1600/chatbot_nginx_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="214" data-original-width="439" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHEkVUSOLi44HbfNoUn3isPZ3TpRkgIlZ0mIi36tSDDI8n-ZUIMBeUnvPOhptO3Txw4vjjd0Aa-vEG-wKwqNm0wslOSLk_ukrlnQfREvfdJS-DqyfnQqnQrPD9Xs6lewCQRoaYc7bX_qpH/s320/chatbot_nginx_4.PNG" width="320" /></a></div>
It will open a page for you keying your bot info. Note that <b><i>Messaging endpoint</i></b> is <b><i>https://yourdomain.com/bot</i></b>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiqK8kPeGD-Xm_587f0bM9ps5bEy_bynpvHddZpbKMRnk59hnydVOS-_UHekDvKcUFeydHNHQBZv-pHzQdkmmqIz246R0xt2Q5RYe0nreZQwgwZK-YVAs3uNqkosbL1Y6EnAVGsVVY67hs/s1600/chatbot_nginx_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="358" data-original-width="702" height="163" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiqK8kPeGD-Xm_587f0bM9ps5bEy_bynpvHddZpbKMRnk59hnydVOS-_UHekDvKcUFeydHNHQBZv-pHzQdkmmqIz246R0xt2Q5RYe0nreZQwgwZK-YVAs3uNqkosbL1Y6EnAVGsVVY67hs/s320/chatbot_nginx_3.PNG" width="320" /></a></div>
Click <b><i>Create Microsoft App ID and password</i></b> to create app id & password for your bot. Paste your app ID to the required box then copy the app id & password into the source code of your bot (e.g. <span style="font-family: courier new; font-size: x-small;">appId</span> & <span style="font-family: courier new; font-size: x-small;">appPassword</span> in section 2). Save the setting.<br />
<br />
Now you can click <b><i>Test</i></b> button on top right for testing your bot directly from the website <b><i>https://dev.botframework.com</i></b>. For example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd5S1_to_v4uOzOKuPxuEarg1zzq92N9qsC3qmVsERAqX5BQbezkOjvnE3ch8HLY2zHqZWhQTJKx-5ZJWBmAEhAJwf_Ld43QnbAVZ2naC1vj8gLPpSoEiuu0ckd3S312aNoEgx1tcv8-_c/s1600/chatbot_nginx_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="614" data-original-width="389" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd5S1_to_v4uOzOKuPxuEarg1zzq92N9qsC3qmVsERAqX5BQbezkOjvnE3ch8HLY2zHqZWhQTJKx-5ZJWBmAEhAJwf_Ld43QnbAVZ2naC1vj8gLPpSoEiuu0ckd3S312aNoEgx1tcv8-_c/s320/chatbot_nginx_5.PNG" width="202" /></a></div>
<br />
You can also connect your chat bot to other channel like Facebook (see <a href="https://vivavivugeek.blogspot.com/2017/06/create-luis-chat-bot-on-azure-bot-part-2.html"><span id="goog_1843814771"></span>Create a Luis Chat Bot on Azure Bot Service - Part 2<span id="goog_1843814772"></span></a> for how to connect with Facebook).<br />
<br />
Alright, you have known how to set up a production environment for your chat bot which can be hosted any where.<br />
<b><i><span style="color: blue;"><br /></span></i></b>
<b><i><span style="color: blue;">Have fun! Any comment is welcome.</span></i></b><br />
<b></b><i></i><span style="color: blue;"></span><br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com0tag:blogger.com,1999:blog-6453857454125943527.post-42487780847902200202017-10-15T19:12:00.001+07:002017-10-15T19:12:19.421+07:00MS SQL SMS export large data to Excel without breaking formatIf you often work on MS SQL, surely sometimes you want to export large data (result a query) to Excel file. After querying on MS SQL SMS (Microsoft SQL Server Management Studio), you can use right click on the cell top left then select "<b><i>Copy with Headers</i></b>" and copy to Excel file or "<b><i>Save Result As</i></b>" and save to a CSV file.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx_Npda_KdqnLbsptXg7Mpu_1_EAy2VEvI0NVrJFvQ1iavr0TxFf4Px6LYS4nf_Il8a4SC__CMtfQ3PAPQsMwQsslpGUWPzLRxQcIJgISiYY1R1JC46ulVsFF_TKZ-3UaicrR27Xnz5GQN/s1600/mssql_export_excel_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="161" data-original-width="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx_Npda_KdqnLbsptXg7Mpu_1_EAy2VEvI0NVrJFvQ1iavr0TxFf4Px6LYS4nf_Il8a4SC__CMtfQ3PAPQsMwQsslpGUWPzLRxQcIJgISiYY1R1JC46ulVsFF_TKZ-3UaicrR27Xnz5GQN/s1600/mssql_export_excel_1.PNG" /></a></div>
<br />
However 2 these functions have their problems. "<b><i>Copy with Headers</i></b>" cannot copy large data. "<b><i>Save Result As</i></b>" often breaks CSV format if your data contains some special characters.<br />
<br />
Fortunately, there is another function for exporting large data without breaking its format. Right click on your database and choose <b><i>Tasks >> Export Data...</i></b><br />
<b><i><br /></i></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAeySnkJWbtXtYPpMpe-UqQ61dAStBiV3SCmu-5cC3PkQZHkA451xAwuQZ3A-xlrWMJWh7ngBKPCpUoZ6Mtq-BN4T3NnkJbWSJ_hQBEzDYgSZ3s_zXm06u1UO9D0HFP9K9l7-4o1haaO6F/s1600/mssql_export_excel_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="507" data-original-width="549" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAeySnkJWbtXtYPpMpe-UqQ61dAStBiV3SCmu-5cC3PkQZHkA451xAwuQZ3A-xlrWMJWh7ngBKPCpUoZ6Mtq-BN4T3NnkJbWSJ_hQBEzDYgSZ3s_zXm06u1UO9D0HFP9K9l7-4o1haaO6F/s320/mssql_export_excel_2.PNG" width="320" /></a></div>
<br />
For <b><i>Data Source</i></b>, choose <b><i>SQL Server Native >> select Server name >> select your Database</i></b>, see the following for example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIHxjJjufi0EsO4-ZD2EOXREJrZjsajpXcLB6ze2ANofctu5JWWt3GhQi1ZnJysL7jJIEYsIu02k2EUsnbANhX4-OEHN0rHmz9NBuBh3Wiq8FCRMWs6NKVc3t4LbK_GB69pHWpGtKZoWkc/s1600/mssql_export_excel_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="568" data-original-width="558" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIHxjJjufi0EsO4-ZD2EOXREJrZjsajpXcLB6ze2ANofctu5JWWt3GhQi1ZnJysL7jJIEYsIu02k2EUsnbANhX4-OEHN0rHmz9NBuBh3Wiq8FCRMWs6NKVc3t4LbK_GB69pHWpGtKZoWkc/s320/mssql_export_excel_3.PNG" width="314" /></a></div>
<br />
Next, select <b><i>Destination</i></b> as <b><i>Microsoft Excel</i></b> & specify <b><i>Excel file path</i></b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEJqm53kEqSJIRUZzUpZEwFaK_Qax48EoaacEnWVgfxUriHvYUsyblXa4EUS56kTSe9Ma6eKLCO8FDqdT-kp84m8m4FknWrZDc8Y6iBGjH7AUyiHqMJtil92huuaqFrtzQeOhyphenhyphen7WMIUQUP/s1600/mssql_export_excel_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="568" data-original-width="558" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEJqm53kEqSJIRUZzUpZEwFaK_Qax48EoaacEnWVgfxUriHvYUsyblXa4EUS56kTSe9Ma6eKLCO8FDqdT-kp84m8m4FknWrZDc8Y6iBGjH7AUyiHqMJtil92huuaqFrtzQeOhyphenhyphen7WMIUQUP/s320/mssql_export_excel_4.PNG" width="314" /></a></div>
<br />
Next, select <b><i>Write a query to specify the data to transfer</i></b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ3Ge9GM8KqGjsHhX04GsVKPS2yaZylfUJwOYkSfbiwSPoo1KKvHVF2_26LDWiB2X4h2qJchyphenhyphensw422TuX8TCDdhgFkMgVRnFd6orT4-xfHlNHv8YCY2JjBGdszvqiUzNl1wQI6RIg-8YmK/s1600/mssql_export_excel_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="568" data-original-width="558" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ3Ge9GM8KqGjsHhX04GsVKPS2yaZylfUJwOYkSfbiwSPoo1KKvHVF2_26LDWiB2X4h2qJchyphenhyphensw422TuX8TCDdhgFkMgVRnFd6orT4-xfHlNHv8YCY2JjBGdszvqiUzNl1wQI6RIg-8YmK/s320/mssql_export_excel_5.PNG" width="314" /></a></div>
<br />
In next step, paste your query into or select a file containing your query. In the step <b><i>Review Data Type Mapping</i></b>, let review again columns have been converted data (<b><i>Source Type</i></b> vs. <b><i>Destination Type</i></b>). If you want to fix, click <b><i>Back</i></b> to select again <b><i>Destination Type </i></b>for converting.<br />
<br />
If they are ok, click <b><i>Next</i></b> then <b><i>Finish</i></b> (don't worry for warning signs). Waiting a moment and you will have your Excel file with correct format you wanted.<br />
<br />
Yeah! This is a small tip for you, hope it is useful. Share it to your friend for helping him or her out 😍. <b><i>Any comment is welcome!</i></b><br />
<br />
<i>Happy Halloween!</i>
Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com0tag:blogger.com,1999:blog-6453857454125943527.post-73851626524446428812017-09-29T23:51:00.000+07:002018-11-15T16:34:50.558+07:00Ionic 3: Debugging on VS Code and ChromeAfter long time, since from my first post <i><a href="https://vivavivugeek.blogspot.com/2015/12/quick-start-your-mobile-app-with-ionic.html">Quick start your mobile app with Ionic</a></i>, now I have a project using Ionic. So I want to share this post to my team for how to debugging on latest Ionic 3. Because saving debug time means you will delivery the application faster.<br />
<br />
As beginning, I want to brief important things for starting with latest Ionic 3:<br />
<ul>
<li>Follow <a href="https://ionicframework.com/docs/intro/installation/">the document on Ionic's website</a> to install <a href="https://nodejs.org/">Node JS</a> (version 6+), then install/update Ionic with command:</li>
</ul>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">npm install -g ionic cordova</span></blockquote>
<ul>
<li>Start an app with command (<b><i>cutePuppyPics</i></b> is your app name/project)</li>
</ul>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic start cutePuppyPics tutorial</span></blockquote>
<ul>
<li>Install <a href="https://code.visualstudio.com/">MS VS Code</a> and some good extensions for developing Ionic on VS Code, such as: <a href="https://marketplace.visualstudio.com/items?itemName=loiane.ionic-extension-pack">Ionic Extension Pack</a>, <a href="https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome">Debugger for Chrome</a>.</li>
</ul>
OK, you are ready to code! But wait, let setup to debug for your app on Chrome firstly. Open your app on VS Code and do the following steps:<br />
<br />
<b>1.</b> Press <b><i>F5</i></b> >> select <b><i>Chrome</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY4AdOlOuwJGsAG0vxY6LX5q7EN19VABKu6iIZAMBCYl-eAraA5Vm9y1e4oYMn1RgsQM5fjSdSSzuNsVPbKYCNc6ksfaLrSa75iBXopCwvsSOzSGd-UNDzBylCDIPYsmD5wn_pf9Bjl-KX/s1600/ionic_3_debug_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="171" data-original-width="612" height="111" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY4AdOlOuwJGsAG0vxY6LX5q7EN19VABKu6iIZAMBCYl-eAraA5Vm9y1e4oYMn1RgsQM5fjSdSSzuNsVPbKYCNc6ksfaLrSa75iBXopCwvsSOzSGd-UNDzBylCDIPYsmD5wn_pf9Bjl-KX/s400/ionic_3_debug_1.PNG" width="400" /></a></div>
<br />
<b>2.</b> Edit file <b><i>launch.json</i></b> generated with content like below:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "version": "0.2.0",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "configurations": [</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "type": "chrome",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "request": "launch",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "name": "Launch Ionic on Chrome",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "url": "http://localhost:8100",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "sourceMaps": true,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "webRoot": "${workspaceRoot}/src"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> },</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "type": "chrome",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "request": "attach",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "name": "Attach Ionic on Chrome",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "url": "http://localhost:8100",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "port": 9222,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "sourceMaps": true,<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> "webRoot": "${workspaceRoot}/src"</span></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></blockquote>
For Ionic 4, let use <span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">${workspaceFolder}</span> instead of <span style="-webkit-text-stroke-width: 0px; background-color: transparent; color: black; display: inline !important; float: none; font-family: "courier new" , "courier" , monospace; font-size: 13.33px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">${workspaceRoot}/src</span>.<br />
<br />
<b>3</b><b>.</b> If you use Windows, let open <b><i>Properties</i></b> of Chrome's short cut, and add <b><i>--remote-debugging-port=9222</i></b> in to <b><i>Target</i></b> box:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwzy2XQz77YL_VDQVXhlhOv7SsVSV0ZOzeAyj8swre9L-X9WwE3wUFQ_gzysqoBUkSWG1dgYFUL0R5RvLWCU9mTYQZY29J83NpnumLGtyIayVfS2iPmDJ5BWerxVaBbMIJ34ZcKR4axGxN/s1600/ionic_3_debug_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="548" data-original-width="363" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwzy2XQz77YL_VDQVXhlhOv7SsVSV0ZOzeAyj8swre9L-X9WwE3wUFQ_gzysqoBUkSWG1dgYFUL0R5RvLWCU9mTYQZY29J83NpnumLGtyIayVfS2iPmDJ5BWerxVaBbMIJ34ZcKR4axGxN/s400/ionic_3_debug_2.PNG" width="263" /></a></div>
<br />
For Mac, let use same debug flag as Windows. This debug flag is used for attaching your Ionic app into existing Chrome running.<br />
<br />
<b>4</b><b>.</b> Press <b><i>Ctrl+`</i></b> to open VS Code terminal, key:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ionic serve -b</span></blockquote>
It will build the app and start the server (http://localhost:8100/) but don't launch browser (<b><i>-b</i></b> option).<br />
<br />
<b>5</b><b>.</b> Close all Chrome opened, click debugger icon >> select <b><i>Launch Ionic on Chrome</i></b> option >> open a file, for example <b><i>cutePuppyPics\src\pages\list\list.ts</i></b>, set break point and press <b><i>F5</i></b>. It will launch the app on Chrome and display a debug player on the top of VS Code. In this example, when you click <b><i>My First List</i></b> menu and hit an item, it will jump to the break point for debugging, see the following picture:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSy1p6rFKJZv0eoTWx8D5-7WgQMbHl3gJErmnOlrYerp0wiAke_hLqoJFpcH7VpE3_5yFfhEN-mePbyrhRWG37xLpssYAQiPUjPSDtcFfoKNj7SFLEiDdkhw1XFYhTpkNv6-T5QQ5aIBrU/s1600/ionic_3_debug_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="481" data-original-width="1311" height="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSy1p6rFKJZv0eoTWx8D5-7WgQMbHl3gJErmnOlrYerp0wiAke_hLqoJFpcH7VpE3_5yFfhEN-mePbyrhRWG37xLpssYAQiPUjPSDtcFfoKNj7SFLEiDdkhw1XFYhTpkNv6-T5QQ5aIBrU/s640/ionic_3_debug_3.PNG" width="640" /></a></div>
<br />
You can stop the debug by pressing <b><i>Shift+F5</i></b> or stop button<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9T1kHynuWLuYKiHFo0oRJWShx57S4rSoG5Mr_kOXpWwcRyaZfJtiQk7SSY2GojqlcS3vBrkXRkpngeW6y98iLDj1-X6-i4RJ-GDuD5CvpkzZe-N5baH2JLclzr4K_Y10zqoIXapfXlYU7/s1600/ionic_3_debug_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="18" data-original-width="23" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9T1kHynuWLuYKiHFo0oRJWShx57S4rSoG5Mr_kOXpWwcRyaZfJtiQk7SSY2GojqlcS3vBrkXRkpngeW6y98iLDj1-X6-i4RJ-GDuD5CvpkzZe-N5baH2JLclzr4K_Y10zqoIXapfXlYU7/s1600/ionic_3_debug_4.PNG" /></a>on debug player. Stopping the debugger doesn't stop the app, it is still running until you press <b><i>Ctrl+C</i></b> in terminal.<br />
<br />
<b>6.</b> In case you want to debug dynamically, you can attach the debugger into the app is running on Chrome. To try, let open Chrome and key http://localhost:8100 to running the app. Then go to VS Code >> click debugger icon >> select Attach Ionic on Chrome option >> click run (or press F5). It will open a debug player like below, and when you click an item in <b><i>My First List</i></b> page, it will jump to the break point.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3M6SehR1JchSBDZWvHUry9YIXAsI1bv-c5ZSO7BCyR3QTM-EsRahxzq4c8tRit8WLindwewrG8n9m8yLPsPCe2PjaGBL19g12QOxdGOQUyG63vTVEsDeyYcu6BTvX276gCzhkvKp2gaIU/s1600/ionic_3_debug_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="482" data-original-width="1339" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3M6SehR1JchSBDZWvHUry9YIXAsI1bv-c5ZSO7BCyR3QTM-EsRahxzq4c8tRit8WLindwewrG8n9m8yLPsPCe2PjaGBL19g12QOxdGOQUyG63vTVEsDeyYcu6BTvX276gCzhkvKp2gaIU/s640/ionic_3_debug_5.PNG" width="640" /></a></div>
<br />
<b>7.</b> You can change source code and see this change updated to running app on Chrome. That's great point of Ionic which can help to speed up developing your application. I love it due to this live update feature.<br />
<br />
Happy coding! Any comment is welcome.<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com2tag:blogger.com,1999:blog-6453857454125943527.post-89886349295431088552017-09-16T20:45:00.000+07:002017-09-16T21:14:29.945+07:00WAMP 64 Bits + Free SSL (Let's Encrypt)<a href="http://www.wampserver.com/en/">WAMP</a> likes <a href="https://www.apachefriends.org/index.html">XAMPP</a>, they are free tools packaged Apache, MySQL / Maria DB & PHP together. XAMP also has other services / applications such as FileZilla, Mercury & Tomcat and it also can run on Linux & OS-X. While WAMP just runs on Windows. However for Windows' users, I recommend WAMP because it is designed for Windows only, so it has some advanced features for Windows but XAMPP doesn't have, especially it has Windows 64 bits version while XAMPP has only 32 bits version for Windows.<br />
<br />
<b>1. Install</b><br />
<b><br /></b>
To install Wamp 64 bits, you can download it from <a href="http://wampserver.aviatechno.net/">wampserver.aviatechno.net</a>. You should install it as <b><i>Administrator</i></b>. You also must install <a href="http://wampserver.aviatechno.net/files/vcpackages/all_vc_redist_x86_x64.zip">all Visual C++ redistributable packages (x86 + x64) (32bits + 64bits)</a> for running Wamp 64.<br />
<br />
After installing & running, if its system tray icon is green, it's ok. Let choose versions for Apache, PHP & MySQL which you want for your websites.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH5ZcioF0Rw9Ox8gh5gJUXYOAQ9Bn5VRy_hUVHOhJVgkMxbPnh7PFaxeNyISgsBQkW5o8GBdc6xKOsqkQDnPmwQvQyq_zIWnDDyojPayb6kIS6N3yVGAB6cK3cZ8NtciO8XL0pqWPnqC6i/s1600/wamp_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="354" data-original-width="441" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH5ZcioF0Rw9Ox8gh5gJUXYOAQ9Bn5VRy_hUVHOhJVgkMxbPnh7PFaxeNyISgsBQkW5o8GBdc6xKOsqkQDnPmwQvQyq_zIWnDDyojPayb6kIS6N3yVGAB6cK3cZ8NtciO8XL0pqWPnqC6i/s320/wamp_1.PNG" width="320" /></a></div>
<div>
<br /></div>
<div>
<b>2. Configure auto start up</b></div>
<div>
<b><br /></b></div>
<div>
For live server, you need to configure Apache & MySQL auto start up when the server restarts.</div>
<div>
Go to Windows Services, find wampapache64 & wampmysqld64 services then set them <b><i>Automatic</i></b> startup.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZILWIlNyTYil6Ce-Gpgf1WzjVwvveJIoPyvex21hJPPFb-mBUJv8O3RPrd2A0bb-mNFp5Kk5Db1ibJu3esMrp8QRFAE_T6Ov5PEbjRd-lZ2G2a0B0PZPtCznUL3mAF_L7JwaJ4m7Ns60q/s1600/wamp_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="546" data-original-width="877" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZILWIlNyTYil6Ce-Gpgf1WzjVwvveJIoPyvex21hJPPFb-mBUJv8O3RPrd2A0bb-mNFp5Kk5Db1ibJu3esMrp8QRFAE_T6Ov5PEbjRd-lZ2G2a0B0PZPtCznUL3mAF_L7JwaJ4m7Ns60q/s640/wamp_2.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
Next, right click on Wamp tray icon, select <b><i>Wamp Settings</i></b> menu >> select <b><i>Wampserver Homepage at startup</i></b>.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1mOTdXU6rcKNDB6lGsHTAE_ZzpENkGXSr2bS1P1P7-dxXdaKXpYHKbCDrouGcyz2KzRDFNpSumNzMJ1y4vQ2HsU2qAObc_Em2fCzUOsh-VmCVtIjkCWeRH6hScDL4ty_U_YUCh0giF-5T/s1600/wamp_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="363" data-original-width="453" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1mOTdXU6rcKNDB6lGsHTAE_ZzpENkGXSr2bS1P1P7-dxXdaKXpYHKbCDrouGcyz2KzRDFNpSumNzMJ1y4vQ2HsU2qAObc_Em2fCzUOsh-VmCVtIjkCWeRH6hScDL4ty_U_YUCh0giF-5T/s320/wamp_3.PNG" width="320" /></a></div>
<div>
<b><br /></b></div>
<div>
<b>3. Enable SSL (HTTPS)</b></div>
<div>
<b><br /></b></div>
<div>
The latest Wamp 64 has already included Open SSL built-in, so you don't need to install Open SSL. Below are steps to enable it for Apache:<br />
<br /></div>
<ul>
<li>Open <b><i>httpd.conf</i></b> file, uncomment the following lines:</li>
</ul>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">LoadModule ssl_module modules/mod_ssl.so<br />Include conf/extra/httpd-ssl.conf<br />LoadModule socache_shmcb_module modules/mod_socache_shmcb.so</span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></blockquote>
</div>
<ul>
<li>Open <b><i>php.ini</i></b> file, uncomment the following line:</li>
</ul>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">extension=php_openssl.dll</span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span></div>
<div>
<br /></div>
<div>
<b>4. Add virtual host for your website</b></div>
<div>
<br /></div>
<div>
Open <b><i>httpd-vhosts.conf</i></b> file and add a virtual host running on HTTP (port 80) for your website, below is an example:</div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><VirtualHost *:80></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ServerName mydomain.com</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ServerAlias www.mydomain.com</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> DocumentRoot "c:/mywebsites/www.mydomain.com"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <Directory "c:/mywebsites/www.mydomain.com/"></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Options Indexes FollowSymLinks </span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AllowOverride all</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Order Deny,Allow</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Allow from all</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Require all granted</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </Directory></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ErrorLog "logs/mydomain.com-error.log"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> CustomLog "logs/mydomain.com-access.log" common</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Alias /.well-known c:/mywebsites/www.mydomain.com/.well-known</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></VirtualHost></span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span></div>
<div>
In which, <b><i>.wellknow</i></b> folder will be used to store a key to challenge with <b><i>Let's Encrypt</i></b> server for creating your free SSL certificate in next step.</div>
<div>
<br /></div>
<div>
To check if you made right syntax, open <b><i>cmd</i></b> tool, go to <b><i>Apache</i></b> bin folder and run:</div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">httpd –t</span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span></div>
<div>
If the syntax is correct, let restart <b><i>Apache</i></b> service, then check your website on a browser. You can read my article "<i><a href="https://vivavivugeek.blogspot.com/2012/01/creating-multiple-virtual-sites-on-wamp.html">Creating Multiple Virtual Sites on a WAMP Server</a></i>" for more info on creating virtual hosts.</div>
<div>
<i></i><b></b><b></b><b></b><br /></div>
<div>
<b>5</b><b>. Create free SSL certificate with Let's Encrypt</b></div>
<div>
<b><br /></b></div>
<div>
You can read my article <i><a href="https://vivavivugeek.blogspot.com/2016/03/free-ssl-certificate-with-lets-encrypt.html">Free SSL Certificate with Let's Encrypt</a></i> to know about Let's Encrypt and tools to create free SSL certificate. In this post, I will show you how to do this with <b><i><a href="https://github.com/Lone-Coder/letsencrypt-win-simple">letsencrypt-win-simple</a></i></b> tool.</div>
<div>
<br /></div>
<div>
Download latest <b><i>letsencrypt-win-simple</i></b> tool from <a href="https://github.com/Lone-Coder/letsencrypt-win-simple/releases">its release page</a>. Unpack it into a folder, for example: <b><i>C:\letsencrypt-win-simple</i></b>. Open <b><i>cmd</i></b> tool as <b><i>Administrator</i></b>, cd to this folder and run <b><i>letsencrypt.exe</i></b>, its interface will show as below:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfRN6p4hKsU1knTWwPhdcmm1oS_jbBunG4NH6KE78Ili-4nNaSWaB0f7ypE9NbS8sWsUJb05U11GUVAhBaeTAJiwMSdDQ_0eogNX7Bp6cAXSmqQm_fQPokpJR2UyWlQDZygeIGtljxk-YJ/s1600/wamp_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="979" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfRN6p4hKsU1knTWwPhdcmm1oS_jbBunG4NH6KE78Ili-4nNaSWaB0f7ypE9NbS8sWsUJb05U11GUVAhBaeTAJiwMSdDQ_0eogNX7Bp6cAXSmqQm_fQPokpJR2UyWlQDZygeIGtljxk-YJ/s640/wamp_4.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
Key N then key 4, it will ask you enter host names (domain names) as the following screen:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbkEfuLO0Sc7cDKIkDtL-s-VdQazO6jkHm404UmsBZbUxxyY602Ckgn_DUJjHm0WF1L9hieo2q5HC-wArjni5EkepXqebJW_Q-K9_WK3WCp3OptwWTS-rJJnIiZTFYn3HzDlbamE25exo7/s1600/wamp_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="979" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbkEfuLO0Sc7cDKIkDtL-s-VdQazO6jkHm404UmsBZbUxxyY602Ckgn_DUJjHm0WF1L9hieo2q5HC-wArjni5EkepXqebJW_Q-K9_WK3WCp3OptwWTS-rJJnIiZTFYn3HzDlbamE25exo7/s640/wamp_5.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
Let key your domain name, for example: <b><i>www.mydomain.com</i></b>, then it will require you enter the root folder containing your website, for example: <b><i>c:\mywebsites\www.mydomain.com</i></b>. After that, the tool will do a process to create a key in the folder <b><i>c:\mywebsites\www.mydomain.com\.well-known\acme-challenge</i></b>, then challenge with <b><i>letsencrypt.org</i></b> to authorize and create certificates. These certificates are in the folder: <b><i>C:\ProgramData\letsencrypt-win-simple\httpsacme-v01.api.letsencrypt.org</i></b>. We will use them to create virtual host running on port 443 (HTTPS).</div>
<div>
<br /></div>
<div>
On finishing, the tool will ask you to create a scheduled task running on 9 am every day to renew your certificate automatically when it is used 60 days (30 days before expiry), see the following picture. With this scheduled task, you can sleep well :)</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAYsOl_XJyWebAbei5AlQ0TdfOlwhrI3CEMpImxzHShMNrfjB0_bDSsImZqCJTBHp5LDWRA9KIhib9OO6gP7ADBxqVhQG0AiaS3S3BmAAYHMJtFYVXm_OFs6AGnHaCpCFG-eNHN3cFQTHS/s1600/wamp_6.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="474" data-original-width="636" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAYsOl_XJyWebAbei5AlQ0TdfOlwhrI3CEMpImxzHShMNrfjB0_bDSsImZqCJTBHp5LDWRA9KIhib9OO6gP7ADBxqVhQG0AiaS3S3BmAAYHMJtFYVXm_OFs6AGnHaCpCFG-eNHN3cFQTHS/s400/wamp_6.PNG" width="400" /></a></div>
<div>
<br /></div>
<div>
<b>6</b><b>. Add virtual host HTTPS for your website</b></div>
<div>
<b><br /></b></div>
<div>
Now you are ready to up & run your HTTPS website, let create a virtual host running on port 443 with SSL certificates for it, see the following example:</div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><VirtualHost *:443></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ServerName mydomain.com</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ServerAlias www.mydomain.com</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> DocumentRoot "c:/mywebsites/www.mydomain.com"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <Directory "c:/mywebsites/www.mydomain.com/"></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Options Indexes FollowSymLinks </span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AllowOverride all</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Order Deny,Allow</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Allow from all</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Require all granted</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </Directory></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ErrorLog "logs/mydomain.com-error.log"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> CustomLog "logs/mydomain.com-access.log" common</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> SSLEngine on</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> SSLCertificateFile "C:/ProgramData/letsencrypt-win-simple/httpsacme-v01.api.letsencrypt.org/www.mydomain.com-crt.pem"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> SSLCertificateKeyFile "C:/ProgramData/letsencrypt-win-simple/httpsacme-v01.api.letsencrypt.org/www.mydomain.com-key.pem"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> SSLCertificateChainFile "C:/ProgramData/letsencrypt-win-simple/httpsacme-v01.api.letsencrypt.org/ca-<hex code>-crt.pem"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></VirtualHost></span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span></div>
<div>
Restart Apache service then check <b><i>https://www.mydomain.com</i></b> on a browser (for example Chrome). If it has the symbol <span style="color: lime;">https</span> with green, it's ok. Congratulation!</div>
<div>
<br /></div>
<div>
<b>7. Make some securities for Wamp </b></div>
<div>
<b></b><b></b><u></u><i><br /></i></div>
<div>
Remember to restart Wamp's services after configuration 😃<br />
<br /></div>
<div>
<u><i>7.1 Hide server info to prevent bad guys mining it</i></u></div>
<div>
<u></u><i></i><br /></div>
<div>
Open <b><i>httpd-default.conf</i></b> file, find & change parameters the following:</div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ServerSignature Off</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">ServerTokens Prod</span></blockquote>
<u><i>7.2 Make sure directories / files outside of the document root (website) are not allowed to access</i></u></div>
<div>
<u></u><i></i><br /></div>
<div>
Open <b><i>httpd.conf</i></b> file, check if the content of directory tag is like the following:</div>
<div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><Directory /></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Order Deny,Allow</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Deny from all</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Options None</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AllowOverride None</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></Directory></span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span>or</div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><Directory /></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AllowOverride none</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Require all denied</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></Directory></span></blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span>
<br />
<div>
<u><i>7.3 Reduce time out to prevent DoS attacks</i></u><br />
<u><i><br /></i></u>
Open <b><i>httpd-default.conf</i></b> file, find & set the following parameter:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">TimeOut 60</span></blockquote>
</div>
<div>
You can set it less than, for example 30.</div>
<div>
<u><i><br /></i></u></div>
<div>
<u><i>7.4 Set password for MySQL</i></u><u><i></i></u></div>
<ul>
<li>Left click Wamp's system tray icon.</li>
<li>Select <b><i>MySQL > MySQL console</i></b> menu.</li>
<li>Press <b><i>Enter</i></b> on the console opened.</li>
<li>Key <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">SET PASSWORD FOR root@localhost=PASSWORD('your_password');</span> (change your_password to your private password). They press <b><i>Enter</i></b>.</li>
</ul>
<div>
<u><i>7.5 Change permissions for folders in your website</i></u></div>
<div>
<u><i><br /></i></u></div>
<div>
Normally, I prefer to set all folders in my website to allow <b><i>Read & Execute</i></b> permission only except some folders having <b><i>Write</i></b> permission. To check what user runs Apache, let open <b><i>Windows Task Manager</i></b> and click <b><i>Details</i></b> tab, and see in <b><i>User name</i></b> column:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD8hMMaYNnKs9eqG_9Dhx409ZOCXdgjbIQ5j1D-TzNT0wgYTAwWf7X7AiDP4uXMG8oa-6FX2_-5cZ0CJoT9ClENDU5sYNxRK23AemMI8gwXsJAGpva6Ur0Hg34yhSOHOe6fCCU5zk21yTX/s1600/wamp_7.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="593" data-original-width="666" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD8hMMaYNnKs9eqG_9Dhx409ZOCXdgjbIQ5j1D-TzNT0wgYTAwWf7X7AiDP4uXMG8oa-6FX2_-5cZ0CJoT9ClENDU5sYNxRK23AemMI8gwXsJAGpva6Ur0Hg34yhSOHOe6fCCU5zk21yTX/s400/wamp_7.PNG" width="400" /></a></div>
<div>
<br /></div>
<div>
It often is <b><i>SYSTEM</i></b> user. To remove <b><i>Write</i></b> permission, right click on your web root folder >> select <b><i>Properties</i></b> menu >> click <b><i>Security</i></b> tab >> click <b><i>Edit</i></b> button >> select <b><i>SYSTEM</i></b> user >> on <b><i>Write</i></b> permission row, untick on <b><i>Allow</i></b> column, tick <b><i>Deny</i></b> column:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD8BJ6xO2-yKkJwrzgexppLuSy7z1geWnszbTNkOiZGo9onj1TzJsj8ZakvnnHgAbTi-hLUYZnLYx_4JkqQv5jUfmEEuKtoOuJTpQ1IYjcDBCUOkC8pnOb5dqsY-nwsABmzetfqdYylxC9/s1600/wamp_8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="450" data-original-width="363" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD8BJ6xO2-yKkJwrzgexppLuSy7z1geWnszbTNkOiZGo9onj1TzJsj8ZakvnnHgAbTi-hLUYZnLYx_4JkqQv5jUfmEEuKtoOuJTpQ1IYjcDBCUOkC8pnOb5dqsY-nwsABmzetfqdYylxC9/s320/wamp_8.PNG" width="258" /></a></div>
<br /></div>
<div>
If you cannot edit on <b><i>Allow</i></b> column, back to your web root folder >> select <b><i>Properties</i></b> menu >> click <b><i>Security</i></b> tab >> click <b><i>Advanced</i></b> button >> click <b><i>Disable inheritance</i></b> button on <b><i>SYSTEM</i></b> user having <b><i>Full control</i></b> access inheriting from parent folder. Then you can edit in above step.</div>
<div>
<br /></div>
<div>
For folders which you need to write (upload), just enable <b><i>Write</i></b> permission for <b><i>SYSTEM</i></b> user on those folders.</div>
<div>
<br /></div>
<div>
<b><span style="color: blue;">That's all for tonight. Bye and see you next post. Any comment is welcome!</span></b></div>
<div>
<b><span style="color: blue;">Good night!</span></b></div>
<b></b><span style="color: blue;"></span><br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com2tag:blogger.com,1999:blog-6453857454125943527.post-1167542004737795572017-08-17T17:30:00.001+07:002017-08-17T17:30:28.931+07:00Joomla 3: setup to allow registered user to create a post in frontendFroom Joomla 3.x, you can setup to allow registered user to create a post in frontend without installing any third party extension. Below are steps:<br />
<br />
<b>1.</b> Setup ACL (Access Control List) to allow Registered user to create article. Go to <b><i>System >> Global Configuration >> Articles >> Permission</i></b>, set <b><i>Action</i></b> of <b><i>Registered</i></b> to <b><i>Allowed</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoecPVfElUuSCCpsdbxGbs-_o-ekShtazf3Aol3ZapD54H111TsL1kZK-Av2LlViQbvjgbc7RVNjQN8b2_Z4nZVU078iuJuoP4LmoTtW1rc10STK_kjPBqLQnrMfVqV0N1ZwUJUurTCYDT/s1600/joomla_acl_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="559" data-original-width="1337" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoecPVfElUuSCCpsdbxGbs-_o-ekShtazf3Aol3ZapD54H111TsL1kZK-Av2LlViQbvjgbc7RVNjQN8b2_Z4nZVU078iuJuoP4LmoTtW1rc10STK_kjPBqLQnrMfVqV0N1ZwUJUurTCYDT/s640/joomla_acl_1.png" width="640" /></a></div>
<br />
<b>2.</b> Create a menu in frontend for user posting. Remember to select <b><i>Menu Item Type</i></b> as <b><i>Articles >> Create Article</i></b> and select <i><b>Access</b></i> right as <b><i>Registered</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZDURc_a3BVmjRZzJ2gChxQ_25mNwFoirKXGWExDeUIA0e3Ethp3uS8Zedp8MAdfHVMaX7gWGax7FBrdUlWEff2SjScl3QqLiAALtxctJOCuwgHRD4DqU7t8u53jakmfAdWnCDVbvnvD54/s1600/joomla_acl_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="644" data-original-width="1320" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZDURc_a3BVmjRZzJ2gChxQ_25mNwFoirKXGWExDeUIA0e3Ethp3uS8Zedp8MAdfHVMaX7gWGax7FBrdUlWEff2SjScl3QqLiAALtxctJOCuwgHRD4DqU7t8u53jakmfAdWnCDVbvnvD54/s640/joomla_acl_2.png" width="640" /></a></div>
<br />
Now your registered user can create a post, by logging in and clicking the menu (e.g. Create a Post):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg58g3kBoBZwDIXPW9DMC_JQkFywfdDxIl2Rcz7NJf06CaClalzFSKrl5YR1aUPlI_A-cFppOnFOdZ4ZPEvEgLEXZRxkjY9hIa6f4xILP5o4GZ_SNUFRTzExT9j7d88YaTNpJx58ZWh_15J/s1600/joomla_acl_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="697" data-original-width="797" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg58g3kBoBZwDIXPW9DMC_JQkFywfdDxIl2Rcz7NJf06CaClalzFSKrl5YR1aUPlI_A-cFppOnFOdZ4ZPEvEgLEXZRxkjY9hIa6f4xILP5o4GZ_SNUFRTzExT9j7d88YaTNpJx58ZWh_15J/s400/joomla_acl_3.png" width="400" /></a></div>
<br />
However, you should do more steps to customize <b><i>TinyMCE</i></b> editor as also as allow user posting HTML content (by default registered user can only post plain text).<br />
<br />
<b>3.</b> Enable registered user posting HTML content. Go to <b><i>System >> Global Configuration >> Text Filters</i></b>, set <b><i>Registered</i></b> group to <b><i>No Filtering</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMB2PSvE4V3C3ueCkVbxYNXLg2CARsLmurFIO8kYVb7snVsHRDrXAjnyFdpFpU2PD-HY23cUSASL1Dc1wUXYFFo8x_OKRG_kaq_sZq5h-YMlXFZELZ3tM6hIy8wxzX2UdKTnExJoOPvJVh/s1600/joomla_acl_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="548" data-original-width="812" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMB2PSvE4V3C3ueCkVbxYNXLg2CARsLmurFIO8kYVb7snVsHRDrXAjnyFdpFpU2PD-HY23cUSASL1Dc1wUXYFFo8x_OKRG_kaq_sZq5h-YMlXFZELZ3tM6hIy8wxzX2UdKTnExJoOPvJVh/s400/joomla_acl_4.png" width="400" /></a></div>
<b><br /></b>
<b>4.</b> Customize buttons of TinyMCE editor. Go to <b><i>Extensions >> Plugins</i></b>, search TinyMCE then click to configure it:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqbF3WHmf_cukR4ZhEqFxQmt-foZE6isn_lgn6pDMbRUczpthDogiNJ0_Y6e0DFl5xBAHaJL53tqZm3Uw2ApkrvEjloU2VZzkCN9xQHSM7Mt0cUw4AGsh9fhI58rv_sG5xXJOZx4qB4oMf/s1600/joomla_acl_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="269" data-original-width="699" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqbF3WHmf_cukR4ZhEqFxQmt-foZE6isn_lgn6pDMbRUczpthDogiNJ0_Y6e0DFl5xBAHaJL53tqZm3Uw2ApkrvEjloU2VZzkCN9xQHSM7Mt0cUw4AGsh9fhI58rv_sG5xXJOZx4qB4oMf/s400/joomla_acl_5.png" width="400" /></a></div>
Open Set 1, drag & drop buttons which you want to appear in the editor for registered user:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw_rvWpzXngkxu8bk_vzupOHJkYr19HjqHx97QR2tiiDgiP8XyffLqTi20HjPZiVwmfG6egl8RWPsVK72EAkIVTyoLiTPGu05Ld-sInrmPa1tk7RiYGO5OXOjT7KTs4HU5VAcuR877oo_B/s1600/joomla_acl_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="588" data-original-width="988" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw_rvWpzXngkxu8bk_vzupOHJkYr19HjqHx97QR2tiiDgiP8XyffLqTi20HjPZiVwmfG6egl8RWPsVK72EAkIVTyoLiTPGu05Ld-sInrmPa1tk7RiYGO5OXOjT7KTs4HU5VAcuR877oo_B/s400/joomla_acl_6.png" width="400" /></a></div>
<br />
To allow empty tags (e.g. <i><div class="my control class"></div></i>) in the input content, you can set a value <i>div[*]</i> for <b><i>Extended Valid Elements</i></b> field of the TinyMCE editor plugin.<br />
<br />
To disable / enable editor xtd buttons like <b><i>Article, Image</i></b> etc., you can search its plugin then configure them. For example, to disable button <b><i>Article</i></b> (last picture in step 2) for registered user, go to <b><i>Extensions >> Plugins</i></b>, search <i>article</i> then click to configure its <b><i>Access</i></b> to <b><i>Special</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2tttBbYBjRATOjQMqcgBgHwdO1BtxA4XeuS3iLslWARhBO9seVVgx4zzGQxyTNRoSUNAP0fxEhuo5RKlP6Uw4KQ0ZNjtGyiIIIAHLQP-9Ff0Zk7h7RXhNtFt-xh6SjBBd9PyOGIiHiFoO/s1600/joomla_acl_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="546" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2tttBbYBjRATOjQMqcgBgHwdO1BtxA4XeuS3iLslWARhBO9seVVgx4zzGQxyTNRoSUNAP0fxEhuo5RKlP6Uw4KQ0ZNjtGyiIIIAHLQP-9Ff0Zk7h7RXhNtFt-xh6SjBBd9PyOGIiHiFoO/s400/joomla_acl_7.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcyyc_1_aHmDjVSzmfu2NnChE71mNeLxiEyivx0yvkb9QkWJP6Z7asGa4U1smvFM0xNR-Ad73IdZOkUQokPZlv4IH5ZrGJZA0-i8h21D5h99LmuYgjOXRe0-gwRXFFnFutM3Xh6dh9zrLO/s1600/joomla_acl_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="303" data-original-width="1284" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcyyc_1_aHmDjVSzmfu2NnChE71mNeLxiEyivx0yvkb9QkWJP6Z7asGa4U1smvFM0xNR-Ad73IdZOkUQokPZlv4IH5ZrGJZA0-i8h21D5h99LmuYgjOXRe0-gwRXFFnFutM3Xh6dh9zrLO/s640/joomla_acl_8.png" width="640" /></a></div>
<b>5.</b> To receive a notification email when a user create new article, you can use <a href="https://gruz.ml/en/extensions/notificationary.html#general-information">NotificationAry</a> plugin. It is free, just install and enable it. Here is mine:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0b2teFalOWujwgnQvrM05cz-ERc4T4iwT_qL45SoWVgrxQfRKE-ISlI-Eh7ZgpCmuNVaVJfhdO-5oKnOpnFUTP1mVIt2wSDXwLCVtXvom3JIGMB2udIdEyH61bQGbOexKHWlWyLGUdFtF/s1600/joomla_acl_9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="1231" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0b2teFalOWujwgnQvrM05cz-ERc4T4iwT_qL45SoWVgrxQfRKE-ISlI-Eh7ZgpCmuNVaVJfhdO-5oKnOpnFUTP1mVIt2wSDXwLCVtXvom3JIGMB2udIdEyH61bQGbOexKHWlWyLGUdFtF/s640/joomla_acl_9.png" width="640" /></a></div>
<br />
Yeah! Now you can setup a blog with many users can create articles from frontend then you will get an email notification when having new article and able to approve (publish) it via the link inside the email.<br />
<br />
Have dream website! Any comment is welcome!<br />
<br />
<br />
<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com0tag:blogger.com,1999:blog-6453857454125943527.post-27569468003691666842017-08-03T17:47:00.001+07:002017-08-03T17:47:29.459+07:00Joomla 3.x: Create home page with different content for guests & registered usersWhen you develop a web application by Joomla 3.x, you may have a need to customize a page with different content for guests & registered users.<br />
<br />
For example, I will create a sample web site with different top menu and home page content for guests & registered users. Below are steps:<br />
<br />
<b>1.</b> Install & enable <b><i><a href="https://extensions.joomla.org/profile/extension/access-a-security/site-access/osd-content-restriction/">OSD Content restriction</a></i></b> plugin. This plugin will help to create content in articles based on user access group. So we will use it to load different content for user groups.<br />
<br />
<b>2.</b> Create an article for home page. In this article, we input content for guest and non-guest. The following sample will show "<i>This content is only visible to guest users, and NOT visible to registered/logged in users.</i>" for guest, and show "<i>This content is NOT visible to guest users. Only logged-in users will be able to see it."</i> plus the content of a customize HTML module for non-guest (logged user):<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2VTvMe_0aNtUOt3brRjbuaSmLE3B1VQoG-GTh4sZnOutXxKxntYM34VcX-SYt7k1p_Affpir56mKPLYi68uC69Ab5v1M0QsRAfSg4tjdaFlJ3i1xXg6qDV3PWuqG0dqzcK0XOV5RTkOhP/s1600/joomla_cus_0.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="472" data-original-width="1008" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2VTvMe_0aNtUOt3brRjbuaSmLE3B1VQoG-GTh4sZnOutXxKxntYM34VcX-SYt7k1p_Affpir56mKPLYi68uC69Ab5v1M0QsRAfSg4tjdaFlJ3i1xXg6qDV3PWuqG0dqzcK0XOV5RTkOhP/s640/joomla_cus_0.PNG" width="640" /></a></div>
<br />
<b>3.</b> Create a menu for guest, e.g. <b><i>Guest Menu</i></b>. Set up <b><i>Home</i></b> menu as <b><i>Single Article</i></b> pointing to the article in step 2.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz1fxNqu1pYytG0Aa6X_ia7Xi7Ss_UYNWMetigAbklNiuU6Q-VKOgohw8LlM7TyUWhr4ZL-J9BlACC-XoFepsGEib_lK_-lKVqt6m0bCz4PRX4aIsGF42Ps92TFjrlfq-L2kloRdVdbEyt/s1600/joomla_cus_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="284" data-original-width="1123" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz1fxNqu1pYytG0Aa6X_ia7Xi7Ss_UYNWMetigAbklNiuU6Q-VKOgohw8LlM7TyUWhr4ZL-J9BlACC-XoFepsGEib_lK_-lKVqt6m0bCz4PRX4aIsGF42Ps92TFjrlfq-L2kloRdVdbEyt/s640/joomla_cus_1.PNG" width="640" /></a></div>
<br />
<b>4.</b> Create a menu for non-guest, e.g. <b><i>Author Menu</i></b>, all its menu items are set to <b><i>Registered</i></b> or other group required logged. Here is a sample:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXinC0cmOyoKD59OjVVfyrqXBmLVz0QWU6pgvDUMkrplt0e0Tuh0H3n1MLRUKZS4Zl2B3Ejh4gGT1CuYYW0cdO9DL7m_pn15q3lM1fPXbinxHi9NSPr6NG4rMRdIvX3zlGcAmgRtBYXC6H/s1600/joomla_cus_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="536" data-original-width="977" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXinC0cmOyoKD59OjVVfyrqXBmLVz0QWU6pgvDUMkrplt0e0Tuh0H3n1MLRUKZS4Zl2B3Ejh4gGT1CuYYW0cdO9DL7m_pn15q3lM1fPXbinxHi9NSPr6NG4rMRdIvX3zlGcAmgRtBYXC6H/s640/joomla_cus_2.PNG" width="640" /></a></div>
<br />
<b>5.</b> Create modules for showing <b><i>Guest Menu</i></b> & <b><i>Author Menu</i></b>, put them in same position. Set <b><i>Access</i></b> of <b><i>Guest Menu</i></b> to <b><i>Guest</i></b>, <b><i>Author Menu</i></b> to <b><i>Public</i></b>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCs_s4vSOc2k_SsjSkOxH_jwTaXI6M0wQsrhgyonZ-ax23Vn-kOAf2KnNyWK92SwoaxnpD9XMMBLEC5PTaRPdkjeYoIInxozbzritt_p3O0V5iRqwm_IBYNH0jyKX9OMAXppP9FI6Z-T12/s1600/joomla_cus_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="547" data-original-width="1200" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCs_s4vSOc2k_SsjSkOxH_jwTaXI6M0wQsrhgyonZ-ax23Vn-kOAf2KnNyWK92SwoaxnpD9XMMBLEC5PTaRPdkjeYoIInxozbzritt_p3O0V5iRqwm_IBYNH0jyKX9OMAXppP9FI6Z-T12/s640/joomla_cus_3.PNG" width="640" /></a></div>
<br />
<br />
<b>6.</b> Done! Let see the home page for guest:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8TYwmmLUYTxiRSy3oplw_pleq4DAH44hF3bJ3kyECMOfo_KwzyID5K-aof8DOlEwZl7Im07S2r-mo-mPErGMyEGEiz-Y5kyM9ieuh2DS9hrepATeG49UWdG1GagQO5qVzGo12dmxSwh_D/s1600/joomla_cus_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="578" data-original-width="991" height="371" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8TYwmmLUYTxiRSy3oplw_pleq4DAH44hF3bJ3kyECMOfo_KwzyID5K-aof8DOlEwZl7Im07S2r-mo-mPErGMyEGEiz-Y5kyM9ieuh2DS9hrepATeG49UWdG1GagQO5qVzGo12dmxSwh_D/s640/joomla_cus_4.PNG" width="640" /></a></div>
<br />
<b>7.</b> Here is the home page for non-guest (logged user):<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJAkL8t3rXmlRP8Yx1dV4eF3KM3-drvvOUTOl3MGNWdfJlwkZyvwcDo9y99cT6v_36hfDrj3JkWR07QejQBn8WJ1HvNuEg5mjkQjtC8HaHHj5OyTfz4uSKj29DYRckZTUjGrjZ_fazvEqN/s1600/joomla_cus_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="668" data-original-width="990" height="430" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJAkL8t3rXmlRP8Yx1dV4eF3KM3-drvvOUTOl3MGNWdfJlwkZyvwcDo9y99cT6v_36hfDrj3JkWR07QejQBn8WJ1HvNuEg5mjkQjtC8HaHHj5OyTfz4uSKj29DYRckZTUjGrjZ_fazvEqN/s640/joomla_cus_5.PNG" width="640" /></a></div>
<br />
Yeah! Based on this, you can do what ever you want. Good luck.<br />
<b><i><br /></i></b>
<b><i>Any comment is welcome!</i></b>Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-52746348273825123722017-07-23T14:46:00.003+07:002017-07-23T14:46:40.010+07:00Playing with template in Joomla 3.xTemplate is the heart of Joomla. Almost of things which you need for your website, just do them in your template. In the template, you can override other extensions (components & modules) without touching to their source code. So you can easily update new versions of the extensions or Joomla without impacting to the front end of your website. This is very important because Joomla community often releases security fixes which you should update immediately for your website if any.<br />
<br />
In this article, I will collect & introduce to you some tips which you can play with Joomla's template to setup your website beautifully, quickly and security.<br />
<br />
<b>1. Uninstall unnecessary templates</b><br />
<br />
If you don't use a template, let remove it. Less code that means your website is more lightweight, faster and more security. Below the steps to install a template:<br />
<ul>
<li>Go to menu <b><i>Extensions >> Manage >> Manage</i></b></li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdvFc2Ae60PI7nAMyYCBAeeesMvtbQtevT67_NoQuaOJsjU9J9JRvZu3qQJpypHejVvbKhHa8MLPEBvQeUCOYHQei25VVXW05-EAP_k4zWzhKAmjNwmczPXFBVSg4AsVVTXVayTfGGPCcP/s1600/play_w_joomla.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="375" data-original-width="832" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdvFc2Ae60PI7nAMyYCBAeeesMvtbQtevT67_NoQuaOJsjU9J9JRvZu3qQJpypHejVvbKhHa8MLPEBvQeUCOYHQei25VVXW05-EAP_k4zWzhKAmjNwmczPXFBVSg4AsVVTXVayTfGGPCcP/s400/play_w_joomla.PNG" width="400" /></a></div>
<ul>
<li><div class="separator" style="clear: both; text-align: left;">
Click <b><i>Search Tools</i></b> button >> select type as <b><i>Template</i></b> >> click the check box of a template wanted to install >> click <b><i>Uninstall</i></b> button.</div>
</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCuAu8hkOqgsNm2tFloWuzbyvhg7Po1kNOx5rmXV6ZSQHT94XXA2au_6X5T5V0wqzliuqAOMx-AKei_GxDr2sfut0EbhHueC9W9ElShn7s9ohcWGnOP3PgMkU44cfpu1o4c9X5FqH3p4cA/s1600/play_w_joomla_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="374" data-original-width="1343" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCuAu8hkOqgsNm2tFloWuzbyvhg7Po1kNOx5rmXV6ZSQHT94XXA2au_6X5T5V0wqzliuqAOMx-AKei_GxDr2sfut0EbhHueC9W9ElShn7s9ohcWGnOP3PgMkU44cfpu1o4c9X5FqH3p4cA/s640/play_w_joomla_1.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This will remove permanently all source code of the template from your site.</div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
<b>2. Edit source code of a template, code your website on mobile devices</b></div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
Joomla 3.x provides an editor for editing source code of any template. It is very powerful. I think it is a strength of Joomla against the other CMS. With this editor, you can code your website when you are travelling on mobile devices like smart phone or tablet.</div>
<div class="separator" style="clear: both; text-align: left;">
To open the editor for your template, go to <b><i>Extensions >> Templates >> Templates</i></b> >> click on the template name:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe6GOPnNFdQhUUqyTeCB2kPKPKbc88xHG46LTX-uK04MCmq9_qu7FazbCm58ITMgNoyehZQas7gbFkwHvWNKePIWAQPcOG5J-5xxvTmTqnHPWKVLwdtLYv8wXEsELBHT030It6aO4NUaSx/s1600/play_w_joomla_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="380" data-original-width="856" height="177" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe6GOPnNFdQhUUqyTeCB2kPKPKbc88xHG46LTX-uK04MCmq9_qu7FazbCm58ITMgNoyehZQas7gbFkwHvWNKePIWAQPcOG5J-5xxvTmTqnHPWKVLwdtLYv8wXEsELBHT030It6aO4NUaSx/s400/play_w_joomla_2.PNG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
It will open a screen with files & folders of source code in left side. Here you can do many actions via buttons on the top. Click Documentation button if you want to learn more about this editor. To edit a file, click on its name:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbnMQqsfp660NyLil8INYF1ComtiSZcCRD8H76y4ZE6MIuNx6qIC8kYi-EO48f_W2GNXtbCux6CDOSUTCV8LDhJ1PmJCIzSBkBQ_F75hXf3l6MwCkpeijRZPR6fV7FHPwaJd0By0GUFKSO/s1600/play_w_joomla_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="628" data-original-width="659" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbnMQqsfp660NyLil8INYF1ComtiSZcCRD8H76y4ZE6MIuNx6qIC8kYi-EO48f_W2GNXtbCux6CDOSUTCV8LDhJ1PmJCIzSBkBQ_F75hXf3l6MwCkpeijRZPR6fV7FHPwaJd0By0GUFKSO/s320/play_w_joomla_3.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-Is3wBGlbtth9JeOMO1hYN6uQxTqVm6Dey4VvLO1njzmILlVTR7htW5Oda2ZAxVjlkVYzj_KVHdVztQjCcYcaszf3svykG8nXW5ZystmlAg6WI00YMr3GVN3cTJ6tB5dnBy6RjmXfWqRq/s1600/play_w_joomla_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="596" data-original-width="1331" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-Is3wBGlbtth9JeOMO1hYN6uQxTqVm6Dey4VvLO1njzmILlVTR7htW5Oda2ZAxVjlkVYzj_KVHdVztQjCcYcaszf3svykG8nXW5ZystmlAg6WI00YMr3GVN3cTJ6tB5dnBy6RjmXfWqRq/s320/play_w_joomla_4.PNG" width="320" /></a></div>
<div>
<br /></div>
<div>
Above are buttons I often use. The right side is source code of selected file. To change for editing the other file, just click on its name. Soo cool 👍</div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
<b>3. Compile LESS file</b></div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
Another weapon of Joomla is it supports to compile LESS file directly on the template editor. You don't need to install any extra tool. To know what is LESS, let read: <span id="goog_927416168"></span><a href="http://lesscss.org/">http://lesscss.org</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
<u><br /></u></div>
<div class="separator" style="clear: both; text-align: left;">
LESS files are often in <b><i>less</i></b> folder. If you open a LESS file on the editor, it will show Compile LESS button. After compiling, it will translate into a CSS file corresponding with LESS file in <b><i>css</i></b> folder. The template file uses CSS file to present its styles.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBnnen1pk21es0z3BLZtAQmYAEYovwXzCjm8Kl3g2CePTIlYtdZCTFbARMBHOtwmFwy8q4RpKSJnRvbcnRU8XSbR74MEwxCBDaPNodrFNggaS0k8Xtl5HWIL2c4JaV1rKlFt6piiszIZh6/s1600/play_w_joomla_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="568" data-original-width="1229" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBnnen1pk21es0z3BLZtAQmYAEYovwXzCjm8Kl3g2CePTIlYtdZCTFbARMBHOtwmFwy8q4RpKSJnRvbcnRU8XSbR74MEwxCBDaPNodrFNggaS0k8Xtl5HWIL2c4JaV1rKlFt6piiszIZh6/s640/play_w_joomla_5.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
<b>4. Create overrides for extensions</b></div>
<div class="separator" style="clear: both; text-align: left;">
<b><i><br /></i></b></div>
<div class="separator" style="clear: both; text-align: left;">
In manual way, you must copy the original PHP file from the source of extension into a proper place in your template directory. The correct directory structure for your override file is:</div>
<div class="snippet" style="-webkit-text-stroke-width: 0px; background: rgba(204, 196, 247, 0.3); border: 1px solid rgb(204, 204, 204); box-shadow: rgba(0, 0, 0, 0.4) 1px 1px 3px 0px; color: #555555; font-family: Arial, Helvetica, sans-serif; font-size: 14px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; line-height: 20.3px; margin: 4px 16px 12px; orphans: 2; padding: 8px 15px; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
templates/TEMPLATE_NAME/<span style="background-color: orange;">html</span>/EXTENSION_NAME/VIEW_NAME/FILE_NAME.php</div>
<div class="separator" style="clear: both; text-align: left;">
You can read here <a href="https://vivavivugeek.blogspot.com/2012/06/joomla-25-overwrite-category-blog.html">for an example</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
However in Joomla 3.x, you can also create overrides for extensions by clicking <b><i>Create Overrides</i></b> tab then click an extension (module, component, layout) which you want to override in the template manager.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAmhhvwadDIraFOyKwXZ7i8MY4IbNekBxY4W0pjAObY-zx2MhQuFPabSOqPphPVyYAqFN38xlQP4LvzdhDzSZFqEHiLKgRMNMjyN9x_E3XMuat1hAwgsf8U3twEuOBNh6UVaJscEKkBlnK/s1600/play_w_joomla_6.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="350" data-original-width="1017" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAmhhvwadDIraFOyKwXZ7i8MY4IbNekBxY4W0pjAObY-zx2MhQuFPabSOqPphPVyYAqFN38xlQP4LvzdhDzSZFqEHiLKgRMNMjyN9x_E3XMuat1hAwgsf8U3twEuOBNh6UVaJscEKkBlnK/s640/play_w_joomla_6.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<i></i><i></i><u></u><b>5. Customize Protostar template</b></div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
As a beginner of Joomla template coding, one of the fastest way is studying & customizing an existing template. What is good template for you starting? I recommend the Protostar template. It is one of the two front-end templates included with a Joomla 3.x source code. Protostar likes a blank responsive template, it is simple but displays well on many devices. So you can build your own template from this template with a basic knowledge about PHP, JavaScript & CSS.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In this section, I give an example on how to create a mobile menu which displays all submenus without touching on parent menu. By default, a submenu will be showed when hovering on parent menu. You can do this action on desktop with mouse, but cannot in a mobile with touching screen. It causes your submenu is never reached on the mobile.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
By adding below code into <b><i>template.less</i></b> file (in @media query for mobile screen) and re-compile it in the template editor, you will have a proper menu on mobile:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="prettyprint"><code class="language-css hljs "><span class="hljs-at_rule">@<span class="hljs-keyword">media</span> (max-width: <span class="hljs-number">480</span>px) </span>{
//<span class="hljs-tag">start changes</span>
<span class="hljs-class">.navigation</span> <span class="hljs-class">.nav-child</span> <span class="hljs-rules">{
<span class="hljs-rule"><span class="hljs-attribute">display</span>:<span class="hljs-value"> block</span></span>;
<span class="hljs-rule"><span class="hljs-attribute">position</span>:<span class="hljs-value"> unset</span></span>;
<span class="hljs-rule"><span class="hljs-attribute">float</span>:<span class="hljs-value"> unset</span></span>;
<span class="hljs-rule"><span class="hljs-attribute">border</span>:<span class="hljs-value"> unset</span></span>;
<span class="hljs-rule"><span class="hljs-attribute">box-shadow</span>:<span class="hljs-value"> unset</span></span>;
<span class="hljs-rule">&:<span class="hljs-attribute">before {
display</span>:<span class="hljs-value"> none</span></span>;
<span class="hljs-rule">}</span></span>
}
<span class="hljs-class">.navigation</span> <span class="hljs-class">.nav</span> > <span class="hljs-tag">li</span> > <span class="hljs-class">.nav-child</span> <span class="hljs-rules">{
<span class="hljs-rule">&:<span class="hljs-attribute">before {
display</span>:<span class="hljs-value"> none</span></span>;
<span class="hljs-rule">}</span></span>
}
//<span class="hljs-tag">end changes</span>
<span class="hljs-class">.item-info</span> > <span class="hljs-tag">span</span> <span class="hljs-rules">{
<span class="hljs-rule"><span class="hljs-attribute">display</span>:<span class="hljs-value">block</span></span>;
<span class="hljs-rule">}</span></span>
<span class="hljs-class">.blog-item</span> <span class="hljs-class">.pull-right</span><span class="hljs-class">.item-image</span> <span class="hljs-rules">{
<span class="hljs-rule"><span class="hljs-attribute">margin</span>:<span class="hljs-value"><span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">18</span>px <span class="hljs-number">0</span></span></span>;
<span class="hljs-rule">}</span></span>
<span class="hljs-class">.blog-item</span> <span class="hljs-class">.pull-left</span><span class="hljs-class">.item-image</span> <span class="hljs-rules">{
<span class="hljs-rule"><span class="hljs-attribute">margin</span>:<span class="hljs-value"><span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">18</span>px <span class="hljs-number">0</span></span></span>;
<span class="hljs-rule"><span class="hljs-attribute">float</span>:<span class="hljs-value">none</span></span>;
<span class="hljs-rule">}</span></span>
}</code></pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here are screens for desktop and mobile:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMQFD_vUmBH1DS5GgjZ6KRYR8jltblw5Hky0oZTw55qWSYCv4o36l8E_7VJn0ZPgOqwXna9wY_2p8i2O_JN7FdewJ6qrPaqupdNLtRFRN8Q3QQcugO6zDHUHnLPM3YPquyqHw8W2hLh6-k/s1600/play_w_joomla_7.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="177" data-original-width="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMQFD_vUmBH1DS5GgjZ6KRYR8jltblw5Hky0oZTw55qWSYCv4o36l8E_7VJn0ZPgOqwXna9wY_2p8i2O_JN7FdewJ6qrPaqupdNLtRFRN8Q3QQcugO6zDHUHnLPM3YPquyqHw8W2hLh6-k/s1600/play_w_joomla_7.PNG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-Rq_5yweRZ21tyANqyAoso5c0q8bDQezwlRRapk6NCTId8XrNvLcXmVKR6q1Db87ZSwgWwZJSMNoe5FoAoSP64DKjDpwiAerWgAdV78BspzoeaoAdJrJIA9LCDm-N6tBaE7rYUhwmdV_K/s1600/play_w_joomla_8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="309" data-original-width="356" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-Rq_5yweRZ21tyANqyAoso5c0q8bDQezwlRRapk6NCTId8XrNvLcXmVKR6q1Db87ZSwgWwZJSMNoe5FoAoSP64DKjDpwiAerWgAdV78BspzoeaoAdJrJIA9LCDm-N6tBaE7rYUhwmdV_K/s320/play_w_joomla_8.PNG" width="320" /></a></div>
<div>
<br /></div>
<div>
<b><span style="color: purple;">It's time to go to bed. Bye everyone! Any comment is welcome.</span></b></div>
<div class="separator" style="clear: both; text-align: left;">
<b></b><span style="color: purple;"></span><br /></div>
Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com0tag:blogger.com,1999:blog-6453857454125943527.post-85350182154159335832017-07-14T15:50:00.000+07:002017-07-14T15:50:29.307+07:00Learn Selenium (a Test Automation Tool) with C# - Part 2In this part, we will learn how to a test application to do login Facebook automatically.<br />
<br />
For beginning, I want to introduce about XPath. It is a major element in the XSLT standard. XPath can be used to navigate through elements and attributes in an XML document. You can read more about it <a href="https://www.w3schools.com/xml/xml_xpath.asp">on here</a>.<br />
<br />
In Selenium we will use XPath to find element(s) then make action according to the scenarios for testing.<br />
<br />
If you are familiar with FireFox, you can use <a href="https://addons.mozilla.org/en-US/firefox/addon/firebug/">Firebug</a> and <a href="https://addons.mozilla.org/en-US/firefox/addon/firepath/">FirePath</a> add-on. They are very popular and strong tools for FireFox web developer. You just need to install them, open a website which you want to test, open <b><i>Firebug</i></b> >> click <b><i>FirePath</i></b> tab >> click the pointer and select an element on the page for getting its XPath value. See the following picture for example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif-Q2KZba05RWMuPCUxg1ilzDjSYf_NO42gF97UaWGm16bC4YJxXso6sgTe2zy6bGtrRDtEjqovnRmqqFo7Hawe12pmMSlSuAj_JXyt7L3nwlKksFdgGK5zdIi-7On3Gc3CHYTMYnq-Ad1/s1600/selenium_2_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="768" data-original-width="1364" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif-Q2KZba05RWMuPCUxg1ilzDjSYf_NO42gF97UaWGm16bC4YJxXso6sgTe2zy6bGtrRDtEjqovnRmqqFo7Hawe12pmMSlSuAj_JXyt7L3nwlKksFdgGK5zdIi-7On3Gc3CHYTMYnq-Ad1/s640/selenium_2_1.PNG" width="640" /></a></div>
<br />
If your are familiar with Chrome, you can use <a href="https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl?hl=en">XPath-Helper extension</a>. But I recommend you use a built-in function of <b><i>Chrome DevTools</i></b>. Just open the website, press <b><i>F12</i></b> then press <b><i>Ctrl + F</i></b> to enable DOM searching box. Using pointer to point an element then key a XPath value in to searching box for finding matched elements. If the matching is only 1, it is the XPath for this element.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOmzWH9o7Vm2GhyphenhyphenKfjs_BZaeJXzuRlb8sdqrra6FY7R46yyPAuL_fVOk7aBbD5PszeQJKmPt-Mev7k14YdWK_raNvJ2zX2YhFkRt0UkAdNEcodhIZGdAv8LCT8g2p-kP_xOCnHkLYZezld/s1600/selenium_2_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="314" data-original-width="1041" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOmzWH9o7Vm2GhyphenhyphenKfjs_BZaeJXzuRlb8sdqrra6FY7R46yyPAuL_fVOk7aBbD5PszeQJKmPt-Mev7k14YdWK_raNvJ2zX2YhFkRt0UkAdNEcodhIZGdAv8LCT8g2p-kP_xOCnHkLYZezld/s640/selenium_2_2.PNG" width="640" /></a></div>
<br />
For searching, you can try the first search with syntax: .<b>//*[@attribute-name='value']</b><br />
For example a element having id="email", you can try: .//*[@id='email']<br />
<br />
Another way on Chrome is using Console panel of Chrome DevTools with the function <b><i>$x("XPath value")</i></b>. For example: <b><i>$x(".//*[@id='email']")</i></b><br />
<b><i><br /></i></b>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYVFLB3CR9v7ZvAnao1TrFFMHo39xOYDsjivOh0W03F99MGFLIWt4UtIMR0Nhd1xP0ioBrt3mPQgwZ86QzqyMbQKxfSrWN4FB3LkZAThugx2oZQObVsLujDAmugE8SGFwGEZIKs1-ChrKB/s1600/selenium_2_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="184" data-original-width="670" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYVFLB3CR9v7ZvAnao1TrFFMHo39xOYDsjivOh0W03F99MGFLIWt4UtIMR0Nhd1xP0ioBrt3mPQgwZ86QzqyMbQKxfSrWN4FB3LkZAThugx2oZQObVsLujDAmugE8SGFwGEZIKs1-ChrKB/s400/selenium_2_3.PNG" width="400" /></a></div>
OK, that's enough for XPath. It's time to code our test application. Yes, let see the code first and I will explain later:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: xx-small;">using OpenQA.Selenium;<br />using OpenQA.Selenium.Chrome;</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: xx-small;">namespace SeleniumTutorial<br />{<br /> class Program<br /> {<br /> static void Main(string[] args)<br /> {<br /> IWebDriver wd = new ChromeDriver(@"E:\working\abc\SeleniumTutorial");<br /> wd.Url = "https://www.facebook.com/";<br /> <span style="color: blue;">wd.Manage().Window.Maximize();<br /> wd.FindElement(By.XPath(@".//*[@id='email']")).SendKeys("your_email@domain.com");<br /> wd.FindElement(By.XPath(@".//*[@id='pass']")).SendKeys("your_password");<br /> wd.FindElement(By.XPath(@"//input[@value='Đăng nhập']")).Click();</span><br /> }<br /> }<br />}</span><br />
<span style="font-size: x-small;"></span><span style="font-family: "Courier New", Courier, monospace;"></span><span style="font-size: xx-small;"></span><br />
Comparing with <a href="https://vivavivugeek.blogspot.com/2017/07/learn-selenium-test-automation-with-csharp-part1.html">Part 1</a>, the blue codes are new. In which:<br />
<span style="color: blue; font-family: courier new; font-size: xx-small;">wd.Manage().Window.Maximize();</span> ==> to maximize the browser window<br />
<br />
Next 2 lines are for finding email box, password box and input (SendKeys) its values. The last line is for finding login button (it depends on the language used on the browser, mine is Vietnamese ). See below picture for more understanding:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5mxo2SGiCttRMguJY20Plg5EXNaLpWxM1aQp6mCLRRW_w77DJ4CoL9qc3yMQu__GGIm3NN87g2Q7zxVJvyPs8rg0seVZjheuc1tpOYVZ43jYSTZy8kjGUe5D5xV1z7yutXpjIyb1RhVeN/s1600/selenium_2_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="197" data-original-width="445" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5mxo2SGiCttRMguJY20Plg5EXNaLpWxM1aQp6mCLRRW_w77DJ4CoL9qc3yMQu__GGIm3NN87g2Q7zxVJvyPs8rg0seVZjheuc1tpOYVZ43jYSTZy8kjGUe5D5xV1z7yutXpjIyb1RhVeN/s400/selenium_2_4.PNG" width="400" /></a></div>
<br />
Why I don't use @id to find login button? Because I recognize that Facebook changes this id frequently. So I use its value instead of.<br />
<br />
Walking through <a href="https://vivavivugeek.blogspot.com/2017/07/learn-selenium-test-automation-with-csharp-part1.html">Part 1</a> & Part 2, I believe that you have enough basic knowledge to start your automation test application with Selenium. Let's practice.<br />
<span style="color: magenta;"></span><br />
<b><span style="color: magenta;">Happy coding! Any comment is welcome.</span></b><br />
<b><span style="color: magenta;"></span><br /></b>
<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com0tag:blogger.com,1999:blog-6453857454125943527.post-46246721748079211402017-07-06T17:00:00.002+07:002017-07-14T15:52:08.875+07:00Learn Selenium (a Test Automation Tool) with C# - Part 1<a href="http://www.seleniumhq.org/">Selenium</a> is a set of different software tools each with a different approach to supporting test automation. You can read more about Selenium via its website: http://www.seleniumhq.org/docs/01_introducing_selenium.jsp#introducing-selenium<br />
<br />
Selenium has 2 version 1.0 and 2.0. During this article, I just mention about Selenium 2.0. Basically, it is used for testing web application by automation program written by Java, C#, Python... To do that, the test application (created by a tester) will control the browser which the web application (need to be tested) runs on via Selenium webdriver. The browser can be Chrome, FireFox, Internet Explorer... Each browser has a corresponding webdriver to control it.<br />
<br />
In this post, I want to introduce Selenium with C#. To start, you must install <a href="https://www.visualstudio.com/downloads/">MS Visual Studio</a> - MSSV (2015 community is preferred) and download <a href="http://www.seleniumhq.org/download/">Selenium client & webdriver</a>. Below are steps to create<br />
<br />
<b>1.</b> Open MSVS and create new C# Windows project, see the following picture for example:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUS6-m4Y4DSJFEv4yaOGmQq3SD2sxCsq1-_TOfTC4K9Sn81D-bGmEyLLmpEiBrGo_O8ahF_uPmuUiQvAuqR4C_SehNMNhAC6vKv5Sc1uDekYpUuzCJaskLsljRv9MdTG9ub1xZgVry8nD9/s1600/selenium_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="579" data-original-width="936" height="393" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUS6-m4Y4DSJFEv4yaOGmQq3SD2sxCsq1-_TOfTC4K9Sn81D-bGmEyLLmpEiBrGo_O8ahF_uPmuUiQvAuqR4C_SehNMNhAC6vKv5Sc1uDekYpUuzCJaskLsljRv9MdTG9ub1xZgVry8nD9/s640/selenium_1.PNG" width="640" /></a></div>
<br />
<b>2.</b> Add references for Selenium client & webdriver. There are 2 ways.<br />
<u>2.1 Use <b><i>Add Reference</i></b> menu:</u><br />
<u><br /></u>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxY8yGFhByJOs9NkkqmhtD2upfMa2UvOzr3SofuP9Cvng56vwaHHhCf-6gInO1w5uZo_s6cXXmG3CHJV3B8gFiubL7X9E_SS5fVATfTjutyscpGYZ0J32qHtWCaLuMU4PiJj9Sr4HVoImd/s1600/selenium_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="316" data-original-width="364" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxY8yGFhByJOs9NkkqmhtD2upfMa2UvOzr3SofuP9Cvng56vwaHHhCf-6gInO1w5uZo_s6cXXmG3CHJV3B8gFiubL7X9E_SS5fVATfTjutyscpGYZ0J32qHtWCaLuMU4PiJj9Sr4HVoImd/s320/selenium_2.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN5Oo7o8Z37COQr2_G4T1HMO8gxH-a6_xMZWOOZ0PvGvg6dOY1KS7GTSK3eBB2EOrywQHzWeDsEJEcYx7Vyv5ag5fEsHwSc-GdzcjckyFrl70Hm2t1Q565V06l_OxV_-2gCSewnGPrie2F/s1600/selenium_3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="542" data-original-width="786" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN5Oo7o8Z37COQr2_G4T1HMO8gxH-a6_xMZWOOZ0PvGvg6dOY1KS7GTSK3eBB2EOrywQHzWeDsEJEcYx7Vyv5ag5fEsHwSc-GdzcjckyFrl70Hm2t1Q565V06l_OxV_-2gCSewnGPrie2F/s400/selenium_3.PNG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaieOETBuDTg0DSP7VpcJ2tfoDFDFEfbH4hZejx8UqYGuZUtAdXatvo_gtoG2rS_eBzF_Y3C2HZz6GmfQGdQKr1EfdVjoNHCJVgdlZCLPezJNs9Wo6h5OyQbPWRXVteGOADmbEtHCRq6f0/s1600/selenium_4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="403" data-original-width="322" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaieOETBuDTg0DSP7VpcJ2tfoDFDFEfbH4hZejx8UqYGuZUtAdXatvo_gtoG2rS_eBzF_Y3C2HZz6GmfQGdQKr1EfdVjoNHCJVgdlZCLPezJNs9Wo6h5OyQbPWRXVteGOADmbEtHCRq6f0/s320/selenium_4.PNG" width="255" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<u>2.2 Use <b><i>Manage NuGet Packages</i></b> menu:</u><br />
<u><br /></u>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNDrFXrg67Ti3mZ2BqyT7NQpH5OKmq4y8MzPHIKG7-YOZuz-NKmqV6mCv1xBonP-Sz-LkXA3Lf8nTK6yQKVFM-1Y_p3NhJvOULnRTKE6PH8XZU_jyOheR-gnAEni168tgXvRr64MRCK4kO/s1600/selenium_5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="316" data-original-width="322" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNDrFXrg67Ti3mZ2BqyT7NQpH5OKmq4y8MzPHIKG7-YOZuz-NKmqV6mCv1xBonP-Sz-LkXA3Lf8nTK6yQKVFM-1Y_p3NhJvOULnRTKE6PH8XZU_jyOheR-gnAEni168tgXvRr64MRCK4kO/s320/selenium_5.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeibE69Bqgp1Gqoyynr-baPEba1kk2oPcZMc4lXCgz61r4DB_cNgiyjlTUYxepaebaBYHtElLg0m3lre2uzrzicAA8TxQJfqegzaMZpr02pxmP65fhwE_56xZOY_8SGU6iMdu1u44OA2tE/s1600/selenium_6.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="492" data-original-width="958" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeibE69Bqgp1Gqoyynr-baPEba1kk2oPcZMc4lXCgz61r4DB_cNgiyjlTUYxepaebaBYHtElLg0m3lre2uzrzicAA8TxQJfqegzaMZpr02pxmP65fhwE_56xZOY_8SGU6iMdu1u44OA2tE/s640/selenium_6.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
I prefer <i>2.1</i> way. If you use Chrome Webdriver, you need to download the latest version from: <a href="http://chromedriver.storage.googleapis.com/index.html">http://chromedriver.storage.googleapis.com/index.html</a> and unpack it into your project folder. Now you can create a simple test application.<br />
<br />
<b>3.</b> Code your test application. Below is simple code for opening Chrome with google.com website<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">using OpenQA.Selenium;<br />using OpenQA.Selenium.Chrome;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">namespace SeleniumTutorial<br />{<br /> class Program<br /> {<br /> static void Main(string[] args)<br /> {<br /> IWebDriver wd = new ChromeDriver(@"E:\working\abc\SeleniumTutorial");<br /> wd.Url = "http://google.com";<br /> }<br /> }<br />}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
In which, <b><i>@"E:\working\abc\SeleniumTutorial"</i></b> is the folder containing Chrome Webdriver (chromedriver.exe).<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2dVhkrt9EkPFA9RvWxaBwtnCoGid2gAFtP0OIrZWdAcEzvvi2OxG4SGpQBHpSvdpbpmFVNCpcs_USQsSTDHjVHoZIZr2znUytzwRApbROh0TqSyZvtsga4biYSJpNE4qkeD05Lgcb6F3M/s1600/selenium_7.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="498" data-original-width="771" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2dVhkrt9EkPFA9RvWxaBwtnCoGid2gAFtP0OIrZWdAcEzvvi2OxG4SGpQBHpSvdpbpmFVNCpcs_USQsSTDHjVHoZIZr2znUytzwRApbROh0TqSyZvtsga4biYSJpNE4qkeD05Lgcb6F3M/s320/selenium_7.PNG" width="320" /></a></div>
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
Yeah! We already knew how to start a C# project with Selenium. I think that's enough for Part 1. <a href="https://vivavivugeek.blogspot.com/2017/07/learn-selenium-test-automation-with-csharp-part2.html">In Part 2</a>, we will learn more details how to code a test application with some real test scenarios, for example how to login Facebook automatically.<br />
<br />
<b><span style="color: blue;">Any comment is welcome. Have a great day!</span></b><br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com1tag:blogger.com,1999:blog-6453857454125943527.post-39716867731829808862017-06-30T12:24:00.002+07:002017-06-30T12:26:22.538+07:00Prevent Petya/Petwrap/NotPetya Ransomware AttackThis week, new ransomware called Petrwrap (NotPetya) attacked Windows PC across the globe today. It locks hard drive MFT and MBR sections and preventing computers from booting. Unless victims opted to pay hacker $300 by BitCoin (which is not recommended), there was no way to recover their systems.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix4KyoJvFI0DrkFhYwdB4eb5lcJsd9865nhKnNdnR8JP0GZYRmWU-nOs5WJqrSMYXxt0ePYJTIfD2x6JMpsALs_gktTq7r8BupQe5IbHYiNRiW5cgxzfrqfmBLzmM8nmNd64AbVJt_L1sc/s1600/NotPetya_2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="267" data-original-width="480" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix4KyoJvFI0DrkFhYwdB4eb5lcJsd9865nhKnNdnR8JP0GZYRmWU-nOs5WJqrSMYXxt0ePYJTIfD2x6JMpsALs_gktTq7r8BupQe5IbHYiNRiW5cgxzfrqfmBLzmM8nmNd64AbVJt_L1sc/s320/NotPetya_2.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyI6T9PMEcgZ5gOfvT4YbzE37iUdGpU2DRf5ohjS6SQCwmp1aWF7KqULqDJhYBu5ynW_Ovts5JXzxxqcqjMxllO_2lZ1cy9pLe6DY-v1mPkBXYSvLJO-1zcrlc5Yg_pRNdIhYROheGPpek/s1600/NotPetya_1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="768" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyI6T9PMEcgZ5gOfvT4YbzE37iUdGpU2DRf5ohjS6SQCwmp1aWF7KqULqDJhYBu5ynW_Ovts5JXzxxqcqjMxllO_2lZ1cy9pLe6DY-v1mPkBXYSvLJO-1zcrlc5Yg_pRNdIhYROheGPpek/s320/NotPetya_1.jpg" width="320" /></a></div>
<br />
Unfortunately Amit Serper (a security expert) has found a way to prevent the Petya(NotPetya/SortaPetya/Petna) ransomware from infecting computers. The solution is create <b><i>C:\Windows\perfc</i></b> file and make it read only. This batch file can help you for quickly: <a href="https://github.com/vnheros/utilscripts/blob/master/nopetyavac.bat">https://github.com/vnheros/utilscripts/blob/master/nopetyavac.bat</a>. It also creates <b><i>perfc.dat</i></b> and <b><i>perfc.dll</i></b> for more secure. Let run it with Administrator right:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE9kakpM8IbyCdoHe7RWnwV_9bzuXouQYB3owkDnakwo_Ib82grDu3KxOIZWd9jHSZplybbArRde5jIHFbJ710aHgwfOp-xJeb-2o1HsoLq3rWKgt5bIPPHEEXKwouEf4e_PmttYjOPrkR/s1600/NotPetya_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="328" data-original-width="502" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE9kakpM8IbyCdoHe7RWnwV_9bzuXouQYB3owkDnakwo_Ib82grDu3KxOIZWd9jHSZplybbArRde5jIHFbJ710aHgwfOp-xJeb-2o1HsoLq3rWKgt5bIPPHEEXKwouEf4e_PmttYjOPrkR/s320/NotPetya_3.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzlUY8-FxaEJT0wKSDXTLlZQAnYivtE-fJ9hyphenhyphenc0MY7uNqyyZbEA9Vcr-1btJbghRfXw0pMy13KEFJ6S7WqNsebFbdjAKzvMhZTAGrAmGvpeAF36VRBUyBwvbU5kW27_lF3FB_XPN7ZtnmE/s1600/NotPetya_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="280" data-original-width="500" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzlUY8-FxaEJT0wKSDXTLlZQAnYivtE-fJ9hyphenhyphenc0MY7uNqyyZbEA9Vcr-1btJbghRfXw0pMy13KEFJ6S7WqNsebFbdjAKzvMhZTAGrAmGvpeAF36VRBUyBwvbU5kW27_lF3FB_XPN7ZtnmE/s320/NotPetya_4.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc9vx07x9Fj_ujnulDOhj_NU2HOv_8nMmqIFv6GSVFrDiSfgXEwUx3f9OUMkurzU9JMTwuAITttpfRZzemqE0BlICqHvsBPDwNLm_3DfEzbPKzZVedY48EkyhreOxKVGOGN3stAPqZKpRH/s1600/NotPetya_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="227" data-original-width="743" height="97" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc9vx07x9Fj_ujnulDOhj_NU2HOv_8nMmqIFv6GSVFrDiSfgXEwUx3f9OUMkurzU9JMTwuAITttpfRZzemqE0BlICqHvsBPDwNLm_3DfEzbPKzZVedY48EkyhreOxKVGOGN3stAPqZKpRH/s320/NotPetya_5.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
Here are emails which are used to send infected attached files (<i><span style="color: red;">don't open email when receiving from theses emails</span></i>):<br />
<ul>
<li><b>wowsmith123456@posteo.net</b></li>
<li><strong>iva76y3pr@outlook.com</strong></li>
<li><strong>carmellar4hegp@outlook.com</strong></li>
<li><strong>amanda44i8sq@outlook.com</strong><b></b></li>
</ul>
Another required actions are:<br />
<ul>
<li>Let update your Windows, especially patches for MS17-010, CVE 2017-0199.</li>
<li>Disable SMB port: 445/137/138/139</li>
<li>Remove WMIC (Windows Management Instrumentation Command-line) tool</li>
</ul>
<b><i>Hope you are safe after this attack storm!</i></b>Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com2tag:blogger.com,1999:blog-6453857454125943527.post-76384647429962117122017-06-22T20:58:00.001+07:002017-06-22T21:15:07.973+07:00Create a Luis Chat Bot on Azure Bot Service - Part 2In <a href="https://vivavivugeek.blogspot.com/2017/05/create-luis-chat-bot-on-azure-bot-part-1.html">Part 1</a>, you already knew how to create an Azure Chat Bot and deploy it from a local repository. In this article, I'll show you how to apply a Luis app into the bot and how to integrate it with Facebook Messenger.<br />
<br />
<b>1.</b> Go to <a href="https://www.luis.ai/">luis.ai</a> website and create an app.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2XUNKlVbDjRmBZWBLALzA0dtYIug24uKpli2k5z6k75py1QOfT-9ur1AxthDNbGRQZCUDpJMn1T3S-if5urm5lYHVfqzeBUUOEDRMpXrJItrl2o70Jl4lu9CMel5fO1M6i49VBTjjTWVg/s1600/luis_app_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="402" data-original-width="1260" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2XUNKlVbDjRmBZWBLALzA0dtYIug24uKpli2k5z6k75py1QOfT-9ur1AxthDNbGRQZCUDpJMn1T3S-if5urm5lYHVfqzeBUUOEDRMpXrJItrl2o70Jl4lu9CMel5fO1M6i49VBTjjTWVg/s640/luis_app_1.png" width="640" /></a></div>
This Luis app will be used for a Pizza shop, so we create 3 intents: <b><i>greeting</i></b>, <b><i>pizza</i></b> and <b><i>noservice</i></b>. We also create an simple entity named <b><i>topping</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuuA3CYjba2YzFV5SA9SioR5NxesEfIxTrY0ayxQgWTXdIqYkNIMr4-q6BzFjkS-ZWdwgO64XBb8iptSXsMnSGfnpmbVSXU0C8cVnmcFLrl4YFR6aZdNzRb1VKLWLEAqSCVLVWf_7tHTZf/s1600/luis_app_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="606" data-original-width="1245" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuuA3CYjba2YzFV5SA9SioR5NxesEfIxTrY0ayxQgWTXdIqYkNIMr4-q6BzFjkS-ZWdwgO64XBb8iptSXsMnSGfnpmbVSXU0C8cVnmcFLrl4YFR6aZdNzRb1VKLWLEAqSCVLVWf_7tHTZf/s640/luis_app_2.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLbJqAPZZpaXCc9y_1KJj7tlAbEGnAB5L-tjKIywYb5Osk6XG_HSO_vr-XTR6D2Ho2-WZornI3TNOAexH8Y367sDSIosFynSvPvIxsOgkFxG19Zcv_P3G1rl2NDjXONNfMG56FwQoWxp16/s1600/luis_app_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="604" data-original-width="1233" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLbJqAPZZpaXCc9y_1KJj7tlAbEGnAB5L-tjKIywYb5Osk6XG_HSO_vr-XTR6D2Ho2-WZornI3TNOAexH8Y367sDSIosFynSvPvIxsOgkFxG19Zcv_P3G1rl2NDjXONNfMG56FwQoWxp16/s640/luis_app_3.png" width="640" /></a></div>
<br />
And below are utterances for intents:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivp0dA9PFrGcQqrjGRRY4SEh4DwUQSekJs25n6Ii9vG0D3FCirCwF-d3rFPdpBssuiPpGCVp7t9-vSumtVoBwjygVm6GDdEi2lf6fV6ei8r7K_d-A9ozJD74xSXLegqAGvn2z_yIimNHNJ/s1600/luis_app_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="586" data-original-width="924" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivp0dA9PFrGcQqrjGRRY4SEh4DwUQSekJs25n6Ii9vG0D3FCirCwF-d3rFPdpBssuiPpGCVp7t9-vSumtVoBwjygVm6GDdEi2lf6fV6ei8r7K_d-A9ozJD74xSXLegqAGvn2z_yIimNHNJ/s400/luis_app_4.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRJDSeXGpSTarjnkm50NUlDfKj3gJuKMk_a8l344FzbPufIM02AGwfmgfFeSNHdDRgg7uDvbXSS7X8jX7IOpvij7GyxYq_sHlfHFiJTQGX5oQbf_yWeXIjOr7pNYQ0HjUuIVjlwb7_hVE4/s1600/luis_app_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="417" data-original-width="918" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRJDSeXGpSTarjnkm50NUlDfKj3gJuKMk_a8l344FzbPufIM02AGwfmgfFeSNHdDRgg7uDvbXSS7X8jX7IOpvij7GyxYq_sHlfHFiJTQGX5oQbf_yWeXIjOr7pNYQ0HjUuIVjlwb7_hVE4/s400/luis_app_5.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibJ6FTcvowrDP7b9I7jrpbBMytmnaK2pkkb_eWgi1d4F72zlLw9ZZmEqRtMlQu-S9JMP-MGvmZWShgDo4z0cm_54SLanexSXa3J6CGVykBfOWEmc7JLH9oFcWAytAzQONYXhCGgV4utKiL/s1600/luis_app_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="476" data-original-width="916" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibJ6FTcvowrDP7b9I7jrpbBMytmnaK2pkkb_eWgi1d4F72zlLw9ZZmEqRtMlQu-S9JMP-MGvmZWShgDo4z0cm_54SLanexSXa3J6CGVykBfOWEmc7JLH9oFcWAytAzQONYXhCGgV4utKiL/s400/luis_app_6.png" width="400" /></a></div>
Here are another samples of utterances for <b><i>pizza</i></b> intent (you should map label topping every time inputting):<br />
<i>can i have pizza with pineapple and bacon</i><br />
<i>i would like a pizza with cheese bacon and pineapple</i><br />
<i>may i have pizza with pineapple and sausage</i><br />
<i>can i get tomato with cheese on my pizza</i><br />
<i>my pizza should have goat cheese and mozzarella on it</i><br />
<br />
You can add more utterances. After inputting data, click Train & Test link and click Train Application button. Then keying sentences into Interactive Testing box:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW9Z5IYhyy82vAaD8bo7VQkmDbdViOLozTCQZtmR6rcjUNbyBFRBJQfhk3FDvKdA_G4Se0622OEcFPRa-MneLunjaoWa_3vII_2IeC4z2fSx_ha624tYf7UJOmxo74bZ-SQXUHUJGorZTU/s1600/luis_app_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="543" data-original-width="1207" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW9Z5IYhyy82vAaD8bo7VQkmDbdViOLozTCQZtmR6rcjUNbyBFRBJQfhk3FDvKdA_G4Se0622OEcFPRa-MneLunjaoWa_3vII_2IeC4z2fSx_ha624tYf7UJOmxo74bZ-SQXUHUJGorZTU/s640/luis_app_7.png" width="640" /></a></div>
<br />
If the training & test are ok, let publish the app:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-zhA7fuPmIrP2xJcF4Rai58qGdfqd_J6GYNzsk6XSlvaksU__pRrHOg13EeEBAp66YqNbLIOIYbMk28ECIVBJ1N1bDraAa3DQEhIgpCwwYaZjMToCRhSLfhNt560eAgr8QdzMTT2Ox8k3/s1600/luis_app_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="1216" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-zhA7fuPmIrP2xJcF4Rai58qGdfqd_J6GYNzsk6XSlvaksU__pRrHOg13EeEBAp66YqNbLIOIYbMk28ECIVBJ1N1bDraAa3DQEhIgpCwwYaZjMToCRhSLfhNt560eAgr8QdzMTT2Ox8k3/s640/luis_app_8.png" width="640" /></a></div>
<br />
<br />
<b>2.</b> Congratulation! You already had first Luis app, let link it with your bot service on Azure. Open the bot on Azure, click on <b><i>SETTINGS</i></b> tab and select the Luis app then click <b><i>Save changes</i></b> button:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxrNL2Ib5-IYLUPeRJDYvUklLST_1Q3Z8h0VqFIDUKF3EVxjA00aYafov_uylWz1FJqBS6Btd37PLoXT9yIBMPannH9kLI4Mz9sCnIFB8wClpwlRde_ks-MX6ifdBNbmywxeQc4xyeFqQ4/s1600/luis_app_9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="472" data-original-width="900" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxrNL2Ib5-IYLUPeRJDYvUklLST_1Q3Z8h0VqFIDUKF3EVxjA00aYafov_uylWz1FJqBS6Btd37PLoXT9yIBMPannH9kLI4Mz9sCnIFB8wClpwlRde_ks-MX6ifdBNbmywxeQc4xyeFqQ4/s640/luis_app_9.png" width="640" /></a></div>
Now, we will enhance the bot with power from the Luis app. Below is the code of the bot, it will recognize intents & entities from chat message to make corresponding response:<br />
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br />"use strict";<br />var builder = require("botbuilder");<br />var botbuilder_azure = require("botbuilder-azure");<br />var useEmulator = (process.env.NODE_ENV == 'development');<br />var connector = useEmulator ? new builder.ChatConnector() : new botbuilder_azure.BotServiceConnector({<br />appId: process.env['MicrosoftAppId'],<br />appPassword: process.env['MicrosoftAppPassword'],<br />stateEndpoint: process.env['BotStateEndpoint'],<br />openIdMetadata: process.env['BotOpenIdMetadata']<br />});<br /><br />var bot = new builder.UniversalBot(connector);<br />var luisAppId = process.env.LuisAppId;<br />var luisAPIKey = process.env.LuisAPIKey;<br />var luisAPIHostName = process.env.LuisAPIHostName || 'api.projectoxford.ai';</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">const LuisModelUrl = 'https://' + luisAPIHostName + '/luis/v2.0/apps/' + luisAppId + '?subscription-key=' + luisAPIKey + '&verbose=true';<br /><br />var recognizer = new builder.LuisRecognizer(LuisModelUrl);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">var intents = new builder.IntentDialog({ recognizers: [recognizer] })<br />.matches('None', (session, args) => {<br /> session.send('Hello, welcome to Pizza Shop. How may I help you?');<br />})<br />.matches('greeting', (session, args) => {<br /> session.send('Hello, welcome to Pizza Shop. How may I help you?');<br />})<br />.matches('pizza', (session, args) => {<br /> var topping = builder.EntityRecognizer.findEntity(args.entities, 'topping');<br /> if(topping) session.send('Thank you for ordering. Your pizza with %s will be delivered to you in 30 minutes.', topping.entity);<br /> else session.send('Thank you for ordering. Would you like your pizza with anything else?');<br />})<br />.matches('noservice', (session, args) => {<br /> session.send('Thank you for ordering but we only sell pizza. Comeback later if you want a pizza.');<br />})<br />.onDefault((session, args) => {<br /> session.send('Sorry! I am a support bot, I did not understand \'%s\'. Please call XXXXX, our staff will be happy to help you.', session.message.text);<br />});<br /><br />bot.dialog('/', intents);<br /><br />if (useEmulator) {<br /> var restify = require('restify');<br /> var server = restify.createServer();<br /> server.listen(3978, function() {<br /> console.log('test bot endpont at http://localhost:3978/api/messages');<br /> });<br /><br /> server.post('/api/messages', connector.listen()); <br /><br /> } else {<br /> module.exports = { default: connector.listen() }<br />}</span></div>
<br />
Ok, let see our bot working:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw4C5sy5kFhTWvmmEPEwRI-yMrsrfpLBiZ6CswG0PLp1RFnTQbdbfXSK933icDSeftcSsLpFTJXISdgAiPa13we_pB8zUSU9FuRtjeUnShZeNPfFFvYYK2A7P1KGSY1La2o-U_S7p4WLiv/s1600/luis_app_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="730" data-original-width="637" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw4C5sy5kFhTWvmmEPEwRI-yMrsrfpLBiZ6CswG0PLp1RFnTQbdbfXSK933icDSeftcSsLpFTJXISdgAiPa13we_pB8zUSU9FuRtjeUnShZeNPfFFvYYK2A7P1KGSY1La2o-U_S7p4WLiv/s400/luis_app_10.png" width="348" /></a></div>
<br />
<br />
<b>3.</b> We now have a bot serving our Pizza Shop, let connect it with Facebook so our customers can order pizza via Facebook messenger :)<br />
<br />
To do that, you must have a Facebook Page and a Facebook Application. In the case of you don't have your Facebook Page, you can read <a href="https://www.facebook.com/business/learn/set-up-facebook-page">this article</a> for how to. If you don't have any Facebook Application, you can <a href="https://developers.facebook.com/docs/apps/register">read here to register</a> one.<br />
<br />
Assuming that you already had your Facebook Application, go to link <a href="https://developers.facebook.com/">https://developers.facebook.com</a> and open the application. Below is mine for example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB-QTQUpLbWdXuatV4-X6t6m2Lf5kDTr8kmfAPHvgYcUXWsAFcV4kYqEcIWpS3ChxvvtPKgVsQF7ud_MiT7EIaDnMbxQPbuI61T-zOYrWvK_caxPSsmEt3wGy2nUmEzXBI5yK3chjwtHJm/s1600/fb_app_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="408" data-original-width="1219" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB-QTQUpLbWdXuatV4-X6t6m2Lf5kDTr8kmfAPHvgYcUXWsAFcV4kYqEcIWpS3ChxvvtPKgVsQF7ud_MiT7EIaDnMbxQPbuI61T-zOYrWvK_caxPSsmEt3wGy2nUmEzXBI5yK3chjwtHJm/s640/fb_app_1.png" width="640" /></a></div>
<div align="center">
(<i>Picture 1</i>)</div>
<br />
In the above picture, I already added Messenger product into my app. If you don't add yet, click <b><i>+ Add Product</i></b> link >> find <b><i>Messenger</i></b> product then click <b><i>Get Started</i></b> button to add (see the following picture).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigAWAGo0IIP6fOgNn3xinxskm-3ACSBv6EDkPE7bezs2yGqE4o9J7a6mLq3p6okxnWYGwdVjoiAjH7JgGe03sT8xEVmS9J2LRKsb8QsceO3C73gGtSTTKDFF1iKHbg9sFTUQ4jDUyqaID3/s1600/fb_app_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="216" data-original-width="642" height="134" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigAWAGo0IIP6fOgNn3xinxskm-3ACSBv6EDkPE7bezs2yGqE4o9J7a6mLq3p6okxnWYGwdVjoiAjH7JgGe03sT8xEVmS9J2LRKsb8QsceO3C73gGtSTTKDFF1iKHbg9sFTUQ4jDUyqaID3/s400/fb_app_2.png" width="400" /></a></div>
<br />
After that, go to <a href="https://dev.botframework.com/bots">https://dev.botframework.com/bots</a>, open your bot on MS Bot Framework, find <b><i>Facebook Messenger</i></b> in <b><i>Add a channel</i></b> section then click to add and configure it. Scroll down to <b><i>Callback URL and Verify Token for Facebook</i></b> and copy values of <b><i>Callback URL</i></b> and <b><i>Verify Token</i></b>. They will be used for configuring <b><i>Webhooks</i></b> on your Facebook Application.<br />
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr0lM6DKucPK7vMz4OmpaEcdp3UyrbSMG_mitOytGE-4557QDCss4s_uXqaHKV9ybQCZgwBjdZS5vmRLj93fX-xilG8zu7xu0UvPy596kmaSphCfV0KtYXHNrJd-Ip0iQx3rUSIPCqccUc/s1600/fb_app_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="316" data-original-width="500" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr0lM6DKucPK7vMz4OmpaEcdp3UyrbSMG_mitOytGE-4557QDCss4s_uXqaHKV9ybQCZgwBjdZS5vmRLj93fX-xilG8zu7xu0UvPy596kmaSphCfV0KtYXHNrJd-Ip0iQx3rUSIPCqccUc/s400/fb_app_3.png" width="400" /></a></div>
<div style="text-align: center;">
(<i>Picture 2)</i></div>
<u><b><br /></b></u>
Back to the <b><i>Facebook Application</i></b>, click <b><i>Setup Webhooks</i></b> button to verify the callback URL of your bot:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3W9kamUDqERPGgLEAr3RwiQd0O06pIiQACtPLXaxPXiAMBAwHZmSPUDfFrj1P6KhFABc0LpVsNoTbP4IHR8jnYM04x4ThdmW7Gqu3UArXyA1yQWUKio_aHgW9jKEXLu1SAwgsmYzHtyi-/s1600/fb_app_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="379" data-original-width="515" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3W9kamUDqERPGgLEAr3RwiQd0O06pIiQACtPLXaxPXiAMBAwHZmSPUDfFrj1P6KhFABc0LpVsNoTbP4IHR8jnYM04x4ThdmW7Gqu3UArXyA1yQWUKio_aHgW9jKEXLu1SAwgsmYzHtyi-/s1600/fb_app_4.png" /></a></div>
<div style="text-align: center;">
(<i>Picture 3</i>)</div>
<br />
Provide values copied from your bot (<i>Picture 2</i>) in to the opened box, select <b><i>Subscription Fields</i></b> (events) you want:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1ehYDsXX93dUr_I2Sg4eYGf4nU0kxOIfLdsMolDP5tTsBPBMFFknxf-aQp0y0yDfg3PTDGkhn6BcjjXsPxSw5NSG0g6sRj7l50wUxj1G91JOOg4qULsQiXyfWckXMnyBIxGqxle5g2kJr/s1600/fb_app_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="314" data-original-width="669" height="299" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1ehYDsXX93dUr_I2Sg4eYGf4nU0kxOIfLdsMolDP5tTsBPBMFFknxf-aQp0y0yDfg3PTDGkhn6BcjjXsPxSw5NSG0g6sRj7l50wUxj1G91JOOg4qULsQiXyfWckXMnyBIxGqxle5g2kJr/s640/fb_app_5.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
And click <b><i>Verify and Save</i></b> button. When done, let select your <b><i>Facebook Page</i></b> and click <b><i>Subscribe</i></b> button to subscribe the webhook to the page events:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUSb5AMwZPtm7ZcM7AF2plW5BA5hKQyHe8yu7xRm5zW2qRuJrdBf8gcF2SKgOGXZrlcz4e-mHKnQ22WMUZhuyRa5Js0bZDCLxMNs4Anask1voP27sWnHfjWjLxGaR6H5AJEwKpUFro28EY/s1600/fb_app_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="833" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUSb5AMwZPtm7ZcM7AF2plW5BA5hKQyHe8yu7xRm5zW2qRuJrdBf8gcF2SKgOGXZrlcz4e-mHKnQ22WMUZhuyRa5Js0bZDCLxMNs4Anask1voP27sWnHfjWjLxGaR6H5AJEwKpUFro28EY/s640/fb_app_6.png" width="640" /></a></div>
<br />
To enable your app to send and receive messages using your <b><i>Facebook Page</i></b> for everyone coming to your page (public), you must add <b><i>pages_messaging</i></b> and submit to review (see this link <a href="https://developers.facebook.com/docs/messenger-platform/app-review">https://developers.facebook.com/docs/messenger-platform/app-review</a> for more info on this process) :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpSfWUHHhTc6J-BhTQ2k17TgH_2XjzlVQC-vmQ5MNmqK7JnIOZ4N8X2W41e3HHC7f7iNrnlEtR_faiemBqoP6mx4KJTaS2sTNURyc3aX3sNRpY1S-MufnjIQqWhZvLD2T0ojr7q4_l0zUx/s1600/fb_app_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="494" data-original-width="835" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpSfWUHHhTc6J-BhTQ2k17TgH_2XjzlVQC-vmQ5MNmqK7JnIOZ4N8X2W41e3HHC7f7iNrnlEtR_faiemBqoP6mx4KJTaS2sTNURyc3aX3sNRpY1S-MufnjIQqWhZvLD2T0ojr7q4_l0zUx/s400/fb_app_7.png" width="400" /></a></div>
<br />
Otherwise you must add <b><i>Developers</i></b> or <b><i>Testers</i></b> for testing. You can do via <b><i>Roles</i></b> function:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9kqlchbk4AwJEGJaO6A7KCgmjYigL7PaXcZxYhH8pmWG0lRlLTvSZU0GD8u3dzpJWpNnuxUlpinFSf7wiQOe6p4of1HHmCAoTv3gmr_CJvvZ-FcqSaoc2bgmrv1Y74w5jM5lq7V4jGyMS/s1600/fb_app_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="550" data-original-width="1220" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9kqlchbk4AwJEGJaO6A7KCgmjYigL7PaXcZxYhH8pmWG0lRlLTvSZU0GD8u3dzpJWpNnuxUlpinFSf7wiQOe6p4of1HHmCAoTv3gmr_CJvvZ-FcqSaoc2bgmrv1Y74w5jM5lq7V4jGyMS/s640/fb_app_8.png" width="640" /></a></div>
<br />
Yeah! You finished necessary steps on Facebook. Return to the configuration of Facebook Messenger on your bot, let key values from Facebook into:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLQKLGFzTcJkFvfj1rGgV5dHH3FzLhmpnQzStGjcHJzDeKeTFTU9PiK_TQ_0FE_Tv0RIdmbDRVbuZJ4i2Q8B2LuLyWvxC_AqnaHl7PXXk01f-0tQO2u4qariXwWBJAmEzamvp3GVEMMhkR/s1600/fb_app_9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="590" data-original-width="699" height="337" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLQKLGFzTcJkFvfj1rGgV5dHH3FzLhmpnQzStGjcHJzDeKeTFTU9PiK_TQ_0FE_Tv0RIdmbDRVbuZJ4i2Q8B2LuLyWvxC_AqnaHl7PXXk01f-0tQO2u4qariXwWBJAmEzamvp3GVEMMhkR/s400/fb_app_9.png" width="400" /></a></div>
<br />
<br />
Facebook Page ID: find on the <b><i>About</i></b> menu of your Facebook Page:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHIEyCZ52kuhfZHZOQVVzApXMZZ9vqoL-BS41fjCRTr3FEM4QKCCNR8T0rvz4w4MIM65YuPBLo6hg6C1IKet7VXLFTtDDekJSHoqIsXVeVTurZtnz2vvY7wFZI5A1i0mtFNNQQZUZSqJxQ/s1600/fb_app_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="460" data-original-width="528" height="278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHIEyCZ52kuhfZHZOQVVzApXMZZ9vqoL-BS41fjCRTr3FEM4QKCCNR8T0rvz4w4MIM65YuPBLo6hg6C1IKet7VXLFTtDDekJSHoqIsXVeVTurZtnz2vvY7wFZI5A1i0mtFNNQQZUZSqJxQ/s320/fb_app_10.png" width="320" /></a></div>
Facebook App ID & App Secret: get from the dashboard of your Facebook App (<i>Picture 1</i>).<br />
Page Access Token: get from <i>Picture 3</i> when you select your page.<br />
<br />
After keying above values, click Save button, your bot now is connected with Facebook Messenger:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEWoNhGYoLbxQY00QQB3LnfxuF9YaivWLzUw0-B5TY0d7b69axFrMJh32-aND0M1WlJ9ZPANHEWrP0ALDm4-3mbCyytf9TA5d1HV1wlWkCnKwgbXZLvyTfu6VrZZi9PKT_NXiw2TvTAf1b/s1600/fb_app_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="308" data-original-width="1288" height="152" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEWoNhGYoLbxQY00QQB3LnfxuF9YaivWLzUw0-B5TY0d7b69axFrMJh32-aND0M1WlJ9ZPANHEWrP0ALDm4-3mbCyytf9TA5d1HV1wlWkCnKwgbXZLvyTfu6VrZZi9PKT_NXiw2TvTAf1b/s640/fb_app_11.png" width="640" /></a></div>
It's time for talking with your bot. You can try via <i>https://www.messenger.com/t/<Your Page ID></i> or use Facebook Messenger on your mobile:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqHZQ8jo87kp64tfX0VX-cvDti5N3wc_yKSA70Z-7Vt9B4HVTmnv5lN1Tz2lvF9wdazl5o8Oh7ITTOz_lU8b6UZH0yquE6Y2DnOR2aGPp3eEz2VKAoKxnKFlNDVeZMDxk6rijAGYQxdWI8/s1600/fb_app_12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="657" data-original-width="935" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqHZQ8jo87kp64tfX0VX-cvDti5N3wc_yKSA70Z-7Vt9B4HVTmnv5lN1Tz2lvF9wdazl5o8Oh7ITTOz_lU8b6UZH0yquE6Y2DnOR2aGPp3eEz2VKAoKxnKFlNDVeZMDxk6rijAGYQxdWI8/s640/fb_app_12.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDuF-0LNmQPhsdgqJpXLkNugMgmEodlgRYtetMFGSeWtddc6tsnZ8WHvk9GTaBcRKUxZ1Na8oUOPIYV2IzcXIWthFTZaPnCWS83Q5GUQVQoaIAHN3NmioSn4R9BCnAMMaFLGIVHzhz9KmC/s1600/Screenshot_20170622-205306.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1280" data-original-width="720" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDuF-0LNmQPhsdgqJpXLkNugMgmEodlgRYtetMFGSeWtddc6tsnZ8WHvk9GTaBcRKUxZ1Na8oUOPIYV2IzcXIWthFTZaPnCWS83Q5GUQVQoaIAHN3NmioSn4R9BCnAMMaFLGIVHzhz9KmC/s400/Screenshot_20170622-205306.jpg" width="225" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Those are basic steps for creating your bot with MS Bot Framework and connect it with channels like Facebook Messenger. I hope you have a quick start for your bot.<br />
<br />
<b><span style="color: blue;">Good luck! Any comment is welcome</span></b>.<br />
<br />
<br />Hung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com0tag:blogger.com,1999:blog-6453857454125943527.post-14648126656676053802017-05-26T16:56:00.001+07:002017-06-22T21:02:57.277+07:00Create a Luis Chat Bot on Azure Bot Service - Part 1<a href="https://azure.microsoft.com/en-us/services/bot-service/">Azure Bot Service</a> is a service on Azure which provides pre-built environment for developing chat bot based on <a href="https://dev.botframework.com/">Microsoft Bot Framework</a> and <a href="https://luis.ai/">Luis</a>.<br />
<br />
In this post, I'll show you step by step to create a chat bot using Luis on Azure Bot Service. You will see how it is easy.<br />
<br />
Before jumping to steps, I want to introduce the bot app architect with Microsoft Bot Framework (MBF) as the following picture:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiekNiGrS7dzatlwNb3R2kfoPDT7gpnFZ9Caz_aT6QvCDZweuWCL5EV-zV3GpYKCdn02dpBbL3HSaLPLuQtB4d6VcLZuhKnlIt7KAkvJuRKst0u9LCA6JoUV2eZt9IIlaMcj5uMwIXWYmg-/s1600/azure_bot_service.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiekNiGrS7dzatlwNb3R2kfoPDT7gpnFZ9Caz_aT6QvCDZweuWCL5EV-zV3GpYKCdn02dpBbL3HSaLPLuQtB4d6VcLZuhKnlIt7KAkvJuRKst0u9LCA6JoUV2eZt9IIlaMcj5uMwIXWYmg-/s640/azure_bot_service.png" width="640" /></a></div>
<br />
MBF has 2 important parts: Bot Builder and Bot Connector. Bot Builder helps you build your bot with ASP.Net or Node.js and Bot Connector will help your bot connect with other messengers, website or email to send or receive message. Luis will provide a capacity of understanding natural language for your bot. You also can connect your bot with other machine learning service to make it more intelligent.<br />
<br />
That's enough for the theory, let practice.<br />
<br />
<b>1.</b> Go to your <a href="https://portal.azure.com/">Azure Portal</a> and create new Bot Service<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigIBy7Mjsl_t3SLPeg3Ax3_nVu5pRLfaKhOr0fdGmXL7yPLTT0SKYMWXNYnFp6w6JA5WSL9en0L-naCtuspg5FKf3K71RjUBf1tOCbvGgfZceJcurdBMQsju4CPk_HCOj-ewdZc1Xc1tFP/s1600/azure_bot_service1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigIBy7Mjsl_t3SLPeg3Ax3_nVu5pRLfaKhOr0fdGmXL7yPLTT0SKYMWXNYnFp6w6JA5WSL9en0L-naCtuspg5FKf3K71RjUBf1tOCbvGgfZceJcurdBMQsju4CPk_HCOj-ewdZc1Xc1tFP/s400/azure_bot_service1.png" width="400" /></a></div>
<div>
<br /></div>
<div>
Choose <b><i>Bot Service</i></b> as above picture then click <b><i>Create</i></b> button. Next fill in your bot name (app name), resource group and location :</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAMxYXS24bQTj8_rUNUkDgFD0cRoIa2itN7mzEm_ZVo-5YDzyBASb8l5Q1KSpDa5INkMMZJ1HOp6hMPl5bZR17VojOgvzl1CiVoZhb-N3NcAL4Xc0WQU8OR4eOnnX6UHWPWJ0rVXdtPZ9B/s1600/azure_bot_service2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAMxYXS24bQTj8_rUNUkDgFD0cRoIa2itN7mzEm_ZVo-5YDzyBASb8l5Q1KSpDa5INkMMZJ1HOp6hMPl5bZR17VojOgvzl1CiVoZhb-N3NcAL4Xc0WQU8OR4eOnnX6UHWPWJ0rVXdtPZ9B/s320/azure_bot_service2.png" width="270" /></a></div>
<div>
After waiting for Azure finish creating the bot, search its name again and choose it. Azure will ask you <b><i>Create Microsoft App ID and Password</i></b>. Let click this button and it will navigate to MBF to create new bot app id and password:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjesYlp7GOCmr1bxzO-mzZGoWV4-SX303BbIvmIDJX6e0gBMXFvk3Qhyb-MXnB8os1kh5gDr3fkLJSlVtS3pEt_hkf5QyBo6QHGzmyr8qAXxBucNi2F8hoHCiaZR6dtCafaeGoyJhxQ9SvL/s1600/azure_bot_service3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjesYlp7GOCmr1bxzO-mzZGoWV4-SX303BbIvmIDJX6e0gBMXFvk3Qhyb-MXnB8os1kh5gDr3fkLJSlVtS3pEt_hkf5QyBo6QHGzmyr8qAXxBucNi2F8hoHCiaZR6dtCafaeGoyJhxQ9SvL/s400/azure_bot_service3.png" width="400" /></a></div>
<div>
Then click <b><i>Generate an app password to continue</i></b> button, let copy app id & the password generated:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3-BGvgWjadqomLNbe7XACddW4bfBhmbSCFMvf1ulIEPz03n00CFiVza_QYhc30ehpVhdBMCvNwnpcD6d675X937eESeY3wpOKXOKsuD3TgP9RB5sQ7uv87VxUZw88tR5toUbynBmj4_wT/s1600/azure_bot_service4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3-BGvgWjadqomLNbe7XACddW4bfBhmbSCFMvf1ulIEPz03n00CFiVza_QYhc30ehpVhdBMCvNwnpcD6d675X937eESeY3wpOKXOKsuD3TgP9RB5sQ7uv87VxUZw88tR5toUbynBmj4_wT/s320/azure_bot_service4.png" width="320" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5ePaYx9rEubBK0RaOEpvO3-_1N5xzThZzAACMrXPeKuHghyT2lfPq7gxHoSXpaC-YfV66aVq_oBM6cI8jXzzSM0dmvFPgZPRqvJgzfKRxdsBwOeVU2fqkunZW9fy9ZDGw3zScWEheig62/s1600/azure_bot_service5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5ePaYx9rEubBK0RaOEpvO3-_1N5xzThZzAACMrXPeKuHghyT2lfPq7gxHoSXpaC-YfV66aVq_oBM6cI8jXzzSM0dmvFPgZPRqvJgzfKRxdsBwOeVU2fqkunZW9fy9ZDGw3zScWEheig62/s320/azure_bot_service5.png" width="320" /></a></div>
<div>
Click <b><i>Finish and go back to Bot Framework</i></b> button, copy the password generated into password box. Then scroll down, in section <b><i>Choose a language</i></b> I choose <i><b>NodeJS</b></i> because I'm familiar with it. Continue to move down and select <b><i>Language understanding</i></b> (Luis) and click <b><i>Create bot</i></b> button:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2IT32I91FsupPxe8QKlf-uza0LxlIb5JJbxeKfTF9iroFCbyXuOYWjwBRYZozwhoyZ8SL1WL0JSNV-dcHbtigpSPzNGcNqa4M0qc6hfnNkjX-spfkJU23XLg11MCe5B45Nf0r9BqMrTPd/s1600/azure_bot_service6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2IT32I91FsupPxe8QKlf-uza0LxlIb5JJbxeKfTF9iroFCbyXuOYWjwBRYZozwhoyZ8SL1WL0JSNV-dcHbtigpSPzNGcNqa4M0qc6hfnNkjX-spfkJU23XLg11MCe5B45Nf0r9BqMrTPd/s1600/azure_bot_service6.png" /></a></div>
<div>
It will show a confirmation box for creating a blank Luis application and connect it to your bot:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVVkeLEar9wpAbYRx5tUtfA0zNkKjCr6aFGhXr1P0D6dtXj7tr2X819J11uPEsS-2rgWJ1Xaaa5HLonuysvY0s6-KLl2qDBD5lFoHxVhtXSUqlI0GUojw0feZzmceMzkJlGZGts79hv1uq/s1600/azure_bot_service7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVVkeLEar9wpAbYRx5tUtfA0zNkKjCr6aFGhXr1P0D6dtXj7tr2X819J11uPEsS-2rgWJ1Xaaa5HLonuysvY0s6-KLl2qDBD5lFoHxVhtXSUqlI0GUojw0feZzmceMzkJlGZGts79hv1uq/s400/azure_bot_service7.png" width="400" /></a></div>
<div>
<br /></div>
<div>
Let click <b><i>OK</i></b> button and wait for few minutes, then you will see the source code of your bot. Below is a sample:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinGYqrAxOXPhiAo58FtDNjS4datk5axcySsQgSdb-V7iHzJPuEPpfQ2uMp5j2bTWwbqunZwEBNhtwIQXt7hq4YP8oAVr1XJMuoJW6w6YfYW3jAtQBc_aV4atrB7Y7Rb8jN83Qol6SxUtEj/s1600/azure_bot_service8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="572" data-original-width="1294" height="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinGYqrAxOXPhiAo58FtDNjS4datk5axcySsQgSdb-V7iHzJPuEPpfQ2uMp5j2bTWwbqunZwEBNhtwIQXt7hq4YP8oAVr1XJMuoJW6w6YfYW3jAtQBc_aV4atrB7Y7Rb8jN83Qol6SxUtEj/s640/azure_bot_service8.png" width="640" /></a></div>
<br /></div>
By default main source code is in the file <b><i>index.js</i></b>, you can edit its source code and save on this window. On right side, you will see a <b><i>Chat</i></b> box (if you don't see, let click Test button on right top corner ). You can type your message there and see what it replies.<br />
<br />
You also can see the endpoint of your bot in <b><i>SETTINGS</i></b> page, let copy it for testing in the emulator later:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO3n1JKI0fSFwemdAzW4JVZkih0czH9rnUl3s85lBFZYtqxPFc9V4Rcq86D0QKF8FINJZc7FeOjPXs5U5nO9W80mb8MDB9zHNVYuB1hEtfrGnXZBheA9EQCRVV1BlBDAzk1bBnGFG7iG6v/s1600/azure_bot_service18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="357" data-original-width="893" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO3n1JKI0fSFwemdAzW4JVZkih0czH9rnUl3s85lBFZYtqxPFc9V4Rcq86D0QKF8FINJZc7FeOjPXs5U5nO9W80mb8MDB9zHNVYuB1hEtfrGnXZBheA9EQCRVV1BlBDAzk1bBnGFG7iG6v/s400/azure_bot_service18.png" width="400" /></a></div>
<br />
Next step, I'll show you how to integrate its source code to your local repository.<br />
<br />
<b>2.</b> To integrate the source code of your bot with local, click <b><i>SETTINGS</i></b> link and configure <b><i>Continuous integration</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1M-3mz7kgsmIzgAjEPk14rzGg1VAsGCdjY3JD29ohVEJA2Y58cY85DjgaWR_Ok6N2NgLOsPwjdVpOfJ9WvJXzxyYOtc4TetxqRbH8FxBoAn8usIOGYZr6Y2KWR85jFTKzMwHoXrKOoJ9j/s1600/azure_bot_service9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="894" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1M-3mz7kgsmIzgAjEPk14rzGg1VAsGCdjY3JD29ohVEJA2Y58cY85DjgaWR_Ok6N2NgLOsPwjdVpOfJ9WvJXzxyYOtc4TetxqRbH8FxBoAn8usIOGYZr6Y2KWR85jFTKzMwHoXrKOoJ9j/s640/azure_bot_service9.png" width="640" /></a></div>
Firstly, let download the Zip file containing the source code generated (you can see in Section 1 of the above picture). Then click <b><i>Set up integration source</i></b> button. In next window, let click <b><i>Setup</i></b> button and select <b><i>Local Git Repository</i></b>. You can select other type of repository if you want. There are some for you.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY_eHthedRvenXkSzivVyKszKkdCR_mw6bdD80oMHs7IEKPLvqM4P7iDe5_PISyOtWkQBvcK4AlAhOTRq-Mg4C0QLoSmQdeA6mqtzHDjfasPqwew-aLlgM-71VdCS7-ovBU7HjonIG69DX/s1600/azure_bot_service10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1055" data-original-width="1291" height="521" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY_eHthedRvenXkSzivVyKszKkdCR_mw6bdD80oMHs7IEKPLvqM4P7iDe5_PISyOtWkQBvcK4AlAhOTRq-Mg4C0QLoSmQdeA6mqtzHDjfasPqwew-aLlgM-71VdCS7-ovBU7HjonIG69DX/s640/azure_bot_service10.png" width="640" /></a></div>
<br />
In next window, you must key an username & password which are used for the Git:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSU51rtsZopJnBr2vuU5E-PD_JVpnJsdHPxUkYV9mv3-QY9Cinnounh1JqgKYiuP3HZ-Crb7WbSAGGnHmbXPL4C_-3FBhi_-R06JEXQJwHjloxUHUHOlUjNvpo6WxS-O76cLRxPY8b1iWi/s1600/azure_bot_service11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="284" data-original-width="607" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSU51rtsZopJnBr2vuU5E-PD_JVpnJsdHPxUkYV9mv3-QY9Cinnounh1JqgKYiuP3HZ-Crb7WbSAGGnHmbXPL4C_-3FBhi_-R06JEXQJwHjloxUHUHOlUjNvpo6WxS-O76cLRxPY8b1iWi/s400/azure_bot_service11.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Back to the <b><i>SETTINGS</i></b>, click to open <b><i>Advance settings</i></b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjDXnj_mM-SpD3Qi-IyImE7TpK__9bY2kq-usAKmrVQMUZM3qxo1ELYurNGKLhh0TLVujjT97TocjWpKHPcnuG_5nsW9xEwXifGdgIo2R7Tpv-qFeE-bsruI0ZygglRUBnrtW24TDYhyphenhyphenZF/s1600/azure_bot_service13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="432" data-original-width="874" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjDXnj_mM-SpD3Qi-IyImE7TpK__9bY2kq-usAKmrVQMUZM3qxo1ELYurNGKLhh0TLVujjT97TocjWpKHPcnuG_5nsW9xEwXifGdgIo2R7Tpv-qFeE-bsruI0ZygglRUBnrtW24TDYhyphenhyphenZF/s400/azure_bot_service13.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLx1g40TttLWXiistPu93qYqMYgDYmUpw6mubQfb4Lub3Z2MdCC0dMmLAAv9jNku3S4j_4Vt0c1SZItp4QUixjxMy26Z4BHut7JaQMFOQQ0ped4CjZkQT71DVzlSZpXOvNwE8Gz-_qayYf/s1600/azure_bot_service14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="355" data-original-width="1169" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLx1g40TttLWXiistPu93qYqMYgDYmUpw6mubQfb4Lub3Z2MdCC0dMmLAAv9jNku3S4j_4Vt0c1SZItp4QUixjxMy26Z4BHut7JaQMFOQQ0ped4CjZkQT71DVzlSZpXOvNwE8Gz-_qayYf/s640/azure_bot_service14.png" width="640" /></a></div>
<br />
Let copy <b><i>Git clone url</i></b>, it will be used to link your local Git with the Git on Azure.<br />
<br />
On your local computer, extracting the Zip of your bot source code (downloaded in above) into a folder. Assuming that you installed <a href="https://git-scm.com/download/win">Git</a> on your local computer. Change to inside the folder, run the following commands to create your local Git repository and link it with remote Git on Azure:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">#git init</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">#git add -A</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">#git commit -m "<your message, e.g. my first azure bot>"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">#git remote add azure https://<it is git clone url on azure>.git</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">#git push azure master</span><br />
<br />
You will be prompted for the password you created earlier, let key in. Now you can develop your bot on the local as a normal Git project.<br />
<br />
Yeah! It's ready for developing the bot. I often use <a href="https://code.visualstudio.com/">Visual Studio Code</a> for coding NodeJS project with Git. Here is the source code on VSC:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjwpGFRhgdxkBD9L7Rd7sYWYArLWZJ2zugyuEclLOP4eGs7Ge5yKT3h-Ji7u_L5r-sL0lMWz13yxYW2x4x-6N6v9RmZ1Rmpk-AYq3rEATXvbPGJfvC5ZFazyehhE9Ay7fkXSnEnB92uN4C/s1600/azure_bot_service17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="466" data-original-width="1027" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjwpGFRhgdxkBD9L7Rd7sYWYArLWZJ2zugyuEclLOP4eGs7Ge5yKT3h-Ji7u_L5r-sL0lMWz13yxYW2x4x-6N6v9RmZ1Rmpk-AYq3rEATXvbPGJfvC5ZFazyehhE9Ay7fkXSnEnB92uN4C/s400/azure_bot_service17.png" width="400" /></a></div>
<br />
In next step, I'll show you how to use <a href="https://github.com/Microsoft/BotFramework-Emulator/releases">Bot Framework Emulator</a> for testing the bot in your local.<br />
<br />
<b>3.</b> Download he latest setup exe file of Bot Framework Emulator from this link: <i><b>https://github.com/Microsoft/BotFramework-Emulator/releases</b></i>. Then install it. Open it after installation:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuqMDBrKhsXFZIxCEy4olyhZvm_v9dhgm-FjHWJOLgG4qhu4__S5-uX8hswZ0-jv1V0tKDT5L6sJQ7xa-I0EUTT-pGphecefPph5ya0l6LM-bbO5xLhV4KVsx2dDUgYFbYAUL9Y4oSBW2W/s1600/azure_bot_service15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="466" data-original-width="845" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuqMDBrKhsXFZIxCEy4olyhZvm_v9dhgm-FjHWJOLgG4qhu4__S5-uX8hswZ0-jv1V0tKDT5L6sJQ7xa-I0EUTT-pGphecefPph5ya0l6LM-bbO5xLhV4KVsx2dDUgYFbYAUL9Y4oSBW2W/s400/azure_bot_service15.png" width="400" /></a></div>
<br />
Download <a href="https://ngrok.com/">ngrok</a> (a tunneling software to connect to your bot that is hosted remotely, without it you only can send message to your bot but can not receive message from the bot). Click <b><i>App Settings</i></b> menu to point to the <b><i>ngrok.exe</i></b> file and click <b><i>Save</i></b> button:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4HXCOOfajy-mRU_rB3KKpR1SItpxPYrAshqj8Exe7Los-zLbCLzG4lN_FpjN4eVVFl-hO2N8qWU1V5Bn94RUshhUGqgCj6wSebLpjew_QJB5cxPJFRWnxJrVrxy0f-kJgMhA2j7V9xzYU/s1600/azure_bot_service16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="466" data-original-width="505" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4HXCOOfajy-mRU_rB3KKpR1SItpxPYrAshqj8Exe7Los-zLbCLzG4lN_FpjN4eVVFl-hO2N8qWU1V5Bn94RUshhUGqgCj6wSebLpjew_QJB5cxPJFRWnxJrVrxy0f-kJgMhA2j7V9xzYU/s320/azure_bot_service16.png" width="320" /></a></div>
Now, you can test your bot on the emulator. Let use the endpoint that is copied in step <b>1.</b> above and key its app id & password into, then click Connect button:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ87vQ9w_9R7RGqSKAjbrht7jISaaoWdG-FCbWR8FXf7v1Ogmjr19Wvd-cq-JGNP8tNoxjV9Xkxg89OgM3cv5x9_M84umUQXmFFTO0J7fVAi7Xkbiom8ksbELcLZzgssZmY1JAoeL90bm9/s1600/azure_bot_service19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="233" data-original-width="621" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ87vQ9w_9R7RGqSKAjbrht7jISaaoWdG-FCbWR8FXf7v1Ogmjr19Wvd-cq-JGNP8tNoxjV9Xkxg89OgM3cv5x9_M84umUQXmFFTO0J7fVAi7Xkbiom8ksbELcLZzgssZmY1JAoeL90bm9/s400/azure_bot_service19.png" width="400" /></a></div>
<br />
<br />
And you can try, watching Log windows for debug information:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr5foFYAulmIllJZgTsPRU0puk8wwexcPoHp9eAzW0_k9Hg9wxsyUtFwNNb9gyHZ81d8T-oZy4JqT9s_PtgcuCOzfGn1sxDOfgGvqPb5olpvjmC0tvDMYRgJwNQ4kBcUOr-hy8vkVdH5ow/s1600/azure_bot_service20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="733" data-original-width="977" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr5foFYAulmIllJZgTsPRU0puk8wwexcPoHp9eAzW0_k9Hg9wxsyUtFwNNb9gyHZ81d8T-oZy4JqT9s_PtgcuCOzfGn1sxDOfgGvqPb5olpvjmC0tvDMYRgJwNQ4kBcUOr-hy8vkVdH5ow/s400/azure_bot_service20.png" width="400" /></a></div>
<br />
That's it. You already had basic weapons for building your bot. In next article, Part 2, I'll show you how to define a Luis app and use it in your bot. You also can find out how to connect your bot to Facebook in <a href="https://vivavivugeek.blogspot.com/2017/06/create-luis-chat-bot-on-azure-bot-part-2.html">Part 2</a>.<br />
<b><i><span style="color: blue;"><br /></span></i></b>
<b><i><span style="color: blue;">Any comment is welcome. Thank you!</span></i></b><br />
Hung LeHung Lehttp://www.blogger.com/profile/05974694040822196089noreply@blogger.com3