Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mai, Sofie & Wen | Project Authentication #333

Open
wants to merge 72 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
077f8fd
Create user model and signup endpoint as well as modify the gitignore…
wwenzz May 21, 2024
8702ff4
add endpint login
maikanetaka May 22, 2024
3b55895
add expresslistendpoint
maikanetaka May 22, 2024
f4fb349
install express-list-endpoint
maikanetaka May 22, 2024
8b3a629
create loginform component
maikanetaka May 22, 2024
62f31c0
import LoginForm component in App
maikanetaka May 22, 2024
6e18d4f
Delete netlify.toml
AntonellaMorittu May 22, 2024
3e17d0d
worked on loginForm
SofieFerrari May 22, 2024
9001fc4
loginform component
maikanetaka May 23, 2024
a8cc8da
install packages
maikanetaka May 23, 2024
dc384d2
install packages in backend
maikanetaka May 23, 2024
208dd90
Merge branch 'Technigo:master' into master
wwenzz May 23, 2024
fe5a051
Add react routes
maikanetaka May 23, 2024
cff0ffc
Add Homepage and Secret components
maikanetaka May 23, 2024
3ee3a81
Adding back home component
maikanetaka May 23, 2024
6d633bd
fix the link
maikanetaka May 23, 2024
259ba00
add homepage component
maikanetaka May 23, 2024
c45bac3
add homepage and secrets component in routes
maikanetaka May 23, 2024
88c131a
Login to redirect secret page
maikanetaka May 23, 2024
de9b987
fix path to /secrets
maikanetaka May 23, 2024
f66518d
set a default frontend port for dev to be 5173
maikanetaka May 23, 2024
4777510
Delete the wrong code
maikanetaka May 23, 2024
f456434
specify where to redirect for frontend
maikanetaka May 23, 2024
d9bc7a1
Fix redirecting when logging in by using status code instead of redir…
maikanetaka May 23, 2024
26aaecc
Properly set session cookie in frontend and use it when requesting ba…
maikanetaka May 23, 2024
588f429
change .send() to .end()
maikanetaka May 23, 2024
a99c971
show userdata
maikanetaka May 23, 2024
4cd24ec
having the 2nd authenticate method (token)
maikanetaka May 23, 2024
2d8c54c
secret component
maikanetaka May 23, 2024
1e3f8b6
add requirements
maikanetaka May 23, 2024
41decd1
update read me
maikanetaka May 24, 2024
79b38d4
Deploy the backend and replace the url with the backend URL
wwenzz May 24, 2024
ed8206c
Set the security to true in cookie
wwenzz May 24, 2024
dd14d82
remove duplicated req,res
wwenzz May 24, 2024
0f3a61b
Fix the bug in the backend
wwenzz May 24, 2024
3cfc769
Modify the cors
wwenzz May 24, 2024
b392e7d
Add mode: cors to frontend request
wwenzz May 24, 2024
08428ab
refactor the backend code
wwenzz May 24, 2024
1c07171
uninstall unused packages
wwenzz May 24, 2024
b41d49b
fix backend module bugs
wwenzz May 24, 2024
998d801
Refactor frontend code
wwenzz May 24, 2024
9b25d4c
fix the cors
wwenzz May 24, 2024
e9940bf
fix access token
wwenzz May 24, 2024
25ffea3
navigate the user to secrets page when sucessfully signing up
wwenzz May 24, 2024
6d1e121
customise the errors in signup form
wwenzz May 24, 2024
0492c38
display error message in the frontend
wwenzz May 24, 2024
8dba60a
Modify the error message
wwenzz May 24, 2024
563046f
display detailed error
wwenzz May 24, 2024
0083ec0
Add id and name in the response of secrets endpoint
wwenzz May 24, 2024
aae2f48
add success as true to 200 response in login endpoint
wwenzz May 24, 2024
3ed1e4a
Add signout function in frontend
wwenzz May 24, 2024
8bb0793
Style the homepage
wwenzz May 24, 2024
4f9bbc8
Merge signup & login form into authform component and style the new c…
wwenzz May 24, 2024
36f8a0e
hide email input for login form
wwenzz May 24, 2024
c970365
fix the navigate endpoint
wwenzz May 24, 2024
6b68167
Conditionally render the button text
wwenzz May 24, 2024
f72c72c
add accessToken to local storage
wwenzz May 24, 2024
a131ffc
fix the bug of localStorage
wwenzz May 24, 2024
ceeeae7
fix the localStorage
wwenzz May 24, 2024
52eb2db
console log data to debug
wwenzz May 24, 2024
fb0fabf
add success in json
wwenzz May 24, 2024
c80e168
Style the secrets component
wwenzz May 24, 2024
ed031f8
adjust style for secrets component
wwenzz May 24, 2024
8b87e5b
Adjust the animation style
wwenzz May 24, 2024
3758a65
adjust the localstorage key in secrets component
wwenzz May 24, 2024
fcb137a
set loading state and add 401 animation
wwenzz May 24, 2024
db8024c
remove console logs and adjust error message
wwenzz May 24, 2024
4546d20
add links of deployed frontend and backend to readme
wwenzz May 24, 2024
156ed53
correct a typo in the message
wwenzz May 24, 2024
af6cbab
set the message as null when navigating
wwenzz May 24, 2024
d712da0
add error handling for no accesstoken
wwenzz May 24, 2024
3a201f3
save access token only when logging in
wwenzz May 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,26 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*

package-lock.json
package-lock.json
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
# Project Auth API

Replace this readme with your own information about your project.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.
This assignment involves creating a backend API with Mongoose for user registration, login, and an authenticated endpoint for logged-in users. The React frontend includes registration and login forms, a page for authenticated content, and a sign-out button that clears the access token from local storage. The API should validate user input, encrypt passwords with bcrypt, and handle unauthorized access with appropriate error messages.

## The problem

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
We were confused by the instructions. Authentication using tokens was required, but we also implemented authentication using sessions with Passport.js for higher security.

## View it live

Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
Frontend: https://team-peace-auth.netlify.app
Backend: https://project-auth-lh3p.onrender.com
31 changes: 30 additions & 1 deletion backend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,31 @@
package-lock.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
package-lock.json
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
3 changes: 3 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
"@babel/core": "^7.17.9",
"@babel/node": "^7.16.8",
"@babel/preset-env": "^7.16.11",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.17.3",
"express-list-endpoints": "^7.1.0",
"mongoose": "^8.0.0",
"nodemon": "^3.0.1"
}
Expand Down
116 changes: 110 additions & 6 deletions backend/server.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,128 @@
import bcrypt from "bcrypt";
import cors from "cors";
import dotenv from "dotenv";
import express from "express";
import expressListEndpoints from "express-list-endpoints";
import mongoose from "mongoose";

const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo";
dotenv.config();
const { Schema } = mongoose;
const mongoUrl =
process.env.MONGO_URL || "mongodb://localhost/project-authentication";
mongoose.connect(mongoUrl);
mongoose.Promise = Promise;

// Defines the port the app will run on. Defaults to 8080, but can be overridden
// when starting the server. Example command to overwrite PORT env variable value:
// PORT=9000 npm start
const userSchema = new Schema({
username: { type: String, unique: true, required: true, minLength: 8 },
email: {
type: String,
unique: true,
required: true,
match: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
},
password: { type: String, required: true },
accessToken: { type: String, default: () => bcrypt.genSaltSync() },
Comment on lines +16 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice if all properties were formatted like the email one 😄

});

const User = mongoose.model("User", userSchema);

const port = process.env.PORT || 8080;
const app = express();

// Function for authenticate by token
const authenticateUser = async (req, res, next) => {
const user = await User.findOne({ accessToken: req.header("Authorization") });
if (user) {
req.user = user;
next();
} else {
res.status(401).json({
message: "Unauthorised access",
success: false,
error: "You are not allowed to see our top secret message!",
});
}
};

// Add middlewares to enable cors and json body parsing
app.use(cors());
app.use(
cors({
origin: "https://team-peace-auth.netlify.app",
methods: ["GET", "POST"],
}) // Allow sending credentials from frontend to backend
);
app.use(express.json());

// Start defining your routes here
app.get("/", (req, res) => {
res.send("Hello Technigo!");
const endpoints = expressListEndpoints(app);
res.json(endpoints);
});

// Sign-up
app.post("/signup", async (req, res) => {
try {
const { username, email, password } = req.body;
const user = new User({
username,
email,
password: bcrypt.hashSync(password, 10),
});
await user.save();
res.status(201).json({ message: "Sign up successfully", success: true });
} catch (error) {
console.log(error.message);
res.status(400).json({
message: "Could not sign up.",
success: false,
error: error.message,
});
}
});

// Log-in
app.post("/login", async (req, res) => {
Comment on lines +63 to +84
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually endpoints are named in plural nouns, after what they return or in this case create. So a name suggestion is: POST /users and POST /sessions

try {
const { username, password } = req.body;
const user = await User.findOne({ username });

if (user && bcrypt.compareSync(password, user.password)) {
res.status(200).json({
message: "Login Successful.",
success: true,
accessToken: user.accessToken,
});
} else if (user) {
res.status(401).json({
message: "Could not login.",
success: false,
error: "Incorrect password",
});
} else {
res.status(401).json({
message: "Could not login.",
success: false,
error: "Invalid username",
});
}
} catch (error) {
res.status(400).json({
message: "Could not login. Something is wrong.",
success: false,
error: error.message,
});
}
});

// secrets - Authentication method 2 - by Token
app.get("/secrets", authenticateUser);
app.get("/secrets", (req, res) => {
res.json({
message: "This is a super secret message",
success: true,
id: req.user._id,
name: req.user.username,
});
});

// Start the server
Expand Down
7 changes: 7 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,11 @@ dist-ssr
*.sln
*.sw?

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

package-lock.json
8 changes: 7 additions & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&display=swap"
rel="stylesheet"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
Expand Down
6 changes: 4 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"dev": "vite --port 5173",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"lottie-react": "^2.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-router-dom": "^6.23.1"
},
"devDependencies": {
"@types/react": "^18.2.15",
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import { AuthRoutes } from "./routes/AuthRoutes";
import { BrowserRouter } from "react-router-dom";

export const App = () => {
return <div>Find me in src/app.jsx!</div>;
return (
<BrowserRouter>
<h1>TOP secret saver!</h1>
<AuthRoutes />
</BrowserRouter>
);
};
1 change: 1 addition & 0 deletions frontend/src/assets/401.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/src/assets/home-animation.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/src/assets/loading.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"v":"5.8.1","fr":29.9700012207031,"ip":0,"op":57.0000023216576,"w":1080,"h":1080,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":5,"ty":4,"nm":"Load3 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,539,0],"ix":2,"l":2},"a":{"a":0,"k":[1518,1004.5,0],"ix":1,"l":2},"s":{"a":0,"k":[51.5,51.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-350.603,530.029],[-350.603,-100.78799999999998],[-193.633,-684.641],[0.001,-684.641],[350.603,-527.678],[350.603,334.722],[350.603,339.305],[195.99099999999999,684.641],[-5.267,684.641]],"o":[[-350.603,339.305],[-350.603,-527.678],[0,-684.641],[193.633,-684.641],[350.603,-334.046],[350.603,334.722],[350.603,530.029],[5.267,684.641],[-195.99099999999999,684.641]],"v":[[-350.603,339.305],[-350.603,-334.046],[0,-684.641],[0.001,-684.641],[350.603,-334.046],[350.603,334.722],[350.603,339.305],[5.267,684.641],[-5.267,684.641]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false,"_render":true},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[50]},{"t":37.0000015070409,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[69]},{"t":37.0000015070409,"s":[19]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false,"_render":true},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[0.9244,0.8486,0.3556,1]},{"t":37.0000015070409,"s":[0.2353,0.149,0.9961,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":150,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[1327.382,1042.938],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform","_render":true}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true}],"ip":0,"op":58.0000023623884,"st":-38.0000015477717,"bm":0,"completed":true},{"ddd":0,"ind":6,"ty":4,"nm":"Load3 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[344,580,0],"ix":2,"l":2},"a":{"a":0,"k":[1518,1004.5,0],"ix":1,"l":2},"s":{"a":0,"k":[51.5,51.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-350.603,530.029],[-350.603,-100.78799999999998],[-193.633,-684.641],[0.001,-684.641],[350.603,-527.678],[350.603,334.722],[350.603,339.305],[195.99099999999999,684.641],[-5.267,684.641]],"o":[[-350.603,339.305],[-350.603,-527.678],[0,-684.641],[193.633,-684.641],[350.603,-334.046],[350.603,334.722],[350.603,530.029],[5.267,684.641],[-195.99099999999999,684.641]],"v":[[-350.603,339.305],[-350.603,-334.046],[0,-684.641],[0.001,-684.641],[350.603,-334.046],[350.603,334.722],[350.603,339.305],[5.267,684.641],[-5.267,684.641]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false,"_render":true},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[0.2353,0.149,0.9961,1]},{"t":37.0000015070409,"s":[0.9725,0.8824,0.3216,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":150,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[1327.382,1042.938],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform","_render":true}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[50]},{"t":37.0000015070409,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[69]},{"t":37.0000015070409,"s":[19]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false,"_render":true}],"ip":0,"op":58.0000023623884,"st":-48.0000019550801,"bm":0,"completed":true},{"ddd":0,"ind":7,"ty":4,"nm":"Load3 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[799.136,559.345,0],"ix":2,"l":2},"a":{"a":0,"k":[2021.177,1040.875,0],"ix":1,"l":2},"s":{"a":0,"k":[51.5,51.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-347.995,336.15],[-192.192,684.141],[0,684.141],[347.995,528.342],[347.995,-334.141],[347.995,-338.725],[193.347,-684.141],[-2.575,-684.141],[-347.995,-529.491]],"o":[[-347.995,528.342],[0,684.141],[192.192,684.141],[347.995,336.15],[347.995,-334.141],[347.995,-529.493],[2.58,-684.141],[-193.345,-684.141],[-347.995,-338.72]],"v":[[-347.995,336.15],[0,684.141],[0,684.141],[347.995,336.15],[347.995,-334.141],[347.995,-338.725],[2.58,-684.141],[-2.575,-684.141],[-347.995,-338.72]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false,"_render":true},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[81]},{"t":51.0000020772726,"s":[31]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[100]},{"t":51.0000020772726,"s":[50]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false,"_render":true},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[0.3124,0.3779,0.9676,1]},{"t":51.0000020772726,"s":[1,0.5412,0.4902,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":150,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[1673.182,1042.438],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform","_render":true}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true}],"ip":0,"op":58.0000023623884,"st":-42.0000017106951,"bm":0,"completed":true},{"ddd":0,"ind":8,"ty":4,"nm":"Load3 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-180,"ix":10},"p":{"a":0,"k":[440.864,560.955,0],"ix":2,"l":2},"a":{"a":0,"k":[2021.177,1020.875,0],"ix":1,"l":2},"s":{"a":0,"k":[51.5,51.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-347.995,336.15],[-192.192,684.141],[0,684.141],[347.995,528.342],[347.995,-334.141],[347.995,-338.725],[193.347,-684.141],[-2.575,-684.141],[-347.995,-529.491]],"o":[[-347.995,528.342],[0,684.141],[192.192,684.141],[347.995,336.15],[347.995,-334.141],[347.995,-529.493],[2.58,-684.141],[-193.345,-684.141],[-347.995,-338.72]],"v":[[-347.995,336.15],[0,684.141],[0,684.141],[347.995,336.15],[347.995,-334.141],[347.995,-338.725],[2.58,-684.141],[-2.575,-684.141],[-347.995,-338.72]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false,"_render":true},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[81]},{"t":51.0000020772726,"s":[31]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[100]},{"t":51.0000020772726,"s":[50]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false,"_render":true},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[0.9734,0.3373,0.2666,1]},{"t":51.0000020772726,"s":[0.4431,0.502,0.9922,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":150,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[1673.182,1022.438],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform","_render":true}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true}],"ip":0,"op":58.0000023623884,"st":-42.0000017106951,"bm":0,"completed":true}],"markers":[],"__complete":true}
Loading