From a1f8f2922beb3c7da15bb363c13a52cc6b26e31d Mon Sep 17 00:00:00 2001 From: Darshan Lukhi Date: Fri, 7 Jun 2024 12:39:13 +0530 Subject: [PATCH 1/3] Add project documentation and README --- README.md | 175 +- docker-compose.yaml | 2 +- docs/architecture.md | 81 + docs/code-of-conduct.md | 60 + docs/contributing.md | 39 + docs/development.md | 120 + docs/index.md | 11 + docs/limitations.md | 10 + docs/logo.png | Bin 0 -> 52594 bytes docs/security.md | 33 + docs/support.md | 11 + resources/configuration.json | 173 + resources/data/load_sample_data.py | 26 + resources/metadata.json | 4811 ++++++++++++---------------- 14 files changed, 2679 insertions(+), 2873 deletions(-) create mode 100644 docs/architecture.md create mode 100644 docs/code-of-conduct.md create mode 100644 docs/contributing.md create mode 100644 docs/development.md create mode 100644 docs/index.md create mode 100644 docs/limitations.md create mode 100644 docs/logo.png create mode 100644 docs/security.md create mode 100644 docs/support.md create mode 100644 resources/configuration.json create mode 100644 resources/data/load_sample_data.py diff --git a/README.md b/README.md index 6bf3f48..da10916 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,127 @@ -# Hasura Elasticsearch Connector - -## Get started -This guide will help you perform the setup of this connector in local - -### Clone Repository -Clone connector from [ndc-elasticsearch](https://github.com/hasura/ndc-elasticsearch/) github repository -``` -git clone https://github.com/hasura/ndc-elasticsearch.git -``` - -### Set Environment Variables -Set the following environment variables for connector -``` -ELASTICSEARCH_URL=${YOUR_ELASTICSEARCH_URL} -ELASTICSEARCH_USERNAME=${YOUR_ELASTICSEARCH_USERNAME} -ELASTICSEARCH_PASSWORD=${YOUR_ELASTICSEARCH_PASSWORD} -ELASTICSEARCH_API_KEY=${YOUR_ELASTICSEARCH_API_KEY} -ELASTICSEARCH_CA_CERT_PATH=${YOUR_ELASTICSEARCH_CA_CERT_PATH} -ELASTICSEARCH_INDEX_PATTERN=${REGEX_PATTERN_OF_INDICES} -``` -Note: One can set either username and password or api key in env variables for authentication. - -### Build connector executable file -```go -go build -``` - -### Update configuration -Run the update cli command to update the `configuration.json` file - -``` -ndc-elasticsearch update -``` - -### Run the connector locally -Run the following command to start your connector - -``` -ndc-elasticsearch serve -``` -Connector server will be up and running at http://localhost:8080 - -### Verify -``` -curl http://localhost:8080/schema -``` -Send request to `query` endpoint for queries + + +# Elasticsearch Connector + + + +[![Docs](https://img.shields.io/badge/docs-v3.x-brightgreen.svg?style=flat)](https://hasura.io/docs/3.0/latest/connectors/elasticsearch/) +[![ndc-hub](https://img.shields.io/badge/ndc--hub-elasticsearch-blue.svg?style=flat)](https://hasura.io/connectors/ndc-elasticsearch) +[![License](https://img.shields.io/badge/license-Apache--2.0-purple.svg?style=flat)](LICENSE.txt) +[![Status](https://img.shields.io/badge/status-alpha-yellow.svg?style=flat)](./readme.md) + +The Hasura Elasticsearch Connector allows for connecting to a Elasticsearch search engine, giving you an instant +GraphQL API on top of your Elasticsearch data. + +This connector is built using the [Go Data Connector SDK](https://github.com/hasura/ndc-sdk-go) and implements the [Data Connector Spec](https://github.com/hasura/ndc-spec). + +- [Connector information in the Hasura Hub](https://hasura.io/connectors/elasticsearch) +- [Hasura V3 Documentation](https://hasura.io/docs/3.0) + +## Features + +Below, you'll find a matrix of all supported features for the Elasticsearch connector: + + + +| Feature | Supported | Notes | +| ------------------------------- | --------- | ----- | +| Native Queries + Logical Models | ❌ | | +| Simple Object Query | ✅ | | +| Filter / Search | ✅ | | +| Simple Aggregation | ✅ | | +| Sort | ✅ | | +| Paginate | ✅ | | +| Nested Objects | ✅ | | +| Nested Arrays | ✅ | | +| Nested Filtering | ✅ | | +| Nested Sorting | ✅ | | +| Nested Relationships | ❌ | | + + +## Before you get Started + +1. Create a [Hasura Cloud account](https://console.hasura.io) +2. Install the [CLI](https://hasura.io/docs/3.0/cli/installation/) +3. [Create a project](https://hasura.io/docs/3.0/getting-started/create-a-project) + +## Using the connector + +To use the Elasticsearch connector, follow these steps in a Hasura project: + +1. Add the connector: + + ```bash + ddn add connector-manifest es_connector --subgraph app --hub-connector hasura/elasticsearch --type cloud + ``` + + In the snippet above, we've used the subgraph `app` as it's available by default; however, you can change this + value to match any [subgraph](https://hasura.io/docs/3.0/project-configuration/subgraphs) which you've created in your project. + +2. Add your Elasticsearch credentials: + + Open your project in your text editor and open the `base.env.yaml` file in the root of your project. Then, add + `ES_CONNECTOR_URL`, `ES_CONNECTOR_USERNAME` and `ES_CONNECTOR_PASSWORD` environment variables under the `app` subgraph: + + ```yaml + supergraph: {} + subgraphs: + app: + ES_CONNECTOR_URL: "" + ES_CONNECTOR_USERNAME: "" + ES_CONNECTOR_PASSWORD: "" + ``` + + Next, update your `/app/es_connector/connector/es_connector.build.hml` file to reference this new environment + variable: + + ```yaml + # other configuration above + ELASTICSEARCH_URL: + valueFromEnv: ES_CONNECTOR_URL + ELASTICSEARCH_USERNAME: + valueFromEnv: ES_CONNECTOR_USERNAME + ELASTICSEARCH_PASSWORD: + valueFromEnv: ES_CONNECTOR_PASSWORD + ``` + + Notice, when we use an environment variable, we must change the key to `valueFromEnv` instead of `value`. This tells + Hasura DDN to look for the value in the environment variable we've defined instead of using the value directly. + +3. Update the connector manifest and the connector link + + These two steps will (1) allow Hasura to introspect your data source and complete the configuration and (2) deploy the + connector to Hasura DDN: + + ```bash + ddn update connector-manifest es_connector + ``` + + ```bash + ddn update connector-link es_connector + ``` + +4. Add Environment Variables + +To configure the connector, the following environment variables need to be set: + +| Environment Variable | Description | Required | Example Value | +| ----------------------------- | --------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------- | +| `ELASTICSEARCH_URL` | The comma-separated list of Elasticsearch host addresses for connection | Yes | `https://example.es.gcp.cloud.es.io:9200` | +| `ELASTICSEARCH_USERNAME` | The username for authenticating to the Elasticsearch cluster | Yes | `admin` | +| `ELASTICSEARCH_PASSWORD` | The password for the Elasticsearch user account | Yes | `default` | +| `ELASTICSEARCH_API_KEY` | The Elasticsearch API key for authenticating to the Elasticsearch cluster | No | `ABCzYWk0NEI0aDRxxxxxxxxxx1k6LWVQa2gxMUpRTUstbjNwTFIzbGoyUQ==` | +| `ELASTICSEARCH_CA_CERT_PATH` | The path to the Certificate Authority (CA) certificate for verifying the Elasticsearch server's SSL certificate | No | `/etc/connector/cacert.pem` | +| `ELASTICSEARCH_INDEX_PATTERN` | The pattern for matching Elasticsearch indices, potentially including wildcards, used by the connector | No | `hasura*` | + +## Documentation + +View the full documentation for the Elasticsearch connector [here](./docs/index.md). + +## Contributing + +Check out our [contributing guide](./docs/contributing.md) for more details. + +## License + +The Elasticsearch connector is available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/docker-compose.yaml b/docker-compose.yaml index 1280368..cec7d4b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,7 +3,7 @@ services: ndc-elasticsearch: build: . volumes: - - ./configuration.json:/etc/connector/configuration.json + - ./resources/configuration.json:/etc/connector/configuration.json - certs:/usr/share/elasticsearch/config/certs ports: - 8080:8080 diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..6bf8233 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,81 @@ +# General Architecture of the Elasticsearch Connector + +### Overview + +The Elasticsearch Connector takes a `QueryRequest`, which contains information about the query a user would like to run, translates it to an Elasticsearch DSL (Domain Specific Language) query, executes it against Elasticsearch, and returns the results as a `QueryResponse`. + +### Components + +The architecture of the Elasticsearch Connector is composed of three main components: + +1. **prepareElasticsearchQuery** +2. **Search** +3. **prepareResponse** + +### Details + +#### 1. prepareElasticsearchQuery + +Transforms `QueryRequest` into Elasticsearch DSL (Domain Specific Language) queries. + +**Functionality:** +- Parse the incoming `QueryRequest`. +- Construct the DSL query with parameters like source, size, from, sort, and query. + +**API:** + +```go +func prepareElasticsearchQuery( + ctx context.Context, + request *schema.QueryRequest, + state *types.State +) (map[string]interface{}, error) +``` + +#### 2. Search + +Executes the DSL query against Elasticsearch and returns results. + +**Functionality:** +- Execute the query on the Elasticsearch index. +- Fetch raw search results. + +**API:** + +```go +func (e *Client) Search( + ctx context.Context, + index string, + body map[string]interface{} +) (map[string]interface{}, error) +``` + +#### 3. prepareResponse + +Converts Elasticsearch search results into `QueryResponse`. + +**Functionality:** +- Traverse through each field in the Elasticsearch response. +- Construct and return the `QueryResponse`, ensuring it aligns with the expected fields. + +**API:** + +```go +func prepareResponse( + ctx context.Context, + response map[string]interface{} +) *schema.RowSet +``` +## Workflow + +1. **Receive `QueryRequest`:** + - Incoming `QueryRequest` are intercepted by the connector. + +2. **Prepare Query:** + - The `prepareElasticsearchQuery` component processes the incoming query, translating it into an Elasticsearch DSL query. + +3. **Execute Query:** + - The `Search` component executes the DSL query against Elasticsearch and retrieves the raw response. + +4. **Prepare Response:** + - The `prepareResponse` component transforms the raw Elasticsearch response into a `QueryResponse`. \ No newline at end of file diff --git a/docs/code-of-conduct.md b/docs/code-of-conduct.md new file mode 100644 index 0000000..03c982f --- /dev/null +++ b/docs/code-of-conduct.md @@ -0,0 +1,60 @@ +# Hasura GraphQL Engine Community Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make +participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, +disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, +socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming, inclusive and gender-neutral language (example: instead of "Hey guys", you could use "Hey folks" or + "Hey all") +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take +appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, +issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the +project or its community. Examples of representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed representative at an online or offline +event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at +community@hasura.io. All complaints will be reviewed and investigated and will result in a response that is deemed +necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to +the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent +repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..e8bc43c --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,39 @@ +# Contributing + +_First_: if you feel insecure about how to start contributing, feel free to ask us on our +[Discord channel](https://discordapp.com/invite/hasura) in the #contrib channel. You can also just go ahead with your contribution and we'll give you feedback. Don't worry - the worst that can happen is that you'll be politely asked to change something. We appreciate any contributions, and we don't want a wall of rules to stand in the way of that. + +However, for those individuals who want a bit more guidance on the best way to contribute to the project, read on. This document will cover what we're looking for. By addressing the points below, the chances that we can quickly merge or address your contributions will increase. + +## 1. Code of conduct + +Please follow our [Code of conduct](./code-of-conduct.md) in the context of any contributions made to Hasura. + +## 2. CLA + +For all contributions, a CLA (Contributor License Agreement) needs to be signed +[here](https://cla-assistant.io/hasura/) before (or after) the pull request has been submitted. A bot will prompt contributors to sign the CLA via a pull request comment, if necessary. + +## 3. Ways of contributing + +### Reporting an Issue + +- Make sure you test against the latest released cloud version. It is possible that we may have already fixed the bug you're experiencing. +- Provide steps to reproduce the issue, including Database (e.g. Postgres) version and Hasura DDN version. +- Please include logs, if relevant. +- Create a [issue](https://github.com/hasura/[connectorName]/issues/new/choose). + +### Working on an issue + +- We use the [fork-and-branch git workflow](https://blog.scottlowe.org/2015/01/27/using-fork-branch-git-workflow/). +- Please make sure there is an issue associated with the work that you're doing. +- If you're working on an issue, please comment that you are doing so to prevent duplicate work by others also. +- Squash your commits and refer to the issue using `fix #` or `close #` in the commit message, at the end. For example: `resolve answers to everything (fix #42)` or `resolve answers to everything, fix #42` +- Rebase master with your branch before submitting a pull request. + +## 6. Commit messages + +- The first line should be a summary of the changes, not exceeding 50 characters, followed by an optional body which has more details about the changes. Refer to [this link](https://github.com/erlang/otp/wiki/writing-good-commit-messages) for more information on writing good commit messages. +- Use the imperative present tense: "add/fix/change", not "added/fixed/changed" nor "adds/fixes/changes". +- Don't capitalize the first letter of the summary line. +- Don't add a period/dot (.) at the end of the summary line. diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..f1ec49b --- /dev/null +++ b/docs/development.md @@ -0,0 +1,120 @@ +# Elasticsearch Connector Development + +## Building the Connector + +Prerequisites: + +1. Install [Go](https://go.dev/doc/install) +2. Install [Docker](https://docs.docker.com/get-docker/) +3. Install [Hasura DDN Cli](https://hasura.io/docs/3.0/cli/installation) + +### Steps + +### 1. Clone the Repository + +```sh +git clone https://github.com/hasura/ndc-elasticsearch.git +cd ndc-elasticsearch +``` + +### 2. Set Environment Variables + +Set up the required environment variables for the Elasticsearch connector: +```sh +export ELASTICSEARCH_URL= +export ELASTICSEARCH_USERNAME= +export ELASTICSEARCH_PASSWORD= +export ELASTICSEARCH_API_KEY= +export ELASTICSEARCH_CA_CERT_PATH= +export ELASTICSEARCH_INDEX_PATTERN= +``` + +Replace the placeholders with your actual Elasticsearch details. + +### 3. Build the Connector + +Compile the executable: +```go +go build +``` + +### 4. Initialize with Configuration + +Initialize with your database schema: +```sh +ndc-elasticsearch update +``` + +See [configuration.md](./configuration.md) for details. + +### 5. Running the Connector Locally + +Execute the connector: +```sh +ndc-elasticsearch serve +``` + +Access at: http://localhost:8080 + +### 6. Verify + +Check the schema: +```sh +curl http://localhost:8080/schema +``` + +Use the /query endpoint for queries. + +## Docker Setup + +Instructions for building and running the connector using Docker: + +### Running the connector using Docker + +Build the docker image using the provided `Dockerfile`: + +```sh +docker build -t ndc-elasticsearch . +``` + +Run the Docker Container +```sh +docker run -p 8080:8080 -v :/etc/connector/configuration.json -e "ELASTICSEARCH_URL:" -e "ELASTICSEARCH_USERNAME:" -e "ELASTICSEARCH_PASSWORD:" -it ndc-elasticsearch +``` + +Replace placeholders with your Elasticsearch details. + +### Development with v3-engine via Docker + +Use `docker-compose.yaml` for setting up a local dev environment with Hasura `v3-engine` and other services: + +```sh +docker compose up -d +open http://localhost:3000 # Graphiql +open http://localhost:4002 # Jaeger +open http://localhost:9090 # Prometheus +``` + +Update /etc/hosts Add required local mappings. + +Load Sample Data: + +Run the script below after starting Elasticsearch and Kibana to load sample data: + +```sh +python resources/data/load_sample_data.py +``` + +Test with GraphiQL +```graphql +query MyQuery { + app_dsKibanaSampleDataLogs { + id + } +} +``` + +Set x-hasura-role to admin in headers for testing. +```json +{"x-hasura-role": "admin"} +``` \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..6d47a05 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,11 @@ +# Elasticsearch Documentation + +Elasticsearch is a [Hasura](https://hasura.io/) Native Data Connector. + +- [Architecture](./architecture.md) +- [Development](./development.md) +- [Code of Conduct](./code-of-conduct.md) +- [Contributing](./contributing.md) +- [Limitations](./limitations.md) +- [Support](./support.md) +- [Security](./security.md) \ No newline at end of file diff --git a/docs/limitations.md b/docs/limitations.md new file mode 100644 index 0000000..b67a00d --- /dev/null +++ b/docs/limitations.md @@ -0,0 +1,10 @@ +# Limitations of the Elasticsearch Connector + +## Query + +- Native Queries and logical models are not supported +- Nested relationships are not supported + +## Mutations + +Mutations are currently not supported. \ No newline at end of file diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..06b4a258912f0e08619757289b55daa498873e4e GIT binary patch literal 52594 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'QDSl;vG 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 z z9MnV0&%!I-1@5*){rvUkR7U(cfzyHE@kr}Qk73U@?BBe8ts2&TN>wV&X&Pq_?_kO1 zNky^&j1+kHEAQZ>m>Lz;tGeCIVQjgcmL3Wgm!|uyq>v=li%T>N;CL})$8A4N_~S(4 zBJ{&fAeQKTBjec0I9uq0iXU!uupuJGj6y$^$kpy|`DV&cgkzB7eSasrS@K#4X?q4NA~og)IZ_iC7gP@RmOF+I|=&pkBK2 z$TYT30z7>N(J2>Z!_#HWE>!%|)^Pv9z}GwJAaTT~Am~2(d7RFfG*)=u76=pFd#mm@ z&?N%>b^?d!T5V9G+WI`p-*V)ZYuJrJ?bG0ys=ZZ#NTu(dTujYC^5;dx;Ild7Yf#RQ z!+M|IqR=(k?HXC4${+s(iwRWI+sk=NQ=Y3+Il49&y8g&e`an3i3M$tLdZ#jlokm75 z5B5_*vmb}0u>XYD0j)dw{kVXRiPs5+zDtyc*N`C`IAdMvm35+3tCD5UNtUu>Jz$0V z(}jv?4^;DlN~*8ti)yc(kI`F)aV|N@>F(z-&kbq?UPP8bS&(W&azu8EJ}6u5cSW2M zYN2?gs@>Ow9_`Xf!F=dOt-Kt5&xO>Uvi#Ed#JA_y3}8FA$gE8kW}%8Rh(86Z#cj_< zQ6>p#vIH7Af}pLUmCv(TPy56$C(rSOp`}nQt3u+7dq}6C^>hjfs**;&+yj<9<=G>d51_SpCJkEtqx< zFT@+iMcn_Q1m2^^g2}+BC89g{btn<_!HFUrF)x1s?LlgkUJe*`0Rh-?H*S9fC0Q@X z9GTlVy{FXHRhSjq2Y#o;QNS^$&fw`gE+K!PMWt;2OpJJA3O$%exY8@`)k=RK3}!u1 z67(1K{uWffpJ~)(Zf`{bd9T~|;9ZA_En^Tz~I%c-4Y}woQdU=07-+$oy>-X{Kr<~X8 zb>G*0?dy46H+drCW27RF;mnJSY@SOid{Pc{5!Dza=8)|l#V?Xj(XkL>s)D9ab({?y zY7ST0?Uqa$bh+DbJ_YQVH`>|k)k4XUC8VtjMP2HL zoj3Lpe*Kne?61;b!6H~>(mPszg5oGI6Sndm=VBb$AdH>~v#Rocv^fE(AABsJ>^KXT zT88fQEn5}H;=~elSN4>!2EMd&Y-w^1Pnd%VmXe1m4*%iT{YG`{9lZ*S{eWFji&omO zrp*;6QYNat1n(V|7xQF5{hoAaI2s$oM<#|6^WW*VX$}%LcEgz9JAm%bq_$RD@y)G? zF_P?c@?5}Ya%5Uh2KDZBDjX8Yh)bfZkPBE0XEL<`FgD;SIG>)JIIn^?SAIFTFNmF1 z^}p?tK&nbAp}A}jagxl3)s0(1-g$Of6yv+81nDEpF-Xu+-L2_%mp^*B?3~C!Kx7{Y#hORe(Aj6Pg=T zzjxsuM=n9pk$f>5vs8zvdklbS+@c9;`V!~%PIvB>QkC*w$?ia-%4v!yOol_CGH%^S zrF_0GiQsddwnB(y?<`Ar5#=kS%i|+;%>3`KEe`u8C!$wEkn^AVOGh|gj-6Pyp@0U4 z>;6dQk45jZ9Rd-?{|TK5Js^FaSXCs@BN*omNu+x z#zDibEt{W*a*?o-HtZeF&F7qi(w750>S7wSlsp&d@l+MtUVgdblF{MgIJ%i` zSiXXw(+|)!3U8N^lXg~fc3fi$S1vE?!%%_%rqgqMm+m!>GFD-Z1P7_?e4ajbvOD6i z^hb-TJS1bFb{EL^%2~FSf%!q`EaFE*pI-luEVOv z55yqVhGRw+dPkM-c4u!Xx;6X>Suh57mQp2M4Y%M*4c$5kPJY#yMs+FXDKlr6MsyJm zP?UvUS>dho5QEnC!o?#d*Ac4}tM#`KOxp7!ZwX{8OvB>Bd?Wu%g#%l?{#)8jvX9#? z{mVndUf=ywQ+t(ms^zaYn4mG1!(F}XNzfZV{v)4)4sC?S7jj=6aJv7?6cVW*ZtKD# zv*WRGl};CP7?irGc<_Wv(eu^O1c?QKo7iX5ziJk_Sh`}whcxG&aZ$$-EP(>s*L#aX zdc*cDk7Nb5BZ*)Vo{lzcw_Njt(?v3IoL`dum<4U3X0wo0SsFsM@1Wqe<6>z8Y@)Yj zUm!`7LV^m<>jCX^)kAywq_^9&!*j$Rk`Iv*iE})NOtp0>9d?T^paxlvKWncp$y@FP zNWU6AaoOgu!y)ziaSlk8XzDCTK-KQ5h7ef#vM1YSOI{z5ikWCpr0sw%(ejxv_RcUs zmE&AAwPKp2k^G)>FuXq{ymG#&|KF!3t<(W|zT4qj+W13PVz2g=QvipO-{f%f*7CAv z(@u3P)xLzuh=Y$Prk$62y)kR0bLEr#H)?Jy>E;U%8QLsaOUlz&)G3M`A0g+Tt=8XO zF#6;mTSj#H_O-#%sOi|5AXV=*H*OdcMD)q+D7gQb7BCRJK+PNik+xDlYVI*c1 zIs*raBk`SeKM&7MTt?DSXViIK_h}oX1m2{8&b!6;#Qm_`cOI`b{P{E3kpvuUmyzOoGA5}wa(*CBc8qiX zcogPHX5^h$YXfAzwjc3N1-hxd=S;!dH$q6)ralUAFMMR!&xCO;2%5r zYHgm#9gH*<#x*$9N9Ks!QIvzy6liTvp}F46xS253)azDrX^=7g%7(RdW$isuL45`K z81>b^H7&)zIuj=csl=uzczar*13TK$i)79rhWIJ9bePrS_`u`aO4u^rfo+tkmszuR zNA>|UpTG@@&NBoT;&pF~S%MP03ert_|J%1>35ubH|De;*h{AyuJK4eE-TaC$UboO( z7RPj+w7Dx7#G!pa&@1T34%>28zi?Uyv*pOuo6tWD`i-KiVpw!`qhS>* zTVNZ*o~(_hOdY@^4Lk!Wo4UkL3=NhSzI+;i>50OSr7f~NnU;<6K{p){hUeftJn3;&O4A5PPx`Uv_jWqAn|WQQ|N$I7d8Ie@(kn!pBZ2&WlbIPAN)27e_f7oa*AgYRfgd@yF^?2N-?2uDh? zYfhhcQ+STy#2?*Q)$4M*CTM5q1dy0xfMb2~#^cwUo~`P=Pl+Nr`X0y-5^74CFn4^Q z=_xYk&UHPv_#zVXU1DQH2&?u_E_dDt*DO)7J7FVqUEdWZ4iL&IRm!pFlq{T?ph%{~ zX}!0SNNgL2SU?Sb2oHQ>lrW&{zMmZv@W|_chL*fjvs{l@b1|IZ|7faTk8S43;NTB9 z9?;A7Q}YiA<;CG`xG>Le(B8-mHqO6a_#EgK1%IX#&#i~jhUE`bk)IEP*x7fs4DsVS zjRmsQf6IZxUKZ3Nic)okRWTSI+bBAcp6Kr3oC+F91_b(HXOd^5`UkEIsr z5m3i?XG$)*inHSNgr!T;Id{oCk)d@bdUCR7Q3Sfm|J8ZED%fn+YFr3+xZkPT( zvR_oE!kQU?B=>FfDYD>8y@iQK0En{dhe{pbF^&Jq{R(jWGJG|Qq3#JEVuYoRA*6sH z19fqN9W-}cPB?!{pwK($D90+DW-@EBC%XqHslkg~N)=uoSuTK@Dd+(aV3w2lMxPIrSx8)y@VTg?CeLgS%ORO|=0$A^^ z&~q5v;~kxZ$;q@|01U?onV{(WNP}|(&tk@)OoiF;3Fzw&lIMFp6rs@tk$NJze6>Ue z%~T91XEpp*GS%CQYsQ0GcSfIRCM>h24(J^CnM+4CC(_XiM>#L!w`!d}h4q@I=^d-u z$ph{)uqr?uy>%=kpsiAU0_ zYWZiIQhdE+L$Ds7p!W^Co+C#VKLTE?*-m*QD=RvGlgs zAjKF`{;@Kun~OA{RX+rw^ywwir`2y_W$(i)Gi1KEt?qN-H+SE=RH1V!xvgFLkge;c9Z>QQ~g(j2Ix)ItZ_Ful)X6k)J6L1%j6RwBhRzHozlF?u;` z>iXCEYcK-I$CmTa)ckS1(y8*u*skaQ#dWd86{;Uww?@xlWo5b4hyVFR#}I05$u9mi zbE(>T(jAxI`}a74>&#%sgvl%h-Nidgz9dtM!o0d~{6GZR*fDw{S)AnEm6^?FN95jc)PI>~4 zRl6w|Q8DCoKj%}u>L)NbvBLFD3jOkbzMIdGTIv@EvUqhhUUDoQ^A!y`;V_#Yg&3|mN^+t;B=112d#EHw zNlu39p|QL3w^h6Vs|_Gg5frugx#Ec1K4t33F^RV$F;iay<@qGpy!wEMpAToI;{&FH zq>&GKBvTEeZfu4+q!)V9H_i@fHOL;sV4L*)Hso!GuHeJ-HQIlMf7dvMm9>VCXC9sG z$(@oqZ5+Wjf&4IonzF687*+aHM5f5h8Z&umV#%|Gc5+-u2+mIgx)CKg1 zN;z4n{(Fd3^bY4T+#FLq5I2ul_a@JoNa&;JoqjZ)<^4ni1h8ydHbN2`ZqU(bMr ze-!hA;q9MS6Kl*f%V^w%9|s;o9A@qix+xeNV$Tng#9nZ<-%GwhKfFs1E^Q*})J=&A zCb{u8d%}Oe4RB>$VhBKDd*zF7IE-0${X;RF2yez_nW);1hX`A10$2~o`2-el=|JVg zbV@wByAmV@7+fHxNhSm9XH{XqMZ);jK+x0ROyELv$ZVr8f8s95LTDb1{0zfnlgNt^ zBZDZ9Dc}o4s)aQ_=}ip;T0(!K0r$$!Lm_gTGx%{L)Kd|*4OjkK$e@EdWKIsD%pbJO z;Xvhb0Bm-IB3npp=bb844`%xcxe&bGNyqdn002umiZ3CJ!>}e8JV0%7uah<_@Wka} z6#NGbL^#0+`vnLDC(gGOVK}*v4HmM|v;@9jJq#~Nh;-puW>5xD80(|AsGXiH*fJq` z^j9mKs|z{$@zYC?S7Gvtf3iRZRsR^ui$yY)>9TT{3;s&tJ8WP{S0u{Ht~XKKp`+FLiV$1S6VfXhVb8 zV-8sQwZX;`bRCm$(Z2&0ak9n~-Y5w(z{hs{3;4SXr*nv&c&T&#?8^F(SgnEk0Ze%{ zc9_!-f9>V1o4SaEvzwwAK1SZTCcUcpaHaQS)Stw^L*@ZwwWsP2hj&~^8p-~lhsSwREcn*`p>cb@D3 zJYaeS{BDhzW5a|6$p5DYlUdPjlqUEWXQ{4*GN7@Qb>xqfYxU^yl99H1=XoI69SS^0 zu-0KhJ{9zXk4SN5?D%a?9*;d^IMZXJ{_9t5FoNQ*|?W9J6z z0Qv8p&iuH>G~#W9wB4XQKgloXiPij7qJZ^1kMyK|i#f(aRrlZ5mu#<$o34*jf`b!; zc10iy+M-l-FAi2l#RT8xY+wyOXm6d?g%iIPfP@6H;EYk6xqZBi7CiyrO=y|trSuIJ zz^ZBbr6SCe0~YX_yE@HRKJc|T#RO6O88oy2JNs|JaEN8qvX!vcTZ_QMXClG7;)KH` zJC@HNp^k_wHmIKa9oFFLCpGFwf+bM-V?G1A6}>(JXa0Q@)_M#h3Z3Zx?LMEu4R(YL zYK4zodxcCo>aauDvf(^0lb0KaZ)6~cH)9Op4C3g5)xxg6&m)SJhn@%{_F8|9m7CLB3N1CXx3T_{bg#q2dV&Al zubXMT{&(nmnCU;h)wK0|qnPfcRIPOA+N*q*DyIo~?(PfSPyg}e)c!s{xh=cUI>{M* zYHX=yxY!T8cH!sBhX>!GvBz-%h z@QnRiGe%*LBZgqw^|VBMh6&$+6G4?<({cQd&s5?!WzJv|9<~$rGJ(<3^H8$}XsZBg z8U8UdQ$+1A2fV&xh9~^~BL3~#|6O)kATKTt!tlFY5E)KiB(wf02aBihRJ|#C@P$Np zOWqaUSPv4%x59OH=+?+3N4Ukbhw2tfe~lQH`ume?i!&21YOM87J{?_#?Grf2e<3fS z?~Cq9c=5)u1lKRRtciPFkQ$j5 zVOCLTW-nmi#SYv(+Vj6ZvpCZ@>842|A^AZ)A5nDmwEiZiRhngkF)lHEytkV9pF@EQ zPN4%^9u%)Qf}u&hv`GCC*q9H-TgK&wqp<@MlTjC$cURQ#3<*>><9Z$UhM2S!Y7F!- z8xKLwFVP~JKyurjP9lkc;VjUqU~|ekuS3;r9;X5N1kYez1H{CwUGRHDL)$KH^4f(B z&PhtiLPT_pNxM>)rTPe9j5#FYg3QHcIPe|1YZOXNpiW#qd3BM!N;1h*#_Oouqfo4c zVv3)2RWR!cUh=amg|scgfH4c^VomTB-U48j2!UX#7G z)?ymX;~F8L=Vj?C0okp66!3J8*ePlXs;I@$Mw)UC98deQ&=p zACApHBOf(uy*Y3L9XCXQFdT_2wB{Z78j_*&nCB_12x*g=_=pxF6Ld9RdB^C}Tn{)H zbDq`DJqO&i-~XN|pF(fF69!8`o*P=^xs6*D4aViovOsG)gNoT{RwsnPOqWE1TjDR0 zgZ@K)R;v|LD9h2vejw&#bjl(gpg>#j1H>W;$`k)Xd>9{XArkwUP?Rbuu=($R#jw_? z4`7W2qjyzGxS&=wm1_b!E$mSJ>`Y3!>+Y$%$GHEw&a0#s11ZB4zzk3_2gEkNR8bpgc|i{5M||eQwZg@1N;p zBq7|EtY@6m%Y$1WVzAlc&tPsWqlkbE$uUPsiht_w33PsKw;9ZaJ+(dUIHx5}n7XGJ zFg3jX4Eb3cA3{&ghuth2k3n2J8hTju(FP@ZAWbH^Fa?eqfcQ6G^MpJ zrFKLpe$?WZoK)WXr1c^r@TfpLb!Q)GH!tDU)jkH=9cG*`lN@8>$135V!ow9PtIiGf zsm_!(6(C=K4sx#j*(E_cLf@t;R~%vU7VoG+gG#&qqMfG;DkZVQyJJw@1a(zfXl}a` zrEkaj{mXw#AZdlgFQ2#rjRU+zbz1(#jO|;>zi0J86gXf&P#qV6)fJvdFgT zThU%Z&jY5MpmQM<)1uAh_s(sAjpO$Pw$PXZ?JgNt>*a5feHWx);!UX2L!X3=-;m?F z06$bH3785>W@}I0;`mAnnsi>DC5c8`r~*$!H>nIKDBs+w<=T%SyoUj$1O=D9zqm@AW}mdoFHqv% z+Md)rjU$jJ=VadI@k(rPKB0h&E{59My%^yKCTEq;eOdQVSqxDJtYcgD8mm(&=mC;f z9`m2;%=Z!tco9nF01YfAtHLwJ8Q)uEgw?6!&0RytC4e{DMr?#L=4EX|JiwtoQ(qB-cwuU2Hw= z8vZWa+2J$t56$FMdeS==zAjy>6;{|m@hc@7DlM+$+%*3Grr15!VX*?p8?&iY$LiL1 znN)-i1nt7y7SoucX+3yeYo(eV*PVxz@pl3K?Q_ec_PeIGLV3G&=?Ea7vDLiFxJbc$ z9wT(JDzsC)a9UMzn{8eo>;@wIq(m0-xn3p=_+%vXhSXx7*Gt^!sfE30f(WE~+06pa zM2B+cD@dk0pi5{$$sR|JVQtM8(vY&hI2N-bzc{QOSH+aWaavCweU| z%(pJsDeDwKe%N4*x5j`Gr+;LjAqFz|ftnQ;Cs_X1IGO38rnyvDNrV1#KC&<_eSjC2 z5maapbPo=Pdc=s=;Yh$$18xO=A?+%<8LnRM>naI*ksNOj2N9b0!A*8 zTCBpbRUd2k<(As+i+=^lzyVdKe<7IY_e$ZL-<%Osl^{%-M&+4&g%l1$Po3sYj%0VR z;iL#6sxAr(s160mSSZ;Ys|#(JiZZwPG!3N=gKm0%*CCa6C;j-Rlpj(LGST#*c^Rh(8d+0H%BE;sL{b(DjIVIIM~dKB@ZXz8QXkZm4mZ>qMo? zm+H+`Iot*N#Yxrj-`84}Zcb9xq{gM9*zMEIy4rkzXP5|yCzy|0ZgyYZ3` za{{N&$?m5~+J#|8FVU7!H4Ph~T(4XJlbe%^>TsaJh2FmZCxL17GD4dl*Ip77E|9d2 zyn`5SAVQpJ<0emGdh6qVL6{cMPFqK^_S9;azI;gI0x!=XE|d_n)lB&o(uo6c+*EEZ z59$XtDIe{$G@*>gRu~PmyX;nF+q_g!$9ZJj|43k^ef?pH2P~I+bl%)p$wc zO?#v2)Tp)dUW1iEXI6obd=%8Nf+37ZT!c0~B9-~-k66SR?tQ1=yDj;K~S`TW4We2qZ6D*}aphg~=PDWuk zF(72=ZHdndSG}#v{?lh)OiuseGQqnX#{THlB@P|a%36@LQJG1MId}k&C-8v%B^_5n zOm8xBJd&TSFGTFJZ@dVCn-Q`i`S{3 z1su{b{HeLG{EhF2v5o&<5c2}A5W93~BnUs(U#SsiaQ^eu%#j64eC z5*9E1^8pIM|IMG{8aXoO>Sgz!9@nGb|VQ%93!EypQa7V=WV?7^JUNK;Y8*<7x+NA?s zJ>UH!X9sTg8e?G^$O%#MI&W1uwXIx%7J6ltD)D+9<^@?k*aE(Q@Lnt~#T12Kb~3;&_v!&?F~QTA zMRXthXDE|W+-LK|+EgS*_WuC`jat-Ey9JL$*dKVbFBPK(oE@aX7saCgTRsnQZRj zg6OQ<&hZ-SsV$RC9b^tsLa{aBLg7o3%#Be!k{9Wa*z=8Qy4sy?CyHoEtFa_s2w~ws zl@mhs-+}2k9>~RkVs9lBZJ-{{Jz)j(}*<%Kvm1R?!GBM zoplCgYY)TMi|17qk((9dkA~Eenhy;}DnGF0)WkD%>kYR^EOL>~vi;Egkh1$W6S5KK z0OdlFKRKGi_ibfq$ihkc+yw^kn;_YwVH8kko_4`Y$%P;>{GRBGDlXn1zO>O;iJ^tZ zF5MGVOrFS(b|CY40GyH#kw9)U^KRTvbAZ`?4B97xE*htv1IOOXo<lau*hHWklq=wq^A0z)LZF-1;V(zZ2(q`fK6sxL~-m_rN) zNLlJTTO~oP^l5XA8+$h#+gTac#gwrmuU{w3)H7Eg48UdgQG1ET-aAi9}Ul zT_Iq$r%-_8ewM#FnsaBoSX`%1wSGrZC#<&3UIuai({2)0?@AwyH9$dvmz z`LBPmng3vZPosE83(tU{Y%OUn_mJN@y2u5F+cs1P=i=AZW)QKjm0*`ZR3BDi{Z^-$ zXkWc}vG^Zk8ek|rgPGH>e>Eyov4sYGF(>;hsDmJaRcZ))_|IxwuN8t z5*`v~2C;R1+UP1_%%(85y{=(-H`4;|e7mIXI`u-DJ|^oL&X~ID63uo&H~=$K!LtvX z_%_bubps>B+D<%1ObOty>a~xP3Ml*?FIzua1$TMX(<(#V|C&E$^Qwq(@$D7t(fyy)7ys(rS9;F;qOf14U_4vU(Ak~iCa!QwgRkyEkIUD=3XrAg7O~vLve%4 zqQhVR_i4LFv~ydz^val)SOLJD|I*xe@Nz^?5V>am9YC zsq5D78m|$#QiU5&$m#O|-b(uVqLjSFM(;Tj2q&kgAzX2^j}8zod^7SB!#+x=1)a+V zppUi-A3{pMMYLWOx$2imXX@X^WBqO>^s=@+nQHhZ4!ms&y)6|oe2b@C@~K0BM{P9Od?!R zTzwjiif@)p!erPXFPJmmp^5eWbG@a|WXs6l^q%QGDLkUvoQW!LOCM3;N?|ts)T1zz z5=!jFVlBtFBTQ!PlbOx10Hg(*L3PH$S8Eg}jxM~R)UYt{<=91m86C*=<(m6XNH8t| z!ZzqrV{_rqIHedvjYA=6XOPMILDfyQuHOJxf#{Mm_O`V+F3r{3Y`#*aJ08lV7?)s8 zv-z~r4L2G;a6~BD$)U55yozJ^g|egFiFS1!jhR5mmOzA33Hs_5j#1=JUvFKp`=+A-!TG4tH-h2{?0U7zoh6nW&=@Zn0oF3NC@!h_-TJC`bk5ctTo4ybEPq#QaQ?d|!x^!tLxUApQNGHKRtS?Icd?d>5e zZ?KG>3cbSEX%-*{Z$hXM`M_en_7OKNh%v*_n(fG)5Y=&;kJ{cAbBMj?n2- zv9JHbGJf+J2j68Hp*Dt^qxb5W%$Ut^CvLQ`jJyuR?m;}FtyX*{G=l5I7l4# z1pQsnjm3Mjm-MxLtM;jPzCYuRa&g5PyrWZYN1?Q4v6nAh3xX!Fcj4>; z?~ZPlI|lnZgm}e)kz+IZWW2z*KfN1aoOV7Jq)nJ8B0S5Hvy8n~N04d^kK66U25qL;+ zp(*uFaaljEjCDDRl|8|GKJC`C*Z9TxoX0n%bLo2yJ)rtBw7OpIpM<-u!4l6CV3e9< zSG+V=GPP1ru(zv;zZ*jJb|Q$e>RABO+tmb`oMvcD!mX*jH4|BC;}1POzHC|_MaWdU z`+=rDUWi8HwGfprL%(Bpx6w^up&M8ZZQF33dg1QuR@rih4I$>Ki1OOVVsh7fX-=7V zkbs$$vwxd1{*2-v?-zN_kZw>x#!YbXJSgfq)Dz{3Xu>)5=30*W-wz~CV>z25>MuCd zxMIG%QNq%tEnC0be@ayh6+O5zg=ErY@F>4M5Bfu=kxrkz;6%t`7OTHtT@fWort7iW`l|E%wnS14o6cC z4Z?*7uImHO`uyL-zhqx$3L*(zUoqfZY!NCo-O%~!@=rP@`2_Z;f`TbWwZ zBh}&_Kf^ot&pQ zlZeN_*apUN#T6+(R-2dXm)%SdCebja-1>1x&$J>~?QxRKsHR~vYNO#G01c;E zVWUsXcVkuvdeiZS@WMyMl*Yh0jorQWQ;aNN7mvc_$ZhVifzciQreQy?SRNJXDOipr9#3mTS z3LIJU- zeivHVWC1%mk<}kGq!%m{Fs6n}s8UklM`W5$kUaGMbv?7QIxJq=eAwj%nnjzNtWizm zBh*A!Ki!$1KVb%j3uZ{v&a%mSV=jPct6fq-yl%r2aqKu{N--l}L)p%C7(Rwv#YE2I zVY8bQi~Pf7Dy055br{PL^;=lkn{0jw-H!XKQg~M$fydqnbrEVG4~}4i_iT?L@;qK2 zp9w8;;Z-!V6jjt-R2%ns_6l|FXMYsg-hul&C**;Ap0)cPg8prNS~s|LZB}elunE+7 zri+iiGKJb*fS5L8yU;(0*zFfe@!+MuoL|?(g_#0qLUaO<=tSj`Z{;&19W0H$eeFuL z#JNZpxDYNiR5|O~*sI!5p>ZdWS-f|q~C(tQO zRwZEqmaYkV`^trh|3or7i=yKd;NWaePs2nB02Do?ajno%?uh zE3*J=AW(7PhQ<3x`W3clhjEpS6eKCepo;>@`3NJ*@bfpw+-Me`5UBzdL%e8Ob#2TW zF2v=pKCSn zpdLJI&cbRL_wBurh0mqOo#X7c;i$r81yP+YKe*imv6`_`y;-eA?JJKDHXW}bR|=KO8}W0$606RqU>0c6 zI(H#;v_j-QA)D8D1sl++ z;`Lv{~oAk94h9wxrZ=H>-jH9~`2)*2QT3sYT6+-|pu?A%gH*lH8oZ z>mvREfwN9EuVtbWSe7444c8xAWNqcGqjr8?D{%Lb(~W3B_$`_D>=mKqNVU+0NsxBT z9c!h%Oo)S zS2?~0o*_gw-2t;qD4#rpRLVS$Xb)m=GE+f*{m<6CY zu;uf3CKHn^0~k69g*tkFC2BEE>-l5YW>H_bW%J_0?}4V1P)UStYf6#L4r)z&Te0VZ zC7brFHB;akf<3#xSw@XeDErkPfbfG_rW9O2L_wU?+xpcrpOS3gVv|ddfs-uL9{KK& zo_@_-T5(|Gww!Jd!s;+wOZfRA)2^X7F!gwb8cZ&;n{j}!U!!QOAAW)fa63;-dxq*I zo;`aLTH5a}HHv?g1dFESok%8$Eg_&H%m2Tf=mSXL?me@+}nrqBJdYFsYh^mH{2t=$(H zb1X*=VEHP!h%>UmO6c;5So|6vpm99`XX3O;1$&fi1?b%R=yZCOUp;3*fChKL%8O*{ zk?QE-woD8smie#fG1K7*E3Cm2VX{_oMVZ$a-+qSFC!L41m9ZLdMd1p{Na->E(7>0X z&Tc~=o=&IZzGKj$HaIWq$c3;%85g)xRcCtPV;SJbJsp z?iI)cD3LHX9%PtUY0 zz-D@N*^@p^`ziFqP37{Vb4!fg--d)MsnY%EBAT?J75qJ7XpySRe&+!k29ltgLhb&Y zbt>^5YWRCIZ7F5kYp)9q(?AeDdd>P{F*TzUxJ@a~{d_S?BPtK%WhJdmyf-%yPVh(O zGCtb*c5Cm!-1NfA^&i{~f>=2y&Ua)uqH{l5F8_r)mKifqiE1?a1I_Ho`ZVL6C&ij& zqX`V7GU`)2Np5@fe?{YB`^#)w-M0nPjpRysVX`&(vlu!-ae(Gd+D1VNC%~KN88RYT zQ)0J#95f|ghU!N44OvZn6Zca}70W-fc4K~=)DGO4M;4vlC`cQ+eg7zw7O=7=yTl>Z zKh#*ajnSNv;3BJ4OJyu$^OHf+rL7)5{Yi8v+hfwx5pBD)B@IXHA0{Xnzoj{R?F{@I z1c4@{3ZZ8FBiP&B1h9(5YfDHf4Hph$_8Gpq*jD+yab0-GVC*?Ga6`oFJhEjWy3&B! z)f1aF#XPX+4?{2f8H-pfyR=kXI*+k~B_o}hD0i4*63yt|_@$p+?fy1>GHhJM#}{FY z>`>wreR1!Ye1tRL9v1&@7IzAqN!he8d+zj)R@)>9YhW-X=ew4fuH~K}rKdq6<~y|> zr8{|v?INIrwKh+M&RlT(%6S_ezjSQam-SE3=>U!AJ#=tQ=a!2U8|jwY@9Ck@I*Yz^ z_UoS=a@azdU_2D_6;1&9YQInW~$4?%_FTAT%b37zn3JEackLE<8lTc~wpt&-0s^wX+zSJSv1@@>-}g0$LO(+3RtqnFj6 z@p^i%K5f+P&gb;-XIv~~`80Zdq@uIkH;2sS`umpalC5t^0)M>T5Qr22QN%G z!u;_lok(`K=FXxjaLXs|jc$(7eg3+^&N!<`_<_djh32&P_g2T*B|7?Ulud;9S@}-x zMeVoWE8aaXh_j?8zDT_Uanc>=2EZuf3JuSpmppFne{eyRz|?6N6Dj*bDqA76Ph(A2 z{8RU!Y+JiiO#4~u; zB^#=dWl}d9Vc|3N^!~zjQ=pd|;t0VN*SYE6lpP{MmB6gaQw>MZj;s<@w3Tst(2jEV ztFf_ClHHeqLD>)0Yx5(6gGWkhlsxbgaR!R@q$*kW99bA`Z8+{9NA5tA+b~BY?O4;J zTksBwQ!@QB=c*oF&02GyP>6ZseK}S#MI_TGBc=(Fx{lvV#8BQHjex+<*(GOzO~RSz zm2qsGN|HpoQEl>#eqAwuHxfkI1=J?yh-nTlKxN9vMtN`IM1_msJ*{j9u%@ zI7)YLC<-2azM8!|rVr8s+r_GR;8+-*QoVhZDxSD?jjO68C8v7yys>z8_ul(z1FjYb zFa}a+4zFC}a0O@$VCNa#;PQ9z7n??oy>+d3z;ci|_G>0kBo|Iue@ZhL-%2VUbZ$zn z^p*H^Z_Cz@lnC7gNM_~Gf!Q)(FK69o^8Y%(K0jFGC)|2b7(UPC$Nx-HLw=sLEX2N4 zKTu}7P+GjuSN!3(9-@bs=<{5> zMdCBq?UDOwJEK{0R!^D+E5%PbNILCZig}erBa(ex=JD6FA){b1Ax2u9;%JY%)Wf{w z-}1Q|v6nfZ9};Y&vSi-Kt%d7|eli}a_-I*PcyPo9?4inOk+wK1Zn#1TZrFW8zSzu! zSBn2J-cW4LD$oL*Mx;~D=B3}h{A-kBH@4f)&o$c(VU@<`;{%9zkEHtKlZ;#G}g2LYK*KOrT<-iTe;hdfO9S7d|fFSwq__@&god>d0YRA2J zzfNoDM-jP|_mA_4HnVj5awXxtz3jTYROZ&h=N@Oe(fAtk77* zv?SCPo$!u%ks}ABs`6rXyP?@$7u(+YLpJo_Cis@en=0RWHpYGic24i#Fwe1w)8DZX zp8ER&yiRMZRalL%CO`O(b5G) zH5(XNE+M?nh{TA@EYxS%0Fk&|$@lwd0vFcx=WN=`Y{BgyQGn5qC2k+${`x&ud<6V3 zZ=c7NYju0cKW-xdf)%~p^+O)=Tf&g*=%lRKzb81Sy`| zbAtnx2A?Y(a8|qh_cP+}!m;nL_}|ZH0F8=$)MWzA+Ru+}nCP^xPqq`h$4^M_X(d7T z%{0%+?!?;UjEsL&MO!n#pB836fDth`F7O`fS5~hI9X-(h6Cbqwy8|)ORk*BrpENx{ zDZ9k)X~lSt+7yd}p(Ca7;KK`BaVPYbdG$$Kwwx-6I2XI zy&ogotuQ)WThyy0o_W2PI$|0tdzksJ5F5m(8b7;P5e{@k<@8p}7A^=#w>efq^)DAETv3|+l_&#SKbrw@E_*r#6TDfY#k@J@_#-e>Fl zl$d+72avm%sqTkVdxbsrUV9qC`XfJCxnqGbf*P-)aa<)!0nr!lem%=*Q8nBI*2?#W z$>;fXcT19Ysprgs1lKOi)U3u)ZWLoAt9zO!;YvC8Z=yt!{Nr{FMeMF=>&s^fmEGjy z>YrCj8t=9%jpBV&6=@;mck^w!AOf_)*}pzC$TE^7fyrvIlV1~VVFx-dHyle(X&h_} znerb@ExJ7`U>I4{(`q=cPdQ(-MYq=Yg=Dm8uF~qk&&A#}frA>n;_;@6R0rCo7T)+Z9+Oc*D)I79!Xr=w9B5mm0 z6tGKst|!_d!aZ0)1FbSHxqN4(;CRw~DQaPb1+%W9^%4I;F7egKGEEftH7o1aD%Qae z4P;SyoxMEB+>3Kso{IG)dBIJ1F8)XCe%{WPQRp2q^jXc@^-jr(Yg$7Yum=;B9T>H@ z@4GD;!;}2vDS>d4^|zk?yi6P$klMm}wAc1*=e;?O*}2Vn8|p2w86h@M7gMJ{AEi4b z-KPIbcNkbQPK;`g_Rr52yVjqeS4|OZ5hXgqRde~hd;1lKg&}Uaw)Hv3!5LKA<{4W5 zJGPNI$fMnu7@bF3fc4P*ZU`y=onJV{LBlD;)3wc)-w;NY0 z#BCVxw6HUOjMX|N*QTNPZvu=SC2{VurQ&anK0Kptw#jlP5<=Vw-_x}C`@yNzW@$?Q z&&Jm95yQO7poUL*Q&TVMDbs!$gQMYdFVdql5pm)qrDw@3nU_lSC!N&3xUCpZYk>xc zE1P;h`D?#owWBF*W~tP?fO9lsG)x^0NGS%3|I^-g21T`e`;rutD5#($(E;R;gM^VJ zDlkL^kBDSOl9Dqrq$3CzK!zw$j|34Bkeo+ENdf{2C~3%&bB39>HvfC8?t5R~$M-BP ztYYu(-QBBK{H?VpqGpz`Znb)@+i*&sXqNBem-!+V+8>zi@_7k&9$?HI$A1^Ubj)fe zX?6N1Y;4qeSe2Gr*`4#s2HR)7umn0-ftvB1V)zQ{Fujai2DJ9_k~Rv~GW!r$mc-=t zZ+*@xufwye3o-|v&BodEXtlXfR7zn~O^lm{-zEnUd164sN;b-catPk-(x=UGp3VzK zQQUT^04KF^jh*$F6Nr>G+C2fmfPfe1YhoCAH{Xb`OXYA%sPoIe=zH#$@>#1obn zpI;@LB4_h^%Yd=+f(=Vn%QtOBL;3TPird%<&~lOcE{8kj>j%aA*M$LibI>s5HTTl7 z-1!WUQS~G>HK+g6>(Q)Q9(QPVg-^i=$M~*fpfLaF(vT8ZT!sN8H)90UR}~&s8}Lj| zZ&+e*V6U%1hdv*P zHfeLs|GKcZNw&O_zx#3g=x)7{(1a*umVy8~6)=jM;)w@qLKu7?#i-5ohOLx^X1Vmu zd4v>@0S+FEXY9%(Z1q(>B&WN8=puKzQ6Kart|bI_n|>@b$KK3OK-L*o3xw#Lcy`2* z$|zq6@&8Pn10!>5_TweHwWLp!vO%OO-KY0U>y?~ekrNC$u#XLT&wn?{b$!1D;S3a% zEFIY2-u{|-^WGX7^s%iDL0Zh#+_UHG#W-Jy!9wh`2jc828`xYl>2}O9Zo&h*`72CO zP~240qH^Na2hf?FIG6k2*mZ(^C(m>OMmbaAn;R&gbJNr58V5U_ugvET-1t5UhEDtd zT27a_tE5>hnt=kge(!DhAzK$RsSXLcU&1*Zruy*bnM0nZ&;gyEsjDV0Oc$;Dbv~*6 zvRe8DCv|*u1^Zl`|1OnQ@qLHd4#@+re>8#se`V_*LQZTP44PD{^MY?^Mx1g;9z0X? z*HSy_U-xD9S|^!BX7b1b-46pYwxTh`7pSO}ltefYXg0oTFp&5&W}D<~e@QO?GNQ7h zLm^d=slT1~0M%x`UgP=d)`7EF=gH-Yq8asH3aT@IB31QY6OPe8{v!(73U~xQN>lCo ze+&14wEwn4ruzfx?D2EQrKmjQX{y;ab_l9mAHs>ral-<7p5ysnd3v72hmMDbbNtD@ z#|ZsEkqE&Rpai;w%gDXTmL>PcE(fEQ&h$}rY&j?GzH;@W;63Uo#2PnUTC z1V-`8`*KaY{(luHc)ucZLkDkKaSHG`{kK=*SJKg8?#P125>;Qqc)@6g(hz8CXXP!$ zDF2nU9RH_ZT;f)DxFks(zHe^2KEXV+Ji#%$U^V&uoZsP2bLvvMFoy&QhMp)t&_d&p zbG|8;;m^}lJK^^{-FhV@3m3)V_YGbyp@~~Gp}C)RUXY2|P{{W(7?@`ERK6al8lHx? za7q^->ePM0XRUI&XrI5+Y4arg$X}<9I}wYpJ#fowBfp6pAi>rR_ZCDmm{lGpq%?f% ztAID(e3DkjM?GQ8$9F04D%ima1UbEwH>XZXQ z9`yy_>GY-|@xUw9=I?OjN!nl4=%P6@oNpOut9s?qt;e^e zN+@1aSURN5Z_30GYvK^uRkjS@WBOyy{1QD~Xj;kyXVGWE?c*3Re0HGJioa2zY;V zUHXiRepb`wPnGh_+j~y|chcv7(qPSu0zSsrw7?kn@((j-3X+slcE%G?xK+QvWQ&Vz zGs#diC>b!;h>c33TPItO7pQo{cb^}j zAz8osyXL-CU}~F@k{q&eNmx4kROraTs$Fi}apnOf<&`Lttwj@QsY~%*kgq&cyRtPA zM*lWZTdx9&zADL5ifgN_K6;*L%HXnd1K}#j;d^||P0Y}jOuX#S**Ib1GE}{k3z3%E zY*p_3q&By)f2_b!d}#dHYS7eijk*NSmA{ARE)RyPhWbV~m-}RuUANY_e)vOwlKbR$ zq8?QJ?3%|@IBW%*wci^hJ-%(KS*tSx}@fE(WkG}pNFLw95Jrysd`O%draPkB9#V>x!xsUPa{;kU%tM5*|Cn!i> z;@;CRFY_X6x}2@OqMK&rV3Bs}5%mPCiXCuYdL4?T<1um+{<3g-$&Y|1v>VTrnX2(6 z-r9`TKiElwcm2S>`ssGEEw^@+1^v5PgwCOf2e>k-2$LPgV(%^Wct4A(n<=Z^<5lc(+@;D^xIp#OI)+x1EBp3e zqgGy^)YftaC+f>(i?{G&c1s0S1mWa8>uXXW|H|i=gFeJvMFPG((%Wwsdw8IKn}HFR zcl$3JZfz>t)_N`F&Xv!PZXuzc*`p(rq)e7%cB3ap;25|+QJ%$ckH2rvm`*;pka}Y- zU^{)KgkVjkcIPzY{n=gb)X+H zci_>jZO+>#EcSMo|KzQ|@4qa$u{*H2;J>+8v{GYe)T*Y8xuYP{JoZo&F%@V2K%20q zk~RNw|CZY*_22G}4HQRQ#RNDTugssE;sO~cdUXLo3$LcS7?oej=(}2PF1@nVXGJvD z;`as7EcnX*y}2Z=t5ynZ{q2N$T@ zWj4ZeHO%Nju)DJ&yjNA&t!&hPNpfS~ z>CKyhI_wB((l9?k+!_7ubl-#bTxU@k724YPOuzZl5d~VLpbB^UW#NN(_hc`zb`@%+Q@5Fz?!ujt z3CbcEonOi7`>;baT5C6lGhKr=k@%_SM#DHEi=CE>0h0|y{sMxeg{XkNjQR(-f4R(< z{=M+ZTns{dM*yz1%?&QB8W~2Ml)8ERM1_|lr|Cfr63))N03M<48jsztPcKd&*DRZ~ z+i|c*wjKC$r#21E^7bkl64ZWln#oZ3KM{}&^~&mc z;+CFHjs3u%KlQ_vF85|Us~4W8GilKP;z#eUyiQOhlKaxVUvg?&?mX|2Y}o=6gtwr_ zaHkVwT$H@p5@+(_Vh6UC4rAsxaGzIbJfaQcdC4>$KrkFN62_H?09W% z+Z9jo^8f%v===)VjrjgJR? zbh@{G3L;AEmulE=)C0x8=Qw-Mt#)b)i9vKS5p^BTLMoEg4;x;5RamDizN+;MY~)>` z37=;=`=pMdBH%eL6Qi;1w!K9%8WZ?XkX0i2eRQ9AAvWAD-A75r<4sv3z$?$fO{Am7W;re=-AsB#Vq!yLPWR4oKHV|R;vT=6lbrugIhA(~iUtAj zIljt(&XD-boqMd?bTRcV{QH^aB1MxJ(Eb7Tg3fS9d6kx$DC;X@9&SC?-)||4=?WT@ zm8$ygPg$*fcul$FBvi##g8YE-#iV^3+}bj?oNtwe?uB0B8J^&a&oSNMe>Z6mI6ykk zACN?ER$bnTR`mS0s~MeOdxb89f8(t1QQBty;U|zOpy)wc`G&**V^-?WDS0`Y7JBHLkC6x>wooJE9Z-qf0PBu2@D%a3`Cul|xB@RdO4M z5LP4sT=8$Lkp4VmlP1(yCW&1IefSW*1XU(6(?Ni zv4(yMwP#a0OYrLtdYws%@diaDcK6oL45)u4c?~o-w;1N%?k(~RrLpWXYYL=S@Ueo~ z^#>{T{i}yao~-y8(cvxVqDAa~ggQuO%u8p=?_J*=QJyqx+nt*RzP4>$YkD8>Y8qev zO+GwCO-|?q(V&)lu!8#ppR)K|Uj^?e9=Hof=-O-eOLn-ws^oUbT-FvSSB) z$)IUZXqlHUa{5d2#MGtX4M8Z4H2whZ`2x93nJp8=i5aUSAevNMc8G+XfJuW3bEdml z6yW&}EL#4Id_dGs8nJ)2YrO3PP`V(8XKu(Bp2vj$*)ehkO3H4s4`_TP z-QU{YZa`F#{JbGEQa%Tl>nPYJX-+ZVWnLgaZ))^Ex6R!6l)hLyP58B2Tu2IAA9Z%`p}v=T}W1d7r251 zGY-|j*Um?WH7D3YB|iG)f5|{`3n8lrRdQIHR>(GImYe^*Q86?=POkDI|M?BDJMe-| zs@HvUQ64nt8=tm{sN0I zFNU~Fj5cd|7mpPN@v_5qK!0Qy#X)d+mqOe*Y%G4V|0As84Fvh2)J%Hd&%_y_)2ro+ zL)Er>fBNg^IXHvHuD!7`^r8U{i{0Ck&#q@)GKoXwj%O13B5PzBXKYm0T1&yT0*uW> zSrXGN;`_r$S=XZIqhnM5pSH5-C{kBlWXq@9&+6!S|Di)X3rF{i?-sBjpn+K#{}7MJ z8vd|>Scm@ol0&iU*PbH)#g%fLDk8#aYrmLm&IkOCS}6(|RFEYl<=Xc2jXq)t0jDrP zL{9g;1J;c4N}w~Pt`Tco_OpE0gJuuV>~>t{NQT-*!1^DvoE;(6+F4XsyAqFpZ(u~} zyWy{;m7mmXAqHYiD_0)@t2+D=kqd;qbBf||-JM@hpjmW_tj<9GY#|s_ajTWBn_Wd4 zm(`ohiyq+iM|<)U3R<@KsN&Vq2)0MmLn(g!wYa}nGBBd z2RhwJDf^3tWMT~nsZId&lk4~Xnsm$g9cXx{0dVn@fl8KJtV2Q8rRy{)ohndHm`H)O z#hu8I;TO6}9@!Wn4wMhIG~9RD*i?eJ4c2ph$y;AX@rMJ!VpjCDf|YMXotDC(a!I&G zY$BLMuEgdO?p%6~+hBm~PJ`PxLR_W-G01F6k0s(Xy9c}C znd6~2gVWsrfv_aKK=LE@z^TyD*V8<5-^pbpEkC1jr{g>yHr>JQLKrdnGY^rQ;89>9 z?`rzt~1{l z_(}Il1Wt}L7sK11h;tia*fN=IIX1K~fC~rH} zgpSVz?C?5{l-W-A_qT05(|@0AFZ?^dQzyu%ugN&OTg(>WgU< zn0X@a{yv6WgLWG^>ZRwQ9-Nqds6>`bpRt;X)*xyumX?(E7QQ z;n5JmKzS8<8JRZxG;tZ7c>Sf#``PmYkX+RcsOnD>8IZoGU00H z=Myx})wrN1%e0te;a(avAq8vwh>?jFgeP^R!P0?p6=&eJBl9V#xY=99zoh$GODSL- z#-M-jXOttB&f-g&I;xs5)WO-1&8eSaJ5WCdA>g%U1jqI8cvzj&8*JyV%aSV}17Z!C z(}bJ;iDkKCP~Zk0%rK}thbXk^21GP*Nb;-xiH14~-#)0FfE=|hM@2e2unpBOi#efH`C=D_G6P5QoBd23s(By8sj zfdw#)rTPt9b}hnCnB6Q{0Q>V$u{RRxUOXH$!cR$qQZY+KR@gNpIon@~uG)5LT0F~5 zeiINIE6(jAlfc`K{d5p7B^-Vt99BcpZn7HX~BL% zaoZrb;d-xgO%ixARu3+hDZ4LCOpxWI6gIxK+|J{P2Ipn)k)MCHg&!SU7lx2%5pzWZ zp_;DcQe*#c&D1Su`gnHb7Fjuq!gOMbX=uh`G@>^LR)8AS2#NXj?gSb8sZCIJGq zLQ)=`BTXS5CX(beROZTICW|&cjt@4Rm4dl$JNCVKjYzq}TzhoCwB(K;wx_2v`F`nX z#qS5f2l2;Y!=a5k)JO8Bn7+DgDfW0Nhp$X7f1{!R1?V%-r+Ie1=z|^F>ho+qXbj}7 z3TH|>saCz(Y;S`M3P{*bb8s--@csp=l=0akbqqD^V|^jH|IG!tkV0#_j22Ob`@@$< zn#Xzfzt1l0X{0MkUD`-wYoE%^_pas$QNz3H1n~k`Ky2>?O6YPA;qPn1r$#?!zKALl zpf}x!1HcMD<}g5n*>V`l7I)v7dagKjvtGK!!*TuP1w+Fip3!nJkND~HYH1F4I81gq z05ohd$L{K40!K>fE+C$0GoXGJ^PkCqz;B%FDxtAr+x@Frub1}$1oAYPmYTL!@($3} zN4h}@Tqr@XJcG1VE>baj$<%Ka@?2p4anNcpwDar29fHRk?3?zFNxCyFQxUI;KqoGA z@_E+_%Pn-g`WP3wP~R*z$bX=QP&)=~4~U{*Rglw)biOB+ah69&rjXpP`Gnv^$O(>C zABzt0d5k`@3ZQo*(@660Z#zsYkU2E<&Xcbcb*H?;*7>1nfEaLb|l5Tr4JVFw3&j)m8$J;CyrP*Vj~UTr#Y z%Ji?_x-7xvH>5{=daZ*$a)cp&@Lpa}Y97zp{$V8ogjl<8mIKBvQ{l<$_BVWW9P;#c zz$JrdN{ri7G0|%KrzL9r(o6!N;yV;OLpk(b^fob?BQ(IV?_~g_nZ0>|{=?9h-@C%cjA}F0;If^8!>mlNxmeB#)mWTS*M@TK}K1ibaK-uxg6(iP^zaW!6 z46G*^3GiY(I^GG3ofn$0*DpUEN{9`frpybjgM=>py0ChPaEShu?c)nm-gr~byaJFC zNRje(;|CuqUQBsL;Ux2OmT4lyY0?=)nqeDq^A;$@F08synfzARoHQwP7}`aS#n=*bmD}}Z#L7Q1onCxdrGC$waQv7w!0h3F#OT$}TjQZ1 zT?sq29YyDnbP5I}%S%Rlp0@57?l0E5-~U`@jW`VUn!+uW0fI5mFsU9b&Q$q*ZST{A z2N=Af7;DCneV#%FNV|kAi<<^SJz^eVT5aN834W2eJ@gQ!rwi5SpsoWZSq@OlYHFEu zsSK${6xrmDT(m=`%h9ElqhP0C|JocK0hpOHJZtg)k;s{TcI}U!(!D6LJk}_kWPEnj z_f?e29EMaiwGL^>lGdIwL&bEzxe`Y9k9K{^M<4I*;#qj8-_xcu zyr)?;o`#&Nf7`#wjBBU-Lnj#cpwc~OuJ6|~TYya_N$dUvHtqyX}tA^j{vP-!IXe~uzl){=GzhrEf z3m$iSREY9=a&*~)Xh8gzVuXimjPCYuZ#c|2gGOxG2sQ1V$`h}rpsVDN7if4#VMnD; zkw82F-47oaSYC#l*0s>WnC5)SyD7a@El{Mq8Uk?OT)A!LtsIYQ@Dfqex#YTIW+7K%?e-4OJG%O_^N^8nBl&@u7c7AxcMIHN?WSdGxDU%ydGb;Uz{4<}U zTFLbWwgLx%G^Uh}0$-P6+7{jn>B$xNtM~2zh<^(?_+*0j3RdoX^Yke*>wo9%S<8;(7NIENG1CS|a?;`7LKN0}CCcobFXY`mCY?2Mn#yR}x+VaP;e0Bnl}awj zv4iIEU>Wdo!KYB7EdtQwg3WCBXy14?;uGo z4~Y#qqN?Akz;EMxyuam}S>Om|9ouL)i;Hl{-JS(gR=Irt+r4K%gFk_2f8B~@_s7F1 zFgi2G3Td{Th(5th6wFpr6@^>0T5A?;{q*|`+ozY)C`O)#4zT`aGkl)Jv_7@n?EpC! zfD?*>LTaEnGy^sQMdR*}dDO}e1wyF3A=+|^L_ptYMdxIG?!7m~Q=dVlLi6ERql*SU zMUCNt>Vuvt(5f%~m!gj`yZ^IKMfYR9j)>fvLoz2_Vcg5}%Q1wjA+*%=FJH2(D?O6& zxemo$hM=L77hx+nFJ!=dVzcb-^V^lT#=C#&ccAmY0tj}QLJX7ll^{A;)vD8adpHsv z6RsvHNbQ>t9tDpVvc!G#_8IjNbX9T{jmbNwY||jO1a@Cw zTG42+PHaIa;UkBF5aCVI%af**B3N53i57H@Omr532Wr-++h*^5h;+rWjxFdO$6A=I zt;1D;A)xIm+~C5$+0E&mo|kEkd2DsQEjTtfT-xwB53>l>(dB^0o)^zc9CxI3ruuLs zP<29((pf)ZAhP5)#u6gK#&&>6?EvENs?$ z;@(LB>FH37LwTDgbs57ObI&QApM)y03<3AB!w*d@wjH0QYs^fWdT6MoL^xNN+8pVl%gEEFW9%#P zo%v)T$B(Wq+o|nE4(YA+p}@XAoi4fJw^&*Ut>mZ;BleQT{vGKL%4^KU9ipJIL2o!v z!Lf>Npg8h9R!h!f`9pp57?<`0jjh0uM5@o^_(oX^qJiuA~naPW%?+QoTjb0iNJuyHnDbc7y*-tBCZENi+R5(FG8X5`$CU+*KV)cTe zPwz~wKI=8BC(ZWBNVEB0*mt*f34J+U>A$!;S4~o0WG)nERmWPQ8o#3&WhJxQ-R%?4 z7Ot#s7?T6}A;MCk7vurFO(ti5I7e)vEod3lYx>a7e!BT;GE4JyH8BS_YdB^hZ+QSej=_6J%AL{E0>d8OJicR8epQ{toPi{~8*AjF-ZO?6S51Vxli4JdU z&6w4f1x@zNRM%w(PWI*c?{o(4jL<)8YQ96~_N-Yxw1{P#BQ%o3{;K^|M>dCWj^AIt zJ6h~c+I^W;o({mx76qkmkmKN#p(Hz0eD3DjNMg+3Q~$%4f#QRTyT|whBp=hLiK((i zVnSIKcb|k-NAWgUs6575G~s*vNlu!SRFcnG#&v`^*woJQF*eGE#K~mxy}-*3VEJ^f z(&79UJU)_)1pe=92mSvM{{IgA_YRQAo5Wxm3JMC<@8rG%x>NAK|A+pNsN8OL)2vA2 zrC`zgp4abq-m~(wL1W!*;0J}2gp`D+gtVxn^essRw3HNDMp9Tp0xcn7lg#n;e|y2n z<(`ABAG{!`ASxj*Dj|1EQVNaymH*ER2@n5%2ruX&GkCbzdiq$o+fZPftn6%bt?V4I z56;Po$%`q7DxAA1DSOUWUe-cZ=G@_6l9Hm5Qs?YFJzde_;yyk;Vh+el@DE-Rb8)x3 zcZ>822IfEpzGd&_WQ|5&bHRE!**JTm(Kp~x4+_Z~aiJ!Ir?&(r?!neK=z#{Xj=T?Z!{Pd`^1io@>`cXhT?`FL9o9%BC= zv+3S~rzj*Z$zGC_Q&5nW4|)8h2_9klACDM1JhY*Zmlc!LR#S6ep=X6(OZ<;t|80Pw zuyt^>flaV+wDRzDz>5CYPY)X_cdWgrql=x37|iZ_DQ^+prNCU*yY@lN@}K_&)yQHO literal 0 HcmV?d00001 diff --git a/docs/security.md b/docs/security.md new file mode 100644 index 0000000..495d8f2 --- /dev/null +++ b/docs/security.md @@ -0,0 +1,33 @@ +# Security + +## Reporting Vulnerabilities + +We’re extremely grateful for security researchers and users that report vulnerabilities to the Hasura Community. All reports are thoroughly investigated by a set of community volunteers and the Hasura team. + +To report a security issue, please email us at [security@hasura.io](mailto:security@hasura.io) with all the details, attaching all necessary information. + +### When Should I Report a Vulnerability? + +- You think you have discovered a potential security vulnerability in the Hasura GraphQL Engine or related components. +- You are unsure how a vulnerability affects the Hasura GraphQL Engine. +- You think you discovered a vulnerability in another project that Hasura GraphQL Engine depends on (e.g. Heroku, Docker, etc). +- You want to report any other security risk that could potentially harm Hasura GraphQL Engine users. + +### When Should I NOT Report a Vulnerability? + +- You need help tuning Hasura GraphQL Engine components for security. +- You need help applying security related updates. +- Your issue is not security related. + +## Security Vulnerability Response + +Each report is acknowledged and analyzed by the project's maintainers and the security team within 3 working days. + +The reporter will be kept updated at every stage of the issue's analysis and resolution (triage -> fix -> release). + +## Public Disclosure Timing + +A public disclosure date is negotiated by the Hasura product security team and the bug submitter. We prefer to fully disclose the bug as soon as possible once a user mitigation is available. It is reasonable to delay disclosure when the bug or the fix is not yet fully understood, the solution is not well-tested, or for vendor coordination. The timeframe for disclosure is from immediate (especially if it's already publicly known) to a few weeks. We expect the time-frame between a report to a public disclosure to typically be in the order of 7 days. The Hasura GraphQL Engine maintainers and the security team will take the final call on setting a disclosure date. + +(Some sections have been inspired and adapted from +[https://github.com/kubernetes/website/blob/master/content/en/docs/reference/issues-security/security.md](https://github.com/kubernetes/website/blob/master/content/en/docs/reference/issues-security/security.md). \ No newline at end of file diff --git a/docs/support.md b/docs/support.md new file mode 100644 index 0000000..a05dc0d --- /dev/null +++ b/docs/support.md @@ -0,0 +1,11 @@ +# Support & Troubleshooting + +The documentation and community will help you troubleshoot most issues. If you have encountered a bug or need to get in touch with us, you can contact us using one of the following channels: +* Support & feedback: [Discord](https://discord.gg/hasura) +* Issue & bug tracking: [GitHub issues](https://github.com/hasura/ndc-elasticsearch/issues) +* Follow product updates: [@HasuraHQ](https://twitter.com/hasurahq) +* Talk to us on our [website chat](https://hasura.io) + +We are committed to fostering an open and welcoming environment in the community. Please see the [Code of Conduct](code-of-conduct.md). + +If you want to report a security issue, please [read this](security.md). \ No newline at end of file diff --git a/resources/configuration.json b/resources/configuration.json new file mode 100644 index 0000000..81c28e3 --- /dev/null +++ b/resources/configuration.json @@ -0,0 +1,173 @@ +{ + ".ds-kibana_sample_data_logs-*": { + "mappings": { + "_data_stream_timestamp": { + "enabled": true + }, + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "bytes": { + "type": "long" + }, + "bytes_counter": { + "type": "long", + "time_series_metric": "counter" + }, + "bytes_gauge": { + "type": "long", + "time_series_metric": "gauge" + }, + "clientip": { + "type": "ip" + }, + "event": { + "properties": { + "dataset": { + "type": "keyword" + } + } + }, + "extension": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "geo": { + "properties": { + "coordinates": { + "type": "geo_point" + }, + "dest": { + "type": "keyword" + }, + "src": { + "type": "keyword" + }, + "srcdest": { + "type": "keyword" + } + } + }, + "host": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "index": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "ip": { + "type": "ip" + }, + "ip_range": { + "type": "ip_range" + }, + "machine": { + "properties": { + "os": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "ram": { + "type": "long" + } + } + }, + "memory": { + "type": "double" + }, + "message": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "phpmemory": { + "type": "long" + }, + "referer": { + "type": "keyword" + }, + "request": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "time_series_dimension": true + } + } + }, + "response": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "tags": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "timestamp": { + "type": "alias", + "path": "@timestamp" + }, + "timestamp_range": { + "type": "date_range" + }, + "url": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "utc_time": { + "type": "date" + } + } + } + } +} \ No newline at end of file diff --git a/resources/data/load_sample_data.py b/resources/data/load_sample_data.py new file mode 100644 index 0000000..332fe23 --- /dev/null +++ b/resources/data/load_sample_data.py @@ -0,0 +1,26 @@ +import requests +from requests.auth import HTTPBasicAuth + +def add_sample_data(kibana_url, username, password): + url = f"{kibana_url}/api/sample_data/logs" + headers = { + 'kbn-xsrf': 'true', + 'Content-Type': 'application/json' + } + + # Send the POST request + response = requests.post(url, headers=headers, auth=HTTPBasicAuth(username, password)) + + # Check the response status + if response.status_code == 200: + print("Sample data added successfully!") + else: + print(f"Failed to add sample data. Status code: {response.status_code}") + print(f"Response: {response.text}") + +# Example usage +kibana_url = "http://localhost:5601" +username = "elastic" +password = "default" + +add_sample_data(kibana_url, username, password) diff --git a/resources/metadata.json b/resources/metadata.json index 4d79ce2..c1ec582 100644 --- a/resources/metadata.json +++ b/resources/metadata.json @@ -1,2972 +1,2135 @@ { - "version": "v2", - "supergraph": { + "version": "v2", + "supergraph": { + "objects": [ + { + "kind": "GraphqlConfig", + "version": "v1", + "definition": { + "query": { + "rootOperationTypeName": "Query", + "argumentsInput": { + "fieldName": "args" + }, + "limitInput": { + "fieldName": "limit" + }, + "offsetInput": { + "fieldName": "offset" + }, + "filterInput": { + "fieldName": "where", + "operatorNames": { + "and": "_and", + "or": "_or", + "not": "_not", + "isNull": "_is_null" + } + }, + "orderByInput": { + "fieldName": "order_by", + "enumDirectionValues": { + "asc": "Asc", + "desc": "Desc" + }, + "enumTypeNames": [ + { + "directions": [ + "Asc", + "Desc" + ], + "typeName": "OrderBy" + } + ] + } + }, + "mutation": { + "rootOperationTypeName": "Mutation" + } + } + } + ] + }, + "subgraphs": [ + { + "name": "app", "objects": [ { - "kind": "GraphqlConfig", + "kind": "DataConnectorLink", "version": "v1", "definition": { - "query": { - "rootOperationTypeName": "Query", - "argumentsInput": { - "fieldName": "args" - }, - "limitInput": { - "fieldName": "limit" - }, - "offsetInput": { - "fieldName": "offset" - }, - "filterInput": { - "fieldName": "where", - "operatorNames": { - "and": "_and", - "or": "_or", - "not": "_not", - "isNull": "_is_null" - } - }, - "orderByInput": { - "fieldName": "order_by", - "enumDirectionValues": { - "asc": "Asc", - "desc": "Desc" - }, - "enumTypeNames": [ - { - "directions": [ - "Asc", - "Desc" - ], - "typeName": "OrderBy" - } - ] + "name": "elasticsearch", + "url": { + "singleUrl": { + "value": "http://ndc-elasticsearch:8080" } }, - "mutation": { - "rootOperationTypeName": "Mutation" - } - } - } - ] - }, - "subgraphs": [ - { - "name": "app", - "objects": [ - { - "kind": "DataConnectorLink", - "version": "v1", - "definition": { - "name": "elasticsearch", - "url": { - "singleUrl": { - "value": "http://ndc-elasticsearch:8080" - } - }, + "schema": { + "version": "v0.1", "schema": { - "version": "v0.1", - "schema": { - "scalar_types": { - "_id": { - "representation": { - "type": "string" - }, - "aggregate_functions": {}, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "_id" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { + "scalar_types": { + "_id": { + "representation": { + "type": "string" + }, + "aggregate_functions": {}, + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "_id" + } + }, + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "_id" + } + }, + "term": { + "type": "equal" + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", "name": "_id" } - }, - "term": { - "type": "equal" - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "_id" - } - } } } - }, - "boolean": { - "representation": { - "type": "boolean" + } + }, + "date": { + "representation": { + "type": "string" + }, + "aggregate_functions": { + "avg": { + "result_type": { + "type": "named", + "name": "long" + } }, - "aggregate_functions": { - "avg": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "cardinality": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "max": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "min": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "stats": { - "result_type": { - "type": "named", - "name": "stats" - } - }, - "sum": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "value_count": { - "result_type": { - "type": "named", - "name": "integer" - } + "cardinality": { + "result_type": { + "type": "named", + "name": "integer" } }, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "boolean" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "boolean" - } - }, - "term": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "boolean" - } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "boolean" - } - } + "max": { + "result_type": { + "type": "named", + "name": "long" + } + }, + "min": { + "result_type": { + "type": "named", + "name": "long" + } + }, + "stats": { + "result_type": { + "type": "named", + "name": "stats" + } + }, + "sum": { + "result_type": { + "type": "named", + "name": "long" + } + }, + "value_count": { + "result_type": { + "type": "named", + "name": "integer" } } }, - "date": { - "representation": { - "type": "string" + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "date" + } }, - "aggregate_functions": { - "avg": { - "result_type": { - "type": "named", - "name": "long" - } - }, - "cardinality": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "max": { - "result_type": { - "type": "named", - "name": "long" - } - }, - "min": { - "result_type": { - "type": "named", - "name": "long" - } - }, - "stats": { - "result_type": { - "type": "named", - "name": "stats" - } - }, - "sum": { - "result_type": { - "type": "named", - "name": "long" - } - }, - "value_count": { - "result_type": { - "type": "named", - "name": "integer" - } + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "date" } }, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "date" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "date" - } - }, - "term": { - "type": "custom", - "argument_type": { + "term": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "date" + } + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", "name": "date" } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "date" - } - } } } - }, - "double": { - "representation": { - "type": "number" + } + }, + "double": { + "representation": { + "type": "number" + }, + "aggregate_functions": { + "avg": { + "result_type": { + "type": "named", + "name": "double" + } }, - "aggregate_functions": { - "avg": { - "result_type": { - "type": "named", - "name": "double" - } - }, - "cardinality": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "max": { - "result_type": { - "type": "named", - "name": "double" - } - }, - "min": { - "result_type": { - "type": "named", - "name": "double" - } - }, - "stats": { - "result_type": { - "type": "named", - "name": "stats" - } - }, - "sum": { - "result_type": { - "type": "named", - "name": "double" - } - }, - "value_count": { - "result_type": { - "type": "named", - "name": "integer" - } + "cardinality": { + "result_type": { + "type": "named", + "name": "integer" } }, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "double" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "double" - } - }, - "term": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "double" - } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "double" - } - } + "max": { + "result_type": { + "type": "named", + "name": "double" + } + }, + "min": { + "result_type": { + "type": "named", + "name": "double" + } + }, + "stats": { + "result_type": { + "type": "named", + "name": "stats" + } + }, + "sum": { + "result_type": { + "type": "named", + "name": "double" + } + }, + "value_count": { + "result_type": { + "type": "named", + "name": "integer" } } }, - "float": { - "representation": { - "type": "number" + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "double" + } }, - "aggregate_functions": { - "avg": { - "result_type": { - "type": "named", - "name": "float" - } - }, - "cardinality": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "max": { - "result_type": { - "type": "named", - "name": "float" - } - }, - "min": { - "result_type": { - "type": "named", - "name": "float" - } - }, - "stats": { - "result_type": { - "type": "named", - "name": "stats" - } - }, - "sum": { - "result_type": { - "type": "named", - "name": "float" - } - }, - "value_count": { - "result_type": { - "type": "named", - "name": "integer" - } + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "double" } }, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "float" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "float" - } - }, - "term": { - "type": "custom", - "argument_type": { + "term": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "double" + } + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", - "name": "float" - } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "float" - } + "name": "double" } } } - }, - "half_float": { - "representation": { - "type": "number" + } + }, + "integer": { + "representation": { + "type": "integer" + }, + "aggregate_functions": { + "avg": { + "result_type": { + "type": "named", + "name": "integer" + } }, - "aggregate_functions": { - "avg": { - "result_type": { - "type": "named", - "name": "half_float" - } - }, - "cardinality": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "max": { - "result_type": { - "type": "named", - "name": "half_float" - } - }, - "min": { - "result_type": { - "type": "named", - "name": "half_float" - } - }, - "stats": { - "result_type": { - "type": "named", - "name": "stats" - } - }, - "sum": { - "result_type": { - "type": "named", - "name": "half_float" - } - }, - "value_count": { - "result_type": { - "type": "named", - "name": "integer" - } + "cardinality": { + "result_type": { + "type": "named", + "name": "integer" } }, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "half_float" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "half_float" - } - }, - "term": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "half_float" - } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "half_float" - } - } + "max": { + "result_type": { + "type": "named", + "name": "integer" + } + }, + "min": { + "result_type": { + "type": "named", + "name": "integer" + } + }, + "stats": { + "result_type": { + "type": "named", + "name": "stats" + } + }, + "sum": { + "result_type": { + "type": "named", + "name": "integer" + } + }, + "value_count": { + "result_type": { + "type": "named", + "name": "integer" } } }, - "integer": { - "representation": { - "type": "integer" + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "integer" + } }, - "aggregate_functions": { - "avg": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "cardinality": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "max": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "min": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "stats": { - "result_type": { - "type": "named", - "name": "stats" - } - }, - "sum": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "value_count": { - "result_type": { - "type": "named", - "name": "integer" - } + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "integer" } }, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "integer" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "integer" - } - }, - "term": { - "type": "custom", - "argument_type": { + "term": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "integer" + } + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", "name": "integer" } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "integer" - } - } + } + } + } + }, + "ip": { + "representation": { + "type": "string" + }, + "aggregate_functions": { + "cardinality": { + "result_type": { + "type": "named", + "name": "integer" + } + }, + "value_count": { + "result_type": { + "type": "named", + "name": "integer" } } }, - "keyword": { - "representation": { - "type": "string" + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "ip" + } }, - "aggregate_functions": { - "cardinality": { - "result_type": { - "type": "named", - "name": "integer" - } - }, - "string_stats": { - "result_type": { - "type": "named", - "name": "string_stats" - } - }, - "value_count": { - "result_type": { - "type": "named", - "name": "integer" - } + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "ip" } }, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { + "term": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "ip" + } + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", - "name": "keyword" - } - }, - "match_bool_prefix": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "keyword" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "keyword" - } - }, - "prefix": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "keyword" - } - }, - "regexp": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "keyword" - } - }, - "term": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "keyword" - } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "keyword" - } - } - }, - "wildcard": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "keyword" + "name": "ip" } } } + } + }, + "keyword": { + "representation": { + "type": "string" + }, + "aggregate_functions": { + "cardinality": { + "result_type": { + "type": "named", + "name": "integer" + } + }, + "string_stats": { + "result_type": { + "type": "named", + "name": "string_stats" + } + }, + "value_count": { + "result_type": { + "type": "named", + "name": "integer" + } + } }, - "text": { - "representation": { - "type": "string" - }, - "aggregate_functions": {}, - "comparison_operators": { - "match": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "text" - } - }, - "match_bool_prefix": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "text" - } - }, - "match_phrase": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "text" - } - }, - "match_phrase_prefix": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "text" - } - }, - "prefix": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "text" - } - }, - "regexp": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "text" - } - }, - "term": { - "type": "custom", - "argument_type": { - "type": "named", - "name": "text" - } - }, - "terms": { - "type": "custom", - "argument_type": { - "type": "array", - "element_type": { - "type": "named", - "name": "text" - } - } - }, - "wildcard": { - "type": "custom", - "argument_type": { + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "keyword" + } + }, + "match_bool_prefix": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "keyword" + } + }, + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "keyword" + } + }, + "prefix": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "keyword" + } + }, + "regexp": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "keyword" + } + }, + "term": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "keyword" + } + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", - "name": "text" + "name": "keyword" } } + }, + "wildcard": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "keyword" + } } } }, - "object_types": { - "alias": { - "fields": {} - }, - "date_range": { - "fields": {} - }, - "dense_vector": { - "fields": {} - }, - "double_range": { - "fields": {} - }, - "event": { - "fields": {} - }, - "float_range": { - "fields": {} - }, - "geo_point": { - "fields": {} - }, - "geo_shape": { - "fields": {} - }, - "geoip": { - "fields": {} - }, - "histogram": { - "fields": { - "counts": { - "type": { - "type": "named", - "name": "integer" - } - }, - "values": { - "type": { - "type": "named", - "name": "float" - } + "long": { + "representation": { + "type": "integer" + }, + "aggregate_functions": { + "avg": { + "result_type": { + "type": "named", + "name": "long" + } + }, + "cardinality": { + "result_type": { + "type": "named", + "name": "integer" + } + }, + "max": { + "result_type": { + "type": "named", + "name": "long" + } + }, + "min": { + "result_type": { + "type": "named", + "name": "long" + } + }, + "stats": { + "result_type": { + "type": "named", + "name": "stats" + } + }, + "sum": { + "result_type": { + "type": "named", + "name": "long" + } + }, + "value_count": { + "result_type": { + "type": "named", + "name": "integer" } } }, - "integer_range": { - "fields": {} - }, - "ip_range": { - "fields": {} - }, - "join": { - "fields": {} - }, - "kibana_sample_data_ecommerce": { - "fields": { - "_id": { - "type": { - "type": "named", - "name": "_id" - } - }, - "category": { - "type": { - "type": "named", - "name": "text" - } - }, - "currency": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "customer_birth_date": { - "type": { - "type": "named", - "name": "date" - } - }, - "customer_first_name": { - "type": { - "type": "named", - "name": "text" - } - }, - "customer_full_name": { - "type": { - "type": "named", - "name": "text" - } - }, - "customer_gender": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "customer_id": { - "type": { + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "long" + } + }, + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "long" + } + }, + "term": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "long" + } + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", - "name": "keyword" + "name": "long" } - }, - "customer_last_name": { - "type": { + } + } + } + }, + "text": { + "representation": { + "type": "string" + }, + "aggregate_functions": {}, + "comparison_operators": { + "match": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + }, + "match_bool_prefix": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + }, + "match_phrase": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + }, + "match_phrase_prefix": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + }, + "prefix": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + }, + "regexp": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + }, + "term": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + }, + "terms": { + "type": "custom", + "argument_type": { + "type": "array", + "element_type": { "type": "named", "name": "text" } - }, - "customer_phone": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "day_of_week": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "day_of_week_i": { - "type": { - "type": "named", - "name": "integer" - } - }, - "email": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "event": { - "type": { + } + }, + "wildcard": { + "type": "custom", + "argument_type": { + "type": "named", + "name": "text" + } + } + } + } + }, + "object_types": { + ".ds-kibana_sample_data_logs-*": { + "fields": { + "@timestamp": { + "type": { + "type": "named", + "name": "date" + } + }, + "_id": { + "type": { + "type": "named", + "name": "_id" + } + }, + "agent": { + "type": { + "type": "named", + "name": "text" + } + }, + "bytes": { + "type": { + "type": "named", + "name": "long" + } + }, + "bytes_counter": { + "type": { + "type": "named", + "name": "long" + } + }, + "bytes_gauge": { + "type": { + "type": "named", + "name": "long" + } + }, + "clientip": { + "type": { + "type": "named", + "name": "ip" + } + }, + "event": { + "type": { + "type": "array", + "element_type": { "type": "named", "name": "event" } - }, - "geoip": { - "type": { - "type": "named", - "name": "geoip" - } - }, - "manufacturer": { - "type": { - "type": "named", - "name": "text" - } - }, - "order_date": { - "type": { - "type": "named", - "name": "date" - } - }, - "order_id": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "products": { - "type": { - "type": "named", - "name": "products" - } - }, - "sku": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "taxful_total_price": { - "type": { - "type": "named", - "name": "half_float" - } - }, - "taxless_total_price": { - "type": { - "type": "named", - "name": "half_float" - } - }, - "total_quantity": { - "type": { - "type": "named", - "name": "integer" - } - }, - "total_unique_products": { - "type": { - "type": "named", - "name": "integer" - } - }, + } + }, + "extension": { "type": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "user": { - "type": { - "type": "named", - "name": "keyword" - } + "type": "named", + "name": "text" } - } - }, - "kibana_sample_data_flights": { - "fields": { - "AvgTicketPrice": { - "type": { - "type": "named", - "name": "float" - } - }, - "Cancelled": { - "type": { - "type": "named", - "name": "boolean" - } - }, - "Carrier": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "Dest": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "DestAirportID": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "DestCityName": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "DestCountry": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "DestLocation": { - "type": { + }, + "geo": { + "type": { + "type": "array", + "element_type": { "type": "named", - "name": "geo_point" + "name": "geo" } - }, - "DestRegion": { - "type": { + } + }, + "host": { + "type": { + "type": "named", + "name": "text" + } + }, + "index": { + "type": { + "type": "named", + "name": "text" + } + }, + "ip": { + "type": { + "type": "named", + "name": "ip" + } + }, + "ip_range": { + "type": { + "type": "named", + "name": "ip_range" + } + }, + "machine": { + "type": { + "type": "array", + "element_type": { "type": "named", - "name": "keyword" - } - }, - "DestWeather": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "DistanceKilometers": { - "type": { - "type": "named", - "name": "float" - } - }, - "DistanceMiles": { - "type": { - "type": "named", - "name": "float" - } - }, - "FlightDelay": { - "type": { - "type": "named", - "name": "boolean" - } - }, - "FlightDelayMin": { - "type": { - "type": "named", - "name": "integer" - } - }, - "FlightDelayType": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "FlightNum": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "FlightTimeHour": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "FlightTimeMin": { - "type": { - "type": "named", - "name": "float" - } - }, - "Origin": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "OriginAirportID": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "OriginCityName": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "OriginCountry": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "OriginLocation": { - "type": { - "type": "named", - "name": "geo_point" - } - }, - "OriginRegion": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "OriginWeather": { - "type": { - "type": "named", - "name": "keyword" - } - }, - "_id": { - "type": { - "type": "named", - "name": "_id" - } - }, - "dayOfWeek": { - "type": { - "type": "named", - "name": "integer" - } - }, - "timestamp": { - "type": { - "type": "named", - "name": "date" + "name": "machine" } } + }, + "memory": { + "type": { + "type": "named", + "name": "double" + } + }, + "message": { + "type": { + "type": "named", + "name": "text" + } + }, + "phpmemory": { + "type": { + "type": "named", + "name": "long" + } + }, + "referer": { + "type": { + "type": "named", + "name": "keyword" + } + }, + "request": { + "type": { + "type": "named", + "name": "text" + } + }, + "response": { + "type": { + "type": "named", + "name": "text" + } + }, + "tags": { + "type": { + "type": "named", + "name": "text" + } + }, + "timestamp": { + "type": { + "type": "named", + "name": "alias" + } + }, + "timestamp_range": { + "type": { + "type": "named", + "name": "date_range" + } + }, + "url": { + "type": { + "type": "named", + "name": "text" + } + }, + "utc_time": { + "type": { + "type": "named", + "name": "date" + } } - }, - "long_range": { - "fields": {} - }, - "percolator": { - "fields": {} - }, - "point": { - "fields": {} - }, - "products": { - "fields": {} - }, - "rank_feature": { - "fields": {} - }, - "rank_features": { - "fields": {} - }, - "shape": { - "fields": {} - }, - "sparse_vector": { - "fields": {} - }, - "stats": { - "fields": { - "avg": { - "type": { - "type": "named", - "name": "double" - } - }, - "count": { - "type": { - "type": "named", - "name": "integer" - } - }, - "max": { - "type": { - "type": "named", - "name": "double" - } - }, - "min": { - "type": { - "type": "named", - "name": "double" - } - }, - "sum": { - "type": { - "type": "named", - "name": "double" - } + } + }, + "alias": { + "fields": {} + }, + "date_range": { + "fields": {} + }, + "dense_vector": { + "fields": {} + }, + "double_range": { + "fields": {} + }, + "event": { + "fields": { + "dataset": { + "type": { + "type": "named", + "name": "keyword" } } - }, - "string_stats": { - "fields": { - "avg_length": { - "type": { - "type": "named", - "name": "double" - } - }, - "count": { - "type": { - "type": "named", - "name": "integer" - } - }, - "entropy": { - "type": { - "type": "named", - "name": "double" - } - }, - "max_length": { - "type": { - "type": "named", - "name": "integer" - } - }, - "min_length": { - "type": { - "type": "named", - "name": "integer" - } + } + }, + "float_range": { + "fields": {} + }, + "geo": { + "fields": { + "coordinates": { + "type": { + "type": "named", + "name": "geo_point" + } + }, + "dest": { + "type": { + "type": "named", + "name": "keyword" + } + }, + "src": { + "type": { + "type": "named", + "name": "keyword" + } + }, + "srcdest": { + "type": { + "type": "named", + "name": "keyword" } } } }, - "collections": [ - { - "name": "kibana_sample_data_ecommerce", - "arguments": {}, - "type": "kibana_sample_data_ecommerce", - "uniqueness_constraints": { - "kibana_sample_data_ecommerce_by_id": { - "unique_columns": [ - "_id" - ] - } - }, - "foreign_keys": {} - }, - { - "name": "kibana_sample_data_flights", - "arguments": {}, - "type": "kibana_sample_data_flights", - "uniqueness_constraints": { - "kibana_sample_data_flights_by_id": { - "unique_columns": [ - "_id" - ] - } - }, - "foreign_keys": {} + "geo_point": { + "fields": {} + }, + "geo_shape": { + "fields": {} + }, + "histogram": { + "fields": { + "counts": { + "type": { + "type": "named", + "name": "integer" + } + }, + "values": { + "type": { + "type": "named", + "name": "double" + } + } } - ], - "functions": [], - "procedures": [] + }, + "integer_range": { + "fields": {} + }, + "ip_range": { + "fields": {} + }, + "join": { + "fields": {} + }, + "long_range": { + "fields": {} + }, + "machine": { + "fields": { + "os": { + "type": { + "type": "named", + "name": "text" + } + }, + "ram": { + "type": { + "type": "named", + "name": "long" + } + } + } + }, + "percolator": { + "fields": {} + }, + "point": { + "fields": {} + }, + "rank_feature": { + "fields": {} + }, + "rank_features": { + "fields": {} + }, + "shape": { + "fields": {} + }, + "sparse_vector": { + "fields": {} + }, + "stats": { + "fields": { + "avg": { + "type": { + "type": "named", + "name": "double" + } + }, + "count": { + "type": { + "type": "named", + "name": "integer" + } + }, + "max": { + "type": { + "type": "named", + "name": "double" + } + }, + "min": { + "type": { + "type": "named", + "name": "double" + } + }, + "sum": { + "type": { + "type": "named", + "name": "double" + } + } + } + }, + "string_stats": { + "fields": { + "avg_length": { + "type": { + "type": "named", + "name": "double" + } + }, + "count": { + "type": { + "type": "named", + "name": "integer" + } + }, + "entropy": { + "type": { + "type": "named", + "name": "double" + } + }, + "max_length": { + "type": { + "type": "named", + "name": "integer" + } + }, + "min_length": { + "type": { + "type": "named", + "name": "integer" + } + } + } + } }, - "capabilities": { - "version": "0.1.2", - "capabilities": { - "query": { - "aggregates": {}, - "variables": {} + "collections": [ + { + "name": ".ds-kibana_sample_data_logs-*", + "arguments": {}, + "type": ".ds-kibana_sample_data_logs-*", + "uniqueness_constraints": { + ".ds-kibana_sample_data_logs-*_by_id": { + "unique_columns": [ + "_id" + ] + } }, - "mutation": {} + "foreign_keys": {} } + ], + "functions": [], + "procedures": [] + }, + "capabilities": { + "version": "0.1.3", + "capabilities": { + "query": { + "aggregates": {}, + "variables": {} + }, + "mutation": {} } } } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_IdComparisonExp" + } + }, + { + "kind": "DataConnectorScalarRepresentation", + "version": "v1", + "definition": { + "graphql": { + "comparisonExpressionTypeName": "App_DateComparisonExp" + }, + "dataConnectorName": "elasticsearch", + "dataConnectorScalarType": "date", + "representation": "Date" + } + }, + { + "kind": "DataConnectorScalarRepresentation", + "version": "v1", + "definition": { + "graphql": { + "comparisonExpressionTypeName": "App_IdComparisonExp" + }, + "dataConnectorName": "elasticsearch", + "dataConnectorScalarType": "_id", + "representation": "Id" + } + }, + { + "kind": "DataConnectorScalarRepresentation", + "version": "v1", + "definition": { + "graphql": { + "comparisonExpressionTypeName": "App_TextComparisonExp" + }, + "dataConnectorName": "elasticsearch", + "dataConnectorScalarType": "text", + "representation": "Text" + } + }, + { + "kind": "DataConnectorScalarRepresentation", + "version": "v1", + "definition": { + "graphql": { + "comparisonExpressionTypeName": "App_LongComparisonExp" + }, + "dataConnectorName": "elasticsearch", + "dataConnectorScalarType": "long", + "representation": "Long" + } + }, + { + "kind": "DataConnectorScalarRepresentation", + "version": "v1", + "definition": { + "graphql": { + "comparisonExpressionTypeName": "App_IpComparisonExp" + }, + "dataConnectorName": "elasticsearch", + "dataConnectorScalarType": "ip", + "representation": "Ip" + } + }, + { + "kind": "DataConnectorScalarRepresentation", + "version": "v1", + "definition": { + "graphql": { + "comparisonExpressionTypeName": "App_KeywordComparisonExp" + }, + "dataConnectorName": "elasticsearch", + "dataConnectorScalarType": "keyword", + "representation": "Keyword" + } + }, + { + "kind": "DataConnectorScalarRepresentation", + "version": "v1", + "definition": { + "graphql": { + "comparisonExpressionTypeName": "App_DoubleComparisonExp" + }, + "dataConnectorName": "elasticsearch", + "dataConnectorScalarType": "double", + "representation": "Double" + } + }, + { + "kind": "Model", + "version": "v1", + "definition": { + "name": "DsKibanaSampleDataLogs", + "graphql": { + "selectUniques": [ + { + "queryRootField": "app_dsKibanaSampleDataLogsById", + "uniqueIdentifier": [ + "id" + ] + } + ], + "selectMany": { + "queryRootField": "app_dsKibanaSampleDataLogs" }, + "orderByExpressionType": "App_DsKibanaSampleDataLogsOrderBy" + }, + "objectType": "DsKibanaSampleDataLogs", + "source": { "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "_id", - "representation": "Id" - } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_TextComparisonExp" + "collection": ".ds-kibana_sample_data_logs-*" + }, + "filterExpressionType": "DsKibanaSampleDataLogsBoolExp", + "orderableFields": [ + { + "fieldName": "timestamp", + "orderByDirections": { + "enableAll": true + } }, - "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "text", - "representation": "Text" - } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_KeywordComparisonExp" + { + "fieldName": "id", + "orderByDirections": { + "enableAll": true + } }, - "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "keyword", - "representation": "Keyword" - } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_DateComparisonExp" + { + "fieldName": "agent", + "orderByDirections": { + "enableAll": true + } }, - "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "date", - "representation": "Date" - } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_IntegerComparisonExp" + { + "fieldName": "bytes", + "orderByDirections": { + "enableAll": true + } }, - "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "integer", - "representation": "Integer" - } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_HalfFloatComparisonExp" + { + "fieldName": "bytesCounter", + "orderByDirections": { + "enableAll": true + } }, - "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "half_float", - "representation": "HalfFloat" - } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_Float1ComparisonExp" + { + "fieldName": "bytesGauge", + "orderByDirections": { + "enableAll": true + } }, - "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "float", - "representation": "Float_1" - } - }, - { - "kind": "DataConnectorScalarRepresentation", - "version": "v1", - "definition": { - "graphql": { - "comparisonExpressionTypeName": "App_Boolean1ComparisonExp" + { + "fieldName": "clientip", + "orderByDirections": { + "enableAll": true + } }, - "dataConnectorName": "elasticsearch", - "dataConnectorScalarType": "boolean", - "representation": "Boolean_1" - } - }, - { - "kind": "Model", - "version": "v1", - "definition": { - "name": "KibanaSampleDataEcommerce", - "graphql": { - "selectUniques": [ - { - "queryRootField": "app_kibanaSampleDataEcommerceById", - "uniqueIdentifier": [ - "id" - ] - } - ], - "selectMany": { - "queryRootField": "app_kibanaSampleDataEcommerce" - }, - "orderByExpressionType": "App_KibanaSampleDataEcommerceOrderBy" + { + "fieldName": "event", + "orderByDirections": { + "enableAll": true + } }, - "objectType": "KibanaSampleDataEcommerce", - "source": { - "dataConnectorName": "elasticsearch", - "collection": "kibana_sample_data_ecommerce" + { + "fieldName": "extension", + "orderByDirections": { + "enableAll": true + } }, - "filterExpressionType": "KibanaSampleDataEcommerceBoolExp", - "orderableFields": [ - { - "fieldName": "id", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "category", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "currency", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "customerBirthDate", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "customerFirstName", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "customerFullName", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "customerGender", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "customerId", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "customerLastName", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "customerPhone", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "dayOfWeek", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "dayOfWeekI", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "email", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "event", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "geoip", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "manufacturer", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "orderDate", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "orderId", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "products", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "sku", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "taxfulTotalPrice", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "taxlessTotalPrice", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "totalQuantity", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "totalUniqueProducts", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "type", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "user", - "orderByDirections": { - "enableAll": true - } + { + "fieldName": "geo", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "Model", - "version": "v1", - "definition": { - "name": "KibanaSampleDataFlights", - "graphql": { - "selectUniques": [ - { - "queryRootField": "app_kibanaSampleDataFlightsById", - "uniqueIdentifier": [ - "id" - ] - } - ], - "selectMany": { - "queryRootField": "app_kibanaSampleDataFlights" - }, - "orderByExpressionType": "App_KibanaSampleDataFlightsOrderBy" }, - "objectType": "KibanaSampleDataFlights", - "source": { - "dataConnectorName": "elasticsearch", - "collection": "kibana_sample_data_flights" + { + "fieldName": "host", + "orderByDirections": { + "enableAll": true + } }, - "filterExpressionType": "KibanaSampleDataFlightsBoolExp", - "orderableFields": [ - { - "fieldName": "id", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "avgTicketPrice", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "cancelled", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "carrier", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "dest", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "destAirportId", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "destCityName", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "destCountry", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "destLocation", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "destRegion", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "destWeather", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "distanceKilometers", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "distanceMiles", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "flightDelay", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "flightDelayMin", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "flightDelayType", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "flightNum", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "flightTimeHour", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "flightTimeMin", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "origin", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "originAirportId", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "originCityName", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "originCountry", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "originLocation", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "originRegion", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "originWeather", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "dayOfWeek", - "orderByDirections": { - "enableAll": true - } - }, - { - "fieldName": "timestamp", - "orderByDirections": { - "enableAll": true - } + { + "fieldName": "index", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ModelPermissions", - "version": "v1", - "definition": { - "permissions": [ - { - "role": "admin", - "select": { - "filter": null - } + }, + { + "fieldName": "ip", + "orderByDirections": { + "enableAll": true } - ], - "modelName": "KibanaSampleDataEcommerce" - } - }, - { - "kind": "ModelPermissions", - "version": "v1", - "definition": { - "permissions": [ - { - "role": "admin", - "select": { - "filter": null - } + }, + { + "fieldName": "ipRange", + "orderByDirections": { + "enableAll": true } - ], - "modelName": "KibanaSampleDataFlights" - } - }, - { - "kind": "ObjectBooleanExpressionType", - "version": "v1", - "definition": { - "name": "KibanaSampleDataEcommerceBoolExp", - "graphql": { - "typeName": "App_KibanaSampleDataEcommerceBoolExp" - }, - "objectType": "KibanaSampleDataEcommerce", - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "kibana_sample_data_ecommerce", - "comparableFields": [ - { - "fieldName": "id", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "category", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "currency", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "customerBirthDate", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "customerFirstName", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "customerFullName", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "customerGender", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "customerId", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "customerLastName", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "customerPhone", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "dayOfWeek", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "dayOfWeekI", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "email", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "event", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "geoip", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "manufacturer", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "orderDate", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "orderId", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "products", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "sku", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "taxfulTotalPrice", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "taxlessTotalPrice", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "totalQuantity", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "totalUniqueProducts", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "type", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "user", - "operators": { - "enableAll": true - } + }, + { + "fieldName": "machine", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ObjectBooleanExpressionType", - "version": "v1", - "definition": { - "name": "KibanaSampleDataFlightsBoolExp", - "graphql": { - "typeName": "App_KibanaSampleDataFlightsBoolExp" - }, - "objectType": "KibanaSampleDataFlights", - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "kibana_sample_data_flights", - "comparableFields": [ - { - "fieldName": "id", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "avgTicketPrice", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "cancelled", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "carrier", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "dest", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "destAirportId", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "destCityName", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "destCountry", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "destLocation", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "destRegion", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "destWeather", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "distanceKilometers", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "distanceMiles", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "flightDelay", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "flightDelayMin", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "flightDelayType", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "flightNum", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "flightTimeHour", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "flightTimeMin", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "origin", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "originAirportId", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "originCityName", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "originCountry", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "originLocation", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "originRegion", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "originWeather", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "dayOfWeek", - "operators": { - "enableAll": true - } - }, - { - "fieldName": "timestamp", - "operators": { - "enableAll": true - } + }, + { + "fieldName": "memory", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ObjectType", - "version": "v1", - "definition": { - "name": "Event", - "fields": [], - "graphql": { - "typeName": "App_Event", - "inputTypeName": "App_EventInput" - }, - "dataConnectorTypeMapping": [ - { - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "event" + }, + { + "fieldName": "message", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ObjectType", - "version": "v1", - "definition": { - "name": "Geoip", - "fields": [], - "graphql": { - "typeName": "App_Geoip", - "inputTypeName": "App_GeoipInput" - }, - "dataConnectorTypeMapping": [ - { - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "geoip" + }, + { + "fieldName": "phpmemory", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ObjectType", - "version": "v1", - "definition": { - "name": "Products", - "fields": [], - "graphql": { - "typeName": "App_Products", - "inputTypeName": "App_ProductsInput" - }, - "dataConnectorTypeMapping": [ - { - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "products" + }, + { + "fieldName": "referer", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ObjectType", - "version": "v1", - "definition": { - "name": "KibanaSampleDataEcommerce", - "fields": [ - { - "name": "id", - "type": "Id!" - }, - { - "name": "category", - "type": "Text!" - }, - { - "name": "currency", - "type": "Keyword!" - }, - { - "name": "customerBirthDate", - "type": "Date!" - }, - { - "name": "customerFirstName", - "type": "Text!" - }, - { - "name": "customerFullName", - "type": "Text!" - }, - { - "name": "customerGender", - "type": "Keyword!" - }, - { - "name": "customerId", - "type": "Keyword!" - }, - { - "name": "customerLastName", - "type": "Text!" - }, - { - "name": "customerPhone", - "type": "Keyword!" - }, - { - "name": "dayOfWeek", - "type": "Keyword!" - }, - { - "name": "dayOfWeekI", - "type": "Integer!" - }, - { - "name": "email", - "type": "Keyword!" - }, - { - "name": "event", - "type": "Event!" - }, - { - "name": "geoip", - "type": "Geoip!" - }, - { - "name": "manufacturer", - "type": "Text!" - }, - { - "name": "orderDate", - "type": "Date!" - }, - { - "name": "orderId", - "type": "Keyword!" - }, - { - "name": "products", - "type": "Products!" - }, - { - "name": "sku", - "type": "Keyword!" - }, - { - "name": "taxfulTotalPrice", - "type": "HalfFloat!" - }, - { - "name": "taxlessTotalPrice", - "type": "HalfFloat!" - }, - { - "name": "totalQuantity", - "type": "Integer!" - }, - { - "name": "totalUniqueProducts", - "type": "Integer!" - }, - { - "name": "type", - "type": "Keyword!" - }, - { - "name": "user", - "type": "Keyword!" + }, + { + "fieldName": "request", + "orderByDirections": { + "enableAll": true } - ], - "graphql": { - "typeName": "App_KibanaSampleDataEcommerce", - "inputTypeName": "App_KibanaSampleDataEcommerceInput" }, - "dataConnectorTypeMapping": [ - { - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "kibana_sample_data_ecommerce", - "fieldMapping": { - "category": { - "column": { - "name": "category" - } - }, - "currency": { - "column": { - "name": "currency" - } - }, - "customerBirthDate": { - "column": { - "name": "customer_birth_date" - } - }, - "customerFirstName": { - "column": { - "name": "customer_first_name" - } - }, - "customerFullName": { - "column": { - "name": "customer_full_name" - } - }, - "customerGender": { - "column": { - "name": "customer_gender" - } - }, - "customerId": { - "column": { - "name": "customer_id" - } - }, - "customerLastName": { - "column": { - "name": "customer_last_name" - } - }, - "customerPhone": { - "column": { - "name": "customer_phone" - } - }, - "dayOfWeek": { - "column": { - "name": "day_of_week" - } - }, - "dayOfWeekI": { - "column": { - "name": "day_of_week_i" - } - }, - "email": { - "column": { - "name": "email" - } - }, - "event": { - "column": { - "name": "event" - } - }, - "geoip": { - "column": { - "name": "geoip" - } - }, - "id": { - "column": { - "name": "_id" - } - }, - "manufacturer": { - "column": { - "name": "manufacturer" - } - }, - "orderDate": { - "column": { - "name": "order_date" - } - }, - "orderId": { - "column": { - "name": "order_id" - } - }, - "products": { - "column": { - "name": "products" - } - }, - "sku": { - "column": { - "name": "sku" - } - }, - "taxfulTotalPrice": { - "column": { - "name": "taxful_total_price" - } - }, - "taxlessTotalPrice": { - "column": { - "name": "taxless_total_price" - } - }, - "totalQuantity": { - "column": { - "name": "total_quantity" - } - }, - "totalUniqueProducts": { - "column": { - "name": "total_unique_products" - } - }, - "type": { - "column": { - "name": "type" - } - }, - "user": { - "column": { - "name": "user" - } - } - } + { + "fieldName": "response", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ObjectType", - "version": "v1", - "definition": { - "name": "GeoPoint", - "fields": [], - "graphql": { - "typeName": "App_GeoPoint", - "inputTypeName": "App_GeoPointInput" - }, - "dataConnectorTypeMapping": [ - { - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "geo_point" + }, + { + "fieldName": "tags", + "orderByDirections": { + "enableAll": true } - ] - } - }, - { - "kind": "ObjectType", - "version": "v1", - "definition": { - "name": "KibanaSampleDataFlights", - "fields": [ - { - "name": "id", - "type": "Id!" - }, - { - "name": "avgTicketPrice", - "type": "Float_1!" - }, - { - "name": "cancelled", - "type": "Boolean_1!" - }, - { - "name": "carrier", - "type": "Keyword!" - }, - { - "name": "dest", - "type": "Keyword!" - }, - { - "name": "destAirportId", - "type": "Keyword!" - }, - { - "name": "destCityName", - "type": "Keyword!" - }, - { - "name": "destCountry", - "type": "Keyword!" - }, - { - "name": "destLocation", - "type": "GeoPoint!" - }, - { - "name": "destRegion", - "type": "Keyword!" - }, - { - "name": "destWeather", - "type": "Keyword!" - }, - { - "name": "distanceKilometers", - "type": "Float_1!" - }, - { - "name": "distanceMiles", - "type": "Float_1!" - }, - { - "name": "flightDelay", - "type": "Boolean_1!" - }, - { - "name": "flightDelayMin", - "type": "Integer!" - }, - { - "name": "flightDelayType", - "type": "Keyword!" - }, - { - "name": "flightNum", - "type": "Keyword!" - }, - { - "name": "flightTimeHour", - "type": "Keyword!" - }, - { - "name": "flightTimeMin", - "type": "Float_1!" - }, - { - "name": "origin", - "type": "Keyword!" - }, - { - "name": "originAirportId", - "type": "Keyword!" - }, - { - "name": "originCityName", - "type": "Keyword!" - }, - { - "name": "originCountry", - "type": "Keyword!" - }, - { - "name": "originLocation", - "type": "GeoPoint!" - }, - { - "name": "originRegion", - "type": "Keyword!" - }, - { - "name": "originWeather", - "type": "Keyword!" - }, - { - "name": "dayOfWeek", - "type": "Integer!" - }, - { - "name": "timestamp", - "type": "Date!" + }, + { + "fieldName": "timestamp_1", + "orderByDirections": { + "enableAll": true } - ], - "graphql": { - "typeName": "App_KibanaSampleDataFlights", - "inputTypeName": "App_KibanaSampleDataFlightsInput" }, - "dataConnectorTypeMapping": [ - { - "dataConnectorName": "elasticsearch", - "dataConnectorObjectType": "kibana_sample_data_flights", - "fieldMapping": { - "avgTicketPrice": { - "column": { - "name": "AvgTicketPrice" - } - }, - "cancelled": { - "column": { - "name": "Cancelled" - } - }, - "carrier": { - "column": { - "name": "Carrier" - } - }, - "dayOfWeek": { - "column": { - "name": "dayOfWeek" - } - }, - "dest": { - "column": { - "name": "Dest" - } - }, - "destAirportId": { - "column": { - "name": "DestAirportID" - } - }, - "destCityName": { - "column": { - "name": "DestCityName" - } - }, - "destCountry": { - "column": { - "name": "DestCountry" - } - }, - "destLocation": { - "column": { - "name": "DestLocation" - } - }, - "destRegion": { - "column": { - "name": "DestRegion" - } - }, - "destWeather": { - "column": { - "name": "DestWeather" - } - }, - "distanceKilometers": { - "column": { - "name": "DistanceKilometers" - } - }, - "distanceMiles": { - "column": { - "name": "DistanceMiles" - } - }, - "flightDelay": { - "column": { - "name": "FlightDelay" - } - }, - "flightDelayMin": { - "column": { - "name": "FlightDelayMin" - } - }, - "flightDelayType": { - "column": { - "name": "FlightDelayType" - } - }, - "flightNum": { - "column": { - "name": "FlightNum" - } - }, - "flightTimeHour": { - "column": { - "name": "FlightTimeHour" - } - }, - "flightTimeMin": { - "column": { - "name": "FlightTimeMin" - } - }, - "id": { - "column": { - "name": "_id" - } - }, - "origin": { - "column": { - "name": "Origin" - } - }, - "originAirportId": { - "column": { - "name": "OriginAirportID" - } - }, - "originCityName": { - "column": { - "name": "OriginCityName" - } - }, - "originCountry": { - "column": { - "name": "OriginCountry" - } - }, - "originLocation": { - "column": { - "name": "OriginLocation" - } - }, - "originRegion": { - "column": { - "name": "OriginRegion" - } - }, - "originWeather": { - "column": { - "name": "OriginWeather" - } - }, - "timestamp": { - "column": { - "name": "timestamp" - } + { + "fieldName": "timestampRange", + "orderByDirections": { + "enableAll": true + } + }, + { + "fieldName": "url", + "orderByDirections": { + "enableAll": true + } + }, + { + "fieldName": "utcTime", + "orderByDirections": { + "enableAll": true + } + } + ] + } + }, + { + "kind": "ModelPermissions", + "version": "v1", + "definition": { + "permissions": [ + { + "role": "admin", + "select": { + "filter": null + } + } + ], + "modelName": "DsKibanaSampleDataLogs" + } + }, + { + "kind": "ObjectBooleanExpressionType", + "version": "v1", + "definition": { + "name": "DsKibanaSampleDataLogsBoolExp", + "graphql": { + "typeName": "App_DsKibanaSampleDataLogsBoolExp" + }, + "objectType": "DsKibanaSampleDataLogs", + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": ".ds-kibana_sample_data_logs-*", + "comparableFields": [ + { + "fieldName": "timestamp", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "id", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "agent", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "bytes", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "bytesCounter", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "bytesGauge", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "clientip", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "event", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "extension", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "geo", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "host", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "index", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "ip", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "ipRange", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "machine", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "memory", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "message", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "phpmemory", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "referer", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "request", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "response", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "tags", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "timestamp_1", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "timestampRange", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "url", + "operators": { + "enableAll": true + } + }, + { + "fieldName": "utcTime", + "operators": { + "enableAll": true + } + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "Event", + "fields": [ + { + "name": "dataset", + "type": "Keyword!" + } + ], + "graphql": { + "typeName": "App_Event", + "inputTypeName": "App_EventInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": "event" + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "GeoPoint", + "fields": [], + "graphql": { + "typeName": "App_GeoPoint", + "inputTypeName": "App_GeoPointInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": "geo_point" + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "Geo", + "fields": [ + { + "name": "coordinates", + "type": "GeoPoint!" + }, + { + "name": "dest", + "type": "Keyword!" + }, + { + "name": "src", + "type": "Keyword!" + }, + { + "name": "srcdest", + "type": "Keyword!" + } + ], + "graphql": { + "typeName": "App_Geo", + "inputTypeName": "App_GeoInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": "geo" + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "IpRange", + "fields": [], + "graphql": { + "typeName": "App_IpRange", + "inputTypeName": "App_IpRangeInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": "ip_range" + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "Machine", + "fields": [ + { + "name": "os", + "type": "Text!" + }, + { + "name": "ram", + "type": "Long!" + } + ], + "graphql": { + "typeName": "App_Machine", + "inputTypeName": "App_MachineInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": "machine" + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "Alias", + "fields": [], + "graphql": { + "typeName": "App_Alias", + "inputTypeName": "App_AliasInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": "alias" + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "DateRange", + "fields": [], + "graphql": { + "typeName": "App_DateRange", + "inputTypeName": "App_DateRangeInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": "date_range" + } + ] + } + }, + { + "kind": "ObjectType", + "version": "v1", + "definition": { + "name": "DsKibanaSampleDataLogs", + "fields": [ + { + "name": "timestamp", + "type": "Date!" + }, + { + "name": "id", + "type": "Id!" + }, + { + "name": "agent", + "type": "Text!" + }, + { + "name": "bytes", + "type": "Long!" + }, + { + "name": "bytesCounter", + "type": "Long!" + }, + { + "name": "bytesGauge", + "type": "Long!" + }, + { + "name": "clientip", + "type": "Ip!" + }, + { + "name": "event", + "type": "[Event!]!" + }, + { + "name": "extension", + "type": "Text!" + }, + { + "name": "geo", + "type": "[Geo!]!" + }, + { + "name": "host", + "type": "Text!" + }, + { + "name": "index", + "type": "Text!" + }, + { + "name": "ip", + "type": "Ip!" + }, + { + "name": "ipRange", + "type": "IpRange!" + }, + { + "name": "machine", + "type": "[Machine!]!" + }, + { + "name": "memory", + "type": "Double!" + }, + { + "name": "message", + "type": "Text!" + }, + { + "name": "phpmemory", + "type": "Long!" + }, + { + "name": "referer", + "type": "Keyword!" + }, + { + "name": "request", + "type": "Text!" + }, + { + "name": "response", + "type": "Text!" + }, + { + "name": "tags", + "type": "Text!" + }, + { + "name": "timestamp_1", + "type": "Alias!" + }, + { + "name": "timestampRange", + "type": "DateRange!" + }, + { + "name": "url", + "type": "Text!" + }, + { + "name": "utcTime", + "type": "Date!" + } + ], + "graphql": { + "typeName": "App_DsKibanaSampleDataLogs", + "inputTypeName": "App_DsKibanaSampleDataLogsInput" + }, + "dataConnectorTypeMapping": [ + { + "dataConnectorName": "elasticsearch", + "dataConnectorObjectType": ".ds-kibana_sample_data_logs-*", + "fieldMapping": { + "agent": { + "column": { + "name": "agent" + } + }, + "bytes": { + "column": { + "name": "bytes" + } + }, + "bytesCounter": { + "column": { + "name": "bytes_counter" + } + }, + "bytesGauge": { + "column": { + "name": "bytes_gauge" + } + }, + "clientip": { + "column": { + "name": "clientip" + } + }, + "event": { + "column": { + "name": "event" + } + }, + "extension": { + "column": { + "name": "extension" + } + }, + "geo": { + "column": { + "name": "geo" + } + }, + "host": { + "column": { + "name": "host" + } + }, + "id": { + "column": { + "name": "_id" + } + }, + "index": { + "column": { + "name": "index" + } + }, + "ip": { + "column": { + "name": "ip" + } + }, + "ipRange": { + "column": { + "name": "ip_range" + } + }, + "machine": { + "column": { + "name": "machine" + } + }, + "memory": { + "column": { + "name": "memory" + } + }, + "message": { + "column": { + "name": "message" + } + }, + "phpmemory": { + "column": { + "name": "phpmemory" + } + }, + "referer": { + "column": { + "name": "referer" + } + }, + "request": { + "column": { + "name": "request" + } + }, + "response": { + "column": { + "name": "response" + } + }, + "tags": { + "column": { + "name": "tags" + } + }, + "timestamp": { + "column": { + "name": "@timestamp" + } + }, + "timestampRange": { + "column": { + "name": "timestamp_range" + } + }, + "timestamp_1": { + "column": { + "name": "timestamp" + } + }, + "url": { + "column": { + "name": "url" + } + }, + "utcTime": { + "column": { + "name": "utc_time" } } } - ] - } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "Id", - "graphql": { - "typeName": "App_Id" } + ] + } + }, + { + "kind": "ScalarType", + "version": "v1", + "definition": { + "name": "Date", + "graphql": { + "typeName": "App_Date" } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "Text", - "graphql": { - "typeName": "App_Text" - } + } + }, + { + "kind": "ScalarType", + "version": "v1", + "definition": { + "name": "Id", + "graphql": { + "typeName": "App_Id" } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "Keyword", - "graphql": { - "typeName": "App_Keyword" - } + } + }, + { + "kind": "ScalarType", + "version": "v1", + "definition": { + "name": "Text", + "graphql": { + "typeName": "App_Text" } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "Date", - "graphql": { - "typeName": "App_Date" - } + } + }, + { + "kind": "ScalarType", + "version": "v1", + "definition": { + "name": "Long", + "graphql": { + "typeName": "App_Long" } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "Integer", - "graphql": { - "typeName": "App_Integer" - } + } + }, + { + "kind": "ScalarType", + "version": "v1", + "definition": { + "name": "Ip", + "graphql": { + "typeName": "App_Ip" } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "HalfFloat", - "graphql": { - "typeName": "App_HalfFloat" - } + } + }, + { + "kind": "ScalarType", + "version": "v1", + "definition": { + "name": "Keyword", + "graphql": { + "typeName": "App_Keyword" } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "Float_1", - "graphql": { - "typeName": "App_Float1" - } + } + }, + { + "kind": "ScalarType", + "version": "v1", + "definition": { + "name": "Double", + "graphql": { + "typeName": "App_Double" } - }, - { - "kind": "ScalarType", - "version": "v1", - "definition": { - "name": "Boolean_1", - "graphql": { - "typeName": "App_Boolean1" + } + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "Event", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [ + "dataset" + ] + } } - } - }, - { - "kind": "TypePermissions", - "version": "v1", - "definition": { - "typeName": "Event", - "permissions": [ - { - "role": "admin", - "output": { - "allowedFields": [] - } + ] + } + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "GeoPoint", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [] } - ] - } - }, - { - "kind": "TypePermissions", - "version": "v1", - "definition": { - "typeName": "Geoip", - "permissions": [ - { - "role": "admin", - "output": { - "allowedFields": [] - } + } + ] + } + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "Geo", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [ + "coordinates", + "dest", + "src", + "srcdest" + ] } - ] - } - }, - { - "kind": "TypePermissions", - "version": "v1", - "definition": { - "typeName": "Products", - "permissions": [ - { - "role": "admin", - "output": { - "allowedFields": [] - } + } + ] + } + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "IpRange", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [] } - ] - } - }, - { - "kind": "TypePermissions", - "version": "v1", - "definition": { - "typeName": "KibanaSampleDataEcommerce", - "permissions": [ - { - "role": "admin", - "output": { - "allowedFields": [ - "id", - "category", - "currency", - "customerBirthDate", - "customerFirstName", - "customerFullName", - "customerGender", - "customerId", - "customerLastName", - "customerPhone", - "dayOfWeek", - "dayOfWeekI", - "email", - "event", - "geoip", - "manufacturer", - "orderDate", - "orderId", - "products", - "sku", - "taxfulTotalPrice", - "taxlessTotalPrice", - "totalQuantity", - "totalUniqueProducts", - "type", - "user" - ] - } + } + ] + } + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "Machine", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [ + "os", + "ram" + ] } - ] - } - }, - { - "kind": "TypePermissions", - "version": "v1", - "definition": { - "typeName": "GeoPoint", - "permissions": [ - { - "role": "admin", - "output": { - "allowedFields": [] - } + } + ] + } + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "Alias", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [] } - ] - } - }, - { - "kind": "TypePermissions", - "version": "v1", - "definition": { - "typeName": "KibanaSampleDataFlights", - "permissions": [ - { - "role": "admin", - "output": { - "allowedFields": [ - "id", - "avgTicketPrice", - "cancelled", - "carrier", - "dest", - "destAirportId", - "destCityName", - "destCountry", - "destLocation", - "destRegion", - "destWeather", - "distanceKilometers", - "distanceMiles", - "flightDelay", - "flightDelayMin", - "flightDelayType", - "flightNum", - "flightTimeHour", - "flightTimeMin", - "origin", - "originAirportId", - "originCityName", - "originCountry", - "originLocation", - "originRegion", - "originWeather", - "dayOfWeek", - "timestamp" - ] - } + } + ] + } + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "DateRange", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [] } - ] - } + } + ] } - ] - } - ] - } \ No newline at end of file + }, + { + "kind": "TypePermissions", + "version": "v1", + "definition": { + "typeName": "DsKibanaSampleDataLogs", + "permissions": [ + { + "role": "admin", + "output": { + "allowedFields": [ + "timestamp", + "id", + "agent", + "bytes", + "bytesCounter", + "bytesGauge", + "clientip", + "event", + "extension", + "geo", + "host", + "index", + "ip", + "ipRange", + "machine", + "memory", + "message", + "phpmemory", + "referer", + "request", + "response", + "tags", + "timestamp_1", + "timestampRange", + "url", + "utcTime" + ] + } + } + ] + } + } + ] + } + ] +} \ No newline at end of file From 0611c5cd20d1a5ce8b401544c05069e753247a92 Mon Sep 17 00:00:00 2001 From: Darshan Lukhi Date: Fri, 7 Jun 2024 21:50:37 +0530 Subject: [PATCH 2/3] Update feature table to match engine support --- README.md | 7 ++----- docs/development.md | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index da10916..5bf868b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ - - # Elasticsearch Connector @@ -34,8 +31,8 @@ Below, you'll find a matrix of all supported features for the Elasticsearch conn | Paginate | ✅ | | | Nested Objects | ✅ | | | Nested Arrays | ✅ | | -| Nested Filtering | ✅ | | -| Nested Sorting | ✅ | | +| Nested Filtering | ❌ | | +| Nested Sorting | ❌ | | | Nested Relationships | ❌ | | diff --git a/docs/development.md b/docs/development.md index f1ec49b..7382362 100644 --- a/docs/development.md +++ b/docs/development.md @@ -45,8 +45,6 @@ Initialize with your database schema: ndc-elasticsearch update ``` -See [configuration.md](./configuration.md) for details. - ### 5. Running the Connector Locally Execute the connector: From 1b99ad9690c78a8aa330bde68233e54e75535c01 Mon Sep 17 00:00:00 2001 From: Darshan Lukhi Date: Sat, 8 Jun 2024 18:00:48 +0530 Subject: [PATCH 3/3] Update documentation as per review feedback --- README.md | 3 +-- docs/architecture.md | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5bf868b..1c9971a 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,7 @@ [![License](https://img.shields.io/badge/license-Apache--2.0-purple.svg?style=flat)](LICENSE.txt) [![Status](https://img.shields.io/badge/status-alpha-yellow.svg?style=flat)](./readme.md) -The Hasura Elasticsearch Connector allows for connecting to a Elasticsearch search engine, giving you an instant -GraphQL API on top of your Elasticsearch data. +With this connector, Hasura allows you to instantly create a real-time GraphQL API on top of your documents in Elasticsearch. This connector supports Elasticsearch functionalities listed in the table below, allowing for efficient and scalable data operations. Additionally, you will benefit from all the powerful features of Hasura’s Data Delivery Network (DDN) platform, including query pushdown capabilities that delegate all query operations to the Elasticsearch, thereby enhancing query optimization and performance. This connector is built using the [Go Data Connector SDK](https://github.com/hasura/ndc-sdk-go) and implements the [Data Connector Spec](https://github.com/hasura/ndc-spec). diff --git a/docs/architecture.md b/docs/architecture.md index 6bf8233..c2090fd 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -6,7 +6,7 @@ The Elasticsearch Connector takes a `QueryRequest`, which contains information a ### Components -The architecture of the Elasticsearch Connector is composed of three main components: +The connector has three main components: 1. **prepareElasticsearchQuery** 2. **Search** @@ -37,8 +37,8 @@ func prepareElasticsearchQuery( Executes the DSL query against Elasticsearch and returns results. **Functionality:** -- Execute the query on the Elasticsearch index. -- Fetch raw search results. +- Execute queries on the specified Elasticsearch index. +- Fetch search results. **API:** @@ -55,8 +55,8 @@ func (e *Client) Search( Converts Elasticsearch search results into `QueryResponse`. **Functionality:** -- Traverse through each field in the Elasticsearch response. -- Construct and return the `QueryResponse`, ensuring it aligns with the expected fields. +- Traverse each field in the Elasticsearch response. +- Construct and return the QueryResponse, ensuring it conforms to the expected fields. **API:**