diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..ac5c94e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "tabWidth": 2, + "proseWrap": "preserve", + "semi": true +} diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..acc2369 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Christoph Lindstädt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index b7c4031..0afce24 100644 --- a/README.md +++ b/README.md @@ -1 +1,94 @@ -# Obsidian Chessify + + +# Chessify + +> A chess study helper and PGN viewer/editor for [Obsidian](https://obsidian.md/). + +With this plugin, you can either import PGNs or simply start a fresh new game. It allows you to add comments and arrows for each move, which will be persisted within a JSON File in your vault. Although it is not a full analysis board, it serves as a valuable tool to support your chess notetaking in [Obsidian](https://obsidian.md/). + + + +## Table of contents + +- [Motivation](#motivation) +- [Installation](#installation) +- [Usage](#usage) +- [Features](#features) +- [Settings](#settings) +- [Roadmap](#roadmap) +- [Tools Used](#tools-used) +- [Alternatives](#alternatives) +- [License](#license) + +## Motivation + +I love [Obsidian](https://obsidian.md/) and its tools, but managing screenshots of chess positions is getting out of hand and is also annoying to update. It would be great to have a PGN Viewer similar to the ones offered by [lichess.org](https://lichess.org/) or [chess.com](https://chess.com/) within [Obsidian](https://obsidian.md/). It should allow us to effortlessly view PGNs, add arrows and comments, while also persisting them inside the [Obsidian](https://obsidian.md/) vault. The currently existing [alternatives](#alternatives) primarily focus on visualizing FEN snapshots, which is why this side project started. + +## Installation + +Once you have disabled Safe Mode, you can find third-party plugins by navigating to Settings > Community Plugins > Browse and search for "Chessify". Once you have installed the plugin, you can access it under Settings > Community Plugins. Please note that you must enable the plugin to use it. You can also unsintall the plugin from there. + +## Usage + +To start, position your cursor where you want to place the PGN viewer/editor within your note. Execute the Obsidian command `Chessify: Insert PGN-Editor at cursor position`. + +This action will trigger a modal window, where you have the option to paste your PGN or leave it empty for a fresh new game. Here is what it will look like: + +![chessify-modal](imgs/chessify-modal.png) + +Once you click `Submit`, Chessify will parse the PGN, generate a new JSON file in your vault located at `.obsidian/plugins/obsidian-chessify/storage/{id}.json`, and insert a chessify codeblock at the cursor's position. Here's an example of the chessify codeblock: + +![chessify-codeblock](imgs/chessify-codeblock.png) + +After that the PGN viewer/editor will render and you are good to go: + +![chessify-codeblock](imgs/chessify-demo.gif) + +## Features + +- [x] Import PGNs +- [x] Store game state in JSON +- [x] Add custom PGN viewer +- [x] Only allow legal moves +- [x] Move through the moves via navigation buttons and direct click +- [x] Draw and sync shapes +- [x] Add and sync comments with Markdown support + +## Settings + +Here are the available settings for a `chessify` code block: + +| Setting | Possible Values | Description | +| ------------------ | ------------------ | ------------------------------------------------ | +| `chessifyId` | Valid nanoid | Valid ID for a file stored in the plugin storage | +| `boardOrientation` | `white` \| `black` | Orientation of the board | +| `boardColor` | `green` \| `brown` | Color of the board | + +You can permanently set some settings in the [Obsidian](https://obsidian.md/) plugin settings for Chessify. + +## Roadmap + +- [ ] Add support for variants +- [ ] Add view to manage stored games +- [ ] Add more styles +- [ ] Add more settings + +## Tools Used + +- Chess visuals are powered by [Chessground](https://github.com/lichess-org/chessground) +- Chess logic is powered by [Chess.js](https://github.com/jhlywa/chess.js) +- The markdown editor is powered by [TipTap](https://github.com/ueberdosis/tiptap) +- Icons are provided by [Lucide](https://github.com/lucide-icons/lucide) +- Everything is tied together by [React](https://github.com/facebook/react) + +## Alternatives + +If you want to have a look at FENs instead, check out these alternative Obsidian plugins: + +- [SilentVoid13/Chesser](https://github.com/SilentVoid13/Chesser) +- [pmorim/obsidian-chess](https://github.com/pmorim/obsidian-chess) +- [THeK3nger/obsidian-chessboard](https://github.com/THeK3nger/obsidian-chessboard) + +## License + +[Chessify](https://github.com/chrislicodes/obsidian-chessify) is licensed under the MIT license. Refer to [LICENSE](https://github.com/chrislicodes/obsidian-chessify/blob/trunk/LICENSE.TXT) for more informations. diff --git a/assets/board/green.css b/assets/board/green.css index f868264..ee8380e 100644 --- a/assets/board/green.css +++ b/assets/board/green.css @@ -1,3 +1,3 @@ .green-board cg-board { - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4PSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICAgIHZpZXdCb3g9IjAgMCA4IDgiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+CjxnIGlkPSJhIj4KICA8ZyBpZD0iYiI+CiAgICA8ZyBpZD0iYyI+CiAgICAgIDxnIGlkPSJkIj4KICAgICAgICA8cmVjdCB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSIjZmZmZmRkIiBpZD0iZSIvPgogICAgICAgIDx1c2UgeD0iMSIgeT0iMSIgaHJlZj0iI2UiIHg6aHJlZj0iI2UiLz4KICAgICAgICA8cmVjdCB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSIjODZhNjY2IiBpZD0iZiIvPgogICAgICAgIDx1c2UgeD0iMSIgeT0iLTEiIGhyZWY9IiNmIiB4OmhyZWY9IiNmIi8+CiAgICAgIDwvZz4KICAgICAgPHVzZSB4PSIyIiBocmVmPSIjZCIgeDpocmVmPSIjZCIvPgogICAgPC9nPgogICAgPHVzZSB4PSI0IiBocmVmPSIjYyIgeDpocmVmPSIjYyIvPgogIDwvZz4KICA8dXNlIHk9IjIiIGhyZWY9IiNiIiB4OmhyZWY9IiNiIi8+CjwvZz4KPHVzZSB5PSI0IiBocmVmPSIjYSIgeDpocmVmPSIjYSIvPgo8L3N2Zz4K"); + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4PSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICAgIHZpZXdCb3g9IjAgMCA4IDgiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+CjxnIGlkPSJhIj4KICA8ZyBpZD0iYiI+CiAgICA8ZyBpZD0iYyI+CiAgICAgIDxnIGlkPSJkIj4KICAgICAgICA8cmVjdCB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSIjZmZmZmRkIiBpZD0iZSIvPgogICAgICAgIDx1c2UgeD0iMSIgeT0iMSIgaHJlZj0iI2UiIHg6aHJlZj0iI2UiLz4KICAgICAgICA8cmVjdCB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSIjODZhNjY2IiBpZD0iZiIvPgogICAgICAgIDx1c2UgeD0iMSIgeT0iLTEiIGhyZWY9IiNmIiB4OmhyZWY9IiNmIi8+CiAgICAgIDwvZz4KICAgICAgPHVzZSB4PSIyIiBocmVmPSIjZCIgeDpocmVmPSIjZCIvPgogICAgPC9nPgogICAgPHVzZSB4PSI0IiBocmVmPSIjYyIgeDpocmVmPSIjYyIvPgogIDwvZz4KICA8dXNlIHk9IjIiIGhyZWY9IiNiIiB4OmhyZWY9IiNiIi8+CjwvZz4KPHVzZSB5PSI0IiBocmVmPSIjYSIgeDpocmVmPSIjYSIvPgo8L3N2Zz4K'); } diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 9ba3233..f679ba4 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -1,7 +1,7 @@ -import builtins from "builtin-modules"; -import esbuild from "esbuild"; -import process from "process"; -import { renameStyles } from "./rename-styles.mjs"; +import builtins from 'builtin-modules'; +import esbuild from 'esbuild'; +import process from 'process'; +import { renameStyles } from './rename-styles.mjs'; const banner = `/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD @@ -9,36 +9,36 @@ if you want to view the source, please visit the github repository of this plugi */ `; -const prod = process.argv[2] === "production"; +const prod = process.argv[2] === 'production'; const context = await esbuild.context({ banner: { js: banner, }, - entryPoints: ["src/main.tsx"], + entryPoints: ['src/main.tsx'], bundle: true, external: [ - "obsidian", - "electron", - "@codemirror/autocomplete", - "@codemirror/collab", - "@codemirror/commands", - "@codemirror/language", - "@codemirror/lint", - "@codemirror/search", - "@codemirror/state", - "@codemirror/view", - "@lezer/common", - "@lezer/highlight", - "@lezer/lr", + 'obsidian', + 'electron', + '@codemirror/autocomplete', + '@codemirror/collab', + '@codemirror/commands', + '@codemirror/language', + '@codemirror/lint', + '@codemirror/search', + '@codemirror/state', + '@codemirror/view', + '@lezer/common', + '@lezer/highlight', + '@lezer/lr', ...builtins, ], - format: "cjs", - target: "es2018", - logLevel: "info", - sourcemap: prod ? false : "inline", + format: 'cjs', + target: 'es2018', + logLevel: 'info', + sourcemap: prod ? false : 'inline', treeShaking: true, - outfile: "main.js", + outfile: 'main.js', plugins: [renameStyles], }); diff --git a/imgs/chessify-codeblock.png b/imgs/chessify-codeblock.png new file mode 100644 index 0000000..997512b Binary files /dev/null and b/imgs/chessify-codeblock.png differ diff --git a/imgs/chessify-demo.gif b/imgs/chessify-demo.gif new file mode 100644 index 0000000..06a1b26 Binary files /dev/null and b/imgs/chessify-demo.gif differ diff --git a/imgs/chessify-modal.png b/imgs/chessify-modal.png new file mode 100644 index 0000000..e696a72 Binary files /dev/null and b/imgs/chessify-modal.png differ diff --git a/manifest.json b/manifest.json index 61eb196..ebe953c 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { "id": "obsidian-chessify", "name": "Chessify", - "version": "0.0.1", + "version": "0.1.0", "minAppVersion": "0.15.0", - "description": "A chess study helper for Obsidian (https://obsidian.md)", - "author": "chrislicodes", + "description": "A chess study helper and PGN viewer for Obsidian.", + "author": "Christoph Lindstädt", "authorUrl": "https://github.com/chrislicodes", "isDesktopOnly": false } diff --git a/package.json b/package.json index ede785f..6e62a32 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,12 @@ { "name": "obsidian-chessify", - "version": "0.0.1", - "description": "A chess study helper for Obsidian (https://obsidian.md)", + "version": "0.1.0", + "description": "A chess study helper and PGN viewer for Obsidian", "keywords": [ "chess", - "obsidian" + "obsidian", + "PGN", + "study" ], "license": "MIT", "author": "Christoph Lindstädt", diff --git a/rename-styles.mjs b/rename-styles.mjs index 3bdb052..2a7dcb2 100644 --- a/rename-styles.mjs +++ b/rename-styles.mjs @@ -1,14 +1,14 @@ -import { existsSync, renameSync } from "fs"; +import { existsSync, renameSync } from 'fs'; export const renameStyles = { - name: "rename-styles", + name: 'rename-styles', setup(build) { build.onEnd(() => { const { outfile } = build.initialOptions; - const outcss = outfile.replace(/\.js$/, ".css"); - const fixcss = outfile.replace(/main\.js$/, "styles.css"); + const outcss = outfile.replace(/\.js$/, '.css'); + const fixcss = outfile.replace(/main\.js$/, 'styles.css'); if (existsSync(outcss)) { - console.log("Renaming", outcss, "to", fixcss); + console.log('Renaming', outcss, 'to', fixcss); renameSync(outcss, fixcss); } }); diff --git a/reset.css b/reset.css deleted file mode 100644 index 58fde3d..0000000 --- a/reset.css +++ /dev/null @@ -1,47 +0,0 @@ -/* - Josh's Custom CSS Reset - https://www.joshwcomeau.com/css/custom-css-reset/ -*/ -*, -*::before, -*::after { - box-sizing: border-box; -} -* { - margin: 0; -} -html, -body { - height: 100%; -} -body { - line-height: 1.5; - -webkit-font-smoothing: antialiased; -} -img, -picture, -video, -canvas, -svg { - display: block; - max-width: 100%; -} -input, -button, -textarea, -select { - font: inherit; -} -p, -h1, -h2, -h3, -h4, -h5, -h6 { - overflow-wrap: break-word; -} -#root, -#__next { - isolation: isolate; -} diff --git a/src/components/ReactView.tsx b/src/components/ReactView.tsx index 18185a8..c992511 100644 --- a/src/components/ReactView.tsx +++ b/src/components/ReactView.tsx @@ -1,9 +1,9 @@ -import { App, MarkdownRenderChild } from "obsidian"; -import * as React from "react"; -import * as ReactDOM from "react-dom/client"; -import { ChessifyDataAdapter, ChessifyFileData } from "src/utils"; -import { Chessify } from "../components/react/Chessify"; -import { ChessifyPluginSettings } from "./obsidian/SettingsTab"; +import { App, MarkdownRenderChild } from 'obsidian'; +import * as React from 'react'; +import * as ReactDOM from 'react-dom/client'; +import { ChessifyDataAdapter, ChessifyFileData } from 'src/utils'; +import { Chessify } from '../components/react/Chessify'; +import { ChessifyPluginSettings } from './obsidian/SettingsTab'; export class ReactView extends MarkdownRenderChild { root: ReactDOM.Root; diff --git a/src/components/obsidian/PgnModal.ts b/src/components/obsidian/PgnModal.ts index 0b7d93d..3bf882c 100644 --- a/src/components/obsidian/PgnModal.ts +++ b/src/components/obsidian/PgnModal.ts @@ -1,4 +1,4 @@ -import { App, Modal, Setting } from "obsidian"; +import { App, Modal, Setting } from 'obsidian'; export class PgnModal extends Modal { pgn: string; @@ -12,21 +12,21 @@ export class PgnModal extends Modal { onOpen() { const { contentEl } = this; - contentEl.createEl("h1", { - text: "Paste the full PGN (leave empty for a new game):", + contentEl.createEl('h1', { + text: 'Paste the full PGN (leave empty for a new game):', }); - new Setting(contentEl).setName("PGN").addTextArea((text) => + new Setting(contentEl).setName('PGN').addTextArea((text) => text .onChange((value) => { this.pgn = value; }) - .inputEl.setCssStyles({ width: "100%", height: "250px" }) + .inputEl.setCssStyles({ width: '100%', height: '250px' }) ); new Setting(contentEl).addButton((btn) => btn - .setButtonText("Submit") + .setButtonText('Submit') .setCta() .onClick(() => { this.close(); diff --git a/src/components/obsidian/SettingsTab.ts b/src/components/obsidian/SettingsTab.ts index c0b7977..5406478 100644 --- a/src/components/obsidian/SettingsTab.ts +++ b/src/components/obsidian/SettingsTab.ts @@ -1,14 +1,14 @@ -import { App, PluginSettingTab, Setting } from "obsidian"; -import ChessifyPlugin from "src/main"; +import { App, PluginSettingTab, Setting } from 'obsidian'; +import ChessifyPlugin from 'src/main'; export interface ChessifyPluginSettings { - boardOrientation: "white" | "black"; - boardColor: "green" | "brown"; + boardOrientation: 'white' | 'black'; + boardColor: 'green' | 'brown'; } export const DEFAULT_SETTINGS: ChessifyPluginSettings = { - boardOrientation: "white", - boardColor: "green", + boardOrientation: 'white', + boardColor: 'green', }; export class SettingsTab extends PluginSettingTab { @@ -24,38 +24,36 @@ export class SettingsTab extends PluginSettingTab { containerEl.empty(); - containerEl.createEl("h2", { text: "Obsidian Chessify Settings" }); + containerEl.createEl('h2', { text: 'Obsidian Chessify Settings' }); new Setting(containerEl) - .setName("Board Orientation") - .setDesc("Sets the default orientation of the board") + .setName('Board Orientation') + .setDesc('Sets the default orientation of the board') .addDropdown((dropdown) => { - dropdown.addOption("white", "White"); - dropdown.addOption("black", "Black"); + dropdown.addOption('white', 'White'); + dropdown.addOption('black', 'Black'); dropdown .setValue(this.plugin.settings.boardOrientation) .onChange((orientation) => { this.plugin.settings.boardOrientation = orientation as - | "white" - | "black"; + | 'white' + | 'black'; this.plugin.saveSettings(); }); }); new Setting(containerEl) - .setName("Board Color") - .setDesc("Sets the default color of the board") + .setName('Board Color') + .setDesc('Sets the default color of the board') .addDropdown((dropdown) => { - dropdown.addOption("green", "Green"); - dropdown.addOption("brown", "Brown"); + dropdown.addOption('green', 'Green'); + dropdown.addOption('brown', 'Brown'); dropdown .setValue(this.plugin.settings.boardColor) .onChange((boardColor) => { - this.plugin.settings.boardColor = boardColor as - | "green" - | "brown"; + this.plugin.settings.boardColor = boardColor as 'green' | 'brown'; this.plugin.saveSettings(); }); }); diff --git a/src/components/react/ChessgroundWrapper/index.tsx b/src/components/react/ChessgroundWrapper/index.tsx index 74980a2..047a4f3 100644 --- a/src/components/react/ChessgroundWrapper/index.tsx +++ b/src/components/react/ChessgroundWrapper/index.tsx @@ -1,19 +1,19 @@ -import { Chessground as ChessgroundApi } from "chessground"; -import * as React from "react"; -import { useEffect, useRef } from "react"; +import { Chessground as ChessgroundApi } from 'chessground'; +import * as React from 'react'; +import { useEffect, useRef } from 'react'; -import { Chess, Move } from "chess.js"; -import { Api } from "chessground/api"; -import { Config } from "chessground/config"; -import { DrawShape } from "chessground/draw"; -import { playOtherSide, toColor, toDests } from "src/utils"; +import { Chess, Move } from 'chess.js'; +import { Api } from 'chessground/api'; +import { Config } from 'chessground/config'; +import { DrawShape } from 'chessground/draw'; +import { playOtherSide, toColor, toDests } from 'src/utils'; export interface ChessGroundSettings { api: Api | null; setApi: React.Dispatch>; chessifyId: string; config?: Config; - boardColor?: "brown" | "green"; + boardColor?: 'brown' | 'green'; chess: Chess; setHistory: React.Dispatch>; setShapes: React.Dispatch>; @@ -28,7 +28,7 @@ export const ChessgroundWrapper = React.memo( api, setApi, chessifyId, - boardColor = "green", + boardColor = 'green', config = {}, chess, setHistory, @@ -54,10 +54,7 @@ export const ChessgroundWrapper = React.memo( events: { //Hook up the Chessground UI changes to our App State after: (orig, dest, _metadata) => { - const handler = playOtherSide( - chessgroundApi, - chess - ); + const handler = playOtherSide(chessgroundApi, chess); setHistory(handler(orig, dest)); setMoveNumber((state) => state + 1); @@ -119,18 +116,17 @@ export const ChessgroundWrapper = React.memo( return (
@@ -138,4 +134,4 @@ export const ChessgroundWrapper = React.memo( } ); -ChessgroundWrapper.displayName = "ChessgroundWrapper"; +ChessgroundWrapper.displayName = 'ChessgroundWrapper'; diff --git a/src/components/react/Chessify.tsx b/src/components/react/Chessify.tsx index 59c3f5e..fe2e377 100644 --- a/src/components/react/Chessify.tsx +++ b/src/components/react/Chessify.tsx @@ -1,19 +1,19 @@ -import { JSONContent } from "@tiptap/react"; -import { Chess, Move } from "chess.js"; -import { Api } from "chessground/api"; -import { DrawShape } from "chessground/draw"; -import { App, Notice } from "obsidian"; -import * as React from "react"; -import { useCallback, useMemo, useState } from "react"; -import { ChessifyPluginSettings } from "src/components/obsidian/SettingsTab"; +import { JSONContent } from '@tiptap/react'; +import { Chess, Move } from 'chess.js'; +import { Api } from 'chessground/api'; +import { DrawShape } from 'chessground/draw'; +import { App, Notice } from 'obsidian'; +import * as React from 'react'; +import { useCallback, useMemo, useState } from 'react'; +import { ChessifyPluginSettings } from 'src/components/obsidian/SettingsTab'; import { ChessifyDataAdapter, ChessifyFileData, parseUserConfig, -} from "src/utils"; -import { ChessGroundSettings, ChessgroundWrapper } from "./ChessgroundWrapper"; -import { CommentSection } from "./CommentSection"; -import { PgnViewer } from "./PgnViewer"; +} from 'src/utils'; +import { ChessGroundSettings, ChessgroundWrapper } from './ChessgroundWrapper'; +import { CommentSection } from './CommentSection'; +import { PgnViewer } from './PgnViewer'; export type ChessifyConfig = ChessGroundSettings; @@ -90,8 +90,7 @@ export const Chessify = ({ fen: move.after, check: tempChess.isCheck(), }); - if (currentMove + 1 === history.length - 1) - setIsViewOnly(false); + if (currentMove + 1 === history.length - 1) setIsViewOnly(false); return currentMove + 1; }); } @@ -123,7 +122,7 @@ export const Chessify = ({ header: chessifyDataModified.header, moves: chessLogic.history({ verbose: true }).map((move, index) => ({ ...move, - subMoves: [], + variants: [], shapes: shapes[index], comment: comments[index], })), @@ -131,7 +130,7 @@ export const Chessify = ({ await dataAdapter.saveFile(chessifyData, chessifyId); - new Notice("Save successfull!"); + new Notice('Save successfull!'); }, [ chessLogic, chessifyDataModified.header, @@ -145,14 +144,14 @@ export const Chessify = ({
-
+
{ setComments((currentComments) => { const currentCommentModified = [...currentComments]; - currentCommentModified[currentMove] = - state.editor.getJSON(); + currentCommentModified[currentMove] = state.editor.getJSON(); return currentCommentModified; }); }, @@ -40,4 +39,4 @@ export const CommentSection = React.memo( } ); -CommentSection.displayName = "CommentSection"; +CommentSection.displayName = 'CommentSection'; diff --git a/src/components/react/PgnViewer/index.tsx b/src/components/react/PgnViewer/index.tsx index 2110665..42fb3a7 100644 --- a/src/components/react/PgnViewer/index.tsx +++ b/src/components/react/PgnViewer/index.tsx @@ -1,7 +1,7 @@ -import { Move } from "chess.js"; -import { ArrowLeft, ArrowRight, Save } from "lucide-react"; -import * as React from "react"; -import { useEffect, useMemo, useRef } from "react"; +import { Move } from 'chess.js'; +import { ArrowLeft, ArrowRight, Save } from 'lucide-react'; +import * as React from 'react'; +import { useEffect, useMemo, useRef } from 'react'; const chunkArray = (array: T[], chunkSize: number) => { return array.reduce((resultArray, item, index) => { @@ -31,9 +31,9 @@ const MoveItem = ({ useEffect(() => { if (ref.current && isCurrentMove) { ref.current?.scrollIntoView({ - behavior: "smooth", - block: "nearest", - inline: "end", + behavior: 'smooth', + block: 'nearest', + inline: 'end', }); } }, [isCurrentMove]); @@ -41,7 +41,7 @@ const MoveItem = ({ return (

{ @@ -73,41 +73,33 @@ export const PgnViewer = React.memo( const movePairs = useMemo(() => chunkArray(history, 2), [history]); return ( -

-
+
+
{movePairs.map((pair, i) => { const [wMove, bMove] = pair; return ( -

- {i + 1} -

+

{i + 1}

- onMoveItemClick(i * 2) - } + onMoveItemClick={() => onMoveItemClick(i * 2)} /> {bMove && ( - onMoveItemClick(i * 2 + 1) - } + isCurrentMove={i * 2 + 1 === currentMove} + onMoveItemClick={() => onMoveItemClick(i * 2 + 1)} /> )}
@@ -117,12 +109,12 @@ export const PgnViewer = React.memo(
@@ -140,4 +132,4 @@ export const PgnViewer = React.memo( } ); -PgnViewer.displayName = "PgnViewer"; +PgnViewer.displayName = 'PgnViewer'; diff --git a/src/main.css b/src/main.css index 30d6301..61dddd6 100644 --- a/src/main.css +++ b/src/main.css @@ -78,3 +78,51 @@ button:active { width: 100%; height: 100%; } + +/* + Josh's Custom CSS Reset + https://www.joshwcomeau.com/css/custom-css-reset/ +*/ +*, +*::before, +*::after { + box-sizing: border-box; +} +* { + margin: 0; +} +html, +body { + height: 100%; +} +body { + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} +input, +button, +textarea, +select { + font: inherit; +} +p, +h1, +h2, +h3, +h4, +h5, +h6 { + overflow-wrap: break-word; +} +#root, +#__next { + isolation: isolate; +} diff --git a/src/main.tsx b/src/main.tsx index beef703..8ce22e1 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,25 +1,24 @@ -import { Chess } from "chess.js"; -import { Editor, Notice, Plugin } from "obsidian"; -import { ReactView } from "./components/ReactView"; -import { PgnModal } from "./components/obsidian/PgnModal"; +import { Chess } from 'chess.js'; +import { Editor, Notice, Plugin } from 'obsidian'; +import { ReactView } from './components/ReactView'; +import { PgnModal } from './components/obsidian/PgnModal'; import { ChessifyPluginSettings, DEFAULT_SETTINGS, SettingsTab, -} from "./components/obsidian/SettingsTab"; +} from './components/obsidian/SettingsTab'; import { ChessifyDataAdapter, ChessifyFileData, parseUserConfig, -} from "./utils"; +} from './utils'; // these styles must be imported somewhere -import "assets/board/green.css"; -import "chessground/assets/chessground.base.css"; -import "chessground/assets/chessground.brown.css"; -import "chessground/assets/chessground.cburnett.css"; -import "../reset.css"; -import "./main.css"; +import 'assets/board/green.css'; +import 'chessground/assets/chessground.base.css'; +import 'chessground/assets/chessground.brown.css'; +import 'chessground/assets/chessground.cburnett.css'; +import './main.css'; export default class ChessifyPlugin extends Plugin { settings: ChessifyPluginSettings; @@ -41,8 +40,8 @@ export default class ChessifyPlugin extends Plugin { // Add command this.addCommand({ - id: "insert-chesser", - name: "Insert PGN-Editor at cursor position", + id: 'insert-chesser', + name: 'Insert PGN-Editor at cursor position', editorCallback: (editor: Editor) => { const cursorPosition = editor.getCursor(); @@ -59,28 +58,24 @@ export default class ChessifyPlugin extends Plugin { const chessifyFileData: ChessifyFileData = { header: { - title: chess.header()["opening"] || null, + title: chess.header()['opening'] || null, }, - moves: chess - .history({ verbose: true }) - .map((move) => ({ - ...move, - subMoves: [], - shapes: [], - comment: null, - })), + moves: chess.history({ verbose: true }).map((move) => ({ + ...move, + variants: [], + shapes: [], + comment: null, + })), }; - const id = await this.dataAdapter.saveFile( - chessifyFileData - ); + const id = await this.dataAdapter.saveFile(chessifyFileData); editor.replaceRange( `\`\`\`chessify\nchessifyId: ${id}\n\`\`\``, cursorPosition ); } catch (e) { - new Notice("There was an error during PGN parsing.", 0); + new Notice('There was an error during PGN parsing.', 0); } }; @@ -90,7 +85,7 @@ export default class ChessifyPlugin extends Plugin { // Add chessify code block processor this.registerMarkdownCodeBlockProcessor( - "chessify", + 'chessify', async (source, el, ctx) => { const { chessifyId } = parseUserConfig(this.settings, source); @@ -122,19 +117,15 @@ export default class ChessifyPlugin extends Plugin { } ); - console.log("Chessify successfully loaded"); + console.log('Chessify successfully loaded'); } async onunload() { - console.log("Chessify successfully unloaded"); + console.log('Chessify successfully unloaded'); } async loadSettings() { - this.settings = Object.assign( - {}, - DEFAULT_SETTINGS, - await this.loadData() - ); + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { diff --git a/src/utils/index.ts b/src/utils/index.ts index 3ef78d1..4d38fd7 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,11 +1,11 @@ -import { JSONContent } from "@tiptap/react"; -import { Chess, Move, QUEEN, SQUARES, Square } from "chess.js"; -import { Api } from "chessground/api"; -import { Config } from "chessground/config"; -import { DrawShape } from "chessground/draw"; -import { nanoid } from "nanoid"; -import { DataAdapter, parseYaml } from "obsidian"; -import { ChessifyPluginSettings } from "src/components/obsidian/SettingsTab"; +import { JSONContent } from '@tiptap/react'; +import { Chess, Move, QUEEN, SQUARES, Square } from 'chess.js'; +import { Api } from 'chessground/api'; +import { Config } from 'chessground/config'; +import { DrawShape } from 'chessground/draw'; +import { nanoid } from 'nanoid'; +import { DataAdapter, parseYaml } from 'obsidian'; +import { ChessifyPluginSettings } from 'src/components/obsidian/SettingsTab'; //Chess Logic type ChessifyAppConfig = ChessifyPluginSettings & { @@ -18,7 +18,7 @@ export const parseUserConfig = ( ): ChessifyAppConfig => { const chessifyConfig: ChessifyAppConfig = { ...settings, - chessifyId: "", + chessifyId: '', }; try { @@ -27,12 +27,12 @@ export const parseUserConfig = ( ...parseYaml(content), }; } catch (e) { - throw Error("Something went wrong during parsing. :("); + throw Error('Something went wrong during parsing. :('); } }; export function toColor(chess: Chess) { - return chess.turn() === "w" ? "white" : "black"; + return chess.turn() === 'w' ? 'white' : 'black'; } export function toDests(chess: Chess): Map { @@ -61,7 +61,7 @@ export function playOtherSide(cg: Api, chess: Chess) { check: chess.isCheck(), }; - if (move.flags === "e" || move.promotion) { + if (move.flags === 'e' || move.promotion) { //Handle En Passant && Promote to Queen by default cg.set({ fen: chess.fen(), @@ -78,7 +78,7 @@ export function playOtherSide(cg: Api, chess: Chess) { //Storage Logic interface ChessifyMove extends Move { - subMoves: Move[]; + variants: Move[][]; shapes: DrawShape[]; comment: JSONContent | null; } diff --git a/styles.css b/styles.css index 2b4742f..6fcba20 100644 --- a/styles.css +++ b/styles.css @@ -261,51 +261,6 @@ cg-board square.current-premove { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMi41IDExLjYzVjYiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48cGF0aCBkPSJNMjIuNSAyNXM0LjUtNy41IDMtMTAuNWMwIDAtMS0yLjUtMy0yLjVzLTMgMi41LTMgMi41Yy0xLjUgMyAzIDEwLjUgMyAxMC41IiBmaWxsPSIjMDAwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIvPjxwYXRoIGQ9Ik0xMS41IDM3YzUuNSAzLjUgMTUuNSAzLjUgMjEgMHYtN3M5LTQuNSA2LTEwLjVjLTQtNi41LTEzLjUtMy41LTE2IDRWMjd2LTMuNWMtMy41LTcuNS0xMy0xMC41LTE2LTQtMyA2IDUgMTAgNSAxMFYzN3oiIGZpbGw9IiMwMDAiLz48cGF0aCBkPSJNMjAgOGg1IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIi8+PHBhdGggZD0iTTMyIDI5LjVzOC41LTQgNi4wMy05LjY1QzM0LjE1IDE0IDI1IDE4IDIyLjUgMjQuNWwuMDEgMi4xLS4wMS0yLjFDMjAgMTggOS45MDYgMTQgNi45OTcgMTkuODVjLTIuNDk3IDUuNjUgNC44NTMgOSA0Ljg1MyA5IiBzdHJva2U9IiNlY2VjZWMiLz48cGF0aCBkPSJNMTEuNSAzMGM1LjUtMyAxNS41LTMgMjEgMG0tMjEgMy41YzUuNS0zIDE1LjUtMyAyMSAwbS0yMSAzLjVjNS41LTMgMTUuNS0zIDIxIDAiIHN0cm9rZT0iI2VjZWNlYyIvPjwvZz48L3N2Zz4=); } -/* reset.css */ -*, -*::before, -*::after { - box-sizing: border-box; -} -* { - margin: 0; -} -html, -body { - height: 100%; -} -body { - line-height: 1.5; - -webkit-font-smoothing: antialiased; -} -img, -picture, -video, -canvas, -svg { - display: block; - max-width: 100%; -} -input, -button, -textarea, -select { - font: inherit; -} -p, -h1, -h2, -h3, -h4, -h5, -h6 { - overflow-wrap: break-word; -} -#root, -#__next { - isolation: isolate; -} - /* src/main.css */ button:active { transform: translateY(1px); @@ -376,4 +331,46 @@ button:active { width: 100%; height: 100%; } -/*# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiYXNzZXRzL2JvYXJkL2dyZWVuLmNzcyIsICJub2RlX21vZHVsZXMvY2hlc3Nncm91bmQvYXNzZXRzL2NoZXNzZ3JvdW5kLmJhc2UuY3NzIiwgIm5vZGVfbW9kdWxlcy9jaGVzc2dyb3VuZC9hc3NldHMvY2hlc3Nncm91bmQuYnJvd24uY3NzIiwgIm5vZGVfbW9kdWxlcy9jaGVzc2dyb3VuZC9hc3NldHMvY2hlc3Nncm91bmQuY2J1cm5ldHQuY3NzIiwgInJlc2V0LmNzcyIsICJzcmMvbWFpbi5jc3MiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi5ncmVlbi1ib2FyZCBjZy1ib2FyZCB7XG5cdGJhY2tncm91bmQtaW1hZ2U6IHVybChcImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlCbGJtTnZaR2x1WnowaVZWUkdMVGdpSUhOMFlXNWtZV3h2Ym1VOUltNXZJajgrQ2p4emRtY2dlRzFzYm5NOUltaDBkSEE2THk5M2QzY3Vkek11YjNKbkx6SXdNREF2YzNabklpQjRiV3h1Y3pwNFBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJZ29nSUNBZ0lIWnBaWGRDYjNnOUlqQWdNQ0E0SURnaUlITm9ZWEJsTFhKbGJtUmxjbWx1WnowaVkzSnBjM0JGWkdkbGN5SStDanhuSUdsa1BTSmhJajRLSUNBOFp5QnBaRDBpWWlJK0NpQWdJQ0E4WnlCcFpEMGlZeUkrQ2lBZ0lDQWdJRHhuSUdsa1BTSmtJajRLSUNBZ0lDQWdJQ0E4Y21WamRDQjNhV1IwYUQwaU1TSWdhR1ZwWjJoMFBTSXhJaUJtYVd4c1BTSWpabVptWm1Sa0lpQnBaRDBpWlNJdlBnb2dJQ0FnSUNBZ0lEeDFjMlVnZUQwaU1TSWdlVDBpTVNJZ2FISmxaajBpSTJVaUlIZzZhSEpsWmowaUkyVWlMejRLSUNBZ0lDQWdJQ0E4Y21WamRDQjVQU0l4SWlCM2FXUjBhRDBpTVNJZ2FHVnBaMmgwUFNJeElpQm1hV3hzUFNJak9EWmhOalkySWlCcFpEMGlaaUl2UGdvZ0lDQWdJQ0FnSUR4MWMyVWdlRDBpTVNJZ2VUMGlMVEVpSUdoeVpXWTlJaU5tSWlCNE9taHlaV1k5SWlObUlpOCtDaUFnSUNBZ0lEd3ZaejRLSUNBZ0lDQWdQSFZ6WlNCNFBTSXlJaUJvY21WbVBTSWpaQ0lnZURwb2NtVm1QU0lqWkNJdlBnb2dJQ0FnUEM5blBnb2dJQ0FnUEhWelpTQjRQU0kwSWlCb2NtVm1QU0lqWXlJZ2VEcG9jbVZtUFNJall5SXZQZ29nSUR3dlp6NEtJQ0E4ZFhObElIazlJaklpSUdoeVpXWTlJaU5pSWlCNE9taHlaV1k5SWlOaUlpOCtDand2Wno0S1BIVnpaU0I1UFNJMElpQm9jbVZtUFNJallTSWdlRHBvY21WbVBTSWpZU0l2UGdvOEwzTjJaejRLXCIpO1xufVxuIiwgIi5jZy13cmFwIHtcbiAgYm94LXNpemluZzogY29udGVudC1ib3g7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgZGlzcGxheTogYmxvY2s7XG59XG5cbmNnLWNvbnRhaW5lciB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogMTAwJTtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHRvcDogMDtcbn1cblxuY2ctYm9hcmQge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogMTAwJTtcbiAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1vei11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1zLXVzZXItc2VsZWN0OiBub25lO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgbGluZS1oZWlnaHQ6IDA7XG4gIGJhY2tncm91bmQtc2l6ZTogY292ZXI7XG59XG5cbi5jZy13cmFwLm1hbmlwdWxhYmxlIGNnLWJvYXJkIHtcbiAgY3Vyc29yOiBwb2ludGVyO1xufVxuXG5jZy1ib2FyZCBzcXVhcmUge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgd2lkdGg6IDEyLjUlO1xuICBoZWlnaHQ6IDEyLjUlO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuY2ctYm9hcmQgc3F1YXJlLm1vdmUtZGVzdCB7XG4gIHBvaW50ZXItZXZlbnRzOiBhdXRvO1xufVxuXG5jZy1ib2FyZCBzcXVhcmUubGFzdC1tb3ZlIHtcbiAgd2lsbC1jaGFuZ2U6IHRyYW5zZm9ybTtcbn1cblxuLmNnLXdyYXAgcGllY2Uge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgd2lkdGg6IDEyLjUlO1xuICBoZWlnaHQ6IDEyLjUlO1xuICBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xuICB6LWluZGV4OiAyO1xuICB3aWxsLWNoYW5nZTogdHJhbnNmb3JtO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuY2ctYm9hcmQgcGllY2UuZHJhZ2dpbmcge1xuICBjdXJzb3I6IG1vdmU7XG4gIC8qICFpbXBvcnRhbnQgdG8gb3ZlcnJpZGUgei1pbmRleCBmcm9tIDNEIHBpZWNlIGlubGluZSBzdHlsZSAqL1xuICB6LWluZGV4OiAxMSAhaW1wb3J0YW50O1xufVxuXG5waWVjZS5hbmltIHtcbiAgei1pbmRleDogODtcbn1cblxucGllY2UuZmFkaW5nIHtcbiAgei1pbmRleDogMTtcbiAgb3BhY2l0eTogMC41O1xufVxuXG4uY2ctd3JhcCBwaWVjZS5naG9zdCB7XG4gIG9wYWNpdHk6IDAuMztcbn1cblxuLmNnLXdyYXAgcGllY2Ugc3ZnIHtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICB0b3A6IDBweDtcbiAgbGVmdDogMHB4O1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgei1pbmRleDogMjtcbiAgb3BhY2l0eTogMC42O1xufVxuXG4uY2ctd3JhcCBjZy1hdXRvLXBpZWNlcyxcbi5jZy13cmFwIC5jZy1zaGFwZXMsXG4uY2ctd3JhcCAuY2ctY3VzdG9tLXN2Z3Mge1xuICBvdmVyZmxvdzogdmlzaWJsZTtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDBweDtcbiAgbGVmdDogMHB4O1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuLmNnLXdyYXAgY2ctYXV0by1waWVjZXMge1xuICB6LWluZGV4OiAyO1xufVxuXG4uY2ctd3JhcCBjZy1hdXRvLXBpZWNlcyBwaWVjZSB7XG4gIG9wYWNpdHk6IDAuMztcbn1cblxuLmNnLXdyYXAgLmNnLXNoYXBlcyB7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIG9wYWNpdHk6IDAuNjtcbiAgei1pbmRleDogMjtcbn1cblxuLmNnLXdyYXAgLmNnLWN1c3RvbS1zdmdzIHtcbiAgLyogb3ZlciBwaWVjZS5hbmltID0gOCwgYnV0IHVuZGVyIHBpZWNlLmRyYWdnaW5nID0gMTEgKi9cbiAgei1pbmRleDogOTtcbn1cblxuLmNnLXdyYXAgLmNnLWN1c3RvbS1zdmdzIHN2ZyB7XG4gIG92ZXJmbG93OiB2aXNpYmxlO1xufVxuXG4uY2ctd3JhcCBjb29yZHMge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIHBvaW50ZXItZXZlbnRzOiBub25lO1xuICBvcGFjaXR5OiAwLjg7XG4gIGZvbnQtZmFtaWx5OiBzYW5zLXNlcmlmO1xuICBmb250LXNpemU6IDlweDtcbn1cblxuLmNnLXdyYXAgY29vcmRzLnJhbmtzIHtcbiAgbGVmdDogNHB4O1xuICB0b3A6IC0yMHB4O1xuICBmbGV4LWZsb3c6IGNvbHVtbi1yZXZlcnNlO1xuICBoZWlnaHQ6IDEwMCU7XG4gIHdpZHRoOiAxMnB4O1xufVxuXG4uY2ctd3JhcCBjb29yZHMucmFua3MuYmxhY2sge1xuICBmbGV4LWZsb3c6IGNvbHVtbjtcbn1cblxuLmNnLXdyYXAgY29vcmRzLnJhbmtzLmxlZnQge1xuICBsZWZ0OiAtMTVweDtcbiAgYWxpZ24taXRlbXM6IGZsZXgtZW5kO1xufVxuXG4uY2ctd3JhcCBjb29yZHMuZmlsZXMge1xuICBib3R0b206IC00cHg7XG4gIGxlZnQ6IDI0cHg7XG4gIGZsZXgtZmxvdzogcm93O1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxNnB4O1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG59XG5cbi5jZy13cmFwIGNvb3Jkcy5maWxlcy5ibGFjayB7XG4gIGZsZXgtZmxvdzogcm93LXJldmVyc2U7XG59XG5cbi5jZy13cmFwIGNvb3JkcyBjb29yZCB7XG4gIGZsZXg6IDEgMSBhdXRvO1xufVxuXG4uY2ctd3JhcCBjb29yZHMucmFua3MgY29vcmQge1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoMzklKTtcbn1cbiIsICIvKiogQ29sb3JlZCBib2FyZCBzcXVhcmVzIGFzIGFuIGVtYmVkZGVkIFNWRyAqL1xuY2ctYm9hcmQge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBkOWI1O1xuICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoJ2RhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlCbGJtTnZaR2x1WnowaVZWUkdMVGdpSUhOMFlXNWtZV3h2Ym1VOUltNXZJajgrQ2p4emRtY2dlRzFzYm5NOUltaDBkSEE2THk5M2QzY3Vkek11YjNKbkx6SXdNREF2YzNabklpQjRiV3h1Y3pwNFBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJZ29nSUNBZ0lIWnBaWGRDYjNnOUlqQWdNQ0E0SURnaUlITm9ZWEJsTFhKbGJtUmxjbWx1WnowaVkzSnBjM0JGWkdkbGN5SStDanhuSUdsa1BTSmhJajRLSUNBOFp5QnBaRDBpWWlJK0NpQWdJQ0E4WnlCcFpEMGlZeUkrQ2lBZ0lDQWdJRHhuSUdsa1BTSmtJajRLSUNBZ0lDQWdJQ0E4Y21WamRDQjNhV1IwYUQwaU1TSWdhR1ZwWjJoMFBTSXhJaUJwWkQwaVpTSWdiM0JoWTJsMGVUMGlNQ0l2UGdvZ0lDQWdJQ0FnSUR4MWMyVWdlRDBpTVNJZ2VUMGlNU0lnYUhKbFpqMGlJMlVpSUhnNmFISmxaajBpSTJVaUx6NEtJQ0FnSUNBZ0lDQThjbVZqZENCNVBTSXhJaUIzYVdSMGFEMGlNU0lnYUdWcFoyaDBQU0l4SWlCcFpEMGlaaUlnYjNCaFkybDBlVDBpTUM0eUlpOCtDaUFnSUNBZ0lDQWdQSFZ6WlNCNFBTSXhJaUI1UFNJdE1TSWdhSEpsWmowaUkyWWlJSGc2YUhKbFpqMGlJMllpTHo0S0lDQWdJQ0FnUEM5blBnb2dJQ0FnSUNBOGRYTmxJSGc5SWpJaUlHaHlaV1k5SWlOa0lpQjRPbWh5WldZOUlpTmtJaTgrQ2lBZ0lDQThMMmMrQ2lBZ0lDQThkWE5sSUhnOUlqUWlJR2h5WldZOUlpTmpJaUI0T21oeVpXWTlJaU5qSWk4K0NpQWdQQzluUGdvZ0lEeDFjMlVnZVQwaU1pSWdhSEpsWmowaUkySWlJSGc2YUhKbFpqMGlJMklpTHo0S1BDOW5QZ284ZFhObElIazlJalFpSUdoeVpXWTlJaU5oSWlCNE9taHlaV1k5SWlOaElpOCtDand2YzNablBnPT0nKTtcbn1cblxuLyoqIEludGVyYWN0aXZlIGJvYXJkIHNxdWFyZSBjb2xvcnMgKi9cbmNnLWJvYXJkIHNxdWFyZS5tb3ZlLWRlc3Qge1xuICBiYWNrZ3JvdW5kOiByYWRpYWwtZ3JhZGllbnQocmdiYSgyMCwgODUsIDMwLCAwLjUpIDIyJSwgIzIwODUzMCAwLCByZ2JhKDAsIDAsIDAsIDAuMykgMCwgcmdiYSgwLCAwLCAwLCAwKSAwKTtcbn1cbmNnLWJvYXJkIHNxdWFyZS5wcmVtb3ZlLWRlc3Qge1xuICBiYWNrZ3JvdW5kOiByYWRpYWwtZ3JhZGllbnQocmdiYSgyMCwgMzAsIDg1LCAwLjUpIDIyJSwgIzIwMzA4NSAwLCByZ2JhKDAsIDAsIDAsIDAuMykgMCwgcmdiYSgwLCAwLCAwLCAwKSAwKTtcbn1cbmNnLWJvYXJkIHNxdWFyZS5vYy5tb3ZlLWRlc3Qge1xuICBiYWNrZ3JvdW5kOiByYWRpYWwtZ3JhZGllbnQodHJhbnNwYXJlbnQgMCUsIHRyYW5zcGFyZW50IDgwJSwgcmdiYSgyMCwgODUsIDAsIDAuMykgODAlKTtcbn1cbmNnLWJvYXJkIHNxdWFyZS5vYy5wcmVtb3ZlLWRlc3Qge1xuICBiYWNrZ3JvdW5kOiByYWRpYWwtZ3JhZGllbnQodHJhbnNwYXJlbnQgMCUsIHRyYW5zcGFyZW50IDgwJSwgcmdiYSgyMCwgMzAsIDg1LCAwLjIpIDgwJSk7XG59XG5jZy1ib2FyZCBzcXVhcmUubW92ZS1kZXN0OmhvdmVyIHtcbiAgYmFja2dyb3VuZDogcmdiYSgyMCwgODUsIDMwLCAwLjMpO1xufVxuY2ctYm9hcmQgc3F1YXJlLnByZW1vdmUtZGVzdDpob3ZlciB7XG4gIGJhY2tncm91bmQ6IHJnYmEoMjAsIDMwLCA4NSwgMC4yKTtcbn1cbmNnLWJvYXJkIHNxdWFyZS5sYXN0LW1vdmUge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDE1NSwgMTk5LCAwLCAwLjQxKTtcbn1cbmNnLWJvYXJkIHNxdWFyZS5zZWxlY3RlZCB7XG4gIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMjAsIDg1LCAzMCwgMC41KTtcbn1cbmNnLWJvYXJkIHNxdWFyZS5jaGVjayB7XG4gIGJhY2tncm91bmQ6IHJhZGlhbC1ncmFkaWVudChcbiAgICBlbGxpcHNlIGF0IGNlbnRlcixcbiAgICByZ2JhKDI1NSwgMCwgMCwgMSkgMCUsXG4gICAgcmdiYSgyMzEsIDAsIDAsIDEpIDI1JSxcbiAgICByZ2JhKDE2OSwgMCwgMCwgMCkgODklLFxuICAgIHJnYmEoMTU4LCAwLCAwLCAwKSAxMDAlXG4gICk7XG59XG5jZy1ib2FyZCBzcXVhcmUuY3VycmVudC1wcmVtb3ZlIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgyMCwgMzAsIDg1LCAwLjUpO1xufVxuXG4vKiogQWx0ZXJuYXRpbmcgY29sb3JzIGluIHJhbmsvZmlsZSBsYWJlbHMgKi9cbi5jZy13cmFwLm9yaWVudGF0aW9uLXdoaXRlIGNvb3Jkcy5yYW5rcyBjb29yZDpudGgtY2hpbGQoMm4pLFxuLmNnLXdyYXAub3JpZW50YXRpb24td2hpdGUgY29vcmRzLmZpbGVzIGNvb3JkOm50aC1jaGlsZCgybiksXG4uY2ctd3JhcC5vcmllbnRhdGlvbi1ibGFjayBjb29yZHMucmFua3MgY29vcmQ6bnRoLWNoaWxkKDJuICsgMSksXG4uY2ctd3JhcC5vcmllbnRhdGlvbi1ibGFjayBjb29yZHMuZmlsZXMgY29vcmQ6bnRoLWNoaWxkKDJuICsgMSkge1xuICBjb2xvcjogcmdiYSg3MiwgNzIsIDcyLCAwLjgpO1xufVxuXG4uY2ctd3JhcC5vcmllbnRhdGlvbi1ibGFjayBjb29yZHMucmFua3MgY29vcmQ6bnRoLWNoaWxkKDJuKSxcbi5jZy13cmFwLm9yaWVudGF0aW9uLWJsYWNrIGNvb3Jkcy5maWxlcyBjb29yZDpudGgtY2hpbGQoMm4pLFxuLmNnLXdyYXAub3JpZW50YXRpb24td2hpdGUgY29vcmRzLnJhbmtzIGNvb3JkOm50aC1jaGlsZCgybiArIDEpLFxuLmNnLXdyYXAub3JpZW50YXRpb24td2hpdGUgY29vcmRzLmZpbGVzIGNvb3JkOm50aC1jaGlsZCgybiArIDEpIHtcbiAgY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC44KTtcbn1cbiIsICIvKiogRW1iZWRkZWQgU1ZHcyBmb3IgYWxsIGNoZXNzIHBpZWNlcyAqL1xuLmNnLXdyYXAgcGllY2UucGF3bi53aGl0ZSB7XG4gIGJhY2tncm91bmQtaW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0kwTlNJZ2FHVnBaMmgwUFNJME5TSStQSEJoZEdnZ1pEMGlUVEl5TGpVZ09XTXRNaTR5TVNBd0xUUWdNUzQzT1MwMElEUWdNQ0F1T0RrdU1qa2dNUzQzTVM0M09DQXlMak00UXpFM0xqTXpJREUyTGpVZ01UWWdNVGd1TlRrZ01UWWdNakZqTUNBeUxqQXpMamswSURNdU9EUWdNaTQwTVNBMUxqQXpMVE1nTVM0d05pMDNMalF4SURVdU5UVXROeTQwTVNBeE15NDBOMmd5TTJNd0xUY3VPVEl0TkM0ME1TMHhNaTQwTVMwM0xqUXhMVEV6TGpRM0lERXVORGN0TVM0eE9TQXlMalF4TFRNZ01pNDBNUzAxTGpBeklEQXRNaTQwTVMweExqTXpMVFF1TlMwekxqSTRMVFV1TmpJdU5Ea3RMalkzTGpjNExURXVORGt1TnpndE1pNHpPQ0F3TFRJdU1qRXRNUzQzT1MwMExUUXROSG9pSUdacGJHdzlJaU5tWm1ZaUlITjBjbTlyWlQwaUl6QXdNQ0lnYzNSeWIydGxMWGRwWkhSb1BTSXhMalVpSUhOMGNtOXJaUzFzYVc1bFkyRndQU0p5YjNWdVpDSXZQand2YzNablBnPT0nKTtcbn1cbi5jZy13cmFwIHBpZWNlLmJpc2hvcC53aGl0ZSB7XG4gIGJhY2tncm91bmQtaW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0kwTlNJZ2FHVnBaMmgwUFNJME5TSStQR2NnWm1sc2JEMGlibTl1WlNJZ1ptbHNiQzF5ZFd4bFBTSmxkbVZ1YjJSa0lpQnpkSEp2YTJVOUlpTXdNREFpSUhOMGNtOXJaUzEzYVdSMGFEMGlNUzQxSWlCemRISnZhMlV0YkdsdVpXTmhjRDBpY205MWJtUWlJSE4wY205clpTMXNhVzVsYW05cGJqMGljbTkxYm1RaVBqeG5JR1pwYkd3OUlpTm1abVlpSUhOMGNtOXJaUzFzYVc1bFkyRndQU0ppZFhSMElqNDhjR0YwYUNCa1BTSk5PU0F6Tm1NekxqTTVMUzQ1TnlBeE1DNHhNUzQwTXlBeE15NDFMVElnTXk0ek9TQXlMalF6SURFd0xqRXhJREV1TURNZ01UTXVOU0F5SURBZ01DQXhMalkxTGpVMElETWdNaTB1TmpndU9UY3RNUzQyTlM0NU9TMHpJQzQxTFRNdU16a3RMamszTFRFd0xqRXhMalEyTFRFekxqVXRNUzB6TGpNNUlERXVORFl0TVRBdU1URXVNRE10TVRNdU5TQXhMVEV1TXpVMExqUTVMVEl1TXpJekxqUTNMVE10TGpVZ01TNHpOVFF0TVM0NU5DQXpMVElnTXkweWVpSXZQanh3WVhSb0lHUTlJazB4TlNBek1tTXlMalVnTWk0MUlERXlMalVnTWk0MUlERTFJREFnTGpVdE1TNDFJREF0TWlBd0xUSWdNQzB5TGpVdE1pNDFMVFF0TWk0MUxUUWdOUzQxTFRFdU5TQTJMVEV4TGpVdE5TMHhOUzQxTFRFeElEUXRNVEF1TlNBeE5DMDFJREUxTGpVZ01DQXdMVEl1TlNBeExqVXRNaTQxSURRZ01DQXdMUzQxTGpVZ01DQXllaUl2UGp4d1lYUm9JR1E5SWsweU5TQTRZVEl1TlNBeUxqVWdNQ0F4SURFdE5TQXdJREl1TlNBeUxqVWdNQ0F4SURFZ05TQXdlaUl2UGp3dlp6NDhjR0YwYUNCa1BTSk5NVGN1TlNBeU5tZ3hNRTB4TlNBek1HZ3hOVzB0Tnk0MUxURTBMalYyTlUweU1DQXhPR2cxSWlCemRISnZhMlV0YkdsdVpXcHZhVzQ5SW0xcGRHVnlJaTgrUEM5blBqd3ZjM1puUGc9PScpO1xufVxuLmNnLXdyYXAgcGllY2Uua25pZ2h0LndoaXRlIHtcbiAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGRwWkhSb1BTSTBOU0lnYUdWcFoyaDBQU0kwTlNJK1BHY2dabWxzYkQwaWJtOXVaU0lnWm1sc2JDMXlkV3hsUFNKbGRtVnViMlJrSWlCemRISnZhMlU5SWlNd01EQWlJSE4wY205clpTMTNhV1IwYUQwaU1TNDFJaUJ6ZEhKdmEyVXRiR2x1WldOaGNEMGljbTkxYm1RaUlITjBjbTlyWlMxc2FXNWxhbTlwYmowaWNtOTFibVFpUGp4d1lYUm9JR1E5SWsweU1pQXhNR014TUM0MUlERWdNVFl1TlNBNElERTJJREk1U0RFMVl6QXRPU0F4TUMwMkxqVWdPQzB5TVNJZ1ptbHNiRDBpSTJabVppSXZQanh3WVhSb0lHUTlJazB5TkNBeE9HTXVNemdnTWk0NU1TMDFMalUxSURjdU16Y3RPQ0E1TFRNZ01pMHlMamd5SURRdU16UXROU0EwTFRFdU1EUXlMUzQ1TkNBeExqUXhMVE11TURRZ01DMHpMVEVnTUNBdU1Ua2dNUzR5TXkweElESXRNU0F3TFRRdU1EQXpJREV0TkMwMElEQXRNaUEyTFRFeUlEWXRNVEp6TVM0NE9TMHhMamtnTWkwekxqVmpMUzQzTXkwdU9UazBMUzQxTFRJdExqVXRNeUF4TFRFZ015QXlMalVnTXlBeUxqVm9Nbk11TnpndE1TNDVPVElnTWk0MUxUTmpNU0F3SURFZ015QXhJRE1pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PUzQxSURJMUxqVmhMalV1TlNBd0lERWdNUzB4SURBZ0xqVXVOU0F3SURFZ01TQXhJREI2YlRVdU5ETXpMVGt1TnpWaExqVWdNUzQxSURNd0lERWdNUzB1T0RZMkxTNDFMalVnTVM0MUlETXdJREVnTVNBdU9EWTJMalY2SWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp3dmMzWm5QZz09Jyk7XG59XG4uY2ctd3JhcCBwaWVjZS5yb29rLndoaXRlIHtcbiAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGRwWkhSb1BTSTBOU0lnYUdWcFoyaDBQU0kwTlNJK1BHY2dabWxzYkQwaUkyWm1aaUlnWm1sc2JDMXlkV3hsUFNKbGRtVnViMlJrSWlCemRISnZhMlU5SWlNd01EQWlJSE4wY205clpTMTNhV1IwYUQwaU1TNDFJaUJ6ZEhKdmEyVXRiR2x1WldOaGNEMGljbTkxYm1RaUlITjBjbTlyWlMxc2FXNWxhbTlwYmowaWNtOTFibVFpUGp4d1lYUm9JR1E5SWswNUlETTVhREkzZGkwelNEbDJNM3B0TXkwemRpMDBhREl4ZGpSSU1USjZiUzB4TFRJeVZqbG9OSFl5YURWV09XZzFkakpvTlZZNWFEUjJOU0lnYzNSeWIydGxMV3hwYm1WallYQTlJbUoxZEhRaUx6NDhjR0YwYUNCa1BTSk5NelFnTVRSc0xUTWdNMGd4Tkd3dE15MHpJaTgrUEhCaGRHZ2daRDBpVFRNeElERTNkakV5TGpWSU1UUldNVGNpSUhOMGNtOXJaUzFzYVc1bFkyRndQU0ppZFhSMElpQnpkSEp2YTJVdGJHbHVaV3B2YVc0OUltMXBkR1Z5SWk4K1BIQmhkR2dnWkQwaVRUTXhJREk1TGpWc01TNDFJREl1TldndE1qQnNNUzQxTFRJdU5TSXZQanh3WVhSb0lHUTlJazB4TVNBeE5HZ3lNeUlnWm1sc2JEMGlibTl1WlNJZ2MzUnliMnRsTFd4cGJtVnFiMmx1UFNKdGFYUmxjaUl2UGp3dlp6NDhMM04yWno0PScpO1xufVxuLmNnLXdyYXAgcGllY2UucXVlZW4ud2hpdGUge1xuICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoJ2RhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIZHBaSFJvUFNJME5TSWdhR1ZwWjJoMFBTSTBOU0krUEdjZ1ptbHNiRDBpSTJabVppSWdabWxzYkMxeWRXeGxQU0psZG1WdWIyUmtJaUJ6ZEhKdmEyVTlJaU13TURBaUlITjBjbTlyWlMxM2FXUjBhRDBpTVM0MUlpQnpkSEp2YTJVdGJHbHVaV05oY0QwaWNtOTFibVFpSUhOMGNtOXJaUzFzYVc1bGFtOXBiajBpY205MWJtUWlQanh3WVhSb0lHUTlJazA0SURFeVlUSWdNaUF3SURFZ01TMDBJREFnTWlBeUlEQWdNU0F4SURRZ01IcHRNVFl1TlMwMExqVmhNaUF5SURBZ01TQXhMVFFnTUNBeUlESWdNQ0F4SURFZ05DQXdlazAwTVNBeE1tRXlJRElnTUNBeElERXROQ0F3SURJZ01pQXdJREVnTVNBMElEQjZUVEUySURndU5XRXlJRElnTUNBeElERXROQ0F3SURJZ01pQXdJREVnTVNBMElEQjZUVE16SURsaE1pQXlJREFnTVNBeExUUWdNQ0F5SURJZ01DQXhJREVnTkNBd2VpSXZQanh3WVhSb0lHUTlJazA1SURJMll6Z3VOUzB4TGpVZ01qRXRNUzQxSURJM0lEQnNNaTB4TWkwM0lERXhWakV4YkMwMUxqVWdNVE11TlMwekxURTFMVE1nTVRVdE5TNDFMVEUwVmpJMVREY2dNVFJzTWlBeE1ub2lJSE4wY205clpTMXNhVzVsWTJGd1BTSmlkWFIwSWk4K1BIQmhkR2dnWkQwaVRUa2dNalpqTUNBeUlERXVOU0F5SURJdU5TQTBJREVnTVM0MUlERWdNU0F1TlNBekxqVXRNUzQxSURFdE1TNDFJREl1TlMweExqVWdNaTQxTFRFdU5TQXhMalV1TlNBeUxqVXVOU0F5TGpVZ05pNDFJREVnTVRZdU5TQXhJREl6SURBZ01DQXdJREV1TlMweElEQXRNaTQxSURBZ01DQXVOUzB4TGpVdE1TMHlMalV0TGpVdE1pNDFMUzQxTFRJZ0xqVXRNeTQxSURFdE1pQXlMalV0TWlBeUxqVXROQzA0TGpVdE1TNDFMVEU0TGpVdE1TNDFMVEkzSURCNklpQnpkSEp2YTJVdGJHbHVaV05oY0QwaVluVjBkQ0l2UGp4d1lYUm9JR1E5SWsweE1TNDFJRE13WXpNdU5TMHhJREU0TGpVdE1TQXlNaUF3VFRFeUlETXpMalZqTmkweElERTFMVEVnTWpFZ01DSWdabWxzYkQwaWJtOXVaU0l2UGp3dlp6NDhMM04yWno0PScpO1xufVxuLmNnLXdyYXAgcGllY2Uua2luZy53aGl0ZSB7XG4gIGJhY2tncm91bmQtaW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0kwTlNJZ2FHVnBaMmgwUFNJME5TSStQR2NnWm1sc2JEMGlibTl1WlNJZ1ptbHNiQzF5ZFd4bFBTSmxkbVZ1YjJSa0lpQnpkSEp2YTJVOUlpTXdNREFpSUhOMGNtOXJaUzEzYVdSMGFEMGlNUzQxSWlCemRISnZhMlV0YkdsdVpXTmhjRDBpY205MWJtUWlJSE4wY205clpTMXNhVzVsYW05cGJqMGljbTkxYm1RaVBqeHdZWFJvSUdROUlrMHlNaTQxSURFeExqWXpWalpOTWpBZ09HZzFJaUJ6ZEhKdmEyVXRiR2x1WldwdmFXNDlJbTFwZEdWeUlpOCtQSEJoZEdnZ1pEMGlUVEl5TGpVZ01qVnpOQzQxTFRjdU5TQXpMVEV3TGpWak1DQXdMVEV0TWk0MUxUTXRNaTQxY3kweklESXVOUzB6SURJdU5XTXRNUzQxSURNZ015QXhNQzQxSURNZ01UQXVOU0lnWm1sc2JEMGlJMlptWmlJZ2MzUnliMnRsTFd4cGJtVmpZWEE5SW1KMWRIUWlJSE4wY205clpTMXNhVzVsYW05cGJqMGliV2wwWlhJaUx6NDhjR0YwYUNCa1BTSk5NVEV1TlNBek4yTTFMalVnTXk0MUlERTFMalVnTXk0MUlESXhJREIyTFRkek9TMDBMalVnTmkweE1DNDFZeTAwTFRZdU5TMHhNeTQxTFRNdU5TMHhOaUEwVmpJM2RpMHpMalZqTFRNdU5TMDNMalV0TVRNdE1UQXVOUzB4TmkwMExUTWdOaUExSURFd0lEVWdNVEJXTXpkNklpQm1hV3hzUFNJalptWm1JaTgrUEhCaGRHZ2daRDBpVFRFeExqVWdNekJqTlM0MUxUTWdNVFV1TlMweklESXhJREJ0TFRJeElETXVOV00xTGpVdE15QXhOUzQxTFRNZ01qRWdNRzB0TWpFZ015NDFZelV1TlMweklERTFMalV0TXlBeU1TQXdJaTgrUEM5blBqd3ZjM1puUGc9PScpO1xufVxuLmNnLXdyYXAgcGllY2UucGF3bi5ibGFjayB7XG4gIGJhY2tncm91bmQtaW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0kwTlNJZ2FHVnBaMmgwUFNJME5TSStQSEJoZEdnZ1pEMGlUVEl5TGpVZ09XTXRNaTR5TVNBd0xUUWdNUzQzT1MwMElEUWdNQ0F1T0RrdU1qa2dNUzQzTVM0M09DQXlMak00UXpFM0xqTXpJREUyTGpVZ01UWWdNVGd1TlRrZ01UWWdNakZqTUNBeUxqQXpMamswSURNdU9EUWdNaTQwTVNBMUxqQXpMVE1nTVM0d05pMDNMalF4SURVdU5UVXROeTQwTVNBeE15NDBOMmd5TTJNd0xUY3VPVEl0TkM0ME1TMHhNaTQwTVMwM0xqUXhMVEV6TGpRM0lERXVORGN0TVM0eE9TQXlMalF4TFRNZ01pNDBNUzAxTGpBeklEQXRNaTQwTVMweExqTXpMVFF1TlMwekxqSTRMVFV1TmpJdU5Ea3RMalkzTGpjNExURXVORGt1TnpndE1pNHpPQ0F3TFRJdU1qRXRNUzQzT1MwMExUUXROSG9pSUhOMGNtOXJaVDBpSXpBd01DSWdjM1J5YjJ0bExYZHBaSFJvUFNJeExqVWlJSE4wY205clpTMXNhVzVsWTJGd1BTSnliM1Z1WkNJdlBqd3ZjM1puUGc9PScpO1xufVxuLmNnLXdyYXAgcGllY2UuYmlzaG9wLmJsYWNrIHtcbiAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGRwWkhSb1BTSTBOU0lnYUdWcFoyaDBQU0kwTlNJK1BHY2dabWxzYkQwaWJtOXVaU0lnWm1sc2JDMXlkV3hsUFNKbGRtVnViMlJrSWlCemRISnZhMlU5SWlNd01EQWlJSE4wY205clpTMTNhV1IwYUQwaU1TNDFJaUJ6ZEhKdmEyVXRiR2x1WldOaGNEMGljbTkxYm1RaUlITjBjbTlyWlMxc2FXNWxhbTlwYmowaWNtOTFibVFpUGp4bklHWnBiR3c5SWlNd01EQWlJSE4wY205clpTMXNhVzVsWTJGd1BTSmlkWFIwSWo0OGNHRjBhQ0JrUFNKTk9TQXpObU16TGpNNUxTNDVOeUF4TUM0eE1TNDBNeUF4TXk0MUxUSWdNeTR6T1NBeUxqUXpJREV3TGpFeElERXVNRE1nTVRNdU5TQXlJREFnTUNBeExqWTFMalUwSURNZ01pMHVOamd1T1RjdE1TNDJOUzQ1T1MweklDNDFMVE11TXprdExqazNMVEV3TGpFeExqUTJMVEV6TGpVdE1TMHpMak01SURFdU5EWXRNVEF1TVRFdU1ETXRNVE11TlNBeExURXVNelUwTGpRNUxUSXVNekl6TGpRM0xUTXRMalVnTVM0ek5UUXRNUzQ1TkNBekxUSWdNeTB5ZWlJdlBqeHdZWFJvSUdROUlrMHhOU0F6TW1NeUxqVWdNaTQxSURFeUxqVWdNaTQxSURFMUlEQWdMalV0TVM0MUlEQXRNaUF3TFRJZ01DMHlMalV0TWk0MUxUUXRNaTQxTFRRZ05TNDFMVEV1TlNBMkxURXhMalV0TlMweE5TNDFMVEV4SURRdE1UQXVOU0F4TkMwMUlERTFMalVnTUNBd0xUSXVOU0F4TGpVdE1pNDFJRFFnTUNBd0xTNDFMalVnTUNBeWVpSXZQanh3WVhSb0lHUTlJazB5TlNBNFlUSXVOU0F5TGpVZ01DQXhJREV0TlNBd0lESXVOU0F5TGpVZ01DQXhJREVnTlNBd2VpSXZQand2Wno0OGNHRjBhQ0JrUFNKTk1UY3VOU0F5Tm1neE1FMHhOU0F6TUdneE5XMHROeTQxTFRFMExqVjJOVTB5TUNBeE9HZzFJaUJ6ZEhKdmEyVTlJaU5sWTJWalpXTWlJSE4wY205clpTMXNhVzVsYW05cGJqMGliV2wwWlhJaUx6NDhMMmMrUEM5emRtYysnKTtcbn1cbi5jZy13cmFwIHBpZWNlLmtuaWdodC5ibGFjayB7XG4gIGJhY2tncm91bmQtaW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0kwTlNJZ2FHVnBaMmgwUFNJME5TSStQR2NnWm1sc2JEMGlibTl1WlNJZ1ptbHNiQzF5ZFd4bFBTSmxkbVZ1YjJSa0lpQnpkSEp2YTJVOUlpTXdNREFpSUhOMGNtOXJaUzEzYVdSMGFEMGlNUzQxSWlCemRISnZhMlV0YkdsdVpXTmhjRDBpY205MWJtUWlJSE4wY205clpTMXNhVzVsYW05cGJqMGljbTkxYm1RaVBqeHdZWFJvSUdROUlrMHlNaUF4TUdNeE1DNDFJREVnTVRZdU5TQTRJREUySURJNVNERTFZekF0T1NBeE1DMDJMalVnT0MweU1TSWdabWxzYkQwaUl6QXdNQ0l2UGp4d1lYUm9JR1E5SWsweU5DQXhPR011TXpnZ01pNDVNUzAxTGpVMUlEY3VNemN0T0NBNUxUTWdNaTB5TGpneUlEUXVNelF0TlNBMExURXVNRFF5TFM0NU5DQXhMalF4TFRNdU1EUWdNQzB6TFRFZ01DQXVNVGtnTVM0eU15MHhJREl0TVNBd0xUUXVNREF6SURFdE5DMDBJREF0TWlBMkxURXlJRFl0TVRKek1TNDRPUzB4TGprZ01pMHpMalZqTFM0M015MHVPVGswTFM0MUxUSXRMalV0TXlBeExURWdNeUF5TGpVZ015QXlMalZvTW5NdU56Z3RNUzQ1T1RJZ01pNDFMVE5qTVNBd0lERWdNeUF4SURNaUlHWnBiR3c5SWlNd01EQWlMejQ4Y0dGMGFDQmtQU0pOT1M0MUlESTFMalZoTGpVdU5TQXdJREVnTVMweElEQWdMalV1TlNBd0lERWdNU0F4SURCNmJUVXVORE16TFRrdU56VmhMalVnTVM0MUlETXdJREVnTVMwdU9EWTJMUzQxTGpVZ01TNDFJRE13SURFZ01TQXVPRFkyTGpWNklpQm1hV3hzUFNJalpXTmxZMlZqSWlCemRISnZhMlU5SWlObFkyVmpaV01pTHo0OGNHRjBhQ0JrUFNKTk1qUXVOVFVnTVRBdU5Hd3RMalExSURFdU5EVXVOUzR4TldNekxqRTFJREVnTlM0Mk5TQXlMalE1SURjdU9TQTJMamMxVXpNMUxqYzFJREk1TGpBMklETTFMakkxSURNNWJDMHVNRFV1TldneUxqSTFiQzR3TlMwdU5XTXVOUzB4TUM0d05pMHVPRGd0TVRZdU9EVXRNeTR5TlMweU1TNHpOQzB5TGpNM0xUUXVORGt0TlM0M09TMDJMalkwTFRrdU1Ua3ROeTR4Tm13dExqVXhMUzR4ZWlJZ1ptbHNiRDBpSTJWalpXTmxZeUlnYzNSeWIydGxQU0p1YjI1bElpOCtQQzluUGp3dmMzWm5QZz09Jyk7XG59XG4uY2ctd3JhcCBwaWVjZS5yb29rLmJsYWNrIHtcbiAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGRwWkhSb1BTSTBOU0lnYUdWcFoyaDBQU0kwTlNJK1BHY2dabWxzYkMxeWRXeGxQU0psZG1WdWIyUmtJaUJ6ZEhKdmEyVTlJaU13TURBaUlITjBjbTlyWlMxM2FXUjBhRDBpTVM0MUlpQnpkSEp2YTJVdGJHbHVaV05oY0QwaWNtOTFibVFpSUhOMGNtOXJaUzFzYVc1bGFtOXBiajBpY205MWJtUWlQanh3WVhSb0lHUTlJazA1SURNNWFESTNkaTB6U0RsMk0zcHRNeTQxTFRkc01TNDFMVEl1TldneE4yd3hMalVnTWk0MWFDMHlNSHB0TFM0MUlEUjJMVFJvTWpGMk5FZ3hNbm9pSUhOMGNtOXJaUzFzYVc1bFkyRndQU0ppZFhSMElpOCtQSEJoZEdnZ1pEMGlUVEUwSURJNUxqVjJMVEV6YURFM2RqRXpTREUwZWlJZ2MzUnliMnRsTFd4cGJtVmpZWEE5SW1KMWRIUWlJSE4wY205clpTMXNhVzVsYW05cGJqMGliV2wwWlhJaUx6NDhjR0YwYUNCa1BTSk5NVFFnTVRZdU5Vd3hNU0F4TkdneU0yd3RNeUF5TGpWSU1UUjZUVEV4SURFMFZqbG9OSFl5YURWV09XZzFkakpvTlZZNWFEUjJOVWd4TVhvaUlITjBjbTlyWlMxc2FXNWxZMkZ3UFNKaWRYUjBJaTgrUEhCaGRHZ2daRDBpVFRFeUlETTFMalZvTWpGdExUSXdMVFJvTVRsdExURTRMVEpvTVRkdExURTNMVEV6YURFM1RURXhJREUwYURJeklpQm1hV3hzUFNKdWIyNWxJaUJ6ZEhKdmEyVTlJaU5sWTJWalpXTWlJSE4wY205clpTMTNhV1IwYUQwaU1TSWdjM1J5YjJ0bExXeHBibVZxYjJsdVBTSnRhWFJsY2lJdlBqd3ZaejQ4TDNOMlp6ND0nKTtcbn1cbi5jZy13cmFwIHBpZWNlLnF1ZWVuLmJsYWNrIHtcbiAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGRwWkhSb1BTSTBOU0lnYUdWcFoyaDBQU0kwTlNJK1BHY2dabWxzYkMxeWRXeGxQU0psZG1WdWIyUmtJaUJ6ZEhKdmEyVTlJaU13TURBaUlITjBjbTlyWlMxM2FXUjBhRDBpTVM0MUlpQnpkSEp2YTJVdGJHbHVaV05oY0QwaWNtOTFibVFpSUhOMGNtOXJaUzFzYVc1bGFtOXBiajBpY205MWJtUWlQanhuSUhOMGNtOXJaVDBpYm05dVpTSStQR05wY21Oc1pTQmplRDBpTmlJZ1kzazlJakV5SWlCeVBTSXlMamMxSWk4K1BHTnBjbU5zWlNCamVEMGlNVFFpSUdONVBTSTVJaUJ5UFNJeUxqYzFJaTgrUEdOcGNtTnNaU0JqZUQwaU1qSXVOU0lnWTNrOUlqZ2lJSEk5SWpJdU56VWlMejQ4WTJseVkyeGxJR040UFNJek1TSWdZM2s5SWpraUlISTlJakl1TnpVaUx6NDhZMmx5WTJ4bElHTjRQU0l6T1NJZ1kzazlJakV5SWlCeVBTSXlMamMxSWk4K1BDOW5Qanh3WVhSb0lHUTlJazA1SURJMll6Z3VOUzB4TGpVZ01qRXRNUzQxSURJM0lEQnNNaTQxTFRFeUxqVk1NekVnTWpWc0xTNHpMVEUwTGpFdE5TNHlJREV6TGpZdE15MHhOQzQxTFRNZ01UUXVOUzAxTGpJdE1UTXVOa3d4TkNBeU5TQTJMalVnTVRNdU5TQTVJREkyZWlJZ2MzUnliMnRsTFd4cGJtVmpZWEE5SW1KMWRIUWlMejQ4Y0dGMGFDQmtQU0pOT1NBeU5tTXdJRElnTVM0MUlESWdNaTQxSURRZ01TQXhMalVnTVNBeElDNDFJRE11TlMweExqVWdNUzB4TGpVZ01pNDFMVEV1TlNBeUxqVXRNUzQxSURFdU5TNDFJREl1TlM0MUlESXVOU0EyTGpVZ01TQXhOaTQxSURFZ01qTWdNQ0F3SURBZ01TNDFMVEVnTUMweUxqVWdNQ0F3SUM0MUxURXVOUzB4TFRJdU5TMHVOUzB5TGpVdExqVXRNaUF1TlMwekxqVWdNUzB5SURJdU5TMHlJREl1TlMwMExUZ3VOUzB4TGpVdE1UZ3VOUzB4TGpVdE1qY2dNSG9pSUhOMGNtOXJaUzFzYVc1bFkyRndQU0ppZFhSMElpOCtQSEJoZEdnZ1pEMGlUVEV4SURNNExqVmhNelVnTXpVZ01TQXdJREFnTWpNZ01DSWdabWxzYkQwaWJtOXVaU0lnYzNSeWIydGxMV3hwYm1WallYQTlJbUoxZEhRaUx6NDhjR0YwYUNCa1BTSk5NVEVnTWpsaE16VWdNelVnTVNBd0lERWdNak1nTUcwdE1qRXVOU0F5TGpWb01qQnRMVEl4SUROaE16VWdNelVnTVNBd0lEQWdNaklnTUcwdE1qTWdNMkV6TlNBek5TQXhJREFnTUNBeU5DQXdJaUJtYVd4c1BTSnViMjVsSWlCemRISnZhMlU5SWlObFkyVmpaV01pTHo0OEwyYytQQzl6ZG1jKycpO1xufVxuLmNnLXdyYXAgcGllY2Uua2luZy5ibGFjayB7XG4gIGJhY2tncm91bmQtaW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0kwTlNJZ2FHVnBaMmgwUFNJME5TSStQR2NnWm1sc2JEMGlibTl1WlNJZ1ptbHNiQzF5ZFd4bFBTSmxkbVZ1YjJSa0lpQnpkSEp2YTJVOUlpTXdNREFpSUhOMGNtOXJaUzEzYVdSMGFEMGlNUzQxSWlCemRISnZhMlV0YkdsdVpXTmhjRDBpY205MWJtUWlJSE4wY205clpTMXNhVzVsYW05cGJqMGljbTkxYm1RaVBqeHdZWFJvSUdROUlrMHlNaTQxSURFeExqWXpWallpSUhOMGNtOXJaUzFzYVc1bGFtOXBiajBpYldsMFpYSWlMejQ4Y0dGMGFDQmtQU0pOTWpJdU5TQXlOWE0wTGpVdE55NDFJRE10TVRBdU5XTXdJREF0TVMweUxqVXRNeTB5TGpWekxUTWdNaTQxTFRNZ01pNDFZeTB4TGpVZ015QXpJREV3TGpVZ015QXhNQzQxSWlCbWFXeHNQU0lqTURBd0lpQnpkSEp2YTJVdGJHbHVaV05oY0QwaVluVjBkQ0lnYzNSeWIydGxMV3hwYm1WcWIybHVQU0p0YVhSbGNpSXZQanh3WVhSb0lHUTlJazB4TVM0MUlETTNZelV1TlNBekxqVWdNVFV1TlNBekxqVWdNakVnTUhZdE4zTTVMVFF1TlNBMkxURXdMalZqTFRRdE5pNDFMVEV6TGpVdE15NDFMVEUySURSV01qZDJMVE11TldNdE15NDFMVGN1TlMweE15MHhNQzQxTFRFMkxUUXRNeUEySURVZ01UQWdOU0F4TUZZek4zb2lJR1pwYkd3OUlpTXdNREFpTHo0OGNHRjBhQ0JrUFNKTk1qQWdPR2cxSWlCemRISnZhMlV0YkdsdVpXcHZhVzQ5SW0xcGRHVnlJaTgrUEhCaGRHZ2daRDBpVFRNeUlESTVMalZ6T0M0MUxUUWdOaTR3TXkwNUxqWTFRek0wTGpFMUlERTBJREkxSURFNElESXlMalVnTWpRdU5Xd3VNREVnTWk0eExTNHdNUzB5TGpGRE1qQWdNVGdnT1M0NU1EWWdNVFFnTmk0NU9UY2dNVGt1T0RWakxUSXVORGszSURVdU5qVWdOQzQ0TlRNZ09TQTBMamcxTXlBNUlpQnpkSEp2YTJVOUlpTmxZMlZqWldNaUx6NDhjR0YwYUNCa1BTSk5NVEV1TlNBek1HTTFMalV0TXlBeE5TNDFMVE1nTWpFZ01HMHRNakVnTXk0MVl6VXVOUzB6SURFMUxqVXRNeUF5TVNBd2JTMHlNU0F6TGpWak5TNDFMVE1nTVRVdU5TMHpJREl4SURBaUlITjBjbTlyWlQwaUkyVmpaV05sWXlJdlBqd3ZaejQ4TDNOMlp6ND0nKTtcbn1cbiIsICIvKlxuICBKb3NoJ3MgQ3VzdG9tIENTUyBSZXNldFxuICBodHRwczovL3d3dy5qb3Nod2NvbWVhdS5jb20vY3NzL2N1c3RvbS1jc3MtcmVzZXQvXG4qL1xuKixcbio6OmJlZm9yZSxcbio6OmFmdGVyIHtcblx0Ym94LXNpemluZzogYm9yZGVyLWJveDtcbn1cbioge1xuXHRtYXJnaW46IDA7XG59XG5odG1sLFxuYm9keSB7XG5cdGhlaWdodDogMTAwJTtcbn1cbmJvZHkge1xuXHRsaW5lLWhlaWdodDogMS41O1xuXHQtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDtcbn1cbmltZyxcbnBpY3R1cmUsXG52aWRlbyxcbmNhbnZhcyxcbnN2ZyB7XG5cdGRpc3BsYXk6IGJsb2NrO1xuXHRtYXgtd2lkdGg6IDEwMCU7XG59XG5pbnB1dCxcbmJ1dHRvbixcbnRleHRhcmVhLFxuc2VsZWN0IHtcblx0Zm9udDogaW5oZXJpdDtcbn1cbnAsXG5oMSxcbmgyLFxuaDMsXG5oNCxcbmg1LFxuaDYge1xuXHRvdmVyZmxvdy13cmFwOiBicmVhay13b3JkO1xufVxuI3Jvb3QsXG4jX19uZXh0IHtcblx0aXNvbGF0aW9uOiBpc29sYXRlO1xufVxuIiwgImJ1dHRvbjphY3RpdmUge1xuXHR0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoMXB4KTtcbn1cblxuLmJvcmRlciB7XG5cdGJvcmRlcjogMXB4IHZhcigtLWNvbG9yLWJhc2UtMTApIHNvbGlkO1xuXHRib3JkZXItcmFkaXVzOiA1cHg7XG59XG5cbi5ib3JkZXItdG9wIHtcblx0Ym9yZGVyOiAxcHggdmFyKC0tY29sb3ItYmFzZS0xMCkgc29saWQ7XG59XG5cbi52ZXJ0aWNhbC1hbGlnbiB7XG5cdGRpc3BsYXk6IGZsZXg7XG5cdGFsaWduLWl0ZW1zOiBjZW50ZXI7XG59XG5cbi5jZW50ZXIge1xuXHRkaXNwbGF5OiBmbGV4O1xuXHRhbGlnbi1pdGVtczogY2VudGVyO1xuXHRqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbn1cblxuLm1vdmUtaXRlbSB7XG5cdHBhZGRpbmctbGVmdDogOHB4O1xuXHR1c2VyLXNlbGVjdDogbm9uZTtcbn1cblxuLm1vdmUtaXRlbTpob3ZlciB7XG5cdGJhY2tncm91bmQtY29sb3I6IGhzbChcblx0XHR2YXIoLS1hY2NlbnQtaCksXG5cdFx0dmFyKC0tYWNjZW50LXMpLFxuXHRcdGNhbGModmFyKC0tYWNjZW50LWwpKVxuXHQpO1xuXHRjb2xvcjogdmFyKC0tdGV4dC1vbi1hY2NlbnQpO1xuXHRjdXJzb3I6IHBvaW50ZXI7XG59XG5cbi5tb3ZlLWl0ZW0uYWN0aXZlIHtcblx0YmFja2dyb3VuZC1jb2xvcjogaHNsKFxuXHRcdHZhcigtLWFjY2VudC1oKSxcblx0XHR2YXIoLS1hY2NlbnQtcyksXG5cdFx0Y2FsYyh2YXIoLS1hY2NlbnQtbCkgLSAxMCUpXG5cdCk7XG5cdGNvbG9yOiB2YXIoLS10ZXh0LW9uLWFjY2VudCk7XG5cdGZvbnQtd2VpZ2h0OiBib2xkO1xufVxuXG4ubW92ZS1pbmRpY2F0b3Ige1xuXHRjb2xvcjogdmFyKC0tY29sb3ItYmFzZS02MCk7XG5cdHRleHQtYWxpZ246IGNlbnRlcjtcblx0YmFja2dyb3VuZC1jb2xvcjogdmFyKC0tY29sb3ItYmFzZS0xMCk7XG5cdHVzZXItc2VsZWN0OiBub25lO1xuXHRjdXJzb3I6IGRlZmF1bHQ7XG59XG5cbi5lZGl0b3ItaW5wdXQge1xuXHRtaW4taGVpZ2h0OiAxNTBweDtcblx0cmVzaXplOiBub25lO1xuXHRmb250LXNpemU6IDE1cHg7XG5cdGNhcmV0LWNvbG9yOiByZ2IoNSwgNSwgNSk7XG5cdHBvc2l0aW9uOiByZWxhdGl2ZTtcblx0dGFiLXNpemU6IDE7XG5cdG91dGxpbmU6IDA7XG5cdHBhZGRpbmc6IDE1cHggMTBweDtcblx0Y2FyZXQtY29sb3I6ICM0NDQ7XG59XG5cbi5Db21tZW50U2VjdGlvbiB7XG5cdGhlaWdodDogMjUwcHg7XG5cdHBhZGRpbmctdG9wOiA1cHg7XG5cdG92ZXJmbG93OiBzY3JvbGw7XG59XG5cbi5Qcm9zZU1pcnJvcixcbi5Db21tZW50U2VjdGlvbiA+IGRpdiB7XG5cdHdpZHRoOiAxMDAlO1xuXHRoZWlnaHQ6IDEwMCU7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQUE7QUFDQztBQUFBOzs7QUNERDtBQUNFO0FBQ0E7QUFDQTtBQUFBO0FBR0Y7QUFDRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFHRjtBQUNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUdGO0FBQ0U7QUFBQTtBQUdGO0FBQ0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFHRjtBQUNFO0FBQUE7QUFHRjtBQUNFO0FBQUE7QUFHRjtBQUNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBR0Y7QUFDRTtBQUVBO0FBQUE7QUFHRjtBQUNFO0FBQUE7QUFHRjtBQUNFO0FBQ0E7QUFBQTtBQUdGO0FBQ0U7QUFBQTtBQUdGO0FBQ0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFHRjtBQUFBO0FBQUE7QUFHRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBR0Y7QUFDRTtBQUFBO0FBR0Y7QUFDRTtBQUFBO0FBR0Y7QUFDRTtBQUNBO0FBQ0E7QUFBQTtBQUdGO0FBRUU7QUFBQTtBQUdGO0FBQ0U7QUFBQTtBQUdGO0FBQ0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFHRjtBQUNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUdGO0FBQ0U7QUFBQTtBQUdGO0FBQ0U7QUFDQTtBQUFBO0FBR0Y7QUFDRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBR0Y7QUFDRTtBQUFBO0FBR0Y7QUFDRTtBQUFBO0FBR0Y7QUFDRTtBQUFBOzs7QUMzS0Y7QUFDRTtBQUNBO0FBQUE7QUFJRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFRRjtBQUNFO0FBQUE7QUFJRjtBQUFBO0FBQUE7QUFBQTtBQUlFO0FBQUE7QUFHRjtBQUFBO0FBQUE7QUFBQTtBQUlFO0FBQUE7OztBQ3ZERjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7QUFFRjtBQUNFO0FBQUE7OztBQy9CRjtBQUFBO0FBQUE7QUFHQztBQUFBO0FBRUQ7QUFDQztBQUFBO0FBRUQ7QUFBQTtBQUVDO0FBQUE7QUFFRDtBQUNDO0FBQ0E7QUFBQTtBQUVEO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFLQztBQUNBO0FBQUE7QUFFRDtBQUFBO0FBQUE7QUFBQTtBQUlDO0FBQUE7QUFFRDtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQU9DO0FBQUE7QUFFRDtBQUFBO0FBRUM7QUFBQTs7O0FDN0NEO0FBQ0M7QUFBQTtBQUdEO0FBQ0M7QUFDQTtBQUFBO0FBR0Q7QUFDQztBQUFBO0FBR0Q7QUFDQztBQUNBO0FBQUE7QUFHRDtBQUNDO0FBQ0E7QUFDQTtBQUFBO0FBR0Q7QUFDQztBQUNBO0FBQUE7QUFHRDtBQUNDO0FBS0E7QUFDQTtBQUFBO0FBR0Q7QUFDQztBQUtBO0FBQ0E7QUFBQTtBQUdEO0FBQ0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBR0Q7QUFDQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUdEO0FBQ0M7QUFDQTtBQUNBO0FBQUE7QUFHRDtBQUFBO0FBRUM7QUFDQTtBQUFBOyIsCiAgIm5hbWVzIjogW10KfQo= */ +*, +*::before, +*::after { + box-sizing: border-box; +} +* { + margin: 0; +} +html, +body { + height: 100%; +} +body { + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} +input, +button, +textarea, +select { + font: inherit; +} +p, +h1, +h2, +h3, +h4, +h5, +h6 { + overflow-wrap: break-word; +} +#root, +#__next { + isolation: isolate; +} diff --git a/version-bump.mjs b/version-bump.mjs index d409fa0..3f6c905 100644 --- a/version-bump.mjs +++ b/version-bump.mjs @@ -1,14 +1,14 @@ -import { readFileSync, writeFileSync } from "fs"; +import { readFileSync, writeFileSync } from 'fs'; const targetVersion = process.env.npm_package_version; // read minAppVersion from manifest.json and bump version to target version -let manifest = JSON.parse(readFileSync("manifest.json", "utf8")); +let manifest = JSON.parse(readFileSync('manifest.json', 'utf8')); const { minAppVersion } = manifest; manifest.version = targetVersion; -writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t")); +writeFileSync('manifest.json', JSON.stringify(manifest, null, '\t')); // update versions.json with target version and minAppVersion from manifest.json -let versions = JSON.parse(readFileSync("versions.json", "utf8")); +let versions = JSON.parse(readFileSync('versions.json', 'utf8')); versions[targetVersion] = minAppVersion; -writeFileSync("versions.json", JSON.stringify(versions, null, "\t")); +writeFileSync('versions.json', JSON.stringify(versions, null, '\t'));