~starkingdoms/starkingdoms

ea219ec91d4a7c415c267b1a33a2f4e74e5ab010 — ghostlyzsh 1 year, 4 months ago 46218c0
equality, comparison, unary added
M kabel/grammar.ebnf => kabel/grammar.ebnf +4 -2
@@ 18,14 18,16 @@ logical_or = logical_and { , "||" , logical_and } ;

logical_and = equality { , "&&" , equality } ;

(* implemented *)
equality = comparison { , ( "==" | "!=" ) , comparison } ;

comparison = term { , ( ">" | "<" | ">=" | "<=" ) , term } ;

(* implemented *)
term = factor { , ( "+" | "-" ) , factor } ;

factor = primary { , ( "*" | "/" ) , primary } ;
factor = unary { , ( "*" | "/" ) , unary } ;

unary = ( ( "!" | "-" ) , unary ) | primary ;

primary = identifier | number | string | group ;


M kabel/src/error.rs => kabel/src/error.rs +11 -8
@@ 8,8 8,7 @@ pub struct KabelError {
}

impl KabelError {
    pub fn new(kind: ErrorKind, message: String, line: usize,
                column: usize, code: String) -> Self {
    pub fn new(kind: ErrorKind, message: String, line: usize, column: usize, code: String) -> Self {
        Self {
            kind,
            message,


@@ 22,19 21,23 @@ impl KabelError {

impl std::fmt::Display for KabelError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let caret_space: String = vec![' '; self.column-1].iter().collect();
        f.write_str(&
            format!("Error {:0>4}: {1} at line {2}, column {3}\n\
        let caret_space: String = vec![' '; self.column - 1].iter().collect();
        f.write_str(&format!(
            "Error {:0>4}: {1} at line {2}, column {3}\n\
                    {4}\n\
                    {5}^",
                    self.kind.clone() as usize, self.message, self.line+1, self.column,
                    self.code, caret_space))
            self.kind.clone() as usize,
            self.message,
            self.line + 1,
            self.column,
            self.code,
            caret_space
        ))
    }
}

impl std::error::Error for KabelError {}


#[derive(Debug, Clone)]
pub enum ErrorKind {
    UnexpectedEof,

M kabel/src/lexer.rs => kabel/src/lexer.rs +108 -20
@@ 1,6 1,9 @@
use std::str::from_utf8;

use crate::{error::{ErrorKind, KabelError}, token};
use crate::{
    error::{ErrorKind, KabelError},
    token,
};

pub struct Lexer {
    input: Vec<u8>,


@@ 32,19 35,83 @@ impl Lexer {
    pub fn next_token(&mut self) -> bool {
        self.read_char();
        match self.c {
            b'+' => { self.output.push(token!(self, TokenType::Plus)); self.start = self.current; },
            b'-' => { self.output.push(token!(self, TokenType::Minus)); self.start = self.current; },
            b'*' => { self.output.push(token!(self, TokenType::Star)); self.start = self.current; },
            b'/' => { self.output.push(token!(self, TokenType::Slash)); self.start = self.current; },
            b'(' => { self.output.push(token!(self, TokenType::LeftParen)); self.start = self.current; },
            b')' => { self.output.push(token!(self, TokenType::RightParen)); self.start = self.current; },
            b'+' => {
                self.output.push(token!(self, TokenType::Plus));
                self.start = self.current;
            }
            b'-' => {
                self.output.push(token!(self, TokenType::Minus));
                self.start = self.current;
            }
            b'*' => {
                self.output.push(token!(self, TokenType::Star));
                self.start = self.current;
            }
            b'/' => {
                self.output.push(token!(self, TokenType::Slash));
                self.start = self.current;
            }
            b'(' => {
                self.output.push(token!(self, TokenType::LeftParen));
                self.start = self.current;
            }
            b')' => {
                self.output.push(token!(self, TokenType::RightParen));
                self.start = self.current;
            }
            b'=' => {
                if self.peek() == b'=' {
                    self.read_char();
                    self.output.push(token!(self, TokenType::EqualEqual));
                    self.start = self.current;
                } else {
                    self.output.push(token!(self, TokenType::Equal));
                    self.start = self.current;
                }
            }
            b'!' => {
                if self.peek() == b'=' {
                    self.read_char();
                    self.output.push(token!(self, TokenType::BangEqual));
                    self.start = self.current;
                } else {
                    self.output.push(token!(self, TokenType::Bang));
                    self.start = self.current;
                }
            }
            b'>' => {
                if self.peek() == b'=' {
                    self.read_char();
                    self.output.push(token!(self, TokenType::GreaterEqual));
                    self.start = self.current;
                } else {
                    self.output.push(token!(self, TokenType::Greater));
                    self.start = self.current;
                }
            }
            b'<' => {
                if self.peek() == b'=' {
                    self.read_char();
                    self.output.push(token!(self, TokenType::LessEqual));
                    self.start = self.current;
                } else {
                    self.output.push(token!(self, TokenType::Less));
                    self.start = self.current;
                }
            }
            b'"' => {
                let mut contents = String::new();
                while self.read_char() != b'"' {
                    if self.c == 0x05 {
                        self.errors.push(KabelError::new(ErrorKind::UnexpectedEof,
                                "File ended before closing quote".to_string(),
                                self.line, self.column, from_utf8(&self.input[self.start..self.current]).unwrap().to_string()));
                        self.errors.push(KabelError::new(
                            ErrorKind::UnexpectedEof,
                            "File ended before closing quote".to_string(),
                            self.line,
                            self.column,
                            from_utf8(&self.input[self.start..self.current])
                                .unwrap()
                                .to_string(),
                        ));
                        return false;
                    }
                    contents.push(self.c as char);


@@ 57,7 124,9 @@ impl Lexer {
                self.line_start = self.current;
                self.column = 0;
            }
            b' ' | b'\r' | b'\t' => { self.start = self.current; }
            b' ' | b'\r' | b'\t' => {
                self.start = self.current;
            }
            0x05 => return false,
            c => {
                if c.is_ascii_alphabetic() {


@@ 79,16 148,20 @@ impl Lexer {
                            number.push(self.c as char);
                        }
                    }
                    /*self.current -= 1;
                    self.column -= 1;*/
                    // panic = error in this code
                    self.output.push(token!(self, TokenType::Num(number.parse().unwrap())));
                    self.output
                        .push(token!(self, TokenType::Num(number.parse().unwrap())));
                    self.start = self.current;
                } else {
                    self.errors.push(KabelError::new(ErrorKind::UnexpectedToken,
                            format!("Stray \"{0}\"", c as char),
                            self.line, self.column,
                            from_utf8(&self.input[self.line_start..self.current]).unwrap().to_string()));
                    self.errors.push(KabelError::new(
                        ErrorKind::UnexpectedToken,
                        format!("Stray \"{0}\"", c as char),
                        self.line,
                        self.column,
                        from_utf8(&self.input[self.line_start..self.current])
                            .unwrap()
                            .to_string(),
                    ));
                }
            }
        }


@@ 127,7 200,22 @@ pub struct Token {

#[derive(Debug, Clone, PartialEq)]
pub enum TokenType {
    Star, Slash, Plus, Minus, LeftParen, RightParen,
    Star,
    Slash,
    Plus,
    Minus,
    LeftParen,
    RightParen,
    Equal,
    EqualEqual,
    Bang,
    BangEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,

    Ident(String), Str(String), Num(f32),
    Ident(String),
    Str(String),
    Num(f32),
}

M kabel/src/lib.rs => kabel/src/lib.rs +3 -3
@@ 1,10 1,10 @@
use lexer::{Lexer, Token};
use parser::{Parser, AST};

pub mod error;
pub mod lexer;
pub mod parser;
pub mod macros;
pub mod error;
pub mod parser;

pub fn run_lexer(input: String) -> Lexer {
    let mut lexer = Lexer::new(input);


@@ 12,7 12,7 @@ pub fn run_lexer(input: String) -> Lexer {
    lexer
}

pub fn run_parser(text:String, input: Vec<Token>) -> (AST, Parser) {
pub fn run_parser(text: String, input: Vec<Token>) -> (AST, Parser) {
    let mut parser = Parser::new(text, input);
    (parser.program(), parser)
}

M kabel/src/parser.rs => kabel/src/parser.rs +219 -36
@@ 1,4 1,7 @@
use crate::{error::{ErrorKind, KabelError}, lexer::{Token, TokenType}};
use crate::{
    error::{ErrorKind, KabelError},
    lexer::{Token, TokenType},
};

pub struct Parser {
    input: Vec<Token>,


@@ 31,7 34,6 @@ impl Parser {
                Ok(ast) => program.push(ast),
                Err(e) => self.errors.push(e),
            }
            break;
        }
        AST {
            ast_type: ASTType::Program(program),


@@ 43,21 45,131 @@ impl Parser {
    }

    pub fn expression(&mut self) -> Result<AST, KabelError> {
        let term = self.term()?;
        Ok(term)
        let equality = self.equality()?;
        Ok(equality)
    }

    pub fn equality(&mut self) -> Result<AST, KabelError> {
        let mut left = self.comparison()?;

        while self.current < self.input.len()
            && (self.peek()?.token_type == TokenType::EqualEqual
                || self.peek()?.token_type == TokenType::BangEqual)
        {
            let binop = self.read_token()?;
            let right = self.comparison()?;
            if binop.token_type == TokenType::EqualEqual {
                left = AST {
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Eq,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,
                    column: left.column,
                };
            } else {
                left = AST {
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Ne,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,
                    column: left.column,
                };
            }
        }

        Ok(left)
    }

    pub fn comparison(&mut self) -> Result<AST, KabelError> {
        let mut left = self.term()?;

        while self.current < self.input.len()
            && (self.peek()?.token_type == TokenType::Less
                || self.peek()?.token_type == TokenType::LessEqual
                || self.peek()?.token_type == TokenType::Greater
                || self.peek()?.token_type == TokenType::GreaterEqual)
        {
            let binop = self.read_token()?;
            let right = self.term()?;
            if binop.token_type == TokenType::Less {
                left = AST {
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Ls,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,
                    column: left.column,
                };
            } else if binop.token_type == TokenType::LessEqual {
                left = AST {
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Le,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,
                    column: left.column,
                };
            } else if binop.token_type == TokenType::Greater {
                left = AST {
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Gr,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,
                    column: left.column,
                };
            } else {
                left = AST {
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Ge,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,
                    column: left.column,
                };
            }
        }

        Ok(left)
    }

    pub fn term(&mut self) -> Result<AST, KabelError> {
        let mut left = self.factor()?;

        while self.current < self.input.len() &&
            (self.peek()?.token_type == TokenType::Plus || self.peek()?.token_type == TokenType::Minus) {
        while self.current < self.input.len()
            && (self.peek()?.token_type == TokenType::Plus
                || self.peek()?.token_type == TokenType::Minus)
        {
            let binop = self.read_token()?;
            let right = self.factor()?;

            if binop.token_type == TokenType::Plus {
                left = AST {
                    ast_type: ASTType::Binary(Box::new(left.clone()), BinOp::Add, Box::new(right.clone())),
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Add,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,


@@ 65,7 177,11 @@ impl Parser {
                };
            } else {
                left = AST {
                    ast_type: ASTType::Binary(Box::new(left.clone()), BinOp::Sub, Box::new(right.clone())),
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Sub,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,


@@ 76,16 192,22 @@ impl Parser {
        Ok(left)
    }
    pub fn factor(&mut self) -> Result<AST, KabelError> {
        let mut left = self.primary()?;
        let mut left = self.unary()?;

        while self.current < self.input.len() &&
            (self.peek()?.token_type == TokenType::Star || self.peek()?.token_type == TokenType::Slash) {
        while self.current < self.input.len()
            && (self.peek()?.token_type == TokenType::Star
                || self.peek()?.token_type == TokenType::Slash)
        {
            let binop = self.read_token()?;
            let right = self.primary()?;
            let right = self.unary()?;

            if binop.token_type == TokenType::Star {
                left = AST {
                    ast_type: ASTType::Binary(Box::new(left.clone()), BinOp::Mul, Box::new(right.clone())),
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Mul,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,


@@ 93,7 215,11 @@ impl Parser {
                };
            } else {
                left = AST {
                    ast_type: ASTType::Binary(Box::new(left.clone()), BinOp::Div, Box::new(right.clone())),
                    ast_type: ASTType::Binary(
                        Box::new(left.clone()),
                        BinOp::Div,
                        Box::new(right.clone()),
                    ),
                    start: left.start,
                    end: right.end,
                    line: left.line,


@@ 103,6 229,31 @@ impl Parser {
        }
        Ok(left)
    }
    pub fn unary(&mut self) -> Result<AST, KabelError> {
        if let TokenType::Bang | TokenType::Minus = self.peek()?.token_type {
            let token = self.read_token()?;
            let unary = self.unary()?;
            if token.token_type == TokenType::Bang {
                return Ok(AST {
                    ast_type: ASTType::Unary(UnOp::Not, Box::new(unary.clone())),
                    start: token.start,
                    end: unary.end,
                    line: token.line,
                    column: token.column,
                });
            } else {
                return Ok(AST {
                    ast_type: ASTType::Unary(UnOp::Neg, Box::new(unary.clone())),
                    start: token.start,
                    end: unary.end,
                    line: token.line,
                    column: token.column,
                });
            }
        }

        Ok(self.primary()?)
    }
    pub fn primary(&mut self) -> Result<AST, KabelError> {
        let token = self.read_token()?;



@@ 138,11 289,17 @@ impl Parser {
                return Ok(self.group(token)?);
            }
            _ => {
                return Err(KabelError::new(ErrorKind::UnexpectedToken,
                        format!("Unexpected token {}", self.text[token.start..token.end].to_string()),
                        token.line, token.column,
                        self.text[token.line_start..token.end].to_string()));
            },
                return Err(KabelError::new(
                    ErrorKind::UnexpectedToken,
                    format!(
                        "Unexpected token {}",
                        self.text[token.start..token.end].to_string()
                    ),
                    token.line,
                    token.column,
                    self.text[token.line_start..token.end].to_string(),
                ));
            }
        }
    }
    pub fn group(&mut self, left_paren: Token) -> Result<AST, KabelError> {


@@ 150,10 307,13 @@ impl Parser {
        let right_paren = self.peek();
        if let Ok(right_paren) = right_paren {
            if right_paren.token_type != TokenType::RightParen {
                return Err(KabelError::new(ErrorKind::MissingDelimiter,
                        "Missing right parenthesis".to_string(),
                        right_paren.line, right_paren.column,
                        self.text[left_paren.start..right_paren.end].to_string()));
                return Err(KabelError::new(
                    ErrorKind::MissingDelimiter,
                    "Missing right parenthesis".to_string(),
                    right_paren.line,
                    right_paren.column,
                    self.text[left_paren.start..right_paren.end].to_string(),
                ));
            }
            self.read_token()?;
            return Ok(AST {


@@ 165,21 325,27 @@ impl Parser {
            });
        }
        if let Err(e) = right_paren {
            return Err(KabelError::new(ErrorKind::MissingDelimiter,
                    "Missing right parenthesis".to_string(),
                    e.line, e.column,
                    self.text[left_paren.line_start..expr.end].to_string()));
            return Err(KabelError::new(
                ErrorKind::MissingDelimiter,
                "Missing right parenthesis".to_string(),
                e.line,
                e.column,
                self.text[left_paren.line_start..expr.end].to_string(),
            ));
        }
        unreachable!();
    }


    pub fn read_token(&mut self) -> Result<Token, KabelError> {
        if self.current >= self.input.len() {
            let last_token = self.input[self.input.len()-1].clone();
            return Err(KabelError::new(ErrorKind::UnexpectedEof,
                    "Unexpected end of file".to_string(), last_token.line, last_token.column,
                    self.text[last_token.line_start..last_token.end].to_string()));
            let last_token = self.input[self.input.len() - 1].clone();
            return Err(KabelError::new(
                ErrorKind::UnexpectedEof,
                "Unexpected end of file".to_string(),
                last_token.line,
                last_token.column,
                self.text[last_token.line_start..last_token.end].to_string(),
            ));
        }
        self.token = self.input[self.current].clone();
        self.current += 1;


@@ 187,10 353,14 @@ impl Parser {
    }
    pub fn peek(&mut self) -> Result<Token, KabelError> {
        if self.current >= self.input.len() {
            let last_token = self.input[self.input.len()-1].clone();
            return Err(KabelError::new(ErrorKind::UnexpectedEof,
                    "Unexpected end of file".to_string(), last_token.line, last_token.column,
                    self.text[last_token.line_start..last_token.end].to_string()));
            let last_token = self.input[self.input.len() - 1].clone();
            return Err(KabelError::new(
                ErrorKind::UnexpectedEof,
                "Unexpected end of file".to_string(),
                last_token.line,
                last_token.column,
                self.text[last_token.line_start..last_token.end].to_string(),
            ));
        }
        return Ok(self.input[self.current].clone());
    }


@@ 210,6 380,7 @@ pub enum ASTType {
    Program(Vec<AST>),

    Binary(Box<AST>, BinOp, Box<AST>),
    Unary(UnOp, Box<AST>),

    Group(Box<AST>),
    Ident(String),


@@ 223,4 394,16 @@ pub enum BinOp {
    Sub,
    Mul,
    Div,
    Eq,
    Ne,
    Gr,
    Ge,
    Ls,
    Le,
}

#[derive(Debug, Clone, Copy)]
pub enum UnOp {
    Not,
    Neg,
}

M starkingdoms-client/vite.config.ts.timestamp-1722468930578-9a55b81119f46.mjs => starkingdoms-client/vite.config.ts.timestamp-1722468930578-9a55b81119f46.mjs +18 -13
@@ 4,13 4,17 @@ import { resolve } from "path";
import * as child from "child_process";
import autoprefixer from "file:///home/ghostlyzsh/dev/starkingdoms.tk/starkingdoms-client/node_modules/autoprefixer/lib/autoprefixer.js";
import { svelte } from "file:///home/ghostlyzsh/dev/starkingdoms.tk/starkingdoms-client/node_modules/@sveltejs/vite-plugin-svelte/src/index.js";
var __vite_injected_original_dirname = "/home/ghostlyzsh/dev/starkingdoms.tk/starkingdoms-client";
var commitHash = child.execSync("git describe --no-match --always --abbrev=8 --dirty").toString().trim();
var __vite_injected_original_dirname =
  "/home/ghostlyzsh/dev/starkingdoms.tk/starkingdoms-client";
var commitHash = child
  .execSync("git describe --no-match --always --abbrev=8 --dirty")
  .toString()
  .trim();
var vite_config_default = defineConfig({
  plugins: [svelte()],
  define: {
    APP_VERSION: JSON.stringify(process.env.npm_package_version),
    COMMIT_HASH: JSON.stringify(commitHash)
    COMMIT_HASH: JSON.stringify(commitHash),
  },
  build: {
    target: ["chrome89", "edge89", "firefox89", "safari15"],


@@ 21,19 25,20 @@ var vite_config_default = defineConfig({
        play: resolve(__vite_injected_original_dirname, "play/index.html"),
        signup: resolve(__vite_injected_original_dirname, "signup/index.html"),
        login: resolve(__vite_injected_original_dirname, "login/index.html"),
        shipeditor: resolve(__vite_injected_original_dirname, "shipeditor/index.html"),
        uikit: resolve(__vite_injected_original_dirname, "uikit/index.html")
      }
    }
        shipeditor: resolve(
          __vite_injected_original_dirname,
          "shipeditor/index.html",
        ),
        uikit: resolve(__vite_injected_original_dirname, "uikit/index.html"),
      },
    },
  },
  appType: "mpa",
  css: {
    postcss: {
      plugins: [autoprefixer({})]
    }
  }
      plugins: [autoprefixer({})],
    },
  },
});
export {
  vite_config_default as default
};
export { vite_config_default as default };
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9naG9zdGx5enNoL2Rldi9zdGFya2luZ2RvbXMudGsvc3Rhcmtpbmdkb21zLWNsaWVudFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvZ2hvc3RseXpzaC9kZXYvc3Rhcmtpbmdkb21zLnRrL3N0YXJraW5nZG9tcy1jbGllbnQvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvZ2hvc3RseXpzaC9kZXYvc3Rhcmtpbmdkb21zLnRrL3N0YXJraW5nZG9tcy1jbGllbnQvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tIFwidml0ZVwiO1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgKiBhcyBjaGlsZCBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuLy9AdHMtaWdub3JlXG5pbXBvcnQgYXV0b3ByZWZpeGVyIGZyb20gXCJhdXRvcHJlZml4ZXJcIjtcbmltcG9ydCB7IHN2ZWx0ZSB9IGZyb20gXCJAc3ZlbHRlanMvdml0ZS1wbHVnaW4tc3ZlbHRlXCI7XG5cbmNvbnN0IGNvbW1pdEhhc2ggPSBjaGlsZFxuICAuZXhlY1N5bmMoXCJnaXQgZGVzY3JpYmUgLS1uby1tYXRjaCAtLWFsd2F5cyAtLWFiYnJldj04IC0tZGlydHlcIilcbiAgLnRvU3RyaW5nKClcbiAgLnRyaW0oKTtcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW3N2ZWx0ZSgpXSxcbiAgZGVmaW5lOiB7XG4gICAgQVBQX1ZFUlNJT046IEpTT04uc3RyaW5naWZ5KHByb2Nlc3MuZW52Lm5wbV9wYWNrYWdlX3ZlcnNpb24pLFxuICAgIENPTU1JVF9IQVNIOiBKU09OLnN0cmluZ2lmeShjb21taXRIYXNoKSxcbiAgfSxcbiAgYnVpbGQ6IHtcbiAgICB0YXJnZXQ6IFtcImNocm9tZTg5XCIsIFwiZWRnZTg5XCIsIFwiZmlyZWZveDg5XCIsIFwic2FmYXJpMTVcIl0sXG4gICAgY3NzQ29kZVNwbGl0OiBmYWxzZSxcbiAgICByb2xsdXBPcHRpb25zOiB7XG4gICAgICBpbnB1dDoge1xuICAgICAgICBtYWluOiByZXNvbHZlKF9fZGlybmFtZSwgXCJpbmRleC5odG1sXCIpLFxuICAgICAgICBwbGF5OiByZXNvbHZlKF9fZGlybmFtZSwgXCJwbGF5L2luZGV4Lmh0bWxcIiksXG4gICAgICAgIHNpZ251cDogcmVzb2x2ZShfX2Rpcm5hbWUsIFwic2lnbnVwL2luZGV4Lmh0bWxcIiksXG4gICAgICAgIGxvZ2luOiByZXNvbHZlKF9fZGlybmFtZSwgXCJsb2dpbi9pbmRleC5odG1sXCIpLFxuICAgICAgICBzaGlwZWRpdG9yOiByZXNvbHZlKF9fZGlybmFtZSwgXCJzaGlwZWRpdG9yL2luZGV4Lmh0bWxcIiksXG4gICAgICAgIHVpa2l0OiByZXNvbHZlKF9fZGlybmFtZSwgXCJ1aWtpdC9pbmRleC5odG1sXCIpLFxuICAgICAgfSxcbiAgICB9LFxuICB9LFxuICBhcHBUeXBlOiBcIm1wYVwiLFxuICBjc3M6IHtcbiAgICBwb3N0Y3NzOiB7XG4gICAgICBwbHVnaW5zOiBbYXV0b3ByZWZpeGVyKHt9KV0sXG4gICAgfSxcbiAgfSxcbn0pO1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUEwVixTQUFTLG9CQUFvQjtBQUN2WCxTQUFTLGVBQWU7QUFDeEIsWUFBWSxXQUFXO0FBRXZCLE9BQU8sa0JBQWtCO0FBQ3pCLFNBQVMsY0FBYztBQUx2QixJQUFNLG1DQUFtQztBQU96QyxJQUFNLGFBQ0gsZUFBUyxxREFBcUQsRUFDOUQsU0FBUyxFQUNULEtBQUs7QUFFUixJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTLENBQUMsT0FBTyxDQUFDO0FBQUEsRUFDbEIsUUFBUTtBQUFBLElBQ04sYUFBYSxLQUFLLFVBQVUsUUFBUSxJQUFJLG1CQUFtQjtBQUFBLElBQzNELGFBQWEsS0FBSyxVQUFVLFVBQVU7QUFBQSxFQUN4QztBQUFBLEVBQ0EsT0FBTztBQUFBLElBQ0wsUUFBUSxDQUFDLFlBQVksVUFBVSxhQUFhLFVBQVU7QUFBQSxJQUN0RCxjQUFjO0FBQUEsSUFDZCxlQUFlO0FBQUEsTUFDYixPQUFPO0FBQUEsUUFDTCxNQUFNLFFBQVEsa0NBQVcsWUFBWTtBQUFBLFFBQ3JDLE1BQU0sUUFBUSxrQ0FBVyxpQkFBaUI7QUFBQSxRQUMxQyxRQUFRLFFBQVEsa0NBQVcsbUJBQW1CO0FBQUEsUUFDOUMsT0FBTyxRQUFRLGtDQUFXLGtCQUFrQjtBQUFBLFFBQzVDLFlBQVksUUFBUSxrQ0FBVyx1QkFBdUI7QUFBQSxRQUN0RCxPQUFPLFFBQVEsa0NBQVcsa0JBQWtCO0FBQUEsTUFDOUM7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUFBLEVBQ0EsU0FBUztBQUFBLEVBQ1QsS0FBSztBQUFBLElBQ0gsU0FBUztBQUFBLE1BQ1AsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7QUFBQSxJQUM1QjtBQUFBLEVBQ0Y7QUFDRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo=