additional changes, setup localStorage

This commit is contained in:
Maciek Głowacki 2020-12-12 17:54:13 +01:00
parent 8ba07f5c07
commit 597f17695d
16 changed files with 12141 additions and 15123 deletions

1
decs.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'react-loading-overlay';

15061
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,9 @@
"react": "16.8.0", "react": "16.8.0",
"react-click-away-listener": "^1.4.3", "react-click-away-listener": "^1.4.3",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-loading-overlay": "^1.0.1",
"react-scripts": "3.4.1", "react-scripts": "3.4.1",
"react-spinners": "^0.9.0",
"styled-components": "^5.1.1" "styled-components": "^5.1.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,11 +1,13 @@
import React, { useState } from 'react'; import React, { ElementType, useContext, useState } from 'react';
import Topbar from './Topbar'; import Topbar from './Topbar';
import { Transfer } from './Transfer'; import { Transfer } from './Transfer';
import { Admin } from './Admin'; import { Admin } from './Admin';
import { Scheduler } from './Scheduler'; import { Scheduler } from './Scheduler';
import { Rightbar } from './Rightbar'; import { Rightbar } from './Rightbar';
import styled from 'styled-components'; import styled from 'styled-components';
import { coursesContext } from '../contexts/CoursesProvider';
import LoadingOverlay from 'react-loading-overlay';
import { SyncLoader } from 'react-spinners';
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
height: calc(100vh - 80px); height: calc(100vh - 80px);
@ -16,21 +18,31 @@ const Wrapper = styled.div`
`; `;
export const App = () => { export const App = () => {
const { isDataLoading } = useContext(coursesContext)!;
const [isOpenTransfer, setOpenTransfer] = useState(false); const [isOpenTransfer, setOpenTransfer] = useState(false);
const handleTransfer = () => { const handleTransfer = () => {
setOpenTransfer(!isOpenTransfer); setOpenTransfer(!isOpenTransfer);
}; };
const userPrivilige = localStorage.getItem('userPrivilige');
return ( return (
<> <>
<Topbar handleTransfer={handleTransfer} /> <LoadingOverlay active={isDataLoading} spinner={<SyncLoader />}>
<Transfer isOpen={isOpenTransfer} handleClose={handleTransfer} /> <Topbar handleTransfer={handleTransfer} />
<Wrapper> <Transfer isOpen={isOpenTransfer} handleClose={handleTransfer} />
<Wrapper>
{sessionStorage.getItem('userPrivilage')=== "STUDENT" ? <><Scheduler /> {userPrivilige === 'STUDENT' ? (
<Rightbar /></>: <Admin/>} <>
</Wrapper> <Scheduler />
<Rightbar />
</>
) : (
<Admin />
)}
</Wrapper>
</LoadingOverlay>
</> </>
); );
}; };

View File

@ -8,6 +8,7 @@ import { makeStyles } from '@material-ui/core/styles';
import DeleteIcon from '@material-ui/icons/Delete'; import DeleteIcon from '@material-ui/icons/Delete';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { createClassTime } from '../utils'; import { createClassTime } from '../utils';
import { dayMapping } from '../constants';
const CourseCardWrapper = styled.div` const CourseCardWrapper = styled.div`
position: relative; position: relative;
@ -51,9 +52,9 @@ const CourseName = styled.div`
const ClassGroupStyled = styled.div` const ClassGroupStyled = styled.div`
position: relative; position: relative;
padding-top: 1px; padding-top: 10px;
padding-bottom: 5px; padding-bottom: 10px;
transition: background-color 0.4s ease; transition: color 0.3s, background-color 0.3s;
:hover { :hover {
cursor: pointer; cursor: pointer;
background-color: #9ed3ff; background-color: #9ed3ff;
@ -147,8 +148,8 @@ export const CourseCard = ({ course }: CourseCardProps) => {
const groups = [...course.lectures!, ...course.classes!]; const groups = [...course.lectures!, ...course.classes!];
const basketCourseGroups = useMemo(() => selectBasketCourseGroups(course.id), []); const basketCourseGroups = useMemo(() => selectBasketCourseGroups(course.id), []);
const [previous, setPrevious] = useState(basketCourseGroups); const [previous, setPrevious] = useState(basketCourseGroups);
// console.log('lecture is: ', courseLecture);
// console.log('class is: ', courseClasses); console.log('course is: ', course);
const onGroupClick = (group: Group, courseId: number) => { const onGroupClick = (group: Group, courseId: number) => {
setPrevious((prev) => (group.type === GroupType.CLASS ? { ...prev, classes: group } : { ...prev, lecture: group })); setPrevious((prev) => (group.type === GroupType.CLASS ? { ...prev, classes: group } : { ...prev, lecture: group }));
changeGroupInBasket(group, courseId); changeGroupInBasket(group, courseId);
@ -175,11 +176,9 @@ export const CourseCard = ({ course }: CourseCardProps) => {
onMouseEnter={() => { onMouseEnter={() => {
if (group.type === GroupType.CLASS) { if (group.type === GroupType.CLASS) {
changeGroupInBasket(group, course.id); changeGroupInBasket(group, course.id);
// setTimeout(()=> { changeHoveredGroup(courseClasses)},[500])
} }
if (group.type === GroupType.LECTURE) { if (group.type === GroupType.LECTURE) {
changeGroupInBasket(group, course.id); changeGroupInBasket(group, course.id);
// setTimeout(()=> { changeHoveredGroup(courseLecture)},[500])
} }
}} }}
onMouseLeave={() => { onMouseLeave={() => {
@ -205,8 +204,14 @@ export const CourseCard = ({ course }: CourseCardProps) => {
{group.lecturer.replace('UAM', '')} {group.lecturer.replace('UAM', '')}
</FlexItem> </FlexItem>
)} )}
<FlexItem style={{ justifyContent: 'center', margin: '0 50px' }}> <FlexItem style={{ justifyContent: 'center', flexDirection: 'column' }}>
<span> {createClassTime(group.time)[0] + " - " + createClassTime(group.time)[1]} {/* Sala: {group.room} */}</span> {/* <span>
{dayMapping[group.day]} {createClassTime(group.time)[0]} - {createClassTime(group.time)[1]}
</span> */}
<div>{dayMapping[group.day]}</div>
<div>
{createClassTime(group.time)[0]} - {createClassTime(group.time)[1]}
</div>
</FlexItem> </FlexItem>
</FlexboxWrapper> </FlexboxWrapper>
</ClassGroupStyled> </ClassGroupStyled>

View File

@ -1,4 +1,4 @@
import React, { Fragment, MouseEvent, useState, useEffect, useContext } from 'react'; import React, { Fragment, MouseEvent, useState, useEffect, useContext } from 'react';
import { GroupType, SchedulerEvent } from '../types'; import { GroupType, SchedulerEvent } from '../types';
import styled, { css } from 'styled-components/macro'; import styled, { css } from 'styled-components/macro';
import Popover from '@material-ui/core/Popover'; import Popover from '@material-ui/core/Popover';
@ -70,6 +70,12 @@ const StyledSchedulerEvent = styled.div<SchedulerEventProps>`
return groupType === 'CLASS' ? '#FFDC61' : '#9ed3ff'; return groupType === 'CLASS' ? '#FFDC61' : '#9ed3ff';
} }
}}; }};
${({ isHovered }) =>
isHovered &&
css`
transition: background-color 0.4s ease;
`}
box-shadow: 3px 3px 3px 0px rgba(0, 0, 0, 0.75); box-shadow: 3px 3px 3px 0px rgba(0, 0, 0, 0.75);
`; `;

View File

@ -54,13 +54,17 @@ const FlexboxColumn = styled.div`
flex: 12; flex: 12;
`; `;
const InputWrapper = styled.div` type InputWrapperProps = {
isStudent: boolean;
};
const InputWrapper = styled.div<InputWrapperProps>`
width: 100%; width: 100%;
display: flex; display: flex;
margin-top: 15px; margin-top: 15px;
max-height: 40px; max-height: 40px;
background-color: #f2f4f7; background-color: #f2f4f7;
border-radius: 0px 6px 6px 0px; border-radius: ${({ isStudent }) => (isStudent ? ` 6px 6px 6px 6px` : ` 0px 6px 6px 0px`)};
padding-left: 6px; padding-left: 6px;
&:hover { &:hover {
background-color: #ffffff; background-color: #ffffff;
@ -123,6 +127,8 @@ interface TopbarProps {
} }
export default function ({ handleTransfer }: TopbarProps) { export default function ({ handleTransfer }: TopbarProps) {
const userPrivilige = localStorage.getItem('userPrivilige');
const [clearInput, setClearInput] = useState(false); const [clearInput, setClearInput] = useState(false);
const [isPolish, setIsPolish] = useState(false); const [isPolish, setIsPolish] = useState(false);
const [anchorEl, setAnchorEl] = useState<HTMLImageElement | null>(null); const [anchorEl, setAnchorEl] = useState<HTMLImageElement | null>(null);
@ -130,7 +136,7 @@ export default function ({ handleTransfer }: TopbarProps) {
const [input, setInput] = useState(''); const [input, setInput] = useState('');
const [selectedOption, setSelectedOption] = useState('przedmioty'); const [selectedOption, setSelectedOption] = useState('przedmioty');
const changeSelectedOption = (option:string) => setSelectedOption(option); const changeSelectedOption = (option: string) => setSelectedOption(option);
const onLangChange = () => setIsPolish(!isPolish); const onLangChange = () => setIsPolish(!isPolish);
@ -162,10 +168,16 @@ export default function ({ handleTransfer }: TopbarProps) {
<FlexboxColumn> <FlexboxColumn>
<ClickAwayListener onClickAway={handleCloseDropdown}> <ClickAwayListener onClickAway={handleCloseDropdown}>
<Flexbox> <Flexbox>
{sessionStorage.getItem('userPrivilage')=== "STUDENT" ? (<div></div>): <SelectMenu changeSelectedOption={changeSelectedOption} selectedOption={selectedOption} changeDropdownOpen={setOpen}/>} {userPrivilige !== 'STUDENT' && (
<InputWrapper> <SelectMenu
changeSelectedOption={changeSelectedOption}
selectedOption={selectedOption}
changeDropdownOpen={setOpen}
/>
)}
<InputWrapper isStudent={userPrivilige === 'STUDENT'}>
<Input <Input
placeholder={`Wyszukaj ${selectedOption === "studenci" ? "studentów..." : "przedmioty..."}`} placeholder={`Wyszukaj ${selectedOption === 'studenci' ? 'studentów...' : 'przedmioty...'}`}
onChange={handleChange} onChange={handleChange}
value={input} value={input}
onFocus={() => { onFocus={() => {
@ -175,14 +187,19 @@ export default function ({ handleTransfer }: TopbarProps) {
<CloseIcon onClick={handleClearInput} /> <CloseIcon onClick={handleClearInput} />
</InputWrapper> </InputWrapper>
</Flexbox> </Flexbox>
<Dropdown open={open} input={input} handleCloseDropdown={handleCloseDropdown} selectedOption={selectedOption}/> <Dropdown
open={open}
input={input}
handleCloseDropdown={handleCloseDropdown}
selectedOption={selectedOption}
/>
</ClickAwayListener> </ClickAwayListener>
</FlexboxColumn> </FlexboxColumn>
<IconWrapper> <IconWrapper>
{/* <Text>Maciej Głowacki</Text> */} {/* <Text>Maciej Głowacki</Text> */}
{/* <Icon alt="transfer" src={Transfer} onClick={handleTransfer} /> */} {/* <Icon alt="transfer" src={Transfer} onClick={handleTransfer} /> */}
<Icon alt="change_language" src={isPolish ? EnglishIcon : PolishIcon} onClick={onLangChange} /> {/* <Icon alt="change_language" src={isPolish ? EnglishIcon : PolishIcon} onClick={onLangChange} /> */}
<Icon alt="profile" src={ProfileIcon} onClick={handleProfile} /> <Icon alt="profile" src={ProfileIcon} onClick={handleProfile} />
<Profile anchorEl={anchorEl} handleClose={handleCloseProfile} /> <Profile anchorEl={anchorEl} handleClose={handleCloseProfile} />
</IconWrapper> </IconWrapper>

View File

@ -42,3 +42,12 @@ export const courseStartTimeToEventRow: { [time: string]: number } = {
//groupTimeToEventRowMapping - 1; //groupTimeToEventRowMapping - 1;
export const ROWS_COUNT = 6; export const ROWS_COUNT = 6;
export const dayMapping: { [key: number]: string } = {
0: 'poniedziałek',
1: 'wtorek',
2: 'środa',
3: 'czwartek',
4: 'piątek',
5: 'sobota',
6: 'niedziela',
};

View File

@ -25,12 +25,12 @@ export const CASProvider = ({ children }: CASProviderProps) => {
redirectToCASLoginService(); redirectToCASLoginService();
} }
try { try {
if (!sessionStorage.getItem('userToken')) { if (!localStorage.getItem('userToken')) {
const { data: token } = await axiosInstance.get(`${process.env.REACT_APP_API_URL}/token?ticket=${ticket}`); const { data: token } = await axiosInstance.get(`${process.env.REACT_APP_API_URL}/token?ticket=${ticket}`);
sessionStorage.setItem('userToken', token.token); localStorage.setItem('userToken', token.token);
sessionStorage.setItem('userPrivilage', token.authorityRole) localStorage.setItem('userPrivilige', token.authorityRole);
} }
const tokenTMP:any = JSON.parse(sessionStorage.getItem('userToken')as string); const tokenTMP: any = JSON.parse(localStorage.getItem('userToken') as string);
const token: Token = { const token: Token = {
authorityRole: tokenTMP.authorityRole, authorityRole: tokenTMP.authorityRole,
email: tokenTMP.email, email: tokenTMP.email,

View File

@ -18,14 +18,15 @@ interface CourseContext {
courses: Array<Course>; courses: Array<Course>;
basket: Array<Basket>; basket: Array<Basket>;
hoveredGroup: Group | undefined | null; hoveredGroup: Group | undefined | null;
userID:string; userID: string;
isDataLoading: boolean;
addCourseToBasket: (courses: Course) => void; addCourseToBasket: (courses: Course) => void;
changeHoveredGroup: (group: Group | null) => void; changeHoveredGroup: (group: Group | null) => void;
changeGroupInBasket: (group: Group, courseId: number) => void; changeGroupInBasket: (group: Group, courseId: number) => void;
restoreGroupInBasket: (restoreGroup: Group, courseId: number) => void; restoreGroupInBasket: (restoreGroup: Group, courseId: number) => void;
deleteFromBasket: (id: number) => void; deleteFromBasket: (id: number) => void;
saveBasket: (userID: string) => Promise<void> saveBasket: (userID: string) => Promise<void>;
getUserID: (userID: string) => Promise<void> getUserID: (userID: string) => Promise<void>;
selectSchedulerEvents: () => Array<SchedulerEvent>; selectSchedulerEvents: () => Array<SchedulerEvent>;
selectBasketNames: () => Array<string>; selectBasketNames: () => Array<string>;
selectBasketCourses: () => Array<Course>; selectBasketCourses: () => Array<Course>;
@ -45,8 +46,10 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
//fetch courses with groups //fetch courses with groups
const [courses, setCourses] = useState<Array<Course>>([]); const [courses, setCourses] = useState<Array<Course>>([]);
const [basket, setBasket] = useState<Array<Basket>>([]); const [basket, setBasket] = useState<Array<Basket>>([]);
const [userID, setUserID] = useState(""); const [userID, setUserID] = useState('');
const [hoveredGroup, setHoveredGroup] = useState<Group | undefined | null>(null); const [hoveredGroup, setHoveredGroup] = useState<Group | undefined | null>(null);
const [isDataLoading, setIsDataLoading] = useState(false);
const selectBasketIds = () => { const selectBasketIds = () => {
const classesIds = basket.map((course) => course?.classes?.id).filter((course) => course !== undefined); const classesIds = basket.map((course) => course?.classes?.id).filter((course) => course !== undefined);
const lecturesIds = basket.map((course) => course?.lecture?.id).filter((course) => course !== undefined); const lecturesIds = basket.map((course) => course?.lecture?.id).filter((course) => course !== undefined);
@ -101,11 +104,11 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
const deleteFromBasket = (id: number) => setBasket(basket.filter((course) => course.id !== id)); const deleteFromBasket = (id: number) => setBasket(basket.filter((course) => course.id !== id));
const getUserID = async (userID:string) => { const getUserID = async (userID: string) => {
setUserID(userID); setUserID(userID);
} };
const saveBasket = async (userID:string) => { const saveBasket = async (userID: string) => {
const basketIds = selectBasketIds(); const basketIds = selectBasketIds();
const action = (key: any) => ( const action = (key: any) => (
<> <>
@ -118,7 +121,10 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
); );
try { try {
await axiosInstance.post(`${process.env.REACT_APP_API_URL}/api/v1/commisions/user/${userID}`, JSON.stringify(basketIds)); await axiosInstance.post(
`${process.env.REACT_APP_API_URL}/api/v1/commisions/user/${userID}`,
JSON.stringify(basketIds),
);
enqueueSnackbar('Plan został zapisany', { enqueueSnackbar('Plan został zapisany', {
variant: 'success', variant: 'success',
action, action,
@ -163,9 +169,7 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
const getNewestTimetable = async () => { const getNewestTimetable = async () => {
try { try {
const { data } = await axiosInstance.get( const { data } = await axiosInstance.get(`${process.env.REACT_APP_API_URL}/api/v1/assignments/user`);
`${process.env.REACT_APP_API_URL}/api/v1/assignments/user`,
);
const basket = data === '' ? [] : data; const basket = data === '' ? [] : data;
setBasket(basket); setBasket(basket);
} catch (e) { } catch (e) {
@ -173,16 +177,14 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
} }
}; };
const getUserTimetable = async (userID:string) => { const getUserTimetable = async (userID: string) => {
try { try {
const {data} = await axiosInstance.get( const { data } = await axiosInstance.get(`${process.env.REACT_APP_API_URL}/api/v1/commisions/user/${userID}`);
`${process.env.REACT_APP_API_URL}/api/v1/commisions/user/${userID}`,
);
console.log(data); console.log(data);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} }
} };
const fetchCourses = async () => { const fetchCourses = async () => {
try { try {
@ -197,10 +199,12 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
}; };
useEffect(() => { useEffect(() => {
setIsDataLoading(true);
setTimeout(() => { setTimeout(() => {
fetchCourses(); fetchCourses();
getNewestTimetable(); getNewestTimetable();
}, 10); setIsDataLoading(false);
}, 500);
}, []); }, []);
return ( return (
@ -210,6 +214,7 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
courses, courses,
basket, basket,
hoveredGroup, hoveredGroup,
isDataLoading,
addCourseToBasket, addCourseToBasket,
changeHoveredGroup, changeHoveredGroup,
changeGroupInBasket, changeGroupInBasket,

View File

@ -14,19 +14,21 @@ interface UsersProviderProps {
export const UsersProvider = ({ children }: UsersProviderProps) => { export const UsersProvider = ({ children }: UsersProviderProps) => {
const [users, setUsers] = useState<Array<User>>([]); const [users, setUsers] = useState<Array<User>>([]);
const getUsers = async () => { const getUsers = async () => {
try { try {
const {data}= await axiosInstance.get<Array<User>>(`${process.env.REACT_APP_API_URL}/api/v1/users/students`); const { data } = await axiosInstance.get<Array<User>>(`${process.env.REACT_APP_API_URL}/api/v1/users/students`);
setUsers(data); setUsers(data);
console.log(data); console.log(data);
} catch(e){ } catch (e) {
console.log(e); console.log(e);
} }
}; };
useEffect(() => { useEffect(() => {
setTimeout(() => {
getUsers(); getUsers();
}, 500);
}, []); }, []);
return ( return (

View File

@ -4,9 +4,9 @@ export const axiosInstance = axios.create();
axiosInstance.interceptors.request.use( axiosInstance.interceptors.request.use(
(config) => { (config) => {
const token = sessionStorage.getItem('userToken'); const token = localStorage.getItem('userToken');
config.headers['Authorization'] = 'Bearer ' + token;
config.headers['Content-Type'] = 'application/json'; config.headers['Content-Type'] = 'application/json';
config.headers['Authorization'] = token ? `Bearer ${token}` : '';
return config; return config;
}, },
(error) => { (error) => {

View File

@ -13,6 +13,10 @@ export const selectGroupsToShow = (schedulerEvents: Array<SchedulerEvent>, index
return schedulerEvents.filter(({ time }: { time: [string, string] }) => courseStartTimeToEventRow[time[0]] === index); return schedulerEvents.filter(({ time }: { time: [string, string] }) => courseStartTimeToEventRow[time[0]] === index);
}; };
//debounce declaration and implementation
type Procedure = (...args: any[]) => any; type Procedure = (...args: any[]) => any;
interface Debounce { interface Debounce {

View File

@ -15,5 +15,5 @@
"noEmit": true, "noEmit": true,
"jsx": "react" "jsx": "react"
}, },
"include": ["src"] "include": ["src", "decs.d.ts"]
} }

11882
yarn-error.log Normal file

File diff suppressed because it is too large Load Diff

150
yarn.lock
View File

@ -1153,7 +1153,7 @@
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7": "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7":
version "7.12.5" version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
@ -1251,7 +1251,38 @@
resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18"
integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==
"@emotion/hash@^0.8.0": "@emotion/cache@^10.0.27":
version "10.0.29"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
dependencies:
"@emotion/sheet" "0.9.4"
"@emotion/stylis" "0.8.5"
"@emotion/utils" "0.11.3"
"@emotion/weak-memoize" "0.2.5"
"@emotion/core@^10.0.15":
version "10.1.1"
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3"
integrity sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==
dependencies:
"@babel/runtime" "^7.5.5"
"@emotion/cache" "^10.0.27"
"@emotion/css" "^10.0.27"
"@emotion/serialize" "^0.11.15"
"@emotion/sheet" "0.9.4"
"@emotion/utils" "0.11.3"
"@emotion/css@^10.0.27":
version "10.0.27"
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c"
integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==
dependencies:
"@emotion/serialize" "^0.11.15"
"@emotion/utils" "0.11.3"
babel-plugin-emotion "^10.0.27"
"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0":
version "0.8.0" version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
@ -1268,16 +1299,42 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
"@emotion/stylis@^0.8.4": "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
version "0.11.16"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==
dependencies:
"@emotion/hash" "0.8.0"
"@emotion/memoize" "0.7.4"
"@emotion/unitless" "0.7.5"
"@emotion/utils" "0.11.3"
csstype "^2.5.7"
"@emotion/sheet@0.9.4":
version "0.9.4"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
"@emotion/stylis@0.8.5", "@emotion/stylis@^0.8.4":
version "0.8.5" version "0.8.5"
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
"@emotion/unitless@^0.7.4": "@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4":
version "0.7.5" version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@emotion/utils@0.11.3":
version "0.11.3"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924"
integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==
"@emotion/weak-memoize@0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@hapi/address@2.x.x": "@hapi/address@2.x.x":
version "2.1.4" version "2.1.4"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
@ -2572,6 +2629,22 @@ babel-plugin-dynamic-import-node@^2.3.3:
dependencies: dependencies:
object.assign "^4.1.0" object.assign "^4.1.0"
babel-plugin-emotion@^10.0.27:
version "10.0.33"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz#ce1155dcd1783bbb9286051efee53f4e2be63e03"
integrity sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@emotion/hash" "0.8.0"
"@emotion/memoize" "0.7.4"
"@emotion/serialize" "^0.11.16"
babel-plugin-macros "^2.0.0"
babel-plugin-syntax-jsx "^6.18.0"
convert-source-map "^1.5.0"
escape-string-regexp "^1.0.5"
find-root "^1.1.0"
source-map "^0.5.7"
babel-plugin-istanbul@^5.1.0: babel-plugin-istanbul@^5.1.0:
version "5.2.0" version "5.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854"
@ -2589,7 +2662,7 @@ babel-plugin-jest-hoist@^24.9.0:
dependencies: dependencies:
"@types/babel__traverse" "^7.0.6" "@types/babel__traverse" "^7.0.6"
babel-plugin-macros@2.8.0: babel-plugin-macros@2.8.0, babel-plugin-macros@^2.0.0:
version "2.8.0" version "2.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
@ -3483,7 +3556,7 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
convert-source-map@1.7.0, convert-source-map@^1.4.0, convert-source-map@^1.7.0: convert-source-map@1.7.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.7.0:
version "1.7.0" version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
@ -3587,6 +3660,16 @@ create-ecdh@^4.0.0:
bn.js "^4.1.0" bn.js "^4.1.0"
elliptic "^6.5.3" elliptic "^6.5.3"
create-emotion@^10.0.27:
version "10.0.27"
resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.27.tgz#cb4fa2db750f6ca6f9a001a33fbf1f6c46789503"
integrity sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==
dependencies:
"@emotion/cache" "^10.0.27"
"@emotion/serialize" "^0.11.15"
"@emotion/sheet" "0.9.4"
"@emotion/utils" "0.11.3"
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
@ -3885,7 +3968,7 @@ cssstyle@^1.0.0, cssstyle@^1.1.1:
dependencies: dependencies:
cssom "0.3.x" cssom "0.3.x"
csstype@^2.5.2: csstype@^2.5.2, csstype@^2.5.7:
version "2.6.14" version "2.6.14"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.14.tgz#004822a4050345b55ad4dcc00be1d9cf2f4296de" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.14.tgz#004822a4050345b55ad4dcc00be1d9cf2f4296de"
integrity sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A== integrity sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==
@ -4153,6 +4236,13 @@ dom-converter@^0.2:
dependencies: dependencies:
utila "~0.4" utila "~0.4"
dom-helpers@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
dependencies:
"@babel/runtime" "^7.1.2"
dom-helpers@^5.0.1: dom-helpers@^5.0.1:
version "5.2.0" version "5.2.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b"
@ -4310,6 +4400,14 @@ emojis-list@^3.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
emotion@^10.0.1:
version "10.0.27"
resolved "https://registry.yarnpkg.com/emotion/-/emotion-10.0.27.tgz#f9ca5df98630980a23c819a56262560562e5d75e"
integrity sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==
dependencies:
babel-plugin-emotion "^10.0.27"
create-emotion "^10.0.27"
encodeurl@~1.0.2: encodeurl@~1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
@ -5069,6 +5167,11 @@ find-cache-dir@^3.2.0, find-cache-dir@^3.3.1:
make-dir "^3.0.2" make-dir "^3.0.2"
pkg-dir "^4.1.0" pkg-dir "^4.1.0"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@4.1.0, find-up@^4.0.0: find-up@4.1.0, find-up@^4.0.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@ -9344,6 +9447,20 @@ react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-loading-overlay@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/react-loading-overlay/-/react-loading-overlay-1.0.1.tgz#ee3b1ad56c45bb2f1ba46d4820ba0d06cd319a91"
integrity sha512-aUjtZ8tNXBSx+MbD2SQs0boPbeTAGTh+I5U9nWjDzMasKlYr58RJpr57c8W7uApeLpOkAGbInExRi6GamNC2bA==
dependencies:
emotion "^10.0.1"
prop-types "^15.6.2"
react-transition-group "^2.5.0"
react-scripts@3.4.1: react-scripts@3.4.1:
version "3.4.1" version "3.4.1"
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.1.tgz#f551298b5c71985cc491b9acf3c8e8c0ae3ada0a" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.1.tgz#f551298b5c71985cc491b9acf3c8e8c0ae3ada0a"
@ -9404,6 +9521,23 @@ react-scripts@3.4.1:
optionalDependencies: optionalDependencies:
fsevents "2.1.2" fsevents "2.1.2"
react-spinners@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.9.0.tgz#b22c38acbfce580cd6f1b04a4649e812370b1fb8"
integrity sha512-+x6eD8tn/aYLdxZjNW7fSR1uoAXLb9qq6TFYZR1dFweJvckcf/HfP8Pa/cy5HOvB/cvI4JgrYXTjh2Me3S6Now==
dependencies:
"@emotion/core" "^10.0.15"
react-transition-group@^2.5.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
dependencies:
dom-helpers "^3.4.0"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
react-transition-group@^4.4.0: react-transition-group@^4.4.0:
version "4.4.1" version "4.4.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
@ -10269,7 +10403,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@^0.5.0, source-map@^0.5.6: source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7" version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=