Release catalyst

This commit is contained in:
Jonas Plum committed 2021-12-13 00:39:15 +01:00
commit 15cf0ebd49
339 files changed
+111677

No files matched your search

+248
View File
@@ -0,0 +1,248 @@
<template>
<v-app class="background">
<v-navigation-drawer dark permanent :mini-variant="mini" :expand-on-hover="mini" app color="statusbar">
<v-list>
<v-list-item class="px-2" :to="{ name: 'Dashboard' }">
<v-list-item-avatar rounded="0">
<v-img src="/flask_white.svg" :width="40"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title class="title">
Catalyst
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
<!--v-list dense nav>
<v-list-item class="px-0" dense :to="{ name: 'Profile' }">
<v-list-item-avatar>
<v-img v-if="$store.state.userdata.image" :src="$store.state.userdata.image"></v-img>
<v-icon v-else>mdi-account-circle</v-icon>
</v-list-item-avatar>
<div v-if="$store.state.user">
{{ $store.state.userdata.name }}
</div>
</v-list-item>
</v-list>
<v-divider></v-divider-->
<v-list nav dense>
<v-list-item>
<v-list-item-icon>
<v-icon class="my-1">mdi-arrow-right-bold</v-icon>
</v-list-item-icon>
<v-list-item-title>
<v-text-field
placeholder="Goto"
outlined
dense
hide-details
v-on:keyup.enter="enter"
clearable
color="#fff"
v-model="goto"></v-text-field>
</v-list-item-title>
</v-list-item>
</v-list>
<v-divider></v-divider>
<AppLink :links="internal"></AppLink>
<v-list nav dense v-if="$store.state.settings.ticketTypes">
<v-list-item
v-for="customType in $store.state.settings.ticketTypes"
:key="customType.id"
link
:class="{ 'v-list-item--active': ($route.params.type === customType.id) }"
@click="openTicketList(customType.id)">
<v-list-item-icon>
<v-badge
v-if="customType.id in counts && counts[customType.id] > 0"
:content="counts[customType.id]"
color="red"
left
offset-x="35"
offset-y="8"
bottom>
<v-icon>{{ customType.icon }}</v-icon>
</v-badge>
<v-icon v-else>{{ customType.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-title>{{ customType.name }}</v-list-item-title>
</v-list-item>
</v-list>
<v-divider></v-divider>
<AppLink :links="settings"></AppLink>
<template v-slot:append>
<v-list nav dense>
<v-list-item class="version" dense style="min-height: 20px">
<v-list-item-content>
<v-list-item-title style="text-align: center; opacity: 0.5;">
{{ $store.state.settings.tier }} v{{ $store.state.settings.version }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
<v-divider></v-divider>
<v-list nav dense>
<v-list-item :to="{ name: 'API' }">
<v-list-item-icon>
<v-icon>mdi-share-variant</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>API Documentation</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</template>
</v-navigation-drawer>
<v-app-bar app dense flat absolute color="transparent">
<v-btn icon @click="mini = !mini">
<v-icon color="primary">mdi-menu</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn :to="{ name: 'Profile' }" icon>
<v-avatar v-if="$store.state.userdata.image" size="32">
<v-img :src="$store.state.userdata.image"></v-img>
</v-avatar>
<v-icon v-else>mdi-account-circle</v-icon>
</v-btn>
</v-app-bar>
<div>
<router-view></router-view>
</div>
<v-snackbar v-model="snackbar" :color="$store.state.alert.type" :timeout="$store.state.alert.type === 'error' ? -1 : 5000" outlined>
<b style="display: block">{{ $store.state.alert.name | capitalize }}</b>
{{ $store.state.alert.detail }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" @click="snackbar = false">Close</v-btn>
</template>
</v-snackbar>
</v-app>
</template>
<script lang="ts">
import Vue from "vue";
import AppLink from "./components/AppLink.vue";
export default Vue.extend({
name: "App",
components: {AppLink},
data: () => ({
settings: [
{ icon: "mdi-format-list-bulleted-type", name: "Ticket Types", to: "TicketTypeList", role: "engineer:tickettype:write" },
{ icon: "mdi-file-hidden", name: "Templates", to: "TemplateList", role: "analyst:template:read" },
{ icon: "mdi-file-cog-outline", name: "Playbooks", to: "PlaybookList", role: "analyst:playbook:read" },
{ icon: "mdi-flash", name: "Automations", to: "AutomationList", role: "analyst:automation:read" },
{ icon: "mdi-filter", name: "Ingestion Rules", to: "RuleList", role: "analyst:rule:read", tier: "enterprise" },
{ icon: "mdi-account", name: "Users & API Keys", to: "UserList", role: "admin:user:write" },
{ icon: "mdi-account-group", name: "Groups", to: "GroupList", role: "admin:group:write", tier: "enterprise" },
{ icon: "mdi-cogs", name: "User Data", to: "UserDataList", role: "admin:userdata:write" },
{ icon: "mdi-format-list-checks", name: "Jobs", to: "JobList", role: "admin:job:write" },
],
mini: false,
goto: "",
snackbar: false,
}),
watch: {
showAlert: function () {
this.snackbar = true
}
},
computed: {
counts: function (): number {
return this.$store.state.counts
},
internal: function (): Array<any> {
return [
{ icon: "mdi-check-bold", name: "Open Tasks", to: "TaskList", count: this.$store.state.task_count },
]
},
showAlert: function (): boolean {
return this.$store.state.showAlert
}
},
methods: {
enter: function () {
if (!this.goto) {
return
}
this.$router.push({
name: "Ticket",
params: { id: this.goto.toString() }
});
},
openTicketList: function (type: string) {
this.$router.push({ name: "TicketList", params: { type: type } })
},
hasRole: function (s: string) {
if (this.$store.state.user.roles) {
return this.lodash.includes(this.$store.state.user.roles, s);
}
return false;
}
},
mounted() {
this.$store.dispatch("getUser");
this.$store.dispatch("getUserData");
this.$store.dispatch("getSettings");
},
});
</script>
<style>
.background {
background-color: #f5f5f5 !important;
}
.v-app-bar.v-toolbar--dense .v-toolbar__content {
border-bottom: 1px solid #e0e0e0 !important;
}
.theme--dark.background {
background-color: #303030 !important;
}
.theme--dark h1,
.theme--dark h2,
.theme--dark h3,
.theme--dark h4 {
color: white !important;
}
.theme--dark.v-btn:hover::before {
opacity: 0 !important;
}
.theme--dark .v-application .primary--text {
text-shadow: 0 0 3px #FFC107; /* #00bcd4;/* 0 0 3px #ffff00; */
}
.theme--dark .glow,
.theme--dark .v-list .v-list-item--active,
.theme--dark.v-btn:hover,
.theme--dark a:hover {
color: #FFC107 !important; /* #00bcd4 !important;/* #ffff00 !important; */
text-shadow: 0 0 3px #FFC107 !important; /* #00bcd4 !important;/* 0 0 3px #ffff00 !important; */
}
/* box-shadow: 0 0 8px rgba(255, 255, 0, 0.2) !important; */
.v-navigation-drawer--mini-variant .version {
opacity: 0;
transition: opacity 0.2s, visibility 0.2s;
}
</style>
+1
View File
@@ -0,0 +1 @@
# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm
+8104
View File
File diff suppressed because it is too large. Load diff
+71
View File
@@ -0,0 +1,71 @@
/* tslint:disable */
/* eslint-disable */
/**
*
* API for the catalyst incident response platform.
*
* The version of the OpenAPI document:
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { Configuration } from "./configuration";
// Some imports not used depending on template conditions
// @ts-ignore
import globalAxios, { AxiosPromise, AxiosInstance } from 'axios';
export const BASE_PATH = "http://./api".replace(/\/+$/, "");
/**
*
* @export
*/
export const COLLECTION_FORMATS = {
csv: ",",
ssv: " ",
tsv: "\t",
pipes: "|",
};
/**
*
* @export
* @interface RequestArgs
*/
export interface RequestArgs {
url: string;
options: any;
}
/**
*
* @export
* @class BaseAPI
*/
export class BaseAPI {
protected configuration: Configuration | undefined;
constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) {
if (configuration) {
this.configuration = configuration;
this.basePath = configuration.basePath || this.basePath;
}
}
};
/**
*
* @export
* @class RequiredError
* @extends {Error}
*/
export class RequiredError extends Error {
name: "RequiredError" = "RequiredError";
constructor(public field: string, msg?: string) {
super(msg);
}
}
+138
View File
@@ -0,0 +1,138 @@
/* tslint:disable */
/* eslint-disable */
/**
*
* API for the catalyst incident response platform.
*
* The version of the OpenAPI document:
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { Configuration } from "./configuration";
import { RequiredError, RequestArgs } from "./base";
import { AxiosInstance } from 'axios';
/**
*
* @export
*/
export const DUMMY_BASE_URL = 'https://example.com'
/**
*
* @throws {RequiredError}
* @export
*/
export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) {
if (paramValue === null || paramValue === undefined) {
throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`);
}
}
/**
*
* @export
*/
export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) {
if (configuration && configuration.apiKey) {
const localVarApiKeyValue = typeof configuration.apiKey === 'function'
? await configuration.apiKey(keyParamName)
: await configuration.apiKey;
object[keyParamName] = localVarApiKeyValue;
}
}
/**
*
* @export
*/
export const setBasicAuthToObject = function (object: any, configuration?: Configuration) {
if (configuration && (configuration.username || configuration.password)) {
object["auth"] = { username: configuration.username, password: configuration.password };
}
}
/**
*
* @export
*/
export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) {
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
object["Authorization"] = "Bearer " + accessToken;
}
}
/**
*
* @export
*/
export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) {
if (configuration && configuration.accessToken) {
const localVarAccessTokenValue = typeof configuration.accessToken === 'function'
? await configuration.accessToken(name, scopes)
: await configuration.accessToken;
object["Authorization"] = "Bearer " + localVarAccessTokenValue;
}
}
/**
*
* @export
*/
export const setSearchParams = function (url: URL, ...objects: any[]) {
const searchParams = new URLSearchParams(url.search);
for (const object of objects) {
for (const key in object) {
if (Array.isArray(object[key])) {
searchParams.delete(key);
for (const item of object[key]) {
searchParams.append(key, item);
}
} else {
searchParams.set(key, object[key]);
}
}
}
url.search = searchParams.toString();
}
/**
*
* @export
*/
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
const nonString = typeof value !== 'string';
const needsSerialization = nonString && configuration && configuration.isJsonMime
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
: nonString;
return needsSerialization
? JSON.stringify(value !== undefined ? value : {})
: (value || "");
}
/**
*
* @export
*/
export const toPathString = function (url: URL) {
return url.pathname + url.search + url.hash
}
/**
*
* @export
*/
export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) {
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url};
return axios.request(axiosRequestArgs);
};
}
+101
View File
@@ -0,0 +1,101 @@
/* tslint:disable */
/* eslint-disable */
/**
*
* API for the catalyst incident response platform.
*
* The version of the OpenAPI document:
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface ConfigurationParameters {
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
username?: string;
password?: string;
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
basePath?: string;
baseOptions?: any;
formDataCtor?: new () => any;
}
export class Configuration {
/**
* parameter for apiKey security
* @param name security name
* @memberof Configuration
*/
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
username?: string;
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
password?: string;
/**
* parameter for oauth2 security
* @param name security name
* @param scopes oauth2 scope
* @memberof Configuration
*/
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
/**
* override base path
*
* @type {string}
* @memberof Configuration
*/
basePath?: string;
/**
* base options for axios calls
*
* @type {any}
* @memberof Configuration
*/
baseOptions?: any;
/**
* The FormData constructor that will be used to create multipart form data
* requests. You can inject this here so that execution environments that
* do not support the FormData class can still run the generated client.
*
* @type {new () => FormData}
*/
formDataCtor?: new () => any;
constructor(param: ConfigurationParameters = {}) {
this.apiKey = param.apiKey;
this.username = param.username;
this.password = param.password;
this.accessToken = param.accessToken;
this.basePath = param.basePath;
this.baseOptions = param.baseOptions;
this.formDataCtor = param.formDataCtor;
}
/**
* Check if the given MIME is a JSON MIME.
* JSON MIME examples:
* application/json
* application/json; charset=UTF8
* APPLICATION/JSON
* application/vnd.company+json
* @param mime - MIME (Multipurpose Internet Mail Extensions)
* @return True if the given MIME is JSON, false otherwise.
*/
public isJsonMime(mime: string): boolean {
const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
}
}
+18
View File
@@ -0,0 +1,18 @@
/* tslint:disable */
/* eslint-disable */
/**
*
* API for the catalyst incident response platform.
*
* The version of the OpenAPI document:
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export * from "./api";
export * from "./configuration";
@@ -0,0 +1,195 @@
<template>
<div>
<div class="d-flex" >
<v-spacer></v-spacer>
<v-switch
v-model="advanced"
label="Advanced"
class="float-right mt-0"
></v-switch>
</div>
<div class="d-flex" >
<v-spacer></v-spacer>
<span v-if="advanced" class="float-right">
See
<a target="_blank" href="https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/">
vuetify-jsonschema documentation
</a>
for styling.
</span>
</div>
<v-row class="flex-grow-0 flex-shrink-0">
<v-col :cols="hidepreview ? 12 : 7">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
Schema
</v-subheader>
<div v-if="!advanced">
<json-schema-editor :disabled="readonly" :value="{ root: internalSchema }" lang="en_US" style="border: 1px solid #393a3f" class="mb-3 rounded" />
</div>
<div v-else class="flex-grow-1 flex-shrink-1 overflow-scroll">
<Editor v-model="schemaString" lang="json" :readonly="readonly"></Editor>
</div>
</v-col>
<v-col v-if="!hidepreview" cols="5">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
Form output preview
</v-subheader>
<v-form v-model="valid">
<v-jsf
v-model="details"
:schema="advanced ? parsedSchemaString : internalSchema"
:options="{ readonly: true, formats: { time: timeformat, date: dateformat, 'date-time': datetimeformat } }"
/>
</v-form>
</v-col>
</v-row>
<v-row v-if="!readonly" class="px-3 my-6 flex-grow-0 flex-shrink-0">
<v-btn v-if="this.$route.params.id === 'new'" color="success" @click="save" outlined>
<v-icon>mdi-plus-thick</v-icon>
Create
</v-btn>
<v-btn v-else color="success" @click="save" outlined>
<v-icon>mdi-content-save</v-icon>
Save
</v-btn>
</v-row>
</div>
</template>
<script lang="ts">
import Editor from "./Editor.vue";
import Vue from "vue";
import {DateTime} from "luxon";
interface State {
advanced: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
internalSchema: any;
schemaString: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
details: any;
valid: boolean;
}
export default Vue.extend({
name: "AdvancedJSONSchemaEditor",
components: { Editor },
props: {
schema: {
type: Object,
required: true
},
hidepreview: {
type: Boolean,
default: true
},
readonly: {
type: Boolean,
default: false
},
},
data: (): State => ({
details: {},
advanced: false,
internalSchema: {},
schemaString: "{}",
valid: true,
}),
watch: {
schema: function () {
this.internalSchema = this.schema;
this.schemaString = JSON.stringify(this.internalSchema, null, 2);
},
advanced: function (advanced) {
if (advanced) {
this.schemaString = JSON.stringify(this.internalSchema, null, 2);
} else {
this.internalSchema = JSON.parse(this.schemaString);
}
}
},
computed: {
parsedSchemaString: function() {
try {
return JSON.parse(this.schemaString);
}
catch (e) {
return {}
}
},
},
methods: {
save: function () {
let schema = this.schemaString;
if (!this.advanced) {
schema = JSON.stringify(this.internalSchema);
}
this.$emit("save", schema);
},
timeformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
dateformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
datetimeformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
hasRole: function (s: string): boolean {
if (this.$store.state.user.roles) {
return this.lodash.includes(this.$store.state.user.roles, s);
}
return false;
}
},
mounted() {
this.internalSchema = this.schema;
this.schemaString = JSON.stringify(this.internalSchema, null, 2);
},
});
</script>
<style>
.theme--dark .ant-btn,
.theme--dark .ant-select-selection,
.theme--dark .ant-input,
.theme--dark .ant-input-number,
.theme--dark .ant-modal-header,
.theme--dark .ant-modal-title,
.theme--dark .ant-form-item,
.theme--dark .ant-modal-close-x,
.theme--dark .ant-select-dropdown,
.theme--dark .ant-checkbox-inner {
color: white !important;
background: none !important;
}
.theme--dark .ant-select-selection,
.theme--dark .ant-input,
.theme--dark .ant-input-number,
.theme--dark .ant-modal-header,
.theme--dark .ant-modal-footer,
.theme--dark .ant-checkbox-inner {
border-color: #424242 !important;
}
.theme--dark .ant-modal-content,
.theme--dark .ant-select-dropdown {
color: white !important;
background: #303030 !important;
}
</style>
+64
View File
@@ -0,0 +1,64 @@
<template>
<div>
<v-list nav dense>
<v-list-item v-for="link in userLinks" :key="link.to" link :to="{ name: link.to }">
<v-list-item-icon>
<v-badge
v-if="'count' in link && link.count"
:content="link.count"
color="red"
left
offset-x="35"
offset-y="8"
bottom>
<v-icon>{{ link.icon }}</v-icon>
</v-badge>
<v-icon v-else>{{ link.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-title>{{ link.name }}</v-list-item-title>
</v-list-item>
</v-list>
<v-divider v-if="userLinks.length > 0"></v-divider>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "AppLink",
props: ["links"],
computed: {
userLinks: function (): Array<any> {
return this.lodash.filter(this.links, link => {
return this.hasRole(link) && this.hasTier(link)
})
}
},
methods: {
hasRole: function (link: any) {
if (!("role" in link)) {
return true;
}
let has = false;
if (this.$store.state.user.roles) {
this.lodash.forEach(this.$store.state.user.roles, (userRole) => {
if (link.role === userRole || this.lodash.startsWith(link.role, userRole + ":")) {
has = true;
}
})
}
return has;
},
hasTier: function (link: any): boolean {
if ("tier" in link) {
if (this.$store.state.settings.tier) {
return this.$store.state.settings.tier == link.tier;
}
return false;
}
return true;
}
},
});
</script>
+115
View File
@@ -0,0 +1,115 @@
<template>
<prism-editor
v-if="showEditor"
class="my-editor"
v-model="code"
:highlight="highlighter"
line-numbers
:readonly="readonly">
</prism-editor>
<!--MonacoEditor
v-if="showEditor"
ref="editor"
class="editor"
style="height: 100%"
v-model="code"
:language="this.lang"
:options="{ scrollBeyondLastLine: false }"
:theme="$vuetify.theme.dark ? 'vs-dark' : 'vs'"
/-->
</template>
<script lang="ts">
import Vue from "vue";
// import MonacoEditor from "vue-monaco";
import { PrismEditor } from 'vue-prism-editor';
import 'vue-prism-editor/dist/prismeditor.min.css'; // import the styles somewhere
import { highlight, languages } from 'prismjs/components/prism-core';
// import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-json';
import 'prismjs/components/prism-python';
import 'prismjs/components/prism-yaml';
import 'prismjs/components/prism-markup';
import 'prismjs/components/prism-log';
import 'prismjs/themes/prism-tomorrow.css'; // import syntax highlighting styles
interface State {
showEditor: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resize?: any;
code: string,
}
export default Vue.extend({
name: "Editor",
props: ["value", "lang", "readonly"],
components: {PrismEditor},
data: (): State => ({
showEditor: true,
resize: undefined,
code: "",
}),
watch: {
code: function () {
this.$emit('input', this.code);
},
value: function () {
this.code = this.value;
}
},
methods: {
// resizeEditor() {
// this.showEditor = false;
// this.$nextTick(() => {
// this.showEditor = true;
// });
// },
highlighter(code: string) {
switch (this.lang) {
case "python":
return highlight(code, languages.python);
case "log":
return highlight(code, languages.log);
case "yaml":
return highlight(code, languages.yaml);
case "json":
return highlight(code, languages.json);
case "html":
return highlight(code, languages.html);
}
return highlight(code, languages.json);
},
},
mounted() {
this.code = this.value;
// this.resize = this.lodash.debounce(this.resizeEditor, 200);
// window.addTicketListener("resize", this.resize);
},
destroyed() {
// window.removeticketListener("resize", this.resize);
},
});
</script>
<style>
/* required class */
.my-editor {
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
background: #2d2d2d;
color: #ccc;
/* you must provide font-family font-size line-height. Example: */
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
font-size: 14px;
line-height: 1.5;
padding: 5px;
}
/* optional class for removing the outline */
.prism-editor__textarea:focus {
outline: none;
}
</style>
+20
View File
@@ -0,0 +1,20 @@
<template>
<div>
<div v-for="(value, key) in json" :key="key">
<dl v-if="typeof(value) == 'object'">
<dt>{{ key }}</dt>
<dd><JSONHTML :json="value"></JSONHTML></dd>
</dl>
<span v-else>
<b>{{ key }}</b>: {{ value }}
</span>
</div>
</div>
</template>
<script>
export default {
name: "JSONHTML",
props: ["json"]
}
</script>
+153
View File
@@ -0,0 +1,153 @@
<template>
<v-row class="fill-height ma-0">
<v-col cols="3" class="listnav" style="">
<v-list nav color="background">
<v-list-item
v-if="showNew && canWrite"
:to="{ name: routername, params: { id: 'new' } }"
class="mt-4 mx-4 text-center newbutton"
>
<v-list-item-content>
<v-list-item-title>
<v-icon small>mdi-plus</v-icon> New {{ singular }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-subheader class="pl-4">{{ plural }}</v-subheader>
<v-list-item
v-for="item in (items ? items : [])"
:key="item[itemid]"
link
:to="{ name: routername, params: { id: item[itemid] } }"
class="mx-2"
>
<v-list-item-content>
<v-list-item-title>
{{ item[itemname] }}
</v-list-item-title>
</v-list-item-content>
<v-list-item-action v-if="deletable && canWrite">
<v-icon @click="askDelete(item[itemid])" class="fader">
mdi-close
</v-icon>
</v-list-item-action>
</v-list-item>
</v-list>
</v-col>
<v-col cols="9">
<router-view></router-view>
</v-col>
<v-dialog v-model="dialog" persistent max-width="400">
<v-card>
<v-card-title> Delete {{ singular }} {{ deleteName }} ? </v-card-title>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="error" text @click="dialog = false">Cancel</v-btn>
<v-btn color="success" outlined @click="deleteItem(deleteName)">Delete</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-row>
</template>
<script lang="ts">
import Vue from "vue";
interface State {
dialog: boolean;
deleteName?: string;
}
export default Vue.extend({
name: "List",
components: { },
props: {
items: {
type: Array,
required: true
},
routername: {
type: String,
required: true
},
itemid: {
type: String,
required: true
},
itemname: {
type: String,
required: true
},
singular: {
type: String,
required: true
},
plural: {
type: String,
required: true
},
showNew: {
type: Boolean,
default: true
},
deletable: {
type: Boolean,
default: true
},
writepermission: {
type: String,
required: true,
}
},
data: (): State => ({
dialog: false,
deleteName: undefined,
}),
computed: {
canWrite: function (): boolean {
return this.hasRole(this.writepermission);
},
},
methods: {
askDelete(name: string) {
this.deleteName = name;
this.dialog = true;
},
deleteItem(deleteName: string) {
this.$emit('delete', deleteName);
this.dialog = false;
},
hasRole: function (s: string): boolean {
if (this.$store.state.user.roles) {
return this.lodash.includes(this.$store.state.user.roles, s);
}
return false;
}
}
});
</script>
<style>
.listnav {
border-right: 1px solid #e0e0e0;
}
.theme--dark .listnav {
border-right: 1px solid #393a3f;
}
.newbutton {
background: #e0e0e0;
}
.theme--dark .newbutton {
background: #424242;
}
.v-list-item .fader {
opacity: 0 !important;
}
.v-list-item:hover .fader {
opacity: 1 !important;
}
</style>
+325
View File
@@ -0,0 +1,325 @@
<template>
<v-container>
<v-row v-if="type">
<v-col cols="12">
<v-btn elevation="0" rounded class="float-right" :to="{ name: 'TicketNew', params: { type: type } }">
<v-icon class="mr-1">mdi-plus</v-icon>
New {{ type | capitalize }}
</v-btn>
</v-col>
</v-row>
<v-toolbar
rounded
filled
dense
flat
elevation="0"
style="border-radius: 40px !important;"
>
<v-btn-toggle dense v-model="defaultcaql">
<v-btn
text
color="primary"
@click="caql = !caql"
rounded
style="border-radius: 40px !important;">
CAQL
</v-btn>
</v-btn-toggle>
<v-text-field
placeholder="Search term or query (e.g. name == 'malware' AND 'wannacry')"
v-model="term"
dense
solo
flat
hide-details
clearable
append-icon="mdi-magnify"
@click:clear="clear"
@click:append="loadTickets"
@keydown.enter="loadTickets"
:rules="[validate]"
@focus="focus = true"
@blur="blur"
></v-text-field>
</v-toolbar>
<span v-if="focus && caql">CAQL Query Suggestions</span>
<v-list class="mb-2" v-if="focus && caql">
<v-list-item v-for="example in examples" :key="example.q" dense link @click="term = example.q; caql = true; defaultcaql = 0; loadTickets()">
<v-list-item-content>
<v-list-item-title>
<v-row>
<span class="col-6">{{ example.q }}</span> <span class="text--disabled col-6">{{ example.desc }}</span>
</v-row>
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item>
<v-list-item-content>
Fields: {{ lodash.join(fields, ", ") }}
</v-list-item-content>
</v-list-item>
</v-list>
<v-data-table
:headers="headers"
:items="tickets"
item-key="name"
multi-sort
class="elevation-0 cards clickable mt-2"
:options.sync="options"
:server-items-length="totalTickets"
:loading="loading"
:footer-props="{ 'items-per-page-options': [10, 25, 50, 100] }"
>
<template v-slot:item="{ item }">
<tr @click="open(item)">
<td colspan="5">
<ticketSnippet :ticket="item" class="pa-0"></ticketSnippet>
</td>
</tr>
</template>
</v-data-table>
</v-container>
</template>
<script lang="ts">
import Vue from "vue";
import { Ticket } from "@/client";
import { API } from "@/services/api";
import TicketSnippet from "../components/snippets/TicketSnippet.vue";
import {validateCAQL} from "@/suggestions/suggestions";
import {DateTime} from "luxon";
interface State {
term: string;
loading: boolean;
tickets: Array<Ticket>;
totalTickets: number;
options: {
page?: number;
itemsPerPage?: number;
sortBy?: string[];
sortDesc?: boolean[];
groupBy?: string[];
groupDesc?: boolean[];
multiSort?: boolean;
mustSort?: boolean;
};
focus: boolean;
caql: boolean;
defaultcaql?: number;
}
interface QuerySuggestion {
q: string;
desc: string;
}
export default Vue.extend({
name: "TicketList",
components: {
TicketSnippet,
},
props: ["type", "query"],
data: (): State => ({
term: "status == 'open'",
loading: true,
tickets: [],
totalTickets: 0,
options: {
itemsPerPage: 10,
},
focus: false,
caql: true,
defaultcaql: 0,
}),
computed: {
fields(): Array<string> {
return [
"type", "id", "name",
"status" , "owner",
"created", "modified",
"details", "details.description", "details.…",
"schema",
"comments", "comments.#.created", "comments.#.creator", "comments.#.message",
"playbooks", "playbooks.#.name", "playbooks.#.tasks",
"references", "references.#.href", "references.#.name",
"artifacts", "artifacts.#.name", "artifacts.#.status", "artifacts.#.type",
"files", "files.#.name"
];
},
user(): string {
return this.$store.state.user.id
},
headers() {
return [
{
text: "Name",
align: "start",
value: "name",
},
{
text: "Status",
align: "start",
value: "status",
},
{
text: "Owner",
align: "start",
value: "owner",
},
{
text: "Creation",
align: "start",
value: "created",
},
{
text: "Last Modification",
align: "start",
value: "modified",
},
];
},
examples (): Array<QuerySuggestion> {
let twoWeeksAgo = DateTime.utc().minus({weeks: 2}).toFormat("yyyy-MM-dd");
let ex: Array<QuerySuggestion> = [];
if (this.user) {
ex.push({q: "status == 'open' AND (owner == '" + this.user + "' OR !owner)", desc: "Select all open tickets by you and unassigned"})
ex.push({q: "status == 'closed' AND owner == '" + this.user + "'", desc: "Select completed tickets by you"})
} else {
ex.push({q: "status == 'open'", desc: "Select all open tickets"})
ex.push({q: "status == 'closed'", desc: "Select completed tickets"})
}
ex.push({q: "created > \""+twoWeeksAgo+"\"", desc: "Select tickets created in the last two weeks"})
if (this.term && this.term.match(/^[A-Za-z ]+$/)) {
ex.unshift({q: "'" + this.term + "'", desc: "Full text search for '" + this.term + "'"})
}
return ex;
},
},
watch: {
options: {
handler() {
this.loadTickets();
},
deep: true,
},
$route: function () {
this.loadTickets();
},
},
methods: {
blur: function () {
setTimeout(()=>{this.focus = false}, 200)
},
clear: function () {
this.caql = false;
this.defaultcaql = undefined;
this.term = "";
this.loadTickets();
},
open: function (ticket: Ticket) {
this.$emit("click", ticket);
},
select: function (e: string) {
this.loadTerm(e);
},
loadTickets() {
let term = this.term;
if (!term) {
term = "";
}
this.loadTerm(term);
},
loadTerm(term: string) {
this.loading = true;
let offset = 0;
let count = 25;
let sortBy: Array<string> = [];
let sortDesc: Array<boolean> = [];
if (this.options.itemsPerPage !== undefined) {
count = this.options.itemsPerPage;
if (this.options.page !== undefined) {
offset = (this.options.page - 1) * this.options.itemsPerPage;
}
}
if (this.options.sortBy !== undefined) {
sortBy = this.options.sortBy;
}
if (this.options.sortDesc !== undefined) {
sortDesc = this.options.sortDesc;
}
let t = this.type;
if (!t) {
t = "";
}
if (!this.caql && this.term.length > 0) {
term = "'" + this.lodash.join(this.lodash.split(term, " "), "'&&'") + "'"
}
API.listTickets(t, offset, count, sortBy, sortDesc, term)
.then((response) => {
if (response.data.tickets) {
this.tickets = response.data.tickets;
} else {
this.tickets = [];
}
this.totalTickets = response.data.count;
this.loading = false;
})
.catch(() => {
this.loading = false;
});
},
validate: function () {
if (!this.term) {
return true
}
let err = validateCAQL(this.term);
if (err !== null) {
return err.message;
}
return true;
}
},
mounted() {
if (this.user) {
this.term = "status == 'open' AND (owner == '" + this.user + "' OR !owner)";
} else {
this.term = "status == 'open'";
}
if (this.query) {
this.term = this.query;
}
this.loadTickets();
},
});
</script>
<style>
.clickable td {
cursor: pointer !important;
}
.vue-simple-suggest.designed .input-wrapper input {
background: none !important;
border: none !important;
color: #fff;
}
.vue-simple-suggest.designed .suggestions {
background-color: #333 !important;
top: 60px !important;
border: 1px solid #ddd !important;
}
</style>
+139
View File
@@ -0,0 +1,139 @@
<template>
<div>
<v-textarea
v-model="comment"
hide-details
flat
label="Add a comment..."
solo
auto-grow
rows="2"
class="py-2"
>
<template v-slot:append>
<v-btn class="mx-0 mt-n1" text @click="addTicketLog">
<v-icon>mdi-send</v-icon>
</v-btn>
</template>
</v-textarea>
<div
v-for="(log, id) in internalLogs"
:key="id"
:icon="icon(log.type)"
:small="small(log.type)"
class="pb-2"
>
<v-card v-if="log.type === 'comment'" elevation="0" color="cards">
<v-card-subtitle class="pb-0">
<strong> {{ log.creator }}</strong>
<span class="text--disabled ml-3" :title="log.created">
{{ relDate(log.created) }}
</span>
</v-card-subtitle>
<v-card-text class="mb-0 mt-2">
<!--{{ log.message }}-->
<vue-markdown v-if="show">{{ log.message }}</vue-markdown>
</v-card-text>
</v-card>
<div v-else style="line-height: 24px" class="d-flex flex-row">
<v-divider class="mt-3 mr-3"></v-divider>
{{ log.message }}
<span class="text--disabled ml-1" :title="log.created">
&middot;
{{ log.creator }} &middot;
{{ relDate(log.created) }}
</span>
<v-divider class="mt-3 ml-3"></v-divider>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { LogEntry } from "@/client";
import VueMarkdown from "vue-markdown";
import { API } from "@/services/api";
interface State {
comment: string
internalLogs: Array<LogEntry>
show: boolean
}
export default Vue.extend({
name: "Timeline",
components: {
"vue-markdown": VueMarkdown
},
props: ["id", "logs"],
data: (): State => ({
comment: "",
internalLogs: [],
show: true
}),
watch: {
logs: function () {
// this.internalLogs = this.logs;
this.reload(this.logs);
}
},
methods: {
reload: function(newlogs: Array<LogEntry>) {
if (newlogs === undefined) {
return
}
this.show = false;
Vue.nextTick(() => {
this.internalLogs = newlogs;
this.show = true;
})
},
icon: function(s: string) {
switch (s) {
case "comment":
return "mdi-comment";
}
return "";
},
small: function(s: string) {
switch (s) {
case "comment":
return false;
}
return true;
},
relDate: function(date: string) {
let rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
let deltaDays =
(new Date(date).getTime() - new Date().getTime()) / (1000 * 3600 * 24);
let relDate = rtf.format(Math.round(deltaDays), "days");
if (deltaDays > -3) {
relDate +=
", " +
new Date(date).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit"
});
}
return relDate;
},
addTicketLog() {
// API.addLog({ id: this.id, message: this.comment }).then(
// response => {
// this.$store.dispatch("alertSuccess", { name: "Log saved", type: "success" });
// if (this.internalLogs === undefined) {
// this.reload([response.data]);
// } else {
// this.internalLogs.unshift(response.data);
// this.reload(this.internalLogs);
// }
// }
// );
}
},
mounted() {
this.internalLogs = this.logs;
}
});
</script>
+173
View File
@@ -0,0 +1,173 @@
<template>
<div>
<div v-if="editoruserdata === undefined" class="text-sm-center py-16">
<v-progress-circular
indeterminate
color="primary"
:size="70"
:width="7"
class="align-center"
>
</v-progress-circular>
</div>
<div v-else class="pa-8">
<v-form>
<v-row>
<v-col cols="4" class="d-flex flex-column align-center">
<v-avatar v-if="editoruserdata.image" size="128" class="mt-1">
<img :src="editoruserdata.image" alt="userdata avatar" />
</v-avatar>
<v-file-input
v-model="file"
type="file"
class="pt-2 flex-grow-0"
style="width: 100%"
accept="image/png, image/jpeg"
label="Select Image"
@change="change"
:clearable="false"
>
<template v-slot:append-outer>
<v-btn
v-if="showCrop"
rounded
small
color="accent"
@click="validate"
>
<v-icon>
mdi-check
</v-icon>
Set
</v-btn>
<v-btn
v-if="!!editoruserdata.image"
small
rounded
color="error"
@click="
file = null;
editoruserdata.image = '';
showCrop = false;
"
class="ml-2"
>
<v-icon>
mdi-close
</v-icon>
Clear
</v-btn>
</template>
</v-file-input>
<vue-cropper
v-if="showCrop"
ref="cropper"
v-bind="{ aspectRatio: 1, autoCrop: true }"
:src="imgSrc"
alt="Avatar"
/>
</v-col>
<v-col cols="8">
<v-text-field
prepend-icon="mdi-account"
label="Name"
v-model="editoruserdata.name"
></v-text-field>
<v-text-field
prepend-icon="mdi-email"
label="Email"
v-model="editoruserdata.email"
></v-text-field>
<v-btn
color="success"
outlined
@click="saveUserData"
class="mt-6"
>
<v-icon>mdi-content-save</v-icon>
Save
</v-btn>
</v-col>
</v-row>
</v-form>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { UserData } from "@/client";
import VueCropper from "vue-cropperjs";
import "cropperjs/dist/cropper.css";
interface State {
tab: number;
editoruserdata?: UserData;
file: File | null;
imgSrc: string | ArrayBuffer | null;
showCrop: boolean;
}
export default Vue.extend({
name: "UserDataEditor",
data: (): State => ({
tab: 0,
editoruserdata: undefined,
file: null,
imgSrc: null,
showCrop: false
}),
props: ['userdata'],
components: {
VueCropper
},
methods: {
saveUserData: function() {
this.$emit("save", this.editoruserdata);
},
change: function() {
if (!this.file) {
this.imgSrc = null;
return;
}
const reader = new FileReader();
reader.onload = ticket => {
if (ticket.target && this.$refs.cropper) {
this.imgSrc = ticket.target.result;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let cropper: any = this.$refs.cropper;
cropper.replace(this.imgSrc);
}
};
reader.readAsDataURL(this.file);
this.showCrop = true;
},
validate: function() {
if (this.$refs.cropper && this.editoruserdata) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let cropper: any = this.$refs.cropper;
this.editoruserdata.image = cropper
.getCroppedCanvas({width: 128, height: 128})
.toDataURL("image/png");
// this.on.input(croppedImg)
this.showCrop = false;
// this.file = null
// this.imgSrc = null
}
},
},
mounted() {
this.editoruserdata = this.userdata;
}
});
</script>
<style>
.theme--dark.v-tabs-items,
.theme--dark.v-tabs > .v-tabs-bar {
background: none;
}
</style>
+85
View File
@@ -0,0 +1,85 @@
<template>
<v-input :value="value" class="vjsf-crop-img">
<v-row class="mt-0 mx-0" align="center">
<v-avatar v-if="value" size="128" class="mt-1">
<img :src="value">
</v-avatar>
<v-file-input
v-model="file"
type="file"
class="pt-2"
accept="image/png, image/jpeg"
placeholder="User Avatar"
@change="change"
:clearable="false"
>
<template v-slot:append-outer>
<v-btn v-if="imgSrc" fab x-small color="accent" @click="validate">
<v-icon>
mdi-check
</v-icon>
</v-btn>
</template>
</v-file-input>
<v-icon v-if="!!value" @click="on.input(null)">
mdi-close
</v-icon>
</v-row>
<vue-cropper
v-if="file"
ref="cropper"
v-bind="cropperOptions"
:src="imgSrc"
alt="Avatar"
/>
</v-input>
</template>
<script>
import VueCropper from 'vue-cropperjs'
import 'cropperjs/dist/cropper.css'
export default {
components: { VueCropper },
props: {
value: { type: String, default: '' },
on: { type: Object, required: true },
cropperOptions: { type: Object, default: () => ({ aspectRatio: 1, autoCrop: true }) },
size: { type: Number, default: 128 } // same as default v-avatar size
},
data: () => ({
file: null,
imgSrc: null
}),
computed: {},
methods: {
change() {
if (!this.file) {
this.imgSrc = null
return
}
const reader = new FileReader()
reader.onload = (ticket) => {
this.imgSrc = ticket.target.result
this.dialog = true
this.$refs.cropper.replace(this.imgSrc)
}
reader.readAsDataURL(this.file)
},
async validate() {
const croppedImg = this.$refs.cropper
.getCroppedCanvas({ width: this.size, height: this.size })
.toDataURL('image/png')
this.on.input(croppedImg)
this.file = null
this.imgSrc = null
}
}
}
</script>
<style lang="css">
.vjsf-crop-img>.v-input__control>.v-input__slot {
display: block;
}
</style>
+20
View File
@@ -0,0 +1,20 @@
import { Component, Mixins } from 'vue-property-decorator'
import {HorizontalBar, mixins} from 'vue-chartjs';
import ChartOptions from "chart.js";
@Component({
extends: HorizontalBar,
mixins: [mixins.reactiveProp],
props: {
chartOptions: {
type: ChartOptions,
default: null
}
},
})
export default class BarChart extends Mixins(mixins.reactiveProp, HorizontalBar) {
mounted () {
// @ts-expect-error chartOptions are not expected
this.renderChart(this.chartData, this.chartOptions);
}
}
+20
View File
@@ -0,0 +1,20 @@
import { Component, Mixins } from "vue-property-decorator";
import { mixins, Pie } from "vue-chartjs";
import ChartOptions from "chart.js";
@Component({
extends: Pie,
mixins: [mixins.reactiveProp],
props: {
chartOptions: {
type: ChartOptions,
default: null
}
}
})
export default class DoughnutChart extends Mixins(mixins.reactiveProp, Pie) {
mounted() {
// @ts-expect-error chartOptions are not expected
this.renderChart(this.chartData, this.chartOptions);
}
}
+20
View File
@@ -0,0 +1,20 @@
import { Component, Mixins } from 'vue-property-decorator'
import {Line, mixins} from 'vue-chartjs';
import ChartOptions from "chart.js";
@Component({
extends: Line,
mixins: [mixins.reactiveProp],
props: {
chartOptions: {
type: ChartOptions,
default: null,
}
},
})
export default class LineChart extends Mixins(mixins.reactiveProp, Line) {
mounted () {
// @ts-expect-error chartOptions are not expected
this.renderChart(this.chartData, this.chartOptions);
}
}
+34
View File
@@ -0,0 +1,34 @@
<template>
<svg
width="64"
viewBox="74.499 105.376 55.861 54.285"
height="64"
>
<path
style="fill: #ffffff"
id="path1566"
fill="#577138"
d="m128.867 130.714c-1.045-3.482-3.378-6.163-5.467-9.02-3.97-5.362-9.123-8.322-13.86-8.357-9.088-.174-15.495 3.97-18.246 10.48-.348.836-.8 1.184-1.637 1.358-3.03.696-6.06 1.393-8.88 2.82-1.915.975-3.865 1.88-5.084 3.76-1.532 2.368-1.358 4.875-.766 7.487 1.532 6.476 5.467 10.48 11.978 11.943 4.005.87 7.904.766 11.56-1.323 2.298-1.288 4.144-3.133 5.955-5.015.453-.487.8-.592 1.393-.313l3.343 1.637c3.552 1.776 7.173 3.238 11.247 2.994 6.477-.383 10.342-4.736 9.924-11.073-.14-2.507-.73-4.944-1.463-7.382zm-23.992 8.8c-3.9 2.6-7.94 4.875-12.605 5.815-1.497.314-2.995.418-4.005.348-3.76 0-6.93-.382-9.715-2.298-3.273-2.3-4.666-7.313-2.786-10.83.592-1.15 1.602-1.985 2.716-2.647 3.865-2.403 8.183-3.517 12.57-4.422 4.56-.975 9.192-2.02 13.963-1.985 2.298 0 4.352.905 5.815 2.75 1.288 1.67.906 3.552.28 5.328-1.22 3.343-3.308 6-6.233 7.94zm23.713 2.856c-1.463 3.656-4.562 4.875-8.078 5.397-3.76.557-6.86-1.22-10.063-2.716-1.045-.487-2.055-1.114-3.134-1.532-.94-.348-1.08-.697-.313-1.358 1.184-1.497 2.368-2.995 3.308-4.667 1.15-2.472 1.846-5.084 1.846-7.834 0-4.248-2.264-6.13-6.546-6.616-.836-.104-1.706-.035-2.577-.035-2.9.2-5.78.662-8.636 1.184-.592-.035-1.323.662-1.706.035-.278-.453.418-1 .73-1.497 2.1-3.62 5.223-5.85 9.158-7.104 3.447-1.08 6.86-1.323 10.4-.383 2.925.766 5.014 2.542 6.93 4.666 2.368 2.6 4.527 5.328 6.268 8.357 1.706 2.96 2.577 6.128 2.82 9.506.07 1.566.2 3.1-.418 4.597z"
/>
<path
style="fill: #ffffff"
id="path1570"
fill="#a2b24f"
d="m126.185 128.277c-1.776-3.03-3.935-5.78-6.268-8.357-1.915-2.124-4.005-3.9-6.93-4.666-3.55-.94-6.964-.697-10.4.383-3.935 1.22-7.07 3.482-9.158 7.104-.278.487-1 1.045-.73 1.497.383.592 1.114-.07 1.706-.035.696-2.263 2.228-3.935 4.144-5.153 3.378-2.194 7.138-3.1 11.178-3.03 3.9.104 6.964 1.8 9.54 4.63 1.88 2.054 3.517 4.353 5.12 6.616 2.542 3.587 3.935 7.556 3.656 12.013-.2 3.17-1.67 5.537-4.77 6.686-2.542.94-5.12 1.15-7.695.035-1.497-.627-3.065-1.08-4.527-1.8-1.358-.66-2.925-.836-4.04-1.95-.8.66-.627 1 .313 1.358 1.08.417 2.1 1.045 3.134 1.532 3.204 1.497 6.337 3.273 10.063 2.716 3.517-.522 6.616-1.775 8.078-5.397.592-1.497.488-3.03.383-4.56-.2-3.482-1.08-6.65-2.786-9.6zm-15.112 3.308c.627-1.776 1-3.656-.28-5.328-1.462-1.88-3.482-2.75-5.815-2.75-4.736-.035-9.367 1-13.998 1.985-4.387.94-8.705 2.02-12.57 4.422-1.114.697-2.124 1.532-2.716 2.647-1.845 3.517-.487 8.53 2.786 10.83 2.786 1.95 5.954 2.298 9.715 2.298 1 .07 2.542-.07 4.004-.348 4.666-.94 8.705-3.204 12.605-5.815 2.994-1.95 5.084-4.596 6.268-7.94zm-8.044 8.183c-3.308 1.985-6.65 3.9-10.516 4.596-3.134.557-6.338.732-9.47-.07-3.656-.87-6.477-4.18-6.616-7.94-.07-2.055.94-3.726 2.507-5.05 2.438-2.054 5.328-3.134 8.392-3.796.07 0 .174.104.278.174 2.577-1.985 5.502-2.368 8.636-2.124.278-.66.94-.453 1.428-.592 2.68-.662 5.397-.94 8.078-.383 5.05 1 5.676 3.83 4.04 7.94-1.288 3.308-3.83 5.467-6.755 7.243zm8.6-2.508c3.308.2 5.64-2.9 5.64-5.57 0-3.726-1.985-6.407-4.84-8.53-1.358-.975-2.9-1.636-4.562-1.045-1.428.487-2.82.8-4.318.697-.174 0-.348.14-.522.174.87 0 1.706-.07 2.577.034 4.283.488 6.546 2.368 6.546 6.616 0 2.75-.696 5.362-1.846 7.835.383-.245.836-.245 1.323-.2z"
/>
<path
style="fill: #ffffff"
id="path1574"
fill="#5e3108"
d="m83.564 134.823c-.105.905.14 1.636 1 2.16 3.134 1.915 6.477 3.03 10.203 2.6 2.75-.313 5.327-1.184 7.452-3.03 1.985-1.706 2.368-3.83 1.044-6.024-1.637-2.68-3.97-4.353-7.034-4.944-3.1-.244-6.06.14-8.636 2.124-2.228 1.88-3.726 4.18-4.04 7.104z"
/>
</svg>
</template>
<script>
export default {
name: "ArangoIcon",
};
</script>
<style scoped></style>
+31
View File
@@ -0,0 +1,31 @@
<template>
<svg viewBox="0 0 205.18876 205.19" height="205.19" width="205.18875" id="svg4136">
<g transform="matrix(1.25,0,0,-1.25,0,205.19)" id="g4144">
<g transform="scale(0.1)" style="fill: #ff0000" clip-path="url(#clipPath4152)" id="g4150">
<path
id="path4156"
style="fill: #ffffff; fill-opacity: 1; fill-rule: nonzero; stroke: none"
d="m 820.992,276.18 c -295.238,0 -535.441,240.211 -535.441,535.465 0,295.245 240.203,535.445 535.441,535.445 295.258,0 535.468,-240.2 535.468,-535.445 0,-58.926 -47.77,-106.696 -106.71,-106.696 -58.92,0 -106.69,47.77 -106.69,106.696 0,177.574 -144.482,322.055 -322.068,322.055 -177.574,0 -322.047,-144.481 -322.047,-322.055 0,-177.575 144.473,-322.075 322.047,-322.075 58.93,0 106.703,-47.769 106.703,-106.691 0,-58.93 -47.773,-106.699 -106.703,-106.699"
/>
<path
id="path4158"
style="fill: #ffffff; fill-opacity: 1; fill-rule: nonzero; stroke: none"
d="m 1009.77,811.645 c 0,-104.254 -84.516,-188.774 -188.778,-188.774 -104.258,0 -188.769,84.52 -188.769,188.774 0,104.257 84.511,188.775 188.769,188.775 104.262,0 188.778,-84.518 188.778,-188.775"
/>
<path
id="path4160"
style="fill: #ffffff; fill-opacity: 1; fill-rule: nonzero; stroke: none"
d="m 820.758,0 c -45.328,0 -82.074,36.7617 -82.074,82.0781 0,45.3319 36.746,82.0629 82.074,82.0629 362.052,0 656.592,294.57 656.592,656.625 0,362.054 -294.54,656.604 -656.592,656.604 -362.059,0 -656.602,-294.55 -656.602,-656.604 0,-45.325 -36.758,-82.075 -82.0857,-82.075 C 36.7461,738.691 0,775.441 0,820.766 c 0,452.564 368.18,820.754 820.758,820.754 452.562,0 820.752,-368.19 820.752,-820.754 C 1641.51,368.191 1273.32,0 820.758,0"
/>
</g>
</g>
</svg>
</template>
<script>
export default {
name: "EmitterIcon",
};
</script>
<style scoped></style>
+22
View File
@@ -0,0 +1,22 @@
<template>
<svg
viewBox="-0.231 -10.008 1143.859 1147.992"
width="2500"
height="2500"
>
<path
style="fill: #ffffff"
id="path887"
fill="#f8e6ea"
d="m 649.50958,1130.9299 c -1.375,-0.74 -16.788,-15.67 -34.25,-33.18 l -31.75,-31.834 V 858.86783 c 0,-113.876 -0.289,-207.336 -0.641,-207.69 -0.649,-0.647 -52.692,25.508 -205.773,103.415 -46.152,23.488 -84.548,42.462 -85.324,42.164 -0.906,-0.347 -1.206,-1.359 -0.837,-2.827 0.315,-1.257 1.018,-6.483 1.562,-11.614 2.754,-25.985 23.256,-87.028 45.006,-134 59.272,-128.003 155.174,-234.087 277.19,-306.617 19.913,-11.837 36.64,-20.494 38.337,-19.843 1.294,0.497 1.48,13.97 1.48,107.1 0,76.287 0.31,106.531 1.091,106.531 0.6,0 5.174,-2.109 10.165,-4.686 35.003,-18.079 60.409,-51.848 68.9,-91.58 2.871,-13.436 3.13,-37.923 0.537,-50.916 -4.763,-23.874 -15.756,-46.334 -31.252,-63.852 -7.652,-8.65 -33.057,-35.365 -77.946,-81.966 -67.875,-70.462 -80.303,-83.931 -88.255,-95.65 -5.834,-8.6 -10.87,-19.113 -13.922,-29.062 -2.447,-7.979 -2.7,-10.307 -2.754,-25.288003 -0.065,-18.287 0.974,-23.978 6.985,-38.248 11.6,-27.537 41.822,-53.2229997 66.951,-56.9029997 17.627,-2.58 39.898,-2.083 54.386,1.217 11.81,2.69 30.942,14.2249997 44.057,26.5619997 15.396,14.484 23.147,26.045 81.04,120.872003 68.315,111.898 76.461,125.692 77.628,131.443 1.155,5.692 0.319,8.097 -2.79,8.027 -2.589,-0.058 -1.805,0.745 -124.8,-127.97 -10.774,-11.275 -29.537,-31.075 -41.694,-44 -31.729,-33.731003 -44.894,-46.440003 -50.863,-49.098003 -7.641,-3.404 -18.242,-3.248 -25.625,0.378 -14.476,7.109 -21.328,23.505 -15.867,37.970003 2.708,7.171 -1.064,3.061 87.873,95.75 39.844,41.525 75.834,79.55 79.979,84.5 66.885,79.884 61.447,198.583 -12.46,271.993 -16.97,16.855 -33.934,28.403 -65.364,44.493 -10.725,5.49 -20.962,10.883 -22.75,11.984 l -3.25,2 v 257.934 c 0,141.86307 -0.273,258.64407 -0.607,259.51407 -0.703,1.833 -1.03,1.835 -4.393,0.024 z m -177.63,-500.38507 c 87.548,-44.936 105.617,-54.442 108.183,-56.912 1.61,-1.548 2.312,-3.78 2.792,-8.857 0.969,-10.263 0.782,-118.091 -0.206,-118.702 -2.176,-1.345 -38.95,31.338 -63.639,56.56 -42.682,43.6 -78.365,92.834 -107.7,148.595 -3.836,7.292 -6.656,13.259 -6.267,13.259 0.389,0 30.467,-15.274 66.838,-33.943 z"
/>
</svg>
</template>
<script>
export default {
name: "MinioIcon",
};
</script>
<style scoped></style>
+43
View File
@@ -0,0 +1,43 @@
<template>
<svg
viewBox="0 0 512 512"
width="512"
height="512"
>
<g id="g861" transform="translate(0 -540.36)">
<g style="fill: #ffffff" id="g841" transform="matrix(6.1195921,0,0,6.1195921,-464.85522,-1122.4443)">
<path
id="path839"
fill="#ffffff"
d="m 120.6731,296.55103 c -2.3846,0 -4.3789,2.0376 -4.3789,4.4222 v 0.77344 c -2.2304,0.10995 -4.0388,0.5467 -5.3281,1.4316 -1.5951,1.0948 -2.4675,2.582 -3.1816,3.877 -0.71415,1.295 -1.2996,2.4093 -2.1504,3.1894 -0.72545,0.66525 -1.7997,1.1216 -3.4512,1.3301 -0.21359,-2.192 -2.0615,-3.9512 -4.305197,-3.9512 h -17.167 c -2.3846,0 -4.4165,1.965 -4.4165,4.3496 v 4.2422 c 0,2.3846 2.0319,4.3516 4.4165,4.3516 h 17.167 c 2.384597,0 4.387197,-1.9669 4.387197,-4.3516 v -1.6133 c 9.7257,0.15307 12.467,2.6032 15.594,5.3379 3.0006,2.6241 6.6658,5.3789 15.436,5.4948 v 0.73633 c 0,2.3846 2.0695,4.3799 4.4541,4.3799 h 17.092 c 2.3846,0 4.4541,-1.9952 4.4541,-4.3799 v -4.2422 c 0,-2.3846 -2.0695,-4.3779 -4.4541,-4.3779 h -17.092 c -2.3846,0 -4.4541,1.9933 -4.4541,4.3779 v 0.58594 c -8.0984,-0.0599 -10.486,-2.1557 -13.498,-4.7897 -2.5035,-2.1893 -5.6398,-4.5852 -11.947,-5.5859 1.176,-1.1795 1.8834,-2.5192 2.5137,-3.6621 0.67724,-1.228 1.2899,-2.2006 2.2695,-2.873 0.76303,-0.52371 1.9757,-0.83922 3.6621,-0.93945 v 0.55078 c 0,2.3846 1.9943,4.3356 4.3789,4.3356 h 17.242 c 2.3846,0 4.3789,-1.951 4.3789,-4.3356 v -4.2422 c 0,-2.3846 -1.9943,-4.4222 -4.3789,-4.4222 z m 0,3 h 17.242 c 0.80513,0 1.3789,0.6171 1.3789,1.4222 v 4.2422 c 0,0.80514 -0.57378,1.3356 -1.3789,1.3356 h -17.242 c -0.80513,0 -1.3789,-0.53045 -1.3789,-1.3356 v -4.2422 c 0,-0.80513 0.57378,-1.4222 1.3789,-1.4222 z m -39.961997,11.016 h 17.167 c 0.80513,0 1.4165,0.60112 1.4165,1.4062 v 4.2422 c 0,0.80513 -0.61138,1.4082 -1.4165,1.4082 h -17.167 c -0.80513,0 -1.4165,-0.60307 -1.4165,-1.4082 v -4.2422 c 0,-0.80513 0.61137,-1.4062 1.4165,-1.4062 z m 57.037997,9.984 h 17.092 c 0.80513,0 1.4541,0.5728 1.4541,1.3779 v 4.168 c 0,0.80513 -0.64898,1.4541 -1.4541,1.4541 h -17.092 c -0.80513,0 -1.4541,-0.64897 -1.4541,-1.4541 v -4.168 c 0,-0.80513 0.64897,-1.3779 1.4541,-1.3779 z"
style="
color: #000000;
text-indent: 0;
text-decoration: none;
text-decoration-line: none;
text-decoration-style: solid;
text-decoration-color: #000000;
text-transform: none;
white-space: normal;
isolation: auto;
mix-blend-mode: normal;
solid-color: #000000;
fill: #ffffff;
color-rendering: auto;
image-rendering: auto;
shape-rendering: auto;
"
/>
</g>
<g id="g859" fill="#8f0000" transform="matrix(1.0024 0 0 1.0024 .26914 -2.6855)" />
</g>
</svg>
</template>
<script>
export default {
name: "NodeRedIcon",
};
</script>
<style scoped></style>
@@ -0,0 +1,64 @@
<template>
<v-list-item link dense>
<v-list-item-content @click="goto">
<v-list-item-title class="d-flex">
<v-icon small class="mr-1">mdi-gauge</v-icon>
<span class="text-truncate">{{ artifact.name }}</span>
</v-list-item-title>
<v-list-item-subtitle class="d-flex">
<v-icon small class="mr-1" :color="statusColor">{{ statusIcon }}</v-icon>
<span :class="statusColor + '--text'">{{ artifact.status | capitalize }}</span>
<v-spacer></v-spacer>
<v-icon small class="mr-1">mdi-information</v-icon>
<span class="mr-1">{{ artifact.enrichments ? lodash.size(artifact.enrichments) : 0 }}</span>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action v-if="action !== ''">
<v-btn icon small>
<v-icon small @click="actionClick">{{ action }}</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</template>
<script lang="ts">
import Vue from "vue";
import {Type, TypeColorEnum} from "../../client";
export default Vue.extend({
name: "ArtifactSnippet",
props: ["artifact", "to", "action"],
computed: {
statusIcon: function () {
let icon = "mdi-help";
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
if (this.artifact.status === state.id) {
icon = state.icon;
}
})
return icon;
},
statusColor: function () {
let color = TypeColorEnum.Info;
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
if (this.artifact.status === state.id && state.color) {
color = state.color
}
})
return color;
}
},
methods: {
actionClick: function () {
this.$emit("actionClick", this.artifact)
},
goto: function () {
this.$emit("click", this.artifact)
if (this.to) {
this.$router.push(this.to);
}
}
}
});
</script>
+60
View File
@@ -0,0 +1,60 @@
<template>
<div>
<TicketSnippet v-if="ticket !== undefined" :ticket="ticket" :to="{ name: 'Ticket', params: { type: ticket.type, id: ticket.id } }"></TicketSnippet>
<ArtifactSnippet v-if="artifact !== undefined" :artifact="artifact" :to="{ name: 'Artifact', params: { artifact: artifact.name } }"></ArtifactSnippet>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import {Artifact, TicketResponse} from "../../client";
import {API} from "@/services/api";
import TicketSnippet from "./TicketSnippet.vue";
import ArtifactSnippet from "./ArtifactSnippet.vue";
interface State {
ticket?: TicketResponse;
artifact?: Artifact;
}
export default Vue.extend({
name: "IDSnippet",
props: ["id"],
data: (): State => ({
ticket: undefined,
artifact: undefined,
}),
components: {
ArtifactSnippet,
TicketSnippet
},
methods: {
loadSnippet() {
if (this.id.startsWith("tickets/")) {
this.artifact = undefined;
let ticketID = this.id.replace("tickets/", "")
API.getTicket(ticketID).then(response => {
this.ticket = response.data;
});
}
if (this.id.startsWith("artifacts/")) {
this.ticket = undefined;
// TODO
// let artifactID = this.id.replace("artifacts/", "")
// API.getArtifact(artifactID).then(response => {
// this.artifact = response.data;
// });
}
}
},
watch: {
"id": "loadSnippet",
$route: "loadSnippet"
},
mounted() {
this.loadSnippet();
}
});
</script>
<style scoped></style>
@@ -0,0 +1,91 @@
<template>
<v-list-item link dense>
<v-list-item-content @click="goto">
<v-list-item-title class="d-flex">
<v-icon small class="mr-1">{{ typeIcon }}</v-icon>
<span class="text-truncate">{{ ticket.type | capitalize }} #{{ ticket.id }}: {{ ticket.name }}</span>
<v-spacer></v-spacer>
<v-icon small class="mr-1">mdi-calendar-plus</v-icon>
{{ ticket.created | formatdate($store.state.settings.timeformat) }}
</v-list-item-title>
<v-list-item-subtitle class="d-flex">
<v-icon small class="mr-1" :color="statusColor">{{ statusIcon }}</v-icon>
<span :class="statusColor + '--text'">{{ ticket.status | capitalize }}</span>
<v-icon small class="mx-1">mdi-account</v-icon>
{{ ticket.owner ? ticket.owner : 'unassigned' }}
<v-spacer></v-spacer>
<v-icon small class="mr-1">mdi-source-branch</v-icon>
<span class="mr-1">{{ ticket.playbooks ? lodash.size(ticket.playbooks) : 0 }}</span>
<v-icon small class="mr-1">mdi-checkbox-multiple-marked-outline</v-icon>
<span class="mr-1">{{ opentaskcount }}</span>
<v-icon small class="mr-1">mdi-comment</v-icon>
<span class="mr-1">{{ ticket.comments ? ticket.comments.length : 0 }}</span>
<v-icon small class="mr-1">mdi-file</v-icon>
<span class="mr-1">{{ ticket.files ? ticket.files.length : 0 }}</span>
<v-icon small class="mr-1">mdi-link</v-icon>
<span class="mr-1">{{ ticket.references ? ticket.references.length : 0 }}</span>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action v-if="action !== ''">
<v-btn icon small>
<v-icon small @click="actionClick">{{ action }}</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</template>
<script lang="ts">
import Vue from "vue";
import {Playbook, Task, Type, TypeColorEnum} from "@/client";
export default Vue.extend({
name: "TicketSnippet",
props: ["ticket", "to", "action"],
computed: {
opentaskcount: function() {
let count = 0;
this.lodash.forEach(this.ticket.playbooks, (playbook: Playbook) => {
this.lodash.forEach(playbook.tasks, (task: Task) => {
if (task.done) {
count++;
}
})
})
return count;
},
typeIcon: function () {
let icon = "mdi-help";
this.lodash.forEach(this.$store.state.settings.ticketTypes, (ticketType: Type) => {
if (this.ticket.type === ticketType.id) {
icon = ticketType.icon
}
})
return icon;
},
statusIcon: function() {
if (this.ticket.status === 'closed') {
return "mdi-checkbox-marked-circle-outline";
}
return "mdi-arrow-right-drop-circle-outline";
},
statusColor: function() {
if (this.ticket.status === 'closed') {
return TypeColorEnum.Success;
}
return TypeColorEnum.Info;
},
},
methods: {
actionClick: function () {
this.$emit("actionClick", this.ticket)
},
goto: function () {
if (this.to === undefined) {
return
}
this.$router.push(this.to);
}
}
});
</script>
+86
View File
@@ -0,0 +1,86 @@
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import JsonSchemaEditor from "json-schema-editor-vue";
import vuetify from "./plugins/vuetify";
import VuePipeline from "vue-pipeline";
import VueLodash from "vue-lodash";
import lodash from "lodash";
import axios from "axios";
import { DateTime } from 'luxon';
import VueNativeSock from 'vue-native-websocket';
import antInputDirective from 'ant-design-vue/es/_util/antInputDirective'
import antDirective from 'ant-design-vue/es/_util/antDirective'
import VueAxios from "vue-axios";
import VueLuxon from "vue-luxon";
import "./registerServiceWorker";
import "json-schema-editor-vue/lib/json-schema-editor-vue.css";
import "@mdi/font/css/materialdesignicons.css";
import "vue-d3-network/dist/vue-d3-network.css";
import '@koumoul/vjsf/dist/main.css'
import { Problem } from "@/types/types";
Vue.use(VueLodash, { lodash: lodash });
Vue.use(antDirective);
Vue.use(antInputDirective);
Vue.use(JsonSchemaEditor);
Vue.use(VuePipeline);
Vue.use(VueAxios, axios);
Vue.use(VueLuxon);
// import VJsf from '@koumoul/vjsf'
import VJsf from '@koumoul/vjsf/lib/VJsf.js';
import '@koumoul/vjsf/lib/deps/third-party.js';
Vue.component('VJsf', VJsf)
Vue.config.productionTip = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Vue.filter("capitalize", function(value: any) {
if (!value) return "";
return lodash.startCase(value.toString());
});
Vue.filter("formatdate", function(s: string, format: string) {
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
});
let protocol = "ws"
if (location.protocol === "https:") {
protocol = "wss"
}
Vue.use(VueNativeSock, protocol + '://' + location.hostname + ':'+ location.port +'/wss', { store: store, format: 'json' })
const v = new Vue({
router,
vuetify,
store,
render: h => h(App)
}).$mount("#app");
axios.interceptors.response.use(
response => response,
error => {
console.log(error)
if (error.response.data && 'title' in error.response.data && 'detail' in error.response.data) {
const problem = error.response.data as Problem;
v.$store.dispatch("alertError", { name: problem.title, detail: problem.detail });
return Promise.reject(error);
}
if (error.response.data && 'error' in error.response.data) {
v.$store.dispatch("alertError", { name: "Error", detail: error.response.data.error });
return Promise.reject(error);
}
v.$store.dispatch("alertError", { name: "Error", detail: JSON.stringify(error.response.data) });
return Promise.reject(error);
}
);
+90
View File
@@ -0,0 +1,90 @@
import "@mdi/font/css/materialdesignicons.css";
import Vue from "vue";
import Vuetify from "vuetify/lib";
import MinioIcon from "../components/icons/MinioIcon.vue";
import NodeRedIcon from "../components/icons/NodeRedIcon.vue";
import ArangoIcon from "../components/icons/ArangoIcon.vue";
import EmitterIcon from "../components/icons/EmitterIcon.vue";
Vue.use(Vuetify);
export const colors = [
'#c62828', '#6a1b9a',
'#283593', '#0277bd',
'#00695c', '#558b2f',
'#f9a825', '#ef6c00',
'#ad1457', '#4527a0',
'#1565c0', '#00838f',
'#2e7d32', '#9e9d24',
'#ff8f00', '#d84315',
]
export default new Vuetify({
theme: {
dark: false,
themes: {
light: {
statusbar: "#212121", // "#1c313a",
appbar: "#eeeeee", //'#28282e',
background: "#f5f5f5", //'#393a3f',
cards: "#e0e0e0", //'#393a3f',
primary: "#607d8b",
yellow: "#FFC107", // "#FFEB3B",
error: "#C62828", // "#d32f2f",
info: "#1565C0", // "#2196F3",
success: "#2E7D32", // "#689f38",
warning: "#D84315", // "#fbc02d",
red: "#C62828", // "#d32f2f",
},
dark: {
// statusbar: "#d35400",
// statusbar: "#f03f24", //'#18181c', 240 63 36
// appbar: "#212121", //'#28282e',
// background: "#303030", //'#393a3f',
// cards: "#424242", //'#393a3f',
statusbar: "#121212",
appbar: "#212121", //'#28282e',
background: "#303030", //'#393a3f',
cards: "#424242", //'#393a3f',
// alertmanager: "#ef6c00",
// catalyst: "#ad1457",
// blocklist: "#2e7d32",
// uploadportal: "#283593",
// search: "#c62828",
// darksteel: "#1c313a",
// steel: "#455a64",
// lightsteel: "#718792",
primary: "#FFC107", // "#00bcd4", // "#FFEB3B",
yellow: "#FFC107", // "#FFEB3B",
// accent: "#82B1FF",
error: "#ef9a9a", // "#d32f2f",
info: "#90caf9", // "#2196F3",
success: "#a5d6a7", // "#689f38",
warning: "#ffab91", // "#fbc02d",
red: "#C62828", // "#d32f2f",
},
},
},
icons: {
values: {
minio: {
component: MinioIcon,
},
nodered: {
component: NodeRedIcon,
},
arango: {
component: ArangoIcon,
},
emitter: {
component: EmitterIcon,
},
},
},
});
+34
View File
@@ -0,0 +1,34 @@
/* eslint-disable no-console */
import { register } from "register-service-worker";
if (process.env.NODE_ENV === "production") {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log(
"App is being served from cache by a service worker.\n" +
"For more details, visit https://goo.gl/AFskqB"
);
},
registered() {
console.log("Service worker has been registered.");
},
cached() {
console.log("Content has been cached for offline use.");
},
updatefound() {
console.log("New content is downloading.");
},
updated() {
console.log("New content is available; please refresh.");
},
offline() {
console.log(
"No internet connection found. App is running in offline mode."
);
},
error(error) {
console.error("Error during service worker registration:", error);
},
});
}
+236
View File
@@ -0,0 +1,236 @@
import Vue from "vue";
import VueRouter, { RouteConfig, RawLocation, Route } from "vue-router";
import ArtifactPopup from "../views/ArtifactPopup.vue";
import Ticket from "../views/Ticket.vue";
import TicketNew from "../views/TicketNew.vue";
import TicketList from "../views/TicketList.vue";
import Graph from "../views/Graph.vue";
import Playbook from "../views/Playbook.vue";
import PlaybookList from "../views/PlaybookList.vue";
import Automation from "../views/Automation.vue";
import UserData from "../views/UserData.vue";
import Profile from "../views/Profile.vue";
import UserDataList from "../views/UserDataList.vue";
import AutomationList from "../views/AutomationList.vue";
import Rule from "../views/Rule.vue";
import RuleList from "../views/RuleList.vue";
import Template from "../views/Template.vue";
import TemplateList from "../views/TemplateList.vue";
import API from "../views/API.vue";
import User from '../views/User.vue';
import UserList from "@/views/UserList.vue";
import Job from '../views/Job.vue';
import JobList from "@/views/JobList.vue";
import GroupList from "@/views/GroupList.vue";
import Dashboard from "@/views/Dashboard.vue";
import Group from "@/views/Group.vue";
import TicketType from '../views/TicketType.vue';
import TicketTypeList from "@/views/TicketTypeList.vue";
import TaskList from "@/views/TaskList.vue";
Vue.use(VueRouter);
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location: RawLocation): Promise<Route> {
return new Promise((resolve, reject) => {
originalPush.call(this, location, () => {
// on complete
resolve(this.currentRoute);
}, (error) => {
// on abort
// only ignore NavigationDuplicated error
if (error.name === 'NavigationDuplicated') {
resolve(this.currentRoute);
} else {
reject(error);
}
});
});
};
const routes: Array<RouteConfig> = [
{
path: "/",
name: "Catalyst",
redirect: { name: "Dashboard" },
},
{
path: "/dashboard",
name: "Dashboard",
component: Dashboard,
},
{
path: "/profile",
name: "Profile",
component: Profile,
},
{
path: "/tickets/:type?",
name: "TicketList",
component: TicketList,
props: true,
},
{
path: "/tickets/:type?/:id",
name: "Ticket",
component: Ticket,
},
{
path: "/tickets/:type/new",
name: "TicketNew",
component: TicketNew,
},
{
path: "/tickets/:type?/:id/artifact/:artifact",
name: "ArtifactPopup",
component: ArtifactPopup,
},
{
path: "/tasks",
name: "TaskList",
component: TaskList,
},
{
path: "/templates",
name: "TemplateList",
component: TemplateList,
children: [
{
path: ":id",
name: "Template",
component: Template,
},
]
},
{
path: "/tickettype",
name: "TicketTypeList",
component: TicketTypeList,
children: [
{
path: ":id",
name: "TicketType",
component: TicketType,
},
]
},
{
path: "/playbooks",
name: "PlaybookList",
component: PlaybookList,
children: [
{
path: ":id",
name: "Playbook",
component: Playbook,
},
]
},
{
path: "/userdata",
name: "UserDataList",
component: UserDataList,
children: [
{
path: ":id",
name: "UserData",
component: UserData,
},
]
},
{
path: "/jobs",
name: "JobList",
component: JobList,
children: [
{
path: ":id",
name: "Job",
component: Job,
},
]
},
{
path: "/automations",
name: "AutomationList",
component: AutomationList,
children: [
{
path: ":id",
name: "Automation",
component: Automation,
},
]
},
{
path: "/rules",
name: "RuleList",
component: RuleList,
children: [
{
path: ":id",
name: "Rule",
component: Rule,
},
]
},
{
path: "/users",
name: "UserList",
component: UserList,
children: [
{
path: ":id",
name: "User",
component: User,
},
]
},
{
path: "/groups",
name: "GroupList",
component: GroupList,
children: [
{
path: ":id",
name: "Group",
component: Group,
},
]
},
{
path: "/apidocs",
name: "API",
component: API,
},
{
path: "/graph/:col/:id",
name: "Graph",
component: Graph,
},
];
const router = new VueRouter({
mode: 'history',
routes,
});
export default router;
+29
View File
@@ -0,0 +1,29 @@
// Globals
// $body-font-family: 'Work Sans', serif;
$border-radius-root: 6px;
$font-size-root: 14px;
// Variables must come before the import
$btn-letter-spacing: 0;
$btn-font-weight: 400;
$list-item-title-font-size: 0.929rem;
$list-item-dense-title-font-size: 0.929rem;
$list-item-dense-title-font-weight: initial;
$fab-icon-sizes: (
'small': 20
);
$btn-sizes: (
'default': 41,
'large': 54
);
$headings: (
'h1': (
'size': 3.3125rem,
'line-height': 1.15em
),
'h2': (
'size': 2.25rem,
'line-height': 1.5em
)
);
+78
View File
@@ -0,0 +1,78 @@
import {
UserdataApi,
UserdataApiFactory,
AutomationsApi,
AutomationsApiFactory,
Configuration,
GraphApi,
GraphApiFactory,
GroupsApi,
GroupsApiFactory,
LogsApi,
LogsApiFactory,
PlaybooksApi,
PlaybooksApiFactory,
RulesApi,
RulesApiFactory,
StatisticsApi,
StatisticsApiFactory,
TasksApi,
TasksApiFactory,
TemplatesApi,
TemplatesApiFactory,
TicketsApi,
TicketsApiFactory,
TickettypesApi,
TickettypesApiFactory,
UsersApi,
UsersApiFactory,
SettingsApi,
SettingsApiFactory,
JobsApi,
JobsApiFactory,
} from "@/client";
const config = new Configuration({
basePath:
window.location.protocol +
"//" +
window.location.hostname +
":" +
window.location.port +
"/api"
});
export const API: TicketsApi &
TemplatesApi &
PlaybooksApi &
RulesApi &
AutomationsApi &
UserdataApi &
LogsApi &
GraphApi &
UsersApi &
GroupsApi &
StatisticsApi &
SettingsApi &
TickettypesApi &
JobsApi &
TasksApi = Object.assign(
{},
TicketsApiFactory(config),
PlaybooksApiFactory(config),
TemplatesApiFactory(config),
RulesApiFactory(config),
AutomationsApiFactory(config),
SettingsApiFactory(config),
LogsApiFactory(config),
GraphApiFactory(config),
UsersApiFactory(config),
UserdataApiFactory(config),
GroupsApiFactory(config),
StatisticsApiFactory(config),
SettingsApiFactory(config),
TickettypesApiFactory(config),
TasksApiFactory(config),
SettingsApiFactory(config),
JobsApiFactory(config)
);
+13
View File
@@ -0,0 +1,13 @@
import Vue, { VNode } from "vue";
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
+22
View File
@@ -0,0 +1,22 @@
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
declare module "v-jsoneditor/src/index";
declare module "@koumoul/vjsf";
declare module "@koumoul/vjsf/lib/VJsf.js";
declare module "vue-pipeline";
declare module "json-schema-editor-vue";
declare module "vue-json-to-html";
declare module "vue-d3-network";
declare module "vue-luxon";
declare module 'swagger-ui';
declare module 'prismjs/components/prism-core';
declare module 'vue-native-websocket';
declare module 'antlr4';
declare module 'vue-cropperjs';
declare module 'graphlib';
declare module 'ant-design-vue/es/_util/antInputDirective';
declare module 'flat';
declare module 'crypto';
+104
View File
@@ -0,0 +1,104 @@
import Vue from "vue";
import Vuex, {ActionContext} from "vuex";
import {API} from "@/services/api";
import {UserData, TicketList, Settings, UserResponse} from "@/client";
import {AxiosResponse} from "axios";
import {Alert} from "@/types/types";
import {templateStore} from "./modules/templates";
import {socketStore} from "@/store/modules/socket";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
templates: templateStore,
socket: socketStore,
},
state: {
user: {} as UserResponse,
counts: {} as Record<string, number>,
task_count: 0 as number,
settings: {} as Settings,
userdata: {} as UserData,
alert: {} as Alert,
showAlert: false as boolean,
},
getters: {
timeformat: (state) => {
if ('timeformat' in state.settings && state.settings.timeformat) {
return state.settings.timeformat
}
return 'dd-MM-yyyy'
}
},
mutations: {
setUser (state, msg) {
state.user = msg;
},
setCount (state, msg) {
Vue.set(state.counts, msg.name, msg.count);
},
setTaskCount (state, msg) {
state.task_count = msg;
},
setUserData (state, msg: UserData) {
state.userdata = msg
},
setSettings (state, msg: Settings) {
state.settings = msg
},
setAlert (state, msg: Alert) {
state.showAlert = false;
state.showAlert = true;
state.alert = msg;
}
},
actions: {
getUser (context: ActionContext<any, any>) {
API.currentUser().then((response) => {
context.commit("setUser", response.data);
context.dispatch("fetchCount");
})
},
getUserData (context: ActionContext<any, any>) {
API.currentUserData().then((response: AxiosResponse<UserData>) => {
context.commit("setUserData", response.data);
})
},
getSettings (context: ActionContext<any, any>) {
API.getSettings().then((response: AxiosResponse<Settings>) => {
context.commit("setSettings", response.data);
context.dispatch("fetchCount");
})
},
fetchCount (context: ActionContext<any, any>) {
if (!context.state.user.id || !context.state.settings.ticketTypes) {
return
}
const username = context.state.user.id;
Vue.lodash.forEach(context.state.settings.ticketTypes, (t) => {
API.listTickets(t.id,0,10,[],[], "status == 'open' AND (owner == '"+username+"' OR !owner)")
.then((response: AxiosResponse<TicketList>) => {
context.commit("setCount", {"name": t.id, "count": response.data.count});
});
API.listTasks().then((response) => {
if (response.data) {
context.commit("setTaskCount", response.data.length );
}
})
})
},
alertSuccess(context: ActionContext<any, any>, msg) {
msg.type = "success"
context.commit("setAlert", msg)
},
alertError(context: ActionContext<any, any>, msg) {
msg.type = "error"
context.commit("setAlert", msg)
},
},
});
+64
View File
@@ -0,0 +1,64 @@
import Vue from "vue";
import Vuex, {ActionContext} from "vuex";
import lodash from "lodash";
Vue.use(Vuex);
interface State {
socket: any;
}
export const socketStore = {
state: (): State => ({
socket: {
isConnected: false,
message: '',
reconnectError: false,
}
}),
mutations: {
SOCKET_ONOPEN (state: State, event: any) {
// console.log("SOCKET_ONOPEN");
Vue.prototype.$socket = event.currentTarget;
state.socket.isConnected = true;
},
SOCKET_ONCLOSE (state: State, event: any) {
// console.log("SOCKET_ONCLOSE");
state.socket.isConnected = false;
},
SOCKET_ONERROR (state: State, event: any) {
// console.log("SOCKET_ONERROR");
console.error(state, event);
},
// default handler called for all methods
SOCKET_ONMESSAGE (state: State, message: any) {
// console.log("SOCKET_ONMESSAGE");
state.socket.message = message;
},
// mutations for reconnect methods
SOCKET_RECONNECT(state: State, count: any) {
// console.log("SOCKET_RECONNECT");
console.info(state, count);
},
SOCKET_RECONNECT_ERROR(state: State) {
// console.log("SOCKET_RECONNECT_ERROR");
state.socket.reconnectError = true;
},
},
actions: {
sendMessage: function(context: ActionContext<any, any>, msg: any) {
Vue.prototype.$socket.send(msg);
},
update: function (context: ActionContext<any, any>, msg: any) {
// console.log("update", msg);
if (!msg || !(lodash.has(msg, "ids")) || !msg["ids"]) {
return
}
Vue.lodash.forEach(msg["ids"], (id) => {
if (lodash.startsWith(id, "settings/")) {
context.dispatch("getSetting")
}
});
}
}
}
+75
View File
@@ -0,0 +1,75 @@
import Vue from "vue";
import Vuex, {ActionContext} from "vuex";
import {TicketTemplate} from "@/client";
import {API} from "@/services/api";
import {AxiosResponse} from "axios";
Vue.use(Vuex);
interface State {
templates: Array<TicketTemplate>;
}
export const templateStore = {
state: (): State => ({
templates: [],
}),
mutations: {
setTemplates(state: State, msg: Array<TicketTemplate>) {
state.templates = msg;
},
},
actions: {
listTemplates(context: ActionContext<any, any>) {
API.listTemplates().then((response: AxiosResponse<Array<TicketTemplate>>) => {
context.commit("setTemplates", response.data)
});
},
getTemplate(context: ActionContext<any, any>, id: string) {
return new Promise((resolve) => {
API.getTemplate(id).then((response: AxiosResponse<TicketTemplate>) => {
resolve(response.data);
}).catch(error => {
context.dispatch("alertError", {name: "Template could not be loaded", details: error});
});
});
},
addTemplate(context: ActionContext<any, any>, template: TicketTemplate) {
return new Promise((resolve) => {
API.createTemplate(template).then(() => {
context.dispatch("listTemplates").then(() => {
context.dispatch("alertSuccess", {name: "Template created"}).then(() => {
resolve({})
});
}).catch(error => {
context.dispatch("alertError", {name: "Template created, but reload failed", details: error});
});
}).catch(error => {
context.dispatch("alertError", {name: "Template could not be created", details: error});
});
});
},
updateTemplate(context: ActionContext<any, any>, msg: any) {
API.updateTemplate(msg.id, msg.template).then(() => {
context.dispatch("alertSuccess", {name: "Template updated"});
}).catch(error => {
context.dispatch("alertError", {name: "Template could not be updated", details: error});
});
},
deleteTemplate(context: ActionContext<any, any>, id: string) {
return new Promise((resolve) => {
API.deleteTemplate(id).then(() => {
context.dispatch("listTemplates").then(() => {
context.dispatch("alertSuccess", {name: "Template deleted"}).then(() => {
resolve({});
});
}).catch(error => {
context.dispatch("alertError", {name: "Template deleted, but reload failed", details: error});
});
}).catch(error => {
context.dispatch("alertError", {name: "Template could not be deleted", details: error});
});
});
},
}
}
+282
View File
@@ -0,0 +1,282 @@
token literal names:
null
'.'
'=~'
'!~'
'=='
'!='
'<'
'>'
'<='
'>='
'+'
'-'
'*'
'/'
'%'
'?'
':'
'::'
'..'
','
'('
')'
'{'
'}'
'['
']'
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
token symbolic names:
null
DOT
T_REGEX_MATCH
T_REGEX_NON_MATCH
T_EQ
T_NE
T_LT
T_GT
T_LE
T_GE
T_PLUS
T_MINUS
T_TIMES
T_DIV
T_MOD
T_QUESTION
T_COLON
T_SCOPE
T_RANGE
T_COMMA
T_OPEN
T_CLOSE
T_OBJECT_OPEN
T_OBJECT_CLOSE
T_ARRAY_OPEN
T_ARRAY_CLOSE
T_AGGREGATE
T_ALL
T_AND
T_ANY
T_ASC
T_COLLECT
T_DESC
T_DISTINCT
T_FALSE
T_FILTER
T_FOR
T_GRAPH
T_IN
T_INBOUND
T_INSERT
T_INTO
T_K_SHORTEST_PATHS
T_LET
T_LIKE
T_LIMIT
T_NONE
T_NOT
T_NULL
T_OR
T_OUTBOUND
T_REMOVE
T_REPLACE
T_RETURN
T_SHORTEST_PATH
T_SORT
T_TRUE
T_UPDATE
T_UPSERT
T_WITH
T_KEEP
T_COUNT
T_OPTIONS
T_PRUNE
T_SEARCH
T_TO
T_CURRENT
T_NEW
T_OLD
T_STRING
T_INT
T_FLOAT
T_PARAMETER
T_QUOTED_STRING
SINGLE_LINE_COMMENT
MULTILINE_COMMENT
SPACES
UNEXPECTED_CHAR
ERROR_RECONGNIGION
rule names:
DOT
T_REGEX_MATCH
T_REGEX_NON_MATCH
T_EQ
T_NE
T_LT
T_GT
T_LE
T_GE
T_PLUS
T_MINUS
T_TIMES
T_DIV
T_MOD
T_QUESTION
T_COLON
T_SCOPE
T_RANGE
T_COMMA
T_OPEN
T_CLOSE
T_OBJECT_OPEN
T_OBJECT_CLOSE
T_ARRAY_OPEN
T_ARRAY_CLOSE
T_AGGREGATE
T_ALL
T_AND
T_ANY
T_ASC
T_COLLECT
T_DESC
T_DISTINCT
T_FALSE
T_FILTER
T_FOR
T_GRAPH
T_IN
T_INBOUND
T_INSERT
T_INTO
T_K_SHORTEST_PATHS
T_LET
T_LIKE
T_LIMIT
T_NONE
T_NOT
T_NULL
T_OR
T_OUTBOUND
T_REMOVE
T_REPLACE
T_RETURN
T_SHORTEST_PATH
T_SORT
T_TRUE
T_UPDATE
T_UPSERT
T_WITH
T_KEEP
T_COUNT
T_OPTIONS
T_PRUNE
T_SEARCH
T_TO
T_CURRENT
T_NEW
T_OLD
T_STRING
T_INT
T_FLOAT
T_PARAMETER
T_QUOTED_STRING
SINGLE_LINE_COMMENT
MULTILINE_COMMENT
SPACES
UNEXPECTED_CHAR
HEX_DIGIT
DIGIT
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
ERROR_RECONGNIGION
channel names:
DEFAULT_TOKEN_CHANNEL
HIDDEN
null
null
ERRORCHANNEL
mode names:
DEFAULT_MODE
atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 80, 739, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 4, 78, 9, 78, 4, 79, 9, 79, 4, 80, 9, 80, 4, 81, 9, 81, 4, 82, 9, 82, 4, 83, 9, 83, 4, 84, 9, 84, 4, 85, 9, 85, 4, 86, 9, 86, 4, 87, 9, 87, 4, 88, 9, 88, 4, 89, 9, 89, 4, 90, 9, 90, 4, 91, 9, 91, 4, 92, 9, 92, 4, 93, 9, 93, 4, 94, 9, 94, 4, 95, 9, 95, 4, 96, 9, 96, 4, 97, 9, 97, 4, 98, 9, 98, 4, 99, 9, 99, 4, 100, 9, 100, 4, 101, 9, 101, 4, 102, 9, 102, 4, 103, 9, 103, 4, 104, 9, 104, 4, 105, 9, 105, 4, 106, 9, 106, 4, 107, 9, 107, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 5, 29, 294, 10, 29, 3, 30, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 5, 48, 414, 10, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 5, 50, 426, 10, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 3, 64, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 70, 3, 70, 7, 70, 555, 10, 70, 12, 70, 14, 70, 558, 11, 70, 3, 71, 3, 71, 7, 71, 562, 10, 71, 12, 71, 14, 71, 565, 11, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 572, 10, 71, 13, 71, 14, 71, 573, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 580, 10, 71, 13, 71, 14, 71, 581, 5, 71, 584, 10, 71, 3, 72, 3, 72, 7, 72, 588, 10, 72, 12, 72, 14, 72, 591, 11, 72, 3, 72, 5, 72, 594, 10, 72, 3, 72, 3, 72, 6, 72, 598, 10, 72, 13, 72, 14, 72, 599, 3, 72, 3, 72, 5, 72, 604, 10, 72, 3, 72, 6, 72, 607, 10, 72, 13, 72, 14, 72, 608, 5, 72, 611, 10, 72, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 7, 74, 622, 10, 74, 12, 74, 14, 74, 625, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 7, 74, 634, 10, 74, 12, 74, 14, 74, 637, 11, 74, 3, 74, 5, 74, 640, 10, 74, 3, 75, 3, 75, 3, 75, 3, 75, 7, 75, 646, 10, 75, 12, 75, 14, 75, 649, 11, 75, 3, 75, 5, 75, 652, 10, 75, 3, 75, 3, 75, 5, 75, 656, 10, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 76, 3, 76, 7, 76, 664, 10, 76, 12, 76, 14, 76, 667, 11, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 78, 3, 78, Line truncated
+607
View File
@@ -0,0 +1,607 @@
// Generated from CAQLLexer.g4 by ANTLR 4.9.2
// jshint ignore: start
import antlr4 from 'antlr4';
const serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786",
"\u5964\u0002P\u02e3\b\u0001\u0004\u0002\t\u0002\u0004\u0003\t\u0003",
"\u0004\u0004\t\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007",
"\t\u0007\u0004\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004",
"\f\t\f\u0004\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010",
"\t\u0010\u0004\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013",
"\u0004\u0014\t\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017",
"\t\u0017\u0004\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a",
"\u0004\u001b\t\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e",
"\t\u001e\u0004\u001f\t\u001f\u0004 \t \u0004!\t!\u0004\"\t\"\u0004#",
"\t#\u0004$\t$\u0004%\t%\u0004&\t&\u0004\'\t\'\u0004(\t(\u0004)\t)\u0004",
"*\t*\u0004+\t+\u0004,\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u0004",
"1\t1\u00042\t2\u00043\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u0004",
"8\t8\u00049\t9\u0004:\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004",
"?\t?\u0004@\t@\u0004A\tA\u0004B\tB\u0004C\tC\u0004D\tD\u0004E\tE\u0004",
"F\tF\u0004G\tG\u0004H\tH\u0004I\tI\u0004J\tJ\u0004K\tK\u0004L\tL\u0004",
"M\tM\u0004N\tN\u0004O\tO\u0004P\tP\u0004Q\tQ\u0004R\tR\u0004S\tS\u0004",
"T\tT\u0004U\tU\u0004V\tV\u0004W\tW\u0004X\tX\u0004Y\tY\u0004Z\tZ\u0004",
"[\t[\u0004\\\t\\\u0004]\t]\u0004^\t^\u0004_\t_\u0004`\t`\u0004a\ta\u0004",
"b\tb\u0004c\tc\u0004d\td\u0004e\te\u0004f\tf\u0004g\tg\u0004h\th\u0004",
"i\ti\u0004j\tj\u0004k\tk\u0003\u0002\u0003\u0002\u0003\u0003\u0003\u0003",
"\u0003\u0003\u0003\u0004\u0003\u0004\u0003\u0004\u0003\u0005\u0003\u0005",
"\u0003\u0005\u0003\u0006\u0003\u0006\u0003\u0006\u0003\u0007\u0003\u0007",
"\u0003\b\u0003\b\u0003\t\u0003\t\u0003\t\u0003\n\u0003\n\u0003\n\u0003",
"\u000b\u0003\u000b\u0003\f\u0003\f\u0003\r\u0003\r\u0003\u000e\u0003",
"\u000e\u0003\u000f\u0003\u000f\u0003\u0010\u0003\u0010\u0003\u0011\u0003",
"\u0011\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0013\u0003\u0013\u0003",
"\u0013\u0003\u0014\u0003\u0014\u0003\u0015\u0003\u0015\u0003\u0016\u0003",
"\u0016\u0003\u0017\u0003\u0017\u0003\u0018\u0003\u0018\u0003\u0019\u0003",
"\u0019\u0003\u001a\u0003\u001a\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
"\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
"\u001b\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001d\u0003",
"\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0005\u001d\u0126",
"\n\u001d\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001f",
"\u0003\u001f\u0003\u001f\u0003\u001f\u0003 \u0003 \u0003 \u0003 \u0003",
" \u0003 \u0003 \u0003 \u0003!\u0003!\u0003!\u0003!\u0003!\u0003\"\u0003",
"\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003#\u0003",
"#\u0003#\u0003#\u0003#\u0003#\u0003$\u0003$\u0003$\u0003$\u0003$\u0003",
"$\u0003$\u0003%\u0003%\u0003%\u0003%\u0003&\u0003&\u0003&\u0003&\u0003",
"&\u0003&\u0003\'\u0003\'\u0003\'\u0003(\u0003(\u0003(\u0003(\u0003(",
"\u0003(\u0003(\u0003(\u0003)\u0003)\u0003)\u0003)\u0003)\u0003)\u0003",
")\u0003*\u0003*\u0003*\u0003*\u0003*\u0003+\u0003+\u0003+\u0003+\u0003",
"+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003",
"+\u0003+\u0003+\u0003,\u0003,\u0003,\u0003,\u0003-\u0003-\u0003-\u0003",
"-\u0003-\u0003.\u0003.\u0003.\u0003.\u0003.\u0003.\u0003/\u0003/\u0003",
"/\u0003/\u0003/\u00030\u00030\u00030\u00030\u00030\u00050\u019e\n0\u0003",
"1\u00031\u00031\u00031\u00031\u00032\u00032\u00032\u00032\u00032\u0005",
"2\u01aa\n2\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u0003",
"3\u00034\u00034\u00034\u00034\u00034\u00034\u00034\u00035\u00035\u0003",
"5\u00035\u00035\u00035\u00035\u00035\u00036\u00036\u00036\u00036\u0003",
"6\u00036\u00036\u00037\u00037\u00037\u00037\u00037\u00037\u00037\u0003",
"7\u00037\u00037\u00037\u00037\u00037\u00037\u00038\u00038\u00038\u0003",
"8\u00038\u00039\u00039\u00039\u00039\u00039\u0003:\u0003:\u0003:\u0003",
":\u0003:\u0003:\u0003:\u0003;\u0003;\u0003;\u0003;\u0003;\u0003;\u0003",
";\u0003<\u0003<\u0003<\u0003<\u0003<\u0003=\u0003=\u0003=\u0003=\u0003",
"=\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003?\u0003?\u0003?\u0003",
"?\u0003?\u0003?\u0003?\u0003?\u0003@\u0003@\u0003@\u0003@\u0003@\u0003",
"@\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003B\u0003B\u0003",
"B\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003D\u0003",
"D\u0003D\u0003D\u0003E\u0003E\u0003E\u0003E\u0003F\u0003F\u0007F\u022b",
"\nF\fF\u000eF\u022e\u000bF\u0003G\u0003G\u0007G\u0232\nG\fG\u000eG\u0235",
"\u000bG\u0003G\u0003G\u0003G\u0003G\u0003G\u0006G\u023c\nG\rG\u000e",
"G\u023d\u0003G\u0003G\u0003G\u0003G\u0006G\u0244\nG\rG\u000eG\u0245",
"\u0005G\u0248\nG\u0003H\u0003H\u0007H\u024c\nH\fH\u000eH\u024f\u000b",
"H\u0003H\u0005H\u0252\nH\u0003H\u0003H\u0006H\u0256\nH\rH\u000eH\u0257",
"\u0003H\u0003H\u0005H\u025c\nH\u0003H\u0006H\u025f\nH\rH\u000eH\u0260",
"\u0005H\u0263\nH\u0003I\u0003I\u0003I\u0003J\u0003J\u0003J\u0003J\u0003",
"J\u0003J\u0007J\u026e\nJ\fJ\u000eJ\u0271\u000bJ\u0003J\u0003J\u0003",
"J\u0003J\u0003J\u0003J\u0003J\u0007J\u027a\nJ\fJ\u000eJ\u027d\u000b",
"J\u0003J\u0005J\u0280\nJ\u0003K\u0003K\u0003K\u0003K\u0007K\u0286\n",
"K\fK\u000eK\u0289\u000bK\u0003K\u0005K\u028c\nK\u0003K\u0003K\u0005",
"K\u0290\nK\u0003K\u0003K\u0003L\u0003L\u0003L\u0003L\u0007L\u0298\n",
"L\fL\u000eL\u029b\u000bL\u0003L\u0003L\u0003L\u0003L\u0003L\u0003M\u0003",
"M\u0003M\u0003M\u0003N\u0003N\u0003O\u0003O\u0003P\u0003P\u0003Q\u0003",
"Q\u0003R\u0003R\u0003S\u0003S\u0003T\u0003T\u0003U\u0003U\u0003V\u0003",
"V\u0003W\u0003W\u0003X\u0003X\u0003Y\u0003Y\u0003Z\u0003Z\u0003[\u0003",
"[\u0003\\\u0003\\\u0003]\u0003]\u0003^\u0003^\u0003_\u0003_\u0003`\u0003",
"`\u0003a\u0003a\u0003b\u0003b\u0003c\u0003c\u0003d\u0003d\u0003e\u0003",
"e\u0003f\u0003f\u0003g\u0003g\u0003h\u0003h\u0003i\u0003i\u0003j\u0003",
"j\u0003k\u0003k\u0003k\u0003k\u0003\u0299\u0002l\u0003\u0003\u0005\u0004",
"\u0007\u0005\t\u0006\u000b\u0007\r\b\u000f\t\u0011\n\u0013\u000b\u0015",
"\f\u0017\r\u0019\u000e\u001b\u000f\u001d\u0010\u001f\u0011!\u0012#\u0013",
"%\u0014\'\u0015)\u0016+\u0017-\u0018/\u00191\u001a3\u001b5\u001c7\u001d",
"9\u001e;\u001f= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o",
"9q:s;u<w=y>{?}@\u007fA\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008d",
"H\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009d\u0002\u009f",
"\u0002\u00a1\u0002\u00a3\u0002\u00a5\u0002\u00a7\u0002\u00a9\u0002\u00ab",
"\u0002\u00ad\u0002\u00af\u0002\u00b1\u0002\u00b3\u0002\u00b5\u0002\u00b7",
"\u0002\u00b9\u0002\u00bb\u0002\u00bd\u0002\u00bf\u0002\u00c1\u0002\u00c3",
"\u0002\u00c5\u0002\u00c7\u0002\u00c9\u0002\u00cb\u0002\u00cd\u0002\u00cf",
"\u0002\u00d1\u0002\u00d3\u0002\u00d5P\u0003\u0002\'\u0005\u0002C\\a",
"ac|\u0006\u00022;C\\aac|\u0003\u00023;\u0003\u000223\u0004\u0002--/",
"/\u0004\u0002))^^\u0004\u0002$$^^\u0004\u0002\f\f\u000f\u000f\u0005",
"\u0002\u000b\r\u000f\u000f\"\"\u0005\u00022;CHch\u0003\u00022;\u0004",
"\u0002CCcc\u0004\u0002DDdd\u0004\u0002EEee\u0004\u0002FFff\u0004\u0002",
"GGgg\u0004\u0002HHhh\u0004\u0002IIii\u0004\u0002JJjj\u0004\u0002KKk",
"k\u0004\u0002LLll\u0004\u0002MMmm\u0004\u0002NNnn\u0004\u0002OOoo\u0004",
"\u0002PPpp\u0004\u0002QQqq\u0004\u0002RRrr\u0004\u0002SSss\u0004\u0002",
"TTtt\u0004\u0002UUuu\u0004\u0002VVvv\u0004\u0002WWww\u0004\u0002XXx",
"x\u0004\u0002YYyy\u0004\u0002ZZzz\u0004\u0002[[{{\u0004\u0002\\\\||",
"\u0002\u02e2\u0002\u0003\u0003\u0002\u0002\u0002\u0002\u0005\u0003\u0002",
"\u0002\u0002\u0002\u0007\u0003\u0002\u0002\u0002\u0002\t\u0003\u0002",
"\u0002\u0002\u0002\u000b\u0003\u0002\u0002\u0002\u0002\r\u0003\u0002",
"\u0002\u0002\u0002\u000f\u0003\u0002\u0002\u0002\u0002\u0011\u0003\u0002",
"\u0002\u0002\u0002\u0013\u0003\u0002\u0002\u0002\u0002\u0015\u0003\u0002",
"\u0002\u0002\u0002\u0017\u0003\u0002\u0002\u0002\u0002\u0019\u0003\u0002",
"\u0002\u0002\u0002\u001b\u0003\u0002\u0002\u0002\u0002\u001d\u0003\u0002",
"\u0002\u0002\u0002\u001f\u0003\u0002\u0002\u0002\u0002!\u0003\u0002",
"\u0002\u0002\u0002#\u0003\u0002\u0002\u0002\u0002%\u0003\u0002\u0002",
"\u0002\u0002\'\u0003\u0002\u0002\u0002\u0002)\u0003\u0002\u0002\u0002",
"\u0002+\u0003\u0002\u0002\u0002\u0002-\u0003\u0002\u0002\u0002\u0002",
"/\u0003\u0002\u0002\u0002\u00021\u0003\u0002\u0002\u0002\u00023\u0003",
"\u0002\u0002\u0002\u00025\u0003\u0002\u0002\u0002\u00027\u0003\u0002",
"\u0002\u0002\u00029\u0003\u0002\u0002\u0002\u0002;\u0003\u0002\u0002",
"\u0002\u0002=\u0003\u0002\u0002\u0002\u0002?\u0003\u0002\u0002\u0002",
"\u0002A\u0003\u0002\u0002\u0002\u0002C\u0003\u0002\u0002\u0002\u0002",
"E\u0003\u0002\u0002\u0002\u0002G\u0003\u0002\u0002\u0002\u0002I\u0003",
"\u0002\u0002\u0002\u0002K\u0003\u0002\u0002\u0002\u0002M\u0003\u0002",
"\u0002\u0002\u0002O\u0003\u0002\u0002\u0002\u0002Q\u0003\u0002\u0002",
"\u0002\u0002S\u0003\u0002\u0002\u0002\u0002U\u0003\u0002\u0002\u0002",
"\u0002W\u0003\u0002\u0002\u0002\u0002Y\u0003\u0002\u0002\u0002\u0002",
"[\u0003\u0002\u0002\u0002\u0002]\u0003\u0002\u0002\u0002\u0002_\u0003",
"\u0002\u0002\u0002\u0002a\u0003\u0002\u0002\u0002\u0002c\u0003\u0002",
"\u0002\u0002\u0002e\u0003\u0002\u0002\u0002\u0002g\u0003\u0002\u0002",
"\u0002\u0002i\u0003\u0002\u0002\u0002\u0002k\u0003\u0002\u0002\u0002",
"\u0002m\u0003\u0002\u0002\u0002\u0002o\u0003\u0002\u0002\u0002\u0002",
"q\u0003\u0002\u0002\u0002\u0002s\u0003\u0002\u0002\u0002\u0002u\u0003",
"\u0002\u0002\u0002\u0002w\u0003\u0002\u0002\u0002\u0002y\u0003\u0002",
"\u0002\u0002\u0002{\u0003\u0002\u0002\u0002\u0002}\u0003\u0002\u0002",
"\u0002\u0002\u007f\u0003\u0002\u0002\u0002\u0002\u0081\u0003\u0002\u0002",
"\u0002\u0002\u0083\u0003\u0002\u0002\u0002\u0002\u0085\u0003\u0002\u0002",
"\u0002\u0002\u0087\u0003\u0002\u0002\u0002\u0002\u0089\u0003\u0002\u0002",
"\u0002\u0002\u008b\u0003\u0002\u0002\u0002\u0002\u008d\u0003\u0002\u0002",
"\u0002\u0002\u008f\u0003\u0002\u0002\u0002\u0002\u0091\u0003\u0002\u0002",
"\u0002\u0002\u0093\u0003\u0002\u0002\u0002\u0002\u0095\u0003\u0002\u0002",
"\u0002\u0002\u0097\u0003\u0002\u0002\u0002\u0002\u0099\u0003\u0002\u0002",
"\u0002\u0002\u009b\u0003\u0002\u0002\u0002\u0002\u00d5\u0003\u0002\u0002",
"\u0002\u0003\u00d7\u0003\u0002\u0002\u0002\u0005\u00d9\u0003\u0002\u0002",
"\u0002\u0007\u00dc\u0003\u0002\u0002\u0002\t\u00df\u0003\u0002\u0002",
"\u0002\u000b\u00e2\u0003\u0002\u0002\u0002\r\u00e5\u0003\u0002\u0002",
"\u0002\u000f\u00e7\u0003\u0002\u0002\u0002\u0011\u00e9\u0003\u0002\u0002",
"\u0002\u0013\u00ec\u0003\u0002\u0002\u0002\u0015\u00ef\u0003\u0002\u0002",
"\u0002\u0017\u00f1\u0003\u0002\u0002\u0002\u0019\u00f3\u0003\u0002\u0002",
"\u0002\u001b\u00f5\u0003\u0002\u0002\u0002\u001d\u00f7\u0003\u0002\u0002",
"\u0002\u001f\u00f9\u0003\u0002\u0002\u0002!\u00fb\u0003\u0002\u0002",
"\u0002#\u00fd\u0003\u0002\u0002\u0002%\u0100\u0003\u0002\u0002\u0002",
"\'\u0103\u0003\u0002\u0002\u0002)\u0105\u0003\u0002\u0002\u0002+\u0107",
"\u0003\u0002\u0002\u0002-\u0109\u0003\u0002\u0002\u0002/\u010b\u0003",
"\u0002\u0002\u00021\u010d\u0003\u0002\u0002\u00023\u010f\u0003\u0002",
"\u0002\u00025\u0111\u0003\u0002\u0002\u00027\u011b\u0003\u0002\u0002",
"\u00029\u0125\u0003\u0002\u0002\u0002;\u0127\u0003\u0002\u0002\u0002",
"=\u012b\u0003\u0002\u0002\u0002?\u012f\u0003\u0002\u0002\u0002A\u0137",
"\u0003\u0002\u0002\u0002C\u013c\u0003\u0002\u0002\u0002E\u0145\u0003",
"\u0002\u0002\u0002G\u014b\u0003\u0002\u0002\u0002I\u0152\u0003\u0002",
"\u0002\u0002K\u0156\u0003\u0002\u0002\u0002M\u015c\u0003\u0002\u0002",
"\u0002O\u015f\u0003\u0002\u0002\u0002Q\u0167\u0003\u0002\u0002\u0002",
"S\u016e\u0003\u0002\u0002\u0002U\u0173\u0003\u0002\u0002\u0002W\u0184",
"\u0003\u0002\u0002\u0002Y\u0188\u0003\u0002\u0002\u0002[\u018d\u0003",
"\u0002\u0002\u0002]\u0193\u0003\u0002\u0002\u0002_\u019d\u0003\u0002",
"\u0002\u0002a\u019f\u0003\u0002\u0002\u0002c\u01a9\u0003\u0002\u0002",
"\u0002e\u01ab\u0003\u0002\u0002\u0002g\u01b4\u0003\u0002\u0002\u0002",
"i\u01bb\u0003\u0002\u0002\u0002k\u01c3\u0003\u0002\u0002\u0002m\u01ca",
"\u0003\u0002\u0002\u0002o\u01d8\u0003\u0002\u0002\u0002q\u01dd\u0003",
"\u0002\u0002\u0002s\u01e2\u0003\u0002\u0002\u0002u\u01e9\u0003\u0002",
"\u0002\u0002w\u01f0\u0003\u0002\u0002\u0002y\u01f5\u0003\u0002\u0002",
"\u0002{\u01fa\u0003\u0002\u0002\u0002}\u0200\u0003\u0002\u0002\u0002",
"\u007f\u0208\u0003\u0002\u0002\u0002\u0081\u020e\u0003\u0002\u0002\u0002",
"\u0083\u0215\u0003\u0002\u0002\u0002\u0085\u0218\u0003\u0002\u0002\u0002",
"\u0087\u0220\u0003\u0002\u0002\u0002\u0089\u0224\u0003\u0002\u0002\u0002",
"\u008b\u0228\u0003\u0002\u0002\u0002\u008d\u0247\u0003\u0002\u0002\u0002",
"\u008f\u0251\u0003\u0002\u0002\u0002\u0091\u0264\u0003\u0002\u0002\u0002",
"\u0093\u027f\u0003\u0002\u0002\u0002\u0095\u0281\u0003\u0002\u0002\u0002",
"\u0097\u0293\u0003\u0002\u0002\u0002\u0099\u02a1\u0003\u0002\u0002\u0002",
"\u009b\u02a5\u0003\u0002\u0002\u0002\u009d\u02a7\u0003\u0002\u0002\u0002",
"\u009f\u02a9\u0003\u0002\u0002\u0002\u00a1\u02ab\u0003\u0002\u0002\u0002",
"\u00a3\u02ad\u0003\u0002\u0002\u0002\u00a5\u02af\u0003\u0002\u0002\u0002",
"\u00a7\u02b1\u0003\u0002\u0002\u0002\u00a9\u02b3\u0003\u0002\u0002\u0002",
"\u00ab\u02b5\u0003\u0002\u0002\u0002\u00ad\u02b7\u0003\u0002\u0002\u0002",
"\u00af\u02b9\u0003\u0002\u0002\u0002\u00b1\u02bb\u0003\u0002\u0002\u0002",
"\u00b3\u02bd\u0003\u0002\u0002\u0002\u00b5\u02bf\u0003\u0002\u0002\u0002",
"\u00b7\u02c1\u0003\u0002\u0002\u0002\u00b9\u02c3\u0003\u0002\u0002\u0002",
"\u00bb\u02c5\u0003\u0002\u0002\u0002\u00bd\u02c7\u0003\u0002\u0002\u0002",
"\u00bf\u02c9\u0003\u0002\u0002\u0002\u00c1\u02cb\u0003\u0002\u0002\u0002",
"\u00c3\u02cd\u0003\u0002\u0002\u0002\u00c5\u02cf\u0003\u0002\u0002\u0002",
"\u00c7\u02d1\u0003\u0002\u0002\u0002\u00c9\u02d3\u0003\u0002\u0002\u0002",
"\u00cb\u02d5\u0003\u0002\u0002\u0002\u00cd\u02d7\u0003\u0002\u0002\u0002",
"\u00cf\u02d9\u0003\u0002\u0002\u0002\u00d1\u02db\u0003\u0002\u0002\u0002",
"\u00d3\u02dd\u0003\u0002\u0002\u0002\u00d5\u02df\u0003\u0002\u0002\u0002",
"\u00d7\u00d8\u00070\u0002\u0002\u00d8\u0004\u0003\u0002\u0002\u0002",
"\u00d9\u00da\u0007?\u0002\u0002\u00da\u00db\u0007\u0080\u0002\u0002",
"\u00db\u0006\u0003\u0002\u0002\u0002\u00dc\u00dd\u0007#\u0002\u0002",
"\u00dd\u00de\u0007\u0080\u0002\u0002\u00de\b\u0003\u0002\u0002\u0002",
"\u00df\u00e0\u0007?\u0002\u0002\u00e0\u00e1\u0007?\u0002\u0002\u00e1",
"\n\u0003\u0002\u0002\u0002\u00e2\u00e3\u0007#\u0002\u0002\u00e3\u00e4",
"\u0007?\u0002\u0002\u00e4\f\u0003\u0002\u0002\u0002\u00e5\u00e6\u0007",
">\u0002\u0002\u00e6\u000e\u0003\u0002\u0002\u0002\u00e7\u00e8\u0007",
"@\u0002\u0002\u00e8\u0010\u0003\u0002\u0002\u0002\u00e9\u00ea\u0007",
">\u0002\u0002\u00ea\u00eb\u0007?\u0002\u0002\u00eb\u0012\u0003\u0002",
"\u0002\u0002\u00ec\u00ed\u0007@\u0002\u0002\u00ed\u00ee\u0007?\u0002",
"\u0002\u00ee\u0014\u0003\u0002\u0002\u0002\u00ef\u00f0\u0007-\u0002",
"\u0002\u00f0\u0016\u0003\u0002\u0002\u0002\u00f1\u00f2\u0007/\u0002",
"\u0002\u00f2\u0018\u0003\u0002\u0002\u0002\u00f3\u00f4\u0007,\u0002",
"\u0002\u00f4\u001a\u0003\u0002\u0002\u0002\u00f5\u00f6\u00071\u0002",
"\u0002\u00f6\u001c\u0003\u0002\u0002\u0002\u00f7\u00f8\u0007\'\u0002",
"\u0002\u00f8\u001e\u0003\u0002\u0002\u0002\u00f9\u00fa\u0007A\u0002",
"\u0002\u00fa \u0003\u0002\u0002\u0002\u00fb\u00fc\u0007<\u0002\u0002",
"\u00fc\"\u0003\u0002\u0002\u0002\u00fd\u00fe\u0007<\u0002\u0002\u00fe",
"\u00ff\u0007<\u0002\u0002\u00ff$\u0003\u0002\u0002\u0002\u0100\u0101",
"\u00070\u0002\u0002\u0101\u0102\u00070\u0002\u0002\u0102&\u0003\u0002",
"\u0002\u0002\u0103\u0104\u0007.\u0002\u0002\u0104(\u0003\u0002\u0002",
"\u0002\u0105\u0106\u0007*\u0002\u0002\u0106*\u0003\u0002\u0002\u0002",
"\u0107\u0108\u0007+\u0002\u0002\u0108,\u0003\u0002\u0002\u0002\u0109",
"\u010a\u0007}\u0002\u0002\u010a.\u0003\u0002\u0002\u0002\u010b\u010c",
"\u0007\u007f\u0002\u0002\u010c0\u0003\u0002\u0002\u0002\u010d\u010e",
"\u0007]\u0002\u0002\u010e2\u0003\u0002\u0002\u0002\u010f\u0110\u0007",
"_\u0002\u0002\u01104\u0003\u0002\u0002\u0002\u0111\u0112\u0005\u00a1",
"Q\u0002\u0112\u0113\u0005\u00adW\u0002\u0113\u0114\u0005\u00adW\u0002",
"\u0114\u0115\u0005\u00c3b\u0002\u0115\u0116\u0005\u00a9U\u0002\u0116",
"\u0117\u0005\u00adW\u0002\u0117\u0118\u0005\u00a1Q\u0002\u0118\u0119",
"\u0005\u00c7d\u0002\u0119\u011a\u0005\u00a9U\u0002\u011a6\u0003\u0002",
"\u0002\u0002\u011b\u011c\u0005\u00a1Q\u0002\u011c\u011d\u0005\u00b7",
"\\\u0002\u011d\u011e\u0005\u00b7\\\u0002\u011e8\u0003\u0002\u0002\u0002",
"\u011f\u0120\u0005\u00a1Q\u0002\u0120\u0121\u0005\u00bb^\u0002\u0121",
"\u0122\u0005\u00a7T\u0002\u0122\u0126\u0003\u0002\u0002\u0002\u0123",
"\u0124\u0007(\u0002\u0002\u0124\u0126\u0007(\u0002\u0002\u0125\u011f",
"\u0003\u0002\u0002\u0002\u0125\u0123\u0003\u0002\u0002\u0002\u0126:",
"\u0003\u0002\u0002\u0002\u0127\u0128\u0005\u00a1Q\u0002\u0128\u0129",
"\u0005\u00bb^\u0002\u0129\u012a\u0005\u00d1i\u0002\u012a<\u0003\u0002",
"\u0002\u0002\u012b\u012c\u0005\u00a1Q\u0002\u012c\u012d\u0005\u00c5",
"c\u0002\u012d\u012e\u0005\u00a5S\u0002\u012e>\u0003\u0002\u0002\u0002",
"\u012f\u0130\u0005\u00a5S\u0002\u0130\u0131\u0005\u00bd_\u0002\u0131",
"\u0132\u0005\u00b7\\\u0002\u0132\u0133\u0005\u00b7\\\u0002\u0133\u0134",
"\u0005\u00a9U\u0002\u0134\u0135\u0005\u00a5S\u0002\u0135\u0136\u0005",
"\u00c7d\u0002\u0136@\u0003\u0002\u0002\u0002\u0137\u0138\u0005\u00a7",
"T\u0002\u0138\u0139\u0005\u00a9U\u0002\u0139\u013a\u0005\u00c5c\u0002",
"\u013a\u013b\u0005\u00a5S\u0002\u013bB\u0003\u0002\u0002\u0002\u013c",
"\u013d\u0005\u00a7T\u0002\u013d\u013e\u0005\u00b1Y\u0002\u013e\u013f",
"\u0005\u00c5c\u0002\u013f\u0140\u0005\u00c7d\u0002\u0140\u0141\u0005",
"\u00b1Y\u0002\u0141\u0142\u0005\u00bb^\u0002\u0142\u0143\u0005\u00a5",
"S\u0002\u0143\u0144\u0005\u00c7d\u0002\u0144D\u0003\u0002\u0002\u0002",
"\u0145\u0146\u0005\u00abV\u0002\u0146\u0147\u0005\u00a1Q\u0002\u0147",
"\u0148\u0005\u00b7\\\u0002\u0148\u0149\u0005\u00c5c\u0002\u0149\u014a",
"\u0005\u00a9U\u0002\u014aF\u0003\u0002\u0002\u0002\u014b\u014c\u0005",
"\u00abV\u0002\u014c\u014d\u0005\u00b1Y\u0002\u014d\u014e\u0005\u00b7",
"\\\u0002\u014e\u014f\u0005\u00c7d\u0002\u014f\u0150\u0005\u00a9U\u0002",
"\u0150\u0151\u0005\u00c3b\u0002\u0151H\u0003\u0002\u0002\u0002\u0152",
"\u0153\u0005\u00abV\u0002\u0153\u0154\u0005\u00bd_\u0002\u0154\u0155",
"\u0005\u00c3b\u0002\u0155J\u0003\u0002\u0002\u0002\u0156\u0157\u0005",
"\u00adW\u0002\u0157\u0158\u0005\u00c3b\u0002\u0158\u0159\u0005\u00a1",
"Q\u0002\u0159\u015a\u0005\u00bf`\u0002\u015a\u015b\u0005\u00afX\u0002",
"\u015bL\u0003\u0002\u0002\u0002\u015c\u015d\u0005\u00b1Y\u0002\u015d",
"\u015e\u0005\u00bb^\u0002\u015eN\u0003\u0002\u0002\u0002\u015f\u0160",
"\u0005\u00b1Y\u0002\u0160\u0161\u0005\u00bb^\u0002\u0161\u0162\u0005",
"\u00a3R\u0002\u0162\u0163\u0005\u00bd_\u0002\u0163\u0164\u0005\u00c9",
"e\u0002\u0164\u0165\u0005\u00bb^\u0002\u0165\u0166\u0005\u00a7T\u0002",
"\u0166P\u0003\u0002\u0002\u0002\u0167\u0168\u0005\u00b1Y\u0002\u0168",
"\u0169\u0005\u00bb^\u0002\u0169\u016a\u0005\u00c5c\u0002\u016a\u016b",
"\u0005\u00a9U\u0002\u016b\u016c\u0005\u00c3b\u0002\u016c\u016d\u0005",
"\u00c7d\u0002\u016dR\u0003\u0002\u0002\u0002\u016e\u016f\u0005\u00b1",
"Y\u0002\u016f\u0170\u0005\u00bb^\u0002\u0170\u0171\u0005\u00c7d\u0002",
"\u0171\u0172\u0005\u00bd_\u0002\u0172T\u0003\u0002\u0002\u0002\u0173",
"\u0174\u0005\u00b5[\u0002\u0174\u0175\u0007a\u0002\u0002\u0175\u0176",
"\u0005\u00c5c\u0002\u0176\u0177\u0005\u00afX\u0002\u0177\u0178\u0005",
"\u00bd_\u0002\u0178\u0179\u0005\u00c3b\u0002\u0179\u017a\u0005\u00c7",
"d\u0002\u017a\u017b\u0005\u00a9U\u0002\u017b\u017c\u0005\u00c5c\u0002",
"\u017c\u017d\u0005\u00c7d\u0002\u017d\u017e\u0007a\u0002\u0002\u017e",
"\u017f\u0005\u00bf`\u0002\u017f\u0180\u0005\u00a1Q\u0002\u0180\u0181",
"\u0005\u00c7d\u0002\u0181\u0182\u0005\u00afX\u0002\u0182\u0183\u0005",
"\u00c5c\u0002\u0183V\u0003\u0002\u0002\u0002\u0184\u0185\u0005\u00b7",
"\\\u0002\u0185\u0186\u0005\u00a9U\u0002\u0186\u0187\u0005\u00c7d\u0002",
"\u0187X\u0003\u0002\u0002\u0002\u0188\u0189\u0005\u00b7\\\u0002\u0189",
"\u018a\u0005\u00b1Y\u0002\u018a\u018b\u0005\u00b5[\u0002\u018b\u018c",
"\u0005\u00a9U\u0002\u018cZ\u0003\u0002\u0002\u0002\u018d\u018e\u0005",
"\u00b7\\\u0002\u018e\u018f\u0005\u00b1Y\u0002\u018f\u0190\u0005\u00b9",
"]\u0002\u0190\u0191\u0005\u00b1Y\u0002\u0191\u0192\u0005\u00c7d\u0002",
"\u0192\\\u0003\u0002\u0002\u0002\u0193\u0194\u0005\u00bb^\u0002\u0194",
"\u0195\u0005\u00bd_\u0002\u0195\u0196\u0005\u00bb^\u0002\u0196\u0197",
"\u0005\u00a9U\u0002\u0197^\u0003\u0002\u0002\u0002\u0198\u0199\u0005",
"\u00bb^\u0002\u0199\u019a\u0005\u00bd_\u0002\u019a\u019b\u0005\u00c7",
"d\u0002\u019b\u019e\u0003\u0002\u0002\u0002\u019c\u019e\u0007#\u0002",
"\u0002\u019d\u0198\u0003\u0002\u0002\u0002\u019d\u019c\u0003\u0002\u0002",
"\u0002\u019e`\u0003\u0002\u0002\u0002\u019f\u01a0\u0005\u00bb^\u0002",
"\u01a0\u01a1\u0005\u00c9e\u0002\u01a1\u01a2\u0005\u00b7\\\u0002\u01a2",
"\u01a3\u0005\u00b7\\\u0002\u01a3b\u0003\u0002\u0002\u0002\u01a4\u01a5",
"\u0005\u00bd_\u0002\u01a5\u01a6\u0005\u00c3b\u0002\u01a6\u01aa\u0003",
"\u0002\u0002\u0002\u01a7\u01a8\u0007~\u0002\u0002\u01a8\u01aa\u0007",
"~\u0002\u0002\u01a9\u01a4\u0003\u0002\u0002\u0002\u01a9\u01a7\u0003",
"\u0002\u0002\u0002\u01aad\u0003\u0002\u0002\u0002\u01ab\u01ac\u0005",
"\u00bd_\u0002\u01ac\u01ad\u0005\u00c9e\u0002\u01ad\u01ae\u0005\u00c7",
"d\u0002\u01ae\u01af\u0005\u00a3R\u0002\u01af\u01b0\u0005\u00bd_\u0002",
"\u01b0\u01b1\u0005\u00c9e\u0002\u01b1\u01b2\u0005\u00bb^\u0002\u01b2",
"\u01b3\u0005\u00a7T\u0002\u01b3f\u0003\u0002\u0002\u0002\u01b4\u01b5",
"\u0005\u00c3b\u0002\u01b5\u01b6\u0005\u00a9U\u0002\u01b6\u01b7\u0005",
"\u00b9]\u0002\u01b7\u01b8\u0005\u00bd_\u0002\u01b8\u01b9\u0005\u00cb",
"f\u0002\u01b9\u01ba\u0005\u00a9U\u0002\u01bah\u0003\u0002\u0002\u0002",
"\u01bb\u01bc\u0005\u00c3b\u0002\u01bc\u01bd\u0005\u00a9U\u0002\u01bd",
"\u01be\u0005\u00bf`\u0002\u01be\u01bf\u0005\u00b7\\\u0002\u01bf\u01c0",
"\u0005\u00a1Q\u0002\u01c0\u01c1\u0005\u00a5S\u0002\u01c1\u01c2\u0005",
"\u00a9U\u0002\u01c2j\u0003\u0002\u0002\u0002\u01c3\u01c4\u0005\u00c3",
"b\u0002\u01c4\u01c5\u0005\u00a9U\u0002\u01c5\u01c6\u0005\u00c7d\u0002",
"\u01c6\u01c7\u0005\u00c9e\u0002\u01c7\u01c8\u0005\u00c3b\u0002\u01c8",
"\u01c9\u0005\u00bb^\u0002\u01c9l\u0003\u0002\u0002\u0002\u01ca\u01cb",
"\u0005\u00c5c\u0002\u01cb\u01cc\u0005\u00afX\u0002\u01cc\u01cd\u0005",
"\u00bd_\u0002\u01cd\u01ce\u0005\u00c3b\u0002\u01ce\u01cf\u0005\u00c7",
"d\u0002\u01cf\u01d0\u0005\u00a9U\u0002\u01d0\u01d1\u0005\u00c5c\u0002",
"\u01d1\u01d2\u0005\u00c7d\u0002\u01d2\u01d3\u0007a\u0002\u0002\u01d3",
"\u01d4\u0005\u00bf`\u0002\u01d4\u01d5\u0005\u00a1Q\u0002\u01d5\u01d6",
"\u0005\u00c7d\u0002\u01d6\u01d7\u0005\u00afX\u0002\u01d7n\u0003\u0002",
"\u0002\u0002\u01d8\u01d9\u0005\u00c5c\u0002\u01d9\u01da\u0005\u00bd",
"_\u0002\u01da\u01db\u0005\u00c3b\u0002\u01db\u01dc\u0005\u00c7d\u0002",
"\u01dcp\u0003\u0002\u0002\u0002\u01dd\u01de\u0005\u00c7d\u0002\u01de",
"\u01df\u0005\u00c3b\u0002\u01df\u01e0\u0005\u00c9e\u0002\u01e0\u01e1",
"\u0005\u00a9U\u0002\u01e1r\u0003\u0002\u0002\u0002\u01e2\u01e3\u0005",
"\u00c9e\u0002\u01e3\u01e4\u0005\u00bf`\u0002\u01e4\u01e5\u0005\u00a7",
"T\u0002\u01e5\u01e6\u0005\u00a1Q\u0002\u01e6\u01e7\u0005\u00c7d\u0002",
"\u01e7\u01e8\u0005\u00a9U\u0002\u01e8t\u0003\u0002\u0002\u0002\u01e9",
"\u01ea\u0005\u00c9e\u0002\u01ea\u01eb\u0005\u00bf`\u0002\u01eb\u01ec",
"\u0005\u00c5c\u0002\u01ec\u01ed\u0005\u00a9U\u0002\u01ed\u01ee\u0005",
"\u00c3b\u0002\u01ee\u01ef\u0005\u00c7d\u0002\u01efv\u0003\u0002\u0002",
"\u0002\u01f0\u01f1\u0005\u00cdg\u0002\u01f1\u01f2\u0005\u00b1Y\u0002",
"\u01f2\u01f3\u0005\u00c7d\u0002\u01f3\u01f4\u0005\u00afX\u0002\u01f4",
"x\u0003\u0002\u0002\u0002\u01f5\u01f6\u0005\u00b5[\u0002\u01f6\u01f7",
"\u0005\u00a9U\u0002\u01f7\u01f8\u0005\u00a9U\u0002\u01f8\u01f9\u0005",
"\u00bf`\u0002\u01f9z\u0003\u0002\u0002\u0002\u01fa\u01fb\u0005\u00a5",
"S\u0002\u01fb\u01fc\u0005\u00bd_\u0002\u01fc\u01fd\u0005\u00c9e\u0002",
"\u01fd\u01fe\u0005\u00bb^\u0002\u01fe\u01ff\u0005\u00c7d\u0002\u01ff",
"|\u0003\u0002\u0002\u0002\u0200\u0201\u0005\u00bd_\u0002\u0201\u0202",
"\u0005\u00bf`\u0002\u0202\u0203\u0005\u00c7d\u0002\u0203\u0204\u0005",
"\u00b1Y\u0002\u0204\u0205\u0005\u00bd_\u0002\u0205\u0206\u0005\u00bb",
"^\u0002\u0206\u0207\u0005\u00c5c\u0002\u0207~\u0003\u0002\u0002\u0002",
"\u0208\u0209\u0005\u00bf`\u0002\u0209\u020a\u0005\u00c3b\u0002\u020a",
"\u020b\u0005\u00c9e\u0002\u020b\u020c\u0005\u00bb^\u0002\u020c\u020d",
"\u0005\u00a9U\u0002\u020d\u0080\u0003\u0002\u0002\u0002\u020e\u020f",
"\u0005\u00c5c\u0002\u020f\u0210\u0005\u00a9U\u0002\u0210\u0211\u0005",
"\u00a1Q\u0002\u0211\u0212\u0005\u00c3b\u0002\u0212\u0213\u0005\u00a5",
"S\u0002\u0213\u0214\u0005\u00afX\u0002\u0214\u0082\u0003\u0002\u0002",
"\u0002\u0215\u0216\u0005\u00c7d\u0002\u0216\u0217\u0005\u00bd_\u0002",
"\u0217\u0084\u0003\u0002\u0002\u0002\u0218\u0219\u0005\u00a5S\u0002",
"\u0219\u021a\u0005\u00c9e\u0002\u021a\u021b\u0005\u00c3b\u0002\u021b",
"\u021c\u0005\u00c3b\u0002\u021c\u021d\u0005\u00a9U\u0002\u021d\u021e",
"\u0005\u00bb^\u0002\u021e\u021f\u0005\u00c7d\u0002\u021f\u0086\u0003",
"\u0002\u0002\u0002\u0220\u0221\u0005\u00bb^\u0002\u0221\u0222\u0005",
"\u00a9U\u0002\u0222\u0223\u0005\u00cdg\u0002\u0223\u0088\u0003\u0002",
"\u0002\u0002\u0224\u0225\u0005\u00bd_\u0002\u0225\u0226\u0005\u00b7",
"\\\u0002\u0226\u0227\u0005\u00a7T\u0002\u0227\u008a\u0003\u0002\u0002",
"\u0002\u0228\u022c\t\u0002\u0002\u0002\u0229\u022b\t\u0003\u0002\u0002",
"\u022a\u0229\u0003\u0002\u0002\u0002\u022b\u022e\u0003\u0002\u0002\u0002",
"\u022c\u022a\u0003\u0002\u0002\u0002\u022c\u022d\u0003\u0002\u0002\u0002",
"\u022d\u008c\u0003\u0002\u0002\u0002\u022e\u022c\u0003\u0002\u0002\u0002",
"\u022f\u0233\t\u0004\u0002\u0002\u0230\u0232\u0005\u009fP\u0002\u0231",
"\u0230\u0003\u0002\u0002\u0002\u0232\u0235\u0003\u0002\u0002\u0002\u0233",
"\u0231\u0003\u0002\u0002\u0002\u0233\u0234\u0003\u0002\u0002\u0002\u0234",
"\u0248\u0003\u0002\u0002\u0002\u0235\u0233\u0003\u0002\u0002\u0002\u0236",
"\u0248\u00072\u0002\u0002\u0237\u0238\u00072\u0002\u0002\u0238\u0239",
"\u0007z\u0002\u0002\u0239\u023b\u0003\u0002\u0002\u0002\u023a\u023c",
"\u0005\u009dO\u0002\u023b\u023a\u0003\u0002\u0002\u0002\u023c\u023d",
"\u0003\u0002\u0002\u0002\u023d\u023b\u0003\u0002\u0002\u0002\u023d\u023e",
"\u0003\u0002\u0002\u0002\u023e\u0248\u0003\u0002\u0002\u0002\u023f\u0240",
"\u00072\u0002\u0002\u0240\u0241\u0007d\u0002\u0002\u0241\u0243\u0003",
"\u0002\u0002\u0002\u0242\u0244\t\u0005\u0002\u0002\u0243\u0242\u0003",
"\u0002\u0002\u0002\u0244\u0245\u0003\u0002\u0002\u0002\u0245\u0243\u0003",
"\u0002\u0002\u0002\u0245\u0246\u0003\u0002\u0002\u0002\u0246\u0248\u0003",
"\u0002\u0002\u0002\u0247\u022f\u0003\u0002\u0002\u0002\u0247\u0236\u0003",
"\u0002\u0002\u0002\u0247\u0237\u0003\u0002\u0002\u0002\u0247\u023f\u0003",
"\u0002\u0002\u0002\u0248\u008e\u0003\u0002\u0002\u0002\u0249\u024d\t",
"\u0004\u0002\u0002\u024a\u024c\u0005\u009fP\u0002\u024b\u024a\u0003",
"\u0002\u0002\u0002\u024c\u024f\u0003\u0002\u0002\u0002\u024d\u024b\u0003",
"\u0002\u0002\u0002\u024d\u024e\u0003\u0002\u0002\u0002\u024e\u0252\u0003",
"\u0002\u0002\u0002\u024f\u024d\u0003\u0002\u0002\u0002\u0250\u0252\u0007",
"2\u0002\u0002\u0251\u0249\u0003\u0002\u0002\u0002\u0251\u0250\u0003",
"\u0002\u0002\u0002\u0251\u0252\u0003\u0002\u0002\u0002\u0252\u0253\u0003",
"\u0002\u0002\u0002\u0253\u0255\u00070\u0002\u0002\u0254\u0256\u0005",
"\u009fP\u0002\u0255\u0254\u0003\u0002\u0002\u0002\u0256\u0257\u0003",
"\u0002\u0002\u0002\u0257\u0255\u0003\u0002\u0002\u0002\u0257\u0258\u0003",
"\u0002\u0002\u0002\u0258\u0262\u0003\u0002\u0002\u0002\u0259\u025b\u0005",
"\u00a9U\u0002\u025a\u025c\t\u0006\u0002\u0002\u025b\u025a\u0003\u0002",
"\u0002\u0002\u025b\u025c\u0003\u0002\u0002\u0002\u025c\u025e\u0003\u0002",
"\u0002\u0002\u025d\u025f\u0005\u009fP\u0002\u025e\u025d\u0003\u0002",
"\u0002\u0002\u025f\u0260\u0003\u0002\u0002\u0002\u0260\u025e\u0003\u0002",
"\u0002\u0002\u0260\u0261\u0003\u0002\u0002\u0002\u0261\u0263\u0003\u0002",
"\u0002\u0002\u0262\u0259\u0003\u0002\u0002\u0002\u0262\u0263\u0003\u0002",
"\u0002\u0002\u0263\u0090\u0003\u0002\u0002\u0002\u0264\u0265\u0007B",
"\u0002\u0002\u0265\u0266\u0005\u008bF\u0002\u0266\u0092\u0003\u0002",
"\u0002\u0002\u0267\u026f\u0007)\u0002\u0002\u0268\u0269\u0007^\u0002",
"\u0002\u0269\u026e\u000b\u0002\u0002\u0002\u026a\u026b\u0007)\u0002",
"\u0002\u026b\u026e\u0007)\u0002\u0002\u026c\u026e\n\u0007\u0002\u0002",
"\u026d\u0268\u0003\u0002\u0002\u0002\u026d\u026a\u0003\u0002\u0002\u0002",
"\u026d\u026c\u0003\u0002\u0002\u0002\u026e\u0271\u0003\u0002\u0002\u0002",
"\u026f\u026d\u0003\u0002\u0002\u0002\u026f\u0270\u0003\u0002\u0002\u0002",
"\u0270\u0272\u0003\u0002\u0002\u0002\u0271\u026f\u0003\u0002\u0002\u0002",
"\u0272\u0280\u0007)\u0002\u0002\u0273\u027b\u0007$\u0002\u0002\u0274",
"\u0275\u0007^\u0002\u0002\u0275\u027a\u000b\u0002\u0002\u0002\u0276",
"\u0277\u0007$\u0002\u0002\u0277\u027a\u0007$\u0002\u0002\u0278\u027a",
"\n\b\u0002\u0002\u0279\u0274\u0003\u0002\u0002\u0002\u0279\u0276\u0003",
"\u0002\u0002\u0002\u0279\u0278\u0003\u0002\u0002\u0002\u027a\u027d\u0003",
"\u0002\u0002\u0002\u027b\u0279\u0003\u0002\u0002\u0002\u027b\u027c\u0003",
"\u0002\u0002\u0002\u027c\u027e\u0003\u0002\u0002\u0002\u027d\u027b\u0003",
"\u0002\u0002\u0002\u027e\u0280\u0007$\u0002\u0002\u027f\u0267\u0003",
"\u0002\u0002\u0002\u027f\u0273\u0003\u0002\u0002\u0002\u0280\u0094\u0003",
"\u0002\u0002\u0002\u0281\u0282\u00071\u0002\u0002\u0282\u0283\u0007",
"1\u0002\u0002\u0283\u0287\u0003\u0002\u0002\u0002\u0284\u0286\n\t\u0002",
"\u0002\u0285\u0284\u0003\u0002\u0002\u0002\u0286\u0289\u0003\u0002\u0002",
"\u0002\u0287\u0285\u0003\u0002\u0002\u0002\u0287\u0288\u0003\u0002\u0002",
"\u0002\u0288\u028f\u0003\u0002\u0002\u0002\u0289\u0287\u0003\u0002\u0002",
"\u0002\u028a\u028c\u0007\u000f\u0002\u0002\u028b\u028a\u0003\u0002\u0002",
"\u0002\u028b\u028c\u0003\u0002\u0002\u0002\u028c\u028d\u0003\u0002\u0002",
"\u0002\u028d\u0290\u0007\f\u0002\u0002\u028e\u0290\u0007\u0002\u0002",
"\u0003\u028f\u028b\u0003\u0002\u0002\u0002\u028f\u028e\u0003\u0002\u0002",
"\u0002\u0290\u0291\u0003\u0002\u0002\u0002\u0291\u0292\bK\u0002\u0002",
"\u0292\u0096\u0003\u0002\u0002\u0002\u0293\u0294\u00071\u0002\u0002",
"\u0294\u0295\u0007,\u0002\u0002\u0295\u0299\u0003\u0002\u0002\u0002",
"\u0296\u0298\u000b\u0002\u0002\u0002\u0297\u0296\u0003\u0002\u0002\u0002",
"\u0298\u029b\u0003\u0002\u0002\u0002\u0299\u029a\u0003\u0002\u0002\u0002",
"\u0299\u0297\u0003\u0002\u0002\u0002\u029a\u029c\u0003\u0002\u0002\u0002",
"\u029b\u0299\u0003\u0002\u0002\u0002\u029c\u029d\u0007,\u0002\u0002",
"\u029d\u029e\u00071\u0002\u0002\u029e\u029f\u0003\u0002\u0002\u0002",
"\u029f\u02a0\bL\u0002\u0002\u02a0\u0098\u0003\u0002\u0002\u0002\u02a1",
"\u02a2\t\n\u0002\u0002\u02a2\u02a3\u0003\u0002\u0002\u0002\u02a3\u02a4",
"\bM\u0002\u0002\u02a4\u009a\u0003\u0002\u0002\u0002\u02a5\u02a6\u000b",
"\u0002\u0002\u0002\u02a6\u009c\u0003\u0002\u0002\u0002\u02a7\u02a8\t",
"\u000b\u0002\u0002\u02a8\u009e\u0003\u0002\u0002\u0002\u02a9\u02aa\t",
"\f\u0002\u0002\u02aa\u00a0\u0003\u0002\u0002\u0002\u02ab\u02ac\t\r\u0002",
"\u0002\u02ac\u00a2\u0003\u0002\u0002\u0002\u02ad\u02ae\t\u000e\u0002",
"\u0002\u02ae\u00a4\u0003\u0002\u0002\u0002\u02af\u02b0\t\u000f\u0002",
"\u0002\u02b0\u00a6\u0003\u0002\u0002\u0002\u02b1\u02b2\t\u0010\u0002",
"\u0002\u02b2\u00a8\u0003\u0002\u0002\u0002\u02b3\u02b4\t\u0011\u0002",
"\u0002\u02b4\u00aa\u0003\u0002\u0002\u0002\u02b5\u02b6\t\u0012\u0002",
"\u0002\u02b6\u00ac\u0003\u0002\u0002\u0002\u02b7\u02b8\t\u0013\u0002",
"\u0002\u02b8\u00ae\u0003\u0002\u0002\u0002\u02b9\u02ba\t\u0014\u0002",
"\u0002\u02ba\u00b0\u0003\u0002\u0002\u0002\u02bb\u02bc\t\u0015\u0002",
"\u0002\u02bc\u00b2\u0003\u0002\u0002\u0002\u02bd\u02be\t\u0016\u0002",
"\u0002\u02be\u00b4\u0003\u0002\u0002\u0002\u02bf\u02c0\t\u0017\u0002",
"\u0002\u02c0\u00b6\u0003\u0002\u0002\u0002\u02c1\u02c2\t\u0018\u0002",
"\u0002\u02c2\u00b8\u0003\u0002\u0002\u0002\u02c3\u02c4\t\u0019\u0002",
"\u0002\u02c4\u00ba\u0003\u0002\u0002\u0002\u02c5\u02c6\t\u001a\u0002",
"\u0002\u02c6\u00bc\u0003\u0002\u0002\u0002\u02c7\u02c8\t\u001b\u0002",
"\u0002\u02c8\u00be\u0003\u0002\u0002\u0002\u02c9\u02ca\t\u001c\u0002",
"\u0002\u02ca\u00c0\u0003\u0002\u0002\u0002\u02cb\u02cc\t\u001d\u0002",
"\u0002\u02cc\u00c2\u0003\u0002\u0002\u0002\u02cd\u02ce\t\u001e\u0002",
"\u0002\u02ce\u00c4\u0003\u0002\u0002\u0002\u02cf\u02d0\t\u001f\u0002",
"\u0002\u02d0\u00c6\u0003\u0002\u0002\u0002\u02d1\u02d2\t \u0002\u0002",
"\u02d2\u00c8\u0003\u0002\u0002\u0002\u02d3\u02d4\t!\u0002\u0002\u02d4",
"\u00ca\u0003\u0002\u0002\u0002\u02d5\u02d6\t\"\u0002\u0002\u02d6\u00cc",
"\u0003\u0002\u0002\u0002\u02d7\u02d8\t#\u0002\u0002\u02d8\u00ce\u0003",
"\u0002\u0002\u0002\u02d9\u02da\t$\u0002\u0002\u02da\u00d0\u0003\u0002",
"\u0002\u0002\u02db\u02dc\t%\u0002\u0002\u02dc\u00d2\u0003\u0002\u0002",
"\u0002\u02dd\u02de\t&\u0002\u0002\u02de\u00d4\u0003\u0002\u0002\u0002",
"\u02df\u02e0\u000b\u0002\u0002\u0002\u02e0\u02e1\u0003\u0002\u0002\u0002",
"\u02e1\u02e2\bk\u0003\u0002\u02e2\u00d6\u0003\u0002\u0002\u0002\u001a",
"\u0002\u0125\u019d\u01a9\u022c\u0233\u023d\u0245\u0247\u024d\u0251\u0257",
"\u025b\u0260\u0262\u026d\u026f\u0279\u027b\u027f\u0287\u028b\u028f\u0299",
"\u0004\u0002\u0003\u0002\u0002\u0004\u0002"].join("");
const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) );
export default class CAQLLexer extends antlr4.Lexer {
static grammarFileName = "CAQLLexer.g4";
static channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "ERRORCHANNEL" ];
static modeNames = [ "DEFAULT_MODE" ];
static literalNames = [ null, "'.'", "'=~'", "'!~'", "'=='", "'!='", "'<'",
"'>'", "'<='", "'>='", "'+'", "'-'", "'*'", "'/'",
"'%'", "'?'", "':'", "'::'", "'..'", "','", "'('",
"')'", "'{'", "'}'", "'['", "']'" ];
static symbolicNames = [ null, "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH",
"T_EQ", "T_NE", "T_LT", "T_GT", "T_LE", "T_GE",
"T_PLUS", "T_MINUS", "T_TIMES", "T_DIV", "T_MOD",
"T_QUESTION", "T_COLON", "T_SCOPE", "T_RANGE",
"T_COMMA", "T_OPEN", "T_CLOSE", "T_OBJECT_OPEN",
"T_OBJECT_CLOSE", "T_ARRAY_OPEN", "T_ARRAY_CLOSE",
"T_AGGREGATE", "T_ALL", "T_AND", "T_ANY", "T_ASC",
"T_COLLECT", "T_DESC", "T_DISTINCT", "T_FALSE",
"T_FILTER", "T_FOR", "T_GRAPH", "T_IN", "T_INBOUND",
"T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS", "T_LET",
"T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE",
"T_RETURN", "T_SHORTEST_PATH", "T_SORT", "T_TRUE",
"T_UPDATE", "T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT",
"T_OPTIONS", "T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT",
"T_NEW", "T_OLD", "T_STRING", "T_INT", "T_FLOAT",
"T_PARAMETER", "T_QUOTED_STRING", "SINGLE_LINE_COMMENT",
"MULTILINE_COMMENT", "SPACES", "UNEXPECTED_CHAR",
"ERROR_RECONGNIGION" ];
static ruleNames = [ "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH", "T_EQ",
"T_NE", "T_LT", "T_GT", "T_LE", "T_GE", "T_PLUS",
"T_MINUS", "T_TIMES", "T_DIV", "T_MOD", "T_QUESTION",
"T_COLON", "T_SCOPE", "T_RANGE", "T_COMMA", "T_OPEN",
"T_CLOSE", "T_OBJECT_OPEN", "T_OBJECT_CLOSE", "T_ARRAY_OPEN",
"T_ARRAY_CLOSE", "T_AGGREGATE", "T_ALL", "T_AND",
"T_ANY", "T_ASC", "T_COLLECT", "T_DESC", "T_DISTINCT",
"T_FALSE", "T_FILTER", "T_FOR", "T_GRAPH", "T_IN",
"T_INBOUND", "T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS",
"T_LET", "T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE", "T_RETURN",
"T_SHORTEST_PATH", "T_SORT", "T_TRUE", "T_UPDATE",
"T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT", "T_OPTIONS",
"T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT", "T_NEW",
"T_OLD", "T_STRING", "T_INT", "T_FLOAT", "T_PARAMETER",
"T_QUOTED_STRING", "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT",
"SPACES", "UNEXPECTED_CHAR", "HEX_DIGIT", "DIGIT",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z", "ERROR_RECONGNIGION" ];
constructor(input) {
super(input)
this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache());
}
get atn() {
return atn;
}
}
CAQLLexer.EOF = antlr4.Token.EOF;
CAQLLexer.DOT = 1;
CAQLLexer.T_REGEX_MATCH = 2;
CAQLLexer.T_REGEX_NON_MATCH = 3;
CAQLLexer.T_EQ = 4;
CAQLLexer.T_NE = 5;
CAQLLexer.T_LT = 6;
CAQLLexer.T_GT = 7;
CAQLLexer.T_LE = 8;
CAQLLexer.T_GE = 9;
CAQLLexer.T_PLUS = 10;
CAQLLexer.T_MINUS = 11;
CAQLLexer.T_TIMES = 12;
CAQLLexer.T_DIV = 13;
CAQLLexer.T_MOD = 14;
CAQLLexer.T_QUESTION = 15;
CAQLLexer.T_COLON = 16;
CAQLLexer.T_SCOPE = 17;
CAQLLexer.T_RANGE = 18;
CAQLLexer.T_COMMA = 19;
CAQLLexer.T_OPEN = 20;
CAQLLexer.T_CLOSE = 21;
CAQLLexer.T_OBJECT_OPEN = 22;
CAQLLexer.T_OBJECT_CLOSE = 23;
CAQLLexer.T_ARRAY_OPEN = 24;
CAQLLexer.T_ARRAY_CLOSE = 25;
CAQLLexer.T_AGGREGATE = 26;
CAQLLexer.T_ALL = 27;
CAQLLexer.T_AND = 28;
CAQLLexer.T_ANY = 29;
CAQLLexer.T_ASC = 30;
CAQLLexer.T_COLLECT = 31;
CAQLLexer.T_DESC = 32;
CAQLLexer.T_DISTINCT = 33;
CAQLLexer.T_FALSE = 34;
CAQLLexer.T_FILTER = 35;
CAQLLexer.T_FOR = 36;
CAQLLexer.T_GRAPH = 37;
CAQLLexer.T_IN = 38;
CAQLLexer.T_INBOUND = 39;
CAQLLexer.T_INSERT = 40;
CAQLLexer.T_INTO = 41;
CAQLLexer.T_K_SHORTEST_PATHS = 42;
CAQLLexer.T_LET = 43;
CAQLLexer.T_LIKE = 44;
CAQLLexer.T_LIMIT = 45;
CAQLLexer.T_NONE = 46;
CAQLLexer.T_NOT = 47;
CAQLLexer.T_NULL = 48;
CAQLLexer.T_OR = 49;
CAQLLexer.T_OUTBOUND = 50;
CAQLLexer.T_REMOVE = 51;
CAQLLexer.T_REPLACE = 52;
CAQLLexer.T_RETURN = 53;
CAQLLexer.T_SHORTEST_PATH = 54;
CAQLLexer.T_SORT = 55;
CAQLLexer.T_TRUE = 56;
CAQLLexer.T_UPDATE = 57;
CAQLLexer.T_UPSERT = 58;
CAQLLexer.T_WITH = 59;
CAQLLexer.T_KEEP = 60;
CAQLLexer.T_COUNT = 61;
CAQLLexer.T_OPTIONS = 62;
CAQLLexer.T_PRUNE = 63;
CAQLLexer.T_SEARCH = 64;
CAQLLexer.T_TO = 65;
CAQLLexer.T_CURRENT = 66;
CAQLLexer.T_NEW = 67;
CAQLLexer.T_OLD = 68;
CAQLLexer.T_STRING = 69;
CAQLLexer.T_INT = 70;
CAQLLexer.T_FLOAT = 71;
CAQLLexer.T_PARAMETER = 72;
CAQLLexer.T_QUOTED_STRING = 73;
CAQLLexer.SINGLE_LINE_COMMENT = 74;
CAQLLexer.MULTILINE_COMMENT = 75;
CAQLLexer.SPACES = 76;
CAQLLexer.UNEXPECTED_CHAR = 77;
CAQLLexer.ERROR_RECONGNIGION = 78;
CAQLLexer.ERRORCHANNEL = 2;
+103
View File
@@ -0,0 +1,103 @@
DOT=1
T_REGEX_MATCH=2
T_REGEX_NON_MATCH=3
T_EQ=4
T_NE=5
T_LT=6
T_GT=7
T_LE=8
T_GE=9
T_PLUS=10
T_MINUS=11
T_TIMES=12
T_DIV=13
T_MOD=14
T_QUESTION=15
T_COLON=16
T_SCOPE=17
T_RANGE=18
T_COMMA=19
T_OPEN=20
T_CLOSE=21
T_OBJECT_OPEN=22
T_OBJECT_CLOSE=23
T_ARRAY_OPEN=24
T_ARRAY_CLOSE=25
T_AGGREGATE=26
T_ALL=27
T_AND=28
T_ANY=29
T_ASC=30
T_COLLECT=31
T_DESC=32
T_DISTINCT=33
T_FALSE=34
T_FILTER=35
T_FOR=36
T_GRAPH=37
T_IN=38
T_INBOUND=39
T_INSERT=40
T_INTO=41
T_K_SHORTEST_PATHS=42
T_LET=43
T_LIKE=44
T_LIMIT=45
T_NONE=46
T_NOT=47
T_NULL=48
T_OR=49
T_OUTBOUND=50
T_REMOVE=51
T_REPLACE=52
T_RETURN=53
T_SHORTEST_PATH=54
T_SORT=55
T_TRUE=56
T_UPDATE=57
T_UPSERT=58
T_WITH=59
T_KEEP=60
T_COUNT=61
T_OPTIONS=62
T_PRUNE=63
T_SEARCH=64
T_TO=65
T_CURRENT=66
T_NEW=67
T_OLD=68
T_STRING=69
T_INT=70
T_FLOAT=71
T_PARAMETER=72
T_QUOTED_STRING=73
SINGLE_LINE_COMMENT=74
MULTILINE_COMMENT=75
SPACES=76
UNEXPECTED_CHAR=77
ERROR_RECONGNIGION=78
'.'=1
'=~'=2
'!~'=3
'=='=4
'!='=5
'<'=6
'>'=7
'<='=8
'>='=9
'+'=10
'-'=11
'*'=12
'/'=13
'%'=14
'?'=15
':'=16
'::'=17
'..'=18
','=19
'('=20
')'=21
'{'=22
'}'=23
'['=24
']'=25
@@ -0,0 +1,178 @@
token literal names:
null
'.'
'=~'
'!~'
'=='
'!='
'<'
'>'
'<='
'>='
'+'
'-'
'*'
'/'
'%'
'?'
':'
'::'
'..'
','
'('
')'
'{'
'}'
'['
']'
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
token symbolic names:
null
DOT
T_REGEX_MATCH
T_REGEX_NON_MATCH
T_EQ
T_NE
T_LT
T_GT
T_LE
T_GE
T_PLUS
T_MINUS
T_TIMES
T_DIV
T_MOD
T_QUESTION
T_COLON
T_SCOPE
T_RANGE
T_COMMA
T_OPEN
T_CLOSE
T_OBJECT_OPEN
T_OBJECT_CLOSE
T_ARRAY_OPEN
T_ARRAY_CLOSE
T_AGGREGATE
T_ALL
T_AND
T_ANY
T_ASC
T_COLLECT
T_DESC
T_DISTINCT
T_FALSE
T_FILTER
T_FOR
T_GRAPH
T_IN
T_INBOUND
T_INSERT
T_INTO
T_K_SHORTEST_PATHS
T_LET
T_LIKE
T_LIMIT
T_NONE
T_NOT
T_NULL
T_OR
T_OUTBOUND
T_REMOVE
T_REPLACE
T_RETURN
T_SHORTEST_PATH
T_SORT
T_TRUE
T_UPDATE
T_UPSERT
T_WITH
T_KEEP
T_COUNT
T_OPTIONS
T_PRUNE
T_SEARCH
T_TO
T_CURRENT
T_NEW
T_OLD
T_STRING
T_INT
T_FLOAT
T_PARAMETER
T_QUOTED_STRING
SINGLE_LINE_COMMENT
MULTILINE_COMMENT
SPACES
UNEXPECTED_CHAR
ERROR_RECONGNIGION
rule names:
parse
expression
operator_unary
reference
compound_value
function_call
value_literal
array
object
object_element
object_element_name
atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 80, 192, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 32, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 48, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 66, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 86, 10, 3, 12, 3, 14, 3, 89, 11, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 97, 10, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 107, 10, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 117, 10, 5, 12, 5, 14, 5, 120, 11, 5, 3, 6, 3, 6, 5, 6, 124, 10, 6, 3, 7, 3, 7, 3, 7, 5, 7, 129, 10, 7, 3, 7, 3, 7, 7, 7, 133, 10, 7, 12, 7, 14, 7, 136, 11, 7, 3, 7, 5, 7, 139, 10, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 5, 9, 147, 10, 9, 3, 9, 3, 9, 7, 9, 151, 10, 9, 12, 9, 14, 9, 154, 11, 9, 3, 9, 5, 9, 157, 10, 9, 3, 9, 3, 9, 3, 10, 3, 10, 5, 10, 163, 10, 10, 3, 10, 3, 10, 7, 10, 167, 10, 10, 12, 10, 14, 10, 170, 11, 10, 3, 10, 5, 10, 173, 10, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 188, 10, 11, 3, 12, 3, 12, 3, 12, 4, 134, 152, 4, 4, 8, 13, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 2, 11, 3, 2, 12, 13, 3, 2, 14, 16, 3, 2, 8, 11, 3, 2, 6, 7, 5, 2, 29, 29, 31, 31, 48, 48, 4, 2, 6, 11, 40, 40, 4, 2, 4, 5, 46, 46, 7, 2, 36, 36, 50, 50, 58, 58, 72, 73, 75, 75, 4, 2, 71, 71, 75, 75, 2, 216, 2, 24, 3, 2, 2, 2, 4, 31, 3, 2, 2, 2, 6, 96, 3, 2, 2, 2, 8, 106, 3, 2, 2, 2, 10, 123, 3, 2, 2, 2, 12, 125, 3, 2, 2, 2, 14, 142, 3, 2, 2, 2, 16, 144, 3, 2, 2, 2, 18, 160, 3, 2, 2, 2, 20, 187, 3, 2, 2, 2, 22, 189, 3, 2, 2, 2, 24, 25, 5, 4, 3, 2, 25, 26, 7, 2, 2, 3, 26, 3, 3, 2, 2, 2, 27, 28, 8, 3, 1, 2, 28, 32, 5, 14, 8, 2, 29, 32, 5, 8, 5, 2, 30, 32, 5, 6, 4, 2, 31, 27, 3, 2, 2, 2, 31, 29, 3, 2, 2, 2, 31, 30, 3, 2, 2, 2, 32, 87, 3, 2, 2, 2, 33, 34, 12, 15, 2, 2, 34, 35, 9, 2, 2, 2, 35, 86, 5, 4, 3, 16, 36, 37, 12, 14, 2, 2, 37, 38, 9, 3, 2, 2, 38, 86, 5, 4, 3, 15, 39, 40, 12, 13, 2, 2, 40, 41, 7, 20, 2, 2, 41, 86, 5, 4, 3, 14, 42, 43, 12, 12, 2, 2, 43, 44, 9, 4, 2, 2, 44, 86, 5, 4, 3, 13, 45, 47, 12, 11, 2, 2, 46, 48, 7, 49, 2, 2, 47, 46, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 49, 3, 2, 2, 2, 49, 50, 7, 40, 2, 2, 50, 86, 5, 4, 3, 12, 51, 52, 12, 10, 2, 2, 52, 53, 9, 5, 2, 2, 53, 86, 5, 4, 3, 11, 54, 55, 12, 9, 2, 2, 55, 56, 9, 6, 2, 2, 56, 57, 9, 7, 2, 2, 57, 86, 5, 4, 3, 10, 58, 59, 12, 8, 2, 2, 59, 60, 9, 6, 2, 2, 60, 61, 7, 49, 2, 2, 61, 62, 7, 40, 2, 2, 62, 86, 5, 4, 3, 9, 63, 65, 12, 7, 2, 2, 64, 66, 7, 49, 2, 2, 65, 64, 3, 2, 2, 2, 65, 66, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 68, 9, 8, 2, 2, 68, 86, 5, 4, 3, 8, 69, 70, 12, 6, 2, 2, 70, 71, 7, 30, 2, 2, 71, 86, 5, 4, 3, 7, 72, 73, 12, 5, 2, 2, 73, 74, 7, 51, 2, 2, 74, 86, 5, 4, 3, 6, 75, 76, 12, 4, 2, 2, 76, 77, 7, 17, 2, 2, 77, 78, 5, 4, 3, 2, 78, 79, 7, 18, 2, 2, 79, 80, 5, 4, 3, 5, 80, 86, 3, 2, 2, 2, 81, 82, 12, 3, 2, 2, 82, 83, 7, 17, 2, 2, 83, 84, 7, 18, 2, 2, 84, 86, 5, 4, 3, 4, 85, 33, 3, 2, 2, 2, 85, 36, 3, 2, 2, 2, 85, 39, 3, 2, 2, 2, 85, 42, 3, 2, 2, 2, 85, 45, 3, 2, 2, 2, 85, 51, 3, 2, 2, 2, 85, 54, 3, 2, 2, 2, 85, 58, 3, 2, 2, 2, 85, 63, 3, 2, 2, 2, 85, 69, 3, 2, 2, 2, 85, 72, 3, 2, 2, 2, 85, 75, 3, 2, 2, 2, 85, 81, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 5, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 91, 7, 12, 2, 2, 91, 97, 5, 4, 3, 2, 92, 93, 7, 13, 2, 2, 93, 97, 5, 4, 3, 2, 94, 95, 7, 49, 2, 2, 95, 97, 5, 4, 3, 2, 96, 90, 3, 2, 2, 2, 96, 92, 3, 2, 2, 2, 96, 94, 3, 2, 2, 2, 97, 7, 3, 2, 2, 2, 98, 99, 8, 5, 1, 2, 99, 107, 7, 71, 2, 2, 100, 107, 5, 10, 6, 2, 101, 107, 5, 12, 7, 2, 102, 103, 7, 22, 2, 2, 103, 104, 5, 4, 3, 2, 104, 105, 7, 23, 2, 2, 105, 107, 3, 2, 2, 2, 106, 98, 3, 2, 2, 2, 106, 100, 3, 2, 2, 2, 106, 101, 3, 2, 2, 2, 106, 102, 3, 2, 2, 2, 107, 118, 3, 2, 2, 2, 108, 109, 12, 4, 2, 2, 109, 110, 7, 3, 2, 2, 110, 117, 7, 71, 2, 2, 111, 112, 12, 3, 2, 2, 112, 113, 7, 26, 2, 2, 113, 114, 5, 4, 3, 2, 114, 115, 7, 27, 2, 2, 115, 117, 3, 2, 2, 2, 116, 108, 3, 2, 2, 2, 116, 111, 3, 2, 2, 2, 117, 120, 3, 2, 2, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 9, 3, 2, 2, 2, 120, 118, 3, 2, 2, 2, 121, 124, 5, 16, 9, 2, 122, 124, 5, 18, 10, 2, 123, 121, 3, 2, 2, 2, 123, 122, 3, 2, 2, 2, 124, 11, 3, 2, 2, 2, 125, 126, 7, 71, 2, 2, 126, 128, 7, 22, 2, 2, 127, 129, 5, 4, 3, 2, 128, 127, 3, 2, 2, 2, 128, 129, 3, 2, 2, 2, 129, 134, 3, 2, 2, 2, 130, 131, 7, 21, 2, 2, 131, 133, 5, 4, 3, 2, 132, 130, 3, 2, 2, 2, 133, 136, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 135, 138, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 137, 139, 7, 21, 2, 2, 138, 137, 3, 2, 2, 2, 138, 139, 3, 2, 2, 2, 139, 140, 3, 2, 2, 2, 140, 141, 7, 23, 2, 2, 141, 13, 3, 2, 2, 2, 142, 143, 9, 9, 2, 2, 143, 15, 3, 2Line truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,103 @@
DOT=1
T_REGEX_MATCH=2
T_REGEX_NON_MATCH=3
T_EQ=4
T_NE=5
T_LT=6
T_GT=7
T_LE=8
T_GE=9
T_PLUS=10
T_MINUS=11
T_TIMES=12
T_DIV=13
T_MOD=14
T_QUESTION=15
T_COLON=16
T_SCOPE=17
T_RANGE=18
T_COMMA=19
T_OPEN=20
T_CLOSE=21
T_OBJECT_OPEN=22
T_OBJECT_CLOSE=23
T_ARRAY_OPEN=24
T_ARRAY_CLOSE=25
T_AGGREGATE=26
T_ALL=27
T_AND=28
T_ANY=29
T_ASC=30
T_COLLECT=31
T_DESC=32
T_DISTINCT=33
T_FALSE=34
T_FILTER=35
T_FOR=36
T_GRAPH=37
T_IN=38
T_INBOUND=39
T_INSERT=40
T_INTO=41
T_K_SHORTEST_PATHS=42
T_LET=43
T_LIKE=44
T_LIMIT=45
T_NONE=46
T_NOT=47
T_NULL=48
T_OR=49
T_OUTBOUND=50
T_REMOVE=51
T_REPLACE=52
T_RETURN=53
T_SHORTEST_PATH=54
T_SORT=55
T_TRUE=56
T_UPDATE=57
T_UPSERT=58
T_WITH=59
T_KEEP=60
T_COUNT=61
T_OPTIONS=62
T_PRUNE=63
T_SEARCH=64
T_TO=65
T_CURRENT=66
T_NEW=67
T_OLD=68
T_STRING=69
T_INT=70
T_FLOAT=71
T_PARAMETER=72
T_QUOTED_STRING=73
SINGLE_LINE_COMMENT=74
MULTILINE_COMMENT=75
SPACES=76
UNEXPECTED_CHAR=77
ERROR_RECONGNIGION=78
'.'=1
'=~'=2
'!~'=3
'=='=4
'!='=5
'<'=6
'>'=7
'<='=8
'>='=9
'+'=10
'-'=11
'*'=12
'/'=13
'%'=14
'?'=15
':'=16
'::'=17
'..'=18
','=19
'('=20
')'=21
'{'=22
'}'=23
'['=24
']'=25
@@ -0,0 +1,108 @@
// Generated from CAQLParser.g4 by ANTLR 4.9.2
// jshint ignore: start
import antlr4 from 'antlr4';
// This class defines a complete listener for a parse tree produced by CAQLParser.
export default class CAQLParserListener extends antlr4.tree.ParseTreeListener {
// Enter a parse tree produced by CAQLParser#parse.
enterParse(ctx) {
}
// Exit a parse tree produced by CAQLParser#parse.
exitParse(ctx) {
}
// Enter a parse tree produced by CAQLParser#expression.
enterExpression(ctx) {
}
// Exit a parse tree produced by CAQLParser#expression.
exitExpression(ctx) {
}
// Enter a parse tree produced by CAQLParser#operator_unary.
enterOperator_unary(ctx) {
}
// Exit a parse tree produced by CAQLParser#operator_unary.
exitOperator_unary(ctx) {
}
// Enter a parse tree produced by CAQLParser#reference.
enterReference(ctx) {
}
// Exit a parse tree produced by CAQLParser#reference.
exitReference(ctx) {
}
// Enter a parse tree produced by CAQLParser#compound_value.
enterCompound_value(ctx) {
}
// Exit a parse tree produced by CAQLParser#compound_value.
exitCompound_value(ctx) {
}
// Enter a parse tree produced by CAQLParser#function_call.
enterFunction_call(ctx) {
}
// Exit a parse tree produced by CAQLParser#function_call.
exitFunction_call(ctx) {
}
// Enter a parse tree produced by CAQLParser#value_literal.
enterValue_literal(ctx) {
}
// Exit a parse tree produced by CAQLParser#value_literal.
exitValue_literal(ctx) {
}
// Enter a parse tree produced by CAQLParser#array.
enterArray(ctx) {
}
// Exit a parse tree produced by CAQLParser#array.
exitArray(ctx) {
}
// Enter a parse tree produced by CAQLParser#object.
enterObject(ctx) {
}
// Exit a parse tree produced by CAQLParser#object.
exitObject(ctx) {
}
// Enter a parse tree produced by CAQLParser#object_element.
enterObject_element(ctx) {
}
// Exit a parse tree produced by CAQLParser#object_element.
exitObject_element(ctx) {
}
// Enter a parse tree produced by CAQLParser#object_element_name.
enterObject_element_name(ctx) {
}
// Exit a parse tree produced by CAQLParser#object_element_name.
exitObject_element_name(ctx) {
}
}
+282
View File
@@ -0,0 +1,282 @@
token literal names:
null
'.'
'=~'
'!~'
'=='
'!='
'<'
'>'
'<='
'>='
'+'
'-'
'*'
'/'
'%'
'?'
':'
'::'
'..'
','
'('
')'
'{'
'}'
'['
']'
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
token symbolic names:
null
DOT
T_REGEX_MATCH
T_REGEX_NON_MATCH
T_EQ
T_NE
T_LT
T_GT
T_LE
T_GE
T_PLUS
T_MINUS
T_TIMES
T_DIV
T_MOD
T_QUESTION
T_COLON
T_SCOPE
T_RANGE
T_COMMA
T_OPEN
T_CLOSE
T_OBJECT_OPEN
T_OBJECT_CLOSE
T_ARRAY_OPEN
T_ARRAY_CLOSE
T_AGGREGATE
T_ALL
T_AND
T_ANY
T_ASC
T_COLLECT
T_DESC
T_DISTINCT
T_FALSE
T_FILTER
T_FOR
T_GRAPH
T_IN
T_INBOUND
T_INSERT
T_INTO
T_K_SHORTEST_PATHS
T_LET
T_LIKE
T_LIMIT
T_NONE
T_NOT
T_NULL
T_OR
T_OUTBOUND
T_REMOVE
T_REPLACE
T_RETURN
T_SHORTEST_PATH
T_SORT
T_TRUE
T_UPDATE
T_UPSERT
T_WITH
T_KEEP
T_COUNT
T_OPTIONS
T_PRUNE
T_SEARCH
T_TO
T_CURRENT
T_NEW
T_OLD
T_STRING
T_INT
T_FLOAT
T_PARAMETER
T_QUOTED_STRING
SINGLE_LINE_COMMENT
MULTILINE_COMMENT
SPACES
UNEXPECTED_CHAR
ERROR_RECONGNIGION
rule names:
DOT
T_REGEX_MATCH
T_REGEX_NON_MATCH
T_EQ
T_NE
T_LT
T_GT
T_LE
T_GE
T_PLUS
T_MINUS
T_TIMES
T_DIV
T_MOD
T_QUESTION
T_COLON
T_SCOPE
T_RANGE
T_COMMA
T_OPEN
T_CLOSE
T_OBJECT_OPEN
T_OBJECT_CLOSE
T_ARRAY_OPEN
T_ARRAY_CLOSE
T_AGGREGATE
T_ALL
T_AND
T_ANY
T_ASC
T_COLLECT
T_DESC
T_DISTINCT
T_FALSE
T_FILTER
T_FOR
T_GRAPH
T_IN
T_INBOUND
T_INSERT
T_INTO
T_K_SHORTEST_PATHS
T_LET
T_LIKE
T_LIMIT
T_NONE
T_NOT
T_NULL
T_OR
T_OUTBOUND
T_REMOVE
T_REPLACE
T_RETURN
T_SHORTEST_PATH
T_SORT
T_TRUE
T_UPDATE
T_UPSERT
T_WITH
T_KEEP
T_COUNT
T_OPTIONS
T_PRUNE
T_SEARCH
T_TO
T_CURRENT
T_NEW
T_OLD
T_STRING
T_INT
T_FLOAT
T_PARAMETER
T_QUOTED_STRING
SINGLE_LINE_COMMENT
MULTILINE_COMMENT
SPACES
UNEXPECTED_CHAR
HEX_DIGIT
DIGIT
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
ERROR_RECONGNIGION
channel names:
DEFAULT_TOKEN_CHANNEL
HIDDEN
null
null
ERRORCHANNEL
mode names:
DEFAULT_MODE
atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 80, 739, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 4, 78, 9, 78, 4, 79, 9, 79, 4, 80, 9, 80, 4, 81, 9, 81, 4, 82, 9, 82, 4, 83, 9, 83, 4, 84, 9, 84, 4, 85, 9, 85, 4, 86, 9, 86, 4, 87, 9, 87, 4, 88, 9, 88, 4, 89, 9, 89, 4, 90, 9, 90, 4, 91, 9, 91, 4, 92, 9, 92, 4, 93, 9, 93, 4, 94, 9, 94, 4, 95, 9, 95, 4, 96, 9, 96, 4, 97, 9, 97, 4, 98, 9, 98, 4, 99, 9, 99, 4, 100, 9, 100, 4, 101, 9, 101, 4, 102, 9, 102, 4, 103, 9, 103, 4, 104, 9, 104, 4, 105, 9, 105, 4, 106, 9, 106, 4, 107, 9, 107, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 5, 29, 294, 10, 29, 3, 30, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 5, 48, 414, 10, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 5, 50, 426, 10, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 3, 64, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 70, 3, 70, 7, 70, 555, 10, 70, 12, 70, 14, 70, 558, 11, 70, 3, 71, 3, 71, 7, 71, 562, 10, 71, 12, 71, 14, 71, 565, 11, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 572, 10, 71, 13, 71, 14, 71, 573, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 580, 10, 71, 13, 71, 14, 71, 581, 5, 71, 584, 10, 71, 3, 72, 3, 72, 7, 72, 588, 10, 72, 12, 72, 14, 72, 591, 11, 72, 3, 72, 5, 72, 594, 10, 72, 3, 72, 3, 72, 6, 72, 598, 10, 72, 13, 72, 14, 72, 599, 3, 72, 3, 72, 5, 72, 604, 10, 72, 3, 72, 6, 72, 607, 10, 72, 13, 72, 14, 72, 608, 5, 72, 611, 10, 72, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 7, 74, 622, 10, 74, 12, 74, 14, 74, 625, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 7, 74, 634, 10, 74, 12, 74, 14, 74, 637, 11, 74, 3, 74, 5, 74, 640, 10, 74, 3, 75, 3, 75, 3, 75, 3, 75, 7, 75, 646, 10, 75, 12, 75, 14, 75, 649, 11, 75, 3, 75, 5, 75, 652, 10, 75, 3, 75, 3, 75, 5, 75, 656, 10, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 76, 3, 76, 7, 76, 664, 10, 76, 12, 76, 14, 76, 667, 11, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 78, 3, 78, Line truncated
+607
View File
@@ -0,0 +1,607 @@
// Generated from CAQLLexer.g4 by ANTLR 4.9.2
// jshint ignore: start
import antlr4 from 'antlr4';
const serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786",
"\u5964\u0002P\u02e3\b\u0001\u0004\u0002\t\u0002\u0004\u0003\t\u0003",
"\u0004\u0004\t\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007",
"\t\u0007\u0004\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004",
"\f\t\f\u0004\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010",
"\t\u0010\u0004\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013",
"\u0004\u0014\t\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017",
"\t\u0017\u0004\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a",
"\u0004\u001b\t\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e",
"\t\u001e\u0004\u001f\t\u001f\u0004 \t \u0004!\t!\u0004\"\t\"\u0004#",
"\t#\u0004$\t$\u0004%\t%\u0004&\t&\u0004\'\t\'\u0004(\t(\u0004)\t)\u0004",
"*\t*\u0004+\t+\u0004,\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u0004",
"1\t1\u00042\t2\u00043\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u0004",
"8\t8\u00049\t9\u0004:\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004",
"?\t?\u0004@\t@\u0004A\tA\u0004B\tB\u0004C\tC\u0004D\tD\u0004E\tE\u0004",
"F\tF\u0004G\tG\u0004H\tH\u0004I\tI\u0004J\tJ\u0004K\tK\u0004L\tL\u0004",
"M\tM\u0004N\tN\u0004O\tO\u0004P\tP\u0004Q\tQ\u0004R\tR\u0004S\tS\u0004",
"T\tT\u0004U\tU\u0004V\tV\u0004W\tW\u0004X\tX\u0004Y\tY\u0004Z\tZ\u0004",
"[\t[\u0004\\\t\\\u0004]\t]\u0004^\t^\u0004_\t_\u0004`\t`\u0004a\ta\u0004",
"b\tb\u0004c\tc\u0004d\td\u0004e\te\u0004f\tf\u0004g\tg\u0004h\th\u0004",
"i\ti\u0004j\tj\u0004k\tk\u0003\u0002\u0003\u0002\u0003\u0003\u0003\u0003",
"\u0003\u0003\u0003\u0004\u0003\u0004\u0003\u0004\u0003\u0005\u0003\u0005",
"\u0003\u0005\u0003\u0006\u0003\u0006\u0003\u0006\u0003\u0007\u0003\u0007",
"\u0003\b\u0003\b\u0003\t\u0003\t\u0003\t\u0003\n\u0003\n\u0003\n\u0003",
"\u000b\u0003\u000b\u0003\f\u0003\f\u0003\r\u0003\r\u0003\u000e\u0003",
"\u000e\u0003\u000f\u0003\u000f\u0003\u0010\u0003\u0010\u0003\u0011\u0003",
"\u0011\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0013\u0003\u0013\u0003",
"\u0013\u0003\u0014\u0003\u0014\u0003\u0015\u0003\u0015\u0003\u0016\u0003",
"\u0016\u0003\u0017\u0003\u0017\u0003\u0018\u0003\u0018\u0003\u0019\u0003",
"\u0019\u0003\u001a\u0003\u001a\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
"\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
"\u001b\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001d\u0003",
"\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0005\u001d\u0126",
"\n\u001d\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001f",
"\u0003\u001f\u0003\u001f\u0003\u001f\u0003 \u0003 \u0003 \u0003 \u0003",
" \u0003 \u0003 \u0003 \u0003!\u0003!\u0003!\u0003!\u0003!\u0003\"\u0003",
"\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003#\u0003",
"#\u0003#\u0003#\u0003#\u0003#\u0003$\u0003$\u0003$\u0003$\u0003$\u0003",
"$\u0003$\u0003%\u0003%\u0003%\u0003%\u0003&\u0003&\u0003&\u0003&\u0003",
"&\u0003&\u0003\'\u0003\'\u0003\'\u0003(\u0003(\u0003(\u0003(\u0003(",
"\u0003(\u0003(\u0003(\u0003)\u0003)\u0003)\u0003)\u0003)\u0003)\u0003",
")\u0003*\u0003*\u0003*\u0003*\u0003*\u0003+\u0003+\u0003+\u0003+\u0003",
"+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003",
"+\u0003+\u0003+\u0003,\u0003,\u0003,\u0003,\u0003-\u0003-\u0003-\u0003",
"-\u0003-\u0003.\u0003.\u0003.\u0003.\u0003.\u0003.\u0003/\u0003/\u0003",
"/\u0003/\u0003/\u00030\u00030\u00030\u00030\u00030\u00050\u019e\n0\u0003",
"1\u00031\u00031\u00031\u00031\u00032\u00032\u00032\u00032\u00032\u0005",
"2\u01aa\n2\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u0003",
"3\u00034\u00034\u00034\u00034\u00034\u00034\u00034\u00035\u00035\u0003",
"5\u00035\u00035\u00035\u00035\u00035\u00036\u00036\u00036\u00036\u0003",
"6\u00036\u00036\u00037\u00037\u00037\u00037\u00037\u00037\u00037\u0003",
"7\u00037\u00037\u00037\u00037\u00037\u00037\u00038\u00038\u00038\u0003",
"8\u00038\u00039\u00039\u00039\u00039\u00039\u0003:\u0003:\u0003:\u0003",
":\u0003:\u0003:\u0003:\u0003;\u0003;\u0003;\u0003;\u0003;\u0003;\u0003",
";\u0003<\u0003<\u0003<\u0003<\u0003<\u0003=\u0003=\u0003=\u0003=\u0003",
"=\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003?\u0003?\u0003?\u0003",
"?\u0003?\u0003?\u0003?\u0003?\u0003@\u0003@\u0003@\u0003@\u0003@\u0003",
"@\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003B\u0003B\u0003",
"B\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003D\u0003",
"D\u0003D\u0003D\u0003E\u0003E\u0003E\u0003E\u0003F\u0003F\u0007F\u022b",
"\nF\fF\u000eF\u022e\u000bF\u0003G\u0003G\u0007G\u0232\nG\fG\u000eG\u0235",
"\u000bG\u0003G\u0003G\u0003G\u0003G\u0003G\u0006G\u023c\nG\rG\u000e",
"G\u023d\u0003G\u0003G\u0003G\u0003G\u0006G\u0244\nG\rG\u000eG\u0245",
"\u0005G\u0248\nG\u0003H\u0003H\u0007H\u024c\nH\fH\u000eH\u024f\u000b",
"H\u0003H\u0005H\u0252\nH\u0003H\u0003H\u0006H\u0256\nH\rH\u000eH\u0257",
"\u0003H\u0003H\u0005H\u025c\nH\u0003H\u0006H\u025f\nH\rH\u000eH\u0260",
"\u0005H\u0263\nH\u0003I\u0003I\u0003I\u0003J\u0003J\u0003J\u0003J\u0003",
"J\u0003J\u0007J\u026e\nJ\fJ\u000eJ\u0271\u000bJ\u0003J\u0003J\u0003",
"J\u0003J\u0003J\u0003J\u0003J\u0007J\u027a\nJ\fJ\u000eJ\u027d\u000b",
"J\u0003J\u0005J\u0280\nJ\u0003K\u0003K\u0003K\u0003K\u0007K\u0286\n",
"K\fK\u000eK\u0289\u000bK\u0003K\u0005K\u028c\nK\u0003K\u0003K\u0005",
"K\u0290\nK\u0003K\u0003K\u0003L\u0003L\u0003L\u0003L\u0007L\u0298\n",
"L\fL\u000eL\u029b\u000bL\u0003L\u0003L\u0003L\u0003L\u0003L\u0003M\u0003",
"M\u0003M\u0003M\u0003N\u0003N\u0003O\u0003O\u0003P\u0003P\u0003Q\u0003",
"Q\u0003R\u0003R\u0003S\u0003S\u0003T\u0003T\u0003U\u0003U\u0003V\u0003",
"V\u0003W\u0003W\u0003X\u0003X\u0003Y\u0003Y\u0003Z\u0003Z\u0003[\u0003",
"[\u0003\\\u0003\\\u0003]\u0003]\u0003^\u0003^\u0003_\u0003_\u0003`\u0003",
"`\u0003a\u0003a\u0003b\u0003b\u0003c\u0003c\u0003d\u0003d\u0003e\u0003",
"e\u0003f\u0003f\u0003g\u0003g\u0003h\u0003h\u0003i\u0003i\u0003j\u0003",
"j\u0003k\u0003k\u0003k\u0003k\u0003\u0299\u0002l\u0003\u0003\u0005\u0004",
"\u0007\u0005\t\u0006\u000b\u0007\r\b\u000f\t\u0011\n\u0013\u000b\u0015",
"\f\u0017\r\u0019\u000e\u001b\u000f\u001d\u0010\u001f\u0011!\u0012#\u0013",
"%\u0014\'\u0015)\u0016+\u0017-\u0018/\u00191\u001a3\u001b5\u001c7\u001d",
"9\u001e;\u001f= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o",
"9q:s;u<w=y>{?}@\u007fA\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008d",
"H\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009d\u0002\u009f",
"\u0002\u00a1\u0002\u00a3\u0002\u00a5\u0002\u00a7\u0002\u00a9\u0002\u00ab",
"\u0002\u00ad\u0002\u00af\u0002\u00b1\u0002\u00b3\u0002\u00b5\u0002\u00b7",
"\u0002\u00b9\u0002\u00bb\u0002\u00bd\u0002\u00bf\u0002\u00c1\u0002\u00c3",
"\u0002\u00c5\u0002\u00c7\u0002\u00c9\u0002\u00cb\u0002\u00cd\u0002\u00cf",
"\u0002\u00d1\u0002\u00d3\u0002\u00d5P\u0003\u0002\'\u0005\u0002C\\a",
"ac|\u0006\u00022;C\\aac|\u0003\u00023;\u0003\u000223\u0004\u0002--/",
"/\u0004\u0002))^^\u0004\u0002$$^^\u0004\u0002\f\f\u000f\u000f\u0005",
"\u0002\u000b\r\u000f\u000f\"\"\u0005\u00022;CHch\u0003\u00022;\u0004",
"\u0002CCcc\u0004\u0002DDdd\u0004\u0002EEee\u0004\u0002FFff\u0004\u0002",
"GGgg\u0004\u0002HHhh\u0004\u0002IIii\u0004\u0002JJjj\u0004\u0002KKk",
"k\u0004\u0002LLll\u0004\u0002MMmm\u0004\u0002NNnn\u0004\u0002OOoo\u0004",
"\u0002PPpp\u0004\u0002QQqq\u0004\u0002RRrr\u0004\u0002SSss\u0004\u0002",
"TTtt\u0004\u0002UUuu\u0004\u0002VVvv\u0004\u0002WWww\u0004\u0002XXx",
"x\u0004\u0002YYyy\u0004\u0002ZZzz\u0004\u0002[[{{\u0004\u0002\\\\||",
"\u0002\u02e2\u0002\u0003\u0003\u0002\u0002\u0002\u0002\u0005\u0003\u0002",
"\u0002\u0002\u0002\u0007\u0003\u0002\u0002\u0002\u0002\t\u0003\u0002",
"\u0002\u0002\u0002\u000b\u0003\u0002\u0002\u0002\u0002\r\u0003\u0002",
"\u0002\u0002\u0002\u000f\u0003\u0002\u0002\u0002\u0002\u0011\u0003\u0002",
"\u0002\u0002\u0002\u0013\u0003\u0002\u0002\u0002\u0002\u0015\u0003\u0002",
"\u0002\u0002\u0002\u0017\u0003\u0002\u0002\u0002\u0002\u0019\u0003\u0002",
"\u0002\u0002\u0002\u001b\u0003\u0002\u0002\u0002\u0002\u001d\u0003\u0002",
"\u0002\u0002\u0002\u001f\u0003\u0002\u0002\u0002\u0002!\u0003\u0002",
"\u0002\u0002\u0002#\u0003\u0002\u0002\u0002\u0002%\u0003\u0002\u0002",
"\u0002\u0002\'\u0003\u0002\u0002\u0002\u0002)\u0003\u0002\u0002\u0002",
"\u0002+\u0003\u0002\u0002\u0002\u0002-\u0003\u0002\u0002\u0002\u0002",
"/\u0003\u0002\u0002\u0002\u00021\u0003\u0002\u0002\u0002\u00023\u0003",
"\u0002\u0002\u0002\u00025\u0003\u0002\u0002\u0002\u00027\u0003\u0002",
"\u0002\u0002\u00029\u0003\u0002\u0002\u0002\u0002;\u0003\u0002\u0002",
"\u0002\u0002=\u0003\u0002\u0002\u0002\u0002?\u0003\u0002\u0002\u0002",
"\u0002A\u0003\u0002\u0002\u0002\u0002C\u0003\u0002\u0002\u0002\u0002",
"E\u0003\u0002\u0002\u0002\u0002G\u0003\u0002\u0002\u0002\u0002I\u0003",
"\u0002\u0002\u0002\u0002K\u0003\u0002\u0002\u0002\u0002M\u0003\u0002",
"\u0002\u0002\u0002O\u0003\u0002\u0002\u0002\u0002Q\u0003\u0002\u0002",
"\u0002\u0002S\u0003\u0002\u0002\u0002\u0002U\u0003\u0002\u0002\u0002",
"\u0002W\u0003\u0002\u0002\u0002\u0002Y\u0003\u0002\u0002\u0002\u0002",
"[\u0003\u0002\u0002\u0002\u0002]\u0003\u0002\u0002\u0002\u0002_\u0003",
"\u0002\u0002\u0002\u0002a\u0003\u0002\u0002\u0002\u0002c\u0003\u0002",
"\u0002\u0002\u0002e\u0003\u0002\u0002\u0002\u0002g\u0003\u0002\u0002",
"\u0002\u0002i\u0003\u0002\u0002\u0002\u0002k\u0003\u0002\u0002\u0002",
"\u0002m\u0003\u0002\u0002\u0002\u0002o\u0003\u0002\u0002\u0002\u0002",
"q\u0003\u0002\u0002\u0002\u0002s\u0003\u0002\u0002\u0002\u0002u\u0003",
"\u0002\u0002\u0002\u0002w\u0003\u0002\u0002\u0002\u0002y\u0003\u0002",
"\u0002\u0002\u0002{\u0003\u0002\u0002\u0002\u0002}\u0003\u0002\u0002",
"\u0002\u0002\u007f\u0003\u0002\u0002\u0002\u0002\u0081\u0003\u0002\u0002",
"\u0002\u0002\u0083\u0003\u0002\u0002\u0002\u0002\u0085\u0003\u0002\u0002",
"\u0002\u0002\u0087\u0003\u0002\u0002\u0002\u0002\u0089\u0003\u0002\u0002",
"\u0002\u0002\u008b\u0003\u0002\u0002\u0002\u0002\u008d\u0003\u0002\u0002",
"\u0002\u0002\u008f\u0003\u0002\u0002\u0002\u0002\u0091\u0003\u0002\u0002",
"\u0002\u0002\u0093\u0003\u0002\u0002\u0002\u0002\u0095\u0003\u0002\u0002",
"\u0002\u0002\u0097\u0003\u0002\u0002\u0002\u0002\u0099\u0003\u0002\u0002",
"\u0002\u0002\u009b\u0003\u0002\u0002\u0002\u0002\u00d5\u0003\u0002\u0002",
"\u0002\u0003\u00d7\u0003\u0002\u0002\u0002\u0005\u00d9\u0003\u0002\u0002",
"\u0002\u0007\u00dc\u0003\u0002\u0002\u0002\t\u00df\u0003\u0002\u0002",
"\u0002\u000b\u00e2\u0003\u0002\u0002\u0002\r\u00e5\u0003\u0002\u0002",
"\u0002\u000f\u00e7\u0003\u0002\u0002\u0002\u0011\u00e9\u0003\u0002\u0002",
"\u0002\u0013\u00ec\u0003\u0002\u0002\u0002\u0015\u00ef\u0003\u0002\u0002",
"\u0002\u0017\u00f1\u0003\u0002\u0002\u0002\u0019\u00f3\u0003\u0002\u0002",
"\u0002\u001b\u00f5\u0003\u0002\u0002\u0002\u001d\u00f7\u0003\u0002\u0002",
"\u0002\u001f\u00f9\u0003\u0002\u0002\u0002!\u00fb\u0003\u0002\u0002",
"\u0002#\u00fd\u0003\u0002\u0002\u0002%\u0100\u0003\u0002\u0002\u0002",
"\'\u0103\u0003\u0002\u0002\u0002)\u0105\u0003\u0002\u0002\u0002+\u0107",
"\u0003\u0002\u0002\u0002-\u0109\u0003\u0002\u0002\u0002/\u010b\u0003",
"\u0002\u0002\u00021\u010d\u0003\u0002\u0002\u00023\u010f\u0003\u0002",
"\u0002\u00025\u0111\u0003\u0002\u0002\u00027\u011b\u0003\u0002\u0002",
"\u00029\u0125\u0003\u0002\u0002\u0002;\u0127\u0003\u0002\u0002\u0002",
"=\u012b\u0003\u0002\u0002\u0002?\u012f\u0003\u0002\u0002\u0002A\u0137",
"\u0003\u0002\u0002\u0002C\u013c\u0003\u0002\u0002\u0002E\u0145\u0003",
"\u0002\u0002\u0002G\u014b\u0003\u0002\u0002\u0002I\u0152\u0003\u0002",
"\u0002\u0002K\u0156\u0003\u0002\u0002\u0002M\u015c\u0003\u0002\u0002",
"\u0002O\u015f\u0003\u0002\u0002\u0002Q\u0167\u0003\u0002\u0002\u0002",
"S\u016e\u0003\u0002\u0002\u0002U\u0173\u0003\u0002\u0002\u0002W\u0184",
"\u0003\u0002\u0002\u0002Y\u0188\u0003\u0002\u0002\u0002[\u018d\u0003",
"\u0002\u0002\u0002]\u0193\u0003\u0002\u0002\u0002_\u019d\u0003\u0002",
"\u0002\u0002a\u019f\u0003\u0002\u0002\u0002c\u01a9\u0003\u0002\u0002",
"\u0002e\u01ab\u0003\u0002\u0002\u0002g\u01b4\u0003\u0002\u0002\u0002",
"i\u01bb\u0003\u0002\u0002\u0002k\u01c3\u0003\u0002\u0002\u0002m\u01ca",
"\u0003\u0002\u0002\u0002o\u01d8\u0003\u0002\u0002\u0002q\u01dd\u0003",
"\u0002\u0002\u0002s\u01e2\u0003\u0002\u0002\u0002u\u01e9\u0003\u0002",
"\u0002\u0002w\u01f0\u0003\u0002\u0002\u0002y\u01f5\u0003\u0002\u0002",
"\u0002{\u01fa\u0003\u0002\u0002\u0002}\u0200\u0003\u0002\u0002\u0002",
"\u007f\u0208\u0003\u0002\u0002\u0002\u0081\u020e\u0003\u0002\u0002\u0002",
"\u0083\u0215\u0003\u0002\u0002\u0002\u0085\u0218\u0003\u0002\u0002\u0002",
"\u0087\u0220\u0003\u0002\u0002\u0002\u0089\u0224\u0003\u0002\u0002\u0002",
"\u008b\u0228\u0003\u0002\u0002\u0002\u008d\u0247\u0003\u0002\u0002\u0002",
"\u008f\u0251\u0003\u0002\u0002\u0002\u0091\u0264\u0003\u0002\u0002\u0002",
"\u0093\u027f\u0003\u0002\u0002\u0002\u0095\u0281\u0003\u0002\u0002\u0002",
"\u0097\u0293\u0003\u0002\u0002\u0002\u0099\u02a1\u0003\u0002\u0002\u0002",
"\u009b\u02a5\u0003\u0002\u0002\u0002\u009d\u02a7\u0003\u0002\u0002\u0002",
"\u009f\u02a9\u0003\u0002\u0002\u0002\u00a1\u02ab\u0003\u0002\u0002\u0002",
"\u00a3\u02ad\u0003\u0002\u0002\u0002\u00a5\u02af\u0003\u0002\u0002\u0002",
"\u00a7\u02b1\u0003\u0002\u0002\u0002\u00a9\u02b3\u0003\u0002\u0002\u0002",
"\u00ab\u02b5\u0003\u0002\u0002\u0002\u00ad\u02b7\u0003\u0002\u0002\u0002",
"\u00af\u02b9\u0003\u0002\u0002\u0002\u00b1\u02bb\u0003\u0002\u0002\u0002",
"\u00b3\u02bd\u0003\u0002\u0002\u0002\u00b5\u02bf\u0003\u0002\u0002\u0002",
"\u00b7\u02c1\u0003\u0002\u0002\u0002\u00b9\u02c3\u0003\u0002\u0002\u0002",
"\u00bb\u02c5\u0003\u0002\u0002\u0002\u00bd\u02c7\u0003\u0002\u0002\u0002",
"\u00bf\u02c9\u0003\u0002\u0002\u0002\u00c1\u02cb\u0003\u0002\u0002\u0002",
"\u00c3\u02cd\u0003\u0002\u0002\u0002\u00c5\u02cf\u0003\u0002\u0002\u0002",
"\u00c7\u02d1\u0003\u0002\u0002\u0002\u00c9\u02d3\u0003\u0002\u0002\u0002",
"\u00cb\u02d5\u0003\u0002\u0002\u0002\u00cd\u02d7\u0003\u0002\u0002\u0002",
"\u00cf\u02d9\u0003\u0002\u0002\u0002\u00d1\u02db\u0003\u0002\u0002\u0002",
"\u00d3\u02dd\u0003\u0002\u0002\u0002\u00d5\u02df\u0003\u0002\u0002\u0002",
"\u00d7\u00d8\u00070\u0002\u0002\u00d8\u0004\u0003\u0002\u0002\u0002",
"\u00d9\u00da\u0007?\u0002\u0002\u00da\u00db\u0007\u0080\u0002\u0002",
"\u00db\u0006\u0003\u0002\u0002\u0002\u00dc\u00dd\u0007#\u0002\u0002",
"\u00dd\u00de\u0007\u0080\u0002\u0002\u00de\b\u0003\u0002\u0002\u0002",
"\u00df\u00e0\u0007?\u0002\u0002\u00e0\u00e1\u0007?\u0002\u0002\u00e1",
"\n\u0003\u0002\u0002\u0002\u00e2\u00e3\u0007#\u0002\u0002\u00e3\u00e4",
"\u0007?\u0002\u0002\u00e4\f\u0003\u0002\u0002\u0002\u00e5\u00e6\u0007",
">\u0002\u0002\u00e6\u000e\u0003\u0002\u0002\u0002\u00e7\u00e8\u0007",
"@\u0002\u0002\u00e8\u0010\u0003\u0002\u0002\u0002\u00e9\u00ea\u0007",
">\u0002\u0002\u00ea\u00eb\u0007?\u0002\u0002\u00eb\u0012\u0003\u0002",
"\u0002\u0002\u00ec\u00ed\u0007@\u0002\u0002\u00ed\u00ee\u0007?\u0002",
"\u0002\u00ee\u0014\u0003\u0002\u0002\u0002\u00ef\u00f0\u0007-\u0002",
"\u0002\u00f0\u0016\u0003\u0002\u0002\u0002\u00f1\u00f2\u0007/\u0002",
"\u0002\u00f2\u0018\u0003\u0002\u0002\u0002\u00f3\u00f4\u0007,\u0002",
"\u0002\u00f4\u001a\u0003\u0002\u0002\u0002\u00f5\u00f6\u00071\u0002",
"\u0002\u00f6\u001c\u0003\u0002\u0002\u0002\u00f7\u00f8\u0007\'\u0002",
"\u0002\u00f8\u001e\u0003\u0002\u0002\u0002\u00f9\u00fa\u0007A\u0002",
"\u0002\u00fa \u0003\u0002\u0002\u0002\u00fb\u00fc\u0007<\u0002\u0002",
"\u00fc\"\u0003\u0002\u0002\u0002\u00fd\u00fe\u0007<\u0002\u0002\u00fe",
"\u00ff\u0007<\u0002\u0002\u00ff$\u0003\u0002\u0002\u0002\u0100\u0101",
"\u00070\u0002\u0002\u0101\u0102\u00070\u0002\u0002\u0102&\u0003\u0002",
"\u0002\u0002\u0103\u0104\u0007.\u0002\u0002\u0104(\u0003\u0002\u0002",
"\u0002\u0105\u0106\u0007*\u0002\u0002\u0106*\u0003\u0002\u0002\u0002",
"\u0107\u0108\u0007+\u0002\u0002\u0108,\u0003\u0002\u0002\u0002\u0109",
"\u010a\u0007}\u0002\u0002\u010a.\u0003\u0002\u0002\u0002\u010b\u010c",
"\u0007\u007f\u0002\u0002\u010c0\u0003\u0002\u0002\u0002\u010d\u010e",
"\u0007]\u0002\u0002\u010e2\u0003\u0002\u0002\u0002\u010f\u0110\u0007",
"_\u0002\u0002\u01104\u0003\u0002\u0002\u0002\u0111\u0112\u0005\u00a1",
"Q\u0002\u0112\u0113\u0005\u00adW\u0002\u0113\u0114\u0005\u00adW\u0002",
"\u0114\u0115\u0005\u00c3b\u0002\u0115\u0116\u0005\u00a9U\u0002\u0116",
"\u0117\u0005\u00adW\u0002\u0117\u0118\u0005\u00a1Q\u0002\u0118\u0119",
"\u0005\u00c7d\u0002\u0119\u011a\u0005\u00a9U\u0002\u011a6\u0003\u0002",
"\u0002\u0002\u011b\u011c\u0005\u00a1Q\u0002\u011c\u011d\u0005\u00b7",
"\\\u0002\u011d\u011e\u0005\u00b7\\\u0002\u011e8\u0003\u0002\u0002\u0002",
"\u011f\u0120\u0005\u00a1Q\u0002\u0120\u0121\u0005\u00bb^\u0002\u0121",
"\u0122\u0005\u00a7T\u0002\u0122\u0126\u0003\u0002\u0002\u0002\u0123",
"\u0124\u0007(\u0002\u0002\u0124\u0126\u0007(\u0002\u0002\u0125\u011f",
"\u0003\u0002\u0002\u0002\u0125\u0123\u0003\u0002\u0002\u0002\u0126:",
"\u0003\u0002\u0002\u0002\u0127\u0128\u0005\u00a1Q\u0002\u0128\u0129",
"\u0005\u00bb^\u0002\u0129\u012a\u0005\u00d1i\u0002\u012a<\u0003\u0002",
"\u0002\u0002\u012b\u012c\u0005\u00a1Q\u0002\u012c\u012d\u0005\u00c5",
"c\u0002\u012d\u012e\u0005\u00a5S\u0002\u012e>\u0003\u0002\u0002\u0002",
"\u012f\u0130\u0005\u00a5S\u0002\u0130\u0131\u0005\u00bd_\u0002\u0131",
"\u0132\u0005\u00b7\\\u0002\u0132\u0133\u0005\u00b7\\\u0002\u0133\u0134",
"\u0005\u00a9U\u0002\u0134\u0135\u0005\u00a5S\u0002\u0135\u0136\u0005",
"\u00c7d\u0002\u0136@\u0003\u0002\u0002\u0002\u0137\u0138\u0005\u00a7",
"T\u0002\u0138\u0139\u0005\u00a9U\u0002\u0139\u013a\u0005\u00c5c\u0002",
"\u013a\u013b\u0005\u00a5S\u0002\u013bB\u0003\u0002\u0002\u0002\u013c",
"\u013d\u0005\u00a7T\u0002\u013d\u013e\u0005\u00b1Y\u0002\u013e\u013f",
"\u0005\u00c5c\u0002\u013f\u0140\u0005\u00c7d\u0002\u0140\u0141\u0005",
"\u00b1Y\u0002\u0141\u0142\u0005\u00bb^\u0002\u0142\u0143\u0005\u00a5",
"S\u0002\u0143\u0144\u0005\u00c7d\u0002\u0144D\u0003\u0002\u0002\u0002",
"\u0145\u0146\u0005\u00abV\u0002\u0146\u0147\u0005\u00a1Q\u0002\u0147",
"\u0148\u0005\u00b7\\\u0002\u0148\u0149\u0005\u00c5c\u0002\u0149\u014a",
"\u0005\u00a9U\u0002\u014aF\u0003\u0002\u0002\u0002\u014b\u014c\u0005",
"\u00abV\u0002\u014c\u014d\u0005\u00b1Y\u0002\u014d\u014e\u0005\u00b7",
"\\\u0002\u014e\u014f\u0005\u00c7d\u0002\u014f\u0150\u0005\u00a9U\u0002",
"\u0150\u0151\u0005\u00c3b\u0002\u0151H\u0003\u0002\u0002\u0002\u0152",
"\u0153\u0005\u00abV\u0002\u0153\u0154\u0005\u00bd_\u0002\u0154\u0155",
"\u0005\u00c3b\u0002\u0155J\u0003\u0002\u0002\u0002\u0156\u0157\u0005",
"\u00adW\u0002\u0157\u0158\u0005\u00c3b\u0002\u0158\u0159\u0005\u00a1",
"Q\u0002\u0159\u015a\u0005\u00bf`\u0002\u015a\u015b\u0005\u00afX\u0002",
"\u015bL\u0003\u0002\u0002\u0002\u015c\u015d\u0005\u00b1Y\u0002\u015d",
"\u015e\u0005\u00bb^\u0002\u015eN\u0003\u0002\u0002\u0002\u015f\u0160",
"\u0005\u00b1Y\u0002\u0160\u0161\u0005\u00bb^\u0002\u0161\u0162\u0005",
"\u00a3R\u0002\u0162\u0163\u0005\u00bd_\u0002\u0163\u0164\u0005\u00c9",
"e\u0002\u0164\u0165\u0005\u00bb^\u0002\u0165\u0166\u0005\u00a7T\u0002",
"\u0166P\u0003\u0002\u0002\u0002\u0167\u0168\u0005\u00b1Y\u0002\u0168",
"\u0169\u0005\u00bb^\u0002\u0169\u016a\u0005\u00c5c\u0002\u016a\u016b",
"\u0005\u00a9U\u0002\u016b\u016c\u0005\u00c3b\u0002\u016c\u016d\u0005",
"\u00c7d\u0002\u016dR\u0003\u0002\u0002\u0002\u016e\u016f\u0005\u00b1",
"Y\u0002\u016f\u0170\u0005\u00bb^\u0002\u0170\u0171\u0005\u00c7d\u0002",
"\u0171\u0172\u0005\u00bd_\u0002\u0172T\u0003\u0002\u0002\u0002\u0173",
"\u0174\u0005\u00b5[\u0002\u0174\u0175\u0007a\u0002\u0002\u0175\u0176",
"\u0005\u00c5c\u0002\u0176\u0177\u0005\u00afX\u0002\u0177\u0178\u0005",
"\u00bd_\u0002\u0178\u0179\u0005\u00c3b\u0002\u0179\u017a\u0005\u00c7",
"d\u0002\u017a\u017b\u0005\u00a9U\u0002\u017b\u017c\u0005\u00c5c\u0002",
"\u017c\u017d\u0005\u00c7d\u0002\u017d\u017e\u0007a\u0002\u0002\u017e",
"\u017f\u0005\u00bf`\u0002\u017f\u0180\u0005\u00a1Q\u0002\u0180\u0181",
"\u0005\u00c7d\u0002\u0181\u0182\u0005\u00afX\u0002\u0182\u0183\u0005",
"\u00c5c\u0002\u0183V\u0003\u0002\u0002\u0002\u0184\u0185\u0005\u00b7",
"\\\u0002\u0185\u0186\u0005\u00a9U\u0002\u0186\u0187\u0005\u00c7d\u0002",
"\u0187X\u0003\u0002\u0002\u0002\u0188\u0189\u0005\u00b7\\\u0002\u0189",
"\u018a\u0005\u00b1Y\u0002\u018a\u018b\u0005\u00b5[\u0002\u018b\u018c",
"\u0005\u00a9U\u0002\u018cZ\u0003\u0002\u0002\u0002\u018d\u018e\u0005",
"\u00b7\\\u0002\u018e\u018f\u0005\u00b1Y\u0002\u018f\u0190\u0005\u00b9",
"]\u0002\u0190\u0191\u0005\u00b1Y\u0002\u0191\u0192\u0005\u00c7d\u0002",
"\u0192\\\u0003\u0002\u0002\u0002\u0193\u0194\u0005\u00bb^\u0002\u0194",
"\u0195\u0005\u00bd_\u0002\u0195\u0196\u0005\u00bb^\u0002\u0196\u0197",
"\u0005\u00a9U\u0002\u0197^\u0003\u0002\u0002\u0002\u0198\u0199\u0005",
"\u00bb^\u0002\u0199\u019a\u0005\u00bd_\u0002\u019a\u019b\u0005\u00c7",
"d\u0002\u019b\u019e\u0003\u0002\u0002\u0002\u019c\u019e\u0007#\u0002",
"\u0002\u019d\u0198\u0003\u0002\u0002\u0002\u019d\u019c\u0003\u0002\u0002",
"\u0002\u019e`\u0003\u0002\u0002\u0002\u019f\u01a0\u0005\u00bb^\u0002",
"\u01a0\u01a1\u0005\u00c9e\u0002\u01a1\u01a2\u0005\u00b7\\\u0002\u01a2",
"\u01a3\u0005\u00b7\\\u0002\u01a3b\u0003\u0002\u0002\u0002\u01a4\u01a5",
"\u0005\u00bd_\u0002\u01a5\u01a6\u0005\u00c3b\u0002\u01a6\u01aa\u0003",
"\u0002\u0002\u0002\u01a7\u01a8\u0007~\u0002\u0002\u01a8\u01aa\u0007",
"~\u0002\u0002\u01a9\u01a4\u0003\u0002\u0002\u0002\u01a9\u01a7\u0003",
"\u0002\u0002\u0002\u01aad\u0003\u0002\u0002\u0002\u01ab\u01ac\u0005",
"\u00bd_\u0002\u01ac\u01ad\u0005\u00c9e\u0002\u01ad\u01ae\u0005\u00c7",
"d\u0002\u01ae\u01af\u0005\u00a3R\u0002\u01af\u01b0\u0005\u00bd_\u0002",
"\u01b0\u01b1\u0005\u00c9e\u0002\u01b1\u01b2\u0005\u00bb^\u0002\u01b2",
"\u01b3\u0005\u00a7T\u0002\u01b3f\u0003\u0002\u0002\u0002\u01b4\u01b5",
"\u0005\u00c3b\u0002\u01b5\u01b6\u0005\u00a9U\u0002\u01b6\u01b7\u0005",
"\u00b9]\u0002\u01b7\u01b8\u0005\u00bd_\u0002\u01b8\u01b9\u0005\u00cb",
"f\u0002\u01b9\u01ba\u0005\u00a9U\u0002\u01bah\u0003\u0002\u0002\u0002",
"\u01bb\u01bc\u0005\u00c3b\u0002\u01bc\u01bd\u0005\u00a9U\u0002\u01bd",
"\u01be\u0005\u00bf`\u0002\u01be\u01bf\u0005\u00b7\\\u0002\u01bf\u01c0",
"\u0005\u00a1Q\u0002\u01c0\u01c1\u0005\u00a5S\u0002\u01c1\u01c2\u0005",
"\u00a9U\u0002\u01c2j\u0003\u0002\u0002\u0002\u01c3\u01c4\u0005\u00c3",
"b\u0002\u01c4\u01c5\u0005\u00a9U\u0002\u01c5\u01c6\u0005\u00c7d\u0002",
"\u01c6\u01c7\u0005\u00c9e\u0002\u01c7\u01c8\u0005\u00c3b\u0002\u01c8",
"\u01c9\u0005\u00bb^\u0002\u01c9l\u0003\u0002\u0002\u0002\u01ca\u01cb",
"\u0005\u00c5c\u0002\u01cb\u01cc\u0005\u00afX\u0002\u01cc\u01cd\u0005",
"\u00bd_\u0002\u01cd\u01ce\u0005\u00c3b\u0002\u01ce\u01cf\u0005\u00c7",
"d\u0002\u01cf\u01d0\u0005\u00a9U\u0002\u01d0\u01d1\u0005\u00c5c\u0002",
"\u01d1\u01d2\u0005\u00c7d\u0002\u01d2\u01d3\u0007a\u0002\u0002\u01d3",
"\u01d4\u0005\u00bf`\u0002\u01d4\u01d5\u0005\u00a1Q\u0002\u01d5\u01d6",
"\u0005\u00c7d\u0002\u01d6\u01d7\u0005\u00afX\u0002\u01d7n\u0003\u0002",
"\u0002\u0002\u01d8\u01d9\u0005\u00c5c\u0002\u01d9\u01da\u0005\u00bd",
"_\u0002\u01da\u01db\u0005\u00c3b\u0002\u01db\u01dc\u0005\u00c7d\u0002",
"\u01dcp\u0003\u0002\u0002\u0002\u01dd\u01de\u0005\u00c7d\u0002\u01de",
"\u01df\u0005\u00c3b\u0002\u01df\u01e0\u0005\u00c9e\u0002\u01e0\u01e1",
"\u0005\u00a9U\u0002\u01e1r\u0003\u0002\u0002\u0002\u01e2\u01e3\u0005",
"\u00c9e\u0002\u01e3\u01e4\u0005\u00bf`\u0002\u01e4\u01e5\u0005\u00a7",
"T\u0002\u01e5\u01e6\u0005\u00a1Q\u0002\u01e6\u01e7\u0005\u00c7d\u0002",
"\u01e7\u01e8\u0005\u00a9U\u0002\u01e8t\u0003\u0002\u0002\u0002\u01e9",
"\u01ea\u0005\u00c9e\u0002\u01ea\u01eb\u0005\u00bf`\u0002\u01eb\u01ec",
"\u0005\u00c5c\u0002\u01ec\u01ed\u0005\u00a9U\u0002\u01ed\u01ee\u0005",
"\u00c3b\u0002\u01ee\u01ef\u0005\u00c7d\u0002\u01efv\u0003\u0002\u0002",
"\u0002\u01f0\u01f1\u0005\u00cdg\u0002\u01f1\u01f2\u0005\u00b1Y\u0002",
"\u01f2\u01f3\u0005\u00c7d\u0002\u01f3\u01f4\u0005\u00afX\u0002\u01f4",
"x\u0003\u0002\u0002\u0002\u01f5\u01f6\u0005\u00b5[\u0002\u01f6\u01f7",
"\u0005\u00a9U\u0002\u01f7\u01f8\u0005\u00a9U\u0002\u01f8\u01f9\u0005",
"\u00bf`\u0002\u01f9z\u0003\u0002\u0002\u0002\u01fa\u01fb\u0005\u00a5",
"S\u0002\u01fb\u01fc\u0005\u00bd_\u0002\u01fc\u01fd\u0005\u00c9e\u0002",
"\u01fd\u01fe\u0005\u00bb^\u0002\u01fe\u01ff\u0005\u00c7d\u0002\u01ff",
"|\u0003\u0002\u0002\u0002\u0200\u0201\u0005\u00bd_\u0002\u0201\u0202",
"\u0005\u00bf`\u0002\u0202\u0203\u0005\u00c7d\u0002\u0203\u0204\u0005",
"\u00b1Y\u0002\u0204\u0205\u0005\u00bd_\u0002\u0205\u0206\u0005\u00bb",
"^\u0002\u0206\u0207\u0005\u00c5c\u0002\u0207~\u0003\u0002\u0002\u0002",
"\u0208\u0209\u0005\u00bf`\u0002\u0209\u020a\u0005\u00c3b\u0002\u020a",
"\u020b\u0005\u00c9e\u0002\u020b\u020c\u0005\u00bb^\u0002\u020c\u020d",
"\u0005\u00a9U\u0002\u020d\u0080\u0003\u0002\u0002\u0002\u020e\u020f",
"\u0005\u00c5c\u0002\u020f\u0210\u0005\u00a9U\u0002\u0210\u0211\u0005",
"\u00a1Q\u0002\u0211\u0212\u0005\u00c3b\u0002\u0212\u0213\u0005\u00a5",
"S\u0002\u0213\u0214\u0005\u00afX\u0002\u0214\u0082\u0003\u0002\u0002",
"\u0002\u0215\u0216\u0005\u00c7d\u0002\u0216\u0217\u0005\u00bd_\u0002",
"\u0217\u0084\u0003\u0002\u0002\u0002\u0218\u0219\u0005\u00a5S\u0002",
"\u0219\u021a\u0005\u00c9e\u0002\u021a\u021b\u0005\u00c3b\u0002\u021b",
"\u021c\u0005\u00c3b\u0002\u021c\u021d\u0005\u00a9U\u0002\u021d\u021e",
"\u0005\u00bb^\u0002\u021e\u021f\u0005\u00c7d\u0002\u021f\u0086\u0003",
"\u0002\u0002\u0002\u0220\u0221\u0005\u00bb^\u0002\u0221\u0222\u0005",
"\u00a9U\u0002\u0222\u0223\u0005\u00cdg\u0002\u0223\u0088\u0003\u0002",
"\u0002\u0002\u0224\u0225\u0005\u00bd_\u0002\u0225\u0226\u0005\u00b7",
"\\\u0002\u0226\u0227\u0005\u00a7T\u0002\u0227\u008a\u0003\u0002\u0002",
"\u0002\u0228\u022c\t\u0002\u0002\u0002\u0229\u022b\t\u0003\u0002\u0002",
"\u022a\u0229\u0003\u0002\u0002\u0002\u022b\u022e\u0003\u0002\u0002\u0002",
"\u022c\u022a\u0003\u0002\u0002\u0002\u022c\u022d\u0003\u0002\u0002\u0002",
"\u022d\u008c\u0003\u0002\u0002\u0002\u022e\u022c\u0003\u0002\u0002\u0002",
"\u022f\u0233\t\u0004\u0002\u0002\u0230\u0232\u0005\u009fP\u0002\u0231",
"\u0230\u0003\u0002\u0002\u0002\u0232\u0235\u0003\u0002\u0002\u0002\u0233",
"\u0231\u0003\u0002\u0002\u0002\u0233\u0234\u0003\u0002\u0002\u0002\u0234",
"\u0248\u0003\u0002\u0002\u0002\u0235\u0233\u0003\u0002\u0002\u0002\u0236",
"\u0248\u00072\u0002\u0002\u0237\u0238\u00072\u0002\u0002\u0238\u0239",
"\u0007z\u0002\u0002\u0239\u023b\u0003\u0002\u0002\u0002\u023a\u023c",
"\u0005\u009dO\u0002\u023b\u023a\u0003\u0002\u0002\u0002\u023c\u023d",
"\u0003\u0002\u0002\u0002\u023d\u023b\u0003\u0002\u0002\u0002\u023d\u023e",
"\u0003\u0002\u0002\u0002\u023e\u0248\u0003\u0002\u0002\u0002\u023f\u0240",
"\u00072\u0002\u0002\u0240\u0241\u0007d\u0002\u0002\u0241\u0243\u0003",
"\u0002\u0002\u0002\u0242\u0244\t\u0005\u0002\u0002\u0243\u0242\u0003",
"\u0002\u0002\u0002\u0244\u0245\u0003\u0002\u0002\u0002\u0245\u0243\u0003",
"\u0002\u0002\u0002\u0245\u0246\u0003\u0002\u0002\u0002\u0246\u0248\u0003",
"\u0002\u0002\u0002\u0247\u022f\u0003\u0002\u0002\u0002\u0247\u0236\u0003",
"\u0002\u0002\u0002\u0247\u0237\u0003\u0002\u0002\u0002\u0247\u023f\u0003",
"\u0002\u0002\u0002\u0248\u008e\u0003\u0002\u0002\u0002\u0249\u024d\t",
"\u0004\u0002\u0002\u024a\u024c\u0005\u009fP\u0002\u024b\u024a\u0003",
"\u0002\u0002\u0002\u024c\u024f\u0003\u0002\u0002\u0002\u024d\u024b\u0003",
"\u0002\u0002\u0002\u024d\u024e\u0003\u0002\u0002\u0002\u024e\u0252\u0003",
"\u0002\u0002\u0002\u024f\u024d\u0003\u0002\u0002\u0002\u0250\u0252\u0007",
"2\u0002\u0002\u0251\u0249\u0003\u0002\u0002\u0002\u0251\u0250\u0003",
"\u0002\u0002\u0002\u0251\u0252\u0003\u0002\u0002\u0002\u0252\u0253\u0003",
"\u0002\u0002\u0002\u0253\u0255\u00070\u0002\u0002\u0254\u0256\u0005",
"\u009fP\u0002\u0255\u0254\u0003\u0002\u0002\u0002\u0256\u0257\u0003",
"\u0002\u0002\u0002\u0257\u0255\u0003\u0002\u0002\u0002\u0257\u0258\u0003",
"\u0002\u0002\u0002\u0258\u0262\u0003\u0002\u0002\u0002\u0259\u025b\u0005",
"\u00a9U\u0002\u025a\u025c\t\u0006\u0002\u0002\u025b\u025a\u0003\u0002",
"\u0002\u0002\u025b\u025c\u0003\u0002\u0002\u0002\u025c\u025e\u0003\u0002",
"\u0002\u0002\u025d\u025f\u0005\u009fP\u0002\u025e\u025d\u0003\u0002",
"\u0002\u0002\u025f\u0260\u0003\u0002\u0002\u0002\u0260\u025e\u0003\u0002",
"\u0002\u0002\u0260\u0261\u0003\u0002\u0002\u0002\u0261\u0263\u0003\u0002",
"\u0002\u0002\u0262\u0259\u0003\u0002\u0002\u0002\u0262\u0263\u0003\u0002",
"\u0002\u0002\u0263\u0090\u0003\u0002\u0002\u0002\u0264\u0265\u0007B",
"\u0002\u0002\u0265\u0266\u0005\u008bF\u0002\u0266\u0092\u0003\u0002",
"\u0002\u0002\u0267\u026f\u0007)\u0002\u0002\u0268\u0269\u0007^\u0002",
"\u0002\u0269\u026e\u000b\u0002\u0002\u0002\u026a\u026b\u0007)\u0002",
"\u0002\u026b\u026e\u0007)\u0002\u0002\u026c\u026e\n\u0007\u0002\u0002",
"\u026d\u0268\u0003\u0002\u0002\u0002\u026d\u026a\u0003\u0002\u0002\u0002",
"\u026d\u026c\u0003\u0002\u0002\u0002\u026e\u0271\u0003\u0002\u0002\u0002",
"\u026f\u026d\u0003\u0002\u0002\u0002\u026f\u0270\u0003\u0002\u0002\u0002",
"\u0270\u0272\u0003\u0002\u0002\u0002\u0271\u026f\u0003\u0002\u0002\u0002",
"\u0272\u0280\u0007)\u0002\u0002\u0273\u027b\u0007$\u0002\u0002\u0274",
"\u0275\u0007^\u0002\u0002\u0275\u027a\u000b\u0002\u0002\u0002\u0276",
"\u0277\u0007$\u0002\u0002\u0277\u027a\u0007$\u0002\u0002\u0278\u027a",
"\n\b\u0002\u0002\u0279\u0274\u0003\u0002\u0002\u0002\u0279\u0276\u0003",
"\u0002\u0002\u0002\u0279\u0278\u0003\u0002\u0002\u0002\u027a\u027d\u0003",
"\u0002\u0002\u0002\u027b\u0279\u0003\u0002\u0002\u0002\u027b\u027c\u0003",
"\u0002\u0002\u0002\u027c\u027e\u0003\u0002\u0002\u0002\u027d\u027b\u0003",
"\u0002\u0002\u0002\u027e\u0280\u0007$\u0002\u0002\u027f\u0267\u0003",
"\u0002\u0002\u0002\u027f\u0273\u0003\u0002\u0002\u0002\u0280\u0094\u0003",
"\u0002\u0002\u0002\u0281\u0282\u00071\u0002\u0002\u0282\u0283\u0007",
"1\u0002\u0002\u0283\u0287\u0003\u0002\u0002\u0002\u0284\u0286\n\t\u0002",
"\u0002\u0285\u0284\u0003\u0002\u0002\u0002\u0286\u0289\u0003\u0002\u0002",
"\u0002\u0287\u0285\u0003\u0002\u0002\u0002\u0287\u0288\u0003\u0002\u0002",
"\u0002\u0288\u028f\u0003\u0002\u0002\u0002\u0289\u0287\u0003\u0002\u0002",
"\u0002\u028a\u028c\u0007\u000f\u0002\u0002\u028b\u028a\u0003\u0002\u0002",
"\u0002\u028b\u028c\u0003\u0002\u0002\u0002\u028c\u028d\u0003\u0002\u0002",
"\u0002\u028d\u0290\u0007\f\u0002\u0002\u028e\u0290\u0007\u0002\u0002",
"\u0003\u028f\u028b\u0003\u0002\u0002\u0002\u028f\u028e\u0003\u0002\u0002",
"\u0002\u0290\u0291\u0003\u0002\u0002\u0002\u0291\u0292\bK\u0002\u0002",
"\u0292\u0096\u0003\u0002\u0002\u0002\u0293\u0294\u00071\u0002\u0002",
"\u0294\u0295\u0007,\u0002\u0002\u0295\u0299\u0003\u0002\u0002\u0002",
"\u0296\u0298\u000b\u0002\u0002\u0002\u0297\u0296\u0003\u0002\u0002\u0002",
"\u0298\u029b\u0003\u0002\u0002\u0002\u0299\u029a\u0003\u0002\u0002\u0002",
"\u0299\u0297\u0003\u0002\u0002\u0002\u029a\u029c\u0003\u0002\u0002\u0002",
"\u029b\u0299\u0003\u0002\u0002\u0002\u029c\u029d\u0007,\u0002\u0002",
"\u029d\u029e\u00071\u0002\u0002\u029e\u029f\u0003\u0002\u0002\u0002",
"\u029f\u02a0\bL\u0002\u0002\u02a0\u0098\u0003\u0002\u0002\u0002\u02a1",
"\u02a2\t\n\u0002\u0002\u02a2\u02a3\u0003\u0002\u0002\u0002\u02a3\u02a4",
"\bM\u0002\u0002\u02a4\u009a\u0003\u0002\u0002\u0002\u02a5\u02a6\u000b",
"\u0002\u0002\u0002\u02a6\u009c\u0003\u0002\u0002\u0002\u02a7\u02a8\t",
"\u000b\u0002\u0002\u02a8\u009e\u0003\u0002\u0002\u0002\u02a9\u02aa\t",
"\f\u0002\u0002\u02aa\u00a0\u0003\u0002\u0002\u0002\u02ab\u02ac\t\r\u0002",
"\u0002\u02ac\u00a2\u0003\u0002\u0002\u0002\u02ad\u02ae\t\u000e\u0002",
"\u0002\u02ae\u00a4\u0003\u0002\u0002\u0002\u02af\u02b0\t\u000f\u0002",
"\u0002\u02b0\u00a6\u0003\u0002\u0002\u0002\u02b1\u02b2\t\u0010\u0002",
"\u0002\u02b2\u00a8\u0003\u0002\u0002\u0002\u02b3\u02b4\t\u0011\u0002",
"\u0002\u02b4\u00aa\u0003\u0002\u0002\u0002\u02b5\u02b6\t\u0012\u0002",
"\u0002\u02b6\u00ac\u0003\u0002\u0002\u0002\u02b7\u02b8\t\u0013\u0002",
"\u0002\u02b8\u00ae\u0003\u0002\u0002\u0002\u02b9\u02ba\t\u0014\u0002",
"\u0002\u02ba\u00b0\u0003\u0002\u0002\u0002\u02bb\u02bc\t\u0015\u0002",
"\u0002\u02bc\u00b2\u0003\u0002\u0002\u0002\u02bd\u02be\t\u0016\u0002",
"\u0002\u02be\u00b4\u0003\u0002\u0002\u0002\u02bf\u02c0\t\u0017\u0002",
"\u0002\u02c0\u00b6\u0003\u0002\u0002\u0002\u02c1\u02c2\t\u0018\u0002",
"\u0002\u02c2\u00b8\u0003\u0002\u0002\u0002\u02c3\u02c4\t\u0019\u0002",
"\u0002\u02c4\u00ba\u0003\u0002\u0002\u0002\u02c5\u02c6\t\u001a\u0002",
"\u0002\u02c6\u00bc\u0003\u0002\u0002\u0002\u02c7\u02c8\t\u001b\u0002",
"\u0002\u02c8\u00be\u0003\u0002\u0002\u0002\u02c9\u02ca\t\u001c\u0002",
"\u0002\u02ca\u00c0\u0003\u0002\u0002\u0002\u02cb\u02cc\t\u001d\u0002",
"\u0002\u02cc\u00c2\u0003\u0002\u0002\u0002\u02cd\u02ce\t\u001e\u0002",
"\u0002\u02ce\u00c4\u0003\u0002\u0002\u0002\u02cf\u02d0\t\u001f\u0002",
"\u0002\u02d0\u00c6\u0003\u0002\u0002\u0002\u02d1\u02d2\t \u0002\u0002",
"\u02d2\u00c8\u0003\u0002\u0002\u0002\u02d3\u02d4\t!\u0002\u0002\u02d4",
"\u00ca\u0003\u0002\u0002\u0002\u02d5\u02d6\t\"\u0002\u0002\u02d6\u00cc",
"\u0003\u0002\u0002\u0002\u02d7\u02d8\t#\u0002\u0002\u02d8\u00ce\u0003",
"\u0002\u0002\u0002\u02d9\u02da\t$\u0002\u0002\u02da\u00d0\u0003\u0002",
"\u0002\u0002\u02db\u02dc\t%\u0002\u0002\u02dc\u00d2\u0003\u0002\u0002",
"\u0002\u02dd\u02de\t&\u0002\u0002\u02de\u00d4\u0003\u0002\u0002\u0002",
"\u02df\u02e0\u000b\u0002\u0002\u0002\u02e0\u02e1\u0003\u0002\u0002\u0002",
"\u02e1\u02e2\bk\u0003\u0002\u02e2\u00d6\u0003\u0002\u0002\u0002\u001a",
"\u0002\u0125\u019d\u01a9\u022c\u0233\u023d\u0245\u0247\u024d\u0251\u0257",
"\u025b\u0260\u0262\u026d\u026f\u0279\u027b\u027f\u0287\u028b\u028f\u0299",
"\u0004\u0002\u0003\u0002\u0002\u0004\u0002"].join("");
const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) );
export default class CAQLLexer extends antlr4.Lexer {
static grammarFileName = "CAQLLexer.g4";
static channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "ERRORCHANNEL" ];
static modeNames = [ "DEFAULT_MODE" ];
static literalNames = [ null, "'.'", "'=~'", "'!~'", "'=='", "'!='", "'<'",
"'>'", "'<='", "'>='", "'+'", "'-'", "'*'", "'/'",
"'%'", "'?'", "':'", "'::'", "'..'", "','", "'('",
"')'", "'{'", "'}'", "'['", "']'" ];
static symbolicNames = [ null, "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH",
"T_EQ", "T_NE", "T_LT", "T_GT", "T_LE", "T_GE",
"T_PLUS", "T_MINUS", "T_TIMES", "T_DIV", "T_MOD",
"T_QUESTION", "T_COLON", "T_SCOPE", "T_RANGE",
"T_COMMA", "T_OPEN", "T_CLOSE", "T_OBJECT_OPEN",
"T_OBJECT_CLOSE", "T_ARRAY_OPEN", "T_ARRAY_CLOSE",
"T_AGGREGATE", "T_ALL", "T_AND", "T_ANY", "T_ASC",
"T_COLLECT", "T_DESC", "T_DISTINCT", "T_FALSE",
"T_FILTER", "T_FOR", "T_GRAPH", "T_IN", "T_INBOUND",
"T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS", "T_LET",
"T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE",
"T_RETURN", "T_SHORTEST_PATH", "T_SORT", "T_TRUE",
"T_UPDATE", "T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT",
"T_OPTIONS", "T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT",
"T_NEW", "T_OLD", "T_STRING", "T_INT", "T_FLOAT",
"T_PARAMETER", "T_QUOTED_STRING", "SINGLE_LINE_COMMENT",
"MULTILINE_COMMENT", "SPACES", "UNEXPECTED_CHAR",
"ERROR_RECONGNIGION" ];
static ruleNames = [ "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH", "T_EQ",
"T_NE", "T_LT", "T_GT", "T_LE", "T_GE", "T_PLUS",
"T_MINUS", "T_TIMES", "T_DIV", "T_MOD", "T_QUESTION",
"T_COLON", "T_SCOPE", "T_RANGE", "T_COMMA", "T_OPEN",
"T_CLOSE", "T_OBJECT_OPEN", "T_OBJECT_CLOSE", "T_ARRAY_OPEN",
"T_ARRAY_CLOSE", "T_AGGREGATE", "T_ALL", "T_AND",
"T_ANY", "T_ASC", "T_COLLECT", "T_DESC", "T_DISTINCT",
"T_FALSE", "T_FILTER", "T_FOR", "T_GRAPH", "T_IN",
"T_INBOUND", "T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS",
"T_LET", "T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE", "T_RETURN",
"T_SHORTEST_PATH", "T_SORT", "T_TRUE", "T_UPDATE",
"T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT", "T_OPTIONS",
"T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT", "T_NEW",
"T_OLD", "T_STRING", "T_INT", "T_FLOAT", "T_PARAMETER",
"T_QUOTED_STRING", "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT",
"SPACES", "UNEXPECTED_CHAR", "HEX_DIGIT", "DIGIT",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z", "ERROR_RECONGNIGION" ];
constructor(input) {
super(input)
this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache());
}
get atn() {
return atn;
}
}
CAQLLexer.EOF = antlr4.Token.EOF;
CAQLLexer.DOT = 1;
CAQLLexer.T_REGEX_MATCH = 2;
CAQLLexer.T_REGEX_NON_MATCH = 3;
CAQLLexer.T_EQ = 4;
CAQLLexer.T_NE = 5;
CAQLLexer.T_LT = 6;
CAQLLexer.T_GT = 7;
CAQLLexer.T_LE = 8;
CAQLLexer.T_GE = 9;
CAQLLexer.T_PLUS = 10;
CAQLLexer.T_MINUS = 11;
CAQLLexer.T_TIMES = 12;
CAQLLexer.T_DIV = 13;
CAQLLexer.T_MOD = 14;
CAQLLexer.T_QUESTION = 15;
CAQLLexer.T_COLON = 16;
CAQLLexer.T_SCOPE = 17;
CAQLLexer.T_RANGE = 18;
CAQLLexer.T_COMMA = 19;
CAQLLexer.T_OPEN = 20;
CAQLLexer.T_CLOSE = 21;
CAQLLexer.T_OBJECT_OPEN = 22;
CAQLLexer.T_OBJECT_CLOSE = 23;
CAQLLexer.T_ARRAY_OPEN = 24;
CAQLLexer.T_ARRAY_CLOSE = 25;
CAQLLexer.T_AGGREGATE = 26;
CAQLLexer.T_ALL = 27;
CAQLLexer.T_AND = 28;
CAQLLexer.T_ANY = 29;
CAQLLexer.T_ASC = 30;
CAQLLexer.T_COLLECT = 31;
CAQLLexer.T_DESC = 32;
CAQLLexer.T_DISTINCT = 33;
CAQLLexer.T_FALSE = 34;
CAQLLexer.T_FILTER = 35;
CAQLLexer.T_FOR = 36;
CAQLLexer.T_GRAPH = 37;
CAQLLexer.T_IN = 38;
CAQLLexer.T_INBOUND = 39;
CAQLLexer.T_INSERT = 40;
CAQLLexer.T_INTO = 41;
CAQLLexer.T_K_SHORTEST_PATHS = 42;
CAQLLexer.T_LET = 43;
CAQLLexer.T_LIKE = 44;
CAQLLexer.T_LIMIT = 45;
CAQLLexer.T_NONE = 46;
CAQLLexer.T_NOT = 47;
CAQLLexer.T_NULL = 48;
CAQLLexer.T_OR = 49;
CAQLLexer.T_OUTBOUND = 50;
CAQLLexer.T_REMOVE = 51;
CAQLLexer.T_REPLACE = 52;
CAQLLexer.T_RETURN = 53;
CAQLLexer.T_SHORTEST_PATH = 54;
CAQLLexer.T_SORT = 55;
CAQLLexer.T_TRUE = 56;
CAQLLexer.T_UPDATE = 57;
CAQLLexer.T_UPSERT = 58;
CAQLLexer.T_WITH = 59;
CAQLLexer.T_KEEP = 60;
CAQLLexer.T_COUNT = 61;
CAQLLexer.T_OPTIONS = 62;
CAQLLexer.T_PRUNE = 63;
CAQLLexer.T_SEARCH = 64;
CAQLLexer.T_TO = 65;
CAQLLexer.T_CURRENT = 66;
CAQLLexer.T_NEW = 67;
CAQLLexer.T_OLD = 68;
CAQLLexer.T_STRING = 69;
CAQLLexer.T_INT = 70;
CAQLLexer.T_FLOAT = 71;
CAQLLexer.T_PARAMETER = 72;
CAQLLexer.T_QUOTED_STRING = 73;
CAQLLexer.SINGLE_LINE_COMMENT = 74;
CAQLLexer.MULTILINE_COMMENT = 75;
CAQLLexer.SPACES = 76;
CAQLLexer.UNEXPECTED_CHAR = 77;
CAQLLexer.ERROR_RECONGNIGION = 78;
CAQLLexer.ERRORCHANNEL = 2;
+103
View File
@@ -0,0 +1,103 @@
DOT=1
T_REGEX_MATCH=2
T_REGEX_NON_MATCH=3
T_EQ=4
T_NE=5
T_LT=6
T_GT=7
T_LE=8
T_GE=9
T_PLUS=10
T_MINUS=11
T_TIMES=12
T_DIV=13
T_MOD=14
T_QUESTION=15
T_COLON=16
T_SCOPE=17
T_RANGE=18
T_COMMA=19
T_OPEN=20
T_CLOSE=21
T_OBJECT_OPEN=22
T_OBJECT_CLOSE=23
T_ARRAY_OPEN=24
T_ARRAY_CLOSE=25
T_AGGREGATE=26
T_ALL=27
T_AND=28
T_ANY=29
T_ASC=30
T_COLLECT=31
T_DESC=32
T_DISTINCT=33
T_FALSE=34
T_FILTER=35
T_FOR=36
T_GRAPH=37
T_IN=38
T_INBOUND=39
T_INSERT=40
T_INTO=41
T_K_SHORTEST_PATHS=42
T_LET=43
T_LIKE=44
T_LIMIT=45
T_NONE=46
T_NOT=47
T_NULL=48
T_OR=49
T_OUTBOUND=50
T_REMOVE=51
T_REPLACE=52
T_RETURN=53
T_SHORTEST_PATH=54
T_SORT=55
T_TRUE=56
T_UPDATE=57
T_UPSERT=58
T_WITH=59
T_KEEP=60
T_COUNT=61
T_OPTIONS=62
T_PRUNE=63
T_SEARCH=64
T_TO=65
T_CURRENT=66
T_NEW=67
T_OLD=68
T_STRING=69
T_INT=70
T_FLOAT=71
T_PARAMETER=72
T_QUOTED_STRING=73
SINGLE_LINE_COMMENT=74
MULTILINE_COMMENT=75
SPACES=76
UNEXPECTED_CHAR=77
ERROR_RECONGNIGION=78
'.'=1
'=~'=2
'!~'=3
'=='=4
'!='=5
'<'=6
'>'=7
'<='=8
'>='=9
'+'=10
'-'=11
'*'=12
'/'=13
'%'=14
'?'=15
':'=16
'::'=17
'..'=18
','=19
'('=20
')'=21
'{'=22
'}'=23
'['=24
']'=25
+178
View File
@@ -0,0 +1,178 @@
token literal names:
null
'.'
'=~'
'!~'
'=='
'!='
'<'
'>'
'<='
'>='
'+'
'-'
'*'
'/'
'%'
'?'
':'
'::'
'..'
','
'('
')'
'{'
'}'
'['
']'
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
token symbolic names:
null
DOT
T_REGEX_MATCH
T_REGEX_NON_MATCH
T_EQ
T_NE
T_LT
T_GT
T_LE
T_GE
T_PLUS
T_MINUS
T_TIMES
T_DIV
T_MOD
T_QUESTION
T_COLON
T_SCOPE
T_RANGE
T_COMMA
T_OPEN
T_CLOSE
T_OBJECT_OPEN
T_OBJECT_CLOSE
T_ARRAY_OPEN
T_ARRAY_CLOSE
T_AGGREGATE
T_ALL
T_AND
T_ANY
T_ASC
T_COLLECT
T_DESC
T_DISTINCT
T_FALSE
T_FILTER
T_FOR
T_GRAPH
T_IN
T_INBOUND
T_INSERT
T_INTO
T_K_SHORTEST_PATHS
T_LET
T_LIKE
T_LIMIT
T_NONE
T_NOT
T_NULL
T_OR
T_OUTBOUND
T_REMOVE
T_REPLACE
T_RETURN
T_SHORTEST_PATH
T_SORT
T_TRUE
T_UPDATE
T_UPSERT
T_WITH
T_KEEP
T_COUNT
T_OPTIONS
T_PRUNE
T_SEARCH
T_TO
T_CURRENT
T_NEW
T_OLD
T_STRING
T_INT
T_FLOAT
T_PARAMETER
T_QUOTED_STRING
SINGLE_LINE_COMMENT
MULTILINE_COMMENT
SPACES
UNEXPECTED_CHAR
ERROR_RECONGNIGION
rule names:
parse
expression
operator_unary
reference
compound_value
function_call
value_literal
array
object
object_element
object_element_name
atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 80, 192, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 32, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 48, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 66, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 86, 10, 3, 12, 3, 14, 3, 89, 11, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 97, 10, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 107, 10, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 117, 10, 5, 12, 5, 14, 5, 120, 11, 5, 3, 6, 3, 6, 5, 6, 124, 10, 6, 3, 7, 3, 7, 3, 7, 5, 7, 129, 10, 7, 3, 7, 3, 7, 7, 7, 133, 10, 7, 12, 7, 14, 7, 136, 11, 7, 3, 7, 5, 7, 139, 10, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 5, 9, 147, 10, 9, 3, 9, 3, 9, 7, 9, 151, 10, 9, 12, 9, 14, 9, 154, 11, 9, 3, 9, 5, 9, 157, 10, 9, 3, 9, 3, 9, 3, 10, 3, 10, 5, 10, 163, 10, 10, 3, 10, 3, 10, 7, 10, 167, 10, 10, 12, 10, 14, 10, 170, 11, 10, 3, 10, 5, 10, 173, 10, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 188, 10, 11, 3, 12, 3, 12, 3, 12, 4, 134, 152, 4, 4, 8, 13, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 2, 11, 3, 2, 12, 13, 3, 2, 14, 16, 3, 2, 8, 11, 3, 2, 6, 7, 5, 2, 29, 29, 31, 31, 48, 48, 4, 2, 6, 11, 40, 40, 4, 2, 4, 5, 46, 46, 7, 2, 36, 36, 50, 50, 58, 58, 72, 73, 75, 75, 4, 2, 71, 71, 75, 75, 2, 216, 2, 24, 3, 2, 2, 2, 4, 31, 3, 2, 2, 2, 6, 96, 3, 2, 2, 2, 8, 106, 3, 2, 2, 2, 10, 123, 3, 2, 2, 2, 12, 125, 3, 2, 2, 2, 14, 142, 3, 2, 2, 2, 16, 144, 3, 2, 2, 2, 18, 160, 3, 2, 2, 2, 20, 187, 3, 2, 2, 2, 22, 189, 3, 2, 2, 2, 24, 25, 5, 4, 3, 2, 25, 26, 7, 2, 2, 3, 26, 3, 3, 2, 2, 2, 27, 28, 8, 3, 1, 2, 28, 32, 5, 14, 8, 2, 29, 32, 5, 8, 5, 2, 30, 32, 5, 6, 4, 2, 31, 27, 3, 2, 2, 2, 31, 29, 3, 2, 2, 2, 31, 30, 3, 2, 2, 2, 32, 87, 3, 2, 2, 2, 33, 34, 12, 15, 2, 2, 34, 35, 9, 2, 2, 2, 35, 86, 5, 4, 3, 16, 36, 37, 12, 14, 2, 2, 37, 38, 9, 3, 2, 2, 38, 86, 5, 4, 3, 15, 39, 40, 12, 13, 2, 2, 40, 41, 7, 20, 2, 2, 41, 86, 5, 4, 3, 14, 42, 43, 12, 12, 2, 2, 43, 44, 9, 4, 2, 2, 44, 86, 5, 4, 3, 13, 45, 47, 12, 11, 2, 2, 46, 48, 7, 49, 2, 2, 47, 46, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 49, 3, 2, 2, 2, 49, 50, 7, 40, 2, 2, 50, 86, 5, 4, 3, 12, 51, 52, 12, 10, 2, 2, 52, 53, 9, 5, 2, 2, 53, 86, 5, 4, 3, 11, 54, 55, 12, 9, 2, 2, 55, 56, 9, 6, 2, 2, 56, 57, 9, 7, 2, 2, 57, 86, 5, 4, 3, 10, 58, 59, 12, 8, 2, 2, 59, 60, 9, 6, 2, 2, 60, 61, 7, 49, 2, 2, 61, 62, 7, 40, 2, 2, 62, 86, 5, 4, 3, 9, 63, 65, 12, 7, 2, 2, 64, 66, 7, 49, 2, 2, 65, 64, 3, 2, 2, 2, 65, 66, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 68, 9, 8, 2, 2, 68, 86, 5, 4, 3, 8, 69, 70, 12, 6, 2, 2, 70, 71, 7, 30, 2, 2, 71, 86, 5, 4, 3, 7, 72, 73, 12, 5, 2, 2, 73, 74, 7, 51, 2, 2, 74, 86, 5, 4, 3, 6, 75, 76, 12, 4, 2, 2, 76, 77, 7, 17, 2, 2, 77, 78, 5, 4, 3, 2, 78, 79, 7, 18, 2, 2, 79, 80, 5, 4, 3, 5, 80, 86, 3, 2, 2, 2, 81, 82, 12, 3, 2, 2, 82, 83, 7, 17, 2, 2, 83, 84, 7, 18, 2, 2, 84, 86, 5, 4, 3, 4, 85, 33, 3, 2, 2, 2, 85, 36, 3, 2, 2, 2, 85, 39, 3, 2, 2, 2, 85, 42, 3, 2, 2, 2, 85, 45, 3, 2, 2, 2, 85, 51, 3, 2, 2, 2, 85, 54, 3, 2, 2, 2, 85, 58, 3, 2, 2, 2, 85, 63, 3, 2, 2, 2, 85, 69, 3, 2, 2, 2, 85, 72, 3, 2, 2, 2, 85, 75, 3, 2, 2, 2, 85, 81, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 5, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 91, 7, 12, 2, 2, 91, 97, 5, 4, 3, 2, 92, 93, 7, 13, 2, 2, 93, 97, 5, 4, 3, 2, 94, 95, 7, 49, 2, 2, 95, 97, 5, 4, 3, 2, 96, 90, 3, 2, 2, 2, 96, 92, 3, 2, 2, 2, 96, 94, 3, 2, 2, 2, 97, 7, 3, 2, 2, 2, 98, 99, 8, 5, 1, 2, 99, 107, 7, 71, 2, 2, 100, 107, 5, 10, 6, 2, 101, 107, 5, 12, 7, 2, 102, 103, 7, 22, 2, 2, 103, 104, 5, 4, 3, 2, 104, 105, 7, 23, 2, 2, 105, 107, 3, 2, 2, 2, 106, 98, 3, 2, 2, 2, 106, 100, 3, 2, 2, 2, 106, 101, 3, 2, 2, 2, 106, 102, 3, 2, 2, 2, 107, 118, 3, 2, 2, 2, 108, 109, 12, 4, 2, 2, 109, 110, 7, 3, 2, 2, 110, 117, 7, 71, 2, 2, 111, 112, 12, 3, 2, 2, 112, 113, 7, 26, 2, 2, 113, 114, 5, 4, 3, 2, 114, 115, 7, 27, 2, 2, 115, 117, 3, 2, 2, 2, 116, 108, 3, 2, 2, 2, 116, 111, 3, 2, 2, 2, 117, 120, 3, 2, 2, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 9, 3, 2, 2, 2, 120, 118, 3, 2, 2, 2, 121, 124, 5, 16, 9, 2, 122, 124, 5, 18, 10, 2, 123, 121, 3, 2, 2, 2, 123, 122, 3, 2, 2, 2, 124, 11, 3, 2, 2, 2, 125, 126, 7, 71, 2, 2, 126, 128, 7, 22, 2, 2, 127, 129, 5, 4, 3, 2, 128, 127, 3, 2, 2, 2, 128, 129, 3, 2, 2, 2, 129, 134, 3, 2, 2, 2, 130, 131, 7, 21, 2, 2, 131, 133, 5, 4, 3, 2, 132, 130, 3, 2, 2, 2, 133, 136, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 135, 138, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 137, 139, 7, 21, 2, 2, 138, 137, 3, 2, 2, 2, 138, 139, 3, 2, 2, 2, 139, 140, 3, 2, 2, 2, 140, 141, 7, 23, 2, 2, 141, 13, 3, 2, 2, 2, 142, 143, 9, 9, 2, 2, 143, 15, 3, 2Line truncated
File diff suppressed because it is too large. Load diff
+103
View File
@@ -0,0 +1,103 @@
DOT=1
T_REGEX_MATCH=2
T_REGEX_NON_MATCH=3
T_EQ=4
T_NE=5
T_LT=6
T_GT=7
T_LE=8
T_GE=9
T_PLUS=10
T_MINUS=11
T_TIMES=12
T_DIV=13
T_MOD=14
T_QUESTION=15
T_COLON=16
T_SCOPE=17
T_RANGE=18
T_COMMA=19
T_OPEN=20
T_CLOSE=21
T_OBJECT_OPEN=22
T_OBJECT_CLOSE=23
T_ARRAY_OPEN=24
T_ARRAY_CLOSE=25
T_AGGREGATE=26
T_ALL=27
T_AND=28
T_ANY=29
T_ASC=30
T_COLLECT=31
T_DESC=32
T_DISTINCT=33
T_FALSE=34
T_FILTER=35
T_FOR=36
T_GRAPH=37
T_IN=38
T_INBOUND=39
T_INSERT=40
T_INTO=41
T_K_SHORTEST_PATHS=42
T_LET=43
T_LIKE=44
T_LIMIT=45
T_NONE=46
T_NOT=47
T_NULL=48
T_OR=49
T_OUTBOUND=50
T_REMOVE=51
T_REPLACE=52
T_RETURN=53
T_SHORTEST_PATH=54
T_SORT=55
T_TRUE=56
T_UPDATE=57
T_UPSERT=58
T_WITH=59
T_KEEP=60
T_COUNT=61
T_OPTIONS=62
T_PRUNE=63
T_SEARCH=64
T_TO=65
T_CURRENT=66
T_NEW=67
T_OLD=68
T_STRING=69
T_INT=70
T_FLOAT=71
T_PARAMETER=72
T_QUOTED_STRING=73
SINGLE_LINE_COMMENT=74
MULTILINE_COMMENT=75
SPACES=76
UNEXPECTED_CHAR=77
ERROR_RECONGNIGION=78
'.'=1
'=~'=2
'!~'=3
'=='=4
'!='=5
'<'=6
'>'=7
'<='=8
'>='=9
'+'=10
'-'=11
'*'=12
'/'=13
'%'=14
'?'=15
':'=16
'::'=17
'..'=18
','=19
'('=20
')'=21
'{'=22
'}'=23
'['=24
']'=25
@@ -0,0 +1,108 @@
// Generated from CAQLParser.g4 by ANTLR 4.9.2
// jshint ignore: start
import antlr4 from 'antlr4';
// This class defines a complete listener for a parse tree produced by CAQLParser.
export default class CAQLParserListener extends antlr4.tree.ParseTreeListener {
// Enter a parse tree produced by CAQLParser#parse.
enterParse(ctx) {
}
// Exit a parse tree produced by CAQLParser#parse.
exitParse(ctx) {
}
// Enter a parse tree produced by CAQLParser#expression.
enterExpression(ctx) {
}
// Exit a parse tree produced by CAQLParser#expression.
exitExpression(ctx) {
}
// Enter a parse tree produced by CAQLParser#operator_unary.
enterOperator_unary(ctx) {
}
// Exit a parse tree produced by CAQLParser#operator_unary.
exitOperator_unary(ctx) {
}
// Enter a parse tree produced by CAQLParser#reference.
enterReference(ctx) {
}
// Exit a parse tree produced by CAQLParser#reference.
exitReference(ctx) {
}
// Enter a parse tree produced by CAQLParser#compound_value.
enterCompound_value(ctx) {
}
// Exit a parse tree produced by CAQLParser#compound_value.
exitCompound_value(ctx) {
}
// Enter a parse tree produced by CAQLParser#function_call.
enterFunction_call(ctx) {
}
// Exit a parse tree produced by CAQLParser#function_call.
exitFunction_call(ctx) {
}
// Enter a parse tree produced by CAQLParser#value_literal.
enterValue_literal(ctx) {
}
// Exit a parse tree produced by CAQLParser#value_literal.
exitValue_literal(ctx) {
}
// Enter a parse tree produced by CAQLParser#array.
enterArray(ctx) {
}
// Exit a parse tree produced by CAQLParser#array.
exitArray(ctx) {
}
// Enter a parse tree produced by CAQLParser#object.
enterObject(ctx) {
}
// Exit a parse tree produced by CAQLParser#object.
exitObject(ctx) {
}
// Enter a parse tree produced by CAQLParser#object_element.
enterObject_element(ctx) {
}
// Exit a parse tree produced by CAQLParser#object_element.
exitObject_element(ctx) {
}
// Enter a parse tree produced by CAQLParser#object_element_name.
enterObject_element_name(ctx) {
}
// Exit a parse tree produced by CAQLParser#object_element_name.
exitObject_element_name(ctx) {
}
}
+46
View File
@@ -0,0 +1,46 @@
import lexerModule from "./grammar/CAQLLexer.js";
import parserModule from "./grammar/CAQLParser.js";
import antlr4 from "antlr4";
class ErrorListener extends antlr4.error.ErrorListener {
/**
* Checks syntax error
*
* @param {object} recognizer The parsing support code essentially. Most of it is error recovery stuff
* @param {object} symbol Offending symbol
* @param {int} line Line of offending symbol
* @param {int} column Position in line of offending symbol
* @param {string} message Error message
* @param {string} payload Stack trace
*/
syntaxError(
recognizer: any,
symbol: any,
line: number,
column: number,
message: string,
payload: string
) {
throw {symbol, line, column, message, payload};
}
}
export function validateCAQL(term: string): any {
const chars = new antlr4.InputStream(term);
const lexer = new lexerModule(chars);
const tokens = new antlr4.CommonTokenStream(lexer);
const parser = new parserModule(tokens);
const listener = new ErrorListener();
parser.removeErrorListeners();
parser.addErrorListener(listener);
try {
parser.parse()
return null;
} catch (error) {
return error;
}
}
+17
View File
@@ -0,0 +1,17 @@
export interface Problem {
title: string;
detail: string;
}
enum AlertType {
success = "success",
info = "info",
warning = "warning",
error = "error",
}
export interface Alert {
name: string;
detail: string;
type: AlertType;
}
+48
View File
@@ -0,0 +1,48 @@
<template>
<v-container>
<v-card style="background-color: #fff;" class="mt-8">
<div class="swagger" id="swagger" ></div>
</v-card>
</v-container>
</template>
<script lang="ts">
import SwaggerUI from 'swagger-ui';
import 'swagger-ui/dist/swagger-ui.css';
import Vue from "vue";
import spec from '../../../generated/community.json';
export default Vue.extend({
name: "API",
components: {},
mounted() {
SwaggerUI({
spec: spec,
dom_id: '#swagger',
oauth2RedirectUrl: location.href
})
}
});
</script>
<style>
#swagger a,
#swagger h1,
#swagger h2,
#swagger h3,
#swagger h4,
#swagger h5,
#swagger h6 {
color: black !important
}
#swagger .info {
padding: 0 10px 10px;
border-radius: 4px;
}
#swagger .servers-title,
#swagger .servers {
display: none;
}
</style>
+264
View File
@@ -0,0 +1,264 @@
<template>
<v-container>
<h1>{{ name }}</h1>
<v-divider class="my-2"></v-divider>
<h2 class="text--disabled" style="font-size: 12pt" v-if="artifact">
Status:
<v-menu offset-y class="mr-2">
<template v-slot:activator="{ on, attrs }">
<span v-bind="attrs" v-on="on">
<v-icon small class="mr-1" :color="statusColor(artifact.status)">{{ statusIcon(artifact.status) }}</v-icon>
<span :class="statusColor(artifact.status) + '--text'">{{ artifact.status | capitalize }}</span>
</span>
</template>
<v-list>
<v-list-item dense link v-for="state in otherStates" :key="state.id" @click="setStatus(state.id)">
<v-list-item-title>
Set status to <v-icon small>{{ statusIcon(state.id) }}</v-icon> {{ state.name }}
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
&middot;
Type:
<v-menu
:close-on-content-click="false"
offset-y
class="mr-2">
<template v-slot:activator="{ on, attrs }">
<span v-bind="attrs" v-on="on">
{{ artifact.type ? artifact.type : "empty" }}
</span>
</template>
<v-combobox
class="pt-6 pb-0 px-3"
style="background-color: white"
v-model="artifacttype"
:items="['ip', 'domain', 'md5', 'sha1', 'sha256', 'filename', 'url']"
label="Artifact Type"
@change="setArtifactType"
></v-combobox>
</v-menu>
</h2>
<v-divider class="mt-0 mb-4"></v-divider>
<div v-if="automations">
<v-card
v-for="automation in artifactautomations" :key="automation.id" class="mb-4" elevation="0" outlined>
<v-card-title>
{{ automation.id }}
<v-spacer></v-spacer>
<v-btn
v-if="artifact && artifact.enrichments && automation.id in artifact.enrichments"
@click="enrich(automation.id)"
elevation="0"
>
<v-icon>mdi-sync</v-icon>
</v-btn>
<v-btn v-else @click="enrich(automation.id)" elevation="0">
<v-icon>mdi-play</v-icon>
</v-btn>
</v-card-title>
<v-card-text v-if="artifact && artifact.enrichments && automation.id in artifact.enrichments && artifact.enrichments[automation.id].data">
<div class="template" v-if="artifact.enrichments[automation.id].html" v-html="artifact.enrichments[automation.id].html"></div>
<JSONHTML v-else :json="artifact.enrichments[automation.id].data"></JSONHTML>
</v-card-text>
</v-card>
</div>
<div v-if="artifact">
<div v-for="enrichment in artifact.enrichments" :key="enrichment.name" >
<v-card v-if="!hasautomation(enrichment.name)" outlined>
<v-card-title>
{{ enrichment.name }}
</v-card-title>
<v-card-text>
<vue-markdown>
{{ enrichment.data }}
</vue-markdown>
</v-card-text>
</v-card>
</div>
</div>
</v-container>
</template>
<script lang="ts">
import Vue from "vue";
import {
Artifact,
AutomationResponse, AutomationResponseTypeEnum, AutomationTypeEnum,
Type,
TypeColorEnum
} from "@/client";
import VueMarkdown from "vue-markdown";
import { API } from "@/services/api";
import JSONHTML from "../components/JSONHTML.vue";
interface State {
artifact?: Artifact;
automations?: Array<AutomationResponse>;
artifacttype: string;
}
export default Vue.extend({
name: "ArtifactPopup",
components: {
"vue-markdown": VueMarkdown,
JSONHTML,
},
props: ["id", "name"],
data: (): State => ({
artifact: undefined,
automations: undefined,
artifacttype: "unknown",
}),
watch: {
id: function(): void {
this.load();
},
name: function(): void {
this.load();
}
},
computed: {
artifactautomations: function (): Array<AutomationResponse> {
if (!this.automations) {
return [];
}
return this.lodash.filter(this.automations, (automation: AutomationResponse) => {
if (!automation || !automation.type) {
return true;
}
return this.lodash.includes(automation.type, AutomationResponseTypeEnum.Artifact)
})
},
ticketID(): number {
return parseInt(this.id, 10);
},
otherStates: function (): Array<Type> {
return this.lodash.filter(this.$store.state.settings.artifactStates, (state: Type) => {
if (!this.artifact || !this.artifact.status) {
return true;
}
return state.id !== this.artifact.status;
})
},
},
methods: {
setArtifactType() {
if (!this.artifact || !this.artifact.name || this.ticketID === undefined) {
return;
}
let artifact = this.artifact
artifact.type = this.artifacttype
API.setArtifact(this.ticketID, this.artifact.name, artifact).then((response) => {
this.$store.dispatch("alertSuccess", { name: "Artifact type changed", type: "success" })
if (response.data.artifacts) {
this.lodash.forEach(response.data.artifacts, (artifact) => {
if (artifact.name == this.name) {
this.artifact = artifact;
}
})
}
});
},
hasautomation(name: string): boolean {
let found = false;
this.lodash.forEach(this.automations, (automation) => {
if (automation.id === name) {
found = true
}
})
return found;
},
loadArtifact(id: number, artifact: string) {
API.getArtifact(id, artifact).then((response) => {
this.artifact = response.data;
});
},
loadAutomations() {
API.listAutomations().then((response) => {
this.automations = response.data;
});
},
enrich(automation: string) {
if (this.artifact === undefined || this.ticketID === undefined) {
return
}
API.runArtifact(this.ticketID, this.name, automation);
},
statusIcon: function (status: string): string {
let icon = "mdi-help";
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
if (status === state.id) {
icon = state.icon;
}
})
return icon;
},
statusColor: function (status: string) {
let color = TypeColorEnum.Info;
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
if (status === state.id && state.color) {
color = state.color
}
})
return color;
},
setStatus(status: string) {
if (!this.artifact || !this.artifact.name || this.ticketID === undefined) {
return;
}
let artifact = this.artifact
artifact.status = status
API.setArtifact(this.ticketID, this.artifact.name, artifact).then((response) => {
this.$store.dispatch("alertSuccess", { name: "Artifact status changed", type: "success" })
if (response.data.artifacts) {
this.lodash.forEach(response.data.artifacts, (artifact) => {
if (artifact.name == this.name) {
this.artifact = artifact;
}
})
}
});
},
load() {
this.loadArtifact(this.ticketID, this.name);
}
},
mounted(): void {
this.load();
this.loadAutomations();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (id === "tickets/" + this.ticketID) {
this.load();
}
});
})
},
});
</script>
<style>
.template {
overflow: auto;
}
.template table, .template th, .template td {
border: 1px solid #777 !important;
border-left: 0 !important;
border-right: 0 !important;
padding: 4px !important;
}
</style>
+131
View File
@@ -0,0 +1,131 @@
<template>
<div v-if="automation !== undefined" class="flex-grow-1 flex-column d-flex fill-height pa-8">
<v-alert v-if="readonly" type="info">You do not have write access to automations.</v-alert>
<h2 v-if="readonly">Automation: {{ automation.id }}</h2>
<h2 v-else-if="this.$route.params.id === 'new'">New Automation: {{ automation.id }}</h2>
<h2 v-else>Edit Automation: {{ automation.id }}</h2>
<v-row class="flex-grow-0 flex-shrink-0">
<v-col cols="12">
<v-text-field :readonly="readonly" label="ID" v-model="automation.id" class="flex-grow-0 flex-shrink-0"></v-text-field>
<v-select
label="Type"
:items="types"
item-text="id"
return-object
multiple
v-model="automation.type"
></v-select>
<v-text-field :readonly="readonly" label="Docker Image" v-model="automation.image" class="flex-grow-0 flex-shrink-0"></v-text-field>
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Script</v-subheader>
<div class="flex-grow-1 flex-shrink-1 overflow-scroll">
<Editor v-model="automation.script" lang="python" :readonly="readonly" ></Editor>
</div>
<AdvancedJSONSchemaEditor
@save="save"
:schema="automation.schema ? JSON.parse(automation.schema) : {}"
hidepreview
class="mt-4"
:readonly="readonly"></AdvancedJSONSchemaEditor>
</v-col>
</v-row>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Editor from "../components/Editor.vue";
import AdvancedJSONSchemaEditor from "../components/AdvancedJSONSchemaEditor.vue";
import {API} from "@/services/api";
import {AutomationResponse, AutomationForm, AutomationResponseTypeEnum} from "@/client";
import {DateTime} from "luxon";
interface State {
automation?: AutomationResponse;
data?: any;
valid: boolean;
}
export default Vue.extend({
name: "Automation",
components: { Editor, AdvancedJSONSchemaEditor },
data: (): State => ({
automation: undefined,
data: undefined,
valid: true,
}),
watch: {
$route: function () {
this.loadAutomation();
},
},
computed: {
readonly: function (): boolean {
return !this.hasRole("engineer:automation:write");
},
types: function (): Array<string> {
return [ AutomationResponseTypeEnum.Global, AutomationResponseTypeEnum.Playbook, AutomationResponseTypeEnum.Artifact ]
}
},
methods: {
save(schema) {
if (this.automation === undefined) {
return;
}
let automation = this.automation as any as AutomationForm;
automation.schema = schema;
if (this.$route.params.id == "new") {
API.createAutomation(automation);
} else {
API.updateAutomation(this.$route.params.id, automation);
}
},
loadAutomation() {
if (!this.$route.params.id) {
return;
}
if (this.$route.params.id == "new") {
this.automation = { id: "my-automation", image: "docker.io/ubuntu", script: "", type: [ AutomationResponseTypeEnum.Global, AutomationResponseTypeEnum.Playbook, AutomationResponseTypeEnum.Artifact ] };
} else {
API.getAutomation(this.$route.params.id).then((response) => {
this.automation = response.data;
});
}
},
hasRole: function (s: string): boolean {
if (this.$store.state.user.roles) {
return this.lodash.includes(this.$store.state.user.roles, s);
}
return false;
},
timeformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
dateformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
datetimeformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
},
mounted() {
this.loadAutomation();
},
});
</script>
+64
View File
@@ -0,0 +1,64 @@
<template>
<v-main style="min-height: 100vh">
<List
:items="automations"
routername="Automation"
itemid="id"
itemname="id"
singular="Automation"
plural="Automations"
writepermission="engineer:automation:write"
@delete="deleteAutomation"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {AutomationResponse} from "@/client";
import {API} from "@/services/api";
import List from "../components/List.vue";
interface State {
automations: Array<AutomationResponse>;
}
export default Vue.extend({
name: "AutomationList",
components: {List},
data: (): State => ({
automations: [],
}),
methods: {
loadAutomations() {
API.listAutomations().then((response) => {
this.automations = response.data;
});
},
deleteAutomation(name: string) {
API.deleteAutomation(name).then(() => {
this.loadAutomations();
});
},
},
mounted() {
this.loadAutomations();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "automations/")) {
reload = true;
}
});
if (reload) {
this.loadAutomations()
}
})
},
});
</script>
+219
View File
@@ -0,0 +1,219 @@
<template>
<v-main>
<v-row>
<v-col v-if="statistics" cols="12" lg="7">
<v-row>
<v-col cols="4">
<v-subheader>Unassigned tickets</v-subheader>
<span style="font-size: 60pt; text-align: center; display: block">
<router-link :to="{
name: 'TicketList',
params: { query: 'status == \'open\' AND !owner' }
}">
{{ statistics.unassigned }}
</router-link>
</span>
<v-subheader>Your tickets</v-subheader>
<span style="font-size: 60pt; text-align: center; display: block">
<router-link :to="{
name: 'TicketList',
params: { query: 'status == \'open\' AND owner == \'' + $store.state.user.id + '\'' }
}">
{{ $store.state.user.id in statistics.open_tickets_per_user ? statistics.open_tickets_per_user[$store.state.user.id] : 0 }}
</router-link>
</span>
</v-col>
<v-col cols="8">
<v-subheader>Open tickets per owner</v-subheader>
<bar-chart
v-if="open_tickets_per_user"
:chart-data="open_tickets_per_user"
:styles="{
width: '100%',
'max-height': '400px',
position: 'relative'
}"
:chart-options="{
responsive: true,
maintainAspectRatio: false,
legend: undefined,
scales: { xAxes: [ { ticks: { beginAtZero: true, precision: 0 } } ] },
onClick: clickUser,
hover: {
onHover: function(e) {
var point = this.getElementAtEvent(e);
if (point.length) e.target.style.cursor = 'pointer';
else e.target.style.cursor = 'default';
}
}
}"
></bar-chart>
</v-col>
</v-row>
<v-row>
<v-col cols="7">
<v-subheader>Tickets created per week</v-subheader>
<line-chart
v-if="tickets_per_week"
:chart-data="tickets_per_week"
:styles="{ width: '100%', position: 'relative' }"
:chart-options="{
responsive: true,
maintainAspectRatio: false,
legend: undefined,
scales: { yAxes: [ { ticks: { beginAtZero: true, precision: 0 } } ] }
}"
>
</line-chart>
</v-col>
<v-col cols="5">
<v-subheader>Ticket Types</v-subheader>
<pie-chart
v-if="tickets_per_type"
:chart-data="tickets_per_type"
:styles="{ width: '100%', position: 'relative' }"
:chart-options="{
onClick: clickPie,
hover: {
onHover: function(e) {
var point = this.getElementAtEvent(e);
if (point.length) e.target.style.cursor = 'pointer';
else e.target.style.cursor = 'default';
}
}
}"
>
</pie-chart>
</v-col>
</v-row>
</v-col>
<v-col cols="12" lg="5">
<TicketList :type="this.$route.params.type" @click="open"></TicketList>
</v-col>
</v-row>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import LineChart from "../components/charts/Line";
import BarChart from "../components/charts/Bar";
import PieChart from "../components/charts/Doughnut";
import { API } from "@/services/api";
import {Statistics, TicketResponse} from "@/client";
import {DateTime} from "luxon";
import { colors } from "@/plugins/vuetify";
import TicketList from "@/components/TicketList.vue";
import { createHash } from "crypto";
export default Vue.extend({
name: "Dashboard",
components: {
LineChart,
BarChart,
PieChart,
TicketList
},
data() {
return {
statistics: (undefined as unknown) as Statistics
};
},
computed: {
tickets_per_type: function () {
let data = { labels: [] as Array<string>, datasets: [{ backgroundColor: [] as Array<string>, data: [] as Array<number> }] }
this.lodash.forEach(this.statistics.tickets_per_type, (count, type) => {
data.labels.push(type);
data.datasets[0].data.push(count);
data.datasets[0].backgroundColor.push(this.color(type));
})
return data
},
open_tickets_per_user: function () {
let data = { labels: [] as Array<string>, datasets: [{ backgroundColor: [] as Array<string>, data: [] as Array<number> }] }
this.lodash.forEach(this.statistics.open_tickets_per_user, (count, user) => {
if (!user) {
data.labels.push("unassigned");
} else {
data.labels.push(user);
}
data.datasets[0].data.push(count);
data.datasets[0].backgroundColor.push(this.color(user));
})
return data
},
tickets_per_week: function () {
let data = {labels: [] as Array<string>, datasets: [{backgroundColor: [] as Array<string>, data: [] as Array<number> }]}
this.lodash.forEach(this.weeks(), (week) => {
data.labels.push(week);
if (week in this.statistics.tickets_per_week) {
data.datasets[0].data.push(this.statistics.tickets_per_week[week]);
} else {
data.datasets[0].data.push(0);
}
data.datasets[0].backgroundColor.push("#607d8b");
})
return data
}
},
methods: {
open: function (ticket: TicketResponse) {
if (ticket.id === undefined) {
return;
}
this.$router.push({
name: "Ticket",
params: {type: '-', id: ticket.id.toString()}
});
},
clickUser: function (evt, elem) {
let owner = this.open_tickets_per_user.labels[elem[0]._index];
let query = 'status == \'open\' AND owner == \'' + owner + '\'';
if (owner == 'unassigned') {
query = 'status == \'open\' AND !owner';
}
this.$router.push({
name: "TicketList",
params: {query: query}
});
},
clickPie: function (evt, elem) {
this.$router.push({
name: "TicketList",
params: {type: this.tickets_per_type.labels[elem[0]._index]}
});
},
color: function (s: string): string {
let pos = createHash('md5').update(s).digest().readUInt32BE(0) % colors.length;
return colors[pos];
},
fillData() {
API.getStatistics().then(response => {
this.statistics = response.data;
});
},
weeks: function () {
let w = [] as Array<string>;
for (let i = 0; i < 53; i++) {
w.push(DateTime.utc().minus({ weeks: i }).toFormat("kkkk-WW"))
}
this.lodash.reverse(w);
return w
}
},
mounted() {
this.fillData();
}
});
</script>
<style>
canvas {
position: relative !important;
margin: 0 auto;
}
</style>
+217
View File
@@ -0,0 +1,217 @@
<template>
<div class="fill-height">
<v-card
v-if="selected !== undefined"
class="mt-3 ml-3 px-0"
style="position: absolute; width: 33%; left: 60px; top: 60px; z-index: 5">
<v-card-title>
{{ selected.name }}
<v-spacer></v-spacer>
<v-btn
text
:to="{ name: 'Graph', params: { col: col(selected.id), 'id': id(selected.id) } }"
>
<v-icon>mdi-bullseye</v-icon>
</v-btn>
<v-btn
vv-if="selected.id.startsWith('artifacts/')"
text
@click="to(selected.id)"
>
<v-icon>mdi-open-in-new</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="ma-0 pa-0">
<!--TicketSnippet v-if="selected.id.startsWith('tickets/')"></TicketSnippet-->
<!--ArtifactSnippet v-if="selected.id.startsWith('artifacts/')"></ArtifactSnippet-->
<IDSnippet :id="selected.id"></IDSnippet>
</v-card-text>
</v-card>
<v-main class="fill-height overflow-hidden">
<div class="d-flex flex-column fill-height overflow-hidden">
<v-row class="flex-grow-0 pb-4">
<v-col cols="4" class="pl-8">
<v-slider
class="mt-4 mb-4"
v-model="depth"
dense
:label="'Depth ' + depth"
hide-details
max="10"
min="0"
></v-slider>
</v-col>
<v-col cols="4" class="pl-4">
<v-slider
class="mt-4 mb-4"
v-model="force"
dense
label="Node Distance"
hide-details
max="10000"
min="0"
></v-slider>
</v-col>
<v-col cols="2">
<v-switch label="Hide Labels"
v-model="hidelabel" class="mt-6 mb-4" hide-details>
</v-switch>
</v-col>
</v-row>
<v-row class="flex-grow-1 mt-0">
<d3-network
v-if="g !== undefined && g.links !== undefined"
:net-nodes="nodes"
:net-links="g.links"
:options="options"
@node-click="nodeclick"
class="pt-0 mt-n4"
style="width: 100%; height: 100%"
/>
</v-row>
</div>
</v-main>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import D3Network from "vue-d3-network";
import {API} from "../services/api";
import {Graph, Node} from "../client";
// import TicketSnippet from "../components/snippets/TicketSnippet.vue";
// import ArtifactSnippet from "../components/snippets/ArtifactSnippet.vue";
import IDSnippet from "../components/snippets/IDSnippet.vue";
interface State {
g?: Graph;
force: number;
depth: number;
hidelabel: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
selected?: any;
}
export default Vue.extend({
name: "Graph",
components: {
IDSnippet,
D3Network
},
data: (): State => ({
g: undefined,
force: 3000,
depth: 2,
hidelabel: false,
selected: undefined,
}),
computed: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options: function (): any {
return {
canvas: false,
nodeLabels: !this.hidelabel,
nodeSize: 20,
linkWidth: 2,
fontSize: 16,
force: this.force
}
},
nodes: function (): Array<any> {
if (this.g === undefined || this.g.nodes === undefined) {
return []
}
return this.lodash.map(this.g.nodes, (node: Node) => {
if (node.id === this.$route.params.col + "/" + this.$route.params.id) {
return {id: node.id, name: node.name, _size: 40, _cssClass: "center", _labelClass: "center"}
}
if (node.id.startsWith("tickets/")) {
return {id: node.id, name: node.name, _size: 30, _cssClass: "ticket", _labelClass: "event"}
}
return {id: node.id, name: node.name}
})
}
},
watch: {
depth: function () {
this.fetchGraph();
},
$route: function () {
this.fetchGraph();
},
},
methods: {
col: function (id: string): string {
let parts = id.split("/");
return parts[0];
},
id: function (id: string): string {
let parts = id.split("/");
return parts[1];
},
to: function (fid: string) {
let col = this.col(fid);
let id = this.id(fid);
if (col === 'tickets') {
this.$router.push({
name: "Ticket",
params: { id: id, type: "-" }
});
return
}
this.$router.push({
name: "Artifact",
params: { artifact: id }
});
},
fetchGraph: function(): void {
API.graph(this.$route.params.col, this.$route.params.id, this.depth).then((response) => {
this.g = response.data;
});
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
nodeclick(e: any, node: any) {
this.selected = node;
}
},
mounted() {
this.fetchGraph();
},
});
</script>
<style>
.node,
.node.selected {
stroke: #388E3C !important;
}
.node.event {
stroke: #D32F2F !important;
}
.node.center {
stroke: #FFEB3B !important;
fill: #FFEB3B !important;
}
.theme--dark .node-label,
.theme--dark .node-label.event {
fill: #ffffff !important;
}
.node-label,
.node-label.event {
fill: #000000 !important;
}
.link {
stroke: #424242 !important;
}
.link.selected,
.link:hover,.node:hover{
stroke: #FFEB3B !important;
}
</style>
+13
View File
@@ -0,0 +1,13 @@
<template>
<div></div>
</template>
<script>
export default {
name: "Group"
}
</script>
<style scoped>
</style>
+62
View File
@@ -0,0 +1,62 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="groups"
routername="Group"
itemid="id"
itemname="name"
singular="Group"
plural="Groups"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {Group} from "../client";
import {API} from "../services/api";
import List from "../components/List.vue";
interface State {
groups: Array<Group>;
}
export default Vue.extend({
name: "GroupList",
components: {List},
data: (): State => ({
groups: [],
}),
methods: {
loadGroups() {
API.listGroups().then((response) => {
this.groups = response.data;
});
},
deleteGroup(name: string) {
// API.deleteU(name).then(() => {
// this.loadAutomations();
// });
},
},
mounted() {
this.loadGroups();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "groups/")) {
reload = true;
}
});
if (reload) {
this.loadGroups()
}
})
},
});
</script>
+186
View File
@@ -0,0 +1,186 @@
<template>
<div>
<div v-if="$route.params.id == 'new'" class="fill-height d-flex flex-column pa-8">
<v-alert v-if="readonly" type="info">
You do not have write access to jobs.
</v-alert>
<h2>Start new job</h2>
<v-select
label="Automations"
:items="globalautomations"
item-text="id"
return-object
v-model="automation"
></v-select>
<v-form v-if="automation" v-model="valid">
<v-jsf
v-model="data"
:schema="JSON.parse(automation.schema)"
:options="{ readonly: true, formats: { time: timeformat, date: dateformat, 'date-time': datetimeformat } }"
/>
<v-btn @click="run" color="success" outlined :disabled="!valid">
Run
</v-btn>
</v-form>
</div>
<div v-else-if="job !== undefined">
<h2>Job: {{ job.id }}</h2>
<div v-if="job.automation" class="flex-grow-0 flex-shrink-0">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Automation</v-subheader>
{{ job.automation }}
</div>
<div v-if="job.container" class="flex-grow-0 flex-shrink-0">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Container</v-subheader>
{{ job.container }}
</div>
<div v-if="job.status" class="flex-grow-0 flex-shrink-0">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Status</v-subheader>
{{ job.status }}
</div>
<div v-if="job.payload" class="flex-grow-0 flex-shrink-0">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Input Payload</v-subheader>
<Editor :value="JSON.stringify(job.payload, null, 2)" lang="json" :readonly="true"></Editor>
</div>
<div v-if="job.log" class="flex-grow-0 flex-shrink-0">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Log</v-subheader>
<Editor :value="job.log" lang="log" :readonly="true"></Editor>
</div>
<div v-if="job.output" class="flex-grow-0 flex-shrink-0">
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Output</v-subheader>
<Editor :value="JSON.stringify(job.output, null, 2)" lang="json" :readonly="true"></Editor>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import {AutomationResponse, AutomationResponseTypeEnum, JobResponse} from "@/client";
import {API} from "@/services/api";
import {DateTime} from "luxon";
import Editor from "@/components/Editor.vue";
interface State {
job?: JobResponse,
data?: any;
valid: boolean;
automation?: AutomationResponse;
automations: Array<AutomationResponse>;
}
export default Vue.extend({
name: "Job",
components: { Editor },
data: (): State => ({
job: undefined,
data: undefined,
valid: true,
automation: undefined,
automations: [],
}),
watch: {
$route: 'loadJob',
},
computed: {
readonly: function (): boolean {
return !this.hasRole("admin:job:write");
},
globalautomations: function (): Array<AutomationResponse> {
if (!this.automations) {
return [];
}
return this.lodash.filter(this.automations, (automation: AutomationResponse) => {
if (!automation || !automation.type) {
return true;
}
return this.lodash.includes(automation.type, AutomationResponseTypeEnum.Global)
})
},
},
methods: {
timeformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
dateformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
datetimeformat: function(s: string, locale: string) {
let format = this.$store.state.settings.timeformat;
if (!format) {
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
}
return DateTime.fromISO(s).toFormat(format);
},
run: function () {
if (!this.automation) {
return;
}
API.runJob({ automation: this.automation.id, payload: this.data }).then(() => {
this.$store.dispatch("alertSuccess", { name: "Job started." });
})
},
loadJob() {
if (!this.$route.params.id) {
return
}
if (this.$route.params.id == 'new') {
// this.template = { name: "MyTemplate", schema: '{ "type": "object", "name": "Incident" }' }
// this.schema = { type: "object", name: "Incident" }
} else {
API.getJob(this.$route.params.id).then((response) => {
this.job = response.data;
});
}
},
loadAutomations() {
API.listAutomations(this.$route.params.id).then((response) => {
this.automations = response.data;
});
},
hasRole: function (s: string): boolean {
if (this.$store.state.user.roles) {
return this.lodash.includes(this.$store.state.user.roles, s);
}
return false;
}
},
mounted() {
this.loadJob();
this.loadAutomations();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "jobs/")) {
reload = true;
}
});
if (reload) {
this.loadJob()
}
})
},
});
</script>
+61
View File
@@ -0,0 +1,61 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="jobs"
routername="Job"
itemid="id"
itemname="id"
singular="Job"
plural="Jobs"
writepermission="admin:job:write"
:deletable="false"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {JobResponse} from "@/client";
import {API} from "@/services/api";
import List from "../components/List.vue";
interface State {
jobs: Array<JobResponse>;
}
export default Vue.extend({
name: "JobList",
components: {List},
data: (): State => ({
jobs: [],
}),
methods: {
loadJobs() {
API.listJobs().then((response) => {
if (response.data) {
this.jobs = response.data;
}
});
},
},
mounted() {
this.loadJobs();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "jobs/")) {
reload = true;
}
});
if (reload) {
this.loadJobs()
}
})
},
});
</script>
+311
View File
@@ -0,0 +1,311 @@
<template>
<div v-if="playbook !== undefined" class="fill-height d-flex flex-column pa-8">
<v-alert v-if="readonly" type="info">You do not have write access to playbooks.</v-alert>
<h2 v-if="this.$route.params.id === 'new'">New Playbook</h2>
<h2 v-else>Edit Playbook: {{ playbook.name }}</h2>
<v-alert v-if="formaterrors.length" color="warning">
<div v-for="(formaterror, index) in formaterrors" :key="index">
{{ formaterror.instancePath }}{{ formaterror.instancePath ? ": " : "" }}{{ formaterror.message }}
</div>
</v-alert>
<v-alert v-else-if="error" color="warning">
{{ error }}
</v-alert>
<div v-else class="px-4 overflow-scroll">
<vue-pipeline
v-if="pipelineData"
ref="pipeline"
:x="50"
:y="55"
:data="pipelineData"
:showArrow="true"
:ystep="70"
:xstep="100"
lineStyle="default"
/>
</div>
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
Playbook
</v-subheader>
<div class="flex-grow-1 flex-shrink-1 overflow-scroll">
<Editor v-model="playbook.yaml" @input="updatePipeline" lang="yaml" :readonly="readonly"></Editor>
</div>
<v-row v-if="!readonly" class="px-3 my-6 flex-grow-0 flex-shrink-0">
<v-btn v-if="this.$route.params.id === 'new'" color="success" @click="save" outlined>
<v-icon>mdi-plus-thick</v-icon>
Create
</v-btn>
<v-btn v-else color="success" @click="save" outlined>
<v-icon>mdi-content-save</v-icon>
Save
</v-btn>
</v-row>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import {Playbook, PlaybookTemplate, Task, TaskResponse} from "../client";
import { API } from "@/services/api";
import Editor from "../components/Editor.vue";
import {alg, Graph} from "graphlib";
import yaml from 'yaml';
import Ajv from "ajv";
const playbookSchema = {
type: "object",
required: ["name", "tasks"],
properties: {
name: { type: "string" },
tasks: {
type: "object",
additionalProperties: { $ref: "#/definitions/Task" }
}
},
// additionalProperties: false,
$id: "#/definitions/Playbook"
};
const taskSchema = {
type: "object",
required: ["name", "type"],
properties: {
automation: { type: "string" },
join: { type: "boolean" },
msg: { type: "object", additionalProperties: { type: "string" } },
name: { type: "string" },
next: {
type: "object",
additionalProperties: { type: ["string", "null"] }
},
schema: { type: "object" },
type: { type: "string", enum: ["task", "input", "automation"] }
},
// additionalProperties: false,
$id: "#/definitions/Task"
};
interface State {
playbook?: PlaybookTemplate;
g: Record<string, any>;
selected: any;
pipelineData: any;
error: string;
}
interface TaskWithID {
id: string;
task: Task;
}
const inityaml = "name: VirusTotal hash check\n" +
"tasks:\n" +
" input:\n" +
" name: Please enter a word\n" +
" type: input\n" +
" schema:\n" +
" title: Word\n" +
" type: object\n" +
" properties:\n" +
" word:\n" +
" type: string\n" +
" title: Enter a Word\n" +
" default: \"\"\n" +
" next:\n" +
" hash: \"word != ''\"\n" +
"\n" +
" hash:\n" +
" name: Hash the word\n" +
" type: automation\n" +
" automation: hash.sha1\n" +
" msg:\n" +
" payload: \"playbook.tasks['input'].data['word']\"\n" +
" next:\n" +
" end:\n" +
"\n" +
" end:\n" +
" name: Finish the incident\n" +
" type: task\n"
export default Vue.extend({
name: "Playbook",
components: { Editor },
data: (): State => ({
playbook: undefined,
g: {},
selected: undefined,
pipelineData: undefined,
error: "",
}),
watch: {
'$route': function () {
this.loadPlaybook();
}
},
computed: {
formaterrors: function (): Array<any> {
if (!this.playbook) {
return [];
}
try {
let playbook = yaml.parse(this.playbook.yaml);
const ajv = new Ajv({validateFormats: false});
ajv.addSchema(taskSchema, "#/definitions/Task")
const validate = ajv.compile(playbookSchema);
const valid = validate(playbook)
if (!valid && validate.errors) {
return validate.errors;
}
return [];
}
catch (e) {
return [e];
}
},
readonly: function (): boolean {
return !this.hasRole("engineer:playbook:write");
},
},
methods: {
gstatus: function(task: TaskResponse) {
if (task.active) {
return "open"
}
return "inactive"
},
tasks: function(g: any, playbook: Playbook): Array<TaskWithID> {
let taskKeys = alg.topsort(g);
let tasks = [] as Array<TaskWithID>;
for (const tasksKey in taskKeys) {
let taskWithID = {} as TaskWithID;
if (playbook.tasks[taskKeys[tasksKey]] === undefined) {
continue; // TODO
}
taskWithID.task = playbook.tasks[taskKeys[tasksKey]];
taskWithID.id = taskKeys[tasksKey];
tasks.push(taskWithID);
}
return tasks;
},
updatePipeline: function () {
if (this.playbook) {
this.pipeline(this.playbook.yaml);
}
},
pipeline: function(playbookYAML: string) {
try {
let playbook = yaml.parse(playbookYAML);
this.error = "";
let g = new Graph();
for (const stepKey in playbook.tasks) {
g.setNode(stepKey);
}
this.lodash.forEach(playbook.tasks, (task: Task, stepKey: string) => {
if ("next" in task) {
this.lodash.forEach(task.next, (condition, nextKey) => {
g.setEdge(stepKey, nextKey);
});
}
});
let tasks = this.tasks(g, playbook);
let elements = [] as Array<any>;
this.lodash.forEach(tasks, task => {
elements.push({
id: task.id,
name: task.task.name,
next: [],
status: "unknown"
});
});
this.lodash.forEach(tasks, (task: TaskWithID) => {
if ("next" in task.task) {
this.lodash.forEach(task.task.next, (condition, nextKey) => {
let nextID = this.lodash.findIndex(elements, ["id", nextKey]);
let stepID = this.lodash.findIndex(elements, ["id", task.id]);
if (nextID !== -1) {
// TODO: invalid schema
elements[stepID].next.push({index: nextID});
}
});
}
});
this.pipelineData = undefined;
this.$nextTick(() => {
this.pipelineData = this.lodash.values(elements);
})
}
catch (e: unknown) {
console.log(e);
this.error = this.lodash.toString(e);
}
},
save() {
if (this.playbook === undefined) {
return;
}
if (this.$route.params.id == 'new') {
let playbook = this.playbook;
// playbook.id = kebabCase(playbook.name);
API.createPlaybook(playbook).then(() => {
this.$store.dispatch("alertSuccess", { name: "Playbook created" });
});
} else {
API.updatePlaybook(this.$route.params.id, this.playbook).then(() => {
this.$store.dispatch("alertSuccess", { name: "Playbook saved" });
});
}
},
loadPlaybook() {
if (!this.$route.params.id) {
return
}
if (this.$route.params.id == 'new') {
this.playbook = { name: "MyPlaybook", yaml: inityaml }
} else {
API.getPlaybook(this.$route.params.id).then((response) => {
this.playbook = response.data;
});
}
},
hasRole: function (s: string): boolean {
if (this.$store.state.user.roles) {
return this.lodash.includes(this.$store.state.user.roles, s);
}
return false;
}
},
mounted() {
this.loadPlaybook();
},
});
</script>
<style>
.my-code {
background: #2d2d2d;
color: #ccc;
width: inherit;
height: inherit;
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
font-size: 14px;
line-height: 1.5;
padding: 15px;
}
.pipeline-node-label {
fill: #333 !important;
}
</style>
+66
View File
@@ -0,0 +1,66 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="playbooks"
routername="Playbook"
itemid="id"
itemname="name"
singular="Playbook"
plural="Playbooks"
@delete="deletePlaybook"
writepermission="engineer:playbook:write"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {PlaybookTemplate} from "../client";
import {API} from "../services/api";
import List from "../components/List.vue";
interface State {
playbooks: Array<PlaybookTemplate>;
}
export default Vue.extend({
name: "PlaybookList",
components: {List},
data: (): State => ({
playbooks: [],
}),
methods: {
loadPlaybooks() {
API.listPlaybooks().then((response) => {
if (response.data) {
this.playbooks = response.data;
}
});
},
deletePlaybook(name: string) {
API.deletePlaybook(name).then(() => {
this.loadPlaybooks();
});
},
},
mounted() {
this.loadPlaybooks();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "playbooks/")) {
reload = true;
}
});
if (reload) {
this.loadPlaybooks()
}
})
},
});
</script>
+47
View File
@@ -0,0 +1,47 @@
<template>
<v-main v-if="userdata">
<user-data-editor :userdata="userdata" @save="saveUserData"></user-data-editor>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import { UserData } from "@/client";
import { API } from "@/services/api";
import UserDataEditor from "@/components/UserDataEditor.vue";
interface State {
userdata?: UserData;
}
export default Vue.extend({
name: "Profile",
data: (): State => ({
userdata: undefined,
}),
components: {
UserDataEditor,
},
watch: {
$route: function () {
this.loadUserData();
},
},
methods: {
saveUserData: function(userdata: UserData) {
API.updateCurrentUserData(userdata).then(() => {
this.$store.dispatch("alertSuccess", { name: "User data saved" });
});
},
loadUserData: function () {
API.currentUserData().then((response) => {
this.userdata = response.data;
});
}
},
mounted() {
this.loadUserData();
}
});
</script>
+89
View File
@@ -0,0 +1,89 @@
<template>
<div v-if="rule !== undefined" class="flex-grow-1 flex-column d-flex fill-height pa-8">
<h2 v-if="this.$route.params.id === 'new'">New Rule: {{ rule.name }}</h2>
<h2 v-else>Edit Rule: {{ rule.name }}</h2>
<v-text-field label="Name" v-model="rule.name" class="flex-grow-0 flex-shrink-0"></v-text-field>
<v-text-field label="Condition" v-model="rule.condition" class="flex-grow-0 flex-shrink-0"></v-text-field>
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
Update
</v-subheader>
<div class="flex-grow-1 flex-shrink-1 overflow-scroll">
<Editor v-model="update" lang="json"></Editor>
</div>
<v-row class="px-3 my-6 flex-grow-0 flex-shrink-0">
<v-btn v-if="this.$route.params.id === 'new'" color="success" @click="save" outlined>
<v-icon>mdi-plus-thick</v-icon>
Create
</v-btn>
<v-btn v-else color="success" outlined @click="save">
<v-icon>mdi-content-save</v-icon>
Save
</v-btn>
</v-row>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { Rule } from "@/client";
import { API } from "@/services/api";
import Editor from "../components/Editor.vue";
interface State {
rule?: Rule;
update: string;
}
export default Vue.extend({
name: "Rule",
components: { Editor },
data: (): State => ({
rule: undefined,
update: "",
}),
watch: {
$route: function () {
this.loadRule();
},
},
methods: {
save() {
if (this.rule === undefined) {
return;
}
let rule = this.rule;
// rule.id = kebabCase(rule.name);
rule.update = JSON.parse(this.update);
if (this.$route.params.id == 'new') {
API.createRule(rule).then(() => {
this.$store.dispatch("alertSuccess", { name: "Rule created" });
});
} else {
API.updateRule(this.$route.params.id, rule).then(() => {
this.$store.dispatch("alertSuccess", { name: "Rule saved" });
});
}
},
loadRule() {
if (!this.$route.params.id) {
return
}
if (this.$route.params.id == 'new') {
this.rule = { name: "MyPlaybook", condition: "type == alert", update: { details: { status: "ignored" } } }
} else {
API.getRule(this.$route.params.id).then((response) => {
this.rule = response.data;
this.update = JSON.stringify(response.data.update, null, 4)
});
}
},
},
mounted() {
this.loadRule();
},
});
</script>
+63
View File
@@ -0,0 +1,63 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="rules"
routername="Rule"
itemid="id"
itemname="name"
singular="Rule"
plural="Rules"
@delete="deleteRule"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {Rule} from "@/client";
import {API} from "@/services/api";
import List from "../components/List.vue";
interface State {
rules: Array<Rule>;
}
export default Vue.extend({
name: "RuleList",
components: {List},
data: (): State => ({
rules: [],
}),
methods: {
loadRules() {
API.listRules().then((response) => {
this.rules = response.data;
});
},
deleteRule(name: string) {
API.deleteRule(name).then(() => {
this.loadRules();
});
},
},
mounted() {
this.loadRules();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "rules/")) {
reload = true;
}
});
if (reload) {
this.loadRules()
}
})
},
});
</script>
+85
View File
@@ -0,0 +1,85 @@
<template>
<v-main>
<v-container>
<v-data-table
:headers="headers"
:items="tasks ? tasks : []"
item-key="name"
multi-sort
class="elevation-1 cards clickable"
:loading="loading"
:footer-props="{ 'items-per-page-options': [10, 25, 50, 100] }"
@click:row="open"
>
</v-data-table>
</v-container>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {TaskResponse, TaskWithContext} from "@/client";
import {API} from "@/services/api";
interface State {
tasks: Array<TaskResponse>;
loading: boolean;
}
export default Vue.extend({
name: "TaskList",
data: (): State => ({
tasks: [],
loading: true,
}),
watch: {
$route: function () {
this.loadTasks();
},
},
computed: {
headers() {
return [
{
text: "Ticket",
align: "start",
value: "ticket_name"
},
{
text: "Playbook",
align: "start",
value: "playbook_name"
},
{
text: "Task",
align: "start",
value: "task.name"
},
{
text: "Owner",
align: "start",
value: "task.owner"
}
];
}
},
methods: {
open(task: TaskWithContext) {
this.$router.push({
name: "Ticket",
params: { id: task.ticket_id.toString(), type: "-" }
});
},
loadTasks() {
this.loading = true;
API.listTasks().then((reponse) => {
this.tasks = reponse.data;
this.loading = false;
})
}
},
mounted() {
this.loadTasks();
}
});
</script>
+87
View File
@@ -0,0 +1,87 @@
<template>
<div v-if="template !== undefined" class="flex-grow-1 flex-column d-flex fill-height pa-8">
<v-alert v-if="readonly" type="info">
You do not have write access to templates.
Changes here cannot be saved.
</v-alert>
<div class="d-flex" style="align-items: center">
<h2 v-if="readonly">Template: {{ template.name }}</h2>
<h2 v-else-if="this.$route.params.id === 'new'">New Template: {{ template.name }}</h2>
<h2 v-else>Edit Template: {{ template.name }}</h2>
</div>
<v-text-field label="Name" v-model="template.name" class="flex-grow-0 flex-shrink-0" :readonly="readonly"></v-text-field>
<AdvancedJSONSchemaEditor v-if="schema" @save="save" :schema="schema" :readonly="readonly"></AdvancedJSONSchemaEditor>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { TicketTemplate } from "@/client";
import AdvancedJSONSchemaEditor from "../components/AdvancedJSONSchemaEditor.vue";
interface State {
template?: TicketTemplate,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
schema?: any;
}
export default Vue.extend({
name: "Template",
components: { AdvancedJSONSchemaEditor },
data: (): State => ({
template: undefined,
schema: undefined,
}),
watch: {
$route: 'loadTemplate',
},
computed: {
readonly: function (): boolean {
return !this.hasRole("engineer:template:write");
},
},
methods: {
save(schema) {
if (this.template === undefined) {
return;
}
let template = this.template;
template.schema = schema;
if (this.$route.params.id == 'new') {
this.$store.dispatch("addTemplate", template).then(() => {
this.$router.push({name: "TemplateList" });
});
} else {
this.$store.dispatch("updateTemplate", { id: this.$route.params.id, template: template });
}
},
loadTemplate() {
if (!this.$route.params.id) {
return
}
if (this.$route.params.id == 'new') {
this.template = { name: "MyTemplate", schema: '{ "type": "object", "name": "Incident" }' }
this.schema = { type: "object", name: "Incident" }
} else {
this.$store.dispatch("getTemplate", this.$route.params.id).then((response: TicketTemplate) => {
this.template = response;
this.schema = JSON.parse(response.schema);
});
}
},
hasRole: function (s: string): boolean {
if (this.$store.state.user.roles) {
return this.lodash.includes(this.$store.state.user.roles, s);
}
return false;
}
},
mounted() {
this.loadTemplate();
},
});
</script>
+50
View File
@@ -0,0 +1,50 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="$store.state.templates.templates"
routername="Template"
itemid="id"
itemname="name"
singular="Template"
plural="Templates"
writepermission="engineer:template:write"
@delete="deleteTemplate"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import List from "../components/List.vue";
export default Vue.extend({
name: "TemplateList",
components: {List},
methods: {
deleteTemplate(title: string) {
this.$store.dispatch("deleteTemplate", title).then(() => {
this.$router.push({name: "TemplateList"});
});
}
},
mounted() {
this.$store.dispatch("listTemplates");
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "templates/")) {
reload = true;
}
});
if (reload) {
this.$store.dispatch("listTemplates");
}
})
}
});
</script>
File diff suppressed because it is too large. Load diff
+30
View File
@@ -0,0 +1,30 @@
<template>
<v-main>
<TicketListComponent :type="this.$route.params.type" :query="query" @click="open"></TicketListComponent>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {TicketResponse} from "@/client";
import TicketListComponent from "../components/TicketList.vue";
export default Vue.extend({
name: "TicketList",
components: {TicketListComponent},
props: ['query'],
methods: {
open: function (ticket: TicketResponse) {
if (ticket.id === undefined) {
return;
}
this.$router.push({
name: "Ticket",
params: {type: this.$route.params.type, id: ticket.id.toString()}
});
}
}
});
</script>
+170
View File
@@ -0,0 +1,170 @@
<template>
<v-main>
<v-container>
<v-card color="cards">
<v-card-title>New {{ $route.params.type | capitalize }}</v-card-title>
<v-card-text>
<v-form class="create clearfix">
<v-text-field label="Title" v-model="name"></v-text-field>
<v-select
label="Playbooks"
:items="playbooks"
item-text="name"
return-object
multiple
v-model="selectedPlaybooks"
></v-select>
<v-select
label="Template"
:items="templates"
item-text="name"
return-object
v-model="selectedTemplate"
></v-select>
<v-subheader class="pl-0 mt-4" style="height: 20px">Details</v-subheader>
<div v-if="selectedTemplate !== undefined" class="details">
<v-lazy>
<v-jsf
v-model="details"
:options="{ fieldProps: { 'hide-details': true } }"
:schema="selectedSchema"
/>
</v-lazy>
</div>
<v-btn color="green" @click="createTicket" outlined>
Create
</v-btn>
</v-form>
</v-card-text>
</v-card>
</v-container>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {
PlaybookTemplateForm,
PlaybookTemplateResponse,
TicketForm,
TicketTemplateResponse,
TicketType
} from "../client";
import { API } from "@/services/api";
interface State {
selectedTemplate?: TicketTemplateResponse;
templates: Array<TicketTemplateResponse>;
selectedPlaybooks: Array<PlaybookTemplateResponse>;
playbooks: Array<PlaybookTemplateResponse>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
details: any;
name: string;
ticketType?: TicketType;
}
export default Vue.extend({
name: "TicketNew",
// components: { VJsf },
data: (): State => ({
selectedTemplate: undefined,
templates: [],
selectedPlaybooks: [],
playbooks: [],
name: "",
details: {},
ticketType: undefined,
}),
computed: {
selectedSchema() {
if (
this.selectedTemplate === undefined ||
this.selectedTemplate.schema === undefined
) {
return {};
}
return JSON.parse(this.selectedTemplate.schema);
}
},
methods: {
createTicket: function() {
if (
this.selectedTemplate === undefined ||
this.selectedTemplate?.schema === undefined
) {
this.$store.dispatch("alertError", { name: "No template selected" });
return;
}
let ticket: TicketForm = {
type: this.$route.params.type,
name: this.name,
details: this.details,
schema: this.selectedTemplate?.schema,
status: "open",
owner: this.$store.state.user.id,
playbooks: this.selectedPlaybooks as Array<PlaybookTemplateForm>,
};
API.createTicket(ticket).then(response => {
if (response.data.id === undefined) {
return;
}
this.$router.push({
name: "Ticket",
params: {
id: response.data.id.toString(),
type: response.data.type,
}
});
});
}
},
mounted() {
API.getTicketType(this.$route.params.type).then((response) => {
this.ticketType = response.data;
API.listTemplates().then(response => {
this.templates = response.data;
this.lodash.forEach(this.templates, (template) => {
if (this.ticketType && template.id == this.ticketType.default_template) {
this.selectedTemplate = template;
}
});
});
API.listPlaybooks().then(response => {
this.playbooks = response.data;
this.lodash.forEach(this.playbooks, (playbook) => {
if (this.ticketType && this.lodash.includes(this.ticketType.default_playbooks, playbook.id)) {
this.selectedPlaybooks.push(playbook);
}
});
});
});
},
});
</script>
<style>
.details > .col > .row > .row,
.details > .col > .row > div > .row {
margin-top: 16px !important;
padding: 16px !important;
background-color: rgba(0, 0, 0, 0.2);
}
.v-application .create .vjsf-property {
margin-bottom: 16px;
}
.v-application .create .error--text {
color: white !important;
}
</style>
+126
View File
@@ -0,0 +1,126 @@
<template>
<div v-if="tickettype !== undefined" class="flex-grow-1 flex-column d-flex fill-height pa-8">
<h2 v-if="this.$route.params.id === 'new'">New Ticket Type: {{ tickettype.name }}</h2>
<h2 v-else>Edit Ticket Type: {{ tickettype.name }}</h2>
<v-text-field label="Name" v-model="tickettype.name" class="flex-grow-0 flex-shrink-0"></v-text-field>
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
Icon (see <a href="https://materialdesignicons.com" class="mx-1"> materialdesignicons.com </a> and prefix with "mdi-")
</v-subheader>
<v-text-field v-model="tickettype.icon" placeholder="e.g. mdi-alert" class="flex-grow-0 flex-shrink-0 mt-n3"></v-text-field>
<v-select
v-model="selectedTemplate"
:items="templates"
item-text="name"
label="Default Template"
return-object
class="flex-grow-0 flex-shrink-0"
></v-select>
<v-select
v-model="selectedPlaybooks"
:items="playbooks"
item-text="name"
label="Default Playbooks"
return-object
multiple
class="flex-grow-0 flex-shrink-0"
></v-select>
<v-row class="px-3 my-6 flex-grow-0 flex-shrink-0">
<v-btn v-if="this.$route.params.id === 'new'" color="success" @click="save" outlined>
<v-icon>mdi-plus-thick</v-icon>
Create
</v-btn>
<v-btn v-else color="success" outlined @click="save">
<v-icon>mdi-content-save</v-icon>
Save
</v-btn>
</v-row>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { PlaybookTemplateResponse, TicketTemplateResponse, TicketType } from "@/client";
import { API } from "@/services/api";
interface State {
tickettype?: TicketType;
selectedPlaybooks: Array<PlaybookTemplateResponse>;
playbooks?: Array<PlaybookTemplateResponse>;
selectedTemplate?: TicketTemplateResponse;
templates?: Array<TicketTemplateResponse>;
}
export default Vue.extend({
name: "TicketType",
data: (): State => ({
tickettype: undefined,
selectedPlaybooks: [],
playbooks: undefined,
selectedTemplate: undefined,
templates: undefined,
}),
watch: {
$route: function () {
this.loadRule();
},
},
methods: {
save() {
if (this.tickettype === undefined) {
return;
}
let tickettype = this.tickettype;
if (this.selectedTemplate) {
tickettype.default_template = this.selectedTemplate.id;
}
tickettype.default_playbooks = [];
this.lodash.forEach(this.selectedPlaybooks, (playbook) => {
tickettype.default_playbooks.push(playbook.id)
})
if (this.$route.params.id == 'new') {
API.createTicketType(tickettype).then(() => {
this.$store.dispatch("alertSuccess", { name: "Ticket type created" });
});
} else {
API.updateTicketType(this.$route.params.id, tickettype).then(() => {
this.$store.dispatch("alertSuccess", { name: "Ticket type saved" });
});
}
},
loadRule() {
if (!this.$route.params.id) {
return
}
API.listTemplates().then((response) => {
this.templates = response.data;
if (response.data.length > 0) {
this.selectedTemplate = response.data[0];
}
})
API.listPlaybooks().then((response) => {
this.playbooks = response.data;
})
if (this.$route.params.id == 'new') {
this.tickettype = { name: "TI Ticket", default_groups: [], default_playbooks: [], default_template: "", icon: "" }
} else {
API.getTicketType(this.$route.params.id).then((response) => {
this.tickettype = response.data;
});
}
},
},
mounted() {
this.loadRule();
},
});
</script>
+64
View File
@@ -0,0 +1,64 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="tickettypes"
routername="TicketType"
itemid="id"
itemname="name"
singular="Ticket Type"
plural="Ticket Types"
@delete="deleteTicketType"
writepermission="engineer:tickettype:write"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import { TicketType} from "@/client";
import {API} from "@/services/api";
import List from "../components/List.vue";
interface State {
tickettypes: Array<TicketType>;
}
export default Vue.extend({
name: "TicketTypeList",
components: {List},
data: (): State => ({
tickettypes: [],
}),
methods: {
loadTicketType() {
API.listTicketTypes().then((response) => {
this.tickettypes = response.data;
});
},
deleteTicketType(id: string) {
API.deleteTicketType(id).then(() => {
this.loadTicketType();
});
},
},
mounted() {
this.loadTicketType();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "tickettypes/")) {
reload = true;
}
});
if (reload) {
this.loadTicketType()
}
})
},
});
</script>
+105
View File
@@ -0,0 +1,105 @@
<template>
<div>
<div v-if="user === undefined" class="text-sm-center py-16">
<v-progress-circular
indeterminate
color="primary"
:size="70"
:width="7"
class="align-center"
>
</v-progress-circular>
</div>
<div v-else class="fill-height d-flex flex-column pa-8">
<div v-if="$route.params.id === 'new'">
<h2>Create new API key</h2>
<v-form>
<v-text-field label="ID" v-model="user.id" hide-details></v-text-field>
<v-select multiple chips label="Roles" v-model="user.roles" :items="$store.state.settings.roles"></v-select>
<v-btn @click="save" color="success" outlined>
<v-icon>mdi-plus-thick</v-icon>
Create API-Key
</v-btn>
</v-form>
<v-alert v-if="newUserResponse" color="warning" class="mt-4" dismissible>
<b>New API-Secret:</b> {{ newUserResponse.secret }}<br>
Make sure you save it - you won't be able to access it again.
</v-alert>
</div>
<div v-else>
<h2>
{{ user.id }}
<span v-if="user.apikey">(API Key)</span>
</h2>
<v-select multiple chips v-if="!user.apikey" label="Roles" v-model="user.roles" :items="$store.state.settings.roles"></v-select>
<div v-else>
<v-chip v-for="role in user.roles" :key="role">{{ role }}</v-chip>
</div>
<v-btn v-if="!user.apikey" @click="save" color="success" outlined>
<v-icon>mdi-content-save</v-icon>
Save
</v-btn>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { NewUserResponse, UserResponse } from "../client";
import {API} from "@/services/api";
interface State {
user?: UserResponse;
newUserResponse?: NewUserResponse;
}
export default Vue.extend({
name: "User",
components: {},
data: (): State => ({
user: undefined,
newUserResponse: undefined
}),
watch: {
'$route': function () {
this.loadUser();
}
},
methods: {
save() {
if (!this.user) {
return
}
if (this.$route.params.id == 'new') {
API.createUser(this.user).then(response => {
this.newUserResponse = response.data;
})
} else {
API.updateUser(this.$route.params.id, this.user).then(response => {
this.user = response.data;
})
}
},
loadUser() {
if (!this.$route.params.id) {
return
}
if (this.$route.params.id == 'new') {
this.user = {id: "", roles: [], blocked: false, apikey: true}
} else {
API.getUser(this.$route.params.id).then((response) => {
this.user = response.data;
});
}
},
},
mounted() {
this.loadUser();
},
});
</script>
+44
View File
@@ -0,0 +1,44 @@
<template>
<div v-if="userdata">
<user-data-editor :userdata="userdata" @save="saveUserData"></user-data-editor>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { UserData } from "@/client";
import { API } from "@/services/api";
import UserDataEditor from "@/components/UserDataEditor.vue";
interface State {
userdata?: UserData;
}
export default Vue.extend({
name: "UserData",
data: (): State => ({
userdata: undefined,
}),
components: { UserDataEditor },
watch: {
$route: function () {
this.loadUserData();
},
},
methods: {
saveUserData: function(userdata: UserData) {
API.updateUserData(this.$route.params.id, userdata).then(() => {
this.$store.dispatch("alertSuccess", { name: "User data saved" });
});
},
loadUserData: function () {
API.getUserData(this.$route.params.id).then((response) => {
this.userdata = response.data;
});
}
},
mounted() {
this.loadUserData();
}
});
</script>
+60
View File
@@ -0,0 +1,60 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="userdatas"
routername="UserData"
itemid="id"
itemname="name"
singular="User Data"
plural="User Data"
:show-new="false"
:deletable="false"
writepermission="admin:userdata:write"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {UserData} from "@/client";
import {API} from "@/services/api";
import List from "../components/List.vue";
interface State {
userdatas: Array<UserData>;
}
export default Vue.extend({
name: "UserDataList",
components: {List},
data: (): State => ({
userdatas: [],
}),
methods: {
loadSettings() {
API.listUserData().then((response) => {
this.userdatas = response.data;
});
},
},
mounted() {
this.loadSettings();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "settings/")) {
reload = true;
}
});
if (reload) {
this.loadSettings()
}
})
},
});
</script>
+66
View File
@@ -0,0 +1,66 @@
<template>
<v-main style="min-height: 100vh;">
<List
:items="users"
routername="User"
itemid="id"
itemname="id"
singular="User / API Key"
plural="Users / API Keys"
@delete="deleteUser"
writepermission="admin:user:write"
></List>
</v-main>
</template>
<script lang="ts">
import Vue from "vue";
import {UserResponse} from "@/client";
import {API} from "@/services/api";
import List from "../components/List.vue";
interface State {
users: Array<UserResponse>;
}
export default Vue.extend({
name: "UserList",
components: {List},
data: (): State => ({
users: [],
}),
methods: {
loadUsers() {
API.listUsers().then((response) => {
if (response.data) {
this.users = response.data;
}
});
},
deleteUser(name: string) {
API.deleteUser(name).then(() => {
this.loadUsers();
});
},
},
mounted() {
this.loadUsers();
this.$store.subscribeAction((action, state) => {
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
return
}
let reload = false;
Vue.lodash.forEach(action.payload["ids"], (id) => {
if (this.lodash.startsWith(id, "users/")) {
reload = true;
}
});
if (reload) {
this.loadUsers()
}
})
},
});
</script>
+21
View File
@@ -0,0 +1,21 @@
<template>
<object data="http://localhost:8003">
<embed src="http://localhost:8003" />
Error: Embedded data could not be displayed.
</object>
</template>
<script>
export default {
name: "Arango",
};
</script>
<style scoped>
object,
embed {
padding-left: 56px;
height: 100%;
width: 100%;
}
</style>
+21
View File
@@ -0,0 +1,21 @@
<template>
<object data="http://localhost:9001/keygen">
<embed src="http://localhost:9001/keygen" />
Error: Embedded data could not be displayed.
</object>
</template>
<script>
export default {
name: "Emitter",
};
</script>
<style scoped>
object,
embed {
padding-left: 56px;
height: 100%;
width: 100%;
}
</style>
+21
View File
@@ -0,0 +1,21 @@
<template>
<object data="http://localhost:9000/minio">
<embed src="http://localhost:9000/minio" />
Error: Embedded data could not be displayed.
</object>
</template>
<script>
export default {
name: "Minio",
};
</script>
<style scoped>
object,
embed {
padding-left: 56px;
height: 100%;
width: 100%;
}
</style>
+21
View File
@@ -0,0 +1,21 @@
<template>
<object data="http://localhost:1880">
<embed src="http://localhost:1880" />
Error: Embedded data could not be displayed.
</object>
</template>
<script>
export default {
name: "Nodered",
};
</script>
<style scoped>
object,
embed {
padding-left: 56px;
height: 100%;
width: 100%;
}
</style>