Implement masthead (#30)

This commit is contained in:
Stan Silvert 2020-08-20 20:09:05 -04:00 committed by GitHub
parent a21a196034
commit 18689c6194
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 228 additions and 115 deletions

View file

@ -16,10 +16,10 @@
"build-storybook": "build-storybook"
},
"dependencies": {
"@patternfly/patternfly": "^4.16.7",
"@patternfly/react-core": "^4.23.1",
"@patternfly/react-icons": "^4.4.2",
"@patternfly/react-table": "^4.12.1",
"@patternfly/patternfly": "^4.31.6",
"@patternfly/react-core": "^4.40.4",
"@patternfly/react-icons": "^4.7.2",
"@patternfly/react-table": "^4.15.5",
"i18next": "^19.6.2",
"i18next-http-backend": "^1.0.17",
"keycloak-js": "^11.0.0",

33
public/img_avatar.svg Normal file
View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 36 36" version="1.1" viewBox="0 0 36 36" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
/*stylelint-disable*/
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st1{filter:url(#b);}
.st2{mask:url(#a);}
.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#BBBBBB;}
.st4{opacity:0.1;fill-rule:evenodd;clip-rule:evenodd;enable-background:new ;}
.st5{opacity:8.000000e-02;fill-rule:evenodd;clip-rule:evenodd;fill:#231F20;enable-background:new ;}
/*stylelint-enable*/
</style>
<circle class="st0" cx="18" cy="18.5" r="18"/>
<defs>
<filter id="b" x="5.2" y="7.2" width="25.6" height="53.6" filterUnits="userSpaceOnUse">
<feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"/>
</filter>
</defs>
<mask id="a" x="5.2" y="7.2" width="25.6" height="53.6" maskUnits="userSpaceOnUse">
<g class="st1">
<circle class="st0" cx="18" cy="18.5" r="18"/>
</g>
</mask>
<g class="st2">
<g transform="translate(5.04 6.88)">
<path class="st3" d="m22.6 18.1c-1.1-1.4-2.3-2.2-3.5-2.6s-1.8-0.6-6.3-0.6-6.1 0.7-6.1 0.7 0 0 0 0c-1.2 0.4-2.4 1.2-3.4 2.6-2.3 2.8-3.2 12.3-3.2 14.8 0 3.2 0.4 12.3 0.6 15.4 0 0-0.4 5.5 4 5.5l-0.3-6.3-0.4-3.5 0.2-0.9c0.9 0.4 3.6 1.2 8.6 1.2 5.3 0 8-0.9 8.8-1.3l0.2 1-0.2 3.6-0.3 6.3c3 0.1 3.7-3 3.8-4.4s0.6-12.6 0.6-16.5c0.1-2.6-0.8-12.1-3.1-15z"/>
<path class="st4" d="m22.5 26c-0.1-2.1-1.5-2.8-4.8-2.8l2.2 9.6s1.8-1.7 3-1.8c0 0-0.4-4.6-0.4-5z"/>
<path class="st3" d="m12.7 13.2c-3.5 0-6.4-2.9-6.4-6.4s2.9-6.4 6.4-6.4 6.4 2.9 6.4 6.4-2.8 6.4-6.4 6.4z"/>
<path class="st5" d="m9.4 6.8c0-3 2.1-5.5 4.9-6.3-0.5-0.1-1-0.2-1.6-0.2-3.5 0-6.4 2.9-6.4 6.4s2.9 6.4 6.4 6.4c0.6 0 1.1-0.1 1.6-0.2-2.8-0.6-4.9-3.1-4.9-6.1z"/>
<path class="st4" d="m8.3 22.4c-2 0.4-2.9 1.4-3.1 3.5l-0.6 18.6s1.7 0.7 3.6 0.9l0.1-23z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1,5 +1,5 @@
@import "patternfly.min.css";
.brand {
.pf-c-brand {
height: 35px;
}

View file

@ -7,7 +7,6 @@ import { Client } from './clients/client-model';
import { Page, PageSection } from '@patternfly/react-core';
import { Header } from './PageHeader';
import { PageNav } from './PageNav';
import { NewRealmForm } from './forms/realm/NewRealmForm';
export const App = () => {
const httpClient = useContext(HttpClientContext);
@ -18,7 +17,7 @@ export const App = () => {
.then((r) => r.data as Client[]);
};
return (
<Page header={<Header />} sidebar={<PageNav />}>
<Page header={<Header />} isManagedSidebar sidebar={<PageNav />}>
<PageSection variant="light">
<DataLoader loader={loader}>
{(clients) => <ClientList clients={clients} />}

View file

@ -1,13 +1,149 @@
import React, { useContext } from 'react';
import { PageHeader, Brand, PageHeaderTools } from '@patternfly/react-core';
import React, { useContext, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
Avatar,
Button,
ButtonVariant,
Brand,
Dropdown,
DropdownItem,
DropdownSeparator,
DropdownToggle,
KebabToggle,
PageHeader,
PageHeaderTools,
PageHeaderToolsItem,
PageHeaderToolsGroup} from '@patternfly/react-core';
import { HelpIcon } from '@patternfly/react-icons';
import { KeycloakContext } from './auth/KeycloakContext';
export const Header = () => {
const keycloak = useContext(KeycloakContext);
return (
<PageHeader
logo={<Brand src="/logo.svg" alt="Logo" style={{ height: '35px' }} />}
headerTools={<PageHeaderTools>{keycloak?.loggedInUser}</PageHeaderTools>}
showNavToggle
logo={<Brand src="/logo.svg" alt="Logo" />}
headerTools={headerTools()}
/>
);
};
const ManageAccountDropdownItem = () => {
const keycloak = useContext(KeycloakContext);
const { t } = useTranslation();
return (
<DropdownItem key="manage account" onClick={() => keycloak?.account()}>{t('Manage account')}</DropdownItem>
);
}
const SignOutDropdownItem = () => {
const keycloak = useContext(KeycloakContext);
const { t } = useTranslation();
return (
<DropdownItem key="sign out" onClick={() => keycloak?.logout()}>{t('Sign out')}</DropdownItem>
);
}
const ServerInfoDropdownItem = () => {
const { t } = useTranslation();
return (
<DropdownItem key="server info">{t('Server info')}</DropdownItem>
)
}
const HelpDropdownItem = () => {
const { t } = useTranslation();
const help = t('Help');
return (
<DropdownItem><HelpIcon />{` ${help}`}</DropdownItem>
)
}
const kebabDropdownItems = [
<ManageAccountDropdownItem key='kebab Manage Account'/>,
<ServerInfoDropdownItem key='kebab Server Info'/>,
<HelpDropdownItem key='kebab Help'/>,
<DropdownSeparator key="kebab sign out seperator" />,
<SignOutDropdownItem key='kebab Sign out'/>
];
const userDropdownItems = [
<ManageAccountDropdownItem key='Manage Account'/>,
<ServerInfoDropdownItem key='Server info'/>,
<DropdownSeparator key="sign out seperator" />,
<SignOutDropdownItem key='Sign out'/>
];
const headerTools = () => {
return (
<PageHeaderTools>
<PageHeaderToolsGroup
visibility={{
default: 'hidden',
md: 'visible'
}} /** the settings and help icon buttons are only visible on desktop sizes and replaced by a kebab dropdown for other sizes */
>
<PageHeaderToolsItem>
<Button aria-label="Help actions" variant={ButtonVariant.plain}>
<HelpIcon />
</Button>
</PageHeaderToolsItem>
</PageHeaderToolsGroup>
<PageHeaderToolsGroup>
<PageHeaderToolsItem
visibility={{
md: 'hidden'
}} /** this kebab dropdown replaces the icon buttons and is hidden for desktop sizes */
>
<KebabDropdown/>
</PageHeaderToolsItem>
<PageHeaderToolsItem
visibility={{
default: 'hidden',
md: 'visible'
}} /** this user dropdown is hidden on mobile sizes */
>
<UserDropdown/>
</PageHeaderToolsItem>
</PageHeaderToolsGroup>
<Avatar src="/img_avatar.svg" alt="Avatar image" />
</PageHeaderTools>
);
}
const KebabDropdown = () => {
const [isDropdownOpen, setDropdownOpen] = useState(false);
const onDropdownToggle = () => {
setDropdownOpen(!isDropdownOpen);
};
return (
<Dropdown
isPlain
position="right"
toggle={<KebabToggle onToggle={onDropdownToggle} />}
isOpen={isDropdownOpen}
dropdownItems={kebabDropdownItems}
/>
)
}
const UserDropdown = () => {
const keycloak = useContext(KeycloakContext);
const [isDropdownOpen, setDropdownOpen] = useState(false);
const onDropdownToggle = () => {
setDropdownOpen(!isDropdownOpen);
};
return (
<Dropdown
isPlain
position="right"
isOpen={isDropdownOpen}
toggle={<DropdownToggle onToggle={onDropdownToggle}>{keycloak?.loggedInUser}</DropdownToggle>}
dropdownItems={userDropdownItems}
/>
);
}

View file

@ -26,7 +26,7 @@ export class KeycloakService {
this.keycloakAuth.login(options);
}
public logout(redirectUri: string): void {
public logout(redirectUri: string = ''): void {
this.keycloakAuth.logout({ redirectUri: redirectUri });
}

View file

@ -19,7 +19,7 @@ export function DataLoader<T>(props: DataLoaderProps<T>) {
loadData();
}, [props]);
if (!!data) {
if (data) {
if (props.children instanceof Function) {
return props.children(data.result);
}

View file

@ -1,8 +1,7 @@
import React, { useState } from "react";
import React from "react";
import {
Text,
PageSection,
PageSectionVariants,
TextContent,
FormGroup,
Form,
@ -14,11 +13,11 @@ import {
Divider,
} from "@patternfly/react-core";
type NewRealmFormProps = {
realm: string;
};
//type NewRealmFormProps = {
// realm: string;
//};
export const NewRealmForm = ({ realm }: NewRealmFormProps) => {
export const NewRealmForm = () => { //({ realm }: NewRealmFormProps) => {
return (
<>
<PageSection variant="light">

View file

@ -11,7 +11,13 @@
"applicationsIntroMessage": "Track and manage your app permission to access your account",
"fullName": "{{givenName}} {{familyName}}",
"unknownUser": "Anonymous",
"Keycloak Administration Console": "RH-SSO Administration Console"
"Keycloak Administration Console": "RH-SSO Administration Console",
"********* MASTHEAD *********": "",
"Sign out": "Sign out",
"Manage account": "Manage account",
"Server info": "Server info",
"Help": "Help"
}
}
}

128
yarn.lock
View file

@ -2738,93 +2738,51 @@
"@parcel/utils" "^1.11.0"
physical-cpu-count "^2.0.0"
"@patternfly/patternfly@4.23.3":
version "4.23.3"
resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-4.23.3.tgz#ecc60fe2a1c1315951dc39bf7d52ced9c1c74079"
integrity sha512-q8C98ihcRYBY+FB+KY3bQ9y1Pn/NjBff4hwKsxatrs/MSO/++CuEncg4q7WHjIq2zadA4/7W+Vg3CXuiOP0geg==
"@patternfly/patternfly@4.31.6", "@patternfly/patternfly@^4.31.6":
version "4.31.6"
resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-4.31.6.tgz#ef9919df610171760cd19920a904ca9b09a74593"
integrity sha512-gp8tpbE4Z6C1PIQwNiWMjO5XSr/UGjXs4InL/zmxgZbToyizUxsudwJyCObtdvDNoN57ZJp0gYWYy0tIuwEyMA==
"@patternfly/patternfly@^4.16.7":
version "4.16.7"
resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-4.16.7.tgz#6343eb530528e5b6c2670d24b115031e135f15ad"
integrity sha512-B5jP/xG1MxNNDO3p52rx7a2DJspq8aUJFixYdPk1peK7SaC5X9ju2oCyE9xN1Nfe1AjlPxAOpNWPd9TWw88yLQ==
"@patternfly/react-core@^4.23.1":
version "4.23.1"
resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-4.23.1.tgz#b497a6f4104b5094029b5f25cb944aaca99cf4b7"
integrity sha512-gj3c4ed0r5FY8Z0A0Ql3yeUpjhNEYoVbFMP6a+mVguzlMQPX6wmLj7/JKMq7z7c1grXYgWdYph4xjJIJCgz1UQ==
"@patternfly/react-core@^4.40.4":
version "4.40.4"
resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-4.40.4.tgz#e4409f89327e2fcdcd07a08833c0149e6f2f6966"
integrity sha512-NQuUgIVEty7BBNJMJAVRXejOGRGpRQwgQ8Rw/J/JlgkhtOrCSFX5cEbpAXMXLYWkJrz0++XfRK/FQMoQbvS2hQ==
dependencies:
"@patternfly/react-icons" "^4.4.2"
"@patternfly/react-styles" "^4.4.2"
"@patternfly/react-tokens" "^4.5.2"
"@popperjs/core" "2.4.2"
focus-trap "4.0.2"
react-dropzone "9.0.0"
react-popper "2.2.3"
tippy.js "5.1.2"
tslib "^1.11.1"
"@patternfly/react-core@^4.32.1":
version "4.32.1"
resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-4.32.1.tgz#9fd2dc024eda51b8d8e58d014cbb9d69c3a78604"
integrity sha512-4FrKJvMfjHjWtmvGu1QVxo/nCdUgePlkdNzMs91r0wdL16CpfoQVtZcfZe4343fRAQ2ObeYfZ2GuiwvS1sw8Og==
dependencies:
"@patternfly/react-icons" "^4.5.0"
"@patternfly/react-styles" "^4.5.0"
"@patternfly/react-tokens" "^4.6.0"
"@patternfly/react-icons" "^4.7.2"
"@patternfly/react-styles" "^4.7.2"
"@patternfly/react-tokens" "^4.9.4"
focus-trap "4.0.2"
react-dropzone "9.0.0"
tippy.js "5.1.2"
tslib "^1.11.1"
"@patternfly/react-icons@^4.4.2":
version "4.4.2"
resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-4.4.2.tgz#292098ba4b4eca92eab9354d79fdb746756b1ea6"
integrity sha512-zj740Zm6243iAZI8O/ar90uUL4sRUikM/wEyAahAtelrKP3bqmEOorWClE7cAa3w6TPHYsS7f+Szn5HyKXD/8w==
"@patternfly/react-icons@^4.7.2":
version "4.7.2"
resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-4.7.2.tgz#f4ad252cb5682bd95da474ce9ce6ddf7fb3a1ac1"
integrity sha512-r1yCVHxUtRSblo8VwfaUM0d49z4eToZXAI0VzOnfKPRgSmGZrn6l8soQgDDtyQsSDr534Qvm55y/qLrlR9JCnw==
"@patternfly/react-icons@^4.5.0":
version "4.5.0"
resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-4.5.0.tgz#9c0c74348aa2b4c83765b743022f92d45fd762dc"
integrity sha512-wXAENYa6nST4D8DBkiCrZXf4aRTmVQNA4cyImMJ3aQWAzwJ7Xc1zIBBuYSX5EP0JOuf9DzWVCrzvgfQz1Fcx8g==
"@patternfly/react-styles@^4.7.2":
version "4.7.2"
resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-4.7.2.tgz#6671a243401ef55adddcb0e0922f5f5f4eea840e"
integrity sha512-r3zyrt1mXcqdXaEq+otl1cGsN0Ou1k8uIJSY+4EGe2A5jLGbX3vBTwUrpPKLB6tUdNL+mZriFf+3oKhWbVZDkw==
"@patternfly/react-styles@^4.4.2":
version "4.4.2"
resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-4.4.2.tgz#4149d1a9752e01e68680b07efcfab667e969e698"
integrity sha512-bYLEJzFTSZLZ9zxSl4b8SZ07LoR0DPCghf23fqGljcTBA97zxA8rLV/cFvlmPTw7o/clhTqAZqwjvs+m8RMmtA==
"@patternfly/react-styles@^4.5.0":
version "4.5.0"
resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-4.5.0.tgz#d40c9d1e4b4898cb26ec8dd0aa56e89fce9ba2a9"
integrity sha512-6w8mvxx/cC+yUzBKlWY8YRnavlWCTLWly1si0skleYPF1t69f3P+jeXNy39kH6+o2vXJR5MeecLrnuMV0XtKvg==
"@patternfly/react-table@^4.12.1":
version "4.12.1"
resolved "https://registry.yarnpkg.com/@patternfly/react-table/-/react-table-4.12.1.tgz#6693448a5ebb68cc38db69511219f0d50c23001b"
integrity sha512-QYVtnqYkYu8tdWDDOqu3Sd8daXSCWT9EvZIUQ7GeZO09anGQ/N4HKKH/iAKsLFloGTZUFjgkwSd9IBSH51VjcQ==
"@patternfly/react-table@^4.15.5":
version "4.15.5"
resolved "https://registry.yarnpkg.com/@patternfly/react-table/-/react-table-4.15.5.tgz#7fc3fcd37a6fd4dca00cc32d24c76199ee41a7f1"
integrity sha512-GlyKrEDMY+yLvczj5rWpNKcUp90Ib7alKV9JK8rVLOpTsukQ0QplXxYFsnIrombcaw2V54XVdflZGjsB0GoHEw==
dependencies:
"@patternfly/patternfly" "4.23.3"
"@patternfly/react-core" "^4.32.1"
"@patternfly/react-icons" "^4.5.0"
"@patternfly/react-styles" "^4.5.0"
"@patternfly/react-tokens" "^4.6.0"
"@types/classnames" "^2.2.9"
classnames "^2.2.5"
lodash "^4.17.15"
"@patternfly/patternfly" "4.31.6"
"@patternfly/react-core" "^4.40.4"
"@patternfly/react-icons" "^4.7.2"
"@patternfly/react-styles" "^4.7.2"
"@patternfly/react-tokens" "^4.9.4"
lodash "^4.17.19"
tslib "^1.11.1"
"@patternfly/react-tokens@^4.5.2":
version "4.5.2"
resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-4.5.2.tgz#be399929ab3371e3a870d4e0f5f218d56e129c41"
integrity sha512-hw8o1KLR+VNBmoCxy1LekLHIDilHTNGdXAevj548V0sp0SkdQYLu7mzJNd9HN8OVLBabcrk6XXkx0g8c6YnyhQ==
"@patternfly/react-tokens@^4.6.0":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-4.6.0.tgz#1a9648537e3a7f0202663af49cba4ceda5886dfd"
integrity sha512-zpA4AlYqJNJm5aqsarBVjod1gjP9muJ5oWI2ZwGUFiw4YNRn8eY7QKQ1VvNZxqwI+WSXl98jTqJiKuJGF3DEvw==
"@popperjs/core@2.4.2":
version "2.4.2"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.2.tgz#7c6dc4ecef16149fd7a736710baa1b811017fdca"
integrity sha512-JlGTGRYHC2QK+DDbePyXdBdooxFq2+noLfWpRqJtkxcb/oYWzOF0kcbfvvbWrwevCC1l6hLUg1wHYT+ona5BWQ==
"@patternfly/react-tokens@^4.9.4":
version "4.9.4"
resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-4.9.4.tgz#71ea3c33045fb29bcc8d98f2c0f07bfcdc89a12c"
integrity sha512-AJpcAvzWXvfThT2mx24rV7OJSHvZnIsOP1bVrXiubpFAJhi/Suq+LGe/lTPUnuSXaflwyDBRZDXWWmJb4yaWqg==
"@reach/router@^1.2.1":
version "1.3.4"
@ -3539,11 +3497,6 @@
"@types/node" "*"
"@types/responselike" "*"
"@types/classnames@^2.2.9":
version "2.2.10"
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999"
integrity sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ==
"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@ -14672,14 +14625,6 @@ react-popper-tooltip@^2.8.3:
"@babel/runtime" "^7.9.2"
react-popper "^1.3.7"
react-popper@2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.3.tgz#33d425fa6975d4bd54d9acd64897a89d904b9d97"
integrity sha512-mOEiMNT1249js0jJvkrOjyHsGvqcJd3aGW/agkiMoZk3bZ1fXN1wQszIQSjHIai48fE67+zwF8Cs+C4fWqlfjw==
dependencies:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-popper@^1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324"
@ -16730,16 +16675,11 @@ ts-pnp@^1.1.2, ts-pnp@^1.1.6:
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==
tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.3:
tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.13.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
tslib@^1.9.0:
version "1.11.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
tsutils@^3.17.1:
version "3.17.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"