Merge pull request #784 from Dokploy/754-dokploy-ui-duplicate-deployments

fix: add missing server flag boolean
This commit is contained in:
Mauricio Siu
2024-11-28 23:35:53 -06:00
committed by GitHub
21 changed files with 318 additions and 352 deletions

View File

@@ -202,7 +202,6 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",
@@ -281,7 +280,6 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
" w-full justify-between !bg-input", " w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -193,7 +193,6 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",
@@ -272,7 +271,6 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
" w-full justify-between !bg-input", " w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -209,7 +209,6 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",
@@ -297,7 +296,6 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
" w-full justify-between !bg-input", " w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -204,7 +204,6 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",
@@ -283,7 +282,6 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
" w-full justify-between !bg-input", " w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -195,7 +195,6 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",
@@ -274,7 +273,6 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
" w-full justify-between !bg-input", " w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -211,7 +211,6 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",
@@ -299,7 +298,6 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
" w-full justify-between !bg-input", " w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -160,7 +160,6 @@ export const AddBackup = ({ databaseId, databaseType, refetch }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -144,7 +144,6 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
<FormControl> <FormControl>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"w-full justify-between !bg-input", "w-full justify-between !bg-input",
!field.value && "text-muted-foreground", !field.value && "text-muted-foreground",

View File

@@ -86,14 +86,12 @@ export const ShowVolumes = ({ mysqlId }: Props) => {
)} )}
{mount.type === "file" && ( {mount.type === "file" && (
<>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="font-medium">Content</span> <span className="font-medium">Content</span>
<span className="text-sm text-muted-foreground"> <span className="text-sm text-muted-foreground">
{mount.content} {mount.content}
</span> </span>
</div> </div>
</>
)} )}
{mount.type === "bind" && ( {mount.type === "bind" && (
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">

View File

@@ -127,7 +127,6 @@ export const AddTemplate = ({ projectId }: Props) => {
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button <Button
variant="outline" variant="outline"
role="combobox"
className={cn( className={cn(
"md:max-w-[15rem] w-full justify-between !bg-input", "md:max-w-[15rem] w-full justify-between !bg-input",
)} )}

View File

@@ -89,19 +89,15 @@ export const ShowBilling = () => {
<div className="pb-5"> <div className="pb-5">
<Progress value={safePercentage} className="max-w-lg" /> <Progress value={safePercentage} className="max-w-lg" />
</div> </div>
{admin && ( {admin && admin.serversQuantity! <= servers?.length! && (
<>
{admin.serversQuantity! <= servers?.length! && (
<div className="flex flex-row gap-4 p-2 bg-yellow-50 dark:bg-yellow-950 rounded-lg items-center"> <div className="flex flex-row gap-4 p-2 bg-yellow-50 dark:bg-yellow-950 rounded-lg items-center">
<AlertTriangle className="text-yellow-600 dark:text-yellow-400" /> <AlertTriangle className="text-yellow-600 dark:text-yellow-400" />
<span className="text-sm text-yellow-600 dark:text-yellow-400"> <span className="text-sm text-yellow-600 dark:text-yellow-400">
You have reached the maximum number of servers you can You have reached the maximum number of servers you can create,
create, please upgrade your plan to add more servers. please upgrade your plan to add more servers.
</span> </span>
</div> </div>
)} )}
</>
)}
</div> </div>
)} )}
<div className="flex flex-col gap-1.5 mt-4"> <div className="flex flex-col gap-1.5 mt-4">
@@ -188,7 +184,6 @@ export const ShowBilling = () => {
</p> </p>
<ul <ul
role="list"
className={clsx( className={clsx(
" mt-4 flex flex-col gap-y-2 text-sm", " mt-4 flex flex-col gap-y-2 text-sm",
featured ? "text-white" : "text-slate-200", featured ? "text-white" : "text-slate-200",

View File

@@ -28,11 +28,7 @@ export const ShowRegistry = () => {
</div> </div>
<div className="flex flex-row gap-2"> <div className="flex flex-row gap-2">
{data && data?.length > 0 && ( {data && data?.length > 0 && <AddRegistry />}
<>
<AddRegistry />
</>
)}
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="space-y-2 pt-4 h-full"> <CardContent className="space-y-2 pt-4 h-full">

View File

@@ -397,7 +397,6 @@ export const AddNotification = () => {
)} )}
{type === "discord" && ( {type === "discord" && (
<>
<FormField <FormField
control={form.control} control={form.control}
name="webhookUrl" name="webhookUrl"
@@ -415,7 +414,6 @@ export const AddNotification = () => {
</FormItem> </FormItem>
)} )}
/> />
</>
)} )}
{type === "email" && ( {type === "email" && (

View File

@@ -356,7 +356,6 @@ export const UpdateNotification = ({ notificationId }: Props) => {
)} )}
{type === "discord" && ( {type === "discord" && (
<>
<FormField <FormField
control={form.control} control={form.control}
name="webhookUrl" name="webhookUrl"
@@ -374,7 +373,6 @@ export const UpdateNotification = ({ notificationId }: Props) => {
</FormItem> </FormItem>
)} )}
/> />
</>
)} )}
{type === "email" && ( {type === "email" && (
<> <>

View File

@@ -228,9 +228,7 @@ export const ShowServers = () => {
</DropdownMenuItem> </DropdownMenuItem>
</DialogAction> </DialogAction>
{isActive && ( {isActive && server.sshKeyId && (
<>
{server.sshKeyId && (
<> <>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuLabel>Extra</DropdownMenuLabel> <DropdownMenuLabel>Extra</DropdownMenuLabel>
@@ -243,8 +241,6 @@ export const ShowServers = () => {
/> />
</> </>
)} )}
</>
)}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</TableCell> </TableCell>

View File

@@ -61,7 +61,7 @@ const InputOTPSeparator = React.forwardRef<
React.ElementRef<"div">, React.ElementRef<"div">,
React.ComponentPropsWithoutRef<"div"> React.ComponentPropsWithoutRef<"div">
>(({ ...props }, ref) => ( >(({ ...props }, ref) => (
<div ref={ref} role="separator" {...props}> <div ref={ref} {...props}>
<Dot /> <Dot />
</div> </div>
)); ));

View File

@@ -11,7 +11,7 @@ import { extractCommitMessage, extractHash } from "./[refreshToken]";
export default async function handler( export default async function handler(
req: NextApiRequest, req: NextApiRequest,
res: NextApiResponse, res: NextApiResponse
) { ) {
const signature = req.headers["x-hub-signature-256"]; const signature = req.headers["x-hub-signature-256"];
const githubBody = req.body; const githubBody = req.body;
@@ -40,7 +40,7 @@ export default async function handler(
const verified = await webhooks.verify( const verified = await webhooks.verify(
JSON.stringify(githubBody), JSON.stringify(githubBody),
signature as string, signature as string
); );
if (!verified) { if (!verified) {
@@ -69,7 +69,7 @@ export default async function handler(
eq(applications.sourceType, "github"), eq(applications.sourceType, "github"),
eq(applications.autoDeploy, true), eq(applications.autoDeploy, true),
eq(applications.branch, branchName), eq(applications.branch, branchName),
eq(applications.repository, repository), eq(applications.repository, repository)
), ),
}); });
@@ -94,7 +94,7 @@ export default async function handler(
{ {
removeOnComplete: true, removeOnComplete: true,
removeOnFail: true, removeOnFail: true,
}, }
); );
} }
@@ -103,7 +103,7 @@ export default async function handler(
eq(compose.sourceType, "github"), eq(compose.sourceType, "github"),
eq(compose.autoDeploy, true), eq(compose.autoDeploy, true),
eq(compose.branch, branchName), eq(compose.branch, branchName),
eq(compose.repository, repository), eq(compose.repository, repository)
), ),
}); });
@@ -114,6 +114,7 @@ export default async function handler(
type: "deploy", type: "deploy",
applicationType: "compose", applicationType: "compose",
descriptionLog: `Hash: ${deploymentHash}`, descriptionLog: `Hash: ${deploymentHash}`,
server: !!composeApp.serverId,
}; };
if (IS_CLOUD && composeApp.serverId) { if (IS_CLOUD && composeApp.serverId) {
@@ -128,7 +129,7 @@ export default async function handler(
{ {
removeOnComplete: true, removeOnComplete: true,
removeOnFail: true, removeOnFail: true,
}, }
); );
} }

View File

@@ -41,5 +41,5 @@ commit-msg:
pre-commit: pre-commit:
commands: commands:
lint-staged: check:
run: "pnpm check && npx lint-staged" run: "pnpm check"

View File

@@ -13,7 +13,6 @@
"server:build": "pnpm --filter=server run build", "server:build": "pnpm --filter=server run build",
"docker:build:canary": "./apps/dokploy/docker/build.sh canary", "docker:build:canary": "./apps/dokploy/docker/build.sh canary",
"typecheck": "pnpm -r run typecheck", "typecheck": "pnpm -r run typecheck",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"build": "pnpm -r run build", "build": "pnpm -r run build",
"format-and-lint": "biome check .", "format-and-lint": "biome check .",
"check": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true", "check": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true",
@@ -24,7 +23,7 @@
"esbuild": "0.20.2", "esbuild": "0.20.2",
"tsx": "4.16.2", "tsx": "4.16.2",
"lint-staged": "^15.2.7", "lint-staged": "^15.2.7",
"@biomejs/biome": "1.8.3", "@biomejs/biome": "1.9.4",
"lefthook": "1.8.4", "lefthook": "1.8.4",
"@commitlint/cli": "^19.3.0", "@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2", "@commitlint/config-conventional": "^19.2.2",

74
pnpm-lock.yaml generated
View File

@@ -13,8 +13,8 @@ importers:
.: .:
devDependencies: devDependencies:
'@biomejs/biome': '@biomejs/biome':
specifier: 1.8.3 specifier: 1.9.4
version: 1.8.3 version: 1.9.4
'@commitlint/cli': '@commitlint/cli':
specifier: ^19.3.0 specifier: ^19.3.0
version: 19.3.0(@types/node@18.19.42)(typescript@5.5.3) version: 19.3.0(@types/node@18.19.42)(typescript@5.5.3)
@@ -682,55 +682,55 @@ packages:
'@balena/dockerignore@1.0.2': '@balena/dockerignore@1.0.2':
resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==}
'@biomejs/biome@1.8.3': '@biomejs/biome@1.9.4':
resolution: {integrity: sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==} resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
hasBin: true hasBin: true
'@biomejs/cli-darwin-arm64@1.8.3': '@biomejs/cli-darwin-arm64@1.9.4':
resolution: {integrity: sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==} resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@biomejs/cli-darwin-x64@1.8.3': '@biomejs/cli-darwin-x64@1.9.4':
resolution: {integrity: sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==} resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@biomejs/cli-linux-arm64-musl@1.8.3': '@biomejs/cli-linux-arm64-musl@1.9.4':
resolution: {integrity: sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==} resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@biomejs/cli-linux-arm64@1.8.3': '@biomejs/cli-linux-arm64@1.9.4':
resolution: {integrity: sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==} resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@biomejs/cli-linux-x64-musl@1.8.3': '@biomejs/cli-linux-x64-musl@1.9.4':
resolution: {integrity: sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==} resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@biomejs/cli-linux-x64@1.8.3': '@biomejs/cli-linux-x64@1.9.4':
resolution: {integrity: sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==} resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@biomejs/cli-win32-arm64@1.8.3': '@biomejs/cli-win32-arm64@1.9.4':
resolution: {integrity: sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==} resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@biomejs/cli-win32-x64@1.8.3': '@biomejs/cli-win32-x64@1.9.4':
resolution: {integrity: sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==} resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -6869,39 +6869,39 @@ snapshots:
'@balena/dockerignore@1.0.2': {} '@balena/dockerignore@1.0.2': {}
'@biomejs/biome@1.8.3': '@biomejs/biome@1.9.4':
optionalDependencies: optionalDependencies:
'@biomejs/cli-darwin-arm64': 1.8.3 '@biomejs/cli-darwin-arm64': 1.9.4
'@biomejs/cli-darwin-x64': 1.8.3 '@biomejs/cli-darwin-x64': 1.9.4
'@biomejs/cli-linux-arm64': 1.8.3 '@biomejs/cli-linux-arm64': 1.9.4
'@biomejs/cli-linux-arm64-musl': 1.8.3 '@biomejs/cli-linux-arm64-musl': 1.9.4
'@biomejs/cli-linux-x64': 1.8.3 '@biomejs/cli-linux-x64': 1.9.4
'@biomejs/cli-linux-x64-musl': 1.8.3 '@biomejs/cli-linux-x64-musl': 1.9.4
'@biomejs/cli-win32-arm64': 1.8.3 '@biomejs/cli-win32-arm64': 1.9.4
'@biomejs/cli-win32-x64': 1.8.3 '@biomejs/cli-win32-x64': 1.9.4
'@biomejs/cli-darwin-arm64@1.8.3': '@biomejs/cli-darwin-arm64@1.9.4':
optional: true optional: true
'@biomejs/cli-darwin-x64@1.8.3': '@biomejs/cli-darwin-x64@1.9.4':
optional: true optional: true
'@biomejs/cli-linux-arm64-musl@1.8.3': '@biomejs/cli-linux-arm64-musl@1.9.4':
optional: true optional: true
'@biomejs/cli-linux-arm64@1.8.3': '@biomejs/cli-linux-arm64@1.9.4':
optional: true optional: true
'@biomejs/cli-linux-x64-musl@1.8.3': '@biomejs/cli-linux-x64-musl@1.9.4':
optional: true optional: true
'@biomejs/cli-linux-x64@1.8.3': '@biomejs/cli-linux-x64@1.9.4':
optional: true optional: true
'@biomejs/cli-win32-arm64@1.8.3': '@biomejs/cli-win32-arm64@1.9.4':
optional: true optional: true
'@biomejs/cli-win32-x64@1.8.3': '@biomejs/cli-win32-x64@1.9.4':
optional: true optional: true
'@braintree/sanitize-url@7.0.2': {} '@braintree/sanitize-url@7.0.2': {}