-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from alnavarrop99/fix/styles&rols
Create print view
Showing
41 changed files
with
671 additions
and
1,093 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,324 @@ | ||
import { createFileRoute } from '@tanstack/react-router' | ||
import { Button } from '@/components/ui/button' | ||
import { DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' | ||
import { Input } from '@/components/ui/input' | ||
import { Label } from '@/components/ui/label' | ||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' | ||
import { Separator } from '@/components/ui/separator' | ||
import { ToastAction } from '@/components/ui/toast' | ||
import { toast } from '@/components/ui/use-toast' | ||
import { Navigate, createFileRoute } from '@tanstack/react-router' | ||
import clsx from 'clsx' | ||
import { ComponentRef, useContext, useMemo, useRef, useState } from 'react' | ||
import { Eye, EyeOff } from 'lucide-react' | ||
import { getUserById, pathUserById } from '@/api/users' | ||
import { useStatus } from '@/lib/context/layout' | ||
import { useNotifications } from '@/lib/context/notification' | ||
import { useMutation } from '@tanstack/react-query' | ||
import { type TROLES, getRolById, getRolByName, listRols } from '@/lib/type/rol' | ||
import { type TUsersState, _usersContext } from '@/pages/_layout/user' | ||
|
||
export const Route = createFileRoute('/_layout/user/$userId/update')({ | ||
component: () => <div>Hello /_layout/user/$userId/update!</div> | ||
}) | ||
component: UpdateUserById, | ||
loader: getUserById | ||
}) | ||
|
||
/* eslint-disable-next-line */ | ||
interface TPassowordVisibilityState { | ||
password?: boolean | ||
confirmation?: boolean | ||
} | ||
|
||
interface TPassowordValueState{ | ||
password?: string | ||
confirmation?: string | ||
} | ||
|
||
/* eslint-disable-next-line */ | ||
interface TUpdateUserById { | ||
user?: TUsersState | ||
} | ||
|
||
type TFormName = "firstName" | "lastName" | "rol" | "password" | "newPassword" | ||
|
||
/* eslint-disable-next-line */ | ||
export function UpdateUserById({ user: _user = {} as TUsersState }: TUpdateUserById) { | ||
const [ visibility, setVisibility ] = useState<TPassowordVisibilityState>({}) | ||
const [ password, setPassword ] = useState<TPassowordValueState | undefined>(undefined) | ||
const form = useRef<HTMLFormElement>(null) | ||
const _userDB = (Route.useLoaderData() ?? _user) | ||
const userDB = { ..._userDB, password: "" } | ||
const [ user, setUser ] = useState(userDB) | ||
const [ users, setUsers ] = useContext(_usersContext) ?? [ [], () => {} ] | ||
const { pushNotification } = useNotifications() | ||
const { open, setOpen } = useStatus() | ||
const {mutate: updateUser} = useMutation( { | ||
mutationKey: ["update-user"], | ||
mutationFn: pathUserById, | ||
}) | ||
const active = useMemo( () => Object.values(userDB)?.every( ( value, i ) => ( value === Object.values(user)?.[i] ) ), [ JSON.stringify(user) ] ) | ||
|
||
const onClick: ( prop: keyof TPassowordVisibilityState ) => React.MouseEventHandler< ComponentRef< typeof Button > > = ( prop ) => () => { | ||
setVisibility( { ...visibility, [ prop ]: !visibility?.[prop] } ) | ||
} | ||
|
||
const onChangePassword: React.ChangeEventHandler< ComponentRef< typeof Input > > = (ev) => { | ||
const { name, value } = ev?.target | ||
setPassword( { ...password, [ name ]: value } ) | ||
} | ||
|
||
const onChange: React.ChangeEventHandler< HTMLFormElement > = (ev) => { | ||
const { name, value } = ev.target | ||
|
||
if( name === "firstName" as TFormName || name === "lastName" as TFormName ){ | ||
return; | ||
} | ||
|
||
setUser( { ...user, [ name ]: value } ) | ||
} | ||
|
||
const onChangeName: ( filed: "firstName" | "lastName" ) => React.ChangeEventHandler< React.ComponentRef< typeof Input > > = (field) => (ev) => { | ||
const { value } = ev.target | ||
const { nombre } = user | ||
if( field === "firstName" ){ | ||
setUser( { ...user, nombre: value + nombre.split(" ")?.[1] } ) | ||
} | ||
else if ( field === "lastName" ){ | ||
setUser( { ...user, nombre: nombre.split(" ")?.[0] + value } ) | ||
} | ||
ev.stopPropagation() | ||
} | ||
|
||
const onSubmit: React.FormEventHandler<HTMLFormElement> = (ev) => { | ||
if (!form.current) return; | ||
|
||
const items = Object.fromEntries( Array.from( new FormData(form.current)?.entries() )?.map( ([ key, value ], i, list) => { | ||
if( value === "" ) return [ key, undefined ] | ||
return list?.[i] | ||
})) as Record<TFormName, string> | ||
|
||
const description = text.notification.decription({ | ||
username: userDB?.nombre | ||
}) | ||
|
||
const action = | ||
({ ...items }: Record<TFormName, string>) => | ||
() => { | ||
updateUser({ | ||
userId: userDB?.id, | ||
params: { | ||
rol_id: +items.rol, | ||
password: items?.newPassword, | ||
nombre: items?.firstName + " " + items?.lastName | ||
} }) | ||
pushNotification({ | ||
date: new Date(), | ||
action: "PATH", | ||
description, | ||
}) | ||
} | ||
|
||
const timer = setTimeout(action(items), 6 * 1000) | ||
setOpen({ open: !open }) | ||
setUsers( users?.map( ({ id: userId }, i, list) => { | ||
if( user.id !== userId ) return list[i]; | ||
return ({ | ||
...list?.[i], | ||
nombre: items?.firstName + " " + items?.lastName, | ||
rol: getRolById({ rolId: +items?.rol })?.nombre | ||
}) | ||
} ) ) | ||
|
||
const onClick = () => { | ||
setUsers(users) | ||
clearTimeout(timer) | ||
} | ||
|
||
toast({ | ||
title: text.notification.titile, | ||
description, | ||
variant: 'default', | ||
action: ( | ||
<ToastAction altText="action from new user"> | ||
<Button variant="default" onClick={onClick}> | ||
{text.notification.undo} | ||
</Button> | ||
</ToastAction> | ||
), | ||
}) | ||
|
||
form.current.reset() | ||
ev.preventDefault() | ||
} | ||
|
||
return ( | ||
<> | ||
{!open && <Navigate to={"../../"} />} | ||
<DialogContent className="max-w-lg"> | ||
<DialogHeader> | ||
<DialogTitle className="text-2xl">{text.title}</DialogTitle> | ||
<Separator /> | ||
<DialogDescription>{text.descriiption}</DialogDescription> | ||
</DialogHeader> | ||
<form | ||
autoComplete="off" | ||
ref={form} | ||
onSubmit={onSubmit} | ||
onChange={onChange} | ||
id="update-user" | ||
className={clsx( | ||
'grid-rows-subgrid grid grid-cols-2 gap-3 gap-y-4 [&>:is(label,div)]:space-y-2 [&>*]:col-span-full [&_label>span]:font-bold', | ||
)} | ||
> | ||
<Label className='!col-span-1' > | ||
<span>{text.form.firstName.label}</span> | ||
<Input | ||
required | ||
name={'firstName' as TFormName} | ||
type="text" | ||
placeholder={text.form.firstName.placeholder} | ||
defaultValue={userDB?.nombre.split(" ")?.at(0)} | ||
onChange={onChangeName("firstName")} | ||
/> | ||
</Label> | ||
<Label className='!col-span-1' > | ||
<span>{text.form.lastName.label} </span> | ||
<Input | ||
required | ||
name={'lastName' as TFormName} | ||
type="text" | ||
placeholder={text.form.lastName.placeholder} | ||
defaultValue={userDB?.nombre.split(" ")?.at(1)} | ||
onChange={onChangeName("lastName")} | ||
/> | ||
</Label> | ||
<Label> | ||
<span>{text.form.rol.label} </span> | ||
<Select required name={'rol' as TFormName} defaultValue={ ""+getRolByName({ rolName: userDB?.rol as TROLES })?.id }> | ||
<SelectTrigger className="w-full"> | ||
<SelectValue placeholder={text.form.rol.placeholder} /> | ||
</SelectTrigger> | ||
<SelectContent className='[&_*]:cursor-pointer'> | ||
{ listRols()?.map( ({ id, nombre }) => | ||
<SelectItem key={id} value={""+id}>{nombre}</SelectItem> | ||
) } | ||
</SelectContent> | ||
</Select> | ||
</Label> | ||
<div> | ||
<Label htmlFor='user-password'> | ||
<span>{text.form.password.current.label} </span> | ||
</Label> | ||
<div className="flex flex-row-reverse items-center gap-x-2"> | ||
<Button | ||
type="button" | ||
className="w-fit p-1.5" | ||
onClick={onClick("password")} | ||
variant={!visibility.password ? 'outline' : 'default'} | ||
> | ||
{!visibility.password ? <Eye /> : <EyeOff />} | ||
</Button> | ||
<Input | ||
id='user-password' | ||
name={'password' as TFormName} | ||
type={!visibility.password ? "password" : "text"} | ||
placeholder={text.form.password.current.placeholder} | ||
value={password?.password} | ||
onChange={onChangePassword} | ||
/> | ||
</div> | ||
</div> | ||
<div> | ||
<Label htmlFor='user-new'> | ||
<span>{text.form.password.new.label} </span> | ||
</Label> | ||
<div className="flex flex-row-reverse items-center gap-x-2"> | ||
<Button | ||
type="button" | ||
className="w-fit p-1.5" | ||
onClick={onClick( "confirmation" )} | ||
variant={!visibility.confirmation ? 'outline' : 'default'} | ||
> | ||
{!visibility.confirmation ? <Eye /> : <EyeOff />} | ||
</Button> | ||
<Input | ||
id='user-new' | ||
name={'newPassword' as TFormName} | ||
required={!!password?.password} | ||
type={!visibility.confirmation ? "password" : "text"} | ||
placeholder={text.form.password.new.placeholder} | ||
value={password?.confirmation} | ||
onChange={onChangePassword} | ||
/> | ||
</div> | ||
</div> | ||
</form> | ||
<DialogFooter className="justify-end"> | ||
<Button | ||
disabled={ active } | ||
variant="default" | ||
form="update-user" | ||
type="submit"> | ||
{text.button.update} | ||
</Button> | ||
<DialogClose asChild> | ||
<Button | ||
type="button" | ||
variant="outline" | ||
className="font-bold hover:ring hover:ring-primary" | ||
> | ||
{text.button.close} | ||
</Button> | ||
</DialogClose> | ||
</DialogFooter> | ||
</DialogContent> | ||
</> | ||
) | ||
} | ||
|
||
UpdateUserById.dispalyname = 'UpdateUserById' | ||
|
||
const text = { | ||
title: 'Actualizar Usuario:', | ||
descriiption: | ||
'Modifique los campos para actualizar los datos del usuario en la plataforma.', | ||
button: { | ||
close: 'Cerrar', | ||
update: 'Actualizar', | ||
}, | ||
notification: { | ||
titile: 'Actualizacion de usuario', | ||
decription: ({ username }: { username: string }) => | ||
'Se ha actualizacion el usuario ' + username + ' con exito.', | ||
error: 'Error: la actualizacion del usuario ha fallado', | ||
undo: 'Deshacer', | ||
}, | ||
form: { | ||
firstName: { | ||
label: 'Nombre:', | ||
placeholder: 'Escriba el nombre del usuario', | ||
}, | ||
lastName: { | ||
label: 'Apellidos:', | ||
placeholder: 'Escriba el apellido del usuario', | ||
}, | ||
password: { | ||
current: { | ||
label: 'Contraseña actual:', | ||
placeholder: 'Escriba la cantraseña actual del usuario', | ||
}, | ||
new: { | ||
label: 'Nueva contraseña:', | ||
placeholder: 'Escriba la nuva cantraseña del usuario', | ||
} | ||
}, | ||
rol: { | ||
label: 'Tipo de rol:', | ||
placeholder: 'Seleccione el rol del usuario', | ||
items: { | ||
user: "Usuario", | ||
admin: "Administrador", | ||
client: "Cliente", | ||
} | ||
}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// vite.config.ts | ||
import { defineConfig } from "file:///home/mob/mob99/projects/prestamos/node_modules/.pnpm/vite@5.0.11_@types+node@20.8.10_terser@5.24.0/node_modules/vite/dist/node/index.js"; | ||
import react from "file:///home/mob/mob99/projects/prestamos/node_modules/.pnpm/@vitejs+plugin-react-swc@3.5.0_vite@5.0.11/node_modules/@vitejs/plugin-react-swc/index.mjs"; | ||
import legacy from "file:///home/mob/mob99/projects/prestamos/node_modules/.pnpm/@vitejs+plugin-legacy@4.1.1_terser@5.24.0_vite@5.0.11/node_modules/@vitejs/plugin-legacy/dist/index.mjs"; | ||
import progress from "file:///home/mob/mob99/projects/prestamos/node_modules/.pnpm/vite-plugin-progress@0.0.7_vite@5.0.11/node_modules/vite-plugin-progress/dist/index.mjs"; | ||
import svgr from "file:///home/mob/mob99/projects/prestamos/node_modules/.pnpm/vite-plugin-svgr@4.2.0_typescript@5.2.2_vite@5.0.11/node_modules/vite-plugin-svgr/dist/index.js"; | ||
import { TanStackRouterVite } from "file:///home/mob/mob99/projects/prestamos/node_modules/.pnpm/@tanstack+router-vite-plugin@1.16.3/node_modules/@tanstack/router-vite-plugin/dist/esm/index.js"; | ||
|
||
// vite.alias.ts | ||
import { resolve } from "path"; | ||
var __vite_injected_original_dirname = "/home/mob/mob99/projects/prestamos"; | ||
var root = resolve(__vite_injected_original_dirname, "src"); | ||
var alias = { | ||
"@": root | ||
}; | ||
var vite_alias_default = alias; | ||
|
||
// vite.config.ts | ||
var vite_config_default = defineConfig({ | ||
resolve: { | ||
alias: vite_alias_default | ||
}, | ||
plugins: [react(), legacy({}), progress(), svgr(), TanStackRouterVite()] | ||
}); | ||
export { | ||
vite_config_default as default | ||
}; | ||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiLCAidml0ZS5hbGlhcy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9ob21lL21vYi9tb2I5OS9wcm9qZWN0cy9wcmVzdGFtb3NcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL21vYi9tb2I5OS9wcm9qZWN0cy9wcmVzdGFtb3Mvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvbW9iL21vYjk5L3Byb2plY3RzL3ByZXN0YW1vcy92aXRlLmNvbmZpZy50c1wiO2ltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGUnXG5pbXBvcnQgcmVhY3QgZnJvbSAnQHZpdGVqcy9wbHVnaW4tcmVhY3Qtc3djJ1xuaW1wb3J0IGxlZ2FjeSBmcm9tICdAdml0ZWpzL3BsdWdpbi1sZWdhY3knXG5pbXBvcnQgcHJvZ3Jlc3MgZnJvbSAndml0ZS1wbHVnaW4tcHJvZ3Jlc3MnXG5pbXBvcnQgc3ZnciBmcm9tICd2aXRlLXBsdWdpbi1zdmdyJ1xuaW1wb3J0IHsgVGFuU3RhY2tSb3V0ZXJWaXRlIH0gZnJvbSAnQHRhbnN0YWNrL3JvdXRlci12aXRlLXBsdWdpbidcbmltcG9ydCBhbGlhcyBmcm9tICcuL3ZpdGUuYWxpYXMnXG5cbi8vIGh0dHBzOi8vdml0ZWpzLmRldi9jb25maWcvXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xuICByZXNvbHZlOiB7XG4gICAgYWxpYXMsXG4gIH0sXG4gIHBsdWdpbnM6IFtyZWFjdCgpLCBsZWdhY3koe30pLCBwcm9ncmVzcygpLCBzdmdyKCksIFRhblN0YWNrUm91dGVyVml0ZSgpXSxcbn0pXG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9ob21lL21vYi9tb2I5OS9wcm9qZWN0cy9wcmVzdGFtb3NcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL21vYi9tb2I5OS9wcm9qZWN0cy9wcmVzdGFtb3Mvdml0ZS5hbGlhcy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vaG9tZS9tb2IvbW9iOTkvcHJvamVjdHMvcHJlc3RhbW9zL3ZpdGUuYWxpYXMudHNcIjtpbXBvcnQgeyByZXNvbHZlIH0gZnJvbSAncGF0aCdcblxuY29uc3Qgcm9vdCA9IHJlc29sdmUoX19kaXJuYW1lLCAnc3JjJylcblxuZXhwb3J0IGNvbnN0IGFsaWFzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAnQCc6IHJvb3QsXG59XG5cbmV4cG9ydCBkZWZhdWx0IGFsaWFzXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQXdSLFNBQVMsb0JBQW9CO0FBQ3JULE9BQU8sV0FBVztBQUNsQixPQUFPLFlBQVk7QUFDbkIsT0FBTyxjQUFjO0FBQ3JCLE9BQU8sVUFBVTtBQUNqQixTQUFTLDBCQUEwQjs7O0FDTG1QLFNBQVMsZUFBZTtBQUE5UyxJQUFNLG1DQUFtQztBQUV6QyxJQUFNLE9BQU8sUUFBUSxrQ0FBVyxLQUFLO0FBRTlCLElBQU0sUUFBZ0M7QUFBQSxFQUMzQyxLQUFLO0FBQ1A7QUFFQSxJQUFPLHFCQUFROzs7QURDZixJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUDtBQUFBLEVBQ0Y7QUFBQSxFQUNBLFNBQVMsQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLENBQUMsR0FBRyxTQUFTLEdBQUcsS0FBSyxHQUFHLG1CQUFtQixDQUFDO0FBQ3pFLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg== |