Release 0.3 (#260)
* Bug has been fixed: impossible to lock/occlude object in AAM * Bug has been fixed: invisible points actually are visible * Bug has been fixed: impossible to close points after editing (#98) * doc: grammatical cleanup of README.md (#107) * Add info about development environment into CONTRIBUTING.md (#110) * Now we store virtual URL instead of update it in the browser address bar (#112) * Copy URL, Frame URL and object URL functionality in a context menu * Bug has been fixed: label UIs don't update after changelabel (#109) * Common escape button for exit from creating/groupping/merging/pasting/aam * Switch outside/keyframe shortkeys * Fix django vulnerability (#121) * Add analytics component (#118) * Incremental save of annotations (#120) * Create task timeout 1h -> 4h. (#136) * OpenVino integration (#134) * Update README.md (#138) * Add an extra field into meta section of a dump file (#149) * Job status was implemented (#153) * Back link to task from annotation view (#156) * Change a task with labels and attributes in admin panel (#157) * Permissions per tasks and jobs (#185) * Fix context menu, text visibility for small images (#202) * Fixed: both context menu are opened simultaneously * Fixed: shape can be unavailable behind text * Fixed: invisible text outside frame * Fix upload big xml files for tasks (#199) * Add Questions section to Readme.md (#226) * Fixed labels order (#242) * Propagate behaviour has been updated in cases with a different resolution (#246) * Updated the guide and images (#241) * Fix number attribute for float numbers. (#258)main
@ -1,4 +1,196 @@
|
||||
# How to contribute to Computer Vision Annotation Tool (CVAT)
|
||||
# Contributing to this project
|
||||
|
||||
When contributing to this repository, please first discuss the change you wish to make via issue,
|
||||
email, or any other method with the owners of this repository before making a change.
|
||||
Please take a moment to review this document in order to make the contribution
|
||||
process easy and effective for everyone involved.
|
||||
|
||||
Following these guidelines helps to communicate that you respect the time of
|
||||
the developers managing and developing this open source project. In return,
|
||||
they should reciprocate that respect in addressing your issue or assessing
|
||||
patches and features.
|
||||
|
||||
## Development environment
|
||||
|
||||
Next steps should work on clear Ubuntu 18.04.
|
||||
|
||||
- Install necessary dependencies:
|
||||
|
||||
```sh
|
||||
$ sudo apt-get install -y curl redis-server python3-dev python3-pip python3-venv libldap2-dev libsasl2-dev
|
||||
```
|
||||
|
||||
- Install [Visual Studio Code](https://code.visualstudio.com/docs/setup/linux#_debian-and-ubuntu-based-distributions) for development
|
||||
|
||||
- Install CVAT on your local host:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/opencv/cvat
|
||||
$ cd cvat && mkdir logs keys
|
||||
$ python3 -m venv .env
|
||||
$ . .env/bin/activate
|
||||
$ pip install -U pip wheel
|
||||
$ pip install -r cvat/requirements/development.txt
|
||||
$ python manage.py migrate
|
||||
$ python manage.py collectstatic
|
||||
```
|
||||
|
||||
- Create a super user for CVAT:
|
||||
|
||||
```sh
|
||||
$ python manage.py createsuperuser
|
||||
Username (leave blank to use 'django'): ***
|
||||
Email address: ***
|
||||
Password: ***
|
||||
Password (again): ***
|
||||
```
|
||||
|
||||
- Run Visual Studio Code from the virtual environment
|
||||
|
||||
```
|
||||
$ code .
|
||||
```
|
||||
|
||||
- Inside Visual Studio Code install [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) and [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) extensions
|
||||
|
||||
- Reload Visual Studio Code
|
||||
|
||||
- Select `CVAT Debugging` configuration and start debugging (F5)
|
||||
|
||||
You have done! Now it is possible to insert breakpoints and debug server and client of the tool.
|
||||
|
||||
## Branching model
|
||||
|
||||
The project uses [a successful Git branching model](https://nvie.com/posts/a-successful-git-branching-model).
|
||||
Thus it has a couple of branches. Some of them are described below:
|
||||
|
||||
- `origin/master` to be the main branch where the source code of
|
||||
HEAD always reflects a production-ready state.
|
||||
- `origin/develop` to be the main branch where the source code of
|
||||
HEAD always reflects a state with the latest delivered development
|
||||
changes for the next release. Some would call this the “integration branch”.
|
||||
|
||||
## Using the issue tracker
|
||||
|
||||
The issue tracker is the preferred channel for [bug reports](#bugs),
|
||||
[features requests](#features) and [submitting pull
|
||||
requests](#pull-requests), but please respect the following restrictions:
|
||||
|
||||
* Please **do not** use the issue tracker for personal support requests (use
|
||||
[Stack Overflow](http://stackoverflow.com)).
|
||||
|
||||
* Please **do not** derail or troll issues. Keep the discussion on topic and
|
||||
respect the opinions of others.
|
||||
|
||||
<a name="bugs"></a>
|
||||
## Bug reports
|
||||
|
||||
A bug is a _demonstrable problem_ that is caused by the code in the repository.
|
||||
Good bug reports are extremely helpful - thank you!
|
||||
|
||||
Guidelines for bug reports:
|
||||
|
||||
1. **Use the GitHub issue search** — check if the issue has already been
|
||||
reported.
|
||||
|
||||
2. **Check if the issue has been fixed** — try to reproduce it using the
|
||||
latest `develop` branch in the repository.
|
||||
|
||||
3. **Isolate the problem** — ideally create a reduced test case.
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more
|
||||
information. Please try to be as detailed as possible in your report. What is
|
||||
your environment? What steps will reproduce the issue? What browser(s) and OS
|
||||
experience the problem? What would you expect to be the outcome? All these
|
||||
details will help people to fix any potential bugs.
|
||||
|
||||
Example:
|
||||
|
||||
> Short and descriptive example bug report title
|
||||
>
|
||||
> A summary of the issue and the browser/OS environment in which it occurs. If
|
||||
> suitable, include the steps required to reproduce the bug.
|
||||
>
|
||||
> 1. This is the first step
|
||||
> 2. This is the second step
|
||||
> 3. Further steps, etc.
|
||||
>
|
||||
>
|
||||
> Any other information you want to share that is relevant to the issue being
|
||||
> reported. This might include the lines of code that you have identified as
|
||||
> causing the bug, and potential solutions (and your opinions on their
|
||||
> merits).
|
||||
|
||||
<a name="features"></a>
|
||||
## Feature requests
|
||||
|
||||
Feature requests are welcome. But take a moment to find out whether your idea
|
||||
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||
case to convince the project's developers of the merits of this feature. Please
|
||||
provide as much detail and context as possible.
|
||||
|
||||
<a name="pull-requests"></a>
|
||||
## Pull requests
|
||||
|
||||
Good pull requests - patches, improvements, new features - are a fantastic
|
||||
help. They should remain focused in scope and avoid containing unrelated
|
||||
commits.
|
||||
|
||||
**Please ask first** before embarking on any significant pull request (e.g.
|
||||
implementing features, refactoring code, porting to a different language),
|
||||
otherwise you risk spending a lot of time working on something that the
|
||||
project's developers might not want to merge into the project.
|
||||
|
||||
Please adhere to the coding conventions used throughout a project (indentation,
|
||||
accurate comments, etc.) and any other requirements (such as test coverage).
|
||||
|
||||
Follow this process if you'd like your work considered for inclusion in the
|
||||
project:
|
||||
|
||||
1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
|
||||
and configure the remotes:
|
||||
|
||||
```bash
|
||||
# Clone your fork of the repo into the current directory
|
||||
git clone https://github.com/<your-username>/<repo-name>
|
||||
# Navigate to the newly cloned directory
|
||||
cd <repo-name>
|
||||
# Assign the original repo to a remote called "upstream"
|
||||
git remote add upstream https://github.com/<upstream-owner>/<repo-name>
|
||||
```
|
||||
|
||||
2. If you cloned a while ago, get the latest changes from upstream:
|
||||
|
||||
```bash
|
||||
git checkout <dev-branch>
|
||||
git pull upstream <dev-branch>
|
||||
```
|
||||
|
||||
3. Create a new topic branch (off the main project development branch) to
|
||||
contain your feature, change, or fix:
|
||||
|
||||
```bash
|
||||
git checkout -b <topic-branch-name>
|
||||
```
|
||||
|
||||
4. Commit your changes in logical chunks. Please adhere to these [git commit
|
||||
message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
||||
or your code is unlikely be merged into the main project. Use Git's
|
||||
[interactive rebase](https://help.github.com/articles/interactive-rebase)
|
||||
feature to tidy up your commits before making them public.
|
||||
|
||||
5. Locally merge (or rebase) the upstream development branch into your topic branch:
|
||||
|
||||
```bash
|
||||
git pull [--rebase] upstream <dev-branch>
|
||||
```
|
||||
|
||||
6. Push your topic branch up to your fork:
|
||||
|
||||
```bash
|
||||
git push origin <topic-branch-name>
|
||||
```
|
||||
|
||||
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
|
||||
with a clear title and description.
|
||||
|
||||
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
|
||||
license your work under the same license as that used by the project.
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
### There are some additional components for CVAT
|
||||
|
||||
* [NVIDIA CUDA](cuda/README.md)
|
||||
* [OpenVINO](openvino/README.md)
|
||||
* [Tensorflow Object Detector](tf_annotation/README.md)
|
||||
* [Analytics](analytics/README.md)
|
||||
@ -0,0 +1,104 @@
|
||||
## Analytics for Computer Vision Annotation Tool (CVAT)
|
||||
|
||||
It is possible to proxy annotation logs from client to ELK. To do that run the following command below:
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/analytics/docker-compose.analytics.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/analytics/docker-compose.analytics.yml up -d
|
||||
```
|
||||
|
||||
At the moment it is not possible to save advanced settings. Below values should be specified manually.
|
||||
|
||||
## Time picker default
|
||||
{
|
||||
"from": "now/d",
|
||||
"to": "now/d",
|
||||
"display": "Today",
|
||||
"section": 0
|
||||
}
|
||||
|
||||
## Time picker quick ranges
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"from": "now/d",
|
||||
"to": "now/d",
|
||||
"display": "Today",
|
||||
"section": 0
|
||||
},
|
||||
{
|
||||
"from": "now/w",
|
||||
"to": "now/w",
|
||||
"display": "This week",
|
||||
"section": 0
|
||||
},
|
||||
{
|
||||
"from": "now/M",
|
||||
"to": "now/M",
|
||||
"display": "This month",
|
||||
"section": 0
|
||||
},
|
||||
{
|
||||
"from": "now/y",
|
||||
"to": "now/y",
|
||||
"display": "This year",
|
||||
"section": 0
|
||||
},
|
||||
{
|
||||
"from": "now/d",
|
||||
"to": "now",
|
||||
"display": "Today so far",
|
||||
"section": 2
|
||||
},
|
||||
{
|
||||
"from": "now/w",
|
||||
"to": "now",
|
||||
"display": "Week to date",
|
||||
"section": 2
|
||||
},
|
||||
{
|
||||
"from": "now/M",
|
||||
"to": "now",
|
||||
"display": "Month to date",
|
||||
"section": 2
|
||||
},
|
||||
{
|
||||
"from": "now/y",
|
||||
"to": "now",
|
||||
"display": "Year to date",
|
||||
"section": 2
|
||||
},
|
||||
{
|
||||
"from": "now-1d/d",
|
||||
"to": "now-1d/d",
|
||||
"display": "Yesterday",
|
||||
"section": 1
|
||||
},
|
||||
{
|
||||
"from": "now-1w/w",
|
||||
"to": "now-1w/w",
|
||||
"display": "Previous week",
|
||||
"section": 1
|
||||
},
|
||||
{
|
||||
"from": "now-1m/m",
|
||||
"to": "now-1m/m",
|
||||
"display": "Previous month",
|
||||
"section": 1
|
||||
},
|
||||
{
|
||||
"from": "now-1y/y",
|
||||
"to": "now-1y/y",
|
||||
"display": "Previous year",
|
||||
"section": 1
|
||||
}
|
||||
]
|
||||
```
|
||||
@ -0,0 +1,69 @@
|
||||
version: '2.3'
|
||||
services:
|
||||
cvat_elasticsearch:
|
||||
container_name: cvat_elasticsearch
|
||||
image: cvat_elasticsearch
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
- elasticsearch
|
||||
build:
|
||||
context: ./components/analytics/elasticsearch
|
||||
args:
|
||||
ELK_VERSION: 6.4.0
|
||||
volumes:
|
||||
- cvat_events:/usr/share/elasticsearch/data
|
||||
restart: always
|
||||
|
||||
cvat_kibana:
|
||||
container_name: cvat_kibana
|
||||
image: cvat_kibana
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
- kibana
|
||||
build:
|
||||
context: ./components/analytics/kibana
|
||||
args:
|
||||
ELK_VERSION: 6.4.0
|
||||
depends_on: ['cvat_elasticsearch']
|
||||
restart: always
|
||||
|
||||
cvat_kibana_setup:
|
||||
container_name: cvat_kibana_setup
|
||||
image: cvat
|
||||
volumes: ['./components/analytics/kibana:/home/django/kibana:ro']
|
||||
depends_on: ['cvat']
|
||||
working_dir: '/home/django'
|
||||
entrypoint: ['bash', 'wait-for-it.sh', 'elasticsearch:9200', '-t', '0', '--',
|
||||
'/bin/bash', 'wait-for-it.sh', 'kibana:5601', '-t', '0', '--',
|
||||
'/usr/bin/python3', 'kibana/setup.py', 'kibana/export.json']
|
||||
environment:
|
||||
no_proxy: elasticsearch,kibana,${no_proxy}
|
||||
|
||||
cvat_logstash:
|
||||
container_name: cvat_logstash
|
||||
image: cvat_logstash
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
- logstash
|
||||
build:
|
||||
context: ./components/analytics/logstash
|
||||
args:
|
||||
ELK_VERSION: 6.4.0
|
||||
http_proxy: ${http_proxy}
|
||||
https_proxy: ${https_proxy}
|
||||
depends_on: ['cvat_elasticsearch']
|
||||
restart: always
|
||||
|
||||
cvat:
|
||||
environment:
|
||||
DJANGO_LOG_SERVER_HOST: logstash
|
||||
DJANGO_LOG_SERVER_PORT: 5000
|
||||
DJANGO_LOG_VIEWER_HOST: kibana
|
||||
DJANGO_LOG_VIEWER_PORT: 5601
|
||||
no_proxy: kibana,logstash,${no_proxy}
|
||||
|
||||
volumes:
|
||||
cvat_events:
|
||||
@ -0,0 +1,4 @@
|
||||
ARG ELK_VERSION
|
||||
FROM docker.elastic.co/elasticsearch/elasticsearch-oss:${ELK_VERSION}
|
||||
COPY --chown=elasticsearch:elasticsearch elasticsearch.yml /usr/share/elasticsearch/config/
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
http.host: 0.0.0.0
|
||||
script.painless.regex.enabled: true
|
||||
path.repo: ["/usr/share/elasticsearch/data/backup"]
|
||||
@ -0,0 +1,5 @@
|
||||
ARG ELK_VERSION
|
||||
FROM docker.elastic.co/kibana/kibana-oss:${ELK_VERSION}
|
||||
COPY kibana.yml /usr/share/kibana/config/
|
||||
|
||||
|
||||
@ -0,0 +1,198 @@
|
||||
[
|
||||
{
|
||||
"_id": "7e8996e0-c23d-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "dashboard",
|
||||
"_source": {
|
||||
"panelsJSON": "[{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":21,\"w\":48,\"h\":13,\"i\":\"1\"},\"id\":\"3ade53d0-c23e-11e8-8e1b-758ef07f6de8\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"version\":\"6.4.0\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":34,\"w\":48,\"h\":27,\"i\":\"2\"},\"id\":\"9397f350-c23e-11e8-8e1b-758ef07f6de8\",\"panelIndex\":\"2\",\"type\":\"search\",\"version\":\"6.4.0\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":21,\"i\":\"3\"},\"id\":\"1ec6a660-c244-11e8-8e1b-758ef07f6de8\",\"panelIndex\":\"3\",\"type\":\"visualization\",\"version\":\"6.4.0\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":21,\"i\":\"4\"},\"id\":\"65918380-c244-11e8-8e1b-758ef07f6de8\",\"panelIndex\":\"4\",\"type\":\"visualization\",\"version\":\"6.4.0\"}]",
|
||||
"hits": 0,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"
|
||||
},
|
||||
"timeRestore": false,
|
||||
"description": "",
|
||||
"title": "Monitoring",
|
||||
"optionsJSON": "{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}",
|
||||
"version": 1
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "d92524b0-c25c-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "visualization",
|
||||
"_source": {
|
||||
"visState": "{\"title\":\"Activity of users\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"User\",\"terms_field\":\"userid.keyword\",\"terms_size\":\"100\"}],\"time_field\":\"@timestamp\",\"index_pattern\":\"cvat*\",\"interval\":\"auto\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1},\"aggs\":[]}",
|
||||
"uiStateJSON": "{}",
|
||||
"description": "",
|
||||
"title": "Activity of users",
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
|
||||
},
|
||||
"version": 1
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "9397f350-c23e-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "search",
|
||||
"_source": {
|
||||
"hits": 0,
|
||||
"sort": [
|
||||
"@timestamp",
|
||||
"desc"
|
||||
],
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":\"event:\\\"Send exception\\\"\"},\"filter\":[]}"
|
||||
},
|
||||
"columns": [
|
||||
"task",
|
||||
"type",
|
||||
"userid",
|
||||
"stack"
|
||||
],
|
||||
"description": "",
|
||||
"title": "Table with exceptions",
|
||||
"version": 1
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "3ade53d0-c23e-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "visualization",
|
||||
"_source": {
|
||||
"title": "Timeline for exceptions",
|
||||
"visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{\"customBucket\":{\"enabled\":true,\"id\":\"1-bucket\",\"params\":{\"filters\":[{\"input\":{\"query\":\"event:\\\"Send exception\\\"\"},\"label\":\"\"}]},\"schema\":{\"aggFilter\":[],\"deprecate\":false,\"editor\":false,\"group\":\"none\",\"max\":null,\"min\":0,\"name\":\"bucketAgg\",\"params\":[],\"title\":\"Bucket Agg\"},\"type\":\"filters\"},\"customLabel\":\"Exceptions\",\"customMetric\":{\"enabled\":true,\"id\":\"1-metric\",\"params\":{\"customLabel\":\"Exceptions\"},\"schema\":{\"aggFilter\":[\"!top_hits\",\"!percentiles\",\"!percentile_ranks\",\"!median\",\"!std_dev\",\"!sum_bucket\",\"!avg_bucket\",\"!min_bucket\",\"!max_bucket\",\"!derivative\",\"!moving_avg\",\"!serial_diff\",\"!cumulative_sum\"],\"deprecate\":false,\"editor\":false,\"group\":\"none\",\"max\":null,\"min\":0,\"name\":\"metricAgg\",\"params\":[],\"title\":\"Metric Agg\"},\"type\":\"count\"}},\"schema\":\"metric\",\"type\":\"sum_bucket\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"customInterval\":\"2h\",\"customLabel\":\"Time\",\"extended_bounds\":{},\"field\":\"@timestamp\",\"interval\":\"auto\",\"min_doc_count\":1},\"schema\":\"segment\",\"type\":\"date_histogram\"}],\"params\":{\"addLegend\":true,\"addTimeMarker\":true,\"addTooltip\":true,\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"labels\":{\"show\":true,\"truncate\":100},\"position\":\"bottom\",\"scale\":{\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{},\"type\":\"category\"}],\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"legendPosition\":\"right\",\"seriesParams\":[{\"data\":{\"id\":\"1\",\"label\":\"Exceptions\"},\"drawLinesBetweenPoints\":true,\"mode\":\"stacked\",\"show\":\"true\",\"showCircles\":true,\"type\":\"histogram\",\"valueAxis\":\"ValueAxis-1\"}],\"times\":[],\"type\":\"histogram\",\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"labels\":{\"filter\":false,\"rotate\":0,\"show\":true,\"truncate\":100},\"name\":\"LeftAxis-1\",\"position\":\"left\",\"scale\":{\"mode\":\"normal\",\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"Exceptions\"},\"type\":\"value\"}]},\"title\":\"Timeline for exceptions\",\"type\":\"histogram\"}",
|
||||
"uiStateJSON": "{}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
|
||||
}
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "1ec6a660-c244-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "visualization",
|
||||
"_source": {
|
||||
"title": "Duration of events",
|
||||
"visState": "{\"title\":\"Duration of events\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showMetricsAtAllLevels\":false,\"showPartialRows\":false,\"showTotal\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"event.keyword\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"_key\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Action\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"avg\",\"schema\":\"metric\",\"params\":{\"field\":\"duration\",\"customLabel\":\"\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"min\",\"schema\":\"metric\",\"params\":{\"field\":\"duration\",\"customLabel\":\"\"}},{\"id\":\"5\",\"enabled\":true,\"type\":\"max\",\"schema\":\"metric\",\"params\":{\"field\":\"duration\"}}]}",
|
||||
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[{\"$state\":{\"store\":\"appState\"},\"exists\":{\"field\":\"duration\"},\"meta\":{\"alias\":null,\"disabled\":false,\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"key\":\"duration\",\"negate\":false,\"type\":\"exists\",\"value\":\"exists\"}}]}"
|
||||
}
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "ec510550-c238-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "index-pattern",
|
||||
"_source": {
|
||||
"fields": "[{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"application\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"application.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"box count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"duration\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event\",\"type\":\"string\",\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"event.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"frame count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"object count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"points count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"polygon count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"polyline count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"task\",\"type\":\"string\",\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"task.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"timestamp\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"track count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"userid\",\"type\":\"string\",\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"working time\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
|
||||
"title": "cvat*",
|
||||
"timeFieldName": "@timestamp",
|
||||
"fieldFormatMap": "{\"duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"milliseconds\",\"outputFormat\":\"asSeconds\"}},\"working time\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"milliseconds\",\"outputFormat\":\"asHours\"}}}"
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "65918380-c244-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "visualization",
|
||||
"_source": {
|
||||
"title": "Number of events",
|
||||
"visState": "{\"title\":\"Number of events\",\"type\":\"table\",\"params\":{\"perPage\":20,\"showMetricsAtAllLevels\":false,\"showPartialRows\":false,\"showTotal\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"event.keyword\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Action\"}}]}",
|
||||
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"
|
||||
}
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "543f6260-c25c-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "visualization",
|
||||
"_source": {
|
||||
"title": "Working day",
|
||||
"visState": "{\"title\":\"Working day\",\"type\":\"table\",\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"min\",\"schema\":\"metric\",\"params\":{\"field\":\"@timestamp\",\"customLabel\":\"Start\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"userid.keyword\",\"size\":1000,\"order\":\"asc\",\"orderBy\":\"_key\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"User\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"max\",\"schema\":\"metric\",\"params\":{\"field\":\"@timestamp\",\"customLabel\":\"End\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"split\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"d\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{},\"customLabel\":\"day\",\"row\":true}}]}",
|
||||
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
|
||||
}
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "31ac2d60-c25b-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "visualization",
|
||||
"_source": {
|
||||
"title": "List of users",
|
||||
"visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"2\",\"params\":{\"customLabel\":\"User\",\"field\":\"userid.keyword\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"order\":\"asc\",\"orderBy\":\"_key\",\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"size\":1000},\"schema\":\"bucket\",\"type\":\"terms\"},{\"enabled\":true,\"id\":\"3\",\"params\":{\"customBucket\":{\"enabled\":true,\"id\":\"3-bucket\",\"params\":{\"customInterval\":\"2h\",\"extended_bounds\":{},\"field\":\"@timestamp\",\"interval\":\"auto\",\"min_doc_count\":1},\"schema\":{\"aggFilter\":[],\"deprecate\":false,\"editor\":false,\"group\":\"none\",\"max\":null,\"min\":0,\"name\":\"bucketAgg\",\"params\":[],\"title\":\"Bucket Agg\"},\"type\":\"date_histogram\"},\"customLabel\":\"Activity\",\"customMetric\":{\"enabled\":true,\"id\":\"3-metric\",\"params\":{},\"schema\":{\"aggFilter\":[\"!top_hits\",\"!percentiles\",\"!percentile_ranks\",\"!median\",\"!std_dev\",\"!sum_bucket\",\"!avg_bucket\",\"!min_bucket\",\"!max_bucket\",\"!derivative\",\"!moving_avg\",\"!serial_diff\",\"!cumulative_sum\"],\"deprecate\":false,\"editor\":false,\"group\":\"none\",\"max\":null,\"min\":0,\"name\":\"metricAgg\",\"params\":[],\"title\":\"Metric Agg\"},\"type\":\"count\"}},\"schema\":\"metric\",\"type\":\"sum_bucket\"},{\"enabled\":true,\"id\":\"1\",\"params\":{\"customLabel\":\"Working Time (h)\",\"field\":\"working time\"},\"schema\":\"metric\",\"type\":\"sum\"}],\"params\":{\"perPage\":20,\"showMetricsAtAllLevels\":false,\"showPartialRows\":false,\"showTotal\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"totalFunc\":\"sum\"},\"title\":\"List of users\",\"type\":\"table\"}",
|
||||
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"
|
||||
}
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "7f637200-d068-11e8-9320-a3c87be2b433",
|
||||
"_type": "visualization",
|
||||
"_source": {
|
||||
"title": "List of tasks",
|
||||
"visState": "{\"title\":\"List of tasks\",\"type\":\"table\",\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":2,\"direction\":\"desc\"},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"working time\",\"customLabel\":\"Working time (h)\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"task.keyword\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Task\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"userid.keyword\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"_key\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"User\"}}]}",
|
||||
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":2,\"direction\":\"desc\"}}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"index\":\"ec510550-c238-11e8-8e1b-758ef07f6de8\",\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
|
||||
}
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "22250a40-c25d-11e8-8e1b-758ef07f6de8",
|
||||
"_type": "dashboard",
|
||||
"_source": {
|
||||
"title": "Managment",
|
||||
"hits": 0,
|
||||
"description": "",
|
||||
"panelsJSON": "[{\"embeddableConfig\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":1,\"direction\":\"desc\"}}}},\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":33,\"i\":\"1\"},\"id\":\"31ac2d60-c25b-11e8-8e1b-758ef07f6de8\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"version\":\"6.4.0\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":33,\"w\":48,\"h\":33,\"i\":\"2\"},\"id\":\"543f6260-c25c-11e8-8e1b-758ef07f6de8\",\"panelIndex\":\"2\",\"type\":\"visualization\",\"version\":\"6.4.0\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":66,\"w\":48,\"h\":33,\"i\":\"3\"},\"id\":\"d92524b0-c25c-11e8-8e1b-758ef07f6de8\",\"panelIndex\":\"3\",\"type\":\"visualization\",\"version\":\"6.4.0\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":33,\"i\":\"4\"},\"id\":\"7f637200-d068-11e8-9320-a3c87be2b433\",\"panelIndex\":\"4\",\"type\":\"visualization\",\"version\":\"6.4.0\"}]",
|
||||
"optionsJSON": "{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}",
|
||||
"version": 1,
|
||||
"timeRestore": false,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"
|
||||
}
|
||||
},
|
||||
"_meta": {
|
||||
"savedObjectVersion": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,5 @@
|
||||
server.host: 0.0.0.0
|
||||
elasticsearch.url: http://elasticsearch:9200
|
||||
elasticsearch.requestHeadersWhitelist: [ "cookie", "authorization", "x-forwarded-user" ]
|
||||
kibana.defaultAppId: "discover"
|
||||
server.basePath: /analytics
|
||||
@ -0,0 +1,40 @@
|
||||
#/usr/bin/env python
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import requests
|
||||
import json
|
||||
|
||||
def import_resources(host, port, cfg_file):
|
||||
with open(cfg_file, 'r') as f:
|
||||
for saved_object in json.load(f):
|
||||
_id = saved_object["_id"]
|
||||
_type = saved_object["_type"]
|
||||
_doc = saved_object["_source"]
|
||||
import_saved_object(host, port, _type, _id, _doc)
|
||||
|
||||
def import_saved_object(host, port, _type, _id, data):
|
||||
saved_objects_api = "http://{}:{}/api/saved_objects/{}/{}".format(
|
||||
host, port, _type, _id)
|
||||
request = requests.get(saved_objects_api)
|
||||
if request.status_code == 404:
|
||||
print("Creating {} as {}".format(_type, _id))
|
||||
request = requests.post(saved_objects_api, json={"attributes": data},
|
||||
headers={'kbn-xsrf': 'true'})
|
||||
else:
|
||||
print("Updating {} named {}".format(_type, _id))
|
||||
request = requests.put(saved_objects_api, json={"attributes": data},
|
||||
headers={'kbn-xsrf': 'true'})
|
||||
request.raise_for_status()
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='import Kibana 6.x resources',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('export_file', metavar='FILE',
|
||||
help='JSON export file with resources')
|
||||
parser.add_argument('-p', '--port', metavar='PORT', default=5601, type=int,
|
||||
help='port of Kibana instance')
|
||||
parser.add_argument('-H', '--host', metavar='HOST', default='kibana',
|
||||
help='host of Kibana instance')
|
||||
args = parser.parse_args()
|
||||
import_resources(args.host, args.port, args.export_file)
|
||||
@ -0,0 +1,7 @@
|
||||
ARG ELK_VERSION
|
||||
FROM docker.elastic.co/logstash/logstash-oss:${ELK_VERSION}
|
||||
RUN logstash-plugin install logstash-input-http logstash-filter-aggregate \
|
||||
logstash-filter-prune logstash-output-email
|
||||
|
||||
COPY logstash.conf /usr/share/logstash/pipeline/
|
||||
EXPOSE 5000
|
||||
@ -0,0 +1,98 @@
|
||||
input {
|
||||
tcp {
|
||||
port => 5000
|
||||
codec => json
|
||||
}
|
||||
}
|
||||
|
||||
filter {
|
||||
if [logger_name] =~ /cvat.client/ {
|
||||
# 1. Decode the event from json in 'message' field
|
||||
# 2. Remove unnecessary field from it
|
||||
# 3. Type it as client
|
||||
json {
|
||||
source => "message"
|
||||
}
|
||||
|
||||
date {
|
||||
match => ["timestamp", "UNIX", "UNIX_MS"]
|
||||
remove_field => "timestamp"
|
||||
}
|
||||
|
||||
if [event] == "Send exception" {
|
||||
aggregate {
|
||||
task_id => "%{userid}_%{application}_%{message}_%{filename}_%{line}"
|
||||
code => "
|
||||
require 'time'
|
||||
|
||||
map['userid'] ||= event.get('userid');
|
||||
map['application'] ||= event.get('application');
|
||||
map['error'] ||= event.get('message');
|
||||
map['filename'] ||= event.get('filename');
|
||||
map['line'] ||= event.get('line');
|
||||
map['task'] ||= event.get('task');
|
||||
|
||||
map['error_count'] ||= 0;
|
||||
map['error_count'] += 1;
|
||||
|
||||
map['aggregated_stack'] ||= '';
|
||||
map['aggregated_stack'] += event.get('stack') + '\n\n\n';"
|
||||
|
||||
timeout => 3600
|
||||
timeout_tags => ['aggregated_exception']
|
||||
push_map_as_event_on_timeout => true
|
||||
}
|
||||
}
|
||||
|
||||
prune {
|
||||
blacklist_names => ["level", "host", "logger_name", "message", "path",
|
||||
"port", "stack_info"]
|
||||
}
|
||||
|
||||
mutate {
|
||||
replace => { "type" => "client" }
|
||||
}
|
||||
} else if [logger_name] =~ /cvat.server/ {
|
||||
# 1. Remove 'logger_name' field and create 'task' field
|
||||
# 2. Remove unnecessary field from it
|
||||
# 3. Type it as server
|
||||
if [logger_name] =~ /cvat\.server\.task_[0-9]+/ {
|
||||
mutate {
|
||||
rename => { "logger_name" => "task" }
|
||||
gsub => [ "task", "cvat.server.task_", "" ]
|
||||
}
|
||||
|
||||
# Need to split the mutate because otherwise the conversion
|
||||
# doesn't work.
|
||||
mutate {
|
||||
convert => { "task" => "integer" }
|
||||
}
|
||||
}
|
||||
|
||||
prune {
|
||||
blacklist_names => ["host", "port", "stack_info"]
|
||||
}
|
||||
|
||||
mutate {
|
||||
replace => { "type" => "server" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output {
|
||||
stdout {
|
||||
codec => rubydebug
|
||||
}
|
||||
|
||||
if [type] == "client" {
|
||||
elasticsearch {
|
||||
hosts => ["elasticsearch:9200"]
|
||||
index => "cvat.client"
|
||||
}
|
||||
} else if [type] == "server" {
|
||||
elasticsearch {
|
||||
hosts => ["elasticsearch:9200"]
|
||||
index => "cvat.server"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
## [NVIDIA CUDA Toolkit](https://developer.nvidia.com/cuda-toolkit)
|
||||
|
||||
### Requirements
|
||||
|
||||
* NVIDIA GPU with a compute capability [3.0 - 7.2]
|
||||
* Latest GPU driver
|
||||
|
||||
### Installation
|
||||
|
||||
#### Install the latest driver for your graphics card
|
||||
|
||||
```bash
|
||||
sudo add-apt-repository ppa:graphics-drivers/ppa
|
||||
sudo apt-get update
|
||||
sudo apt-cache search nvidia-* # find latest nvidia driver
|
||||
sudo apt-get install nvidia-* # install the nvidia driver
|
||||
sudo apt-get install mesa-common-dev
|
||||
sudo apt-get install freeglut3-dev
|
||||
sudo apt-get install nvidia-modprobe
|
||||
```
|
||||
|
||||
#### Reboot your PC and verify installation by `nvidia-smi` command.
|
||||
|
||||
#### Install [Nvidia-Docker](https://github.com/NVIDIA/nvidia-docker)
|
||||
|
||||
Please be sure that installation was successful.
|
||||
```bash
|
||||
docker info | grep 'Runtimes' # output should contains 'nvidia'
|
||||
```
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/cuda/docker-compose.cuda.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/cuda/docker-compose.cuda.yml up -d
|
||||
```
|
||||
@ -0,0 +1,23 @@
|
||||
## [Intel OpenVINO toolkit](https://software.intel.com/en-us/openvino-toolkit)
|
||||
|
||||
### Requirements
|
||||
|
||||
* Intel Core with 6th generation and higher or Intel Xeon CPUs.
|
||||
|
||||
### Preparation
|
||||
|
||||
* Download latest [OpenVINO toolkit](https://software.intel.com/en-us/openvino-toolkit) installer (offline or online) for Linux platform. It should be .tgz archive. Minimum required version is 2018 R3.
|
||||
* Put downloaded file into ```components/openvino```.
|
||||
* Accept EULA in the eula.cfg file.
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/openvino/docker-compose.openvino.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/openvino/docker-compose.openvino.yml up -d
|
||||
```
|
||||
@ -0,0 +1,13 @@
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
version: "2.3"
|
||||
|
||||
services:
|
||||
cvat:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
OPENVINO_TOOLKIT: "yes"
|
||||
@ -0,0 +1,3 @@
|
||||
# Accept actual EULA from openvino installation archive. Valid values are: {accept, decline}
|
||||
ACCEPT_EULA=accept
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
set -e
|
||||
|
||||
if [[ `lscpu | grep -o "GenuineIntel"` != "GenuineIntel" ]]; then
|
||||
echo "OpenVINO supports only Intel CPUs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ `lscpu | grep -o "sse4" | head -1` != "sse4" ]] && [[ `lscpu | grep -o "avx2" | head -1` != "avx2" ]]; then
|
||||
echo "You Intel CPU should support sse4 or avx2 instruction if you want use OpenVINO"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
cd /tmp/components/openvino
|
||||
|
||||
tar -xzf `ls | grep "openvino_toolkit"`
|
||||
cd `ls -d */ | grep "openvino_toolkit"`
|
||||
|
||||
apt-get update && apt-get install -y sudo cpio && \
|
||||
./install_cv_sdk_dependencies.sh && SUDO_FORCE_REMOVE=yes apt-get remove -y sudo
|
||||
|
||||
cat ../eula.cfg >> silent.cfg
|
||||
./install.sh -s silent.cfg
|
||||
|
||||
cd /tmp/components && rm openvino -r
|
||||
|
||||
echo "source /opt/intel/computer_vision_sdk/bin/setupvars.sh" >> ${HOME}/.bashrc
|
||||
echo -e '\nexport IE_PLUGINS_PATH=${IE_PLUGINS_PATH}' >> /opt/intel/computer_vision_sdk/bin/setupvars.sh
|
||||
@ -0,0 +1,41 @@
|
||||
## [Tensorflow Object Detector](https://github.com/tensorflow/models/tree/master/research/object_detection)
|
||||
|
||||
### What is it?
|
||||
* This application allows you automatically to annotate many various objects on images.
|
||||
* It uses [Faster RCNN Inception Resnet v2 Atrous Coco Model](http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_resnet_v2_atrous_coco_2018_01_28.tar.gz) from [tensorflow detection model zoo](https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md)
|
||||
* It can work on CPU (with Tensorflow or OpenVINO) or GPU (with Tensorflow GPU).
|
||||
* It supports next classes (just specify them in "labels" row):
|
||||
```
|
||||
'surfboard', 'car', 'skateboard', 'boat', 'clock',
|
||||
'cat', 'cow', 'knife', 'apple', 'cup', 'tv',
|
||||
'baseball_bat', 'book', 'suitcase', 'tennis_racket',
|
||||
'stop_sign', 'couch', 'cell_phone', 'keyboard',
|
||||
'cake', 'tie', 'frisbee', 'truck', 'fire_hydrant',
|
||||
'snowboard', 'bed', 'vase', 'teddy_bear',
|
||||
'toaster', 'wine_glass', 'traffic_light',
|
||||
'broccoli', 'backpack', 'carrot', 'potted_plant',
|
||||
'donut', 'umbrella', 'parking_meter', 'bottle',
|
||||
'sandwich', 'motorcycle', 'bear', 'banana',
|
||||
'person', 'scissors', 'elephant', 'dining_table',
|
||||
'toothbrush', 'toilet', 'skis', 'bowl', 'sheep',
|
||||
'refrigerator', 'oven', 'microwave', 'train',
|
||||
'orange', 'mouse', 'laptop', 'bench', 'bicycle',
|
||||
'fork', 'kite', 'zebra', 'baseball_glove', 'bus',
|
||||
'spoon', 'horse', 'handbag', 'pizza', 'sports_ball',
|
||||
'airplane', 'hair_drier', 'hot_dog', 'remote',
|
||||
'sink', 'dog', 'bird', 'giraffe', 'chair'.
|
||||
```
|
||||
* Component adds "Run TF Annotation" button into dashboard.
|
||||
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/tf_annotation/docker-compose.tf_annotation.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/tf_annotation/docker-compose.tf_annotation.yml up -d
|
||||
```
|
||||
@ -0,0 +1,13 @@
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
version: "2.3"
|
||||
|
||||
services:
|
||||
cvat:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
TF_ANNOTATION: "yes"
|
||||
@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
set -e
|
||||
|
||||
cd ${HOME} && \
|
||||
wget -O model.tar.gz http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_resnet_v2_atrous_coco_2018_01_28.tar.gz && \
|
||||
tar -xzf model.tar.gz && rm model.tar.gz && \
|
||||
mv faster_rcnn_inception_resnet_v2_atrous_coco_2018_01_28 ${HOME}/rcnn && cd ${HOME} && \
|
||||
mv rcnn/frozen_inference_graph.pb rcnn/inference_graph.pb
|
||||
|
||||
if [[ "$CUDA_SUPPORT" = "yes" ]]
|
||||
then
|
||||
pip3 install --no-cache-dir tensorflow-gpu==1.7.0
|
||||
else
|
||||
if [[ "$OPENVINO_TOOLKIT" = "yes" ]]
|
||||
then
|
||||
pip3 install -r ${INTEL_CVSDK_DIR}/deployment_tools/model_optimizer/requirements.txt && \
|
||||
cd ${HOME}/rcnn/ && \
|
||||
${INTEL_CVSDK_DIR}/deployment_tools/model_optimizer/mo.py --framework tf \
|
||||
--data_type FP32 --input_shape [1,600,600,3] \
|
||||
--input image_tensor --output detection_scores,detection_boxes,num_detections \
|
||||
--tensorflow_use_custom_operations_config ${INTEL_CVSDK_DIR}/deployment_tools/model_optimizer/extensions/front/tf/faster_rcnn_support.json \
|
||||
--tensorflow_object_detection_api_pipeline_config pipeline.config --input_model inference_graph.pb && \
|
||||
rm inference_graph.pb
|
||||
else
|
||||
pip3 install --no-cache-dir tensorflow==1.7.0
|
||||
fi
|
||||
fi
|
||||
@ -0,0 +1,80 @@
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
from django.conf import settings
|
||||
import rules
|
||||
from . import AUTH_ROLE
|
||||
|
||||
def register_signals():
|
||||
from django.db.models.signals import post_migrate, post_save
|
||||
from django.contrib.auth.models import User, Group
|
||||
|
||||
def create_groups(sender, **kwargs):
|
||||
for role in AUTH_ROLE:
|
||||
db_group, _ = Group.objects.get_or_create(name=role)
|
||||
db_group.save()
|
||||
|
||||
post_migrate.connect(create_groups, weak=False)
|
||||
|
||||
if settings.DJANGO_AUTH_TYPE == 'BASIC':
|
||||
from .auth_basic import create_user
|
||||
|
||||
post_save.connect(create_user, sender=User)
|
||||
elif settings.DJANGO_AUTH_TYPE == 'LDAP':
|
||||
import django_auth_ldap.backend
|
||||
from .auth_ldap import create_user
|
||||
|
||||
django_auth_ldap.backend.populate_user.connect(create_user)
|
||||
|
||||
# AUTH PREDICATES
|
||||
has_admin_role = rules.is_group_member(str(AUTH_ROLE.ADMIN))
|
||||
has_user_role = rules.is_group_member(str(AUTH_ROLE.USER))
|
||||
has_annotator_role = rules.is_group_member(str(AUTH_ROLE.ANNOTATOR))
|
||||
has_observer_role = rules.is_group_member(str(AUTH_ROLE.OBSERVER))
|
||||
|
||||
@rules.predicate
|
||||
def is_task_owner(db_user, db_task):
|
||||
# If owner is None (null) the task can be accessed/changed/deleted
|
||||
# only by admin. At the moment each task has an owner.
|
||||
return db_task.owner == db_user
|
||||
|
||||
@rules.predicate
|
||||
def is_task_assignee(db_user, db_task):
|
||||
return db_task.assignee == db_user
|
||||
|
||||
@rules.predicate
|
||||
def is_task_annotator(db_user, db_task):
|
||||
from functools import reduce
|
||||
|
||||
db_segments = list(db_task.segment_set.prefetch_related('job_set__assignee').all())
|
||||
return any([is_job_annotator(db_user, db_job)
|
||||
for db_segment in db_segments for db_job in db_segment.job_set.all()])
|
||||
|
||||
@rules.predicate
|
||||
def is_job_owner(db_user, db_job):
|
||||
return is_task_owner(db_user, db_job.segment.task)
|
||||
|
||||
@rules.predicate
|
||||
def is_job_annotator(db_user, db_job):
|
||||
db_task = db_job.segment.task
|
||||
# A job can be annotated by any user if the task's assignee is None.
|
||||
has_rights = db_task.assignee is None or is_task_assignee(db_user, db_task)
|
||||
if db_job.assignee is not None:
|
||||
has_rights |= (db_user == db_job.assignee)
|
||||
|
||||
return has_rights
|
||||
|
||||
# AUTH PERMISSIONS RULES
|
||||
rules.add_perm('engine.task.create', has_admin_role | has_user_role)
|
||||
rules.add_perm('engine.task.access', has_admin_role | has_observer_role |
|
||||
is_task_owner | is_task_annotator)
|
||||
rules.add_perm('engine.task.change', has_admin_role | is_task_owner |
|
||||
is_task_assignee)
|
||||
rules.add_perm('engine.task.delete', has_admin_role | is_task_owner)
|
||||
|
||||
rules.add_perm('engine.job.access', has_admin_role | has_observer_role |
|
||||
is_job_owner | is_job_annotator)
|
||||
rules.add_perm('engine.job.change', has_admin_role | is_job_owner |
|
||||
is_job_annotator)
|
||||
@ -0,0 +1,12 @@
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
from . import AUTH_ROLE
|
||||
from django.conf import settings
|
||||
|
||||
def create_user(sender, instance, created, **kwargs):
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
if instance.is_superuser and instance.is_staff:
|
||||
db_group = Group.objects.get(name=AUTH_ROLE.ADMIN)
|
||||
instance.groups.add(db_group)
|
||||
@ -0,0 +1,33 @@
|
||||
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from django.conf import settings
|
||||
from . import AUTH_ROLE
|
||||
|
||||
AUTH_LDAP_GROUPS = {
|
||||
AUTH_ROLE.ADMIN: settings.AUTH_LDAP_ADMIN_GROUPS,
|
||||
AUTH_ROLE.ANNOTATOR: settings.AUTH_LDAP_ANNOTATOR_GROUPS,
|
||||
AUTH_ROLE.USER: settings.AUTH_LDAP_USER_GROUPS,
|
||||
AUTH_ROLE.OBSERVER: settings.AUTH_LDAP_OBSERVER_GROUPS
|
||||
}
|
||||
|
||||
def create_user(sender, user=None, ldap_user=None, **kwargs):
|
||||
from django.contrib.auth.models import Group
|
||||
user_groups = []
|
||||
for role in AUTH_ROLE:
|
||||
db_group = Group.objects.get(name=role)
|
||||
|
||||
for ldap_group in AUTH_LDAP_GROUPS[role]:
|
||||
if ldap_group.lower() in ldap_user.group_dns:
|
||||
user_groups.append(db_group)
|
||||
if role == AUTH_ROLE.ADMIN:
|
||||
user.is_staff = user.is_superuser = True
|
||||
|
||||
# It is important to save the user before adding groups. Please read
|
||||
# https://django-auth-ldap.readthedocs.io/en/latest/users.html#populating-users
|
||||
# The user instance will be saved automatically after the signal handler
|
||||
# is run.
|
||||
user.save()
|
||||
user.groups.set(user_groups)
|
||||
@ -1,5 +0,0 @@
|
||||
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from django.conf import settings
|
||||
import ldap
|
||||
from django_auth_ldap.config import LDAPSearch, NestedActiveDirectoryGroupType
|
||||
|
||||
# Baseline configuration.
|
||||
settings.AUTH_LDAP_SERVER_URI = ""
|
||||
|
||||
# Credentials for LDAP server
|
||||
settings.AUTH_LDAP_BIND_DN = ""
|
||||
settings.AUTH_LDAP_BIND_PASSWORD = ""
|
||||
|
||||
# Set up basic user search
|
||||
settings.AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=example,dc=com",
|
||||
ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)")
|
||||
|
||||
# Set up the basic group parameters.
|
||||
settings.AUTH_LDAP_GROUP_SEARCH = LDAPSearch("dc=example,dc=com",
|
||||
ldap.SCOPE_SUBTREE, "(objectClass=group)")
|
||||
settings.AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()
|
||||
|
||||
# # Simple group restrictions
|
||||
settings.AUTH_LDAP_REQUIRE_GROUP = "cn=cvat,ou=Groups,dc=example,dc=com"
|
||||
|
||||
# Populate the Django user from the LDAP directory.
|
||||
settings.AUTH_LDAP_USER_ATTR_MAP = {
|
||||
"first_name": "givenName",
|
||||
"last_name": "sn",
|
||||
"email": "mail",
|
||||
}
|
||||
|
||||
settings.AUTH_LDAP_ALWAYS_UPDATE_USER = True
|
||||
|
||||
# Cache group memberships for an hour to minimize LDAP traffic
|
||||
settings.AUTH_LDAP_CACHE_GROUPS = True
|
||||
settings.AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600
|
||||
settings.AUTH_LDAP_AUTHORIZE_ALL_USERS = True
|
||||
|
||||
# Keep ModelBackend around for per-user permissions and maybe a local
|
||||
# superuser.
|
||||
settings.AUTHENTICATION_BACKENDS.append('django_auth_ldap.backend.LDAPBackend')
|
||||
|
||||
AUTH_LDAP_ADMIN_GROUPS = [
|
||||
"cn=cvat_admins,ou=Groups,dc=example,dc=com"
|
||||
]
|
||||
|
||||
AUTH_LDAP_DATA_ANNOTATORS_GROUPS = [
|
||||
]
|
||||
|
||||
AUTH_LDAP_DEVELOPER_GROUPS = [
|
||||
"cn=cvat_users,ou=Groups,dc=example,dc=com"
|
||||
]
|
||||
@ -1,8 +0,0 @@
|
||||
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Specify groups that new users will have
|
||||
AUTH_SIMPLE_DEFAULT_GROUPS = []
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from django.conf import settings
|
||||
import os
|
||||
|
||||
settings.LOGIN_URL = 'login'
|
||||
settings.LOGIN_REDIRECT_URL = '/'
|
||||
|
||||
settings.AUTHENTICATION_BACKENDS = [
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
]
|
||||
|
||||
AUTH_LDAP_DEVELOPER_GROUPS = []
|
||||
AUTH_LDAP_DATA_ANNOTATORS_GROUPS = []
|
||||
AUTH_LDAP_ADMIN_GROUPS = []
|
||||
|
||||
DJANGO_AUTH_TYPE = 'LDAP' if os.environ.get('DJANGO_AUTH_TYPE', '') == 'LDAP' else 'SIMPLE'
|
||||
|
||||
if DJANGO_AUTH_TYPE == 'LDAP':
|
||||
from .auth_ldap import *
|
||||
else:
|
||||
from .auth_simple import *
|
||||
|
||||
# Definition of CVAT groups with permissions for task and annotation objects
|
||||
# Annotator - can modify annotation for task, but cannot add, change and delete tasks
|
||||
# Developer - can create tasks and modify (delete) owned tasks and any actions with annotation
|
||||
# Admin - can any actions for task and annotation, can login to admin area and manage groups and users
|
||||
cvat_groups_definition = {
|
||||
'user': {
|
||||
'description': '',
|
||||
'permissions': {
|
||||
'task': ['view', 'add', 'change', 'delete'],
|
||||
'annotation': ['view', 'change'],
|
||||
},
|
||||
'ldap_groups': AUTH_LDAP_DEVELOPER_GROUPS,
|
||||
},
|
||||
|
||||
'annotator': {
|
||||
'description': '',
|
||||
'permissions': {
|
||||
'task': ['view'],
|
||||
'annotation': ['view', 'change'],
|
||||
},
|
||||
'ldap_groups': AUTH_LDAP_DATA_ANNOTATORS_GROUPS,
|
||||
},
|
||||
|
||||
'admin': {
|
||||
'description': '',
|
||||
'permissions': {
|
||||
'task': ['view', 'add', 'change', 'delete'],
|
||||
'annotation': ['view', 'change'],
|
||||
},
|
||||
'ldap_groups': AUTH_LDAP_ADMIN_GROUPS,
|
||||
},
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from django.db import models
|
||||
|
||||
from django.conf import settings
|
||||
from .settings import authentication
|
||||
from django.contrib.auth.models import User, Group
|
||||
|
||||
def setup_group_permissions(group):
|
||||
from cvat.apps.engine.models import Task
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
def append_permissions_for_model(model):
|
||||
content_type = ContentType.objects.get_for_model(model)
|
||||
for perm_target, actions in authentication.cvat_groups_definition[group.name]['permissions'].items():
|
||||
for action in actions:
|
||||
codename = '{}_{}'.format(action, perm_target)
|
||||
try:
|
||||
perm = Permission.objects.get(codename=codename, content_type=content_type)
|
||||
group_permissions.append(perm)
|
||||
except:
|
||||
pass
|
||||
group_permissions = []
|
||||
append_permissions_for_model(Task)
|
||||
|
||||
group.permissions.set(group_permissions)
|
||||
group.save()
|
||||
|
||||
def create_groups(sender, **kwargs):
|
||||
for cvat_role, _ in authentication.cvat_groups_definition.items():
|
||||
Group.objects.get_or_create(name=cvat_role)
|
||||
|
||||
def update_ldap_groups(sender, user=None, ldap_user=None, **kwargs):
|
||||
user_groups = []
|
||||
for cvat_role, role_settings in authentication.cvat_groups_definition.items():
|
||||
group_instance, _ = Group.objects.get_or_create(name=cvat_role)
|
||||
setup_group_permissions(group_instance)
|
||||
|
||||
for ldap_group in role_settings['ldap_groups']:
|
||||
if ldap_group.lower() in ldap_user.group_dns:
|
||||
user_groups.append(group_instance)
|
||||
|
||||
user.save()
|
||||
user.groups.set(user_groups)
|
||||
user.is_staff = user.is_superuser = user.groups.filter(name='admin').exists()
|
||||
|
||||
def create_user(sender, instance, created, **kwargs):
|
||||
if instance.is_superuser and instance.is_staff:
|
||||
admin_group, _ = Group.objects.get_or_create(name='admin')
|
||||
admin_group.user_set.add(instance)
|
||||
|
||||
if created:
|
||||
for cvat_role, _ in authentication.cvat_groups_definition.items():
|
||||
group_instance, _ = Group.objects.get_or_create(name=cvat_role)
|
||||
setup_group_permissions(group_instance)
|
||||
|
||||
if cvat_role in authentication.AUTH_SIMPLE_DEFAULT_GROUPS:
|
||||
instance.groups.add(group_instance)
|
||||
@ -1,27 +0,0 @@
|
||||
<!--
|
||||
Copyright (C) 2018 Intel Corporation
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
-->
|
||||
{% extends "auth_base.html" %}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Login</h1>
|
||||
{% if form.errors %}
|
||||
<small>Your username and password didn't match. Please try again.</small>
|
||||
{% endif %}
|
||||
<form method="post" action="{% url 'login' %}">
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
<button type="submit" class="btn btn-primary btn-block btn-large">Login</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block note %}
|
||||
{% include "note.html" %}
|
||||
{% endblock %}
|
||||
@ -1,7 +0,0 @@
|
||||
<!--
|
||||
Copyright (C) 2018 Intel Corporation
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
-->
|
||||
<p>
|
||||
</p>
|
||||
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
$(`<button class="menuButton semiBold h2"> Open Task </button>`).on('click', () => {
|
||||
let win = window.open(`${window.location.origin }/dashboard/?jid=${window.cvat.job.id}`, '_blank');
|
||||
win.focus();
|
||||
}).prependTo('#engineMenuButtons');
|
||||
});
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
### AWS-Deployment Guide
|
||||
|
||||
There are two ways of deploying the CVAT.
|
||||
1. **On Nvidia GPU Machine:** Tensorflow annotation feature is dependent on GPU hardware. One of the easy ways to launch CVAT with the tf-annotation app is to use AWS P3 instances, which provides the NVIDIA GPU. Read more about [P3 instances here.](https://aws.amazon.com/about-aws/whats-new/2017/10/introducing-amazon-ec2-p3-instances/)
|
||||
Overall setup instruction is explained in [main readme file](https://github.com/opencv/cvat/), except Installing Nvidia drivers. So we need to download the drivers and install it. For Amazon P3 instances, download the Nvidia Drivers from Nvidia website. For more check [Installing the NVIDIA Driver on Linux Instances](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/install-nvidia-driver.html) link.
|
||||
|
||||
2. **On Any other AWS Machine:** We can follow the same instruction guide mentioned in the [Readme file](https://github.com/opencv/cvat/). The additional step is to add a [security group and rule to allow incoming connections](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html).
|
||||
|
||||
For any of above, don't forget to add exposed AWS public IP address to `docker-compose.override.com`.
|
||||
|
Before Width: | Height: | Size: 4.9 MiB After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 326 KiB |
|
After Width: | Height: | Size: 321 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 425 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 163 KiB |
@ -0,0 +1,100 @@
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import logging
|
||||
from cvat.settings.base import LOGGING
|
||||
from .models import Job, Task
|
||||
|
||||
def _get_task(tid):
|
||||
try:
|
||||
return Task.objects.get(pk=tid)
|
||||
except Exception:
|
||||
raise Exception('{} key must be a task identifier'.format(tid))
|
||||
|
||||
def _get_job(jid):
|
||||
try:
|
||||
return Job.objects.select_related("segment__task").get(id=jid)
|
||||
except Exception:
|
||||
raise Exception('{} key must be a job identifier'.format(jid))
|
||||
|
||||
class TaskLoggerStorage:
|
||||
def __init__(self):
|
||||
self._storage = dict()
|
||||
|
||||
def __getitem__(self, tid):
|
||||
if tid not in self._storage:
|
||||
self._storage[tid] = self._create_task_logger(tid)
|
||||
return self._storage[tid]
|
||||
|
||||
def _create_task_logger(self, tid):
|
||||
task = _get_task(tid)
|
||||
|
||||
logger = logging.getLogger('cvat.server.task_{}'.format(tid))
|
||||
server_file = logging.FileHandler(filename=task.get_log_path())
|
||||
formatter = logging.Formatter(LOGGING['formatters']['standard']['format'])
|
||||
server_file.setFormatter(formatter)
|
||||
logger.addHandler(server_file)
|
||||
|
||||
return logger
|
||||
|
||||
class JobLoggerStorage:
|
||||
def __init__(self):
|
||||
self._storage = dict()
|
||||
|
||||
def __getitem__(self, jid):
|
||||
if jid not in self._storage:
|
||||
self._storage[jid] = self._get_task_logger(jid)
|
||||
return self._storage[jid]
|
||||
|
||||
def _get_task_logger(self, jid):
|
||||
job = _get_job(jid)
|
||||
return slogger.task[job.segment.task.id]
|
||||
|
||||
class TaskClientLoggerStorage:
|
||||
def __init__(self):
|
||||
self._storage = dict()
|
||||
|
||||
def __getitem__(self, tid):
|
||||
if tid not in self._storage:
|
||||
self._storage[tid] = self._create_client_logger(tid)
|
||||
return self._storage[tid]
|
||||
|
||||
def _create_client_logger(self, tid):
|
||||
task = _get_task(tid)
|
||||
logger = logging.getLogger('cvat.client.task_{}'.format(tid))
|
||||
client_file = logging.FileHandler(filename=task.get_client_log_path())
|
||||
logger.addHandler(client_file)
|
||||
|
||||
return logger
|
||||
|
||||
class JobClientLoggerStorage:
|
||||
def __init__(self):
|
||||
self._storage = dict()
|
||||
|
||||
def __getitem__(self, jid):
|
||||
if jid not in self._storage:
|
||||
self._storage[jid] = self._get_task_logger(jid)
|
||||
return self._storage[jid]
|
||||
|
||||
def _get_task_logger(self, jid):
|
||||
job = _get_job(jid)
|
||||
return clogger.task[job.segment.task.id]
|
||||
|
||||
class dotdict(dict):
|
||||
"""dot.notation access to dictionary attributes"""
|
||||
__getattr__ = dict.get
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__
|
||||
|
||||
clogger = dotdict({
|
||||
'task': TaskClientLoggerStorage(),
|
||||
'job': JobClientLoggerStorage()
|
||||
})
|
||||
|
||||
slogger = dotdict({
|
||||
'task': TaskLoggerStorage(),
|
||||
'job': JobLoggerStorage(),
|
||||
'glob': logging.getLogger('cvat.server'),
|
||||
})
|
||||
@ -1,75 +0,0 @@
|
||||
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import inspect
|
||||
import logging
|
||||
from . import models
|
||||
from cvat.settings.base import LOGGING
|
||||
|
||||
|
||||
class TaskLoggerStorage:
|
||||
def __init__(self):
|
||||
self._storage = dict()
|
||||
self._formatter = logging.getLogger('task')
|
||||
|
||||
def __getitem__(self, tid):
|
||||
if tid not in self._storage:
|
||||
self._storage[tid] = self._create_task_logger(tid)
|
||||
return self._storage[tid]
|
||||
|
||||
def _create_task_logger(self, tid):
|
||||
task = self._get_task(tid)
|
||||
if task is not None:
|
||||
configuration = LOGGING.copy()
|
||||
handler_configuration = configuration['handlers']['file']
|
||||
handler_configuration['filename'] = task.get_log_path()
|
||||
configuration['handlers'] = {
|
||||
'file_{}'.format(tid): handler_configuration
|
||||
}
|
||||
configuration['loggers'] = {
|
||||
'task_{}'.format(tid): {
|
||||
'handlers': ['file_{}'.format(tid)],
|
||||
'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),
|
||||
}
|
||||
}
|
||||
|
||||
logging.config.dictConfig(configuration)
|
||||
logger = logging.getLogger('task_{}'.format(tid))
|
||||
return logger
|
||||
else:
|
||||
raise Exception('Key must be task indentificator')
|
||||
|
||||
def _get_task(self, tid):
|
||||
try:
|
||||
return models.Task.objects.get(pk=tid)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
class JobLoggerStorage:
|
||||
def __init__(self):
|
||||
self._storage = dict()
|
||||
|
||||
def __getitem__(self, jid):
|
||||
if jid not in self._storage:
|
||||
self._storage[jid] = self._get_task_logger(jid)
|
||||
return self._storage[jid]
|
||||
|
||||
def _get_task_logger(self, jid):
|
||||
job = self._get_job(jid)
|
||||
if job is not None:
|
||||
return task_logger[job.segment.task.id]
|
||||
else:
|
||||
raise Exception('Key must be job identificator')
|
||||
|
||||
def _get_job(self, jid):
|
||||
try:
|
||||
return models.Job.objects.select_related("segment__task").get(id=jid)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
task_logger = TaskLoggerStorage()
|
||||
job_logger = JobLoggerStorage()
|
||||
@ -0,0 +1,38 @@
|
||||
# Generated by Django 2.0.9 on 2018-10-11 12:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('engine', '0009_auto_20180917_1424'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='labeledbox',
|
||||
name='client_id',
|
||||
field=models.BigIntegerField(default=-1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='labeledpoints',
|
||||
name='client_id',
|
||||
field=models.BigIntegerField(default=-1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='labeledpolygon',
|
||||
name='client_id',
|
||||
field=models.BigIntegerField(default=-1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='labeledpolyline',
|
||||
name='client_id',
|
||||
field=models.BigIntegerField(default=-1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='objectpath',
|
||||
name='client_id',
|
||||
field=models.BigIntegerField(default=-1),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,74 @@
|
||||
# Generated by Django 2.0.9 on 2018-10-24 10:50
|
||||
|
||||
import cvat.apps.engine.models
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('engine', '0010_auto_20181011_1517'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='task',
|
||||
name='source',
|
||||
field=cvat.apps.engine.models.SafeCharField(default='unknown', max_length=256),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='label',
|
||||
name='name',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='labeledboxattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='labeledpointsattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='labeledpolygonattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='labeledpolylineattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='objectpathattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='task',
|
||||
name='name',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=256),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trackedboxattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trackedpointsattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trackedpolygonattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trackedpolylineattributeval',
|
||||
name='value',
|
||||
field=cvat.apps.engine.models.SafeCharField(max_length=64),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,24 @@
|
||||
# Generated by Django 2.0.9 on 2018-10-25 13:18
|
||||
|
||||
import cvat.apps.engine.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('engine', '0011_add_task_source_and_safecharfield'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='job',
|
||||
name='status',
|
||||
field=models.CharField(default=cvat.apps.engine.models.StatusChoice('annotation'), max_length=32),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='task',
|
||||
name='status',
|
||||
field=models.CharField(default=cvat.apps.engine.models.StatusChoice('annotation'), max_length=32),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,118 @@
|
||||
# Generated by Django 2.0.9 on 2018-11-07 12:25
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('engine', '0012_auto_20181025_1618'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='attributespec',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='job',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='label',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='labeledboxattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='labeledpointsattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='labeledpolygonattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='labeledpolylineattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='objectpathattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='segment',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='task',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedbox',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedboxattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedpoints',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedpointsattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedpolygon',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedpolygonattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedpolyline',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='trackedpolylineattributeval',
|
||||
options={'default_permissions': ()},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='job',
|
||||
old_name='annotator',
|
||||
new_name='assignee',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='task',
|
||||
name='assignee',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assignees', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='task',
|
||||
name='owner',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owners', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='job',
|
||||
name='assignee',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='task',
|
||||
name='bug_tracker',
|
||||
field=models.CharField(blank=True, default='', max_length=2000),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='task',
|
||||
name='owner',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owners', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.3 on 2018-11-23 10:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('engine', '0013_auth_no_default_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='job',
|
||||
name='max_shape_id',
|
||||
field=models.BigIntegerField(default=-1),
|
||||
),
|
||||
]
|
||||
@ -1,280 +0,0 @@
|
||||
/*
|
||||
* JavaScript MD5
|
||||
* https://github.com/blueimp/JavaScript-MD5
|
||||
*
|
||||
* Copyright 2011, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
* Based on
|
||||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
* Distributed under the BSD License
|
||||
* See http://pajhome.org.uk/crypt/md5 for more info.
|
||||
*/
|
||||
|
||||
/* global define */
|
||||
|
||||
;(function ($) {
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||||
* to work around bugs in some JS interpreters.
|
||||
*/
|
||||
function safeAdd (x, y) {
|
||||
var lsw = (x & 0xffff) + (y & 0xffff)
|
||||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
|
||||
return (msw << 16) | (lsw & 0xffff)
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
function bitRotateLeft (num, cnt) {
|
||||
return (num << cnt) | (num >>> (32 - cnt))
|
||||
}
|
||||
|
||||
/*
|
||||
* These functions implement the four basic operations the algorithm uses.
|
||||
*/
|
||||
function md5cmn (q, a, b, x, s, t) {
|
||||
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b)
|
||||
}
|
||||
function md5ff (a, b, c, d, x, s, t) {
|
||||
return md5cmn((b & c) | (~b & d), a, b, x, s, t)
|
||||
}
|
||||
function md5gg (a, b, c, d, x, s, t) {
|
||||
return md5cmn((b & d) | (c & ~d), a, b, x, s, t)
|
||||
}
|
||||
function md5hh (a, b, c, d, x, s, t) {
|
||||
return md5cmn(b ^ c ^ d, a, b, x, s, t)
|
||||
}
|
||||
function md5ii (a, b, c, d, x, s, t) {
|
||||
return md5cmn(c ^ (b | ~d), a, b, x, s, t)
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the MD5 of an array of little-endian words, and a bit length.
|
||||
*/
|
||||
function binlMD5 (x, len) {
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << (len % 32)
|
||||
x[((len + 64) >>> 9 << 4) + 14] = len
|
||||
|
||||
var i
|
||||
var olda
|
||||
var oldb
|
||||
var oldc
|
||||
var oldd
|
||||
var a = 1732584193
|
||||
var b = -271733879
|
||||
var c = -1732584194
|
||||
var d = 271733878
|
||||
|
||||
for (i = 0; i < x.length; i += 16) {
|
||||
olda = a
|
||||
oldb = b
|
||||
oldc = c
|
||||
oldd = d
|
||||
|
||||
a = md5ff(a, b, c, d, x[i], 7, -680876936)
|
||||
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586)
|
||||
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819)
|
||||
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330)
|
||||
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897)
|
||||
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426)
|
||||
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341)
|
||||
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983)
|
||||
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416)
|
||||
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417)
|
||||
c = md5ff(c, d, a, b, x[i + 10], 17, -42063)
|
||||
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162)
|
||||
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682)
|
||||
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101)
|
||||
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290)
|
||||
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329)
|
||||
|
||||
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510)
|
||||
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632)
|
||||
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713)
|
||||
b = md5gg(b, c, d, a, x[i], 20, -373897302)
|
||||
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691)
|
||||
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083)
|
||||
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335)
|
||||
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848)
|
||||
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438)
|
||||
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690)
|
||||
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961)
|
||||
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501)
|
||||
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467)
|
||||
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784)
|
||||
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473)
|
||||
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734)
|
||||
|
||||
a = md5hh(a, b, c, d, x[i + 5], 4, -378558)
|
||||
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463)
|
||||
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562)
|
||||
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556)
|
||||
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060)
|
||||
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353)
|
||||
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632)
|
||||
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640)
|
||||
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174)
|
||||
d = md5hh(d, a, b, c, x[i], 11, -358537222)
|
||||
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979)
|
||||
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189)
|
||||
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487)
|
||||
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835)
|
||||
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520)
|
||||
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651)
|
||||
|
||||
a = md5ii(a, b, c, d, x[i], 6, -198630844)
|
||||
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415)
|
||||
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905)
|
||||
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055)
|
||||
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571)
|
||||
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606)
|
||||
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523)
|
||||
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799)
|
||||
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359)
|
||||
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744)
|
||||
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380)
|
||||
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649)
|
||||
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070)
|
||||
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379)
|
||||
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259)
|
||||
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551)
|
||||
|
||||
a = safeAdd(a, olda)
|
||||
b = safeAdd(b, oldb)
|
||||
c = safeAdd(c, oldc)
|
||||
d = safeAdd(d, oldd)
|
||||
}
|
||||
return [a, b, c, d]
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an array of little-endian words to a string
|
||||
*/
|
||||
function binl2rstr (input) {
|
||||
var i
|
||||
var output = ''
|
||||
var length32 = input.length * 32
|
||||
for (i = 0; i < length32; i += 8) {
|
||||
output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a raw string to an array of little-endian words
|
||||
* Characters >255 have their high-byte silently ignored.
|
||||
*/
|
||||
function rstr2binl (input) {
|
||||
var i
|
||||
var output = []
|
||||
output[(input.length >> 2) - 1] = undefined
|
||||
for (i = 0; i < output.length; i += 1) {
|
||||
output[i] = 0
|
||||
}
|
||||
var length8 = input.length * 8
|
||||
for (i = 0; i < length8; i += 8) {
|
||||
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the MD5 of a raw string
|
||||
*/
|
||||
function rstrMD5 (s) {
|
||||
return binl2rstr(binlMD5(rstr2binl(s), s.length * 8))
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the HMAC-MD5, of a key and some data (raw strings)
|
||||
*/
|
||||
function rstrHMACMD5 (key, data) {
|
||||
var i
|
||||
var bkey = rstr2binl(key)
|
||||
var ipad = []
|
||||
var opad = []
|
||||
var hash
|
||||
ipad[15] = opad[15] = undefined
|
||||
if (bkey.length > 16) {
|
||||
bkey = binlMD5(bkey, key.length * 8)
|
||||
}
|
||||
for (i = 0; i < 16; i += 1) {
|
||||
ipad[i] = bkey[i] ^ 0x36363636
|
||||
opad[i] = bkey[i] ^ 0x5c5c5c5c
|
||||
}
|
||||
hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8)
|
||||
return binl2rstr(binlMD5(opad.concat(hash), 512 + 128))
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a raw string to a hex string
|
||||
*/
|
||||
function rstr2hex (input) {
|
||||
var hexTab = '0123456789abcdef'
|
||||
var output = ''
|
||||
var x
|
||||
var i
|
||||
for (i = 0; i < input.length; i += 1) {
|
||||
x = input.charCodeAt(i)
|
||||
output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode a string as utf-8
|
||||
*/
|
||||
function str2rstrUTF8 (input) {
|
||||
return unescape(encodeURIComponent(input))
|
||||
}
|
||||
|
||||
/*
|
||||
* Take string arguments and return either raw or hex encoded strings
|
||||
*/
|
||||
function rawMD5 (s) {
|
||||
return rstrMD5(str2rstrUTF8(s))
|
||||
}
|
||||
function hexMD5 (s) {
|
||||
return rstr2hex(rawMD5(s))
|
||||
}
|
||||
function rawHMACMD5 (k, d) {
|
||||
return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d))
|
||||
}
|
||||
function hexHMACMD5 (k, d) {
|
||||
return rstr2hex(rawHMACMD5(k, d))
|
||||
}
|
||||
|
||||
function md5 (string, key, raw) {
|
||||
if (!key) {
|
||||
if (!raw) {
|
||||
return hexMD5(string)
|
||||
}
|
||||
return rawMD5(string)
|
||||
}
|
||||
if (!raw) {
|
||||
return hexHMACMD5(key, string)
|
||||
}
|
||||
return rawHMACMD5(key, string)
|
||||
}
|
||||
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(function () {
|
||||
return md5
|
||||
})
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
module.exports = md5
|
||||
} else {
|
||||
$.md5 = md5
|
||||
}
|
||||
})(this)
|
||||
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* exported CoordinateTranslator */
|
||||
"use strict";
|
||||
|
||||
class CoordinateTranslator {
|
||||
constructor() {
|
||||
this._boxTranslator = {
|
||||
_playerOffset: 0,
|
||||
_convert: function(box, sign) {
|
||||
for (let prop of ["xtl", "ytl", "xbr", "ybr", "x", "y"]) {
|
||||
if (prop in box) {
|
||||
box[prop] += this._playerOffset * sign;
|
||||
}
|
||||
}
|
||||
|
||||
return box;
|
||||
},
|
||||
actualToCanvas: function(actualBox) {
|
||||
let canvasBox = {};
|
||||
for (let key in actualBox) {
|
||||
canvasBox[key] = actualBox[key];
|
||||
}
|
||||
|
||||
return this._convert(canvasBox, 1);
|
||||
},
|
||||
|
||||
canvasToActual: function(canvasBox) {
|
||||
let actualBox = {};
|
||||
for (let key in canvasBox) {
|
||||
actualBox[key] = canvasBox[key];
|
||||
}
|
||||
|
||||
return this._convert(actualBox, -1);
|
||||
},
|
||||
};
|
||||
|
||||
this._pointsTranslator = {
|
||||
_playerOffset: 0,
|
||||
_convert: function(points, sign) {
|
||||
if (typeof(points) === 'string') {
|
||||
return points.split(' ').map((coord) => coord.split(',')
|
||||
.map((x) => +x + this._playerOffset * sign).join(',')).join(' ');
|
||||
}
|
||||
else if (typeof(points) === 'object') {
|
||||
let result = [];
|
||||
for (let point of points) {
|
||||
result.push({
|
||||
x: point.x + this._playerOffset * sign,
|
||||
y: point.y + this._playerOffset * sign,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
throw Error('Unknown points type was found');
|
||||
}
|
||||
},
|
||||
actualToCanvas: function(actualPoints) {
|
||||
return this._convert(actualPoints, 1);
|
||||
},
|
||||
|
||||
canvasToActual: function(canvasPoints) {
|
||||
return this._convert(canvasPoints, -1);
|
||||
}
|
||||
},
|
||||
|
||||
this._pointTranslator = {
|
||||
clientToCanvas: function(targetCanvas, clientX, clientY) {
|
||||
let pt = targetCanvas.createSVGPoint();
|
||||
pt.x = clientX;
|
||||
pt.y = clientY;
|
||||
pt = pt.matrixTransform(targetCanvas.getScreenCTM().inverse());
|
||||
return pt;
|
||||
},
|
||||
canvasToClient: function(sourceCanvas, canvasX, canvasY) {
|
||||
let pt = sourceCanvas.createSVGPoint();
|
||||
pt.x = canvasX;
|
||||
pt.y = canvasY;
|
||||
pt = pt.matrixTransform(sourceCanvas.getScreenCTM());
|
||||
return pt;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get box() {
|
||||
return this._boxTranslator;
|
||||
}
|
||||
|
||||
get points() {
|
||||
return this._pointsTranslator;
|
||||
}
|
||||
|
||||
get point() {
|
||||
return this._pointTranslator;
|
||||
}
|
||||
|
||||
set playerOffset(value) {
|
||||
this._boxTranslator._playerOffset = value;
|
||||
this._pointsTranslator._playerOffset = value;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* exported
|
||||
IncrementIdGenerator
|
||||
ConstIdGenerator
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
class IncrementIdGenerator {
|
||||
constructor(startId=0) {
|
||||
this._startId = startId;
|
||||
}
|
||||
|
||||
next() {
|
||||
return this._startId++;
|
||||
}
|
||||
|
||||
reset(startId=0) {
|
||||
this._startId = startId;
|
||||
}
|
||||
}
|
||||
|
||||
class ConstIdGenerator {
|
||||
constructor(startId=-1) {
|
||||
this._startId = startId;
|
||||
}
|
||||
|
||||
next() {
|
||||
return this._startId;
|
||||
}
|
||||
}
|
||||