├── .gitignore ├── .env.sample ├── src ├── controllers │ ├── welcome.js │ ├── product │ │ ├── editProduct.js │ │ ├── listProducts.js │ │ ├── createProduct.js │ │ ├── deleteProduct.js │ │ └── editPhotoProduct.js │ ├── routeNotFounded.js │ ├── user │ │ ├── userList.js │ │ ├── userById.js │ │ ├── editUser.js │ │ ├── editNameUser.js │ │ ├── deleteUser.js │ │ └── createUser.js │ └── auth │ │ ├── logout.js │ │ └── login.js ├── config.js ├── models │ ├── sessionModel.js │ └── userModel.js ├── middlewares │ ├── errorHandler.js │ └── logger.js ├── routers │ ├── authRouter.js │ ├── productRouter.js │ └── userRouter.js └── server.js ├── database └── schema.sql ├── prisma ├── schema.production.prisma └── schema.local.prisma ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | DATABASE_URL="mysql://user:pass@localhost:3306/db_name" 2 | HOST="" 3 | PORT= 4 | ENVIRONMENT="" 5 | SECRET_KEY="_____secret_____" -------------------------------------------------------------------------------- /src/controllers/welcome.js: -------------------------------------------------------------------------------- 1 | const welcome = (req, res) => { 2 | res.json({message: "Bem vindo a API"}) 3 | } 4 | 5 | export default welcome -------------------------------------------------------------------------------- /src/controllers/product/editProduct.js: -------------------------------------------------------------------------------- 1 | const editProduct = (req, res) => { 2 | res.json({message: "Rota POST /product"}) 3 | } 4 | 5 | export default editProduct -------------------------------------------------------------------------------- /src/controllers/product/listProducts.js: -------------------------------------------------------------------------------- 1 | const listProducts = (req, res) => { 2 | res.json({message: "Rota GET /product"}) 3 | } 4 | 5 | export default listProducts -------------------------------------------------------------------------------- /src/controllers/product/createProduct.js: -------------------------------------------------------------------------------- 1 | const createProduct = (req, res) => { 2 | res.json({message: "Rota POST /product"}) 3 | } 4 | 5 | export default createProduct -------------------------------------------------------------------------------- /src/controllers/product/deleteProduct.js: -------------------------------------------------------------------------------- 1 | const deleteProduct = (req, res) => { 2 | res.json({message: "Rota DELETE /product"}) 3 | } 4 | 5 | export default deleteProduct -------------------------------------------------------------------------------- /src/controllers/product/editPhotoProduct.js: -------------------------------------------------------------------------------- 1 | const editPhotoProduct = (req, res) => { 2 | res.json({message: "Rota PATCH /product"}) 3 | } 4 | 5 | export default editPhotoProduct -------------------------------------------------------------------------------- /src/controllers/routeNotFounded.js: -------------------------------------------------------------------------------- 1 | const routeNotFounded = (req, res) => { 2 | res.status(404).json({message: "Rota não encontrada"}) 3 | } 4 | 5 | export default routeNotFounded -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | export const PORT = process.env.PORT || 4000 2 | export const HOST = process.env.HOST || 'http://localhost' 3 | export const ENVIRONMENT = process.env.ENVIRONMENT 4 | export const SECRET_KEY = process.env.SECRET_KEY -------------------------------------------------------------------------------- /src/controllers/user/userList.js: -------------------------------------------------------------------------------- 1 | import { getAll } from '../../models/userModel.js' 2 | 3 | const userList = async (req, res) => { 4 | 5 | const users = await getAll() 6 | res.json(users) 7 | } 8 | 9 | export default userList -------------------------------------------------------------------------------- /src/models/sessionModel.js: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client' 2 | 3 | const prisma = new PrismaClient() 4 | 5 | export const create = async (userId) => { 6 | const result = await prisma.session.create({ 7 | data: {userId} 8 | }) 9 | return result 10 | } -------------------------------------------------------------------------------- /src/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | const errorHandler = (err, req, res, next) => { 2 | if(err){ 3 | console.log(err) 4 | return res.status(500).json({ 5 | error: "Erro no servidor, tente novamente!" 6 | }) 7 | } 8 | } 9 | 10 | export default errorHandler -------------------------------------------------------------------------------- /src/routers/authRouter.js: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import login from '../controllers/auth/login.js' 3 | import logout from '../controllers/auth/logout.js' 4 | 5 | const router = express.Router() 6 | 7 | router.post('/login', login) 8 | router.post('/logout', logout) 9 | 10 | export default router -------------------------------------------------------------------------------- /database/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE 'api_express' 2 | 3 | CREATE TABLE IF NOT EXISTS `api_express`.`user` ( 4 | `id` INT NOT NULL, 5 | `name` VARCHAR(100) NOT NULL, 6 | `email` VARCHAR(200) NOT NULL, 7 | `pass` VARCHAR(256) NOT NULL, 8 | PRIMARY KEY (`id`), 9 | UNIQUE INDEX `email_UNIQUE` (`email` ASC) VISIBLE) 10 | ENGINE = InnoDB 11 | DEFAULT CHARACTER SET = utf8mb3 -------------------------------------------------------------------------------- /src/middlewares/logger.js: -------------------------------------------------------------------------------- 1 | const logger = (req, res, next) => { 2 | // const now = new Date() 3 | // const yyyy = now.getFullYear(); 4 | // const mm = now.getMonth() + 1; // Months start at 0! 5 | // const dd = now.getDate() 6 | //console.log(`${dd+'/'+mm+'/'+yyyy} ${req.method} ${req.url}`) 7 | console.log(`${new Date(Date.now()).toLocaleString()} ${req.method} ${req.url}`) 8 | next() 9 | } 10 | 11 | export default logger -------------------------------------------------------------------------------- /prisma/schema.production.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = "postgresql" 7 | url = env("DATABASE_URL") 8 | } 9 | 10 | model user { 11 | id Int @id @default(autoincrement()) 12 | public_id String @unique @db.VarChar(300) 13 | name String @db.VarChar(100) 14 | email String @unique(map: "email_UNIQUE") @db.VarChar(200) 15 | pass String @db.VarChar(256) 16 | } 17 | -------------------------------------------------------------------------------- /src/controllers/user/userById.js: -------------------------------------------------------------------------------- 1 | import { getById } from "../../models/userModel.js" 2 | 3 | const userById = async (req, res) => { 4 | const {id} = req.params 5 | const user = await getById(+id) 6 | 7 | if(user) 8 | return res.json({ 9 | message: "User get by id", 10 | user 11 | }) 12 | else 13 | return res.status(404).json({ 14 | error: "Usuário não encontrado" 15 | }) 16 | 17 | } 18 | 19 | export default userById -------------------------------------------------------------------------------- /src/controllers/user/editUser.js: -------------------------------------------------------------------------------- 1 | import { update } from "../../models/userModel.js" 2 | 3 | const editUser = async (req, res) => { 4 | const {id} = req.params 5 | const user = req.body 6 | 7 | user.id = +id 8 | 9 | const result = await update(user) 10 | 11 | if(!result) 12 | return res.status(401).json({ 13 | error: "Erro ao criar usuário" 14 | }) 15 | 16 | return res.json({ 17 | success: "Usuário atualizado com sucesso!", 18 | user: result 19 | }) 20 | } 21 | 22 | export default editUser -------------------------------------------------------------------------------- /src/controllers/user/editNameUser.js: -------------------------------------------------------------------------------- 1 | import { update } from "../../models/userModel.js" 2 | 3 | const editNameUser = async (req, res) => { 4 | const {id} = req.params 5 | const {name} = req.body 6 | 7 | const user = {id: +id,name} 8 | 9 | const result = await update(user) 10 | 11 | if(!result) 12 | return res.status(401).json({ 13 | error: "Erro ao criar usuário" 14 | }) 15 | 16 | return res.json({ 17 | success: "Nome atualizado com sucesso!", 18 | user: result 19 | }) 20 | } 21 | 22 | export default editNameUser -------------------------------------------------------------------------------- /src/controllers/user/deleteUser.js: -------------------------------------------------------------------------------- 1 | import { remove } from "../../models/userModel.js" 2 | 3 | const deleteUser = async (req, res, next) => { 4 | try { 5 | const {id} = req.params 6 | const user = await remove(+id) 7 | 8 | return res.json({ 9 | message: "Usuário removido com sucesso!", 10 | user 11 | }) 12 | } catch (error) { 13 | console.log(error) 14 | if(error?.code === 'P2025') 15 | return res.status(404).json({ 16 | error: "Usuário não encontrado" 17 | }) 18 | next(error) 19 | } 20 | } 21 | export default deleteUser -------------------------------------------------------------------------------- /src/routers/productRouter.js: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import listProducts from '../controllers/product/listProducts.js' 3 | import createProduct from '../controllers/product/createProduct.js' 4 | import editProduct from '../controllers/product/editProduct.js' 5 | import editPhotoProduct from '../controllers/product/editPhotoProduct.js' 6 | import deleteProduct from '../controllers/product/deleteProduct.js' 7 | 8 | const router = express.Router() 9 | 10 | router.get('/', listProducts) 11 | router.post('/', createProduct) 12 | router.put('/', editProduct) 13 | router.patch('/', editPhotoProduct) 14 | router.delete('/', deleteProduct) 15 | 16 | export default router -------------------------------------------------------------------------------- /prisma/schema.local.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = "mysql" 7 | url = env("DATABASE_URL") 8 | } 9 | 10 | model user { 11 | id Int @id @default(autoincrement()) 12 | public_id String @unique @db.VarChar(300) 13 | name String @db.VarChar(100) 14 | email String @unique(map: "email_UNIQUE") @db.VarChar(200) 15 | pass String @db.VarChar(256) 16 | sessions session[] 17 | } 18 | 19 | model session { 20 | id Int @id @default(autoincrement()) 21 | createdAt DateTime @default(now()) 22 | userId Int 23 | user user @relation(fields: [userId], references: [id]) 24 | } 25 | -------------------------------------------------------------------------------- /src/routers/userRouter.js: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import userList from '../controllers/user/userList.js' 3 | import userById from '../controllers/user/userById.js' 4 | import createUser from '../controllers/user/createUser.js' 5 | import editUser from '../controllers/user/editUser.js' 6 | import editNameUser from '../controllers/user/editNameUser.js' 7 | import deleteUser from '../controllers/user/deleteUser.js' 8 | 9 | const router = express.Router() 10 | 11 | router.post('/', createUser) 12 | router.get('/list', userList) 13 | router.get('/:id', userById) 14 | router.put('/:id', editUser) 15 | router.patch('/:id', editNameUser) 16 | router.delete('/:id', deleteUser) 17 | 18 | export default router -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | //const express = require('express') 2 | import express from 'express' 3 | import userRouter from './routers/userRouter.js' 4 | import productRouter from './routers/productRouter.js' 5 | import authRouter from './routers/authRouter.js' 6 | import logger from './middlewares/logger.js' 7 | import welcome from './controllers/welcome.js' 8 | import routeNotFounded from './controllers/routeNotFounded.js' 9 | import errorHandler from './middlewares/errorHandler.js' 10 | import { PORT, HOST, ENVIRONMENT } from './config.js' 11 | import cors from 'cors' 12 | 13 | const app = express() 14 | 15 | app.use(logger) 16 | app.use(cors()) 17 | // middleware que converte o request body json para objeto 18 | app.use(express.json()) 19 | 20 | app.get('/', welcome) 21 | app.use('/user', userRouter) 22 | app.use('/product', productRouter) 23 | app.use('/auth', authRouter) 24 | app.use('*', routeNotFounded) 25 | 26 | app.use(errorHandler) 27 | 28 | app.listen(PORT, () => { 29 | console.log(`Servidor rodando no ambiente ${ENVIRONMENT} em ${ENVIRONMENT == 'production' ? HOST : HOST+':'+PORT}`) 30 | }) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Comandos 2 | 3 | ### Node 4 | 5 | ``` 6 | node -v #verifica versão do node 7 | npm -v #verifica versão do npm 8 | npm init #cria o package json 9 | npm i #instala todas as dependências listadas no package.json 10 | npm i nome-do-pacote #instala pacotes 11 | npm uninstall #desinstala os pacotes 12 | npm run nome-do-script #executa um script do package.json 13 | npm start #executa o script start do package.json 14 | ``` 15 | 16 | ### Git 17 | 18 | ``` 19 | git config --global user.name "Seu Nome" 20 | git config --global user.email "seuemail@gmail.com" 21 | git remote add origin https://github.com/seugithub/seuprojeto.git 22 | ``` 23 | 24 | ### Prisma 25 | 26 | ``` 27 | npm i prisma -D (instala prisma como dependência de desenvolvimento) 28 | npx prisma init (inicializa o prisma no projeto prisma/schema.prisma e .env) 29 | npm install @prisma/client (Instala o cliente do prisma para importação no model) 30 | npx prisma db pull (gera o modelo a partir do banco criado) 31 | npx prisma db push (gera o banco a partir do modelo) 32 | npx prisma generate (cria as classes baseadas no modelo atual) 33 | ``` 34 | -------------------------------------------------------------------------------- /src/controllers/auth/logout.js: -------------------------------------------------------------------------------- 1 | import { create, validateUserToCreate } from "../../models/userModel.js" 2 | 3 | const logout = async (req, res, next) => { 4 | try{ 5 | const user = req.body 6 | const userValidated = validateUserToCreate(user) 7 | 8 | if(userValidated?.error){ 9 | return res.status(400).json({ 10 | error: "Erro ao criar usuário, verifique os dados!", 11 | fieldErrors: userValidated.error.flatten().fieldErrors 12 | }) 13 | } 14 | 15 | userValidated.data.public_id = uuid() 16 | userValidated.data.pass = bcrypt.hashSync(userValidated.data.pass, 10) 17 | 18 | const result = await create(userValidated.data) 19 | 20 | if(!result) 21 | return res.status(500).json({ 22 | error: "Erro ao criar usuário" 23 | }) 24 | 25 | return res.json({ 26 | success: "Usuário criado com sucesso!", 27 | user: result 28 | }) 29 | } catch(error) { 30 | console.log(error) 31 | if(error?.code === 'P2002') 32 | return res.status(400).json({ 33 | error: "Erro ao criar usuário, verifique os dados!", 34 | fieldErrors: { email: ['Email já cadastrado']} 35 | }) 36 | next(error) 37 | } 38 | } 39 | 40 | export default logout -------------------------------------------------------------------------------- /src/controllers/user/createUser.js: -------------------------------------------------------------------------------- 1 | import { create, validateUserToCreate } from "../../models/userModel.js" 2 | import { v4 as uuid } from 'uuid' 3 | import bcrypt from 'bcrypt' 4 | 5 | const createUser = async (req, res, next) => { 6 | try{ 7 | const user = req.body 8 | const userValidated = validateUserToCreate(user) 9 | 10 | if(userValidated?.error){ 11 | return res.status(400).json({ 12 | error: "Erro ao criar usuário, verifique os dados!", 13 | fieldErrors: userValidated.error.flatten().fieldErrors 14 | }) 15 | } 16 | 17 | userValidated.data.public_id = uuid() 18 | userValidated.data.pass = bcrypt.hashSync(userValidated.data.pass, 10) 19 | 20 | const result = await create(userValidated.data) 21 | 22 | if(!result) 23 | return res.status(500).json({ 24 | error: "Erro ao criar usuário" 25 | }) 26 | 27 | return res.json({ 28 | success: "Usuário criado com sucesso!", 29 | user: result 30 | }) 31 | } catch(error) { 32 | console.log(error) 33 | if(error?.code === 'P2002') 34 | return res.status(400).json({ 35 | error: "Erro ao criar usuário, verifique os dados!", 36 | fieldErrors: { email: ['Email já cadastrado']} 37 | }) 38 | next(error) 39 | } 40 | } 41 | 42 | export default createUser -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-bke-express-ads-2sem2024", 3 | "version": "1.0.0", 4 | "description": "API Node com framework Express", 5 | "main": "src/server.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node src/server.js", 9 | "dev": "node --env-file=.env --watch src/server.js", 10 | "prisma:local:pull": "npx prisma db pull --schema=./prisma/schema.local.prisma", 11 | "prisma:local:push": "npx prisma db push --schema=./prisma/schema.local.prisma", 12 | "prisma:local:generate": "npx prisma generate --schema=./prisma/schema.local.prisma", 13 | "prisma:local:studio": "npx prisma studio --schema=./prisma/schema.local.prisma", 14 | "prisma:pull": "npx prisma db pull --schema=./prisma/schema.production.prisma", 15 | "prisma:push": "npx prisma db push --schema=./prisma/schema.production.prisma", 16 | "prisma:generate": "npx prisma generate --schema=./prisma/schema.production.prisma", 17 | "studio": "npx prisma studio --schema=./prisma/schema.local.prisma" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/renancavichi/api-bke-express-ads-2sem2024.git" 22 | }, 23 | "keywords": [ 24 | "api", 25 | "node", 26 | "express", 27 | "zod" 28 | ], 29 | "author": "Renan Cavichi", 30 | "license": "ISC", 31 | "bugs": { 32 | "url": "https://github.com/renancavichi/api-bke-express-ads-2sem2024/issues" 33 | }, 34 | "homepage": "https://github.com/renancavichi/api-bke-express-ads-2sem2024#readme", 35 | "dependencies": { 36 | "@prisma/client": "^5.18.0", 37 | "bcrypt": "^5.1.1", 38 | "cors": "^2.8.5", 39 | "express": "^4.19.2", 40 | "jsonwebtoken": "^9.0.2", 41 | "uuid": "^11.0.2", 42 | "zod": "^3.23.8" 43 | }, 44 | "devDependencies": { 45 | "prisma": "^5.18.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/controllers/auth/login.js: -------------------------------------------------------------------------------- 1 | import { validateUserToLogin, getByEmail } from "../../models/userModel.js" 2 | import { create } from "../../models/sessionModel.js" 3 | import bcrypt from 'bcrypt' 4 | import jwt from 'jsonwebtoken' 5 | import { SECRET_KEY } from "../../config.js" 6 | 7 | const login = async (req, res, next) => { 8 | try{ 9 | const login = req.body 10 | const loginValidated = validateUserToLogin(login) 11 | 12 | if(loginValidated?.error){ 13 | return res.status(400).json({ 14 | error: "Erro ao logar, verifique os dados!", 15 | fieldErrors: loginValidated.error.flatten().fieldErrors 16 | }) 17 | } 18 | 19 | //buscar o user pelo email 20 | const user = await getByEmail(loginValidated.data.email) 21 | if(!user){ 22 | return res.status(400).json({ 23 | error: "Email ou senha inválida! (email não encontrado)" 24 | }) 25 | } 26 | 27 | //comparar a senha enviada com o hash armazenado 28 | const passIsValid = bcrypt.compareSync(loginValidated.data.pass, user.pass) 29 | 30 | if(!passIsValid){ 31 | return res.status(400).json({ 32 | error: "Email ou senha inválida! (senha não confere)" 33 | }) 34 | } 35 | 36 | const session = await create(user.id) 37 | 38 | const actionToken = jwt.sign({name: user.name, publicId: user.public_id}, SECRET_KEY, { expiresIn: '15m'}) 39 | const refreshToken = jwt.sign({publicId: user.public_id, session: session.id}, SECRET_KEY, { expiresIn: '2d'}) 40 | 41 | res.cookie('refreshToken', refreshToken, { httpOnly: true, sameSite: 'None', secure: true, maxAge: 2 * 24 * 60 * 60 * 1000 }) 42 | return res.json({actionToken, refreshToken, user: {name: user.name, email: user.email, publicId: user.public_id}}) 43 | } catch(error) { 44 | console.log(error) 45 | if(error?.code === 'P2002') 46 | return res.status(400).json({ 47 | error: "Erro ao criar usuário, verifique os dados!", 48 | fieldErrors: { email: ['Email já cadastrado']} 49 | }) 50 | next(error) 51 | } 52 | } 53 | 54 | export default login -------------------------------------------------------------------------------- /src/models/userModel.js: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client' 2 | import { z } from 'zod' 3 | 4 | const prisma = new PrismaClient() 5 | 6 | const userSchema = z.object({ 7 | id: z.number({ 8 | required_error: "O ID é obrigatório", 9 | invalid_type_error: "O ID deve ser um número inteiro.", 10 | }) 11 | .positive({message: "O ID deve ser um número positivo."}), 12 | name: z.string({ 13 | required_error: "O nome é obrigatório", 14 | invalid_type_error: "O nome deve ser uma string.", 15 | }) 16 | .min(3, {message: "O nome deve ter no mínimo 3 caracteres."}) 17 | .max(100, {message: "O nome deve ter no máximo 100 caracteres."}), 18 | email: z.string({ 19 | required_error: "O email é obrigatório", 20 | invalid_type_error: "O email deve ser uma string.", 21 | }) 22 | .email({message: "Email inválido."}) 23 | .max(200, {message: "O email deve ter no máximo 200 caracteres."}), 24 | pass: z.string({ 25 | required_error: "A senha é obrigatória", 26 | invalid_type_error: "A senha deve ser uma string.", 27 | }) 28 | .min(6, {message: "A senha deve ter no mínimo 6 caracteres."}) 29 | .max(256, {message: "A senha deve ter no máximo 256 caracteres."}) 30 | }) 31 | 32 | export const validateUser = (user) => { 33 | return userSchema.safeParse(user) 34 | } 35 | 36 | export const validateUserToCreate = (user) => { 37 | const partialUserSchema = userSchema.partial({ 38 | id: true 39 | }) 40 | return partialUserSchema.safeParse(user) 41 | } 42 | 43 | export const validateUserToLogin = (user) => { 44 | const partialUserSchema = userSchema.partial({ 45 | id: true, 46 | name: true 47 | }) 48 | return partialUserSchema.safeParse(user) 49 | } 50 | 51 | export const getAll = async () => { 52 | const users = await prisma.user.findMany({ 53 | select: { 54 | id: true, 55 | name: true, 56 | email: true 57 | } 58 | }) 59 | return users 60 | } 61 | 62 | export const getById = async (id) => { 63 | const user = await prisma.user.findUnique({ 64 | where: { 65 | id 66 | }, 67 | select: { 68 | id: true, 69 | name: true, 70 | email: true 71 | } 72 | }) 73 | return user 74 | } 75 | 76 | export const getByEmail = async (email) => { 77 | const user = await prisma.user.findUnique({ 78 | where: { 79 | email 80 | } 81 | }) 82 | return user 83 | } 84 | 85 | export const create = async (user) => { 86 | const result = await prisma.user.create({ 87 | data: user, 88 | select: { 89 | id: true, 90 | name: true, 91 | email: true 92 | } 93 | }) 94 | return result 95 | } 96 | 97 | export const remove = async (id) => { 98 | const user = await prisma.user.delete({ 99 | where: { 100 | id 101 | }, 102 | select: { 103 | id: true, 104 | name: true, 105 | email: true 106 | } 107 | }) 108 | return user 109 | } 110 | 111 | export const update = async (user) => { 112 | const result = await prisma.user.update({ 113 | where: { 114 | id: user.id 115 | }, 116 | data: user, 117 | select: { 118 | id: true, 119 | name: true, 120 | email: true 121 | } 122 | }) 123 | return result 124 | } 125 | 126 | 127 | --------------------------------------------------------------------------------