├── DSA ├── search │ ├── BST │ │ └── index.js │ └── linear.js ├── dynamic-programming.js └── recursion.js ├── Microservices ├── client │ ├── src │ │ ├── app │ │ │ ├── errors │ │ │ │ └── 404.php │ │ │ ├── views │ │ │ │ ├── home │ │ │ │ │ └── index.php │ │ │ │ ├── blocks │ │ │ │ │ ├── footer.php │ │ │ │ │ └── header.php │ │ │ │ └── layouts │ │ │ │ │ └── main-layout.php │ │ │ ├── controllers │ │ │ │ ├── Product.php │ │ │ │ ├── admin │ │ │ │ │ └── Dashboard.php │ │ │ │ └── Home.php │ │ │ ├── models │ │ │ │ └── User.php │ │ │ └── App.php │ │ ├── index.php │ │ ├── public │ │ │ └── assets │ │ │ │ └── clients │ │ │ │ └── css │ │ │ │ └── style.css │ │ ├── configs │ │ │ └── routes.php │ │ ├── .htaccess │ │ ├── core │ │ │ ├── Route.php │ │ │ └── Controller.php │ │ └── bootstrap.php │ └── docker-compose.yaml ├── discovery │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ └── application.properties │ │ │ └── java │ │ │ │ └── vn │ │ │ │ └── metemarket │ │ │ │ └── discovery │ │ │ │ └── DiscoveryApplication.java │ │ └── test │ │ │ └── java │ │ │ └── vn │ │ │ └── metemarket │ │ │ └── discovery │ │ │ └── DiscoveryApplicationTests.java │ ├── pom.xml │ └── mvnw.cmd ├── gateway │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── src │ │ ├── test │ │ │ └── java │ │ │ │ └── vn │ │ │ │ └── metemarket │ │ │ │ └── gateway │ │ │ │ └── GatewayApplicationTests.java │ │ └── main │ │ │ ├── java │ │ │ └── vn │ │ │ │ └── metemarket │ │ │ │ └── gateway │ │ │ │ └── GatewayApplication.java │ │ │ └── resources │ │ │ └── application.yaml │ ├── pom.xml │ └── mvnw.cmd ├── services │ ├── userservice │ │ ├── .mvn │ │ │ └── wrapper │ │ │ │ ├── maven-wrapper.jar │ │ │ │ └── maven-wrapper.properties │ │ ├── src │ │ │ ├── main │ │ │ │ ├── resources │ │ │ │ │ └── application.properties │ │ │ │ └── java │ │ │ │ │ └── vn │ │ │ │ │ └── metemarket │ │ │ │ │ └── userservice │ │ │ │ │ ├── models │ │ │ │ │ └── User.java │ │ │ │ │ ├── UserserviceApplication.java │ │ │ │ │ └── controllers │ │ │ │ │ └── DemoController.java │ │ │ └── test │ │ │ │ └── java │ │ │ │ └── vn │ │ │ │ └── metemarket │ │ │ │ └── userservice │ │ │ │ └── UserserviceApplicationTests.java │ │ ├── .gitignore │ │ └── pom.xml │ └── productservice │ │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ └── application.properties │ │ │ └── java │ │ │ │ └── vn │ │ │ │ └── metamarket │ │ │ │ └── productservice │ │ │ │ ├── models │ │ │ │ └── Product.java │ │ │ │ ├── ProductserviceApplication.java │ │ │ │ └── controllers │ │ │ │ └── ProductController.java │ │ └── test │ │ │ └── java │ │ │ └── vn │ │ │ └── metamarket │ │ │ └── productservice │ │ │ └── ProductserviceApplicationTests.java │ │ ├── .gitignore │ │ └── pom.xml ├── docker-configs │ └── my.cnf └── docker-compose.yaml ├── assets └── images │ ├── k8s.png │ ├── IaC_II.jpg │ ├── FE-tools.jpg │ ├── k8s-pod.jpg │ ├── webpack.jpg │ ├── docker-vm.png │ ├── fullstack.jpg │ ├── k8s-cluster.jpg │ ├── k8s-service.png │ ├── k8s-cluster-2.jpg │ ├── k8s-namespcae.jpg │ ├── docker-swarm-1.webp │ ├── docker-swarm-2.webp │ ├── docker-swarm-3.webp │ ├── docker-swarm-4.png │ ├── image-container.jpg │ └── k8s-stateful-set.jpg ├── PHP ├── mvc │ ├── index.php │ ├── public │ │ └── assets │ │ │ ├── images │ │ │ ├── logo.png │ │ │ └── favicon.png │ │ │ ├── css │ │ │ ├── utils │ │ │ │ ├── bootstrap-custom.css │ │ │ │ ├── common.css │ │ │ │ └── atomic.css │ │ │ ├── 404.css │ │ │ ├── pagination.css │ │ │ ├── player-list.css │ │ │ ├── header.css │ │ │ ├── add-player.css │ │ │ ├── home.css │ │ │ └── login.css │ │ │ └── js │ │ │ ├── home.js │ │ │ ├── utils │ │ │ └── toast.js │ │ │ ├── pagination.js │ │ │ ├── add-club.js │ │ │ ├── login.js │ │ │ ├── club-list.js │ │ │ ├── add-player.js │ │ │ ├── search-player.js │ │ │ └── player-list.js │ ├── utils │ │ └── constants.php │ ├── .htaccess │ ├── configs │ │ ├── database.php │ │ └── routes.php │ ├── app │ │ ├── views │ │ │ ├── blocks │ │ │ │ ├── footer.php │ │ │ │ └── header.php │ │ │ ├── mixins │ │ │ │ ├── toast.php │ │ │ │ └── pagination.php │ │ │ ├── login.php │ │ │ ├── home.php │ │ │ ├── search-player.php │ │ │ ├── club-list.php │ │ │ ├── layouts │ │ │ │ └── general.php │ │ │ ├── add-club.php │ │ │ ├── add-player.php │ │ │ └── player-list.php │ │ ├── errors │ │ │ └── 404.php │ │ ├── models │ │ │ ├── Coach.php │ │ │ ├── Stadium.php │ │ │ ├── User.php │ │ │ ├── Club.php │ │ │ └── Player.php │ │ ├── controllers │ │ │ ├── Home.php │ │ │ ├── Account.php │ │ │ ├── Club.php │ │ │ └── Player.php │ │ └── App.php │ ├── core │ │ ├── traits │ │ │ └── GetterSetter.php │ │ ├── Route.php │ │ ├── MySQLConnection.php │ │ ├── Model.php │ │ └── Controller.php │ └── bootstrap.php ├── basic-syntax │ ├── form │ │ ├── get.php │ │ ├── post.php │ │ ├── request.php │ │ └── index.html │ ├── 4-function.php │ ├── 3-data-type.php │ ├── 2-basic-syntax.php │ ├── 1-coding-convention.php │ └── 5-oop.php └── README.md ├── .gitignore ├── Docker ├── docker_demo │ ├── Dockerfile │ ├── note │ │ ├── script.sql │ │ └── step.sh │ ├── code │ │ └── index.php │ └── docker-compose.yaml ├── docker-compose-example │ ├── Dockerfile │ ├── database-script.sql │ ├── my.cnf │ └── docker-compose.yaml ├── docker-file-example │ ├── index.html │ └── Dockerfile ├── docker-machine.md ├── README.md ├── docker-swarm.md ├── docker-file.md └── docker-command.md ├── README.md ├── Frontend-Tools ├── webpack │ ├── .babelrc │ ├── src │ │ └── App.jsx │ ├── tsconfig.json │ ├── index.js │ ├── dist │ │ ├── index.html │ │ └── main.js.LICENSE.txt │ ├── index.html │ ├── README.md │ ├── .eslintrc.js │ ├── package.json │ └── webpack.config.js └── README.md ├── Typescript ├── lessons │ ├── 1-compile.ts │ ├── 4-non-null.ts │ ├── 5-class.ts │ ├── 3-funciton.ts │ ├── 6-interface-type.ts │ ├── 8-utility-types.ts │ ├── 7-generic.ts │ └── 2-types.ts └── README.md └── Kubernetes └── README.md /DSA/search/BST/index.js: -------------------------------------------------------------------------------- 1 | // Binary search tree 2 | -------------------------------------------------------------------------------- /Microservices/client/src/app/errors/404.php: -------------------------------------------------------------------------------- 1 |

404 Not Found

-------------------------------------------------------------------------------- /assets/images/k8s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynonguyen/today-learned/HEAD/assets/images/k8s.png -------------------------------------------------------------------------------- /PHP/mvc/index.php: -------------------------------------------------------------------------------- 1 | Learn to become a Full Stack Developer 😗 4 | 5 | ![FullStack Dev](./assets/images/fullstack.jpg) 6 | -------------------------------------------------------------------------------- /PHP/mvc/utils/constants.php: -------------------------------------------------------------------------------- 1 | 1, 5 | 'LOCK' => 2 6 | ]); 7 | -------------------------------------------------------------------------------- /Frontend-Tools/webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | ["@babel/preset-react", { "runtime": "automatic" }] 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /Frontend-Tools/webpack/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function App() { 4 | return
Hello Webpack
; 5 | } 6 | -------------------------------------------------------------------------------- /Frontend-Tools/webpack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowUmdGlobalAccess": true // make typescript work with ProvidePlugin 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/utils/bootstrap-custom.css: -------------------------------------------------------------------------------- 1 | .form-control { 2 | box-shadow: none !important; 3 | } 4 | 5 | a { 6 | text-decoration: none; 7 | } 8 | -------------------------------------------------------------------------------- /Microservices/client/src/app/views/home/index.php: -------------------------------------------------------------------------------- 1 |
2 |

Ứng dụng đi chợ online siêu cấp vip pro

3 |
-------------------------------------------------------------------------------- /Microservices/discovery/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynonguyen/today-learned/HEAD/Microservices/discovery/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /Microservices/gateway/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynonguyen/today-learned/HEAD/Microservices/gateway/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /PHP/mvc/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | 3 | RewriteCond %{REQUEST_FILENAME} !-d 4 | RewriteCond %{REQUEST_FILENAME} !-f 5 | 6 | RewriteRule ^(.+)$ index.php/$1 [L,QSA] -------------------------------------------------------------------------------- /Docker/docker-compose-example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.1.3-fpm 2 | 3 | RUN docker-php-ext-install mysqli 4 | RUN docker-php-ext-install pdo_mysql 5 | 6 | WORKDIR /home/www -------------------------------------------------------------------------------- /Microservices/client/src/configs/routes.php: -------------------------------------------------------------------------------- 1 | real route 5 | $routes['trang-chu'] = 'home'; 6 | -------------------------------------------------------------------------------- /Microservices/client/src/app/views/blocks/footer.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Microservices/client/src/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | 3 | RewriteCond %{REQUEST_FILENAME} !-d 4 | RewriteCond %{REQUEST_FILENAME} !-f 5 | 6 | RewriteRule ^(.+)$ index.php/$1 [L,QSA] -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/home.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | jQuery(function () {}); 4 | -------------------------------------------------------------------------------- /Microservices/services/userservice/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynonguyen/today-learned/HEAD/Microservices/services/userservice/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /Microservices/client/src/app/controllers/Product.php: -------------------------------------------------------------------------------- 1 | , document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /Microservices/client/src/app/views/blocks/header.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DSA/search/linear.js: -------------------------------------------------------------------------------- 1 | export function linearSearch(keyword, data = []) { 2 | for (const [index, value] of data) { 3 | if (value === keyword) { 4 | return index; 5 | } 6 | } 7 | 8 | return -1; 9 | } 10 | -------------------------------------------------------------------------------- /PHP/mvc/configs/database.php: -------------------------------------------------------------------------------- 1 | 'localhost', 5 | 'username' => 'root', 6 | 'password' => 'root', 7 | 'db' => 'footballdb' 8 | ]; 9 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/blocks/footer.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PHP/basic-syntax/form/get.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

404

5 |

Trang bạn đang tìm đang xảy ra lỗi hoặc không tìm thấy.

6 | Về trang chủ 7 |
-------------------------------------------------------------------------------- /PHP/basic-syntax/form/request.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | > Các công cụ dùng để build, bundle, module hoá, tối ưu production cho Frontend 6 | 7 | > Demo công cụ trên ứng dụng sử dụng ReactJS 8 | -------------------------------------------------------------------------------- /Microservices/discovery/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /Microservices/gateway/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /Microservices/services/userservice/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=user-service 2 | server.port=${USERSERVICE_PORT:3000} 3 | 4 | eureka.client.service-url.defaultZone=${DISCOVERY_URL:http://localhost:8761/eureka} 5 | eureka.instance.hostname=${INSTANCE_HOSTNAME:localhost} -------------------------------------------------------------------------------- /Microservices/services/userservice/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /Microservices/services/productservice/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /Microservices/services/productservice/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=product-service 2 | server.port=${PRODUCTSERVICE_PORT:3001} 3 | 4 | eureka.client.service-url.defaultZone=${DISCOVERY_URL:http://localhost:8761/eureka} 5 | eureka.instance.hostname=${INSTANCE_HOSTNAME:localhost} 6 | -------------------------------------------------------------------------------- /Microservices/discovery/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=discovery-server 2 | server.port=${DISCOVERY_PORT:8761} 3 | 4 | # Avoid this server registering with itself 5 | eureka.client.register-with-eureka=false 6 | eureka.client.fetch-registry=false 7 | eureka.instance.hostname=${INSTANCE_HOSTNAME:discovery-server} -------------------------------------------------------------------------------- /Frontend-Tools/webpack/dist/index.html: -------------------------------------------------------------------------------- 1 | Webpack
-------------------------------------------------------------------------------- /Microservices/gateway/src/test/java/vn/metemarket/gateway/GatewayApplicationTests.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.gateway; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class GatewayApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Typescript/lessons/1-compile.ts: -------------------------------------------------------------------------------- 1 | const user: string = 'Dyno Nguyen'; 2 | console.log(user); 3 | 4 | // TS không thể chạy trực tiếp mà còn compile sang JS để chạy 5 | 6 | /* Compile và giữ nguyên tên file 7 | tsc input.ts 8 | */ 9 | 10 | /* Watching compile 11 | tsc -w input.ts 12 | */ 13 | 14 | /* Tạo file tsconfig.json 15 | tsc --init 16 | */ 17 | -------------------------------------------------------------------------------- /Microservices/discovery/src/test/java/vn/metemarket/discovery/DiscoveryApplicationTests.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.discovery; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DiscoveryApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Docker/docker-file-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Dockerfile 9 | 10 | 11 | 12 |

Hello Dockerfile

13 | 14 | 15 | -------------------------------------------------------------------------------- /Microservices/services/userservice/src/test/java/vn/metemarket/userservice/UserserviceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.userservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class UserserviceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/utils/toast.js: -------------------------------------------------------------------------------- 1 | function showToast(timeout = 4000) { 2 | const toast = $('#toast'); 3 | if (toast) { 4 | toast.addClass('show'); 5 | setTimeout(() => { 6 | toast.removeClass('show'); 7 | }, timeout); 8 | } 9 | } 10 | 11 | function hideToast() { 12 | const toast = $('#toast'); 13 | if (toast) { 14 | toast.removeClass('show'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Microservices/services/productservice/src/test/java/vn/metamarket/productservice/ProductserviceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package vn.metamarket.productservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ProductserviceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Frontend-Tools/webpack/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Webpack 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Typescript/README.md: -------------------------------------------------------------------------------- 1 |

Typescript

2 | 3 | > **Typescript** is **JavaScript with syntax for types.** TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale. 4 | 5 | - [Homepage](https://www.typescriptlang.org/) 6 | 7 | - [Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) 8 | 9 | - [Github](https://github.com/microsoft/TypeScript) 10 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/404.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 100vw; 3 | height: 100vh; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | 10 | h1 { 11 | font-size: 10rem; 12 | color: #1e5c69; 13 | margin: 0; 14 | } 15 | 16 | p { 17 | color: #666; 18 | font-size: 1.5rem; 19 | } 20 | 21 | a { 22 | font-size: 1.3rem; 23 | text-decoration: none; 24 | color: #1e5c69; 25 | } 26 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/pagination.css: -------------------------------------------------------------------------------- 1 | .pagination { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | } 6 | 7 | .pagination button { 8 | border: none; 9 | font-size: 1.6rem; 10 | padding: 6px 12px; 11 | margin: 0 6px; 12 | background-color: var(--app-light); 13 | transition: all 0.25s; 14 | } 15 | 16 | .pagination button:hover { 17 | background-color: var(--bs-primary); 18 | color: #fff; 19 | } 20 | -------------------------------------------------------------------------------- /Docker/docker_demo/note/script.sql: -------------------------------------------------------------------------------- 1 | create table Student( 2 | id char(8) PRIMARY key, 3 | name varchar(100) charset utf8, 4 | avg float, 5 | phone char(10), 6 | grade char(8), 7 | email varchar(100), 8 | birthday date 9 | ); 10 | 11 | INSERT INTO `Student` (`id`, `name`, `avg`, `phone`, `grade`, `email`, `birthday`) VALUES ('18120634', 'Tuấn', '9.1', '0377757578', '18CTT5', 'tuannguyentn2504@gmail.com', '2000-04-25'); 12 | -------------------------------------------------------------------------------- /Docker/docker-compose-example/database-script.sql: -------------------------------------------------------------------------------- 1 | create table Student( 2 | id char(8) PRIMARY key, 3 | name varchar(100) charset utf8, 4 | avg float, 5 | phone char(10), 6 | grade char(8), 7 | email varchar(100), 8 | birthday date 9 | ); 10 | 11 | INSERT INTO `Student` (`id`, `name`, `avg`, `phone`, `grade`, `email`, `birthday`) VALUES ('18120634', 'Tuấn', '9.1', '0377757578', '18CTT5', 'tuannguyentn2504@gmail.com', '2000-04-25'); -------------------------------------------------------------------------------- /PHP/mvc/core/traits/GetterSetter.php: -------------------------------------------------------------------------------- 1 | $property; 8 | } 9 | return null; 10 | } 11 | 12 | public function _set($property, $value) 13 | { 14 | if (property_exists($this, $property)) { 15 | $this->$property = $value; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Microservices/services/productservice/src/main/java/vn/metamarket/productservice/models/Product.java: -------------------------------------------------------------------------------- 1 | package vn.metamarket.productservice.models; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | @Setter 11 | @Getter 12 | public class Product { 13 | private int id; 14 | private String name; 15 | private int price; 16 | } -------------------------------------------------------------------------------- /Docker/docker-file-example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:latest 2 | 3 | RUN cd /etc/yum.repos.d/ 4 | RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 5 | RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 6 | RUN yum install httpd httpd-tools vim epel-release -y 7 | RUN yum update -y 8 | 9 | WORKDIR /var/www/html/ 10 | 11 | EXPOSE 80 12 | 13 | ADD ./index.html . 14 | 15 | ENTRYPOINT [ "httpd" ] 16 | CMD [ "-D", "FOREGROUND" ] -------------------------------------------------------------------------------- /Frontend-Tools/webpack/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # Ưu điểm 4 | 5 | - Bundle JS, CSS into single file. 6 | - Minify assets 7 | - Compile Typescript, SCSS automatically 8 | - Optimize images, SVG 9 | - Dev, Prod mode 10 | - Easy build React, TS, SCSS, ... 11 | - Babel, PostCSS, Auto prefix css, split code 12 | 13 | # Nhược điểm 14 | 15 | - Document khó đọc, khó để học 16 | - Cú pháp hỗn độn 17 | - Mất thời gian cho việc setup 18 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/player-list.css: -------------------------------------------------------------------------------- 1 | .modal-title { 2 | font-size: 2rem; 3 | text-transform: uppercase; 4 | } 5 | 6 | .modal-body *, 7 | .modal-footer * { 8 | font-size: 1.6rem; 9 | } 10 | 11 | .modal-dialog { 12 | max-width: 776px; 13 | } 14 | 15 | .modal-body label { 16 | color: var(--app-gray); 17 | } 18 | 19 | .modal-footer button { 20 | text-transform: uppercase; 21 | } 22 | 23 | .modal-open .container-fluid, 24 | .modal-open .container { 25 | -webkit-filter: blur(5px) grayscale(90%); 26 | } 27 | -------------------------------------------------------------------------------- /Microservices/services/userservice/src/main/java/vn/metemarket/userservice/models/User.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.userservice.models; 2 | 3 | import java.util.Date; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Setter 13 | @Getter 14 | public class User { 15 | private int id; 16 | private String firstName; 17 | private String lastName; 18 | private Date birthday; 19 | } -------------------------------------------------------------------------------- /Microservices/gateway/src/main/java/vn/metemarket/gateway/GatewayApplication.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.gateway; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaClient 9 | public class GatewayApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(GatewayApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Microservices/discovery/src/main/java/vn/metemarket/discovery/DiscoveryApplication.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.discovery; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class DiscoveryApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(DiscoveryApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Microservices/client/src/core/Route.php: -------------------------------------------------------------------------------- 1 | $value) { 12 | if (preg_match('~' . $key . '~is', $url)) { 13 | $handleUrl = preg_replace('~' . $key . '~is', $value, $url); 14 | } 15 | } 16 | } 17 | 18 | return $handleUrl; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Microservices/services/userservice/src/main/java/vn/metemarket/userservice/UserserviceApplication.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.userservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaClient 9 | public class UserserviceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(UserserviceApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Frontend-Tools/webpack/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['import'], 3 | rules: { 4 | 'import/order': [ 5 | 'error', 6 | { 7 | alphabetize: { 8 | order: 'asc', 9 | caseInsensitive: true, 10 | }, 11 | 'newlines-between': 'always', 12 | groups: ['builtin', 'external', 'parent', 'sibling', 'index'], 13 | pathGroups: [ 14 | { 15 | pattern: 'react', 16 | group: 'external', 17 | position: 'before', 18 | }, 19 | ], 20 | pathGroupsExcludedImportTypes: ['builtin'], 21 | }, 22 | ], 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /Microservices/services/userservice/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /Microservices/services/productservice/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /Microservices/services/productservice/src/main/java/vn/metamarket/productservice/ProductserviceApplication.java: -------------------------------------------------------------------------------- 1 | package vn.metamarket.productservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaClient 9 | public class ProductserviceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ProductserviceApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Microservices/client/src/bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | real url 5 | public function handleRoute($url = '') 6 | { 7 | global $routes; 8 | $url = trim($url, '/'); 9 | 10 | $handleUrl = $url; 11 | if (!empty($routes)) { 12 | foreach ($routes as $key => $value) { 13 | if (preg_match('~' . $key . '~is', $url)) { 14 | $handleUrl = preg_replace('~' . $key . '~is', $value, $url); 15 | } 16 | } 17 | } 18 | 19 | return $handleUrl; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Frontend-Tools/webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack", 3 | "scripts": { 4 | "start": "webpack --mode=production", 5 | "build": "webpack", 6 | "dev": "webpack serve --open --color --port 8000" 7 | }, 8 | "devDependencies": { 9 | "@babel/core": "^7.18.6", 10 | "@babel/preset-env": "^7.18.6", 11 | "@babel/preset-react": "^7.18.6", 12 | "babel-loader": "^8.2.5", 13 | "html-webpack-plugin": "^5.5.0", 14 | "webpack": "^5.73.0", 15 | "webpack-cli": "^4.10.0", 16 | "webpack-dev-server": "^4.9.3" 17 | }, 18 | "dependencies": { 19 | "react": "^18.2.0", 20 | "react-dom": "^18.2.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /PHP/basic-syntax/4-function.php: -------------------------------------------------------------------------------- 1 | "; 6 | } 7 | funcName(); 8 | 9 | // Đặt biến 10 | $funcName2 = function () { 11 | echo 'Hi hi hi'; 12 | }; 13 | $funcName2(); 14 | 15 | // Tham số 16 | function funcName3($param1, $param2 = 'Default value') 17 | { 18 | echo "
" . $param1 . " " . $param2 . "
"; 19 | } 20 | funcName3(1); 21 | 22 | 23 | // Anonymous function (Lamda, callback) 24 | $arr = [1, 2, 3]; 25 | array_walk($arr, function ($value, $key) { 26 | echo "Key = " . $key . " - Value = " . $value . "
"; 27 | }); 28 | -------------------------------------------------------------------------------- /Typescript/lessons/4-non-null.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------- 2 | --------------- OPTIONAL & NON NULL --------------- 3 | -------------------------------- */ 4 | // Xuất hiện khi bật flag strict: true trong tsconfig 5 | 6 | const addFunc = (a: number, b?: number): number => a + b; 7 | // b -> Object is possibly 'undefined' 8 | // Vì b là 1 biến optional nên nó có thể bị undefined, ta có thể giải quyết bằng 2 cách 9 | 10 | // 1 - Check trước khi dùng 11 | const addFuncWithCheck = (a: number, b?: number): number => (b ? a + b : a); 12 | // 2 - Dùng toán tử NON NULL ! (báo với TS là mình sẽ chắc chắn truyền vào b khi code 🤣) 13 | const addWithNonNull = (a: number, b?: number): number => a + b!; 14 | -------------------------------------------------------------------------------- /PHP/README.md: -------------------------------------------------------------------------------- 1 |

PHP

2 | 3 | > **PHP**: **P**erson **H**ome **P**age 4 | 5 | > **PHP** là ngôn ngữ kịch bản (Scripting Language), mã nguồn mở và thường dùng tạo ứng dụng web ở server. 6 | 7 | > Đặc trưng của PHP 8 | 9 | - Simplicity 10 | - Efficiency 11 | - Security 12 | - Flexibility 13 | - Familiarity 14 | 15 | > Web server nổi bật khi chạy PHP là **Apache Server**. Tối ưu cho LAMP Stack. 16 | 17 | > Tạo một server ảo nhanh để chạy PHP dùng **XAMPP** hoặc **WAMP** 18 | 19 | > Cấu hình XAMPP trong Arch Linux: 20 | 21 | - Thay đổi cấu hình, port: `/opt/lampp/etc/httpd.conf` 22 | - Thư mục mặc định chứa website: `/opt/lampp/htdocs` 23 | - Service: `systemctl start xampp.service` 24 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/header.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: var(--bs-primary); 3 | width: 100%; 4 | } 5 | 6 | nav * { 7 | color: #fff; 8 | } 9 | 10 | .nav-wrapper { 11 | height: 7.2rem; 12 | display: flex; 13 | justify-content: space-between; 14 | align-items: center; 15 | padding-top: 6px; 16 | padding-bottom: 6px; 17 | } 18 | 19 | nav .logo { 20 | width: 5.4rem; 21 | } 22 | 23 | .logo-name { 24 | font-size: 2.2rem; 25 | text-transform: uppercase; 26 | letter-spacing: 0.5px; 27 | margin-left: 8px; 28 | color: #fff; 29 | } 30 | 31 | .account-group span, 32 | .cart-group span { 33 | font-size: 1.5rem; 34 | } 35 | 36 | .account-group i, 37 | .cart-group i { 38 | font-size: 2.8rem; 39 | } 40 | -------------------------------------------------------------------------------- /PHP/mvc/bootstrap.php: -------------------------------------------------------------------------------- 1 | getProducts() { 15 | List products = new ArrayList<>(); 16 | products.add(new Product(1, "IPhone 12", 19000000)); 17 | products.add(new Product(2, "IPhone 14", 25000000)); 18 | return products; 19 | } 20 | } -------------------------------------------------------------------------------- /Microservices/services/userservice/src/main/java/vn/metemarket/userservice/controllers/DemoController.java: -------------------------------------------------------------------------------- 1 | package vn.metemarket.userservice.controllers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import vn.metemarket.userservice.models.User; 11 | 12 | @RestController 13 | public class DemoController { 14 | @GetMapping("/list") 15 | public List getUserList() { 16 | List userList = new ArrayList<>(); 17 | userList.add(new User(1, "Dyno", "Nguyễn", new Date())); 18 | userList.add(new User(2, "Tuấn", "Nguyễn", new Date())); 19 | return userList; 20 | } 21 | } -------------------------------------------------------------------------------- /PHP/mvc/app/models/Coach.php: -------------------------------------------------------------------------------- 1 | prepare('SELECT CoachID, CFullName FROM coach'); 17 | $st->setFetchMode(PDO::FETCH_CLASS, static::class); 18 | $st->execute(); 19 | $coachList = $st->fetchAll(); 20 | return $coachList; 21 | } catch (Exception $ex) { 22 | error_log($ex); 23 | return []; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PHP/mvc/app/models/Stadium.php: -------------------------------------------------------------------------------- 1 | prepare('SELECT StadiumID, SName FROM stadium'); 17 | $st->setFetchMode(PDO::FETCH_CLASS, static::class); 18 | $st->execute(); 19 | $stadiums = $st->fetchAll(); 20 | return $stadiums; 21 | } catch (Exception $ex) { 22 | error_log($ex); 23 | return []; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Microservices/client/src/app/models/User.php: -------------------------------------------------------------------------------- 1 | id = $id; 12 | $this->$firstName = $firstName; 13 | $this->$lastName = $lastName; 14 | $this->birthday = $birthday; 15 | } 16 | 17 | public function __get($property) 18 | { 19 | if (property_exists($this, $property)) { 20 | return $this->$property; 21 | } 22 | return null; 23 | } 24 | 25 | public function __set($property, $value) 26 | { 27 | if (property_exists($this, $property)) { 28 | $this->$property = $value; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /PHP/mvc/configs/routes.php: -------------------------------------------------------------------------------- 1 | real route 5 | $routes['trang-chu'] = 'home'; 6 | $routes['gioi-thieu'] = 'home/introPage'; 7 | 8 | $routes['danh-sach-cau-thu'] = 'player/showList'; 9 | $routes['xoa-cau-thu'] = 'player/deletePlayerApi'; 10 | $routes['tim-kiem-cau-thu'] = 'player/searchPlayerPage'; 11 | $routes['tim-kiem-cau-thu-api'] = 'player/searchPlayerApi'; 12 | $routes['them-cau-thu'] = 'player/addPlayer'; 13 | $routes['thuc-hien-them-cau-thu'] = 'player/postAddPlayer'; 14 | 15 | $routes['danh-sach-clb'] = 'club/showList'; 16 | $routes['danh-sach-clb-api'] = 'club/getClubsApi'; 17 | $routes['them-clb'] = 'club/addClub'; 18 | $routes['thuc-hien-them-clb'] = 'club/postAddClub'; 19 | 20 | $routes['dang-nhap'] = 'account/getLogin'; 21 | $routes['dang-xuat'] = 'account/logout'; 22 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/mixins/toast.php: -------------------------------------------------------------------------------- 1 | 9 |
10 |
$msg
11 | 12 |
13 | "; 14 | } 15 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/login.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Đăng nhập

4 | 5 |

6 |

Tài khoản test: admin/admin

7 | 8 | 9 |
10 | 11 | 12 |
13 | 14 | 15 |
16 |
-------------------------------------------------------------------------------- /Frontend-Tools/webpack/dist/main.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license React 3 | * react-dom.production.min.js 4 | * 5 | * Copyright (c) Facebook, Inc. and its affiliates. 6 | * 7 | * This source code is licensed under the MIT license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | /** 12 | * @license React 13 | * react-jsx-runtime.production.min.js 14 | * 15 | * Copyright (c) Facebook, Inc. and its affiliates. 16 | * 17 | * This source code is licensed under the MIT license found in the 18 | * LICENSE file in the root directory of this source tree. 19 | */ 20 | 21 | /** 22 | * @license React 23 | * scheduler.production.min.js 24 | * 25 | * Copyright (c) Facebook, Inc. and its affiliates. 26 | * 27 | * This source code is licensed under the MIT license found in the 28 | * LICENSE file in the root directory of this source tree. 29 | */ 30 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/add-player.css: -------------------------------------------------------------------------------- 1 | form .form-control, 2 | form .form-select, 3 | form .btn, 4 | form .alert { 5 | font-size: 1.8rem; 6 | padding: 0.75rem 1.5rem; 7 | } 8 | 9 | form .form-control::-webkit-input-placeholder, form .form-select::-webkit-input-placeholder { 10 | color: var(--app-gray); 11 | } 12 | 13 | form .form-control::-moz-placeholder, form .form-select::-moz-placeholder { 14 | color: var(--app-gray); 15 | } 16 | 17 | form .form-control:-ms-input-placeholder, form .form-select:-ms-input-placeholder { 18 | color: var(--app-gray); 19 | } 20 | 21 | form .form-control::-ms-input-placeholder, form .form-select::-ms-input-placeholder { 22 | color: var(--app-gray); 23 | } 24 | 25 | form .form-control::placeholder, 26 | form .form-select::placeholder { 27 | color: var(--app-gray); 28 | } 29 | 30 | form label { 31 | font-size: 1.8rem; 32 | color: var(--app-gray); 33 | } 34 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/mixins/pagination.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | "; 7 | 8 | if ($totalPage > 1 && $page > 1) { 9 | echo ""; 12 | echo ""; 13 | } 14 | 15 | echo ""; 16 | 17 | if ($totalPage > 1 && $page < $totalPage) { 18 | echo ""; 19 | echo ""; 22 | } 23 | 24 | echo ""; 25 | } 26 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/utils/common.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | font-size: 62.5%; 4 | width: 100%; 5 | overflow-x: hidden; 6 | } 7 | 8 | :root { 9 | --app-dark: #151522; 10 | --app-dark-gray: #333; 11 | --app-gray: #888; 12 | --app-light-gray: #ccc; 13 | --app-light: #eee; 14 | } 15 | 16 | /* Scroll bar */ 17 | ::-webkit-scrollbar { 18 | width: 8px; 19 | } 20 | 21 | ::-webkit-scrollbar-track { 22 | background: #f1f1f1; 23 | } 24 | 25 | ::-webkit-scrollbar-thumb { 26 | background: var(--app-gray); 27 | } 28 | 29 | .app-wrapper { 30 | display: flex; 31 | flex-direction: column; 32 | min-height: 100vh; 33 | } 34 | 35 | .app-wrapper main { 36 | flex-grow: 1; 37 | } 38 | 39 | ul { 40 | padding: 0; 41 | } 42 | 43 | li { 44 | list-style: none; 45 | } 46 | 47 | a:hover { 48 | color: var(--bs-info); 49 | } 50 | 51 | @media only screen and (max-width: 375px) { 52 | html, 53 | body { 54 | font-size: 50%; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/pagination.js: -------------------------------------------------------------------------------- 1 | jQuery(function () { 2 | const url = new URL(location.href); 3 | 4 | function redirectToPage(page) { 5 | url.searchParams.set('page', page); 6 | location.href = url.href; 7 | } 8 | 9 | $('#firstPageBtn').on('click', function () { 10 | redirectToPage(1); 11 | }); 12 | 13 | $('#lastPageBtn').on('click', function () { 14 | const total = Number($(this).attr('data-total')); 15 | if (!total || isNaN(total)) return; 16 | redirectToPage(total); 17 | }); 18 | 19 | $('#prevPageBtn').on('click', function () { 20 | const currentPage = Number($(this).attr('data-page')); 21 | if (isNaN(currentPage) || currentPage <= 1) return; 22 | redirectToPage(currentPage - 1); 23 | }); 24 | 25 | $('#nextPageBtn').on('click', function () { 26 | const currentPage = Number($(this).attr('data-page')); 27 | if (isNaN(currentPage)) return; 28 | redirectToPage(currentPage + 1); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/home.css: -------------------------------------------------------------------------------- 1 | .g-5 { 2 | --bs-gutter-y: 5rem; 3 | --bs-gutter-x: 3.5rem; 4 | } 5 | 6 | .menu-item { 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | flex-direction: column; 11 | padding: 2.5rem 0.5rem; 12 | border-radius: 8px; 13 | box-shadow: rgba(17, 17, 26, 0.05) 0px 4px 8px, 14 | rgba(17, 17, 26, 0.05) 0px 8px 16px; 15 | transition: all 0.35s; 16 | height: 100%; 17 | } 18 | 19 | .menu-item:hover { 20 | background-color: #fdfdfd; 21 | } 22 | 23 | .menu-item:hover * { 24 | color: var(--bs-primary); 25 | font-weight: 500; 26 | } 27 | 28 | .menu-item * { 29 | color: var(--app-dark); 30 | } 31 | 32 | .menu-item i { 33 | font-size: 2.8rem; 34 | } 35 | 36 | .menu-item span { 37 | font-size: 2rem; 38 | text-align: center; 39 | text-transform: capitalize; 40 | } 41 | 42 | @media only screen and (max-width: 576px) { 43 | .g-5 { 44 | --bs-gutter-y: 3rem; 45 | --bs-gutter-x: 3rem; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/utils/atomic.css: -------------------------------------------------------------------------------- 1 | .vertical-center { 2 | display: flex; 3 | align-items: center; 4 | } 5 | 6 | .flex-center { 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | } 11 | 12 | .flex-center-between { 13 | display: flex; 14 | align-items: center; 15 | justify-content: space-between; 16 | } 17 | 18 | .orange-color { 19 | color: var(--bs-orange); 20 | } 21 | 22 | .text-gray { 23 | color: var(--app-gray); 24 | } 25 | 26 | .cursor-pointer { 27 | cursor: pointer; 28 | } 29 | 30 | #overlay { 31 | z-index: 99; 32 | position: fixed; 33 | top: 0; 34 | left: 0; 35 | width: 100%; 36 | height: 100%; 37 | background-color: rgba(0, 0, 0, 0.25); 38 | display: none; 39 | } 40 | 41 | .main-title { 42 | text-transform: uppercase; 43 | font-size: 2.8rem; 44 | text-align: center; 45 | color: var(--bs-primary); 46 | margin-bottom: 2rem; 47 | } 48 | 49 | .disabled { 50 | pointer-events: none; 51 | opacity: 0.5; 52 | } 53 | -------------------------------------------------------------------------------- /Frontend-Tools/webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | 5 | module.exports = { 6 | entry: './index.js', 7 | output: { 8 | path: path.resolve(__dirname, 'dist'), 9 | filename: 'main.js', 10 | clean: true, 11 | }, 12 | mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.m?(js|jsx)$/, 17 | exclude: /node_modules/, 18 | use: { 19 | loader: 'babel-loader', 20 | options: { 21 | presets: [['@babel/preset-env', { targets: 'defaults' }]], 22 | }, 23 | }, 24 | }, 25 | ], 26 | }, 27 | plugins: [ 28 | new HtmlWebpackPlugin({ template: './index.html' }), 29 | new webpack.ProvidePlugin({ 30 | React: 'react', 31 | }), 32 | ], 33 | resolve: { 34 | extensions: ['', '.js', '.jsx'], 35 | }, 36 | externals: { 37 | react: 'React', 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /DSA/dynamic-programming.js: -------------------------------------------------------------------------------- 1 | // Dynamic programing (Quy hoạch động) là một cách thức (tư duy) lập trình tái sử dụng lại kết quả mà không cần phải thực hiện lại việc tính toán phức tạp. 2 | 3 | const fibonacciByRecursion = n => { 4 | if (n <= 2) return 1; 5 | return fibonacciByRecursion(n - 1) + fibonacciByRecursion(n - 2); 6 | }; 7 | 8 | const fibonacciByMemoizeCache = (n, fibs = [0, 1, 1]) => { 9 | if (fibs[n]) return fibs[n]; 10 | fibs[n] = 11 | fibonacciByMemoizeCache(n - 1, fibs) + fibonacciByMemoizeCache(n - 2, fibs); 12 | return fibs[n]; 13 | }; 14 | 15 | let result, 16 | n = 40; 17 | 18 | // 4.036 ms ~ O(n) 19 | console.time('fibonacciByMemoizeCache'); 20 | result = fibonacciByMemoizeCache(n); 21 | console.log(`fibonacci(${n}) = ${result}`); 22 | console.timeEnd('fibonacciByMemoizeCache'); 23 | 24 | // 844.848ms ~ O(2^n) 25 | console.time('fibonacciByRecursion'); 26 | result = fibonacciByRecursion(n); 27 | console.log(`fibonacci(${n}) = ${result}`); 28 | console.timeEnd('fibonacciByRecursion'); 29 | -------------------------------------------------------------------------------- /PHP/basic-syntax/3-data-type.php: -------------------------------------------------------------------------------- 1 | 1, "tuan" => 2]; 26 | $associativeArr['dyno']; //1 27 | var_dump($arr); 28 | echo $arr[0]; 29 | 30 | // Object & Classes 31 | class Person 32 | { 33 | public $name; 34 | private $age; 35 | 36 | function __construct($name, $age) 37 | { 38 | $this->name = $name; 39 | $this->age = $age; 40 | } 41 | 42 | public function getAge() 43 | { 44 | return $this->age; 45 | } 46 | } 47 | 48 | $person = new Person('Dyno', 18); 49 | var_dump($person); 50 | echo $person->name; 51 | echo $person->getAge(); 52 | -------------------------------------------------------------------------------- /PHP/basic-syntax/form/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Form 9 | 10 | 11 | 12 |
13 |

GET FORM

14 | 15 | 16 | 17 |
18 | 19 |
20 |

POST FORM

21 | 22 | 23 | 24 |
25 | 26 |
27 |

REQUEST FORM

28 | 29 | 30 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /Microservices/client/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | # Networks 4 | networks: 5 | default: 6 | external: 7 | name: metamarket_default 8 | 9 | # Services 10 | services: 11 | # PHP My Admin 12 | pma-service: 13 | image: phpmyadmin:5.1.3 14 | container_name: c-pma 15 | hostname: pma 16 | networks: 17 | - default 18 | ports: 19 | - 8080:80 20 | restart: always 21 | environment: 22 | - PMA_ARBITRARY=1 23 | 24 | # PHP FPM 25 | php-service: 26 | image: php:8.1.4-fpm 27 | container_name: c-php 28 | hostname: php 29 | networks: 30 | - default 31 | volumes: 32 | - ./src:/src 33 | 34 | # Apache 35 | apache-service: 36 | image: httpd:2.4.53 37 | container_name: c-httpd 38 | networks: 39 | - default 40 | volumes: 41 | - ./src:/src 42 | - ../docker-configs/httpd.conf:/usr/local/apache2/conf/httpd.conf 43 | restart: always 44 | ports: 45 | - 80:80 46 | - 443:443 47 | depends_on: 48 | - php-service 49 | -------------------------------------------------------------------------------- /Microservices/client/src/core/Controller.php: -------------------------------------------------------------------------------- 1 | data['viewPath'] = $viewPath; 32 | $this->data['pageTitle'] = $pageTitle; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Docker/docker_demo/code/index.php: -------------------------------------------------------------------------------- 1 | setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 14 | echo "Connected successfully"; 15 | 16 | $sql = "SELECT * FROM Student"; 17 | $statement = $conn->query($sql); 18 | $students = $statement->fetchAll(PDO::FETCH_ASSOC); 19 | 20 | // display the publisher name 21 | echo "
    "; 22 | foreach ($students as $student) { 23 | echo "
  • "; 24 | echo $student['id'] . '
    '; 25 | echo $student['name'] . '
    '; 26 | echo $student['email'] . '
    '; 27 | echo "
  • "; 28 | } 29 | echo "
"; 30 | } catch (PDOException $e) { 31 | echo "Connection failed: " . $e->getMessage(); 32 | } 33 | -------------------------------------------------------------------------------- /PHP/basic-syntax/2-basic-syntax.php: -------------------------------------------------------------------------------- 1 |

Variable x in inside function: $x

"; 16 | } 17 | localScope(); 18 | echo "

Variable x in outside function: $x

"; 19 | 20 | // Global keyword 21 | function localScopeWithGlobalKeyword() 22 | { 23 | global $x; // $GLOBALS['x'] 24 | echo "

Variable x with global keyword in inside function: $x

"; 25 | } 26 | 27 | // Static keyword 28 | function testStatic() 29 | { 30 | static $staticVar = 1; 31 | echo $staticVar; 32 | ++$staticVar; 33 | } 34 | testStatic(); 35 | testStatic(); 36 | testStatic(); 37 | 38 | // echo và print, var_dum 39 | // echo - no return, print - return int, var_dum in ra cả kiểu dữ liệu 40 | echo 'Hello ' . $myName . ' Ahihi'; 41 | print 'Hello ' . $myName . ' Ahihi'; 42 | var_dump('Hello ' . $myName . ' Ahihi'); 43 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/add-club.js: -------------------------------------------------------------------------------- 1 | const MAX_CLUB_NAME = 50; 2 | const MAX_CLUB_SHORTNAME = 10; 3 | 4 | function showError(msg = '') { 5 | $('#errorWrap').removeClass('d-none').addClass('d-flex flex-column'); 6 | $('#errorMsg').text(msg); 7 | } 8 | 9 | jQuery(function () { 10 | $('#form').on('submit', function (e) { 11 | e.preventDefault(); 12 | 13 | const ClubName = $('#ClubName').val().trim(); 14 | const Shortname = $('#Shortname').val().trim(); 15 | const StadiumID = $('#StadiumID').val(); 16 | const CoachID = $('#CoachID').val(); 17 | 18 | if (!ClubName) return showError('Vui lòng nhập tên CLB'); 19 | if (!Shortname) return showError('Vui lòng nhập tên viết tắt của CLB'); 20 | if (!StadiumID) return showError('Vui lòng chọn SVĐ'); 21 | if (!CoachID) return showError('Vui lòng chọn HLV'); 22 | 23 | if (ClubName > MAX_CLUB_NAME) 24 | return showError(`Tên CLB tối đa ${MAX_CLUB_NAME} ký tự`); 25 | if (Shortname > MAX_CLUB_SHORTNAME) 26 | return showError(`Tên viết tắt CLB tối đa ${MAX_CLUB_SHORTNAME} ký tự`); 27 | 28 | this.submit(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /PHP/mvc/app/controllers/Home.php: -------------------------------------------------------------------------------- 1 | showSessionMessage(); 7 | $this->setPageTitle('Trang chủ'); 8 | $this->appendCssLink('home.css'); 9 | $this->renderToLayout('home'); 10 | $this->setLayout('general'); 11 | } 12 | 13 | public function introPage() 14 | { 15 | $rootDir = _DIR_ROOT; 16 | $introPageDir = str_replace('18120634_Football', '18120634_CV', $rootDir); 17 | 18 | $htmlContent = file_get_contents($introPageDir . "/18120634.html"); 19 | $cssContent = file_get_contents($introPageDir . "/css/style.css"); 20 | $avtSrc = 'data:image/png' . ';base64,' . base64_encode(file_get_contents($introPageDir . "/images/avatar.png")); 21 | 22 | $htmlContent .= ""; 23 | $htmlContent = str_replace('"./images/avatar.png"', $avtSrc, $htmlContent); 24 | $htmlContent = str_replace('', '', $htmlContent); 25 | echo $htmlContent; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Microservices/client/src/app/controllers/Home.php: -------------------------------------------------------------------------------- 1 | setBasicData('home/index', 'Trang chủ'); 7 | $this->render('layouts/main-layout', $this->data); 8 | 9 | $curl = curl_init(); 10 | curl_setopt($curl, CURLOPT_URL, "http://c-gateway/user-service/list"); 11 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 12 | $users = curl_exec($curl); 13 | $err = curl_error($curl); 14 | echo $err; 15 | 16 | $curl = curl_init(); 17 | curl_setopt($curl, CURLOPT_URL, "http://c-gateway/product-service/list"); 18 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 19 | $products = curl_exec($curl); 20 | $err = curl_error($curl); 21 | echo $err; 22 | 23 | echo "

Dữ liệu lấy từ 'User Service' nè

"; 24 | echo '
';
25 |         print_r($users);
26 |         echo '
'; 27 | 28 | echo "

Dữ liệu lấy từ 'Product Service' nè

"; 29 | echo '
';
30 |         print_r($products);
31 |         echo '
'; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Microservices/client/src/app/views/layouts/main-layout.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <?php echo !empty($pageTitle) ? $pageTitle : "Trang Chủ" ?> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | render('blocks/header'); ?> 18 | 19 | render($viewPath, isset($viewContent) ? $viewContent : []); ?> 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/login.js: -------------------------------------------------------------------------------- 1 | const MAX_LEN_NAME = 50; 2 | const MAX_LEN_PASSWORD = 100; 3 | 4 | function showFormError(msg = '') { 5 | $('#formError').html(msg).removeClass('d-none'); 6 | } 7 | 8 | jQuery(function () { 9 | $('#form').on('submit', function (e) { 10 | e.preventDefault(); 11 | 12 | const name = $('#name').val()?.trim(); 13 | const password = $('#password').val()?.trim(); 14 | 15 | if (name.length > MAX_LEN_NAME) { 16 | return showFormError(`Tên tối đa ${MAX_LEN_NAME} ký tự !`); 17 | } 18 | 19 | if (!password) { 20 | return showFormError('Vui lòng nhập mật khẩu !'); 21 | } 22 | 23 | if (password.length > MAX_LEN_PASSWORD) { 24 | return showFormError(`Mật khẩu tối đa ${MAX_LEN_PASSWORD} ký tự !`); 25 | } 26 | 27 | this.submit(); 28 | }); 29 | 30 | $('.password-icon').on('click', function () { 31 | if ($(this).hasClass('bi-eye-slash-fill')) { 32 | $(this).removeClass('bi-eye-slash-fill').addClass('bi-eye-fill'); 33 | $(this).siblings('input').attr('type', 'text'); 34 | } else { 35 | $(this).removeClass('bi-eye-fill').addClass('bi-eye-slash-fill'); 36 | $(this).siblings('input').attr('type', 'password'); 37 | } 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /Microservices/gateway/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${GATEWAY_PORT:9000} 3 | 4 | eureka: 5 | client: 6 | register-with-eureka: true 7 | fetch-registry: true 8 | service-url: 9 | defaultZone: ${DISCOVERY_URL:http://localhost:8761/eureka} 10 | instance: 11 | hostname: ${INSTANCE_HOSTNAME:localhost} 12 | 13 | spring: 14 | application: 15 | name: gateway-service 16 | cloud: 17 | gateway: 18 | globalcors: 19 | cors-configurations: 20 | '[/**]': 21 | allowedOrigins: '*' 22 | allowedMethods: 23 | - GET 24 | - POST 25 | - DELETE 26 | - PUT 27 | - PATCH 28 | - OPTION 29 | routes: 30 | - id: user-service 31 | uri: http://c-userservice 32 | filters: 33 | - RewritePath=/user-service,/ 34 | predicates: 35 | - Path=/user-service/** 36 | 37 | - id: product-service 38 | uri: http://c-productservice 39 | filters: 40 | - RewritePath=/product-service,/ 41 | predicates: 42 | - Path=/product-service/** 43 | -------------------------------------------------------------------------------- /Typescript/lessons/5-class.ts: -------------------------------------------------------------------------------- 1 | class Student { 2 | public name: string; 3 | private avg: number = 0; // gán giá trị mặc định 4 | protected gender: boolean; 5 | readonly id: string; 6 | 7 | constructor(n: string, a: number, g: boolean, id: string) { 8 | this.name = n; 9 | this.avg = a; 10 | this.gender = g; 11 | this.id = id; 12 | } 13 | } 14 | 15 | // create an instance 16 | const student = new Student('Dyno', 18, true, '1'); 17 | console.log(student); 18 | console.log(typeof student); // object 19 | console.log(student instanceof Student); // true 20 | 21 | console.log(student.id); 22 | console.log(student.name); 23 | 24 | console.log(student.avg); // không thễ truy cập vào private và protected từ bên ngoài 25 | console.log(student.gender); 26 | 27 | student.id = 1; // không thể thay đổi thuộc tính readonly 28 | 29 | /* -------------------------------- 30 | --------------- Khai báo ngắn hơn --------------- 31 | -------------------------------- */ 32 | 33 | class Person { 34 | constructor( 35 | public name: string, 36 | private age: number, 37 | protected gender: boolean, 38 | readonly id: string, 39 | ) {} 40 | } 41 | 42 | const person = new Person('Dyno', 18, true, '123'); 43 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/blocks/header.php: -------------------------------------------------------------------------------- 1 |
2 | 29 |
-------------------------------------------------------------------------------- /Microservices/docker-configs/my.cnf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | # 17 | # The MySQL Server configuration file. 18 | # 19 | # For explanations see 20 | # http://dev.mysql.com/doc/mysql/en/server-system-variables.html 21 | 22 | [mysqld] 23 | pid-file = /var/run/mysqld/mysqld.pid 24 | socket = /var/run/mysqld/mysqld.sock 25 | datadir = /var/lib/mysql 26 | secure-file-priv= NULL 27 | 28 | # Custom config should go here 29 | !includedir /etc/mysql/conf.d/ 30 | 31 | default-authentication-plugin=mysql_native_password -------------------------------------------------------------------------------- /PHP/mvc/app/views/home.php: -------------------------------------------------------------------------------- 1 | '/danh-sach-cau-thu', 'icon' => 'bi bi-card-list', 'label' => 'Danh sách cầu thủ'], 4 | ['to' => '/danh-sach-clb', 'icon' => 'bi bi-card-checklist', 'label' => 'Danh sách câu lạc bộ'], 5 | ['to' => '/tim-kiem-cau-thu', 'icon' => 'bi bi-search', 'label' => 'Tìm kiếm cầu thủ'], 6 | ['to' => '/them-cau-thu', 'icon' => 'bi bi-plus-square', 'label' => 'Thêm cầu thủ'], 7 | ['to' => '/them-clb', 'icon' => 'bi bi-plus-circle', 'label' => 'Thêm câu lạc bộ'], 8 | ['to' => '/dang-nhap', 'icon' => 'bi bi-box-arrow-in-right', 'label' => 'Đăng nhập'], 9 | ['to' => '/gioi-thieu', 'icon' => 'bi bi-info-circle', 'label' => 'Giới thiệu'], 10 | ]; 11 | ?> 12 | 13 |
14 |
    15 | $to, 'icon' => $icon, 'label' => $label] = $menuItem; 18 | 19 | echo "
  • 20 | 21 | 22 | $label 23 | 24 |
  • "; 25 | } 26 | ?> 27 | 28 |
29 |
-------------------------------------------------------------------------------- /Docker/docker-compose-example/my.cnf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | # 17 | # The MySQL Server configuration file. 18 | # 19 | # For explanations see 20 | # http://dev.mysql.com/doc/mysql/en/server-system-variables.html 21 | 22 | [mysqld] 23 | pid-file = /var/run/mysqld/mysqld.pid 24 | socket = /var/run/mysqld/mysqld.sock 25 | datadir = /var/lib/mysql 26 | secure-file-priv= NULL 27 | 28 | # Custom config should go here 29 | !includedir /etc/mysql/conf.d/ 30 | 31 | default-authentication-plugin=mysql_native_password 32 | -------------------------------------------------------------------------------- /DSA/recursion.js: -------------------------------------------------------------------------------- 1 | // Recursion (Đệ quy) là cách thức thực thi một hàm và gọi lại chính nó cho đến khi gặp điều kiện dừng. 2 | 3 | // Đệ quy rất hiệu quả trong nhiều trường hợp, có thể thay thế tốt cho vòng lặp. Tuy nhiên, nhiều trường hợp đệ quy gây lãng phí bộ nhớ và chậm chương trình (có thể crash - stack overflow). 4 | 5 | /* 6 | Đệ quy cần có 2 yếu tố: 7 | - Điều kiện dừng: ở đk nhất định, function sẽ trả về kết quả hoặc dùng mà không cần gọi đệ quy 8 | - hàm đệ quy 9 | */ 10 | 11 | function fibonacciByLoop(n) { 12 | if (n <= 2) return 1; 13 | let fib1 = 1, 14 | fib2 = 1, 15 | fib = 0; 16 | for (let i = 3; i <= n; ++i) { 17 | fib = fib1 + fib2; 18 | fib1 = fib2; 19 | fib2 = fib; 20 | } 21 | return fib; 22 | } 23 | 24 | function fibonacciByRecursion(n) { 25 | // Điều kiện dừng 26 | if (n <= 2) return 1; 27 | 28 | // Hàm đệ quy 29 | return fibonacciByRecursion(n - 1) + fibonacciByRecursion(n - 2); 30 | } 31 | 32 | let result, 33 | n = 40; 34 | 35 | // 3.376 ms ~ O(n) 36 | console.time('fibonacciByLoop'); 37 | result = fibonacciByLoop(n); 38 | console.log(`fibonacci(${n}) = ${result}`); 39 | console.timeEnd('fibonacciByLoop'); 40 | 41 | // 875.69 ms ~ O(2^n) 42 | console.time('fibonacciByRecursion'); 43 | result = fibonacciByRecursion(n); 44 | console.log(`fibonacci(${n}) = ${result}`); 45 | console.timeEnd('fibonacciByRecursion'); 46 | -------------------------------------------------------------------------------- /PHP/mvc/core/MySQLConnection.php: -------------------------------------------------------------------------------- 1 | 'SET NAMES utf8', 20 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION 21 | ]; 22 | 23 | $this->conn = new PDO($dsn, $db_config['username'], $db_config['password'], $options); 24 | } 25 | } 26 | } catch (Exception $ex) { 27 | $msg = $ex->getMessage(); 28 | exit($msg); 29 | } 30 | } 31 | 32 | public static function getConnect(): PDO | null 33 | { 34 | if (!self::$instance) { 35 | self::$instance = new MySQLConnection(); 36 | } 37 | return self::$instance->conn; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Typescript/lessons/3-funciton.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------- 2 | --------------- Khai báo hàm và Function Signature --------------- 3 | -------------------------------- */ 4 | function funcName(param1: string, param2?: number): number { 5 | return 0; 6 | } 7 | 8 | const funcName2 = (param: number): number => param * 2; 9 | 10 | let funcName3: Function; 11 | funcName3 = () => console.log('Hello'); 12 | 13 | // Function signature (Khai báo 1 function như chưa định nghĩa) 14 | let sayHelloFunction: (msg: string) => void; 15 | sayHelloFunction = (msg: string) => console.log(msg); 16 | 17 | /* -------------------------------- 18 | --------------- Kiểu trả về cho hàm --------------- 19 | -------------------------------- */ 20 | // Nếu function không khai báo kiểu trả về thì nó mặc định là void 21 | function returnVoidValueFunc(param: any) {} 22 | // tương đương 23 | function returnVoidValueFunc2(param: any): void {} 24 | 25 | // Hoặc function sẽ tự lấy kiểu ngầm định dựa trên kết quả tính toán 26 | const implicitFunc = (num1: number, num2: number) => num1 * num2; // => type: number 27 | 28 | /* -------------------------------- 29 | --------------- Optional param & default param --------------- 30 | -------------------------------- */ 31 | 32 | // Optional parameter ? 33 | const add = (a: number, b: number, c?: number): number => a + b + c; 34 | 35 | // Default parameter 36 | const add2 = (a: number, b: number = 5) => a + b; 37 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/css/login.css: -------------------------------------------------------------------------------- 1 | #form { 2 | padding: 2.8rem 2.4rem; 3 | background-color: #fff; 4 | max-width: 42rem; 5 | margin: 0 auto; 6 | box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; 7 | } 8 | 9 | .form-error { 10 | color: var(--bs-danger); 11 | font-size: 1.6rem; 12 | } 13 | 14 | #form .form-control { 15 | margin-bottom: 1.2rem; 16 | padding: 0.75rem 1rem; 17 | font-size: 1.5rem; 18 | } 19 | 20 | #form .form-control::-webkit-input-placeholder { 21 | color: var(--mm-gray); 22 | } 23 | 24 | #form .form-control::-moz-placeholder { 25 | color: var(--mm-gray); 26 | } 27 | 28 | #form .form-control:-ms-input-placeholder { 29 | color: var(--mm-gray); 30 | } 31 | 32 | #form .form-control::-ms-input-placeholder { 33 | color: var(--mm-gray); 34 | } 35 | 36 | #form .form-control::placeholder { 37 | color: var(--mm-gray); 38 | } 39 | 40 | #submitBtn { 41 | width: 100%; 42 | padding: 0.75rem 1rem; 43 | font-size: 1.5rem; 44 | border-radius: 6px; 45 | text-transform: capitalize; 46 | } 47 | 48 | .password-field { 49 | position: relative; 50 | } 51 | 52 | .password-field input { 53 | padding: 0.75rem 3rem 0.75rem 1rem !important; 54 | } 55 | 56 | .password-field i { 57 | position: absolute; 58 | right: 1rem; 59 | top: 50%; 60 | transform: translateY(calc(-50% + 0.2rem)); 61 | font-size: 1.6rem; 62 | color: var(--mm-gray); 63 | cursor: pointer; 64 | } 65 | 66 | .password-field i.bi-eye-fill { 67 | color: var(--bs-info); 68 | } 69 | -------------------------------------------------------------------------------- /Docker/docker_demo/note/step.sh: -------------------------------------------------------------------------------- 1 | # Các image cần thiết 2 | docker pull httpd:2.4.53 3 | docker pull php:8.1.4-fpm 4 | docker pull mysql:8.0.28 5 | docker pull phpmyadmin:5.1.3 6 | 7 | # Tạo network chung cho app 8 | docker network create --driver bridge www-net 9 | 10 | # Tạo volume chứa code 11 | docker volume create --opt device="$(pwd)"/code --opt type=none --opt o=bind v-code 12 | 13 | ############# MySQL Service 14 | docker run -d --name c-mysql --network www-net -v "$(pwd)"/db:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234 mysql:8.0.28 15 | 16 | ############ PHP My Admin 17 | docker run --name c-pma --network www-net -d -e PMA_ARBITRARY=1 -p 8080:80 phpmyadmin:5.1.3 18 | 19 | ############# PHP Service 20 | docker run -d --name c-php -h php -v v-code:/code --network www-net php:8.1.4-fpm 21 | docker exec -it c-php /bin/bash -c "docker-php-ext-install mysqli && docker-php-ext-install pdo_mysql" 22 | docker restart c-php 23 | 24 | ############## Apache Service 25 | # Lấy file apache config ra 26 | docker run --rm -v "$(pwd)"/configs:/app httpd:2.4.53 cp /usr/local/apache2/conf/httpd.conf /app 27 | 28 | # Chỉnh sửa file config 29 | # Enable module mod_proxy mod_proxy_fcgi, mod_rewrite.so 30 | # Chỉnh RootDicrectory về /code 31 | # Enable AllowOverride : None -> All 32 | # DirectoryIndex thêm index.php 33 | # AddHandler "proxy:fcgi://c-php:9000" .php 34 | 35 | # Start apache 36 | docker run --name c-httpd -h httpd -d -v v-code:/code -v "$(pwd)"/configs/httpd.conf:/usr/local/apache2/conf/httpd.conf --network www-net -p 80:80 -p 443:443 httpd:2.4.53 -------------------------------------------------------------------------------- /Docker/docker-machine.md: -------------------------------------------------------------------------------- 1 | # Docker Machine (DM) 2 | 3 | > **Docker Machine** là một provisioning tool giúp dễ dàng tiếp cận Docker. DM giúp tạo các máy ảo chạy Docker độc lập trên Virtual Machine. 4 | 5 | > **Docker Machine** sẽ tạo các máy ảo và cài Docker Engine lên chúng và cuối cùng nó sẽ cấu hình Docker Client để giao tiếp với Docker Engine một cách bảo mật. 6 | 7 | > Tải docker-machine cho Arch Linu 8 | 9 | ``` 10 | sudo pacman -S docker-machine 11 | ``` 12 | 13 | Nếu Docker Machine không thể tạo do lỗi config IP thì sửa như sau: 14 | 15 | ``` 16 | sudo mkdir /etc/vbox 17 | sudo vi /etc/vbox/networks.conf 18 | 19 | * 0.0.0.0/0 ::/0 20 | ``` 21 | 22 | # Command 23 | 24 | > Tạo DM 25 | 26 | ```Dockerfile 27 | docker-machine create -driver 28 | # Ex 29 | docker-machine create -driver virtualbox vps0 30 | docker-machine create -driver hyperv vps0 31 | ``` 32 | 33 | > Xóa DM 34 | 35 | ```Dockerfile 36 | docker-machine rm 37 | ``` 38 | 39 | > Liệt kê danh sách DM 40 | 41 | ```Dockerfile 42 | docker-machine ls 43 | ``` 44 | 45 | > Stop & Start 46 | 47 | ```Dockerfile 48 | docker-machine start/stop 49 | ``` 50 | 51 | > SSH vào docker machine 52 | 53 | ``` 54 | docker-machine ssh 55 | ``` 56 | 57 | > Chia sẻ dữ liệu giữa máy host và docker machine 58 | 59 | ``` 60 | docker-machine scp [-r] : 61 | docker-machine scp [-r] : 62 | ``` 63 | 64 | > Xem IP của 1 DM 65 | 66 | ``` 67 | docker-machine ip 68 | ``` 69 | -------------------------------------------------------------------------------- /Docker/docker_demo/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | # Networks 4 | 5 | networks: 6 | www-net: 7 | driver: bridge 8 | 9 | # volumes: 10 | # v-code: 11 | # driver_opts: 12 | # type: 'none' 13 | # o: 'bind' 14 | # device: /home/dyno/docker_demo/code 15 | 16 | # Services 17 | services: 18 | # MySQL 19 | mysql-service: 20 | image: mysql:8.0.28 21 | container_name: c-mysql 22 | hostname: mysql 23 | networks: 24 | - www-net 25 | volumes: 26 | - ./db:/var/lib/mysql 27 | ports: 28 | - 3306:3306 29 | environment: 30 | - MYSQL_ROOT_PASSWORD=1234 31 | 32 | # PHP My Admin 33 | pma-service: 34 | image: phpmyadmin:5.1.3 35 | container_name: c-pma 36 | hostname: pma 37 | networks: 38 | - www-net 39 | ports: 40 | - 8080:80 41 | restart: always 42 | environment: 43 | - PMA_ARBITRARY=1 44 | 45 | # PHP FPM 46 | php-service: 47 | build: 48 | dockerfile: Dockerfile 49 | context: . 50 | container_name: c-php 51 | hostname: php 52 | networks: 53 | - www-net 54 | volumes: 55 | - ./code:/code 56 | 57 | # Apache 58 | apache-service: 59 | image: httpd:2.4.53 60 | container_name: c-httpd 61 | networks: 62 | - www-net 63 | volumes: 64 | - ./code:/code 65 | - ./configs/httpd.conf:/usr/local/apache2/conf/httpd.conf 66 | restart: always 67 | ports: 68 | - 80:80 69 | - 443:443 70 | depends_on: 71 | - mysql-service 72 | - php-service 73 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/club-list.js: -------------------------------------------------------------------------------- 1 | let page = 1; 2 | const pageSize = typeof PAGE_SIZE !== 'undefined' ? Number(PAGE_SIZE) : 10; 3 | const totalPage = typeof TOTAL_PAGE !== 'undefined' ? Number(TOTAL_PAGE) : 1; 4 | 5 | function renderClubs(clubs = []) { 6 | let xml = ''; 7 | clubs.forEach((club) => { 8 | xml += ` 9 | ${club.ClubID} 10 | ${club.ClubName} 11 | ${club.Shortname} 12 | ${club.StadiumName} 13 | ${club.CoachName} 14 | 15 | 16 | 17 | 18 | 19 | 20 | `; 21 | }); 22 | $('tbody').append(xml); 23 | } 24 | 25 | jQuery(function () { 26 | $('#loadMore').on('click', async function () { 27 | if (page < totalPage) { 28 | $(this).addClass('disabled'); 29 | $(this).find('span').html('Đang tải dữ liệu ...'); 30 | 31 | const apiRes = await fetch( 32 | `${location.origin}/danh-sach-clb-api?page=${page + 1}`, 33 | ); 34 | if (apiRes.status === 200) { 35 | const docs = await apiRes.json(); 36 | const clubs = docs.data; 37 | renderClubs(clubs); 38 | 39 | ++page; 40 | if (page >= totalPage) { 41 | $(this).parent('div').remove(); 42 | } else { 43 | $(this).removeClass('disabled'); 44 | $(this) 45 | .find('span') 46 | .html(`Xem thêm ${totalPage - page} trang`); 47 | } 48 | } 49 | } 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /Docker/docker-compose-example/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | # NETWORKS 4 | networks: 5 | www-net: 6 | driver: bridge 7 | 8 | # SERVICES 9 | services: 10 | # PHP container 11 | php-service: 12 | container_name: c-php 13 | hostname: php 14 | build: 15 | dockerfile: Dockerfile 16 | context: . 17 | networks: 18 | - www-net 19 | volumes: 20 | - ./www:/home/www 21 | - ./php.ini-development:/usr/local/etc/php/php.ini-development 22 | 23 | # Apache container 24 | apache-service: 25 | container_name: c-httpd 26 | image: httpd:latest 27 | hostname: httpd 28 | networks: 29 | - www-net 30 | restart: always 31 | volumes: 32 | - ../../PHP/mvc/:/home/www 33 | - ./httpd.conf:/usr/local/apache2/conf/httpd.conf 34 | ports: 35 | - 80:80 36 | - 8080:80 37 | - 443:443 38 | 39 | # MySQL container 40 | mysql-service: 41 | container_name: c-mysql 42 | image: mysql:latest 43 | hostname: mysql 44 | restart: always 45 | networks: 46 | - www-net 47 | volumes: 48 | - ./db:/var/lib/mysql 49 | - ./my.cnf:/etc/mysql/my.cnf 50 | environment: 51 | - MYSQL_ROOT_PASSWORD=2504 52 | - MYSQL_DATABASE=demo 53 | - MYSQL_USER=user01 54 | - MYSQL_PASSWORD=user01 55 | 56 | # PHP My Admin 57 | pma-service: 58 | container_name: c-pma 59 | image: phpmyadmin:latest 60 | hostname: pma 61 | restart: always 62 | networks: 63 | - www-net 64 | ports: 65 | - 3000:80 66 | environment: 67 | - PMA_ARBITRARY=1 68 | -------------------------------------------------------------------------------- /PHP/mvc/core/Model.php: -------------------------------------------------------------------------------- 1 | '', 6 | 'page' => 0, 7 | 'pageSize' => PAGE_SIZE, 8 | 'orderBy' => '', 9 | 'modelName' => '' 10 | ]) 11 | { 12 | ['query' => $query, 'page' => $page, 'pageSize' => $pageSize, 'orderBy' => $orderBy, 'modelName' => $modelName] = $options; 13 | try { 14 | $conn = MySQLConnection::getConnect(); 15 | $sqlCount = preg_replace('/(select).+(from)/i', "SELECT COUNT(*) FROM", $query); 16 | $sqlData = $query; 17 | 18 | if ($page > 0) { 19 | $skip = ($page - 1) * $pageSize; 20 | $sqlData = $query . " ORDER BY $orderBy LIMIT $pageSize OFFSET $skip"; 21 | } 22 | 23 | $st = $conn->prepare($sqlData); 24 | $st->setFetchMode(PDO::FETCH_CLASS, $modelName); 25 | $st->execute(); 26 | $data = $st->fetchAll(); 27 | 28 | $totalRecords = $conn->query($sqlCount)->fetchColumn(); 29 | $total = ceil($totalRecords / $pageSize); 30 | 31 | return [ 32 | 'page' => $page, 33 | 'pageSize' => $pageSize, 34 | 'total' => $total, 35 | 'data' => $data 36 | ]; 37 | } catch (Exception $ex) { 38 | throw new Exception($ex); 39 | } 40 | } 41 | 42 | public static function getNextID($table, $id) 43 | { 44 | $sql = "SELECT MAX($id) FROM $table"; 45 | $conn = MySQLConnection::getConnect(); 46 | $maxId = $conn->query($sql)->fetchColumn(); 47 | return $maxId + 1; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /PHP/basic-syntax/1-coding-convention.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | - Nếu bắt đầu file bằng Php thì không cần kết thúc với ?> 10 | - Kết thúc câu lệnh với dấu ; 11 | */ 12 | 13 | /* 14 | --- PHP CASE SENSITIVITY --- 15 | - Đối với keyword PHP không phân biệt hoa thường như ECHO, echo, Echo, if, else, ... 16 | - Tuy nhiên với biến thì có 17 | */ 18 | 19 | /* 20 | --- CODING CONVENTION --- 21 | - Tuân theo - PSR (PHP Standards Recommendation) bao gồm PRS-0, PSR-1, PSR-2, PRS-4 (Autoloader) 22 | 23 | - PRS-1 (https://www.php-fig.org/psr/psr-1/): 24 | + Code phải được viết trong cặp thẻ . 25 | + Code chỉ được sử dụng UTF-8 không có BOM (Byte Order Mark) 26 | + Mỗi một file PHP chỉ nên làm 1 nhiệm vụ duy nhất, tránh chồng chéo (gọi là side effect). 27 | + Với constants phải viết $CONSTANT_NAME 28 | + Tên method phải viết kiểu camelCase() 29 | + Tên biết thuộc tính có thể sử dụng tùy ý nhưng cần nhất quán trong cả package 30 | 31 | - PRS-2 (https://www.php-fig.org/psr/psr-2/) 32 | + Phải tuân thủ PSR-1 33 | + Sử dụng 4 khoảng trắng(spaces) để thụt dòng thay vì dùng tab. 34 | + Phải có 1 dòng trắng sau khi khai báo namespace và phải có 1 dòng trắng sau các khai báo use. 35 | + Kết thúc file phài là UNIX LF. 36 | + Thẻ đóng và mở của 1 hàm {} phải nằm riêng biệt trên một dòng. 37 | + Trước thẻ mở & đóng hàm {} thì không được có 1 dòng trắng. 38 | + Dùng single quote khi khai báo chụỗi. 39 | 40 | */ 41 | 42 | /* 43 | --- COMMENT --- 44 | - Single line: // or # 45 | - Multiple line: /* 46 | 47 | */ 48 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/search-player.php: -------------------------------------------------------------------------------- 1 |
2 |

Tìm kiếm cầu thủ

3 | 4 |
5 | 6 | 7 |
8 | 9 |
10 | 11 | 12 |
13 | 14 |

Kết quả tìm kiếm

15 | 16 |
17 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
IDHọ tênCLBNgày sinhVị tríQuốc tịchSố áo 34 |
35 |
Hãy nhập từ khoá để tìm kiếm
44 |
-------------------------------------------------------------------------------- /PHP/mvc/app/models/User.php: -------------------------------------------------------------------------------- 1 | prepare("CREATE TABLE IF NOT EXISTS $database.$table ($columns)"); 22 | return $st->execute(); 23 | } 24 | 25 | public static function initAdminUser() 26 | { 27 | $sql = "SELECT COUNT(*) FROM user WHERE userid = 1"; 28 | $conn = MySQLConnection::getConnect(); 29 | $st = $conn->prepare($sql); 30 | $st->execute(); 31 | 32 | $rowCount = $st->fetchColumn(); 33 | 34 | if ($rowCount === 0) { 35 | $userStatus = USER_STATUS['ACTIVE']; 36 | $password = 'admin'; 37 | $hashPwd = password_hash($password, PASSWORD_BCRYPT, ['cost' => 10]); 38 | $sql = "INSERT INTO user (userid, name, password, status) VALUES (1, 'admin', '$hashPwd', $userStatus)"; 39 | $st = $conn->prepare($sql); 40 | return $st->execute(); 41 | } 42 | } 43 | 44 | public static function findUserByName($name) 45 | { 46 | $sql = "SELECT * FROM user WHERE name = '$name' LIMIT 1"; 47 | $conn = MySQLConnection::getConnect(); 48 | $st = $conn->prepare($sql); 49 | $st->setFetchMode(PDO::FETCH_CLASS, static::class); 50 | $st->execute(); 51 | $user = $st->fetch(); 52 | return $user; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/add-player.js: -------------------------------------------------------------------------------- 1 | const MAX_FULL_NAME = 100; 2 | const MAX_PLAYER_NUMBER = 100; 3 | const MAX_POSITION = 50; 4 | const MAX_NATIONALITY = 50; 5 | const MIN_AGE = 8; 6 | 7 | function showError(msg = '') { 8 | $('#errorWrap').removeClass('d-none'); 9 | $('#errorMsg').text(msg); 10 | } 11 | 12 | function calcAge(DOB) { 13 | const yearNow = new Date().getFullYear(); 14 | const yearOfDOB = new Date(DOB).getFullYear(); 15 | return yearNow - yearOfDOB; 16 | } 17 | 18 | jQuery(function () { 19 | $('#form').on('submit', function (e) { 20 | e.preventDefault(); 21 | 22 | const FullName = $('#FullName').val().trim(); 23 | const DOB = $('#DOB').val(); 24 | const ClubID = $('#ClubID').val(); 25 | const Position = $('#Position').val().trim(); 26 | const Nationality = $('#Nationality').val().trim(); 27 | const PlayerNumber = $('#Number').val(); 28 | 29 | if (!FullName) return showError('Vui lòng nhập họ tên cầu thủ'); 30 | if (!DOB) return showError('Vui lòng nhập ngày sinh của cầu thủ'); 31 | if (!ClubID) return showError('Vui lòng chọn câu lạc bộ cầu thủ'); 32 | if (!Position) return showError('Vui lòng nhập vị trí đá cầu thủ'); 33 | if (!Nationality) return showError('Vui lòng nhập quốc tịch cầu thủ'); 34 | if (isNaN(PlayerNumber)) return showError('Vui lòng nhập số áo cầu thủ'); 35 | 36 | if (FullName.length > MAX_FULL_NAME) 37 | return showError(`Họ tên tối đa ${MAX_FULL_NAME} ký tự`); 38 | if (calcAge(DOB) < MIN_AGE) 39 | return showError(`Cầu thủ tối thiểu ${MIN_AGE} tuổi`); 40 | if (PlayerNumber < 0 || PlayerNumber > MAX_PLAYER_NUMBER) 41 | return showError(`Số áo tối thiểu 0 và tối đa ${MAX_PLAYER_NUMBER}`); 42 | if (Position.length > MAX_POSITION) 43 | return showError(`Vị trí tối đa ${MAX_POSITION} ký tự`); 44 | if (Nationality.length > MAX_NATIONALITY) 45 | return showError(`Quốc tịch tối đa ${MAX_NATIONALITY} ký tự`); 46 | 47 | this.submit(); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/search-player.js: -------------------------------------------------------------------------------- 1 | function renderSearchResult(players = []) { 2 | let xml = ''; 3 | 4 | if (players.length) { 5 | players.forEach((player) => { 6 | const { 7 | FullName, 8 | PlayerID, 9 | Nationality, 10 | Position, 11 | DOB, 12 | ClubName, 13 | Number: PlayerNumber, 14 | } = player; 15 | const dobStr = DOB ? new Date(DOB).getFullYear() : '_'; 16 | xml += ` 17 | ${PlayerID} 18 | ${FullName} 19 | ${ClubName} 20 | ${dobStr} 21 | ${Position} 22 | ${Nationality} 23 | ${PlayerNumber} 24 | 25 | `; 26 | }); 27 | } else { 28 | xml += 29 | "Không tìm thấy kết quả phù hợp"; 30 | } 31 | 32 | $('tbody').html(xml); 33 | onCheckboxChange(); 34 | } 35 | 36 | jQuery(function () { 37 | $('#searchBtn').on('click', async function () { 38 | const playerName = $('#name').val().trim(); 39 | const playerNumber = $('#number').val().trim(); 40 | const nationality = $('#nationality').val().trim(); 41 | 42 | if (!playerName && !playerNumber && !nationality) { 43 | return; 44 | } 45 | 46 | const url = new URL(`${location.origin}/tim-kiem-cau-thu-api`); 47 | if (playerName) url.searchParams.set('name', playerName); 48 | if (playerNumber) url.searchParams.set('number', playerNumber); 49 | if (nationality) url.searchParams.set('nationality', nationality); 50 | 51 | let searchResult = []; 52 | const apiRes = await fetch(url.href); 53 | if (apiRes.status === 200) { 54 | searchResult = await apiRes.json(); 55 | } 56 | 57 | $('#searchResultText').html( 58 | `Có ${searchResult.length} phù hợp cho từ khoá trên`, 59 | ); 60 | renderSearchResult(searchResult); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /Docker/README.md: -------------------------------------------------------------------------------- 1 | # Docker là gì ? 2 | 3 | > **Docker** là nền tảng phần mềm cho phép bạn dựng, kiểm thử và triển khai ứng dụng một cách nhanh chóng. 4 | 5 | > **Docker** đóng gói phần mềm vào các **Container** có mọi thứ mà phần mềm cần để chạy, trong đó có thư viện, công cụ hệ thống, code và thời gian chạy. 6 | 7 | > [Docker's Home Page](https://www.docker.com/), [Docker hub](https://hub.docker.com/) 8 | 9 | # Docker vs Virtual Machine 10 | 11 | > **Virtual Machine** chia tài nguyên máy ảo thành nhiều phần riêng biệt để cài một hệ điều hành lên đó (chạy như một máy thật). Điều đó làm lãng phí rất nhiều tài nguyên. 12 | 13 | > **Docker** chia sẻ tài nguyên và chạy trên chính hệ điều hành của máy chủ. Tiết kiệm và chạy nhanh hơn rất nhiều. 14 | 15 | > **VM** ảo hóa (virtualization) ở phần cứng (hardware level), còn **Docker** ảo hóa (containerization) ở tầng ứng dụng (app level). 16 | 17 | ![Docker VM](../assets/images/docker-vm.png) 18 | 19 | # Cài đặt Docker trên Arch Linux 20 | 21 | ```sh 22 | sudo pacman -S docker 23 | sudo systemctl start docker.service 24 | # Thêm người dùng hiện tại vào group docker 25 | usermod -aG docker $USER 26 | ``` 27 | 28 | > Chuyển nơi lưu trữ Image 29 | 30 | ```sh 31 | cp -r 32 | # Ex 33 | cp -r /var/lib/docker /mnt/docker 34 | 35 | # Configure data-root in /etc/docker/daemon.json 36 | { 37 | "data-root": "/mnt/docker" 38 | } 39 | 40 | ``` 41 | 42 | # Images, Containers là gì ? 43 | 44 | > **Image** là những phần mềm được đóng gói trong Docker, chỉ đọc, chứa các source code, libraries, dependencies, tools và các files khác cần thiết cho một ứng dụng để chạy. 45 | 46 | > **Image** đôi khi còn gọi là **Snapshot**. Chúng đại diện cho một application và virtual environment của nó tại một thời điểm cụ thể. Nó cho phép các developers test và thử nghiệm phần mềm trong điều kiện ổn định, thống nhất. **Image** là cơ sở để tạo dựng nên các **Container**. 47 | 48 | > **Container** là một **Run-time environment** được tạo từ các Image mà ở đó người dùng có thể chạy một ứng dụng độc lập. 49 | 50 | ![Image, Container](../assets/images/image-container.jpg) 51 | -------------------------------------------------------------------------------- /Microservices/discovery/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.6 9 | 10 | 11 | vn.metemarket 12 | discovery 13 | 0.0.1-SNAPSHOT 14 | discovery 15 | Eureka Discovery Server 16 | 17 | 17 18 | 2021.0.1 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-actuator 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter-netflix-eureka-server 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-devtools 33 | runtime 34 | true 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | 43 | 44 | 45 | org.springframework.cloud 46 | spring-cloud-dependencies 47 | ${spring-cloud.version} 48 | pom 49 | import 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /PHP/mvc/app/models/Club.php: -------------------------------------------------------------------------------- 1 | prepare('SELECT ClubID, ClubName FROM club'); 18 | $st->setFetchMode(PDO::FETCH_CLASS, static::class); 19 | $st->execute(); 20 | $clubs = $st->fetchAll(); 21 | return $clubs; 22 | } catch (Exception $ex) { 23 | error_log($ex); 24 | return []; 25 | } 26 | } 27 | 28 | public static function findAllClubs($page = 0, $pageSize = PAGE_SIZE, $orderBy = 'ClubID') 29 | { 30 | try { 31 | $sql = 'SELECT * FROM club AS c, coach AS co, stadium AS s WHERE c.CoachID = co.CoachID AND c.StadiumID = s.StadiumID'; 32 | $docs = self::pagination([ 33 | 'query' => $sql, 34 | 'page' => $page, 'pageSize' => $pageSize, 35 | 'orderBy' => $orderBy, 'modelName' => static::class 36 | ]); 37 | return $docs; 38 | } catch (Exception $ex) { 39 | error_log($ex); 40 | return []; 41 | } 42 | } 43 | 44 | public static function addClub($club) 45 | { 46 | try { 47 | [ 48 | 'ClubName' => $ClubName, 'Shortname' => $Shortname, 'StadiumID' => $StadiumID, 'CoachID' => $CoachID 49 | ] = $club; 50 | 51 | $ClubID = self::getNextID(self::$tableName, 'ClubID'); 52 | $sql = "INSERT INTO club (ClubID, ClubName, Shortname, StadiumID, CoachID) VALUES " 53 | . "($ClubID, '$ClubName', '$Shortname', '$StadiumID', $CoachID)"; 54 | 55 | $conn = MySQLConnection::getConnect(); 56 | $st = $conn->prepare($sql); 57 | $isSuccess = $st->execute(); 58 | return $isSuccess; 59 | } catch (Exception $ex) { 60 | throw new Exception($ex); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PHP/mvc/app/controllers/Account.php: -------------------------------------------------------------------------------- 1 | showSessionMessage(); 12 | $this->appendJSLink('login.js'); 13 | $this->appendCssLink('login.css'); 14 | $this->setPageTitle('Đăng nhập'); 15 | $this->renderToLayout('login'); 16 | $this->setLayout('general'); 17 | } else { 18 | self::redirect('/'); 19 | } 20 | } 21 | 22 | public function postLogin() 23 | { 24 | if (empty($_POST)) { 25 | $this->setSessionMessage('Đăng nhập thất bại', true); 26 | self::redirect('/dang-nhap'); 27 | } 28 | 29 | ['name' => $name, 'password' => $password] = $_POST; 30 | $user = UserModel::findUserByName($name); 31 | 32 | if (empty($user)) { 33 | $this->setSessionMessage('Tài khoản không tồn tại', true); 34 | self::redirect('/dang-nhap'); 35 | } 36 | 37 | $userPassword = $user->_get('password'); 38 | $isMatch = password_verify($password, $userPassword); 39 | if (!$isMatch) { 40 | $this->setSessionMessage('Mật khẩu không chính xác', true); 41 | self::redirect('/dang-nhap'); 42 | } 43 | 44 | $this->onLoginSuccess($user); 45 | $this->setSessionMessage('Đăng nhập thành công', false); 46 | self::redirect('/'); 47 | } 48 | 49 | public function logout() 50 | { 51 | unset($_SESSION['isAuth']); 52 | unset($_SESSION['user']); 53 | self::redirect('/'); 54 | } 55 | 56 | private static function initUserTable() 57 | { 58 | if (empty($_SESSION['isCreateUser'])) { 59 | UserModel::createTableIfNotExist(); 60 | UserModel::initAdminUser(); 61 | $_SESSION['isCreateUser'] = true; 62 | } 63 | } 64 | 65 | private function onLoginSuccess($user) 66 | { 67 | $_SESSION['isAuth'] = true; 68 | $_SESSION['user'] = ['userid' => $user->_get('userid'), 'name' => $user->_get('name')]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Microservices/gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.6 9 | 10 | 11 | vn.metemarket 12 | gateway 13 | 0.0.1-SNAPSHOT 14 | gateway 15 | Gateway Service 16 | 17 | 17 18 | 2021.0.1 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-actuator 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter-gateway 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-netflix-eureka-client 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-devtools 37 | runtime 38 | true 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-test 43 | test 44 | 45 | 46 | 47 | 48 | 49 | org.springframework.cloud 50 | spring-cloud-dependencies 51 | ${spring-cloud.version} 52 | pom 53 | import 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-maven-plugin 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/club-list.php: -------------------------------------------------------------------------------- 1 |
2 |

Danh sách câu lạc bộ

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | "; 19 | } else { 20 | foreach ($clubs as $club) { 21 | $stadiumName = empty($club->SName) ? $club->_get('StadiumID') : $club->SName; 22 | $coachName = empty($club->CFullName) ? $club->_get('CoachID') : $club->CFullName; 23 | $clubId = $club->_get('ClubID'); 24 | 25 | echo ""; 26 | echo ""; 27 | echo ""; 28 | echo ""; 29 | echo ""; 30 | echo ""; 31 | echo ""; 37 | echo ""; 38 | } 39 | } 40 | ?> 41 | 42 |
IDTênTên ngắnSân vận độngHuấn luyện viên
Không tìm thấy dữ liệu
" . $clubId . "" . $club->_get('ClubName') . "" . $club->_get('Shortname') . "" . $stadiumName . "" . $coachName . " 32 | 33 | 34 | 35 | 36 |
43 | 44 | 1) { ?> 45 |
46 | 47 | Xem thêm $restPage trang"; 50 | ?> 51 | 52 | 53 |
54 | 55 |
-------------------------------------------------------------------------------- /PHP/mvc/app/views/layouts/general.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | <?php echo !empty($pageTitle) ? $pageTitle : "Trang Chủ" ?> 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | "; 38 | } 39 | } 40 | ?> 41 | 42 | 43 | 44 | 45 |
46 | render('blocks/header'); ?> 47 |
48 | render($viewPath, isset($viewContent) ? $viewContent : []); ?> 49 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 62 | "; 63 | foreach ($passedVariables as $key => $value) { 64 | echo "const $key = '$value';"; 65 | } 66 | echo " 67 | "; 68 | } 69 | ?> 70 | "; 75 | } 76 | } 77 | ?> 78 | 79 | -------------------------------------------------------------------------------- /Microservices/services/productservice/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.6 9 | 10 | 11 | vn.metamarket 12 | productservice 13 | 0.0.1-SNAPSHOT 14 | productservice 15 | Product Service 16 | 17 | 17 18 | 2021.0.1 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter-netflix-eureka-client 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-devtools 33 | runtime 34 | true 35 | 36 | 37 | org.projectlombok 38 | lombok 39 | true 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-dependencies 52 | ${spring-cloud.version} 53 | pom 54 | import 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | org.projectlombok 68 | lombok 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Typescript/lessons/6-interface-type.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------- 2 | --------------- Interface --------------- 3 | -------------------------------- */ 4 | 5 | interface IPerson { 6 | name: string; 7 | age: number; 8 | gender: boolean; 9 | birthday?: Date; 10 | speak(lang: string): void; 11 | } 12 | 13 | const p: IPerson = { 14 | name: 'Dyno', 15 | age: 18, 16 | gender: true, 17 | speak: (lang: string) => { 18 | console.log(`Speak ${lang}`); 19 | }, 20 | }; 21 | 22 | // Một class có thể implement từ 1 hoặc nhiều Interface 23 | class Person2 implements IPerson { 24 | constructor( 25 | public name: string, 26 | public age: number, 27 | public gender: boolean, 28 | ) {} 29 | 30 | speak(lang: string): void { 31 | console.log(lang); 32 | } 33 | } 34 | 35 | /* -------------------------------- 36 | --------------- Type --------------- 37 | -------------------------------- */ 38 | type Shape = { 39 | name: string; 40 | color: string; 41 | }; 42 | 43 | /* -------------------------------- 44 | --------------- Sự khác nhau giữa Type và Interface --------------- 45 | -------------------------------- */ 46 | 47 | // 1. Interface tự merge còn Type thì không 48 | interface A { 49 | a: number; 50 | } 51 | interface A { 52 | b: string; 53 | } 54 | const instanceA: A = { 55 | a: 1, 56 | b: 'hello', 57 | }; 58 | 59 | // Duplicate identifier 'B' 60 | type B = { 61 | a: number; 62 | }; 63 | type B = { 64 | b: string; 65 | }; 66 | 67 | // 2. Type có thể sử dụng được với "Computed Properties" còn interface thì không 68 | type keys = 'color' | 'name'; 69 | 70 | type ComputedProp = { 71 | [key in keys]: string; 72 | }; 73 | const typeInstance: ComputedProp = { 74 | name: 'Red', 75 | color: '#ff0000', 76 | }; 77 | 78 | // A mapped type may not declare properties or methods 79 | interface IComputedProp { 80 | [key in keys]: string; 81 | } 82 | 83 | // 3. Tuple Type 84 | type Tuple = [number, number]; 85 | 86 | interface ITuple { 87 | 0: number; 88 | 1: number; 89 | } 90 | 91 | [1, 2, 3] as Tuple; // Conversion of type '[number, number, number]' to type '[number, number]' may be a mistake 92 | [1, 2, 3] as ITuple; // Ok 93 | 94 | // 4. Type có Unions type còn interface thì không 95 | type colors = 'blue' | 'green'; 96 | 97 | // 5. Cú pháp extends 98 | interface IAnimal { 99 | name: string; 100 | } 101 | 102 | interface IBear extends IAnimal { 103 | honey: boolean; 104 | } 105 | 106 | // Với Type sử dụng Intersection Types(&): 107 | type TAnimal = { 108 | name: string; 109 | }; 110 | 111 | type TBear = TAnimal & { 112 | honey: boolean; 113 | }; 114 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/add-club.php: -------------------------------------------------------------------------------- 1 |
2 |

Thêm câu lạc bộ

3 | 4 |
5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 26 |
27 |
28 | 29 | 39 |
40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 |
48 |
-------------------------------------------------------------------------------- /PHP/mvc/app/views/add-player.php: -------------------------------------------------------------------------------- 1 |
2 |

Thêm cầu thủ

3 | 4 |
5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 26 |
27 |
28 | 29 | 30 |
31 |
32 | 33 | 34 |
35 |
36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 |
-------------------------------------------------------------------------------- /Microservices/services/userservice/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.6 9 | 10 | 11 | vn.metemarket 12 | userservice 13 | 0.0.1-SNAPSHOT 14 | userservice 15 | User Service 16 | 17 | 17 18 | 2021.0.1 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-actuator 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-netflix-eureka-client 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-devtools 37 | runtime 38 | true 39 | 40 | 41 | mysql 42 | mysql-connector-java 43 | runtime 44 | 45 | 46 | org.projectlombok 47 | lombok 48 | true 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-test 53 | test 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.cloud 60 | spring-cloud-dependencies 61 | ${spring-cloud.version} 62 | pom 63 | import 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-maven-plugin 73 | 74 | 75 | 76 | org.projectlombok 77 | lombok 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /Typescript/lessons/8-utility-types.ts: -------------------------------------------------------------------------------- 1 | // Utility Types 2 | // https://www.typescriptlang.org/docs/handbook/utility-types.html 3 | 4 | /* -------------------------------- 5 | --------------- Partial --------------- 6 | -------------------------------- */ 7 | // Set all props of Type to optional 8 | interface Todo { 9 | title: string; 10 | description: string; 11 | } 12 | 13 | function updateTodo(todo: Todo, fieldsToUpdate: Partial) { 14 | return { ...todo, ...fieldsToUpdate }; 15 | } 16 | 17 | const todo1 = { 18 | title: 'organize desk', 19 | description: 'clear clutter', 20 | }; 21 | 22 | const todo2 = updateTodo(todo1, { 23 | description: 'throw out trash', 24 | }); 25 | 26 | /* -------------------------------- 27 | --------------- Required --------------- 28 | -------------------------------- */ 29 | // Set all props of Type to required 30 | 31 | interface Props { 32 | a?: number; 33 | b?: string; 34 | } 35 | 36 | const obj: Props = { a: 5 }; 37 | 38 | const obj2: Required = { a: 5 }; 39 | 40 | /* -------------------------------- 41 | --------------- Readonly --------------- 42 | -------------------------------- */ 43 | // Set all props of Type to readonly 44 | 45 | /* -------------------------------- 46 | --------------- Record --------------- 47 | -------------------------------- */ 48 | // Tạo ra 1 object mới với các keys là Keys và giá trị cho mỗi key đều là Type 49 | interface CatInfo { 50 | age: number; 51 | breed: string; 52 | } 53 | 54 | type CatName = 'miffy' | 'boris' | 'mordred'; 55 | 56 | const cats: Record = { 57 | miffy: { age: 10, breed: 'Persian' }, 58 | boris: { age: 5, breed: 'Maine Coon' }, 59 | mordred: { age: 16, breed: 'British Shorthair' }, 60 | }; 61 | 62 | /* -------------------------------- 63 | --------------- Pick --------------- 64 | -------------------------------- */ 65 | // Get some props with keys from Type 66 | interface Todo { 67 | title: string; 68 | description: string; 69 | completed: boolean; 70 | } 71 | 72 | type TodoPreview = Pick; 73 | 74 | const todo: TodoPreview = { 75 | title: 'Clean room', 76 | completed: false, 77 | }; 78 | 79 | /* -------------------------------- 80 | --------------- Omit --------------- 81 | -------------------------------- */ 82 | // Get all props except keys 83 | interface Todo { 84 | title: string; 85 | description: string; 86 | completed: boolean; 87 | createdAt: number; 88 | } 89 | 90 | type TodoPreview = Omit; 91 | 92 | const todo: TodoPreview = { 93 | title: 'Clean room', 94 | completed: false, 95 | createdAt: 1615544252770, 96 | }; 97 | 98 | /* -------------------------------- 99 | --------------- ReturnType --------------- 100 | -------------------------------- */ 101 | // Trả về kiểu dữ liệu cũa một hàm nào đó 102 | type T0 = ReturnType<() => string>; // T0 = string 103 | 104 | // ... 105 | -------------------------------------------------------------------------------- /PHP/basic-syntax/5-oop.php: -------------------------------------------------------------------------------- 1 | name = $name; 10 | $this->id = $id; 11 | } 12 | 13 | public function intro() 14 | { 15 | echo "My name is " . $this->name; 16 | } 17 | } 18 | 19 | $dyno = new Human("Dyno", "123", 9.5); 20 | 21 | // Extends 22 | class Student extends Human 23 | { 24 | private $avg; 25 | function __construct($name, $id, $avg) 26 | { 27 | parent::__construct($name, $id); 28 | $this->avg = $avg; 29 | } 30 | 31 | final public function get_avg() 32 | { 33 | return $this->avg; 34 | } 35 | } 36 | 37 | // Abstract class 38 | abstract class AbstractClass 39 | { 40 | public $x; 41 | public $y; 42 | 43 | // Only define method 44 | public function abstractMethod() 45 | { 46 | } 47 | } 48 | 49 | class ExtendAbsClass extends AbstractClass 50 | { 51 | function abstractMethod() 52 | { 53 | echo 'Implement the method'; 54 | } 55 | } 56 | 57 | $hihi = new ExtendAbsClass(); 58 | $hihi->abstractMethod(); 59 | 60 | // Interface 61 | interface IAnimal 62 | { 63 | public function speak(): void; 64 | public function isDead(): bool; 65 | } 66 | 67 | class Cat implements IAnimal 68 | { 69 | private $status; 70 | public function speak(): void 71 | { 72 | echo "meow meow"; 73 | } 74 | 75 | public function isDead(): bool 76 | { 77 | return $this->status; 78 | } 79 | } 80 | 81 | // Trait (cũng như interface nhưng có thể khởi tạo 1 instance với trait) 82 | trait Trait_1 83 | { 84 | public function say() 85 | { 86 | echo 'Hello'; 87 | } 88 | } 89 | 90 | trait Trait_2 91 | { 92 | public function eat() 93 | { 94 | echo 'Eating ...'; 95 | } 96 | } 97 | 98 | class ExtendTrait 99 | { 100 | use Trait_1; 101 | use Trait_2; 102 | } 103 | 104 | $traitTest = new ExtendTrait(); 105 | $traitTest->say(); 106 | $traitTest->eat(); 107 | 108 | // Khởi tạo class 1 lần, không tái sử dụng 109 | $useOnlyOnce = new class(1) 110 | { 111 | private $x; 112 | function __construct($a) 113 | { 114 | $this->x = $a; 115 | } 116 | public function getX() 117 | { 118 | return $this->x; 119 | } 120 | }; 121 | 122 | echo $useOnlyOnce->getX(); 123 | 124 | // self và this 125 | class A 126 | { 127 | public function test() 128 | { 129 | echo "Test của A"; 130 | } 131 | public function demo() 132 | { 133 | $this->test(); // gọi hàm test() của lớp kế thừa nếu có 134 | self::test(); // gọi hàm test() của A 135 | } 136 | } 137 | 138 | class B extends A 139 | { 140 | public function test() 141 | { 142 | echo "Test của B"; 143 | } 144 | } 145 | 146 | $b = new B(); 147 | $b->demo(); 148 | 149 | // final và static 150 | // cả 2 đều có thể sử dụng mà không cần khởi tạo instance thông qua tên lớp. Do chương trình chỉ tạo 1 lần khi chạy. 151 | // final không thể chỉnh sửa giá trị nhưng static thì có. -------------------------------------------------------------------------------- /Typescript/lessons/7-generic.ts: -------------------------------------------------------------------------------- 1 | // Generic Type 2 | type StrArray = Array; 3 | const arrStr: StrArray = ['hello', 'Dyno']; 4 | 5 | type NumberArray = Array; 6 | const arrNum: NumberArray = [1, 2, 3]; 7 | 8 | /* -------------------------------- 9 | --------------- Tạo 1 hàm vói Generic param --------------- 10 | -------------------------------- */ 11 | const genericFunc = (arr: Array) => { 12 | console.log(arr[arr.length - 1]); 13 | }; 14 | 15 | genericFunc([1, 2, 3]); 16 | genericFunc(['Hello', 'Dyno']); 17 | 18 | // Có thể có nhiều generic trong 1 hàm 19 | function genericFuncXY(x: X, y: Y): [X, Y] { 20 | console.log([x, y]); 21 | return [x, y]; 22 | } 23 | 24 | genericFuncXY(5, 'Hello'); 25 | genericFuncXY('Hello', 'Dyno'); 26 | 27 | // default generic 28 | function genericFuncDefault(x: X, y: Y) { 29 | return [x, y]; 30 | } 31 | 32 | genericFuncDefault('Hello', 1); 33 | genericFuncDefault('Hello', 'Dyno'); // Argument of type 'string' is not assignable to parameter of type 'number' 34 | 35 | /* -------------------------------- 36 | --------------- Generic Extends --------------- 37 | -------------------------------- */ 38 | const makeFullNameConstraint = (obj: { 39 | firstName: string; 40 | lastName: string; 41 | }) => { 42 | return { ...obj, fullname: `${obj.firstName} ${obj.lastName}` }; 43 | }; 44 | // Object truyền vào bắt buộc phải ;là { firstName và lastName } 45 | makeFullNameConstraint({ name: 'Dyno', age: 18 }); 46 | makeFullNameConstraint({ 47 | name: 'Dyno', 48 | age: 18, 49 | firstName: 'Dyno', 50 | lastName: 'Nguyen', 51 | }); 52 | // Ok 53 | makeFullNameConstraint({ firstName: 'Dyno', lastName: 'Nguyen' }); 54 | 55 | // Use generic extends 56 | const makeFullNameConstraintWithGeneric = < 57 | T extends { firstName: string; lastName: string }, 58 | >( 59 | obj: T, 60 | ) => { 61 | return { ...obj, fullname: `${obj.firstName} ${obj.lastName}` }; 62 | }; 63 | makeFullNameConstraintWithGeneric({ 64 | name: 'Dyno', 65 | age: 18, 66 | firstName: 'Dyno', 67 | lastName: 'Nguyen', 68 | }); 69 | // Generic extends rất cần thiết khi ta cần viết 1 hàm truyền vào 1 object và chưa biết chính xác nó có những gì. Nhưng chắc chắn nó phải có 1 vài thuộc tính nào đó cần trích xuất dề sử dụng. 70 | 71 | // Ex: 72 | const addNewEmployee = (emp: object) => { 73 | return { ...emp, uid: Date.now() }; 74 | }; 75 | const newEmp = addNewEmployee({ name: 'Dyno', age: 18 }); 76 | console.log(newEmp.uid); 77 | console.log(newEmp.name); // Do prop: "name" chỉ tồn tại khi nó khởi chạy 78 | 79 | // Dùng generic extends 80 | const addNewEmployeeT = (emp: T) => { 81 | return { ...emp, uid: Date.now() }; 82 | }; 83 | const newEmp2 = addNewEmployeeT({ name: 'Dyno', age: 18 }); 84 | console.log(newEmp2.uid); 85 | console.log(newEmp2.name); 86 | 87 | /* -------------------------------- 88 | --------------- Generic in Interface --------------- 89 | -------------------------------- */ 90 | 91 | interface APIData { 92 | id: string; 93 | name: string; 94 | data: T[]; 95 | } 96 | 97 | const apiData: APIData = { 98 | id: '123', 99 | name: 'name', 100 | data: ['1', '2'], 101 | }; 102 | -------------------------------------------------------------------------------- /Microservices/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | networks: 4 | default: 5 | driver: bridge 6 | 7 | services: 8 | # Discovery server 9 | discovery: 10 | image: maven:3.8.5-openjdk-17 11 | container_name: c-discovery 12 | hostname: discovery 13 | networks: 14 | - default 15 | volumes: 16 | - ./discovery:/src 17 | - ~/.m2:/root/.m2 18 | environment: 19 | - DISCOVERY_PORT=8761 20 | - INSTANCE_HOSTNAME=c-discovery 21 | ports: 22 | - 8761:8761 23 | entrypoint: ['bash', '-c', 'cd /src && mvn spring-boot:run'] 24 | 25 | # Gateway service 26 | gateway: 27 | image: maven:3.8.5-openjdk-17 28 | container_name: c-gateway 29 | hostname: gateway 30 | networks: 31 | - default 32 | volumes: 33 | - ./gateway:/src 34 | - ~/.m2:/root/.m2 35 | environment: 36 | - DISCOVERY_URL=http://c-discovery:8761/eureka 37 | - GATEWAY_PORT=80 38 | - INSTANCE_HOSTNAME=c-discovery 39 | ports: 40 | - 9000:80 41 | entrypoint: ['bash', '-c', 'cd /src && mvn spring-boot:run'] 42 | depends_on: 43 | - discovery 44 | 45 | ############# SERVICE API ############# 46 | # User service 47 | user-service: 48 | image: maven:3.8.5-openjdk-17 49 | container_name: c-userservice 50 | hostname: userserivce 51 | networks: 52 | - default 53 | volumes: 54 | - ./services/userservice:/src 55 | - ~/.m2:/root/.m2 56 | environment: 57 | - DISCOVERY_URL=http://c-discovery:8761/eureka 58 | - USERSERVICE_PORT=80 59 | - INSTANCE_HOSTNAME=c-discovery 60 | ports: 61 | - 3000:80 62 | entrypoint: ['bash', '-c', 'cd /src && mvn spring-boot:run'] 63 | depends_on: 64 | - discovery 65 | 66 | # Product service 67 | product-service: 68 | image: maven:3.8.5-openjdk-17 69 | container_name: c-productservice 70 | hostname: productserivce 71 | networks: 72 | - default 73 | volumes: 74 | - ./services/productservice:/src 75 | - ~/.m2:/root/.m2 76 | environment: 77 | - DISCOVERY_URL=http://c-discovery:8761/eureka 78 | - PRODUCTSERVICE_PORT=80 79 | - INSTANCE_HOSTNAME=c-discovery 80 | ports: 81 | - 3001:80 82 | entrypoint: ['bash', '-c', 'cd /src && mvn spring-boot:run'] 83 | depends_on: 84 | - discovery 85 | 86 | ############# SERVICE Database ############# 87 | user-database: 88 | container_name: user-db 89 | image: mysql:8.0.28 90 | hostname: userdb 91 | restart: always 92 | networks: 93 | - default 94 | volumes: 95 | - ./database/userservice:/var/lib/mysql 96 | - ./docker-configs/my.cnf:/etc/mysql/my.cnf 97 | environment: 98 | - MYSQL_ROOT_PASSWORD=1234 99 | - MYSQL_DATABASE=users 100 | 101 | product-database: 102 | container_name: product-db 103 | image: mysql:8.0.28 104 | hostname: productdb 105 | restart: always 106 | networks: 107 | - default 108 | volumes: 109 | - ./database/productservice:/var/lib/mysql 110 | - ./docker-configs/my.cnf:/etc/mysql/my.cnf 111 | environment: 112 | - MYSQL_ROOT_PASSWORD=1234 113 | - MYSQL_DATABASE=products 114 | -------------------------------------------------------------------------------- /Docker/docker-swarm.md: -------------------------------------------------------------------------------- 1 | # Docker Swarm là gì ? 2 | 3 | > **Docker Swarm**: là một service cho phép người dùng có thể tạo, quản lý tập chung cho Docker nodes và lịch trình cho các containers 4 | 5 | > Mỗi node của một Docker Swarm là một Docker daemon và tất cả các Docker daemons đều sử dụng docker API. 6 | 7 | > Các services có thể được deploy và có thể truy cập vào các nodes như nhau. 8 | 9 | > Khi một container bị build lỗi, thì với một backup folder sẵn có trong node ta có thể sử dụng để restore data trên một swarm mới. Nếu bạn nào đã từng deploy và sử dụng docker trong dự án chắc chắn đã từng bị chết container. Và đơn giản với docker swarm chúng ta có thể rollback bản build trước một cách dễ dàng với Swarm. 10 | 11 | ![Docker Swarm](../assets/images/docker-swarm-1.webp) 12 | 13 | ![Docker Swarm](../assets/images/docker-swarm-2.webp) 14 | 15 | ![Docker Swarm](../assets/images/docker-swarm-3.webp) 16 | 17 | # Các tính năng của Docker Swarm 18 | 19 | - Truy cập phi tập trung 20 | - Tính bảo mật cao 21 | - Auto load balancing 22 | - Khả năng mở rộng cao 23 | - Có khả năng rollback tiến trình 24 | 25 | # Kiến trúc của Docker Swarm 26 | 27 | - Manage Node 28 | - Worker node 29 | - Docker daemon 30 | - Container 31 | 32 | > Các container được quản lý bởi các Docker daemon trong các Worker node đã được chia nhỏ và quản lý tập trung bởi Manage node. 33 | 34 | ![Docker Swarm](../assets/images/docker-swarm-4.png) 35 | 36 | - Manage node được hiểu là trạng thái của tất cả các Worker node trong cụm. 37 | - Worker node chấp nhận các task được gửi từ Manage node. 38 | - Mọi Worker node như một agent, tự động báo cáo trạnh thái task của node đến Manage node. 39 | - Tất cả các Worker node giao tiếp với Manager node sử dụng API qua HTTP 40 | 41 | # Command 42 | 43 | > Tạo Swarm node - manager node (leader) 44 | 45 | ```sh 46 | docker swarm init --advertise-addr= 47 | 48 | docker info 49 | ``` 50 | 51 | > Kiểm tra các node trong Swarm - Manager 52 | 53 | ```sh 54 | docker node ls 55 | ``` 56 | 57 | > Xem token để các DM khác join vào - Manager node 58 | 59 | ```sh 60 | docker swarm join-token worker 61 | ``` 62 | 63 | > Worker xin join vào 64 | 65 | ```sh 66 | docker swarm join --token 67 | ``` 68 | 69 | > Rời Swarm - Worker 70 | 71 | ```sh 72 | docker swarm leave 73 | ``` 74 | 75 | > Xóa 1 node ra khỏi swarm - Manager 76 | 77 | ```sh 78 | docker swarm rm 79 | ``` 80 | 81 | # Quản lý service 82 | 83 | [Reference](https://docs.docker.com/engine/reference/commandline/service/) 84 | 85 | > Tạo service trên Manager node 86 | 87 | > Khi tạo các service với replicas > 1 thì node leader sẽ phân bổ cho các node trong swarm. Khi có 1 request đến service thì leader sẽ chọn ra 1 node tình trạng tốt nhất để trả về kết quả. 88 | 89 | > Trong trường hợp 1 node xóa đi container hoặc bị shutdown, thì manager sẽ tự tạo lại container đó cho 1 node khác. 90 | 91 | ```sh 92 | docker service create --replicas [OPTIONS] --name 93 | ``` 94 | 95 | > Kiểm tra các container trong 1 service 96 | 97 | ```sh 98 | docker service ps 99 | ``` 100 | 101 | > Scale service 102 | 103 | ```sh 104 | docker service scale = 105 | ``` 106 | -------------------------------------------------------------------------------- /Typescript/lessons/2-types.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------- 2 | --------------- Kiểu nguyên thuỷ (Primitive types) --------------- 3 | -------------------------------- */ 4 | // Boolean 5 | let isTrue: boolean = false; 6 | 7 | // Number 8 | let decimal: number = 6; 9 | let hex: number = 0xf00d; 10 | let binary: number = 0b1010; 11 | let octal: number = 0o744; 12 | let big: bigint = 100n; 13 | 14 | // String 15 | let myName: string = 'Dyno'; 16 | 17 | // Null 18 | const nullType: null = null; 19 | 20 | // Undefined (Giá trị mặc định khi khởi tạo 1 biến mà chưa gán giá trị) 21 | // Nếu gán 1 biến với kiểu undefined thì biến đó không bao giờ đc sử dụng nữa 22 | let undefinedVar: number; 23 | let undefinedVar2: undefined; // Không có ý nghĩa 24 | 25 | /* -------------------------------- 26 | --------------- Các kiểu khác trong TS --------------- 27 | -------------------------------- */ 28 | // Array 29 | let arr: number[] = [1, 2, 3]; 30 | let myArr: Array = [1, 2, 3]; 31 | 32 | // Tuple (mảng phần tử nhiều kiểu có thứ tự) 33 | let myTuple: [string, number, boolean, number]; 34 | myTuple = ['Dyno', 18, true, 20]; 35 | myTuple[0] = 1; // Chửi ngay `Type 'number' is not assignable to type 'string'` 36 | 37 | // Enum 38 | enum Color { 39 | Red, // 0 40 | Green, // 1 41 | Blue, // 2 42 | } 43 | console.log(Color.Blue); // 2 44 | console.log(Color[2]); // Blue 45 | 46 | enum Status { 47 | Waiting = 4, 48 | Doing = 1, 49 | Done = 5, 50 | } 51 | 52 | // Object 53 | const obj1: object = { 54 | name: 'Dyno', 55 | age: 18, 56 | isStudent: true, 57 | }; 58 | // TS sẽ kiểm tra type của từng thuộc tính trong obj 59 | obj1.age = '18'; // Nó chửi liền `Type 'string' is not assignable to type 'number'` 60 | 61 | // Any (nhận giá trị bất kỳ => Không nên dùng kiểu này trong TS) 62 | let anyVar: any = 1; 63 | anyVar = 'Dyno'; 64 | anyVar = [1, 2, 'Dyno']; 65 | 66 | // Void (thường gán cho 1 hàm không trả về gì) 67 | const funcReturnVoid = (): void => console.log('Hello'); 68 | 69 | // Never (Biểu diễn 1 sự việc không bao giờ xảy ra. 1 hàm không thể kết thúc hoặc luôn throw error) 70 | const funcReturnNever = (): never => { 71 | while (true) {} 72 | }; 73 | const funcReturnNever2 = (): never => { 74 | throw new Error('Error'); 75 | }; 76 | 77 | // Unknown (kiểu được gán khi chạy chương trình, thường đi với generics) 78 | 79 | // Type Alias (định nghĩa ra 1 kiểu dữ liệu dựa trên các kiểu dữ liệu có sẵn) 80 | type StringOrNumber = string | number; 81 | let typeAlias: StringOrNumber = 1; 82 | typeAlias = 'Dyno'; 83 | 84 | // TS sẽ kiểm tra type của từng thuộc tính trong obj 85 | const obj1 = { 86 | name: 'Dyno', 87 | age: 18, 88 | isStudent: true, 89 | }; 90 | 91 | obj1.age = '18'; // Nó chửi liền `Type 'string' is not assignable to type 'number'` 92 | 93 | // Union type (1 biến có thể nhận nhiều kiểu dữ liệu) 94 | let unionType: number | string | null = 1; 95 | unionType = 'Hello'; 96 | unionType = null; 97 | unionType = false; // không thể 98 | 99 | /* -------------------------------- 100 | --------------- Các kiểu khai báo --------------- 101 | -------------------------------- */ 102 | // Khai báo kiểu tường minh (Explicit Types) 103 | let explicitType: string = 'Explicit Type'; 104 | 105 | // Khai báo kiểu ngầm định (Implicit Types) 106 | let implicitType = 'Implicit Type'; // typeof implicitType = string 107 | -------------------------------------------------------------------------------- /PHP/mvc/app/App.php: -------------------------------------------------------------------------------- 1 | controller = $routes['default_controller']; 18 | unset($routes['default_controller']); 19 | } 20 | $this->action = 'index'; 21 | $this->params = []; 22 | $this->routes = new Route(); 23 | $this->handleUrl(); 24 | } 25 | 26 | function getUrl() 27 | { 28 | return !empty($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/'; 29 | } 30 | 31 | function handleUrl() 32 | { 33 | $url = $this->getUrl(); 34 | 35 | // virtual route -> real route 36 | $url = $this->routes->handleRoute($url); 37 | 38 | // Tách url ra thành mảng 39 | $urlSplits = array_values(array_filter(explode('/', $url))); 40 | 41 | // Kiểm tra thư mục lồng nhau, tìm ra controller thực sự 42 | // Ex: admin/dashboard => controller = Dashboard 43 | $urlCheck = ''; 44 | foreach ($urlSplits as $key => $u) { 45 | $urlCheck .= $u . '/'; 46 | $fileCheck = rtrim($urlCheck, '/'); 47 | $fileArr = explode('/', $fileCheck); 48 | $fileArr[count($fileArr) - 1] = ucfirst($fileArr[count($fileArr) - 1]); 49 | $fileCheck = implode('/', $fileArr); 50 | 51 | // Remove folder from urlSplit 52 | if (!empty($urlSplits[$key - 1])) { 53 | unset($urlSplits[$key - 1]); 54 | } 55 | 56 | if (file_exists('app/controllers/' . $fileCheck . '.php')) { 57 | $urlCheck = $fileCheck; 58 | break; 59 | } 60 | } 61 | $urlSplits = array_values($urlSplits); 62 | 63 | // Detect controller 64 | if (!empty($urlSplits[0])) { 65 | $this->controller = ucfirst($urlSplits[0]); 66 | } else { 67 | // default controller 68 | $this->controller = ucfirst($this->controller); 69 | } 70 | 71 | // Trường hợp trang chủ thì urlCheck = '' 72 | if (empty($urlCheck)) { 73 | $urlCheck = $this->controller; 74 | } 75 | 76 | if (file_exists('app/controllers/' . $urlCheck . '.php')) { 77 | require_once 'controllers/' . $urlCheck . '.php'; 78 | if (class_exists($this->controller)) { 79 | $this->controller = new $this->controller(); 80 | } else { 81 | $this->handleError('404'); 82 | } 83 | 84 | // delete controller from urls 85 | unset($urlSplits[0]); 86 | } else { 87 | $this->handleError('404'); 88 | } 89 | 90 | // Detect action 91 | if (!empty($urlSplits[1])) { 92 | $this->action = $urlSplits[1]; 93 | unset($urlSplits[1]); 94 | } 95 | 96 | // Detect params & Pass params to Controller 97 | $this->params = array_values($urlSplits); 98 | // check the existence of action method 99 | if (method_exists($this->controller, $this->action)) { 100 | call_user_func_array([$this->controller, $this->action], $this->params); 101 | } else { 102 | $this->handleError('404'); 103 | } 104 | } 105 | 106 | function handleError($name = '404') 107 | { 108 | require_once 'errors/' . $name . '.php'; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Microservices/client/src/app/App.php: -------------------------------------------------------------------------------- 1 | controller = $routes['default_controller']; 18 | unset($routes['default_controller']); 19 | } 20 | $this->action = 'index'; 21 | $this->params = []; 22 | $this->routes = new Route(); 23 | $this->handleUrl(); 24 | } 25 | 26 | function getUrl() 27 | { 28 | return !empty($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/'; 29 | } 30 | 31 | function handleUrl() 32 | { 33 | $url = $this->getUrl(); 34 | 35 | // virtual route -> real route 36 | $url = $this->routes->handleRoute($url); 37 | 38 | // Tách url ra thành mảng 39 | $urlSplits = array_values(array_filter(explode('/', $url))); 40 | 41 | // Kiểm tra thư mục lồng nhau, tìm ra controller thực sự 42 | // Ex: admin/dashboard => controller = Dashboard 43 | $urlCheck = ''; 44 | foreach ($urlSplits as $key => $u) { 45 | $urlCheck .= $u . '/'; 46 | $fileCheck = rtrim($urlCheck, '/'); 47 | $fileArr = explode('/', $fileCheck); 48 | $fileArr[count($fileArr) - 1] = ucfirst($fileArr[count($fileArr) - 1]); 49 | $fileCheck = implode('/', $fileArr); 50 | 51 | // Remove folder from urlSplit 52 | if (!empty($urlSplits[$key - 1])) { 53 | unset($urlSplits[$key - 1]); 54 | } 55 | 56 | if (file_exists('app/controllers/' . $fileCheck . '.php')) { 57 | $urlCheck = $fileCheck; 58 | break; 59 | } 60 | } 61 | $urlSplits = array_values($urlSplits); 62 | 63 | // Detect controller 64 | if (!empty($urlSplits[0])) { 65 | $this->controller = ucfirst($urlSplits[0]); 66 | } else { 67 | // default controller 68 | $this->controller = ucfirst($this->controller); 69 | } 70 | 71 | // Trường hợp trang chủ thì urlCheck = '' 72 | if (empty($urlCheck)) { 73 | $urlCheck = $this->controller; 74 | } 75 | 76 | if (file_exists('app/controllers/' . $urlCheck . '.php')) { 77 | require_once 'controllers/' . $urlCheck . '.php'; 78 | if (class_exists($this->controller)) { 79 | $this->controller = new $this->controller(); 80 | } else { 81 | $this->handleError('404'); 82 | } 83 | 84 | // delete controller from urls 85 | unset($urlSplits[0]); 86 | } else { 87 | $this->handleError('404'); 88 | } 89 | 90 | // Detect action 91 | if (!empty($urlSplits[1])) { 92 | $this->action = $urlSplits[1]; 93 | unset($urlSplits[1]); 94 | } 95 | 96 | // Detect params & Pass params to Controller 97 | $this->params = array_values($urlSplits); 98 | // check the existence of action method 99 | if (method_exists($this->controller, $this->action)) { 100 | call_user_func_array([$this->controller, $this->action], $this->params); 101 | } else { 102 | $this->handleError('404'); 103 | } 104 | } 105 | 106 | function handleError($name = '404') 107 | { 108 | require_once 'errors/' . $name . '.php'; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /PHP/mvc/app/controllers/Club.php: -------------------------------------------------------------------------------- 1 | setViewContent('page', $page); 20 | $this->setViewContent('pageSize', $pageSize); 21 | $this->setViewContent('total', $total); 22 | $this->setViewContent('clubs', $clubs); 23 | 24 | $this->setPassedVariables(['PAGE_SIZE' => PAGE_SIZE]); 25 | $this->setPassedVariables(['TOTAL_PAGE' => $total]); 26 | $this->appendJSLink('club-list.js'); 27 | $this->setPageTitle('Danh sách câu lạc bộ'); 28 | $this->renderToLayout('club-list'); 29 | $this->setLayout('general'); 30 | } 31 | 32 | public function addClub() 33 | { 34 | if (!empty($_SESSION['message'])) { 35 | $this->showSessionMessage(); 36 | } 37 | 38 | $coachList = CoachModel::findAllCoachOptions(); 39 | $stadiums = StadiumModel::findAllStadiumOptions(); 40 | 41 | $this->setViewContent('coachList', $coachList); 42 | $this->setViewContent('stadiums', $stadiums); 43 | 44 | $this->setPageTitle('Thêm câu lạc bộ'); 45 | $this->appendCssLink('add-player.css'); 46 | $this->appendJSLink('add-club.js'); 47 | $this->renderToLayout('add-club'); 48 | $this->setLayout('general'); 49 | } 50 | 51 | public function postAddClub() 52 | { 53 | if (empty($_POST)) { 54 | $this->setSessionMessage('Thêm câu lạc bộ thất bại', true); 55 | self::redirect('/them-clb'); 56 | } 57 | 58 | try { 59 | $isSuccess = ClubModel::addClub($_POST); 60 | if ($isSuccess) { 61 | $this->setSessionMessage('Thêm câu lạc bộ thành công'); 62 | self::redirect('/them-clb'); 63 | } 64 | } catch (Exception $ex) { 65 | error_log($ex); 66 | $this->setSessionMessage('Thêm câu lạc bộ thất bại', true); 67 | self::redirect('/them-clb'); 68 | } 69 | } 70 | 71 | // API 72 | public function getClubsApi() 73 | { 74 | $page = !empty($_GET['page']) && (int)$_GET['page'] ? (int)$_GET['page'] : 1; 75 | $pageSize = !empty($_GET['pageSize']) && (int)$_GET['pageSize'] ? (int)$_GET['pageSize'] : PAGE_SIZE; 76 | $clubDocs = ClubModel::findAllClubs($page, $pageSize); 77 | 78 | if (!empty($clubDocs)) { 79 | $clubs = $clubDocs['data']; 80 | $resultData = []; 81 | 82 | foreach ($clubs as $club) { 83 | array_push($resultData, [ 84 | 'ClubID' => $club->_get('ClubID'), 85 | 'ClubName' => $club->_get('ClubName'), 86 | 'Shortname' => $club->_get('Shortname'), 87 | 'StadiumName' => $club->SName, 88 | 'CoachName' => $club->CFullName 89 | ]); 90 | } 91 | 92 | $this->sendResponseApi(200, [ 93 | 'data' => $resultData, 94 | 'total' => $clubDocs['total'], 'page' => $page, 'pageSize' => $pageSize 95 | ]); 96 | } 97 | $this->sendResponseApi(500); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /PHP/mvc/core/Controller.php: -------------------------------------------------------------------------------- 1 | data['cssLinks'] = []; 9 | $this->data['jsLinks'] = []; 10 | $this->data['pageTitle'] = '18120634 Football'; 11 | $this->data['passedVariables'] = []; 12 | $this->data['viewPath'] = ''; 13 | $this->data['viewContent'] = []; 14 | } 15 | 16 | protected function setLayout($layoutName = 'general') 17 | { 18 | // Transform array keys to variables 19 | extract($this->data); 20 | 21 | $viewFilePath = _DIR_ROOT . '/app/views/layouts/' . $layoutName . '.php'; 22 | if (file_exists($viewFilePath)) { 23 | require_once $viewFilePath; 24 | } 25 | } 26 | 27 | protected function render(string $view = '', array $data = []) 28 | { 29 | // Transform array keys to variables 30 | if (empty($data) || sizeof($data) === 0) { 31 | $data = $this->data; 32 | } 33 | extract($data); 34 | 35 | $viewFilePath = _DIR_ROOT . '/app/views/' . $view . '.php'; 36 | if (file_exists($viewFilePath)) { 37 | require_once $viewFilePath; 38 | } 39 | } 40 | 41 | protected function renderToLayout(string $viewPath) 42 | { 43 | $this->data['viewPath'] = $viewPath; 44 | } 45 | 46 | protected function appendCssLink(string | array $cssFileName) 47 | { 48 | if (is_array($cssFileName)) { 49 | $this->data['cssLinks'] = array_merge($this->data['cssLinks'], $cssFileName); 50 | } else { 51 | array_push($this->data['cssLinks'], $cssFileName); 52 | } 53 | } 54 | 55 | protected function appendJSLink(string | array $jsFileName) 56 | { 57 | if (is_array($jsFileName)) { 58 | $this->data['jsLinks'] = array_merge($this->data['jsLinks'], $jsFileName); 59 | } else { 60 | array_push($this->data['jsLinks'], $jsFileName); 61 | } 62 | } 63 | 64 | protected function setPassedVariables(array $variables) 65 | { 66 | $this->data['passedVariables'] = array_merge($this->data['passedVariables'], $variables); 67 | } 68 | 69 | protected function setPageTitle(string $pageTitle = '') 70 | { 71 | if (!empty($pageTitle)) { 72 | $this->data['pageTitle'] = $pageTitle . ' | 18120634 Football'; 73 | } 74 | } 75 | 76 | protected function setViewContent(string $key, $value) 77 | { 78 | $this->data['viewContent'][$key] = $value; 79 | } 80 | 81 | protected static function redirect(string $url = '', int $statusCode = 301) 82 | { 83 | header('Location:' . $url, true, $statusCode); 84 | exit(0); 85 | } 86 | 87 | protected static function renderErrorPage(string $errorCode = '404') 88 | { 89 | require_once _DIR_ROOT . '/app/errors/' . $errorCode . '.php'; 90 | exit(0); 91 | } 92 | 93 | protected static function setSessionMessage($message = '', $isError = false) 94 | { 95 | $_SESSION['message'] = $message; 96 | $_SESSION['isError'] = $isError; 97 | } 98 | 99 | protected function showSessionMessage($autoDestroySession = true) 100 | { 101 | if (!empty($_SESSION['message'])) { 102 | require_once _DIR_ROOT . '/app/views/mixins/toast.php'; 103 | $this->appendJSLink('utils/toast.js'); 104 | renderToast($_SESSION['message'], true, true, isset($_SESSION['isError']) ? $_SESSION['isError'] : false); 105 | 106 | // Destroy it to prevent it from showing up again 107 | if ($autoDestroySession) { 108 | $_SESSION['message'] = null; 109 | $_SESSION['isError'] = null; 110 | } 111 | } 112 | } 113 | 114 | protected function sendResponseApi($statusCode = 200, $data = null) 115 | { 116 | header('HTTP/1.1 ' . $statusCode); 117 | header("Content-Type: application/json; charset=UTF-8"); 118 | echo json_encode($data); 119 | exit(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /PHP/mvc/public/assets/js/player-list.js: -------------------------------------------------------------------------------- 1 | let playerSelected = []; 2 | let editingPlayer = null; 3 | 4 | function onCheckboxChange() { 5 | const deletePlayerBtn = $('#deletePlayerBtn'); 6 | 7 | $('td input[type="checkbox"]').on('change', function () { 8 | const playerId = $(this).val(); 9 | const isChecked = $(this).is(':checked'); 10 | 11 | if (isChecked) { 12 | playerSelected.push(playerId); 13 | deletePlayerBtn.removeClass('d-none'); 14 | } else { 15 | playerSelected = playerSelected.filter((id) => id != playerId); 16 | if (!playerSelected.length) { 17 | deletePlayerBtn.addClass('d-none'); 18 | } 19 | } 20 | }); 21 | } 22 | 23 | function updateEditPlayerModal(player = {}) { 24 | const { 25 | FullName, 26 | DOB, 27 | ClubID, 28 | Nationality, 29 | Number: PlayerNumber, 30 | Position, 31 | } = player; 32 | $('#FullName').val(FullName); 33 | $('#DOB').val(DOB); 34 | $('#ClubID').val(ClubID); 35 | $('#Nationality').val(Nationality); 36 | $('#Number').val(PlayerNumber); 37 | $('#Position').val(Position); 38 | } 39 | 40 | function getPlayerInModal() { 41 | return { 42 | FullName: $('#FullName').val(), 43 | DOB: $('#DOB').val(), 44 | ClubID: $('#ClubID').val(), 45 | Nationality: $('#Nationality').val(), 46 | Number: $('#Number').val(), 47 | Position: $('#Position').val(), 48 | }; 49 | } 50 | 51 | jQuery(function () { 52 | const deletePlayerBtn = $('#deletePlayerBtn'); 53 | 54 | $('#clubSelect').on('change', function () { 55 | const clubId = Number($(this).val()); 56 | const url = new URL(location.href); 57 | 58 | if (!clubId || isNaN(clubId)) { 59 | url.searchParams.delete('clubId'); 60 | } else { 61 | url.searchParams.set('clubId', clubId); 62 | } 63 | 64 | location.href = url.href; 65 | }); 66 | 67 | $('#selectAll').on('change', function () { 68 | const isChecked = $(this).is(':checked'); 69 | 70 | const checkboxes = $('td input[type="checkbox"]'); 71 | playerSelected = []; 72 | 73 | checkboxes.each(function () { 74 | isChecked && playerSelected.push($(this).val()); 75 | $(this).prop('checked', isChecked); 76 | }); 77 | 78 | if (isChecked && playerSelected.length) { 79 | deletePlayerBtn.removeClass('d-none'); 80 | } else { 81 | deletePlayerBtn.addClass('d-none'); 82 | } 83 | }); 84 | 85 | onCheckboxChange(); 86 | 87 | deletePlayerBtn.on('click', function () { 88 | if (playerSelected.length) { 89 | const isConfirm = confirm( 90 | `Bạn có chắc muốn xoá các cầu thủ ${playerSelected.join( 91 | ',', 92 | )}. Các dữ liệu liên quan đến cầu thủ này cũng sẽ bị xoá như trận đấu, bàn thắng. Dữ liệu sau xoá sẽ không thể khôi phục.`, 93 | ); 94 | 95 | if (isConfirm) { 96 | const url = `${ 97 | location.origin 98 | }/xoa-cau-thu?playerIds=${playerSelected.join(',')}`; 99 | 100 | fetch(url, { method: 'DELETE' }).then((response) => { 101 | if (response.status === 200) { 102 | alert('Xoá thành công'); 103 | location.reload(); 104 | } else { 105 | alert('Xoá thất bại'); 106 | } 107 | }); 108 | } 109 | } 110 | }); 111 | 112 | $('.update-player').on('click', async function () { 113 | const playerId = $(this).attr('data-id'); 114 | const apiRes = await fetch( 115 | `${location.origin}/player/getPlayerById/${playerId}`, 116 | ); 117 | const player = await apiRes.json(); 118 | if (player) { 119 | updateEditPlayerModal(player); 120 | editingPlayer = player; 121 | } 122 | }); 123 | 124 | $('#updateBtn').on('click', async function () { 125 | const player = getPlayerInModal(); 126 | const newPlayer = { ...player, PlayerID: editingPlayer.PlayerID }; 127 | const apiRes = await fetch(`${location.origin}/player/updatePlayer`, { 128 | method: 'POST', 129 | headers: { 130 | 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 131 | }, 132 | body: Object.entries(newPlayer) 133 | .map(([k, v]) => { 134 | return k + '=' + v; 135 | }) 136 | .join('&'), 137 | }); 138 | if (apiRes.status === 200) { 139 | alert('cập nhập thành công'); 140 | location.reload(); 141 | } else { 142 | alert('Cập nhật thất bại'); 143 | } 144 | }); 145 | }); 146 | -------------------------------------------------------------------------------- /PHP/mvc/app/controllers/Player.php: -------------------------------------------------------------------------------- 1 | setViewContent('page', $page); 20 | $this->setViewContent('pageSize', $pageSize); 21 | $this->setViewContent('clubId', $clubId); 22 | $this->setViewContent('total', $total); 23 | $this->setViewContent('clubs', $clubs); 24 | $this->setViewContent('players', $players); 25 | 26 | $this->appendCssLink(['pagination.css', 'player-list.css']); 27 | $this->appendJSLink(['pagination.js', 'player-list.js']); 28 | $this->setPageTitle('Danh sách cầu thủ'); 29 | $this->renderToLayout('player-list'); 30 | $this->setLayout('general'); 31 | } 32 | 33 | public function searchPlayerPage() 34 | { 35 | $this->appendJSLink(['player-list.js', 'search-player.js']); 36 | $this->setPageTitle('Tìm kiếm cầu thủ'); 37 | $this->renderToLayout('search-player'); 38 | $this->setLayout('general'); 39 | } 40 | 41 | public function addPlayer() 42 | { 43 | if (!empty($_SESSION['message'])) { 44 | $this->showSessionMessage(); 45 | } 46 | $clubs = ClubModel::findAllClubOptions(); 47 | $this->setViewContent('clubs', $clubs); 48 | 49 | $this->setPageTitle('Thêm cầu thủ'); 50 | $this->appendCssLink('add-player.css'); 51 | $this->appendJSLink('add-player.js'); 52 | $this->renderToLayout('add-player'); 53 | $this->setLayout('general'); 54 | } 55 | 56 | public function postAddPlayer() 57 | { 58 | if (empty($_POST)) { 59 | $this->setSessionMessage('Thêm cầu thủ thất bại', true); 60 | self::redirect('/them-cau-thu'); 61 | } 62 | 63 | try { 64 | $isSuccess = PlayerModel::addPlayer($_POST); 65 | if ($isSuccess) { 66 | $this->setSessionMessage('Thêm cầu thủ thành công'); 67 | self::redirect('/them-cau-thu'); 68 | } 69 | } catch (Exception $ex) { 70 | error_log($ex); 71 | $this->setSessionMessage('Thêm cầu thủ thất bại', true); 72 | self::redirect('/them-cau-thu'); 73 | } 74 | } 75 | 76 | // APIs 77 | public function deletePlayerApi() 78 | { 79 | if ($_SERVER['REQUEST_METHOD'] !== 'DELETE' || empty($_GET['playerIds'])) { 80 | $this->sendResponseApi(404); 81 | } 82 | 83 | $playerIds = explode(',', $_GET['playerIds']); 84 | $isSuccess = PlayerModel::deletePlayers($playerIds); 85 | 86 | if ($isSuccess) $this->sendResponseApi(200); 87 | $this->sendResponseApi(500); 88 | } 89 | 90 | public function searchPlayerApi() 91 | { 92 | if (empty($_GET)) { 93 | $this->sendResponseApi(400); 94 | } 95 | 96 | $name = !empty($_GET['name']) ? $_GET['name'] : ''; 97 | $number = !empty($_GET['number']) ? $_GET['number'] : ''; 98 | $nationality = !empty($_GET['nationality']) ? $_GET['nationality'] : ''; 99 | 100 | if (empty($name) && empty($number) && empty($nationality)) { 101 | $this->sendResponseApi(400); 102 | } 103 | 104 | $players = PlayerModel::searchPlayers($name, $number, $nationality); 105 | $this->sendResponseApi(200, $players); 106 | } 107 | 108 | public function getPlayerById($playerId) 109 | { 110 | $player = PlayerModel::findPlayerById($playerId); 111 | $this->sendResponseApi(200, $player); 112 | } 113 | 114 | public function updatePlayer() 115 | { 116 | if (!empty($_POST)) { 117 | $isSuccess = PlayerModel::updatePlayer($_POST); 118 | if ($isSuccess) $this->sendResponseApi(200); 119 | } 120 | $this->sendResponseApi(500); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Docker/docker-file.md: -------------------------------------------------------------------------------- 1 |

About Docker File

2 | 3 | # Dockerfile là gì ? 4 | 5 | > Nó là 1 file dùng để build ra 1 **Image** tự động thông qua các dòng code trong **Dockerfile**. 6 | 7 | > **Lợi ích:** Dockerfile gilý Runtime Environment, Configuration cùng Application bằng code. Đóng gói tất cả vào 1 image. Do Image là Read-only nên việc deploy image lên các môi trường là rất ổn định. 8 | 9 | > **Immutable Infrastructure:** Phiên bản ổn định nhất, không đổi trong mọi môi trường khác nhau. 10 | 11 | > **Infrastructure as Code:** Sử dụng Dockerfile để quản lý Infrastructure. 12 | 13 | ![IaC_II](../assets/images/IaC_II.jpg) 14 | 15 | # Dockerfile Instructions 16 | 17 | > Note: Nên viết các Instructions ít thay đổi ở trên. Để tiết kiệm thời gian build cũng như và size của các image layers. 18 | 19 | ## FROM 20 | 21 | > Chỉ định ra base image sẽ sử dụng cho các instruction bên dưới. 22 | 23 | > Hạn chế dùng tag latest để duy trì tính ổn định hệ thống. 24 | 25 | ```Dockerfile 26 | FROM 27 | # Ex 28 | FROM mysql:8.0 29 | ``` 30 | 31 | ## ARG 32 | 33 | > Tùy chỉnh và truyền vào Dockerfile 1 vài variable khi build. Tương tự khi chạy `--build-arg =` 34 | 35 | ```Dockerfile 36 | ARG [=] 37 | # Ex 38 | ARG version 39 | ``` 40 | 41 | ## LABEùng để mô tả thêm cho image (cung cấp các meta data cho image) 42 | 43 | ```Dockerfile 44 | LABEL = = = ... 45 | # Ex 46 | LABEL "com.example.vendor"="ACME Incorporated" 47 | LABEL version="1.0" 48 | LABEL description="This text illustrates \ 49 | that label-value ..." 50 | ``` 51 | 52 | ## ENV 53 | 54 | > Tạo các biến môi trường cho container như tham số `-e` 55 | 56 | ```Dockerfile 57 | ENV = 58 | # Ex 59 | ENV DATABASE_HOST=localhost 60 | ``` 61 | 62 | ## WORKDIR 63 | 64 | > Dùng để thiết lập thư mục làm việc hiện tại cho bất kỳ chỉ thị RUN, CMD, ENTRYPOINT, COPY… trong quá trình build. 65 | 66 | ```Dockerfile 67 | WORKDIR 68 | # Ex: 69 | WORKDIR /home/code 70 | 71 | # Ex2: 72 | ENV DIRPATH=/path 73 | WORKDIR $DIRPATH/$DIRNAME 74 | RUN pwd 75 | ``` 76 | 77 | ## RUN 78 | 79 | > Dùng để chạy các Linux command. 80 | 81 | > Lưu ý: mỗi lần chạy `RUN` sẽ tạo ra 1 image layer, nếu có thể hãy gộp các lệnh RUN lại bằng `\`. Điều này giúp tiết kiệm size cho các images. 82 | 83 | ```Dockerfile 84 | RUN 85 | #or 86 | RUN ["executable", "param1", "param2"] 87 | 88 | # Ex: tạo ra 2 image layers 89 | RUN apt-get update 90 | RUN apt-get install -y apache2 automake build-essential curl 91 | 92 | # Ex gộp các lệnh thành 1 RUN => 1 image layer 93 | RUN apt-get update \ 94 | apt-get install -y apache2 automake build-essential curl \ 95 | command... 96 | ``` 97 | 98 | ## COPY, ADD 99 | 100 | > COPY, ADD Dùng để copy file và thư mục từ hệ thống host tới image trong khi build. Với ADD chúng ta còn có thể tải 1 file từ URL. 101 | 102 | ```Dockerfile 103 | COPY [--chown=:] ... 104 | ADD [--chown=:] ... 105 | # Ex 106 | COPY html/* /var/www/html/ 107 | ADD https://example.com/resource /app 108 | ``` 109 | 110 | ## USER 111 | 112 | > Chạy container với user nào. Mặc định là root. 113 | 114 | ```Dockerfile 115 | USER [:] 116 | # Ex 117 | USER dyno 118 | ``` 119 | 120 | ## VOLUME 121 | 122 | > Chỉ định 1 mount point để lưu trữ và chia sẻ dữ liệu giữa các containers. 123 | 124 | ```Dockerfile 125 | VOLUME 126 | # Ex 127 | VOLUME /app/share 128 | ``` 129 | 130 | ## EXPOSE 131 | 132 | > Chỉ định port mà container sẽ chờ request đến. 133 | 134 | ```Dockerfile 135 | EXPOSE [/] 136 | # Ex 137 | EXPOSE 80 138 | ``` 139 | 140 | ## CMD, ENTRYPOINT 141 | 142 | > Chỉ định 1 command sẽ chạy khi container khởi chạy. 143 | 144 | ```Dockerfile 145 | ENTRYPOINT ["executable", "param1", "param2"] 146 | # or 147 | CMD ["executable", "param1", "param2"] 148 | # Ex 149 | ENTRYPOINT ["/usr/bin/node", "index.js", "--env=DEV"] 150 | ``` 151 | 152 | > Nếu dùng cùng lúc CMD và ENTRYPOINT thì ENTRYPOINT sẽ là command còn CMD sẽ là tham số. 153 | 154 | ```Dockerfile 155 | ENTRYPOINT ["executable", "param1", "param2"] 156 | CMD ["param3", "param4"] 157 | # Ex 158 | ENTRYPOINT ["/usr/bin/node", "index.js"] 159 | CMD ["--env=DEV"] 160 | ``` 161 | 162 | # Command 163 | 164 | > Build 1 Dockerfile 165 | 166 | ```sh 167 | docker build -t : -f 168 | ``` 169 | -------------------------------------------------------------------------------- /Kubernetes/README.md: -------------------------------------------------------------------------------- 1 |

Kubernetes (k8s)

2 | 3 |
4 | 5 | ![K8s](../assets/images/k8s.png) 6 | 7 |
8 | 9 | # Container Orchestration 10 | 11 | > **Container Orchestration** là các công cụ, dịch vụ dùng để điều phối và quản lý nhiều container sao cho chúng làm việc một cách hiệu quả nhất. 12 | 13 | > Các tính năng cần có của một Container Orchestration: 14 | 15 | - Container Deployment: Quản lý các container, start, stop, replicate, ... 16 | - Schedule: Lên lịch xử lý các công việc (workflow) trên các cluster nodes 17 | - Scaling: Thay đổi số lượng container phù hợp với khối lượng công việc hiện tại. 18 | - Networking: Liên kết các service trong cùng 1 application 19 | - Service Discovery: Tìm kiếm các service trong 1 application. 20 | - Resource Allocation: Phân bổ tài nguyên vào container sao cho hợp lý 21 | - Heath Monitoring: Quản lý, kiểm soát tình trạng hoạt động của các containers. 22 | 23 | > Lợi ích: 24 | 25 | - High Availability 26 | - Tối ưu hoá Computing Resources của toàn cluster. 27 | - Tự động hoá được quá trình Deployment. 28 | - Quản lý dễ dàng, khả năng mở rộng rất cao. 29 | 30 | > Một vài Product liên quan: 31 | 32 | - Docker Swarm (Đơn giản, có sẵn trong Docker) 33 | - Kubernetes 34 | - Apache Mesos 35 | - ... 36 | 37 | # Tổng quan về Kubernetes ? 38 | 39 | - Kubernetes là 1 Container Orchestration (Deploy, Scaling, Manage), còn gọi là K8S. 40 | - Ra đời ngày 07/06/2014 bởi Google, mã nguồn mở và trở thành 1 project của CNCF (Cloud Native Computing Foundation) năm 2016. 41 | - Một vài công cụ cung cấp Kubernetes: 42 | 43 | - Google Cloud Kubernetes Engine 44 | - Amazon EKS 45 | - Azure Kubernetes Service (AKS) 46 | - Minikube 47 | 48 | - Lợi ích K8S: 49 | - Đẩy nhanh tốc độ phát triển hệ thống. 50 | - Tính sẵn sàng cao (High Availability). 51 | - Tối ưu khả năng mở rộng (thích hợp cho các hệ thống microservice) 52 | - Open Source, cộng đồng hỗ trợ mạnh mẽ. 53 | 54 | # Các thành phần chính trong Kubernetes 55 | 56 | > **Cluster** là một tập hợp nhiều nodes, với mỗi node bao gồm các tài nguyên như memory, computing, networking, storage ,... Một system có thể có nhiều cluster. 57 | 58 | ![k8s cluster](../assets/images/k8s-cluster.jpg) 59 | 60 | > Master Node: 61 | 62 | - **API Server:** cung cấp API cho k8s cluster dùng để xác thực và thiết lập các configuration data cho Pod services. 63 | 64 | - **etcd:** Key-value storage, lưu trữ toàn bộ cấu hình, trạng thái và meta data của 1 cluster. etcd có thể chạy trên 1 node hoặc nhiều node để dự phòng (trong các hệ thống lớn). 65 | 66 | - **kube controller manager:** Theo dõi các cập nhật trạng thái cũa k8s cluster thông qua API và cập nhật các thay đổi sao cho phù hơp. 67 | 68 | - **cloud controller manager:** Dành cho các cloud provider. 69 | 70 | - **Scheduler:** Lên lịch, sắp xếp, phân bổ tài nguyên cho các Pod cho hợp lý. 71 | 72 | > Worker Node: 73 | 74 | - **Kube-proxy** chạy trên tất cả các node trong cluster, quản lý network policy trên mỗi node, chuyển tiếp hoặc lọc traffic tới node dựa trên policy này. 75 | 76 | - **Kubelet** là 1 Agent chạy trên mỗi Worker, giám sát, quản lý giao tiếp với Master node. Quản lý các Pod, sử dụng CRI (Container Runtime Interface) để giao tiếp với Container Runtime. 77 | 78 | - **Container Runtime** Chịu tránh nhiệm chạy các container. 79 | 80 | ![k8s cluster](../assets/images/k8s-cluster-2.jpg) 81 | 82 | # Các khái niệm quan trọng trong Kubernetes 83 | 84 | > **Pod** là đơn vị nhỏ nhất trong k8s, bao gồm 1 hoặc nhiều container chia sẻ tài nguyên, network với nhau. 85 | 86 | ![k8s pod](../assets/images/k8s-pod.jpg) 87 | 88 | > **Service** thực hiện chức năng discovery và load balancing cho phép tạo một điểm truy cập duy nhất đến các Pods cung cấp cùng một dịch vụ (cùng Label). Service 89 | 90 | ![k8s service](../assets/images/k8s-service.png) 91 | 92 | - **Label** cung cấp meta data nhận dạng cho các object trong k8s. 1 Object có thể có nhiều label và 1 label có thể gán cho nhiều object. 93 | 94 | - **Annotation** như label nhưng dùng để bổ sung các meta data cho máy tính có thể hiểu như timestamp, uid, ... 95 | 96 | - **ReplicaSet** quản lý và chạy nhiều instance. thường thiết kế cho các Stateless application. 97 | 98 | - **StatefulSet** tương tự với ReplicaSet. Tuy nhiên, mỗi bản sao của Pod sẽ khởi chạy với tên cố định, đánh index theo thứ tự. 99 | 100 | ![k8s statefulSet](../assets/images/k8s-stateful-set.jpg) 101 | 102 | - **ConfigMap, Secrets** truyền các config vào các container theo dạng key-value. Secret tránh đóng gói các key nhạy cảm cùng với container. 103 | 104 | - **Namespace** tất cả object trong k8s được deploy vào các namespace, dùng để quản lý các object trong 1 cluster. Các Pod trong namespace này có thể truy cập các pod và service của namespace khác, vì thế cần thiết lập Network Policy rõ ràng. 105 | 106 | ![k8s namespace](../assets/images/k8s-namespcae.jpg) 107 | -------------------------------------------------------------------------------- /Docker/docker-command.md: -------------------------------------------------------------------------------- 1 | # Common Docker 2 | 3 | > Xem thông tin docker 4 | 5 | ``` 6 | docker info 7 | ``` 8 | 9 | # Images 10 | 11 | > Xem image trên docker 12 | 13 | ```sh 14 | docker image ls 15 | # or 16 | docker images 17 | ``` 18 | 19 | > Search docker hub 20 | 21 | ```sh 22 | docker search 23 | ``` 24 | 25 | > Tải 1 image về local repo 26 | 27 | ```sh 28 | docker pull : 29 | ``` 30 | 31 | > Xóa 1 image 32 | 33 | ```sh 34 | docker image rm : 35 | # or 36 | docker image rm 37 | #or 38 | docker rmi 39 | ``` 40 | 41 | > Vài tham số khi tạo container 42 | 43 | ```sh 44 | # -it là khởi tạo và chạy attach trên termial hiện tại 45 | docker run -it --name "container name" -h "Host name" 46 | ``` 47 | 48 | > Xóa container 49 | 50 | ```sh 51 | docker rm 52 | # xóa khi vẫn chạy 53 | docker rm -f 54 | ``` 55 | 56 | > Lưu 1 image ra file 57 | 58 | ```sh 59 | docker save --output 60 | ``` 61 | 62 | > Load 1 image từ file 63 | 64 | ```sh 65 | docker load -i 66 | ``` 67 | 68 | > Đặt tên cho image 69 | 70 | ```sh 71 | docker tag : 72 | ``` 73 | 74 | > Xem lịch sử thao tác trên image 75 | 76 | ```sh 77 | docker image history 78 | ``` 79 | 80 | > Thông tin chi tiết image 81 | 82 | ```sh 83 | docker inspect image 84 | ``` 85 | 86 | # Containers 87 | 88 | > Câu lệnh chung khởi chạy 1 container 89 | 90 | ```sh 91 | docker run [Options] [command] [option_command] 92 | ``` 93 | 94 | > Liệt kê các Container 95 | 96 | ```sh 97 | # Đang chạy 98 | docker ps 99 | 100 | # Tất cả 101 | docker ps -a 102 | ``` 103 | 104 | > Chạy lại 1 container đã tắt 105 | 106 | ```sh 107 | docker start 108 | 109 | # vào lại terminal của container đó 110 | docker attach 111 | ``` 112 | 113 | > Chạy container và xóa khi kết thúc 114 | 115 | ```sh 116 | docker run -it --rm 117 | ``` 118 | 119 | > Dừng 1 container đang chạy 120 | 121 | ```sh 122 | docker stop 123 | 124 | # Dừng nếu đang trong terminal của container 125 | exit 126 | # or 127 | 128 | # Thoát khỏi attach terminal của container nhưng không tắt container 129 | # 130 | ``` 131 | 132 | > Xem chi tiết container 133 | 134 | ```sh 135 | docker inspect 136 | ``` 137 | 138 | > Xem thay đổi container 139 | 140 | ```sh 141 | docker diff 142 | ``` 143 | 144 | > Xem logs và statistic 145 | 146 | ```sh 147 | docker logs 148 | docker logs --tail 10 149 | docker logs -f 150 | docker stats 151 | ``` 152 | 153 | > Thực thi 1 lệnh trong container khi ở ngoài container 154 | 155 | ```sh 156 | docker exec 157 | ``` 158 | 159 | > Commit 1 container thành 1 images để sao lưu dữ liệu trong container, nhầm mục đích tạo lại container với dữ liệu đó sau này. 160 | 161 | ```sh 162 | docker commit 163 | ``` 164 | 165 | # Docker Volumes 166 | 167 | > Do các container chạy độc lập nhau nên chúng ta không thể chia sẻ dữ liệu giữa chúng. Docker Volume giải quyết vấn đề này. 168 | 169 | > Chia sẻ dữ liệu từ Host vào Docker (Volume -v) 170 | 171 | ```sh 172 | docker run -it -v : 173 | # Ex: 174 | docker run -it -v /storage/data:/home/data arch_linux 175 | 176 | # Cấu hình 1 container khác có volume như 1 container có sẵn 177 | docker run -it --volumes-from 178 | ``` 179 | 180 | > Liệt kê các volume trên docker 181 | 182 | ``` 183 | docker volume ls 184 | ``` 185 | 186 | > Tạo 1 volume 187 | 188 | ```sh 189 | docker volume create 190 | ``` 191 | 192 | > Xem dữ liệu trong volume 193 | 194 | ```sh 195 | docker volume inspect 196 | ``` 197 | 198 | > Xóa 1 volume 199 | 200 | ```sh 201 | docker volume rm 202 | ``` 203 | 204 | > Mount volume vào container 205 | 206 | ```sh 207 | docker run -it --mount source=,target= 208 | ``` 209 | 210 | > Tạo 1 volume ánh xạ đến 1 ổ đĩa trên Host 211 | 212 | ```sh 213 | docker volume create --opt device= --opt type=none --opt o=bind 214 | 215 | # Ánh xạ vào container 216 | docker run -it -v : 217 | ``` 218 | 219 | # Network 220 | 221 | > Docker network dùng để kết nối các container trong Docker và kết nối ra bên ngoài Host. 222 | 223 | > Liệt kê các network 224 | 225 | ``` 226 | docker network ls 227 | ``` 228 | 229 | > Thông tin của 1 network 230 | 231 | ``` 232 | docker network inspect 233 | ``` 234 | 235 | > kiểm tra network của 1 container 236 | 237 | ```sh 238 | docker inspect 239 | ``` 240 | 241 | > Ánh xạ localhost vào network của container 242 | 243 | ```sh 244 | docker run -it -p : 245 | ``` 246 | 247 | > Tạo 1 network 248 | 249 | ```sh 250 | docker network create --driver 251 | ``` 252 | 253 | > Các container cùng 1 network có thể connect lẫn nhau, khác network thì không. 254 | 255 | > Connect 1 container tới 1 network khác khi container đang chạy 256 | 257 | ```sh 258 | docker network connect 259 | ``` 260 | -------------------------------------------------------------------------------- /PHP/mvc/app/models/Player.php: -------------------------------------------------------------------------------- 1 | 0) { 20 | $sql = $sql . " AND c.ClubID = $clubId"; 21 | } 22 | $docs = self::pagination([ 23 | 'query' => $sql, 24 | 'page' => $page, 'pageSize' => $pageSize, 25 | 'orderBy' => $orderBy, 'modelName' => static::class 26 | ]); 27 | return $docs; 28 | } catch (Exception $ex) { 29 | error_log($ex); 30 | return []; 31 | } 32 | } 33 | 34 | public static function deletePlayers($playerIds = []) 35 | { 36 | try { 37 | if (!empty($playerIds)) { 38 | $where = ''; 39 | foreach ($playerIds as $index => $playerId) { 40 | $where = $index == 0 ? $where . "PlayerID = $playerId" : $where . " OR PlayerID = $playerId"; 41 | } 42 | $conn = MySQLConnection::getConnect(); 43 | // Delete in match_goals 44 | $sql = "DELETE FROM match_goals WHERE $where"; 45 | $st = $conn->prepare($sql); 46 | $st->execute(); 47 | 48 | // Delete in match_players 49 | $sql = "DELETE FROM match_players WHERE $where"; 50 | $st = $conn->prepare($sql); 51 | $st->execute(); 52 | 53 | // Delete in player 54 | $sql = "DELETE FROM player WHERE $where"; 55 | $st = $conn->prepare($sql); 56 | $st->execute(); 57 | 58 | return true; 59 | } 60 | 61 | return false; 62 | } catch (Exception $ex) { 63 | error_log($ex); 64 | return false; 65 | } 66 | } 67 | 68 | public static function searchPlayers($name = '', $number = '', $nationality = '') 69 | { 70 | try { 71 | $sql = 'SELECT * FROM player AS p, club AS c WHERE p.ClubID = c.ClubID'; 72 | if (!empty($name)) { 73 | $lowerName = strtolower($name); 74 | $sql .= " AND LOWER(p.FullName) LIKE '%$lowerName%'"; 75 | } 76 | if (!empty($nationality)) { 77 | $lowerNationality = strtolower($nationality); 78 | $sql .= " AND LOWER(p.Nationality) LIKE '%$lowerNationality%'"; 79 | } 80 | if (!empty($number)) { 81 | $sql .= " AND p.Number = $number"; 82 | } 83 | 84 | $conn = MySQLConnection::getConnect(); 85 | $st = $conn->prepare($sql); 86 | $st->execute(); 87 | $data = $st->fetchAll(PDO::FETCH_ASSOC); 88 | 89 | return $data; 90 | } catch (Exception $ex) { 91 | error_log($ex); 92 | return []; 93 | } 94 | } 95 | 96 | public static function addPlayer($player) 97 | { 98 | try { 99 | [ 100 | 'FullName' => $FullName, 'DOB' => $DOB, 'ClubID' => $ClubID, 101 | 'Position' => $Position, 'Nationality' => $Nationality, 'Number' => $Number 102 | ] = $player; 103 | 104 | $PlayerID = self::getNextID(self::$tableName, 'PlayerID'); 105 | $sql = "INSERT INTO player (PlayerID, FullName, ClubID, DOB, Position, Nationality, Number) VALUES " 106 | . "($PlayerID, '$FullName', $ClubID, '$DOB', '$Position', '$Nationality', $Number)"; 107 | 108 | $conn = MySQLConnection::getConnect(); 109 | $st = $conn->prepare($sql); 110 | $isSuccess = $st->execute(); 111 | return $isSuccess; 112 | } catch (Exception $ex) { 113 | throw new Exception($ex); 114 | } 115 | } 116 | 117 | public static function findPlayerById($playerId) 118 | { 119 | $sql = "SELECT * FROM player WHERE PlayerID = $playerId"; 120 | $conn = MySQLConnection::getConnect(); 121 | $st = $conn->prepare($sql); 122 | $st->execute(); 123 | $player = $st->fetch(PDO::FETCH_ASSOC); 124 | return $player; 125 | } 126 | 127 | public static function updatePlayer($player) 128 | { 129 | [ 130 | 'PlayerID' => $PlayerID, 'FullName' => $FullName, 'DOB' => $DOB, 'ClubID' => $ClubID, 131 | 'Position' => $Position, 'Nationality' => $Nationality, 'Number' => $Number 132 | ] = $player; 133 | $DOBSQL = empty($DOB) ? "" : ", DOB = '$DOB',"; 134 | 135 | $sql = "UPDATE player 136 | SET FullName = '$FullName',$DOBSQL ClubID = $ClubID, Position = '$Position', Nationality = '$Nationality', Number = '$Number' 137 | WHERE PlayerID = $PlayerID"; 138 | $conn = MySQLConnection::getConnect(); 139 | $st = $conn->prepare($sql); 140 | return $st->execute(); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /PHP/mvc/app/views/player-list.php: -------------------------------------------------------------------------------- 1 | $label"; 6 | } else { 7 | echo ""; 8 | } 9 | } 10 | ?> 11 | 12 |
13 |

Danh sách cầu thủ

14 | 15 |
16 | 27 | 28 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 47 | 48 | 49 | 50 | "; 53 | } else { 54 | foreach ($players as $player) { 55 | $dbo = $player->_get('DOB') ? date_format(date_create($player->_get('DOB')), 'd-m-Y') : '_'; 56 | $club = !empty($player->ClubName) ? $player->ClubName : $player->_get('ClubID'); 57 | $playerId = $player->_get('PlayerID'); 58 | 59 | echo ""; 60 | echo ""; 61 | echo ""; 62 | echo ""; 63 | echo ""; 64 | echo ""; 65 | echo ""; 66 | echo ""; 67 | echo ""; 71 | echo ""; 72 | } 73 | } 74 | ?> 75 | 76 |
IDHọ tênCLBNgày sinhVị tríQuốc tịchSố áo 45 |
46 |
Không tìm thấy dữ liệu
" . $playerId . "" . $player->_get('FullName') . "" . $club . "" . $dbo . "" . $player->_get('Position') . "" . $player->_get('Nationality') . "" . $player->_get('Number') . "" . 68 | "" . 69 | "" . 70 | "
77 | 78 | 79 | "; 83 | renderPagination($total, $page); 84 | echo "
"; 85 | } 86 | ?> 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Microservices/discovery/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /Microservices/gateway/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | --------------------------------------------------------------------------------