diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..415d0c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,372 @@ + +# Created by https://www.gitignore.io/api/python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +.venv/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.vcxproj.filters + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ +Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ + +doc/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9b17c6d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,104 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config.python.pythonPath}", + "program": "${file}", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Integrated Terminal/Console", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config.python.pythonPath}", + "program": "${file}", + "console": "integratedTerminal", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit" + ] + }, + { + "name": "External Terminal/Console", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config.python.pythonPath}", + "program": "${file}", + "console": "externalTerminal", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit" + ] + }, + { + "name": "Django", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config.python.pythonPath}", + "program": "${workspaceRoot}/manage.py", + "args": [ + "runserver", + "--noreload" + ], + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput", + "DjangoDebugging" + ] + }, + { + "name": "Flask", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config.python.pythonPath}", + "program": "${workspaceRoot}/run.py", + "args": [], + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Watson", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config.python.pythonPath}", + "program": "${workspaceRoot}/console.py", + "args": [ + "dev", + "runserver", + "--noreload=True" + ], + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Attach (Remote Debug)", + "type": "python", + "request": "attach", + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}", + "port": 3000, + "secret": "my_secret", + "host": "localhost" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..fe71598 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.linting.pylintEnabled": false +} \ No newline at end of file diff --git a/API_DOC.md b/API_DOC.md deleted file mode 100644 index 3cb94c6..0000000 --- a/API_DOC.md +++ /dev/null @@ -1,781 +0,0 @@ -# Ambar Web API v1.2.0 - -Ambar Web API documentation - -- [Files](#files) - - [Get File Meta by File Id](#get-file-meta-by-file-id) - - [Get File Source by File Id](#get-file-source-by-file-id) - - [Get Parsed Text From File by File Id](#get-parsed-text-from-file-by-file-id) - - [Download File Content by Secure Uri](#download-file-content-by-secure-uri) - - [Download Parsed Text by Secure Uri](#download-parsed-text-by-secure-uri) - - [Upload File](#upload-file) - - [Hide File](#hide-file) - - [Unhide File](#unhide-file) - -- [Search](#search) - - [Search For Documents By Query](#search-for-documents-by-query) - - [Retrieve File Highlight by Query and fileId](#retrieve-file-highlight-by-query-and-fileid) - - [Retrieve Full File Highlight by Query and fileId](#retrieve-full-file-highlight-by-query-and-fileid) - -- [Sources](#sources) - - [Get Available Sources](#get-available-sources) - -- [Statistics](#statistics) - - [Get Statistics](#get-statistics) - -- [Tags](#tags) - - [Delete Tag From File](#delete-tag-from-file) - - [Get Tags](#get-tags) - - [Add Tag For File](#add-tag-for-file) - -- [Thumbnails](#thumbnails) - - [Get Thumbnail by Id](#get-thumbnail-by-id) - - [Add or Update Thumbnail](#add-or-update-thumbnail) - -- [Users](#users) - - [Login](#login) - - [Logout](#logout) - - - -# Files - -## Get File Meta by File Id - - - - GET api/files/direct/:fileId/meta - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Success Response - -HTTP/1.1 200 OK - -``` -Octet-Stream -``` -### Error Response - -HTTP/1.1 404 Not Found - -``` -File meta or content not found -``` -## Get File Source by File Id - - - - GET api/files/direct/:fileId/source - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Success Response - -HTTP/1.1 200 OK - -``` -Octet-Stream -``` -### Error Response - -HTTP/1.1 404 Not Found - -``` -File meta or content not found -``` -## Get Parsed Text From File by File Id - - - - GET api/files/direct/:fileId/text - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Success Response - -HTTP/1.1 200 OK - -``` -Octet-Stream -``` -### Error Response - -HTTP/1.1 404 Not Found - -``` -File meta or content not found -``` -## Download File Content by Secure Uri - - - - GET api/files/:uri - - -### Success Response - -HTTP/1.1 200 OK - -``` -Octet-Stream -``` -### Error Response - -HTTP/1.1 404 Not Found - -``` -File meta or content not found -``` -## Download Parsed Text by Secure Uri - - - - GET api/files/:uri/text - - -### Success Response - -HTTP/1.1 200 OK - -``` -Octet-Stream -``` -### Error Response - -HTTP/1.1 404 Not Found - -``` -File meta or content not found -``` -## Upload File - -

New source named uiupload with description Automatically created on UI upload will be created if source didn't exist.

- - POST api/files/uiupload/:filename - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Examples - -Upload File test.txt - -``` -curl -X POST \ -http://ambar_api_address/api/files/uiupload/test.txt \ --H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \ --F file=@test.txt -``` - -### Success Response - -HTTP/1.1 200 OK - -``` -{ "fileId": xxxxx } -``` -### Error Response - -HTTP/1.1 400 Bad Request - -``` -Wrong request data -``` -HTTP/1.1 404 Not Found - -``` -File meta or content not found -``` -## Hide File - -

Hide file by file id

- - PUT api/files/hide/:fileId - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Success Response - -HTTP/1.1 200 OK - -``` -HTTP/1.1 200 OK -``` -### Error Response - -HTTP/1.1 404 NotFound - -``` -File not found -``` -## Unhide File - -

Unhide file by file id

- - PUT api/files/unhide/:fileId - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Success Response - -HTTP/1.1 200 OK - -``` -HTTP/1.1 200 OK -``` -### Error Response - -HTTP/1.1 404 NotFound - -``` -File not found -``` -# Search - -## Search For Documents By Query - - - - GET api/search - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email.

| -| ambar-email-token | String |

User token.

| - -### Parameters - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| query | String |

URI_ENCODED query string. Check details of query syntax here.

| -| page | Number | **optional**

page to return

| -| size | Number | **optional**

number of results to return per page. Maximum is 100.

| - -### Examples - -Search For `John` - -``` -curl -i http://ambar_api_address/api/search?query=John -``` - -### Success Response - -HTTP/1.1 200 OK - -``` - -{ - "total":1, - "hits":[ - { - "sha256":"60a777c59176e98efee98bf16b67983dc981ec4da3eaafcb4d79046d005456f9", - "meta":{ - "id":"ac8965ab5e07582e0e57cde0e7c4c2d49b955f8b26c779903191893fcb942fa4", - "full_name":"//mail.nic.ru/hello@ambar.cloud/linus torvalds talk of tech innovation is bullshit shut up and get the work done fcc chairman wants it to be easier to listen to free fm radio on your smartphone.eml", - "short_name":"linus torvalds talk of tech innovation is bullshit shut up and get the work done fcc chairman wants it to be easier to listen to free fm radio on your smartphone.eml", - "extension":".eml", - "extra":[ - ], - "source_id":"AmbarEmail", - "created_datetime":"2017-02-17 09:22:44.000", - "updated_datetime":"2017-02-17 09:22:44.000", - "download_uri":"b41c4aaa2999ce42957f087db8e7608970efcedb1eaa40c28336390ecb5373849c955f395258f3dfd7482d4b84d543cdfc23cff8df311276a5e111c0504315c60b159cd2fe2cee20c5470789d9d15e4d7e5fb7c2bc60c29bf9a578e47541fb354dcb5109e49ea9019b2d68c3b35e521a418d9c94f0af55dc79c2442188f039c924d0190c72f488ad77647f2a52aaa267" - }, - "indexed_datetime":"2017-05-31 13:36:40.400", - "file_id":"aa5e000fd79cfed0e839af7073e1ef135e128408f984b9a8e70e34242b49f01a", - "content":{ - "size":49282, - "author":"Slashdot Headlines ", - "ocr_performed":false, - "processed_datetime":"2017-05-31 13:36:40.361", - "length":"", - "language":"", - "thumb_available":false, - "state":"processed", - "title":"", - "type":"message/rfc822", - "highlight":{ - "text":[ - "__________________________________________________________________________
Linus Torvalds: Talk of Tech Innovation is Bullshit. Shut Up and Get the Work Done
http://clicks.slashdot.org/ct.html?ufl=6&rtr=on&s=x8pb08,2qzsp,10sc,d9zf,fh0y,9dml,a0z3
Elon Musk Is Really Boring
http://clicks.slashdot.org/ct.html?ufl=6&rtr=on&s=x8pb08,2qzsp,10sc,a5s3,9k63,9dml,a0z3
FCC Chairman Wants It To Be Easier To Listen To Free FM Radio On Your Smartphone
http://clicks.slashdot.org/ct.html?ufl=6&rtr=on&s=x8pb08,2qzsp", - "self-serving. From a report on The Register: The term of art he used was more blunt: \"The innovation the industry talks about so much is... Read More http://clicks.slashdot.org/ct.html?ufl=6&rtr=on&s=x8pb08,2qzsp,10sc,aiki,d8f2,9dml,a0z3
Elon Musk Is Really Boring http://clicks.slashdot.org/ct.html?ufl=6&rtr=on&s=x8pb08,2qzsp,10sc,ezm,35uk,9dml,a0z3
From the boring-company department
Sometimes it is hard to tell if Elon Musk is serious about the things he says. But as for his \"boring\" claims, that's", - "email to: unsubscribe-47676@elabs10.com
Slashdot | 1660 Logan Ave. Ste A | San Diego, CA 92113
To view our Privacy Policy: http://clicks.slashdot.org/ct.html?ufl=6&rtr=on&s=x8pb08,2qzsp,10sc,8pii,7uiv,9dml,a0z3
Elon Musk Is Really Boring | Lost Winston Churchill Essay Reveals His Thoughts On Alien
Life
All the Power of a Windows 10 PC Right In Your Pocket
As the world gets more advanced, technology is getting", - "WiFi and Bluetooth. Plus, with
a wide range of inputs and outputs, you can link with just about any device you want. Learn More!
Linus Torvalds: Talk of Tech Innovation is Bullshit. Shut Up and Get the Work Done
Elon Musk Is Really Boring
FCC Chairman Wants It To Be Easier To Listen To Free FM Radio On Your Smartphone
Lost Winston Churchill Essay Reveals His Thoughts On Alien Life
JavaScript Attack Breaks ASLR On 22 CPU Architectures
Ethicists", - "of innovation is smug, self-congratulatory, and self-serving. From a report on The Register: The term of art he used was more blunt: \"The innovation the industry talks about so much is...
Elon Musk Is Really Boring
From the boring-company department
Sometimes it is hard to tell if Elon Musk is serious about the things he says. But as for his \"boring\" claims, that's really happening. In a wide-range interview with Bloomberg" - ] - } - }, - "tags":[ - ], - "score":1 - } - ], - "took":24.672135 -} -``` -### Error Response - -HTTP/1.1 400 BadRequest - -``` -HTTP/1.1 400 BadRequest -``` -## Retrieve File Highlight by Query and fileId - -

This method is useful for getting higlights of large files > 30 MB

- - GET api/search/:fileId - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email.

| -| ambar-email-token | String |

User token.

| - -### Parameters - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| fileId | String |

file fileId

| -| query | String |

query string

| - -### Examples - -Retrieve Higlights for File with fileId `318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3` - -``` -curl -i http://ambar:8004/api/search/318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3?query=John -``` - -### Success Response - -HTTP/1.1 200 OK - -``` -{ - "highlight": { - "text": [ - "Aesop, by some strange accident it seems to have entirely
disappeared, and to have been lost sight of. His name is
mentioned by Avienus; by Suidas, a celebrated critic, at the
close of the eleventh century, who gives in his lexicon several
isolated verses of his version of the fables; and by John
Tzetzes, a grammarian and poet of Constantinople, who lived
during the latter half of the twelfth century. Nevelet, in the
preface to the volume which we have described, points out that
the Fables of Planudes could not be the work of Aesop, as they
contain a reference in two places to \"Holy" - ] - } -} -``` -### Error Response - -HTTP/1.1 400 BadRequest - -``` -HTTP/1.1 400 BadRequest -``` -## Retrieve Full File Highlight by Query and fileId - -

This method is useful for getting higlights of large files > 30 MB

- - GET api/search/:fileId/full - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email.

| -| ambar-email-token | String |

User token.

| - -### Parameters - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| fileId | String |

file fileId

| -| query | String |

query string

| - -### Examples - -Retrieve Full Higlight for File with fileId `318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3` - -``` -curl -i http://ambar:8004/api/search/318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3/full?query=John -``` - -### Success Response - -HTTP/1.1 200 OK - -``` -Aesop, by some strange accident it seems to have entirely
disappeared, and to have been lost sight of. His name is
mentioned by Avienus; by Suidas, a celebrated critic, at the
close of the eleventh century, who gives in his lexicon several
isolated verses of his version of the fables; and by John
Tzetzes, a grammarian and poet of Constantinople, who lived
during the latter half of the twelfth century. Nevelet, in the
preface to the volume which we have described, points out that
the Fables of Planudes could not be the work of Aesop, as they
contain a reference in two places to Holy -``` -### Error Response - -HTTP/1.1 400 BadRequest - -``` -HTTP/1.1 400 BadRequest -``` -# Sources - -## Get Available Sources - -

Get Available Sources (Crawlers Included)

- - GET api/sources/ - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email.

| -| ambar-email-token | String |

User token.

| - -### Success Response - -HTTP/1.1 200 OK - -``` - [ - { - "id": "Default", - "description": "Automatically created on UI upload", - "type": "bucket" - }, - { - "id": "Books", - "description": "Books crawler", - "type": "crawler" - }, - { - "id": "Dropbox", - "description": "Dropbox Crawler", - "type": "crawler" - } -] -``` -# Statistics - -## Get Statistics - - - - GET api/stats - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Success Response - -HTTP/1.1 200 OK - -``` - { - "contentType": { - "total": 2, - "minThreshold": 0.1, - "data": [ - { - "name": "application/msword", - "value": 1, - "sizeDataInBytes": { - "count": 1, - "min": 91681, - "max": 91681, - "avg": 91681, - "sum": 91681 - } - } - ] - }, - "procRate": { - "data": [ - { - "date": "2017-04-13", - "default": 0 - }, - { - "date": "2017-04-14", - "default": 2 - } - ], - "names": [ - "default" - ] - }, - "procTotal": { - "totalCount": 2, - "sizeDataInBytes": { - "sum": 147522, - "avg": 73761, - "min": 55841, - "max": 91681 - } - } -} -``` -# Tags - -## Delete Tag From File - - - - DELETE api/tags/:fileId/:tagType/:tagName - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Parameters - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| fileId | String |

File Id to delete tag from.

| -| tagType | String |

Tag type to delete.

| -| tagName | String |

Tag name to delete.

| - -### Success Response - -HTTP/1.1 200 OK - -``` -{ - "tags":[ - { - "name":"ocr", - "filesCount":3 - }, - { - "name":"test", - "filesCount":2 - }, - { - "name":"pdf", - "filesCount":1 - } - ] -} -``` -## Get Tags - - - - GET api/tags/ - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Success Response - -HTTP/1.1 200 OK - -``` -[ - { - "name":"ocr", - "filesCount":3 - }, - { - "name":"test", - "filesCount":2 - }, - { - "name":"pdf", - "filesCount":1 - } -] -``` -## Add Tag For File - - - - POST api/tags/:fileId/:tagType/:tagName - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Parameters - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| fileId | String |

File Id to add tag to.

| -| tagType | String |

Tag type to add.

| -| tagName | String |

Tag name to add.

| - -### Success Response - -HTTP/1.1 200 OK - -``` -{ - "tagId":"e9536a83e64ff03617ab0379d835ac7bbf213bafb95cb42907a56e735472d4fc", - "tags":[ - { - "name":"ocr", - "filesCount":3 - }, - { - "name":"test", - "filesCount":2 - }, - { - "name":"pdf", - "filesCount":1 - } - ] -} -``` -# Thumbnails - -## Get Thumbnail by Id - - - - GET api/thumbs/:id - - -### Success Response - -HTTP/1.1 200 OK - -``` -Octet-Stream -``` -### Error Response - -HTTP/1.1 404 NotFound - -``` -HTTP/1.1 404 NotFound -``` -## Add or Update Thumbnail - - - - POST api/thumbs/:id - - -### Success Response - -HTTP/1.1 200 OK - -``` -HTTP/1.1 200 OK -``` -### Error Response - -HTTP/1.1 400 Bad Request - -``` -Request body is empty -``` -# Users - -## Login - - - - POST api/users/login - - -### Parameters - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| email | String |

User Email

| -| password | String |

User Password

| - -### Success Response - -HTTP/1.1 200 OK - -``` -{ - "token": "504d44935c2ccefb557fd49636a73239147b3895db2f2f...", - "ttl": "604800" -} -``` -### Error Response - -HTTP/1.1 400 BadRequest - -``` -Bad request -``` -HTTP/1.1 404 NotFound - -``` -User with specified email not found -``` -HTTP/1.1 409 Conflict - -``` -User is not in active state -``` -HTTP/1.1 401 Unauthorized - -``` -Wrong password -``` -## Logout - - - - POST api/users/logout - -### Headers - -| Name | Type | Description | -|---------|-----------|--------------------------------------| -| ambar-email | String |

User email

| -| ambar-email-token | String |

User token

| - -### Error Response - -HTTP/1.1 401 Unauthorized - -``` -Unauthorized -``` - diff --git a/ElasticSearch/.gitignore b/ElasticSearch/.gitignore new file mode 100644 index 0000000..eb87e33 --- /dev/null +++ b/ElasticSearch/.gitignore @@ -0,0 +1,371 @@ + +# Created by https://www.gitignore.io/api/python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +.venv/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.vcxproj.filters + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ +Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ + diff --git a/ElasticSearch/Dockerfile b/ElasticSearch/Dockerfile new file mode 100644 index 0000000..c251e5d --- /dev/null +++ b/ElasticSearch/Dockerfile @@ -0,0 +1,16 @@ +FROM elasticsearch:5.6.3 + +# Set a timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +COPY elasticsearch.yml ./config/elasticsearch.yml + +RUN bin/elasticsearch-plugin install http://dl.bintray.com/content/imotov/elasticsearch-plugins/org/elasticsearch/elasticsearch-analysis-morphology/5.6.3/elasticsearch-analysis-morphology-5.6.3.zip +RUN bin/elasticsearch-plugin install analysis-stempel +RUN bin/elasticsearch-plugin install analysis-smartcn + +CMD ["elasticsearch"] + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f http://localhost:9200/ || exit 1 diff --git a/ElasticSearch/elasticsearch.yml b/ElasticSearch/elasticsearch.yml new file mode 100644 index 0000000..8763f90 --- /dev/null +++ b/ElasticSearch/elasticsearch.yml @@ -0,0 +1,12 @@ +network.host: 0.0.0.0 + +# this value is required because we set "network.host" +# be sure to modify it appropriately for a production cluster deployment +discovery.zen.minimum_master_nodes: 1 + +http.max_content_length: 1024mb +http.cors.enabled: true +http.cors.allow-origin: "*" +node.ingest: false +action.auto_create_index: false +bootstrap.memory_lock: true \ No newline at end of file diff --git a/FrontEnd/.babelrc b/FrontEnd/.babelrc new file mode 100644 index 0000000..745632e --- /dev/null +++ b/FrontEnd/.babelrc @@ -0,0 +1,10 @@ +// NOTE: These options are overriden by the babel-loader configuration +// for webpack, which can be found in ~/build/webpack.config. +// +// Why? The react-transform-hmr plugin depends on HMR (and throws if +// module.hot is disabled), so keeping it and related plugins contained +// within webpack helps prevent unexpected errors. +{ + "presets": ["es2015", "react", "stage-0"], + "plugins": ["transform-runtime"] +} diff --git a/FrontEnd/.editorconfig b/FrontEnd/.editorconfig new file mode 100644 index 0000000..90913b4 --- /dev/null +++ b/FrontEnd/.editorconfig @@ -0,0 +1,30 @@ +# http://editorconfig.org + +# A special property that should be specified at the top of the file outside of +# any sections. Set to true to stop .editor config file search on current file +root = true + +[*] +# Indentation style +# Possible values - tab, space +indent_style = space + +# Indentation size in single-spaced characters +# Possible values - an integer, tab +indent_size = 2 + +# Line ending file format +# Possible values - lf, crlf, cr +end_of_line = lf + +# File character encoding +# Possible values - latin1, utf-8, utf-16be, utf-16le +charset = utf-8 + +# Denotes whether to trim whitespace at the end of lines +# Possible values - true, false +trim_trailing_whitespace = true + +# Denotes whether file should end with a newline +# Possible values - true, false +insert_final_newline = true diff --git a/FrontEnd/.eslintignore b/FrontEnd/.eslintignore new file mode 100644 index 0000000..f517d4c --- /dev/null +++ b/FrontEnd/.eslintignore @@ -0,0 +1,6 @@ +blueprints/**/files/** +coverage/** +node_modules/** +dist/** +*.spec.js +src/index.html diff --git a/FrontEnd/.eslintrc b/FrontEnd/.eslintrc new file mode 100644 index 0000000..845a271 --- /dev/null +++ b/FrontEnd/.eslintrc @@ -0,0 +1,29 @@ +{ + "parser" : "babel-eslint", + "extends" : [ + "standard", + "standard-react" + ], + "plugins": [ + "babel", + "react", + "promise" + ], + "env" : { + "browser" : true + }, + "globals" : { + "__DEV__" : false, + "__PROD__" : false, + "__DEBUG__" : false, + "__COVERAGE__" : false, + "__BASENAME__" : false + }, + "rules": { + "semi" : [2, "never"], + "max-len": [2, 120, 2], + "generator-star-spacing": 0, + "babel/generator-star-spacing": 1, + "jsx-quotes": [2, "prefer-single"] + } +} diff --git a/FrontEnd/.gitignore b/FrontEnd/.gitignore new file mode 100644 index 0000000..eb87e33 --- /dev/null +++ b/FrontEnd/.gitignore @@ -0,0 +1,371 @@ + +# Created by https://www.gitignore.io/api/python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +.venv/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.vcxproj.filters + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ +Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ + diff --git a/FrontEnd/.reduxrc b/FrontEnd/.reduxrc new file mode 100644 index 0000000..ef88436 --- /dev/null +++ b/FrontEnd/.reduxrc @@ -0,0 +1,7 @@ +{ + "sourceBase":"src", + "testBase":"tests", + "smartPath":"containers", + "dumbPath":"components", + "fileCasing":"pascal" +} diff --git a/FrontEnd/Dockerfile b/FrontEnd/Dockerfile new file mode 100644 index 0000000..76a9812 --- /dev/null +++ b/FrontEnd/Dockerfile @@ -0,0 +1,15 @@ +FROM nginx:latest + +RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y curl + +# Set a timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +COPY default /etc/nginx/conf.d/default.conf +COPY dist /usr/share/nginx/html + +CMD echo $api > /usr/share/nginx/html/apiUrl.txt && nginx -g "daemon off;" + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f localhost:80 || exit 1 \ No newline at end of file diff --git a/FrontEnd/bin/compile.js b/FrontEnd/bin/compile.js new file mode 100644 index 0000000..76126d4 --- /dev/null +++ b/FrontEnd/bin/compile.js @@ -0,0 +1,24 @@ +import fs from 'fs-extra' +import _debug from 'debug' +import webpackCompiler from '../build/webpack-compiler' +import webpackConfig from '../build/webpack.config' +import config from '../config' + +const debug = _debug('app:bin:compile') +const paths = config.utils_paths + +;(async function () { + try { + debug('Run compiler') + const stats = await webpackCompiler(webpackConfig) + if (stats.warnings.length && config.compiler_fail_on_warning) { + debug('Config set to fail on warning, exiting with status code "1".') + process.exit(1) + } + debug('Copy static assets to dist folder.') + fs.copySync(paths.client('static'), paths.dist()) + } catch (e) { + debug('Compiler encountered an error.', e) + process.exit(1) + } +})() diff --git a/FrontEnd/bin/server.js b/FrontEnd/bin/server.js new file mode 100644 index 0000000..07f2dae --- /dev/null +++ b/FrontEnd/bin/server.js @@ -0,0 +1,11 @@ +import config from '../config' +import server from '../server/main' +import _debug from 'debug' + +const debug = _debug('app:bin:server') +const port = config.server_port +const host = config.server_host + +server.listen(port) +debug(`Server is now running at http://${host}:${port}.`) +debug(`Server accessible via localhost:${port} if you are using the project defaults.`) diff --git a/FrontEnd/blueprints/.eslintrc b/FrontEnd/blueprints/.eslintrc new file mode 100644 index 0000000..a62af02 --- /dev/null +++ b/FrontEnd/blueprints/.eslintrc @@ -0,0 +1,11 @@ +{ + "extends" : "../.eslintrc", + "env" : { + "mocha" : true + }, + "globals" : { + "expect" : false, + "should" : false, + "sinon" : false + } +} diff --git a/FrontEnd/blueprints/component/files/src/components/__name__/__name__.js b/FrontEnd/blueprints/component/files/src/components/__name__/__name__.js new file mode 100644 index 0000000..85c2fe3 --- /dev/null +++ b/FrontEnd/blueprints/component/files/src/components/__name__/__name__.js @@ -0,0 +1,10 @@ +import React from 'react' +import classes from './<%= pascalEntityName %>.scss' + +export const <%= pascalEntityName %> = () => ( +
']}> +

<%= pascalEntityName %>

+
+) + +export default <%= pascalEntityName %> diff --git a/FrontEnd/blueprints/component/files/src/components/__name__/__name__.scss b/FrontEnd/blueprints/component/files/src/components/__name__/__name__.scss new file mode 100644 index 0000000..4825587 --- /dev/null +++ b/FrontEnd/blueprints/component/files/src/components/__name__/__name__.scss @@ -0,0 +1,2 @@ +.<%= pascalEntityName %> { +} diff --git a/FrontEnd/blueprints/component/files/src/components/__name__/index.js b/FrontEnd/blueprints/component/files/src/components/__name__/index.js new file mode 100644 index 0000000..ec37830 --- /dev/null +++ b/FrontEnd/blueprints/component/files/src/components/__name__/index.js @@ -0,0 +1,3 @@ +import <%= pascalEntityName %> from './<%= pascalEntityName %>' + +export default <%= pascalEntityName %> diff --git a/FrontEnd/blueprints/component/index.js b/FrontEnd/blueprints/component/index.js new file mode 100644 index 0000000..dac0825 --- /dev/null +++ b/FrontEnd/blueprints/component/index.js @@ -0,0 +1,25 @@ +// module.exports = { + // locals: function(options) { + // // Return custom template variables here. + // return {}; + // }, + + // fileMapTokens: function(options) ( + // // Return custom tokens to be replaced in your files + // return { + // __token__: function(options){ + // // logic to determine value goes here + // return 'value'; + // } + // } + // }, + + // Should probably never need to be overriden + // + // filesPath: function() { + // return path.join(this.path, 'files'); + // }, + + // beforeInstall: function(options) {}, + // afterInstall: function(options) {}, +// }; diff --git a/FrontEnd/blueprints/route/files/src/routes/__name__/components/__name__.js b/FrontEnd/blueprints/route/files/src/routes/__name__/components/__name__.js new file mode 100644 index 0000000..f453516 --- /dev/null +++ b/FrontEnd/blueprints/route/files/src/routes/__name__/components/__name__.js @@ -0,0 +1,10 @@ +import React from 'react' +import classes from './<%= pascalEntityName %>.scss' + +export const <%= pascalEntityName %> = () => ( +
']}> +

<%= pascalEntityName %>

+
+) + +export default <%= pascalEntityName %> diff --git a/FrontEnd/blueprints/route/files/src/routes/__name__/components/__name__.scss b/FrontEnd/blueprints/route/files/src/routes/__name__/components/__name__.scss new file mode 100644 index 0000000..0bc2243 --- /dev/null +++ b/FrontEnd/blueprints/route/files/src/routes/__name__/components/__name__.scss @@ -0,0 +1,3 @@ +.<%= pascalEntityName %> { + +} diff --git a/FrontEnd/blueprints/route/files/src/routes/__name__/containers/__name__Container.js b/FrontEnd/blueprints/route/files/src/routes/__name__/containers/__name__Container.js new file mode 100644 index 0000000..d2fdc64 --- /dev/null +++ b/FrontEnd/blueprints/route/files/src/routes/__name__/containers/__name__Container.js @@ -0,0 +1,38 @@ +import { connect } from 'react-redux' +import { increment, doubleAsync } from '../modules/<%= pascalEntityName %>' + +/* This is a container component. Notice it does not contain any JSX, + nor does it import React. This component is **only** responsible for + wiring in the actions and state necessary to render a presentational + component - in this case, the counter: */ + +import <%= pascalEntityName %> from '../components/<%= pascalEntityName %>' + +/* Object of action creators (can also be function that returns object). + Keys will be passed as props to presentational components. Here we are + implementing our wrapper around increment; the component doesn't care */ + +const mapActionCreators = { + increment: () => increment(1), + doubleAsync +} + +const mapStateToProps = (state) => ({ + counter: state.counter +}) + +/* Note: mapStateToProps is where you should use `reselect` to create selectors, ie: + + import { createSelector } from 'reselect' + const counter = (state) => state.counter + const tripleCount = createSelector(counter, (count) => count * 3) + const mapStateToProps = (state) => ({ + counter: tripleCount(state) + }) + + Selectors can compute derived data, allowing Redux to store the minimal possible state. + Selectors are efficient. A selector is not recomputed unless one of its arguments change. + Selectors are composable. They can be used as input to other selectors. + https://github.com/reactjs/reselect */ + +export default connect(mapStateToProps, mapActionCreators)(<%= pascalEntityName %>) diff --git a/FrontEnd/blueprints/route/files/src/routes/__name__/index.js b/FrontEnd/blueprints/route/files/src/routes/__name__/index.js new file mode 100644 index 0000000..06f214a --- /dev/null +++ b/FrontEnd/blueprints/route/files/src/routes/__name__/index.js @@ -0,0 +1,24 @@ +import { injectReducer } from '../../store/reducers' + +export default (store) => ({ + path: '<%= dashesEntityName %>', + /* Async getComponent is only invoked when route matches */ + getComponent (nextState, cb) { + /* Webpack - use 'require.ensure' to create a split point + and embed an async module loader (jsonp) when bundling */ + require.ensure([], (require) => { + /* Webpack - use require callback to define + dependencies for bundling */ + const <%= pascalEntityName %> = require('./containers/<%= pascalEntityName %>Container').default + const reducer = require('./modules/<%= pascalEntityName %>').default + + /* Add the reducer to the store on key 'counter' */ + injectReducer(store, { key: '<%= pascalEntityName %>', reducer }) + + /* Return getComponent */ + cb(null, <%= pascalEntityName %>) + + /* Webpack named bundle */ + }, '<%= pascalEntityName %>') + } +}) diff --git a/FrontEnd/blueprints/route/files/src/routes/__name__/modules/__name__.js b/FrontEnd/blueprints/route/files/src/routes/__name__/modules/__name__.js new file mode 100644 index 0000000..1331306 --- /dev/null +++ b/FrontEnd/blueprints/route/files/src/routes/__name__/modules/__name__.js @@ -0,0 +1,55 @@ +// ------------------------------------ +// Constants +// ------------------------------------ +export const COUNTER_INCREMENT = '<%= pascalEntityName %>.COUNTER_INCREMENT' + +// ------------------------------------ +// Actions +// ------------------------------------ +export function increment (value = 1) { + return { + type: COUNTER_INCREMENT, + payload: value + } +} + +/* This is a thunk, meaning it is a function that immediately + returns a function for lazy evaluation. It is incredibly useful for + creating async actions, especially when combined with redux-thunk! + + NOTE: This is solely for demonstration purposes. In a real application, + you'd probably want to dispatch an action of COUNTER_DOUBLE and let the + reducer take care of this logic. */ + +export const doubleAsync = () => { + return (dispatch, getState) => { + return new Promise((resolve) => { + setTimeout(() => { + dispatch(increment(getState().counter)) + resolve() + }, 200) + }) + } +} + +export const actions = { + increment, + doubleAsync +} + +// ------------------------------------ +// Action Handlers +// ------------------------------------ +const ACTION_HANDLERS = { + [COUNTER_INCREMENT]: (state, action) => state + action.payload +} + +// ------------------------------------ +// Reducer +// ------------------------------------ +const initialState = 0 +export default function counterReducer (state = initialState, action) { + const handler = ACTION_HANDLERS[action.type] + + return handler ? handler(state, action) : state +} diff --git a/FrontEnd/blueprints/route/index.js b/FrontEnd/blueprints/route/index.js new file mode 100644 index 0000000..dac0825 --- /dev/null +++ b/FrontEnd/blueprints/route/index.js @@ -0,0 +1,25 @@ +// module.exports = { + // locals: function(options) { + // // Return custom template variables here. + // return {}; + // }, + + // fileMapTokens: function(options) ( + // // Return custom tokens to be replaced in your files + // return { + // __token__: function(options){ + // // logic to determine value goes here + // return 'value'; + // } + // } + // }, + + // Should probably never need to be overriden + // + // filesPath: function() { + // return path.join(this.path, 'files'); + // }, + + // beforeInstall: function(options) {}, + // afterInstall: function(options) {}, +// }; diff --git a/FrontEnd/build/karma.conf.js b/FrontEnd/build/karma.conf.js new file mode 100644 index 0000000..c0aa30e --- /dev/null +++ b/FrontEnd/build/karma.conf.js @@ -0,0 +1,76 @@ +import { argv } from 'yargs' +import config from '../config' +import webpackConfig from './webpack.config' +import _debug from 'debug' + +const debug = _debug('app:karma') +debug('Create configuration.') + +const karmaConfig = { + basePath: '../', // project root in relation to bin/karma.js + files: [ + { + pattern: `./${config.dir_test}/test-bundler.js`, + watched: false, + served: true, + included: true + } + ], + singleRun: !argv.watch, + frameworks: ['mocha'], + reporters: ['mocha'], + preprocessors: { + [`${config.dir_test}/test-bundler.js`]: ['webpack'] + }, + browsers: ['PhantomJS'], + webpack: { + devtool: 'cheap-module-source-map', + resolve: { + ...webpackConfig.resolve, + alias: { + ...webpackConfig.resolve.alias, + sinon: 'sinon/pkg/sinon.js' + } + }, + plugins: webpackConfig.plugins, + module: { + noParse: [ + /\/sinon\.js/ + ], + loaders: webpackConfig.module.loaders.concat([ + { + test: /sinon(\\|\/)pkg(\\|\/)sinon\.js/, + loader: 'imports?define=>false,require=>false' + } + ]) + }, + // Enzyme fix, see: + // https://github.com/airbnb/enzyme/issues/47 + externals: { + ...webpackConfig.externals, + 'react/addons': true, + 'react/lib/ExecutionEnvironment': true, + 'react/lib/ReactContext': 'window' + }, + sassLoader: webpackConfig.sassLoader + }, + webpackMiddleware: { + noInfo: true + }, + coverageReporter: { + reporters: config.coverage_reporters + } +} + +if (config.globals.__COVERAGE__) { + karmaConfig.reporters.push('coverage') + karmaConfig.webpack.module.preLoaders = [{ + test: /\.(js|jsx)$/, + include: new RegExp(config.dir_client), + loader: 'isparta', + exclude: /node_modules/ + }] +} + +// cannot use `export default` because of Karma. +module.exports = (cfg) => cfg.set(karmaConfig) diff --git a/FrontEnd/build/webpack-compiler.js b/FrontEnd/build/webpack-compiler.js new file mode 100644 index 0000000..5e150f0 --- /dev/null +++ b/FrontEnd/build/webpack-compiler.js @@ -0,0 +1,35 @@ +import webpack from 'webpack' +import _debug from 'debug' +import config from '../config' + +const debug = _debug('app:build:webpack-compiler') +const DEFAULT_STATS_FORMAT = config.compiler_stats + +export default function webpackCompiler (webpackConfig, statsFormat = DEFAULT_STATS_FORMAT) { + return new Promise((resolve, reject) => { + const compiler = webpack(webpackConfig) + + compiler.run((err, stats) => { + const jsonStats = stats.toJson() + + debug('Webpack compile completed.') + debug(stats.toString(statsFormat)) + + if (err) { + debug('Webpack compiler encountered a fatal error.', err) + return reject(err) + } else if (jsonStats.errors.length > 0) { + debug('Webpack compiler encountered errors.') + debug(jsonStats.errors.join('\n')) + return reject(new Error('Webpack compiler encountered errors')) + } else if (jsonStats.warnings.length > 0) { + debug('Webpack compiler encountered warnings.') + debug(jsonStats.warnings.join('\n')) + } else { + debug('No errors or warnings encountered.') + } + resolve(jsonStats) + }) + }) +} + diff --git a/FrontEnd/build/webpack.config.js b/FrontEnd/build/webpack.config.js new file mode 100644 index 0000000..9b8012c --- /dev/null +++ b/FrontEnd/build/webpack.config.js @@ -0,0 +1,275 @@ +import webpack from 'webpack' +import cssnano from 'cssnano' +import HtmlWebpackPlugin from 'html-webpack-plugin' +import ExtractTextPlugin from 'extract-text-webpack-plugin' +import config from '../config' +import _debug from 'debug' + +const debug = _debug('app:webpack:config') +const paths = config.utils_paths +const {__DEV__, __PROD__, __TEST__} = config.globals + +debug('Create configuration.') +const webpackConfig = { + name: 'client', + target: 'web', + devtool: config.compiler_devtool, + resolve: { + root: paths.client(), + extensions: ['', '.js', '.jsx', '.json'] + }, + module: {} +} +// ------------------------------------ +// Entry Points +// ------------------------------------ +const APP_ENTRY_PATHS = [ + paths.client('main.js') +] + +webpackConfig.entry = { + app: __DEV__ + ? APP_ENTRY_PATHS.concat(`webpack-hot-middleware/client?path=${config.compiler_public_path}__webpack_hmr`) + : APP_ENTRY_PATHS, + vendor: config.compiler_vendor +} + +// ------------------------------------ +// Bundle Output +// ------------------------------------ +webpackConfig.output = { + filename: `[name].[${config.compiler_hash_type}].js`, + path: paths.dist(), + publicPath: config.compiler_public_path +} + +// ------------------------------------ +// Plugins +// ------------------------------------ +webpackConfig.plugins = [ + new webpack.DefinePlugin(config.globals), + new HtmlWebpackPlugin({ + template: paths.client('index.html'), + hash: false, + favicon: paths.client('static/favicon.ico'), + filename: 'index.html', + inject: 'body', + minify: { + collapseWhitespace: true + } + }) +] + +if (__DEV__) { + debug('Enable plugins for live development (HMR, NoErrors).') + webpackConfig.plugins.push( + new webpack.HotModuleReplacementPlugin(), + new webpack.NoErrorsPlugin() + ) +} else if (__PROD__) { + debug('Enable plugins for production (OccurenceOrder, Dedupe & UglifyJS).') + webpackConfig.plugins.push( + new webpack.optimize.OccurrenceOrderPlugin(), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.UglifyJsPlugin({ + compress: { + unused: true, + dead_code: true, + warnings: false + } + }) + ) +} + +// Don't split bundles during testing, since we only want import one bundle +if (!__TEST__) { + webpackConfig.plugins.push( + new webpack.optimize.CommonsChunkPlugin({ + names: ['vendor'] + }) + ) +} + +// ------------------------------------ +// Pre-Loaders +// ------------------------------------ +/* +[ NOTE ] +We no longer use eslint-loader due to it severely impacting build +times for larger projects. `npm run lint` still exists to aid in +deploy processes (such as with CI), and it's recommended that you +use a linting plugin for your IDE in place of this loader. + +If you do wish to continue using the loader, you can uncomment +the code below and run `npm i --save-dev eslint-loader`. This code +will be removed in a future release. + +webpackConfig.module.preLoaders = [{ + test: /\.(js|jsx)$/, + loader: 'eslint', + exclude: /node_modules/ +}] + +webpackConfig.eslint = { + configFile: paths.base('.eslintrc'), + emitWarning: __DEV__ +} +*/ + +// ------------------------------------ +// Loaders +// ------------------------------------ +// JavaScript / JSON +webpackConfig.module.loaders = [{ + test: /\.(js|jsx)$/, + exclude: /node_modules/, + loader: 'babel', + query: { + cacheDirectory: true, + plugins: ['transform-runtime'], + presets: ['es2015', 'react', 'stage-0'] + } +}, +{ + test: /\.json$/, + loader: 'json' +}] + +// ------------------------------------ +// Style Loaders +// ------------------------------------ +// We use cssnano with the postcss loader, so we tell +// css-loader not to duplicate minimization. +const BASE_CSS_LOADER = 'css?sourceMap&-minimize' + +// Add any packge names here whose styles need to be treated as CSS modules. +// These paths will be combined into a single regex. +const PATHS_TO_TREAT_AS_CSS_MODULES = [ + // 'react-toolbox', (example) +] + +// If config has CSS modules enabled, treat this project's styles as CSS modules. +if (config.compiler_css_modules) { + PATHS_TO_TREAT_AS_CSS_MODULES.push( + paths.client().replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&') // eslint-disable-line + ) +} + +const isUsingCSSModules = !!PATHS_TO_TREAT_AS_CSS_MODULES.length +const cssModulesRegex = new RegExp(`(${PATHS_TO_TREAT_AS_CSS_MODULES.join('|')})`) + +// Loaders for styles that need to be treated as CSS modules. +if (isUsingCSSModules) { + const cssModulesLoader = [ + BASE_CSS_LOADER, + 'modules', + 'importLoaders=1', + 'localIdentName=[name]__[local]___[hash:base64:5]' + ].join('&') + + webpackConfig.module.loaders.push({ + test: /\.scss$/, + include: cssModulesRegex, + loaders: [ + 'style', + cssModulesLoader, + 'postcss', + 'sass?sourceMap' + ] + }) + + webpackConfig.module.loaders.push({ + test: /\.css$/, + include: cssModulesRegex, + loaders: [ + 'style', + cssModulesLoader, + 'postcss' + ] + }) +} + +// Loaders for files that should not be treated as CSS modules. +const excludeCSSModules = isUsingCSSModules ? cssModulesRegex : false +webpackConfig.module.loaders.push({ + test: /\.scss$/, + exclude: excludeCSSModules, + loaders: [ + 'style', + BASE_CSS_LOADER, + 'postcss', + 'sass?sourceMap' + ] +}) +webpackConfig.module.loaders.push({ + test: /\.css$/, + exclude: excludeCSSModules, + loaders: [ + 'style', + BASE_CSS_LOADER, + 'postcss' + ] +}) + +// ------------------------------------ +// Style Configuration +// ------------------------------------ +webpackConfig.sassLoader = { + includePaths: paths.client('styles') +} + +webpackConfig.postcss = [ + cssnano({ + autoprefixer: { + add: true, + remove: true, + browsers: ['last 2 versions'] + }, + discardComments: { + removeAll: true + }, + discardUnused: false, + mergeIdents: false, + reduceIdents: false, + safe: true, + sourcemap: true + }) +] + +// File loaders +/* eslint-disable */ +webpackConfig.module.loaders.push( + { test: /\.woff(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff' }, + { test: /\.woff2(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff2' }, + { test: /\.otf(\?.*)?$/, loader: 'file?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=font/opentype' }, + { test: /\.ttf(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/octet-stream' }, + { test: /\.eot(\?.*)?$/, loader: 'file?prefix=fonts/&name=[path][name].[ext]' }, + { test: /\.svg(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=image/svg+xml' }, + { test: /\.(png|jpg)$/, loader: 'url?limit=8192' } +) +/* eslint-enable */ + +// ------------------------------------ +// Finalize Configuration +// ------------------------------------ +// when we don't know the public path (we know it only when HMR is enabled [in development]) we +// need to use the extractTextPlugin to fix this issue: +// http://stackoverflow.com/questions/34133808/webpack-ots-parsing-error-loading-fonts/34133809#34133809 +if (!__DEV__) { + debug('Apply ExtractTextPlugin to CSS loaders.') + webpackConfig.module.loaders.filter((loader) => + loader.loaders && loader.loaders.find((name) => /css/.test(name.split('?')[0])) + ).forEach((loader) => { + const [first, ...rest] = loader.loaders + loader.loader = ExtractTextPlugin.extract(first, rest.join('!')) + Reflect.deleteProperty(loader, 'loaders') + }) + + webpackConfig.plugins.push( + new ExtractTextPlugin('[name].[contenthash].css', { + allChunks: true + }) + ) +} + +export default webpackConfig diff --git a/FrontEnd/config/environments.js b/FrontEnd/config/environments.js new file mode 100644 index 0000000..9bef69f --- /dev/null +++ b/FrontEnd/config/environments.js @@ -0,0 +1,36 @@ +// Here is where you can define configuration overrides based on the execution environment. +// Supply a key to the default export matching the NODE_ENV that you wish to target, and +// the base configuration will apply your overrides before exporting itself. +export default { + // ====================================================== + // Overrides when NODE_ENV === 'development' + // ====================================================== + // NOTE: In development, we use an explicit public path when the assets + // are served webpack by to fix this issue: + // http://stackoverflow.com/questions/34133808/webpack-ots-parsing-error-loading-fonts/34133809#34133809 + development: (config) => ({ + compiler_public_path: `http://${config.server_host}:${config.server_port}/`, + proxy: { + enabled: false, + options: { + host: 'http://localhost:8000', + match: /^\/api\/.*/ + } + } + }), + + // ====================================================== + // Overrides when NODE_ENV === 'production' + // ====================================================== + production: (config) => ({ + compiler_public_path: '/', + compiler_fail_on_warning: false, + compiler_hash_type: 'chunkhash', + compiler_devtool: null, + compiler_stats: { + chunks: true, + chunkModules: true, + colors: true + } + }) +} diff --git a/FrontEnd/config/index.js b/FrontEnd/config/index.js new file mode 100644 index 0000000..a55a5e7 --- /dev/null +++ b/FrontEnd/config/index.js @@ -0,0 +1,133 @@ +/* eslint key-spacing:0 spaced-comment:0 */ +import path from 'path' +import _debug from 'debug' +import { argv } from 'yargs' +import ip from 'ip' + +const localip = ip.address() +const debug = _debug('app:config') +debug('Creating default configuration.') + +// ======================================================== +// Default Configuration +// ======================================================== +const config = { + env : process.env.NODE_ENV || 'development', + + // ---------------------------------- + // Project Structure + // ---------------------------------- + path_base : path.resolve(__dirname, '..'), + dir_client : 'src', + dir_dist : 'dist', + dir_server : 'server', + dir_test : 'tests', + + // ---------------------------------- + // Server Configuration + // ---------------------------------- + server_host : localip, // use string 'localhost' to prevent exposure on local network + server_port : process.env.PORT || 3000, + + // ---------------------------------- + // Compiler Configuration + // ---------------------------------- + compiler_css_modules : true, + compiler_devtool : 'source-map', + compiler_hash_type : 'hash', + compiler_fail_on_warning : false, + compiler_quiet : false, + compiler_public_path : '/', + compiler_stats : { + chunks : false, + chunkModules : false, + colors : true + }, + compiler_vendor : [ + 'babel-polyfill', + 'history', + 'react', + 'react-redux', + 'react-router', + 'react-router-redux', + 'redux' + ], + + // ---------------------------------- + // Test Configuration + // ---------------------------------- + coverage_reporters : [ + { type : 'text-summary' }, + { type : 'lcov', dir : 'coverage' } + ] +} + +/************************************************ +------------------------------------------------- + +All Internal Configuration Below +Edit at Your Own Risk + +------------------------------------------------- +************************************************/ + +// ------------------------------------ +// Environment +// ------------------------------------ +// N.B.: globals added here must _also_ be added to .eslintrc +config.globals = { + 'process.env' : { + 'NODE_ENV' : JSON.stringify(config.env) + }, + 'NODE_ENV' : config.env, + '__DEV__' : config.env === 'development', + '__PROD__' : config.env === 'production', + '__TEST__' : config.env === 'test', + '__DEBUG__' : config.env === 'development' && !argv.no_debug, + '__COVERAGE__' : !argv.watch && config.env === 'test', + '__BASENAME__' : JSON.stringify(process.env.BASENAME || '') +} + +// ------------------------------------ +// Validate Vendor Dependencies +// ------------------------------------ +const pkg = require('../package.json') + +config.compiler_vendor = config.compiler_vendor + .filter((dep) => { + if (pkg.dependencies[dep]) return true + + debug( + `Package "${dep}" was not found as an npm dependency in package.json; ` + + `it won't be included in the webpack vendor bundle. + Consider removing it from vendor_dependencies in ~/config/index.js` + ) + }) + +// ------------------------------------ +// Utilities +// ------------------------------------ +const resolve = path.resolve +const base = (...args) => + Reflect.apply(resolve, null, [config.path_base, ...args]) + +config.utils_paths = { + base : base, + client : base.bind(null, config.dir_client), + dist : base.bind(null, config.dir_dist) +} + +// ======================================================== +// Environment Configuration +// ======================================================== +debug(`Looking for environment overrides for NODE_ENV "${config.env}".`) +const environments = require('./environments').default +const overrides = environments[config.env] +if (overrides) { + debug('Found overrides, applying to default configuration.') + Object.assign(config, overrides(config)) +} else { + debug('No environment overrides found, defaults will be used.') +} + +export default config diff --git a/FrontEnd/default b/FrontEnd/default new file mode 100644 index 0000000..f592a68 --- /dev/null +++ b/FrontEnd/default @@ -0,0 +1,9 @@ +server { + listen 80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + try_files $uri /index.html; + } +} diff --git a/FrontEnd/nodemon.json b/FrontEnd/nodemon.json new file mode 100644 index 0000000..9a8f40f --- /dev/null +++ b/FrontEnd/nodemon.json @@ -0,0 +1,4 @@ +{ + "verbose": false, + "ignore": ["dist", "coverage", "tests", "src"] +} diff --git a/FrontEnd/package.json b/FrontEnd/package.json new file mode 100644 index 0000000..39d1c6e --- /dev/null +++ b/FrontEnd/package.json @@ -0,0 +1,144 @@ +{ + "name": "ambar-frontend", + "version": "0.0.1", + "description": "Ambar Frontend", + "main": "index.js", + "engines": { + "node": ">=4.2.0", + "npm": "^3.0.0" + }, + "scripts": { + "clean": "rimraf dist", + "compile": "better-npm-run compile", + "lint": "eslint src tests server", + "lint:fix": "npm run lint -- --fix", + "start": "better-npm-run start", + "dev": "better-npm-run dev", + "dev:no-debug": "npm run dev -- --no_debug", + "deploy": "better-npm-run deploy", + "deploy:dev": "better-npm-run deploy:dev", + "deploy:prod": "better-npm-run deploy:prod" + }, + "betterScripts": { + "compile": { + "command": "babel-node bin/compile", + "env": { + "DEBUG": "app:*" + } + }, + "dev": { + "command": "nodemon --exec babel-node bin/server", + "env": { + "NODE_ENV": "development", + "DEBUG": "app:*" + } + }, + "deploy": { + "command": "npm run clean && npm run compile", + "env": { + "DEBUG": "app:*" + } + }, + "deploy:dev": { + "command": "npm run deploy", + "env": { + "NODE_ENV": "development", + "DEBUG": "app:*" + } + }, + "deploy:prod": { + "command": "npm run deploy", + "env": { + "NODE_ENV": "production", + "DEBUG": "app:*" + } + }, + "start": { + "command": "babel-node bin/server", + "env": { + "DEBUG": "app:*" + } + } + }, + "author": "RD17 (https://ambar.cloud)", + "license": "Fair Source", + "dependencies": { + "@blueprintjs/core": "^1.32.0", + "babel-cli": "^6.5.1", + "babel-core": "^6.3.17", + "babel-loader": "^6.2.0", + "babel-plugin-transform-runtime": "^6.3.13", + "babel-polyfill": "^6.9.0", + "babel-preset-es2015": "^6.14.0", + "babel-preset-es2015-loose": "^7.0.0", + "babel-preset-react": "^6.3.13", + "babel-preset-stage-0": "^6.3.13", + "babel-register": "^6.3.13", + "babel-runtime": "^6.3.19", + "better-npm-run": "0.0.10", + "brace": "^0.9.0", + "css-loader": "^0.23.0", + "cssnano": "^3.3.2", + "debug": "^2.2.0", + "deep-equal": "^1.0.1", + "extract-text-webpack-plugin": "^1.0.0", + "file-loader": "^0.9.0", + "fs-extra": "^0.30.0", + "history": "^2.0.0", + "html-webpack-plugin": "^2.7.1", + "immutability-helper": "^2.5.0", + "imports-loader": "^0.6.5", + "ip": "^1.1.2", + "json-loader": "^0.5.4", + "koa": "^2.0.0-alpha.3", + "koa-connect-history-api-fallback": "^0.3.0", + "koa-convert": "^1.2.0", + "koa-proxy": "^0.6.0", + "koa-static": "^3.0.0", + "material-ui": "^0.18.1", + "moment": "^2.14.1", + "node-sass": "^3.7.0", + "postcss-loader": "^0.9.0", + "react": "^15.0.0", + "react-ace": "^4.1.0", + "react-addons-css-transition-group": "^15.6.2", + "react-autosuggest": "^9.0.1", + "react-dom": "^15.0.0", + "react-dropzone": "^3.9.2", + "react-input-autosize": "^1.1.4", + "react-input-mask": "^0.7.2", + "react-redux": "^4.0.0", + "react-responsive": "^1.2.6", + "react-router": "^2.2.0", + "react-router-redux": "^4.0.0", + "react-spinkit": "^1.1.11", + "react-tap-event-plugin": "^2.0.1", + "recharts": "1.0.0-beta.1", + "redux": "^3.0.0", + "redux-thunk": "^2.0.0", + "rimraf": "^2.5.1", + "sass-loader": "^4.0.0", + "style-loader": "^0.13.0", + "url-loader": "^0.5.6", + "validator": "^5.5.0", + "webpack": "^1.12.14", + "whatwg-fetch": "^2.0.1", + "yargs": "^4.0.0" + }, + "devDependencies": { + "babel-eslint": "^6.0.0-beta.6", + "eslint": "^3.0.1", + "eslint-config-standard": "^5.1.0", + "eslint-config-standard-react": "^3.0.0", + "eslint-plugin-babel": "^3.2.0", + "eslint-plugin-promise": "^2.0.0", + "eslint-plugin-react": "^6.0.0", + "eslint-plugin-standard": "^2.0.0", + "isparta-loader": "^2.0.0", + "nodemon": "^1.8.1", + "react-addons-test-utils": "^15.0.0", + "redbox-react": "^1.2.10", + "webpack-dev-middleware": "^1.6.1", + "webpack-hot-middleware": "^2.6.0" + } +} diff --git a/FrontEnd/server/lib/apply-express-middleware.js b/FrontEnd/server/lib/apply-express-middleware.js new file mode 100644 index 0000000..4c8ba2d --- /dev/null +++ b/FrontEnd/server/lib/apply-express-middleware.js @@ -0,0 +1,14 @@ +// Based on: https://github.com/dayAlone/koa-webpack-hot-middleware/blob/master/index.js +export default function applyExpressMiddleware (fn, req, res) { + const originalEnd = res.end + + return new Promise((resolve) => { + res.end = function () { + originalEnd.apply(this, arguments) + resolve(false) + } + fn(req, res, function () { + resolve(true) + }) + }) +} diff --git a/FrontEnd/server/main.js b/FrontEnd/server/main.js new file mode 100644 index 0000000..e61f761 --- /dev/null +++ b/FrontEnd/server/main.js @@ -0,0 +1,61 @@ +import Koa from 'koa' +import convert from 'koa-convert' +import webpack from 'webpack' +import webpackConfig from '../build/webpack.config' +import historyApiFallback from 'koa-connect-history-api-fallback' +import serve from 'koa-static' +import proxy from 'koa-proxy' +import _debug from 'debug' +import config from '../config' +import webpackDevMiddleware from './middleware/webpack-dev' +import webpackHMRMiddleware from './middleware/webpack-hmr' + +const debug = _debug('app:server') +const paths = config.utils_paths +const app = new Koa() + +// Enable koa-proxy if it has been enabled in the config. +if (config.proxy && config.proxy.enabled) { + app.use(convert(proxy(config.proxy.options))) +} + +// This rewrites all routes requests to the root /index.html file +// (ignoring file requests). If you want to implement isomorphic +// rendering, you'll want to remove this middleware. +app.use(convert(historyApiFallback({ + verbose: false +}))) + +// ------------------------------------ +// Apply Webpack HMR Middleware +// ------------------------------------ +if (config.env === 'development') { + const compiler = webpack(webpackConfig) + + // Enable webpack-dev and webpack-hot middleware + const { publicPath } = webpackConfig.output + + app.use(webpackDevMiddleware(compiler, publicPath)) + app.use(webpackHMRMiddleware(compiler)) + + // Serve static assets from ~/src/static since Webpack is unaware of + // these files. This middleware doesn't need to be enabled outside + // of development since this directory will be copied into ~/dist + // when the application is compiled. + app.use(serve(paths.client('static'))) +} else { + debug( + 'Server is being run outside of live development mode, meaning it will ' + + 'only serve the compiled application bundle in ~/dist. Generally you ' + + 'do not need an application server for this and can instead use a web ' + + 'server such as nginx to serve your static files. See the "deployment" ' + + 'section in the README for more information on deployment strategies.' + ) + + // Serving ~/dist by default. Ideally these files should be served by + // the web server and not the app server, but this helps to demo the + // server in production. + app.use(serve(paths.dist())) +} + +export default app diff --git a/FrontEnd/server/middleware/webpack-dev.js b/FrontEnd/server/middleware/webpack-dev.js new file mode 100644 index 0000000..8187ba6 --- /dev/null +++ b/FrontEnd/server/middleware/webpack-dev.js @@ -0,0 +1,34 @@ +import WebpackDevMiddleware from 'webpack-dev-middleware' +import applyExpressMiddleware from '../lib/apply-express-middleware' +import _debug from 'debug' +import config from '../../config' + +const paths = config.utils_paths +const debug = _debug('app:server:webpack-dev') + +export default function (compiler, publicPath) { + debug('Enable webpack dev middleware.') + + const middleware = WebpackDevMiddleware(compiler, { + publicPath, + contentBase: paths.client(), + hot: true, + quiet: config.compiler_quiet, + noInfo: config.compiler_quiet, + lazy: false, + stats: config.compiler_stats + }) + + return async function koaWebpackDevMiddleware (ctx, next) { + let hasNext = await applyExpressMiddleware(middleware, ctx.req, { + end: (content) => (ctx.body = content), + setHeader: function () { + ctx.set.apply(ctx, arguments) + } + }) + + if (hasNext) { + await next() + } + } +} diff --git a/FrontEnd/server/middleware/webpack-hmr.js b/FrontEnd/server/middleware/webpack-hmr.js new file mode 100644 index 0000000..ddaff4d --- /dev/null +++ b/FrontEnd/server/middleware/webpack-hmr.js @@ -0,0 +1,18 @@ +import WebpackHotMiddleware from 'webpack-hot-middleware' +import applyExpressMiddleware from '../lib/apply-express-middleware' +import _debug from 'debug' + +const debug = _debug('app:server:webpack-hmr') + +export default function (compiler, opts) { + debug('Enable Webpack Hot Module Replacement (HMR).') + + const middleware = WebpackHotMiddleware(compiler, opts) + return async function koaWebpackHMR (ctx, next) { + let hasNext = await applyExpressMiddleware(middleware, ctx.req, ctx.res) + + if (hasNext && next) { + await next() + } + } +} diff --git a/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/AmbarResponsiveLogo.js b/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/AmbarResponsiveLogo.js new file mode 100644 index 0000000..6d42221 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/AmbarResponsiveLogo.js @@ -0,0 +1,17 @@ +import React from 'react' +import classes from './AmbarResponsiveLogo.scss' +import MediaQuery from 'react-responsive' + +export const AmbarResponsiveLogo = ({mode, version}) => ( +
+ Logo +
) + + +AmbarResponsiveLogo.propTypes = { + mode: React.PropTypes.string.isRequired, + version: React.PropTypes.string.isRequired +} + +export default AmbarResponsiveLogo \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/AmbarResponsiveLogo.scss b/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/AmbarResponsiveLogo.scss new file mode 100644 index 0000000..6dbe50e --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/AmbarResponsiveLogo.scss @@ -0,0 +1,8 @@ +.ambarResponsiveLogo { + height: 48px; + margin-bottom: 8px; + img { + height: 100%; + } + fill: black; +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/index.js b/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/index.js new file mode 100644 index 0000000..a796bf9 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/AmbarResponsiveLogo/index.js @@ -0,0 +1,3 @@ +import AmbarResponsiveLogo from './AmbarResponsiveLogo' + +export default AmbarResponsiveLogo diff --git a/FrontEnd/src/components/BasicComponents/AuthPageTemplate/AuthPageTemplate.js b/FrontEnd/src/components/BasicComponents/AuthPageTemplate/AuthPageTemplate.js new file mode 100644 index 0000000..19ea37a --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/AuthPageTemplate/AuthPageTemplate.js @@ -0,0 +1,20 @@ +import React from 'react' +import Paper from 'material-ui/Paper' +import { Card, CardText } from 'material-ui/Card' +import FullScreenPattern from '../FullScreenPattern' +import classes from './AuthPageTemplate.scss' + +export const AuthPageTemplate = ({ children }) => ( + + + + + logo + + {children} + + + +) + +export default AuthPageTemplate diff --git a/FrontEnd/src/components/BasicComponents/AuthPageTemplate/AuthPageTemplate.scss b/FrontEnd/src/components/BasicComponents/AuthPageTemplate/AuthPageTemplate.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/BasicComponents/AuthPageTemplate/index.js b/FrontEnd/src/components/BasicComponents/AuthPageTemplate/index.js new file mode 100644 index 0000000..94bbcbd --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/AuthPageTemplate/index.js @@ -0,0 +1,2 @@ +import AuthPageTemplate from'./AuthPageTemplate' +export default AuthPageTemplate \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/AuthorLabel/AuthorLabel.js b/FrontEnd/src/components/BasicComponents/AuthorLabel/AuthorLabel.js new file mode 100644 index 0000000..b16c1bf --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/AuthorLabel/AuthorLabel.js @@ -0,0 +1,25 @@ +import React, { Component } from 'react' +import HighlightedSpan from '../HighlightedSpan' + +import classes from './AuthorLabel.scss' + +const AuthorLabel = ({ content, performSearchByAuthor, ...otherProps }) => { + const authorHighlighted = content.highlight && content.highlight.author ? true : false + + return ( + performSearchByAuthor(`${content.author}*`)} + isClickable={true} + isHighlighted={authorHighlighted} + {...otherProps}> + {content.author} + + ) +} + +AuthorLabel.propTypes = { + content: React.PropTypes.object.isRequired, + performSearchByAuthor: React.PropTypes.func.isRequired +} + +export default AuthorLabel \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/AuthorLabel/AuthorLabel.scss b/FrontEnd/src/components/BasicComponents/AuthorLabel/AuthorLabel.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/BasicComponents/AuthorLabel/index.js b/FrontEnd/src/components/BasicComponents/AuthorLabel/index.js new file mode 100644 index 0000000..37fed5f --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/AuthorLabel/index.js @@ -0,0 +1,3 @@ +import AuthorLabel from './AuthorLabel' + +export default AuthorLabel \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/ClickableFilePath/ClickableFilePath.js b/FrontEnd/src/components/BasicComponents/ClickableFilePath/ClickableFilePath.js new file mode 100644 index 0000000..14bfb58 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/ClickableFilePath/ClickableFilePath.js @@ -0,0 +1,49 @@ +import React, { Component } from 'react' +import classes from './ClickableFilePath.scss' + +const ClickableFilePath = (props) => { + const { meta, performSearchByPathToFile } = props + + const fullPath = meta.full_name + + const fullPathParts = fullPath.split('/') + .filter(part => part != '') + const fullPathPartsExtended = fullPathParts + .map((part, idx) => { + const isLast = idx === fullPathParts.length - 1 + const trailingSymbol = isLast ? '' : '/' + const trailingAsterisk = '*' + + return { + part: `${part}${trailingSymbol}`, + pathToPart: `//${fullPathParts.filter((part, innerIdx) => innerIdx <= idx).join('/')}${trailingAsterisk}` + } + }) + + const isHighlighted = meta.highlight && meta.highlight.full_name + + return ( +
+
+ // + {fullPathPartsExtended.map((part, idx) => performSearchByPathToFile(part.pathToPart)}> + {part.part} + )} +
+
+ ) +} + +ClickableFilePath.propTypes = { + meta: React.PropTypes.object.isRequired, + performSearchByPathToFile: React.PropTypes.func.isRequired +} + +export default ClickableFilePath + + + + diff --git a/FrontEnd/src/components/BasicComponents/ClickableFilePath/ClickableFilePath.scss b/FrontEnd/src/components/BasicComponents/ClickableFilePath/ClickableFilePath.scss new file mode 100644 index 0000000..5ebc53c --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/ClickableFilePath/ClickableFilePath.scss @@ -0,0 +1,30 @@ +div.metaFullNameLineContainer { + color: #9E9E9E; + font-size: 12px; + word-wrap: break-word; + word-break: break-all; +} + +div.metaFullNameLineContainerHighlighted { + border-radius: 4px; + background-color: #fff176; + font-size: 12px; + display: inline; + color: rgb(158, 158, 158); +} + +span.metaFullNamePart { + cursor: pointer; cursor: hand; +} + +span.metaFullNamePart:hover { + cursor: pointer; cursor: hand; + border-radius: 4px; + background-color: #B2EBF2; +} + +span.metaFullNamePart:active { + cursor: pointer; cursor: hand; + border-radius: 4px; + background-color: #80DEEA; +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/ClickableFilePath/index.js b/FrontEnd/src/components/BasicComponents/ClickableFilePath/index.js new file mode 100644 index 0000000..900e453 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/ClickableFilePath/index.js @@ -0,0 +1,3 @@ +import ClickableFilePath from './ClickableFilePath' + +export default ClickableFilePath \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/CodeEditor/CodeEditor.js b/FrontEnd/src/components/BasicComponents/CodeEditor/CodeEditor.js new file mode 100644 index 0000000..61b9558 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/CodeEditor/CodeEditor.js @@ -0,0 +1,38 @@ +import React, { Component } from 'react' +import classes from './CodeEditor.scss' + +import brace from 'brace' +import AceEditor from 'react-ace' +import 'brace/mode/javascript' +import 'brace/theme/monokai' + +const CodeEditor = (props) => { + const { uId, value, onChange, readOnly, systemMessage } = props + return ( +
+ +

{systemMessage}

+
+ ) +} + +CodeEditor.propTypes = { + value: React.PropTypes.string.isRequired, + onChange: React.PropTypes.func.isRequired, + readOnly: React.PropTypes.bool.isRequired, + systemMessage: React.PropTypes.string +} + +export default CodeEditor \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/CodeEditor/CodeEditor.scss b/FrontEnd/src/components/BasicComponents/CodeEditor/CodeEditor.scss new file mode 100644 index 0000000..f0451d1 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/CodeEditor/CodeEditor.scss @@ -0,0 +1,16 @@ +p.codeEditorSystemMessage { + padding: 3px; + text-align: center; + background-color: #272822; + color: #FF3333; + font-family: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace; + font-size: 14px; + font-stretch: normal; + font-style: normal; + font-variant-caps: normal; + font-variant-ligatures: normal; + font-variant-numeric: normal; + font-weight: normal; + height: 25px; + margin: 0; +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/CodeEditor/index.js b/FrontEnd/src/components/BasicComponents/CodeEditor/index.js new file mode 100644 index 0000000..69e5299 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/CodeEditor/index.js @@ -0,0 +1,3 @@ +import CodeEditor from './CodeEditor' + +export default CodeEditor \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FileAvatar/FileAvatar.js b/FrontEnd/src/components/BasicComponents/FileAvatar/FileAvatar.js new file mode 100644 index 0000000..d7ac3c3 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FileAvatar/FileAvatar.js @@ -0,0 +1,50 @@ +import React, { Component } from 'react' +import Avatar from 'material-ui/Avatar' +import { files } from 'utils/' + +import classes from './FileAvatar.scss' + +const getHashCode = (str) => { + let hash = 0; + + if (str.length == 0) { + return hash + } + + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i) + hash = ((hash << 5) - hash) + char + hash = hash & hash // Convert to 32bit integer + } + + return hash +} + +const FileAvatar = ({ meta, searchFunction }) => { + const colors = [ + '#EF5350', '#E53935', '#D81B60', '#EC407A', '#AB47BC', '#7E57C2', '#5C6BC0', '#2196F3', '#43A047', '#EF6C00', '#A1887F', '#78909C', '#FF4081', '#3949AB'] + + let extension = files.getExtension(meta) + + const avatarStyle = { + fontSize: '12px', + textTransform: 'uppercase', + cursor: 'pointer' + } + + return ( + searchFunction(`*.${extension}`)} + size={38} + style={avatarStyle} + backgroundColor={colors[getHashCode(extension) % colors.length]}>{extension} + ) +} + +FileAvatar.propTypes = { + meta: React.PropTypes.object.isRequired, + searchFunction: React.PropTypes.func.isRequired +} + +export default FileAvatar \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FileAvatar/FileAvatar.scss b/FrontEnd/src/components/BasicComponents/FileAvatar/FileAvatar.scss new file mode 100644 index 0000000..2f1bfe0 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FileAvatar/FileAvatar.scss @@ -0,0 +1,19 @@ +span.clickable { + cursor: pointer; cursor: hand; +} + +span.clickable:hover { + cursor: pointer; cursor: hand; + border-radius: 4px; + background-color: #B2EBF2; +} + +span.clickable:active { + cursor: pointer; cursor: hand; + border-radius: 4px; + background-color: #80DEEA; +} + +span.highlighted { + background-color: #fff176; +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FileAvatar/index.js b/FrontEnd/src/components/BasicComponents/FileAvatar/index.js new file mode 100644 index 0000000..a5e14fa --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FileAvatar/index.js @@ -0,0 +1,3 @@ +import FileAvatar from './FileAvatar' + +export default FileAvatar \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FileSizeLabel/FileSizeLabel.js b/FrontEnd/src/components/BasicComponents/FileSizeLabel/FileSizeLabel.js new file mode 100644 index 0000000..fa32c82 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FileSizeLabel/FileSizeLabel.js @@ -0,0 +1,23 @@ +import React, { Component } from 'react' +import { files } from 'utils/' +import HighlightedSpan from '../HighlightedSpan' + +import classes from './FileSizeLabel.scss' + +const FileSizeLabel = ({ content, searchQuery, ...otherProps }) => { + const SIZE_QUERY = /((^|\s)size(>|<)[=]{0,1})([0-9]*)([k|m]{0,1})/im + + const sizeHighlighted = content.size ? SIZE_QUERY.test(searchQuery) : false + const size = content.size + + return ( + {files.formatFileSize(size)} + ) +} + +FileSizeLabel.propTypes = { + content: React.PropTypes.object.isRequired, + searchQuery: React.PropTypes.string.isRequired +} + +export default FileSizeLabel \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FileSizeLabel/FileSizeLabel.scss b/FrontEnd/src/components/BasicComponents/FileSizeLabel/FileSizeLabel.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/BasicComponents/FileSizeLabel/index.js b/FrontEnd/src/components/BasicComponents/FileSizeLabel/index.js new file mode 100644 index 0000000..ac62bae --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FileSizeLabel/index.js @@ -0,0 +1,3 @@ +import FileSizeLabel from './FileSizeLabel' + +export default FileSizeLabel \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FullScreenLoader/FullScreenLoader.js b/FrontEnd/src/components/BasicComponents/FullScreenLoader/FullScreenLoader.js new file mode 100644 index 0000000..6d8924a --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FullScreenLoader/FullScreenLoader.js @@ -0,0 +1,11 @@ +import React from 'react' +import CircularProgress from 'material-ui/CircularProgress' +import FullScreenPattern from '../FullScreenPattern' +import classes from './FullScreenLoader.scss' + +export const FullScreenLoader = (props) => + + + + +export default FullScreenLoader diff --git a/FrontEnd/src/components/BasicComponents/FullScreenLoader/FullScreenLoader.scss b/FrontEnd/src/components/BasicComponents/FullScreenLoader/FullScreenLoader.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/BasicComponents/FullScreenLoader/index.js b/FrontEnd/src/components/BasicComponents/FullScreenLoader/index.js new file mode 100644 index 0000000..c04199d --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FullScreenLoader/index.js @@ -0,0 +1,2 @@ +import FullScreenLoader from'./FullScreenLoader' +export default FullScreenLoader \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FullScreenPattern/FullScreenPattern.js b/FrontEnd/src/components/BasicComponents/FullScreenPattern/FullScreenPattern.js new file mode 100644 index 0000000..2c16323 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FullScreenPattern/FullScreenPattern.js @@ -0,0 +1,9 @@ +import React from 'react' +import classes from './FullScreenPattern.scss' + +export const FullScreenPattern = ({children}) => +
+ {children} +
+ +export default FullScreenPattern diff --git a/FrontEnd/src/components/BasicComponents/FullScreenPattern/FullScreenPattern.scss b/FrontEnd/src/components/BasicComponents/FullScreenPattern/FullScreenPattern.scss new file mode 100644 index 0000000..6310b3f --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FullScreenPattern/FullScreenPattern.scss @@ -0,0 +1,27 @@ +div.solidBackground { + position: fixed; + z-index: 1500; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + background-color: #00acc1; + opacity: 1; + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome and Opera */ + -webkit-transition: opacity 0.2s ease-in-out; + -moz-transition: opacity 0.2s ease-in-out; + -ms-transition: opacity 0.2s ease-in-out; + -o-transition: opacity 0.2s ease-in-out; + transition: opacity 0.2s ease-in-out; + + background-image: url("data:image/svg+xml,%3Csvg width='360' height='360' viewBox='0 0 360 360' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff' fill-opacity='0.2' fill-rule='evenodd'%3E%3Cpath d='M0 52.702l8.38-4.838C7.486 45.41 7 42.762 7 40c0-2.762.487-5.41 1.38-7.864L0 27.298v25.404zm0-39.16C6.5 6.176 15.673 1.222 26 .198v17.15c-5.433.95-10.21 3.81-13.616 7.863L0 18.06v-4.518zm0 52.916c6.5 7.366 15.673 12.32 26 13.344v-17.15c-5.433-.95-10.21-3.81-13.616-7.863L0 61.94v4.518zm34 13.344c11.713-1.162 21.94-7.378 28.47-16.437L47.616 54.79C44.21 58.84 39.433 61.7 34 62.652v17.15zm32.476-23.36C68.74 51.424 70 45.86 70 40c0-5.86-1.26-11.425-3.524-16.44L51.62 32.135C52.514 34.59 53 37.238 53 40c0 2.762-.487 5.41-1.38 7.864l14.856 8.577zM62.47 16.634C55.94 7.575 45.713 1.36 34 .198v17.15c5.433.95 10.21 3.81 13.616 7.863l14.854-8.575zM0 50.392l5.976-3.45C5.34 44.738 5 42.41 5 40c0-2.41.34-4.738.976-6.942L0 29.608v20.784zm.503-34.35C6.275 8.942 14.56 3.97 24 2.472v13.253c-4.656 1.147-8.8 3.598-12.018 6.944L.502 16.04zm0 47.916C6.275 71.058 14.56 76.03 24 77.528V64.276c-4.656-1.147-8.8-3.598-12.018-6.944L.502 63.96zM36 77.528c9.44-1.497 17.725-6.47 23.497-13.57l-11.48-6.627C44.8 60.678 40.658 63.13 36 64.276V77.53zm29.505-23.957C67.117 49.357 68 44.78 68 40c0-4.78-.883-9.356-2.495-13.57l-11.48 6.628C54.658 35.262 55 37.59 55 40c0 2.41-.34 4.738-.976 6.942l11.48 6.63zm-6.008-37.528C53.725 8.942 45.44 3.97 36 2.472v13.253c4.656 1.147 8.8 3.598 12.018 6.944l11.48-6.628zM0 85.016l4.624-4.265c2.316 1.447 4.764 2.7 7.323 3.74l-1.2 10.24 2.66.864 5.05-8.99c2.627.648 5.34 1.08 8.12 1.276L28.6 98h2.8l2.024-10.12c2.78-.196 5.492-.628 8.12-1.277l5.048 8.99 2.662-.864-1.2-10.24c2.558-1.04 5.006-2.293 7.322-3.74l7.583 6.996 2.264-1.646-4.31-9.378c2.096-1.768 4.04-3.712 5.808-5.81l9.378 4.312 1.646-2.265-6.995-7.584c1.447-2.316 2.7-4.764 3.74-7.323l10.24 1.2.864-2.66-8.99-5.05c.648-2.627 1.08-5.34 1.276-8.12L88 41.4v-2.8l-10.12-2.024c-.196-2.78-.628-5.492-1.277-8.12l8.99-5.048-.864-2.662-10.24 1.2c-1.04-2.558-2.293-5.006-3.74-7.322l6.996-7.583L76.1 4.777l-9.378 4.31c-1.768-2.096-3.712-4.04-5.81-5.808L62.42 0H0v85.016zm0 2.67l4.84-4.467c1.607.935 3.27 1.785 4.983 2.542L8.606 96.136l5.706 1.854 5.115-9.11c1.806.39 3.65.68 5.523.868L27 100h6l2.05-10.252c1.874-.188 3.717-.48 5.523-.868l5.115 9.11 5.706-1.854-1.217-10.374c1.713-.757 3.376-1.607 4.982-2.543l7.68 7.084 4.854-3.526-4.368-9.503c1.388-1.242 2.707-2.56 3.95-3.95l9.502 4.37 3.526-4.855-7.085-7.68c.935-1.607 1.785-3.27 2.542-4.983l10.374 1.217 1.854-5.706-9.11-5.115c.39-1.806.68-3.65.868-5.523L90 43v-6l-10.252-2.05c-.188-1.874-.48-3.717-.868-5.523l9.11-5.115-1.854-5.706-10.374 1.217c-.757-1.713-1.607-3.376-2.543-4.982l7.084-7.68-3.526-4.854-9.503 4.368c-1.242-1.388-2.56-2.707-3.95-3.95L64.58 0H0v87.685zM30 54c7.732 0 14-6.268 14-14s-6.268-14-14-14-14 6.268-14 14 6.268 14 14 14zm0-2c6.627 0 12-5.373 12-12s-5.373-12-12-12-12 5.373-12 12 5.373 12 12 12zm0-2c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zM122.67 92.05l-.503-6.05h-2.334l-.504 6.05c-2.185.128-4.3.506-6.323 1.107l-2.54-5.506-2.192.8 1.594 5.85c-1.983.86-3.845 1.94-5.557 3.214l-4.274-4.31-1.788 1.5 3.502 4.96c-1.555 1.47-2.94 3.12-4.127 4.913l-5.49-2.587-1.165 2.02 4.982 3.458c-.95 1.898-1.693 3.92-2.196 6.032l-6.04-.553-.404 2.298 5.868 1.546c-.12 1.054-.182 2.125-.182 3.21s.062 2.156.182 3.21l-5.868 1.545.405 2.298 6.038-.553c.503 2.113 1.245 4.134 2.196 6.032l-4.982 3.458 1.166 2.02 5.49-2.587c1.185 1.793 2.57 3.442 4.126 4.914l-3.502 4.96 1.787 1.498 4.273-4.31c1.712 1.274 3.574 2.356 5.556 3.215l-1.595 5.85 2.193.8 2.54-5.507c2.02.6 4.137.98 6.32 1.108l.505 6.05h2.334l.504-6.05c2.185-.128 4.3-.506 6.323-1.107l2.54 5.506 2.192-.8-1.594-5.85c1.983-.86 3.845-1.94 5.557-3.214l4.274 4.31 1.788-1.5-3.502-4.96c1.555-1.47 2.94-3.12 4.127-4.913l5.49 2.587 1.165-2.02-4.982-3.458c.95-1.898 1.693-3.92 2.196-6.032l6.04.553.404-2.298-5.868-1.546c.12-1.054.182-2.125.182-3.21s-.062-2.156-.182-3.21l5.868-1.545-.405-2.298-6.038.553c-.503-2.113-1.245-4.134-2.196-6.032l4.982-3.458-1.166-2.02-5.49 2.587c-1.185-1.793-2.57-3.442-4.126-4.914l3.502-4.96-1.787-1.498-4.273 4.31c-1.712-1.274-3.574-2.356-5.556-3.215l1.595-5.85-2.193-.8-2.54 5.507c-2.02-.6-4.137-.98-6.32-1.108zm-15.198 1.122c-1.02.508-2.004 1.072-2.953 1.687l-4.347-4.378-4.626 3.88 3.532 5.007c-.79.828-1.534 1.7-2.225 2.614l-5.522-2.6-3.02 5.23 4.974 3.457c-.46 1.055-.86 2.14-1.2 3.253l-6.016-.548-1.047 5.947 5.833 1.54c-.033.576-.05 1.155-.05 1.738s.017 1.162.05 1.737l-5.833 1.54 1.048 5.948 6.018-.548c.338 1.112.74 2.198 1.2 3.252l-4.975 3.455 3.02 5.23 5.522-2.6c.69.914 1.434 1.787 2.224 2.616l-3.533 5.007 4.626 3.88 4.346-4.376c.948.616 1.933 1.18 2.952 1.688l-1.622 5.968 5.675 2.066 2.606-5.642c1.09.252 2.2.445 3.33.576l.52 6.204h6.04l.52-6.204c1.13-.13 2.24-.324 3.33-.576l2.605 5.642 5.675-2.066-1.622-5.968c1.02-.508 2.004-1.072 2.953-1.687l4.347 4.378 4.626-3.88-3.532-5.007c.79-.828 1.534-1.7 2.225-2.614l5.522 2.6 3.02-5.23-4.974-3.457c.46-1.055.86-2.14 1.2-3.253l6.016.548 1.047-5.947-5.833-1.54c.033-.576.05-1.155.05-1.738s-.017-1.162-.05-1.737l5.833-1.54-1.048-5.948-6.018.548c-.338-1.112-.74-2.198-1.2-3.252l4.975-3.455-3.02-5.23-5.522 2.6c-.69-.914-1.434-1.787-2.224-2.616l3.533-5.007-4.626-3.88-4.346 4.376c-.948-.616-1.933-1.18-2.952-1.688l1.622-5.968-5.675-2.066-2.606 5.642c-1.09-.252-2.2-.445-3.33-.576L124.02 84h-6.04l-.52 6.204c-1.13.13-2.24.324-3.33.576l-2.605-5.642-5.675 2.066 1.622 5.968zM121 128c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm0-2c3.314 0 6-2.686 6-6s-2.686-6-6-6-6 2.686-6 6 2.686 6 6 6zm0-18c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm8.485 3.515c1.953 1.952 5.12 1.952 7.07 0 1.954-1.953 1.954-5.12 0-7.07-1.95-1.954-5.117-1.954-7.07 0-1.952 1.95-1.952 5.117 0 7.07zM133 120c0 2.76 2.24 5 5 5s5-2.24 5-5-2.24-5-5-5-5 2.24-5 5zm-3.515 8.485c-1.952 1.953-1.952 5.12 0 7.07 1.953 1.954 5.12 1.954 7.07 0 1.954-1.95 1.954-5.117 0-7.07-1.95-1.952-5.117-1.952-7.07 0zM121 132c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm-8.485-3.515c-1.953-1.952-5.12-1.952-7.07 0-1.954 1.953-1.954 5.12 0 7.07 1.95 1.954 5.117 1.954 7.07 0 1.952-1.95 1.952-5.117 0-7.07zM109 120c0-2.76-2.24-5-5-5s-5 2.24-5 5 2.24 5 5 5 5-2.24 5-5zm3.515-8.485c1.952-1.953 1.952-5.12 0-7.07-1.953-1.954-5.12-1.954-7.07 0-1.954 1.95-1.954 5.117 0 7.07 1.95 1.952 5.117 1.952 7.07 0zM121 106c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm9.9 4.1c1.17 1.172 3.07 1.172 4.242 0 1.172-1.17 1.172-3.07 0-4.242-1.17-1.172-3.07-1.172-4.243 0-1.172 1.17-1.172 3.07 0 4.243zm4.1 9.9c0 1.657 1.343 3 3 3s3-1.343 3-3-1.343-3-3-3-3 1.343-3 3zm-4.1 9.9c-1.172 1.17-1.172 3.07 0 4.242 1.17 1.172 3.07 1.172 4.242 0 1.172-1.17 1.172-3.07 0-4.243-1.17-1.172-3.07-1.172-4.243 0zM121 134c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3zm-9.9-4.1c-1.17-1.172-3.07-1.172-4.242 0-1.172 1.17-1.172 3.07 0 4.242 1.17 1.172 3.07 1.172 4.243 0 1.172-1.17 1.172-3.07 0-4.243zM107 120c0-1.657-1.343-3-3-3s-3 1.343-3 3 1.343 3 3 3 3-1.343 3-3zm4.1-9.9c1.172-1.17 1.172-3.07 0-4.242-1.17-1.172-3.07-1.172-4.242 0-1.172 1.17-1.172 3.07 0 4.243 1.17 1.172 3.07 1.172 4.243 0zM218.64 113.197c-4.648 2.87-8.574 6.795-11.443 11.442l5.2 3c2.338-3.738 5.505-6.905 9.244-9.243l-3-5.2zm1.73-1c4.672-2.53 9.984-4.025 15.63-4.183v6.003c-4.554.154-8.84 1.358-12.628 3.378l-3.002-5.2zm-14.174 14.173c-2.528 4.672-4.024 9.984-4.182 15.63h6.003c.154-4.554 1.358-8.84 3.378-12.628l-5.2-3.002zM202.014 144c.158 5.646 1.654 10.958 4.182 15.63l5.2-3.002c-2.02-3.787-3.225-8.074-3.38-12.628h-6.002zm5.183 17.36c2.87 4.648 6.795 8.574 11.442 11.443l3-5.2c-3.738-2.338-6.905-5.505-9.243-9.244l-5.2 3zm13.173 12.444c4.672 2.528 9.984 4.024 15.63 4.182v-6.003c-4.554-.154-8.84-1.358-12.628-3.378l-3.002 5.2zm17.63 4.182c5.646-.158 10.958-1.654 15.63-4.182l-3.002-5.2c-3.787 2.02-8.074 3.225-12.628 3.38v6.002zm17.36-5.183c4.648-2.87 8.574-6.795 11.443-11.442l-5.2-3c-2.338 3.738-5.505 6.905-9.244 9.243l3 5.2zm12.444-13.173c2.528-4.672 4.024-9.984 4.182-15.63h-6.003c-.154 4.554-1.358 8.84-3.378 12.628l5.2 3.002zm4.182-17.63c-.158-5.646-1.654-10.958-4.182-15.63l-5.2 3.002c2.02 3.787 3.225 8.074 3.38 12.628h6.002zm-5.183-17.36c-2.87-4.648-6.795-8.574-11.442-11.443l-3 5.2c3.738 2.338 6.905 5.505 9.243 9.244l5.2-3zM238 108.013c5.646.158 10.958 1.654 15.63 4.182l-3.002 5.2c-3.787-2.02-8.074-3.225-12.628-3.38v-6.002zm-20.03 8.023c-3.074 2.173-5.76 4.86-7.933 7.932l1.74 1.003c1.987-2.775 4.42-5.21 7.196-7.196l-1.004-1.74zm5.192-3.004c3.348-1.55 6.998-2.552 10.838-2.898v2.008c-3.477.334-6.787 1.243-9.833 2.63l-1.005-1.74zm-16.13 16.13c-1.548 3.347-2.55 6.997-2.897 10.837h2.008c.334-3.477 1.243-6.787 2.63-9.833l-1.74-1.005zM204.136 146c.346 3.84 1.35 7.49 2.898 10.838l1.74-1.005c-1.387-3.046-2.296-6.356-2.63-9.833h-2.008zm5.902 16.03c2.173 3.074 4.86 5.76 7.932 7.933l1.003-1.74c-2.775-1.987-5.21-4.42-7.196-7.196l-1.74 1.004zm13.125 10.937c3.348 1.55 6.998 2.552 10.838 2.898v-2.008c-3.477-.334-6.787-1.243-9.833-2.63l-1.005 1.74zM240 175.865c3.84-.346 7.49-1.35 10.838-2.898l-1.005-1.74c-3.046 1.387-6.356 2.296-9.833 2.63v2.008zm16.03-5.902c3.074-2.173 5.76-4.86 7.933-7.932l-1.74-1.003c-1.987 2.775-4.42 5.21-7.196 7.196l1.004 1.74zm10.937-13.125c1.55-3.348 2.552-6.998 2.898-10.838h-2.008c-.334 3.477-1.243 6.787-2.63 9.833l1.74 1.005zM269.865 140c-.346-3.84-1.35-7.49-2.898-10.838l-1.74 1.005c1.387 3.046 2.296 6.356 2.63 9.833h2.008zm-5.902-16.03c-2.173-3.074-4.86-5.76-7.932-7.933l-1.003 1.74c2.775 1.987 5.21 4.42 7.196 7.196l1.74-1.004zm-13.125-10.937c-3.348-1.55-6.998-2.552-10.838-2.898v2.008c3.477.334 6.787 1.243 9.833 2.63l1.005-1.74zm-10.32-9.88L240 99l-1-4h-4l-1 4-.52 4.153c-.872.076-1.737.18-2.593.31l-1.51-3.91-1.94-3.638-3.88.968-.003 4.123.5 4.136c-.83.283-1.645.592-2.448.927l-2.414-3.433-2.76-3.063-3.533 1.878.994 4 1.483 3.89c-.733.472-1.45.968-2.15 1.485l-3.187-2.758-3.42-2.305-2.972 2.677 1.933 3.642 2.378 3.41c-.61.643-1.197 1.306-1.763 1.988l-3.678-1.945-3.85-1.475-2.294 3.276 2.703 3.114 3.12 2.82c-.43.757-.837 1.53-1.217 2.315l-4.043-.998-4.092-.5-1.434 3.734 3.377 2.367 3.697 1.977c-.234.836-.443 1.683-.623 2.54l-4.173.01-4.092.504-.488 3.97 3.85 1.48 4.064 1.024c-.013.434-.02.87-.02 1.306 0 .437.007.872.02 1.306l-4.064 1.023-3.85 1.48.49 3.97 4.09.504 4.175.01c.18.856.39 1.703.624 2.54l-3.697 1.975-3.376 2.366 1.435 3.735 4.092-.5 4.042-.997c.38.786.785 1.558 1.215 2.314l-3.12 2.82-2.702 3.115 2.294 3.276 3.85-1.475 3.678-1.945c.566.682 1.154 1.345 1.763 1.988l-2.377 3.41-1.932 3.642 2.972 2.677 3.42-2.304 3.187-2.757c.7.517 1.417 1.013 2.15 1.485l-1.483 3.89-.995 4 3.53 1.878 2.762-3.063 2.414-3.432c.803.336 1.62.645 2.447.928l-.5 4.136.004 4.123 3.88.968 1.94-3.64 1.51-3.91c.856.132 1.72.236 2.594.312L234 187l1 4h4l1-4 .52-4.153c.872-.076 1.737-.18 2.593-.31l1.51 3.91 1.94 3.638 3.88-.968.003-4.123-.5-4.136c.83-.283 1.645-.592 2.448-.927l2.414 3.433 2.76 3.063 3.533-1.878-.994-4-1.483-3.89c.733-.472 1.45-.968 2.15-1.485l3.187 2.758 3.42 2.305 2.972-2.677-1.933-3.642-2.378-3.41c.61-.643 1.197-1.306 1.763-1.988l3.678 1.945 3.85 1.475 2.294-3.276-2.703-3.114-3.12-2.82c.43-.757.837-1.53 1.217-2.315l4.043.998 4.092.5 1.434-3.734-3.377-2.367-3.697-1.977c.234-.836.443-1.683.623-2.54l4.173-.01 4.092-.504.488-3.97-3.85-1.48-4.064-1.024c.013-.434.02-.87.02-1.306 0-.437-.007-.872-.02-1.306l4.064-1.023 3.85-1.48-.49-3.97-4.09-.504-4.175-.01c-.18-.856-.39-1.703-.624-2.54l3.697-1.975 3.376-2.366-1.435-3.735-4.092.5-4.042.997c-.38-.786-.785-1.558-1.215-2.314l3.12-2.82 2.702-3.115-2.294-3.276-3.85 1.475-3.678 1.945c-.566-.682-1.154-1.345-1.763-1.988l2.377-3.41 1.932-3.642-2.972-2.677-3.42 2.304-3.187 2.757c-.7-.517-1.417-1.013-2.15-1.485l1.483-3.89.995-4-3.53-1.878-2.762 3.063-2.414 3.432c-.803-.336-1.62-.645-2.447-.928l.5-4.136-.004-4.123-3.88-.968-1.94 3.64-1.51 3.91c-.856-.132-1.72-.236-2.594-.312zm-14.3 3.398c-1.825.54-3.594 1.213-5.294 2.008l-3.503-4.98-1.38-1.53-.882.468.497 2 2.163 5.674c-1.634.957-3.19 2.033-4.656 3.216l-4.614-3.994-1.71-1.15-.743.668.966 1.82 3.473 4.982c-1.367 1.328-2.635 2.757-3.79 4.277l-5.37-2.84-1.924-.738-.575.82 1.352 1.556 4.52 4.088c-.996 1.595-1.877 3.27-2.632 5.012l-5.893-1.455-2.046-.25-.36.933 1.69 1.184 5.366 2.868c-.582 1.78-1.035 3.615-1.35 5.5l-6.08.012-2.045.252-.122.993 1.924.74 5.904 1.486c-.07.935-.104 1.878-.104 2.83 0 .952.035 1.895.104 2.83l-5.905 1.485-1.925.74.122.993 2.046.252 6.08.013c.314 1.884.767 3.72 1.35 5.5l-5.368 2.867-1.688 1.184.36.933 2.045-.25 5.893-1.455c.755 1.742 1.636 3.417 2.632 5.012l-4.52 4.088-1.352 1.557.574.818 1.924-.737 5.368-2.84c1.156 1.52 2.424 2.95 3.79 4.278l-3.47 4.98-.967 1.822.743.67 1.71-1.152 4.614-3.994c1.466 1.183 3.022 2.26 4.656 3.216l-2.163 5.673-.497 2 .882.47 1.38-1.53 3.504-4.98c1.7.794 3.47 1.467 5.295 2.006l-.728 6.028v2.06l.972.243.97-1.82 2.192-5.675c1.83.36 3.706.588 5.62.675L236 187l.5 2h1l.5-2 .755-6.04c1.913-.087 3.79-.315 5.62-.675l2.192 5.676.97 1.82.97-.24v-2.062l-.726-6.03c1.827-.538 3.596-1.21 5.296-2.006l3.503 4.98 1.38 1.53.882-.468-.497-2-2.163-5.674c1.634-.957 3.19-2.033 4.656-3.216l4.614 3.994 1.71 1.15.743-.668-.966-1.82-3.473-4.982c1.367-1.328 2.635-2.757 3.79-4.277l5.37 2.84 1.924.738.575-.82-1.352-1.556-4.52-4.088c.996-1.595 1.877-3.27 2.632-5.012l5.893 1.455 2.046.25.36-.933-1.69-1.184-5.366-2.868c.582-1.78 1.035-3.615 1.35-5.5l6.08-.012 2.045-.252.122-.993-1.924-.74-5.904-1.486c.07-.935.104-1.878.104-2.83 0-.952-.035-1.895-.104-2.83l5.905-1.485 1.925-.74-.122-.993-2.046-.252-6.08-.013c-.314-1.884-.767-3.72-1.35-5.5l5.368-2.867 1.688-1.184-.36-.933-2.045.25-5.893 1.455c-.755-1.742-1.636-3.417-2.632-5.012l4.52-4.088 1.352-1.557-.574-.818-1.924.737-5.368 2.84c-1.156-1.52-2.424-2.95-3.79-4.278l3.47-4.98.967-1.822-.743-.67-1.71 1.152-4.614 3.994c-1.466-1.183-3.022-2.26-4.656-3.216l2.163-5.673.497-2-.882-.47-1.38 1.53-3.504 4.98c-1.7-.794-3.47-1.467-5.295-2.006l.728-6.028v-2.06l-.972-.243-.97 1.82-2.192 5.675c-1.83-.36-3.706-.588-5.62-.675L238 99l-.5-2h-1l-.5 2-.755 6.04c-1.913.087-3.79.315-5.62.675l-2.192-5.676-.97-1.82-.97.24v2.062l.726 6.03zM237 156c7.18 0 13-5.82 13-13s-5.82-13-13-13-13 5.82-13 13 5.82 13 13 13zm0-2c6.075 0 11-4.925 11-11s-4.925-11-11-11-11 4.925-11 11 4.925 11 11 11zM137.153 27c1.4 13.62 12.227 24.447 25.847 25.847V38.7c-5.877-1.193-10.507-5.823-11.7-11.7h-14.147zm12.563-27c-6.896 4.688-11.665 12.27-12.563 21H151.3c1.193-5.877 5.823-10.507 11.7-11.7V0h-13.284zM169 52.847c13.62-1.4 24.447-12.227 25.847-25.847H180.7c-1.193 5.877-5.823 10.507-11.7 11.7v14.147zM182.284 0c6.896 4.688 11.665 12.27 12.563 21H180.7c-1.193-5.877-5.823-10.507-11.7-11.7V0h13.284zm-42.822 29c2.04 10.903 10.635 19.497 21.538 21.538V40.253c-5.368-1.65-9.603-5.885-11.253-11.253h-10.285zm14.156-29c-7.263 3.755-12.604 10.71-14.156 19h10.285c1.65-5.368 5.885-9.603 11.253-11.253V0h-7.382zM171 50.538c10.903-2.04 19.497-10.635 21.538-21.538h-10.285c-1.65 5.368-5.885 9.603-11.253 11.253v10.285zM178.382 0c7.263 3.755 12.604 10.71 14.156 19h-10.285c-1.65-5.368-5.885-9.603-11.253-11.253V0h7.382zm-40.84 0l.737 1.03c-.574.69-1.123 1.405-1.644 2.138l-7.74-2.9-2 3.464 6.376 5.25c-.374.816-.72 1.648-1.034 2.495l-8.22-.797-1.036 3.864 7.522 3.422c-.15.88-.266 1.773-.35 2.675L122 22v4l8.155 1.36c.083.9.2 1.793.35 2.674l-7.523 3.422 1.035 3.864 8.22-.797c.315.847.66 1.68 1.035 2.495l-6.377 5.25 2 3.464 7.74-2.9c.522.733 1.07 1.447 1.644 2.138l-4.807 6.728 2.83 2.83 6.727-4.807c.69.574 1.405 1.123 2.138 1.644l-2.9 7.74 3.464 2 5.25-6.376c.816.374 1.648.72 2.495 1.034l-.797 8.22 3.864 1.036 3.422-7.522c.88.15 1.773.266 2.675.35L164 68h4l1.36-8.155c.9-.083 1.793-.2 2.674-.35l3.422 7.523 3.864-1.035-.797-8.22c.847-.315 1.68-.66 2.495-1.035l5.25 6.377 3.464-2-2.9-7.74c.733-.522 1.447-1.07 2.138-1.644l6.728 4.807 2.83-2.83-4.807-6.727c.574-.69 1.123-1.405 1.644-2.138l7.74 2.9 2-3.464-6.376-5.25c.374-.816.72-1.648 1.034-2.495l8.22.797 1.036-3.864-7.522-3.422c.15-.88.266-1.773.35-2.675L210 26v-4l-8.155-1.36c-.083-.9-.2-1.793-.35-2.674l7.523-3.422-1.035-3.864-8.22.797c-.315-.847-.66-1.68-1.035-2.495l6.377-5.25-2-3.464-7.74 2.9c-.522-.733-1.07-1.447-1.644-2.138l.737-1.03h-56.914zm2.426 0l.836 1.17c-1.242 1.37-2.373 2.84-3.38 4.4l-7.63-2.86-.334.58 6.288 5.175c-.842 1.637-1.555 3.35-2.126 5.128l-8.105-.785-.172.644 7.414 3.372c-.385 1.786-.63 3.624-.72 5.503l-8.04 1.34v.666l8.04 1.34c.09 1.88.335 3.717.72 5.503l-7.415 3.372.172.644 8.105-.785c.57 1.777 1.284 3.49 2.126 5.128l-6.288 5.176.334.58 7.63-2.86c1.007 1.56 2.138 3.03 3.38 4.4l-4.738 6.633.47.47 6.635-4.737c1.37 1.242 2.84 2.373 4.4 3.38l-2.86 7.63.58.334 5.175-6.288c1.637.842 3.35 1.555 5.128 2.126l-.785 8.105.644.172 3.372-7.414c1.786.385 3.624.63 5.503.72l1.34 8.04h.666l1.34-8.04c1.88-.09 3.717-.335 5.503-.72l3.372 7.415.644-.172-.785-8.105c1.777-.57 3.49-1.284 5.128-2.126l5.176 6.288.58-.334-2.86-7.63c1.56-1.007 3.03-2.138 4.4-3.38l6.633 4.738.47-.47-4.737-6.635c1.242-1.37 2.373-2.84 3.38-4.4l7.63 2.86.334-.58-6.288-5.175c.842-1.637 1.555-3.35 2.126-5.128l8.105.785.172-.644-7.414-3.372c.385-1.786.63-3.624.72-5.503l8.04-1.34v-.666l-8.04-1.34c-.09-1.88-.335-3.717-.72-5.503l7.415-3.372-.172-.644-8.105.785c-.57-1.777-1.284-3.49-2.126-5.128l6.288-5.176-.334-.58-7.63 2.86c-1.007-1.56-2.138-3.03-3.38-4.4l.836-1.17h-52.064zM166 34c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zM126.49 208.15c-.32 1.566-.49 3.19-.49 4.85 0 1.66.17 3.284.49 4.85l-10.667 7.954 6 10.392 12.227-5.263c2.412 2.147 5.26 3.815 8.396 4.854L144 249h12l1.554-13.213c3.136-1.04 5.984-2.707 8.396-4.854l12.227 5.263 6-10.392-10.667-7.954c.32-1.566.49-3.19.49-4.85 0-1.66-.17-3.284-.49-4.85l10.667-7.954-6-10.392-12.227 5.263c-2.412-2.147-5.26-3.815-8.396-4.854L156 177h-12l-1.554 13.213c-3.136 1.04-5.984 2.707-8.396 4.854l-12.227-5.263-6 10.392 10.667 7.954zm29.246-16.395l-1.5-12.755h-8.47l-1.502 12.755c-3.755 1.012-7.113 2.992-9.79 5.658l-11.8-5.08-4.237 7.335 10.297 7.677c-.48 1.805-.734 3.7-.734 5.655s.255 3.85.734 5.655l-10.297 7.677 4.236 7.336 11.802-5.08c2.676 2.665 6.034 4.645 9.79 5.657l1.5 12.755h8.47l1.5-12.755c3.756-1.012 7.114-2.992 9.79-5.658l11.802 5.08 4.236-7.335-10.297-7.677c.48-1.805.734-3.7.734-5.655s-.255-3.85-.734-5.655l10.297-7.677-4.236-7.336-11.802 5.08c-2.676-2.665-6.034-4.645-9.79-5.657zM150 225c6.627 0 12-5.373 12-12s-5.373-12-12-12-12 5.373-12 12 5.373 12 12 12zm0-2c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10zM136.115 288.14c-1.552-.73-3.286-1.14-5.115-1.14-1.83 0-3.563.41-5.115 1.14l3.013 5.218c.654-.244 1.362-.377 2.102-.377.74 0 1.448.134 2.102.378l3.013-5.217zm1.73 1.003c2.86 1.99 4.81 5.19 5.114 8.857h-6.024c-.243-1.458-1.01-2.738-2.102-3.64l3.012-5.217zm-13.69 0c-2.86 1.99-4.81 5.19-5.114 8.857h6.024c.243-1.458 1.01-2.738 2.102-3.64l-3.012-5.217zM119.04 300c.304 3.668 2.256 6.868 5.114 8.857l3.012-5.217c-1.09-.902-1.86-2.182-2.102-3.64h-6.023zm6.845 9.86c1.552.73 3.286 1.14 5.115 1.14 1.83 0 3.563-.41 5.115-1.14l-3.013-5.218c-.654.244-1.362.377-2.102.377-.74 0-1.448-.134-2.102-.378l-3.013 5.217zm11.96-1.003c2.86-1.99 4.81-5.19 5.114-8.857h-6.024c-.243 1.458-1.01 2.738-2.102 3.64l3.012 5.217zm-4.672-19.62c-.7-.155-1.427-.237-2.173-.237s-1.473.082-2.173.237l1.052 1.822c.365-.052.74-.08 1.12-.08.38 0 .755.028 1.12.08l1.053-1.823zm5.195 3.002c.98 1.065 1.73 2.345 2.174 3.76h-2.103c-.284-.702-.664-1.354-1.123-1.94l1.05-1.82zm-14.736 0c-.98 1.065-1.73 2.345-2.174 3.76h2.103c.284-.702.664-1.354 1.123-1.94l-1.05-1.82zm-2.174 9.76c.444 1.415 1.195 2.695 2.174 3.76l1.05-1.82c-.458-.586-.838-1.238-1.12-1.94h-2.104zm7.37 6.763c.7.155 1.426.237 2.172.237.746 0 1.473-.082 2.173-.237l-1.052-1.822c-.365.052-.74.08-1.12.08-.38 0-.755-.028-1.12-.08l-1.053 1.823zm9.54-3.002c.98-1.065 1.73-2.345 2.174-3.76h-2.103c-.284.702-.664 1.354-1.123 1.94l1.05 1.82zm15.164-15.043c-.224-.61-.472-1.207-.743-1.792l2.96-3.06-1-1.73-4.134 1.034c-.373-.53-.766-1.04-1.18-1.536l2.07-3.726-1.414-1.414-3.726 2.07c-.495-.414-1.007-.807-1.535-1.18l1.036-4.133-1.732-1-3.06 2.96c-.584-.27-1.182-.518-1.79-.742l-.07-4.255-1.933-.518-2.19 3.652c-.63-.108-1.27-.192-1.92-.25L132 271h-2l-1.17 4.097c-.65.058-1.29.142-1.92.25l-2.19-3.652-1.933.518-.07 4.255c-.61.224-1.207.472-1.792.743l-3.06-2.96-1.73 1 1.034 4.134c-.53.373-1.04.766-1.536 1.18l-3.726-2.07-1.414 1.414 2.07 3.726c-.414.495-.807 1.007-1.18 1.535l-4.133-1.036-1 1.732 2.96 3.06c-.27.584-.518 1.182-.742 1.79l-4.255.07-.518 1.933 3.652 2.19c-.108.63-.192 1.27-.25 1.92L103 298v2l4.097 1.17c.058.65.142 1.29.25 1.92l-3.652 2.19.518 1.933 4.255.07c.224.61.472 1.207.743 1.792l-2.96 3.06 1 1.73 4.134-1.034c.373.53.766 1.04 1.18 1.536l-2.07 3.726 1.414 1.414 3.726-2.07c.495.414 1.007.807 1.535 1.18l-1.036 4.133 1.732 1 3.06-2.96c.584.27 1.182.518 1.79.742l.07 4.255 1.933.518 2.19-3.652c.63.108 1.27.192 1.92.25L130 327h2l1.17-4.097c.65-.058 1.29-.142 1.92-.25l2.19 3.652 1.933-.518.07-4.255c.61-.224 1.207-.472 1.792-.743l3.06 2.96 1.73-1-1.034-4.134c.53-.373 1.04-.766 1.536-1.18l3.726 2.07 1.414-1.414-2.07-3.726c.414-.495.807-1.007 1.18-1.535l4.133 1.036 1-1.732-2.96-3.06c.27-.584.518-1.182.742-1.79l4.255-.07.518-1.933-3.652-2.19c.108-.63.192-1.27.25-1.92L159 300v-2l-4.097-1.17c-.058-.65-.142-1.29-.25-1.92l3.652-2.19-.518-1.933-4.255-.07zM109 299c0 12.15 9.85 22 22 22s22-9.85 22-22-9.85-22-22-22-22 9.85-22 22zm18 0c0 2.21 1.79 4 4 4s4-1.79 4-4-1.79-4-4-4-4 1.79-4 4zm2 0c0 1.105.895 2 2 2s2-.895 2-2-.895-2-2-2-2 .895-2 2zm15 0c0 2.21 1.79 4 4 4s4-1.79 4-4-1.79-4-4-4-4 1.79-4 4zm2 0c0 1.105.895 2 2 2s2-.895 2-2-.895-2-2-2-2 .895-2 2zm-8.5 11.258c-1.913 1.105-2.57 3.55-1.464 5.464 1.104 1.914 3.55 2.57 5.464 1.465 1.913-1.105 2.57-3.55 1.464-5.465-1.104-1.913-3.55-2.568-5.464-1.464zm-13 0c-1.913-1.104-4.36-.45-5.464 1.464-1.105 1.914-.45 4.36 1.464 5.465 1.913 1.104 4.36.45 5.464-1.465 1.105-1.913.45-4.36-1.464-5.464zM118 299c0-2.21-1.79-4-4-4s-4 1.79-4 4 1.79 4 4 4 4-1.79 4-4zm6.5-11.258c1.913-1.105 2.57-3.55 1.464-5.464-1.104-1.914-3.55-2.57-5.464-1.465-1.913 1.105-2.57 3.55-1.464 5.465 1.104 1.913 3.55 2.568 5.464 1.464zm13 0c1.913 1.104 4.36.45 5.464-1.464 1.105-1.914.45-4.36-1.464-5.465-1.913-1.104-4.36-.45-5.464 1.465-1.105 1.913-.45 4.36 1.464 5.464zm1 24.248c-.957.553-1.284 1.776-.732 2.732.552.957 1.775 1.285 2.732.732.957-.552 1.284-1.775.732-2.732-.552-.956-1.775-1.284-2.732-.732zm-15 0c-.957-.552-2.18-.224-2.732.732-.552.957-.225 2.18.732 2.732.957.553 2.18.225 2.732-.732.552-.956.225-2.18-.732-2.732zM116 299c0-1.105-.895-2-2-2s-2 .895-2 2 .895 2 2 2 2-.895 2-2zm7.5-12.99c.957-.553 1.284-1.776.732-2.732-.552-.957-1.775-1.285-2.732-.732-.957.552-1.284 1.775-.732 2.732.552.956 1.775 1.284 2.732.732zm15 0c.957.552 2.18.224 2.732-.732.552-.957.225-2.18-.732-2.732-.957-.553-2.18-.225-2.732.732-.552.956-.225 2.18.732 2.732zM248.997 275.802c-.643 1.607-.997 3.36-.997 5.198 0 1.837.354 3.59.997 5.198l-33.873 19.556C211.214 298.366 209 289.94 209 281c0-8.94 2.214-17.366 6.124-24.754l33.873 19.556zM251 272.34c2.173-2.758 5.36-4.678 9-5.198v-39.105c-18.067.67-33.822 10.384-42.873 24.746L251 272.34zm0 17.32c2.173 2.758 5.36 4.678 9 5.198v39.105c-18.067-.67-33.822-10.384-42.873-24.746L251 289.66zm13 5.198c3.64-.52 6.827-2.44 9-5.197l33.873 19.557c-9.05 14.362-24.806 24.076-42.873 24.746v-39.105zm11.003-8.66c.643-1.607.997-3.36.997-5.198 0-1.837-.354-3.59-.997-5.198l33.873-19.556C312.786 263.634 315 272.06 315 281c0 8.94-2.214 17.366-6.124 24.754l-33.873-19.556zM273 272.338c-2.173-2.756-5.36-4.676-9-5.196v-39.105c18.067.67 33.822 10.384 42.873 24.746L273 272.34zm-57.042-13.3C212.78 265.687 211 273.135 211 281c0 7.864 1.78 15.312 4.958 21.963l30.622-17.68c-.378-1.363-.58-2.8-.58-4.283 0-1.484.202-2.92.58-4.284l-30.622-17.68zm4.007-6.926c8.486-12.325 22.253-20.733 38.035-21.957v35.35c-2.86.735-5.41 2.242-7.416 4.285l-30.62-17.678zm0 57.776c8.486 12.325 22.253 20.733 38.035 21.957v-35.35c-2.86-.735-5.41-2.242-7.416-4.285l-30.62 17.678zM266 331.845c15.782-1.224 29.55-9.632 38.035-21.957l-30.62-17.678c-2.005 2.043-4.555 3.55-7.415 4.286v35.35zm42.042-28.882c3.178-6.65 4.958-14.1 4.958-21.963 0-7.864-1.78-15.312-4.958-21.963l-30.622 17.68c.378 1.363.58 2.8.58 4.283 0 1.484-.202 2.92-.58 4.284l30.622 17.68zm-4.007-50.85c-8.486-12.326-22.253-20.734-38.035-21.958v35.35c2.86.735 5.41 2.242 7.416 4.285l30.62-17.678zm-59.618-26.4c-3.15 1-6.184 2.264-9.076 3.763l-5.185-6.3-2.31 1.333 2.865 7.646c-2.765 1.774-5.37 3.778-7.786 5.982l-6.65-4.75-1.886 1.886 4.75 6.65c-2.204 2.417-4.208 5.02-5.982 7.786l-7.647-2.865-1.334 2.31 6.3 5.186c-1.5 2.893-2.762 5.927-3.763 9.077l-8.12-.787-.69 2.576 7.43 3.38c-.69 3.157-1.12 6.41-1.272 9.737l-8.06 1.344v2.666l8.06 1.344c.152 3.327.583 6.58 1.272 9.738l-7.428 3.38.69 2.575 8.12-.787c1 3.15 2.263 6.184 3.762 9.076l-6.3 5.185 1.333 2.31 7.646-2.865c1.774 2.765 3.778 5.37 5.982 7.786l-4.75 6.65 1.886 1.886 6.65-4.75c2.417 2.204 5.02 4.208 7.786 5.982l-2.865 7.647 2.31 1.334 5.186-6.3c2.893 1.5 5.927 2.762 9.077 3.763l-.787 8.12 2.576.69 3.38-7.43c3.157.69 6.41 1.12 9.737 1.272l1.344 8.06h2.666l1.344-8.06c3.327-.152 6.58-.583 9.738-1.272l3.38 7.428 2.575-.69-.787-8.12c3.15-1 6.184-2.263 9.076-3.762l5.185 6.3 2.31-1.333-2.865-7.646c2.765-1.774 5.37-3.778 7.786-5.982l6.65 4.75 1.886-1.886-4.75-6.65c2.204-2.417 4.208-5.02 5.982-7.786l7.647 2.865 1.334-2.31-6.3-5.186c1.5-2.893 2.762-5.927 3.763-9.077l8.12.787.69-2.576-7.43-3.38c.69-3.157 1.12-6.41 1.272-9.737l8.06-1.344v-2.666l-8.06-1.344c-.152-3.327-.583-6.58-1.272-9.738l7.428-3.38-.69-2.575-8.12.787c-1-3.15-2.263-6.184-3.762-9.076l6.3-5.185-1.333-2.31-7.646 2.865c-1.774-2.765-3.778-5.37-5.982-7.786l4.75-6.65-1.886-1.886-6.65 4.75c-2.417-2.204-5.02-4.208-7.786-5.982l2.865-7.647-2.31-1.334-5.186 6.3c-2.893-1.5-5.927-2.762-9.077-3.763l.787-8.12-2.576-.69-3.38 7.43c-3.157-.69-6.41-1.12-9.737-1.272l-1.344-8.06h-2.666l-1.344 8.06c-3.327.152-6.58.583-9.738 1.272l-3.38-7.428-2.575.69.787 8.12zm-2.118-1.404c-2.214.768-4.368 1.663-6.454 2.675l-5.248-6.375-5.196 3 2.9 7.74c-1.928 1.31-3.776 2.732-5.534 4.252l-6.73-4.807-4.243 4.243 4.807 6.73c-1.52 1.758-2.94 3.606-4.252 5.534l-7.74-2.9-3 5.196 6.375 5.248c-1.012 2.086-1.907 4.24-2.676 6.453l-8.216-.797-1.553 5.795 7.52 3.42c-.432 2.265-.736 4.575-.904 6.923L194 278v6l8.156 1.36c.168 2.347.472 4.657.903 6.922l-7.52 3.42 1.554 5.795 8.215-.796c.768 2.214 1.663 4.368 2.675 6.454l-6.375 5.248 3 5.196 7.74-2.9c1.31 1.928 2.732 3.776 4.252 5.534l-4.807 6.73 4.243 4.243 6.73-4.807c1.758 1.52 3.606 2.94 5.534 4.252l-2.9 7.74 5.196 3 5.248-6.375c2.086 1.012 4.24 1.907 6.453 2.676l-.797 8.216 5.795 1.553 3.42-7.52c2.265.432 4.575.736 6.923.904L259 349h6l1.36-8.156c2.347-.168 4.657-.472 6.922-.903l3.42 7.52 5.795-1.554-.796-8.215c2.214-.768 4.368-1.663 6.454-2.675l5.248 6.375 5.196-3-2.9-7.74c1.928-1.31 3.776-2.732 5.534-4.252l6.73 4.807 4.243-4.243-4.807-6.73c1.52-1.758 2.94-3.606 4.252-5.534l7.74 2.9 3-5.196-6.375-5.248c1.012-2.086 1.907-4.24 2.676-6.453l8.216.797 1.553-5.795-7.52-3.42c.432-2.265.736-4.575.904-6.923L330 284v-6l-8.156-1.36c-.168-2.347-.472-4.657-.903-6.922l7.52-3.42-1.554-5.795-8.215.796c-.768-2.214-1.663-4.368-2.675-6.454l6.375-5.248-3-5.196-7.74 2.9c-1.31-1.928-2.732-3.776-4.252-5.534l4.807-6.73-4.243-4.243-6.73 4.807c-1.758-1.52-3.606-2.94-5.534-4.252l2.9-7.74-5.196-3-5.248 6.375c-2.086-1.012-4.24-1.907-6.453-2.676l.797-8.216-5.795-1.553-3.42 7.52c-2.265-.432-4.575-.736-6.923-.904L265 213h-6l-1.36 8.156c-2.347.168-4.657.472-6.922.903l-3.42-7.52-5.795 1.554.796 8.215zM262 290c4.97 0 9-4.03 9-9s-4.03-9-9-9-9 4.03-9 9 4.03 9 9 9zm0-2c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zM0 244.514l1.76.254 6.41 3.07c1.4-2.066 3.01-3.98 4.798-5.71l-4.14-5.782-1.01-3.07 1.227-1.028 2.847 1.527 4.974 5.078c2.006-1.457 4.17-2.712 6.458-3.735l-1.91-6.84.1-3.23 1.505-.547 2.153 2.41 2.933 6.467c2.36-.673 4.818-1.112 7.35-1.288L36 225l1.2-3h1.6l1.2 3 .545 7.09c2.53.175 4.99.614 7.35 1.287l2.932-6.468 2.154-2.41 1.505.548.1 3.23-1.91 6.84c2.29 1.023 4.453 2.278 6.46 3.735l4.973-5.078 2.847-1.527 1.226 1.028-1.008 3.07-4.14 5.782c1.788 1.73 3.398 3.644 4.797 5.71l6.41-3.07 3.197-.46.8 1.385-1.998 2.54-5.862 4.012c1.082 2.22 1.943 4.566 2.553 7.012l7.07-.693 3.162.66.278 1.576-2.746 1.703-6.885 1.767c.125 1.226.19 2.47.19 3.73 0 1.26-.065 2.504-.19 3.73l6.884 1.767 2.746 1.703-.278 1.576-3.163.66-7.07-.693c-.61 2.446-1.47 4.793-2.552 7.012l5.86 4.013 2 2.54-.8 1.385-3.2-.46-6.41-3.072c-1.398 2.068-3.008 3.982-4.796 5.712l4.14 5.782 1.01 3.07-1.227 1.028-2.847-1.527-4.974-5.078c-2.006 1.457-4.17 2.712-6.458 3.735l1.91 6.84-.1 3.23-1.505.547-2.153-2.41-2.933-6.467c-2.36.673-4.818 1.112-7.35 1.288L40 311l-1.2 3h-1.6l-1.2-3-.545-7.09c-2.53-.175-4.99-.614-7.35-1.287l-2.932 6.468-2.154 2.41-1.505-.548-.1-3.23 1.91-6.84c-2.29-1.023-4.453-2.278-6.46-3.735l-4.973 5.078-2.847 1.527-1.226-1.028 1.008-3.07 4.14-5.782c-1.788-1.73-3.398-3.644-4.797-5.71l-6.41 3.07-1.76.254v-3.882l5.622-3.85c-1.082-2.218-1.943-4.565-2.553-7.01l-3.07.3v-4.752l2.19-.562C2.066 270.504 2 269.26 2 268c0-1.26.065-2.504.19-3.73L0 263.708v-4.752l3.07.3c.61-2.445 1.47-4.792 2.552-7.01L0 248.395v-3.882zm0-1.876l2.76.398 4.753 2.277c.885-1.187 1.837-2.32 2.852-3.396l-3.07-4.286-1.68-5.115 3.063-2.57 4.746 2.544 3.686 3.762c1.23-.812 2.513-1.554 3.84-2.22l-1.416-5.07.17-5.383 3.758-1.37 3.59 4.015 2.174 4.793c1.427-.337 2.886-.594 4.37-.766L34 225l2-5h4l2 5 .404 5.252c1.484.172 2.943.43 4.37.766l2.174-4.793 3.59-4.014 3.758 1.37.17 5.38-1.416 5.07c1.327.668 2.61 1.41 3.84 2.222l3.686-3.763 4.746-2.546 3.064 2.57-1.682 5.117-3.07 4.287c1.016 1.075 1.968 2.21 2.853 3.396l4.752-2.277 5.33-.768 2 3.464-3.33 4.232-4.343 2.973c.585 1.35 1.093 2.743 1.52 4.17l5.235-.513 5.27 1.1.696 3.94-4.577 2.838-5.104 1.31c.043.735.064 1.474.064 2.218s-.02 1.483-.064 2.217l5.105 1.31 4.578 2.838-.695 3.94-5.27 1.1-5.237-.512c-.426 1.427-.934 2.82-1.52 4.17l4.343 2.973 3.33 4.232-2 3.464-5.33-.768-4.753-2.277c-.885 1.187-1.837 2.32-2.852 3.396l3.07 4.286 1.68 5.115-3.063 2.57-4.746-2.544-3.686-3.762c-1.23.812-2.513 1.554-3.84 2.22l1.416 5.07-.17 5.383-3.758 1.37-3.59-4.015-2.174-4.793c-1.427.337-2.886.594-4.37.766L42 311l-2 5h-4l-2-5-.404-5.252c-1.484-.172-2.943-.43-4.37-.766l-2.174 4.793-3.59 4.014-3.758-1.37-.17-5.38 1.416-5.07c-1.327-.668-2.61-1.41-3.84-2.222l-3.686 3.763-4.746 2.546-3.064-2.57 1.682-5.117 3.07-4.287c-1.016-1.075-1.968-2.21-2.853-3.396l-4.752 2.277-2.76.398v-8.174l3.103-2.125c-.585-1.35-1.093-2.743-1.52-4.17L0 279.048v-8.815l.064-.016C.02 269.483 0 268.744 0 268s.02-1.483.064-2.217L0 265.767v-8.815l1.584.155c.426-1.427.934-2.82 1.52-4.17L0 250.812v-8.174zM38 272c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0-2c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zm0-26c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm24 24c0 2.21 1.79 4 4 4s4-1.79 4-4-1.79-4-4-4-4 1.79-4 4zm-24 24c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-24-24c0-2.21-1.79-4-4-4s-4 1.79-4 4 1.79 4 4 4 4-1.79 4-4zm24-26c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zm26 26c0 1.105.895 2 2 2s2-.895 2-2-.895-2-2-2-2 .895-2 2zm-26 26c-1.105 0-2 .895-2 2s.895 2 2 2 2-.895 2-2-.895-2-2-2zm-26-26c0-1.105-.895-2-2-2s-2 .895-2 2 .895 2 2 2 2-.895 2-2zm3.373 22.627c4.686 4.687 12.284 4.687 16.97 0 4.686-4.686 4.686-12.284 0-16.97-4.686-4.686-12.284-4.686-16.97 0-4.687 4.686-4.687 12.284 0 16.97zm0-45.254c-4.687 4.686-4.687 12.284 0 16.97 4.686 4.686 12.284 4.686 16.97 0 4.686-4.686 4.686-12.284 0-16.97-4.686-4.687-12.284-4.687-16.97 0zm45.254 0c-4.686-4.687-12.284-4.687-16.97 0-4.686 4.686-4.686 12.284 0 16.97 4.686 4.686 12.284 4.686 16.97 0 4.687-4.686 4.687-12.284 0-16.97zm0 45.254c4.687-4.686 4.687-12.284 0-16.97-4.686-4.686-12.284-4.686-16.97 0-4.686 4.686-4.686 12.284 0 16.97 4.686 4.687 12.284 4.687 16.97 0zM45.07 260.93c3.906 3.904 10.238 3.904 14.143 0 3.905-3.906 3.905-10.238 0-14.143-3.905-3.905-10.237-3.905-14.142 0-3.904 3.905-3.904 10.237 0 14.142zm0 14.14c-3.904 3.906-3.904 10.238 0 14.143 3.906 3.905 10.238 3.905 14.143 0 3.905-3.905 3.905-10.237 0-14.142-3.905-3.904-10.237-3.904-14.142 0zm-14.14 0c-3.906-3.904-10.238-3.904-14.143 0-3.905 3.906-3.905 10.238 0 14.143 3.905 3.905 10.237 3.905 14.142 0 3.904-3.905 3.904-10.237 0-14.142zm0-14.14c3.904-3.906 3.904-10.238 0-14.143-3.906-3.905-10.238-3.905-14.143 0-3.905 3.905-3.905 10.237 0 14.142 3.905 3.904 10.237 3.904 14.142 0zM261.822 15.54c-1.043.36-2.06.783-3.042 1.26l-2.914-3.013-1.732 1 1.154 4.034c-.91.618-1.78 1.288-2.61 2.005l-3.598-2.16-1.415 1.415 2.16 3.6c-.717.828-1.387 1.7-2.004 2.608l-4.033-1.154-1 1.732 3.013 2.914c-.477.983-.9 2-1.26 3.042l-4.19-.07-.518 1.932 3.665 2.035c-.203 1.066-.347 2.155-.425 3.262L239 41v2l4.072 1.018c.078 1.107.222 2.196.425 3.263l-3.665 2.036.517 1.932 4.19-.07c.36 1.043.783 2.06 1.26 3.042l-3.013 2.914 1 1.732 4.034-1.154c.618.91 1.288 1.78 2.005 2.61l-2.16 3.598 1.415 1.415 3.6-2.16c.828.717 1.7 1.387 2.608 2.004l-1.154 4.033 1.732 1 2.914-3.013c.983.477 2 .9 3.042 1.26l-.07 4.19 1.932.518 2.035-3.665c1.066.203 2.155.347 3.262.425L270 74h2l1.018-4.072c1.107-.078 2.196-.222 3.263-.425l2.036 3.665 1.932-.517-.07-4.19c1.043-.36 2.06-.783 3.042-1.26l2.914 3.013 1.732-1-1.154-4.034c.91-.618 1.78-1.288 2.61-2.005l3.598 2.16 1.415-1.415-2.16-3.6c.717-.828 1.387-1.7 2.004-2.608l4.033 1.154 1-1.732-3.013-2.914c.477-.983.9-2 1.26-3.042l4.19.07.518-1.932-3.665-2.035c.203-1.066.347-2.155.425-3.262L303 43v-2l-4.072-1.018c-.078-1.107-.222-2.196-.425-3.263l3.665-2.036-.517-1.932-4.19.07c-.36-1.043-.783-2.06-1.26-3.042l3.013-2.914-1-1.732-4.034 1.154c-.618-.91-1.288-1.78-2.005-2.61l2.16-3.598-1.415-1.415-3.6 2.16c-.828-.717-1.7-1.387-2.608-2.004l1.154-4.033-1.732-1-2.914 3.013c-.983-.477-2-.9-3.042-1.26l.07-4.19-1.932-.518-2.035 3.665c-1.066-.203-2.155-.347-3.262-.425L272 10h-2l-1.018 4.072c-1.107.078-2.196.222-3.263.425l-2.036-3.665-1.932.517.07 4.19zM271 68c14.36 0 26-11.64 26-26s-11.64-26-26-26-26 11.64-26 26 11.64 26 26 26zm0-9c9.39 0 17-7.61 17-17s-7.61-17-17-17-17 7.61-17 17 7.61 17 17 17zm0-2c8.284 0 15-6.716 15-15 0-8.284-6.716-15-15-15-8.284 0-15 6.716-15 15 0 8.284 6.716 15 15 15zm0-8c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm0-2c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm0-14c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zm9 9c0 1.105.895 2 2 2s2-.895 2-2-.895-2-2-2-2 .895-2 2zm-9 9c-1.105 0-2 .895-2 2s.895 2 2 2 2-.895 2-2-.895-2-2-2zm-9-9c0-1.105-.895-2-2-2s-2 .895-2 2 .895 2 2 2 2-.895 2-2zM309.933 95.785c-.284.33-.54.683-.77 1.056l-4.267-.5-.618 1.903 3.748 2.104c-.017.215-.026.433-.026.653 0 .22.01.438.026.653l-3.748 2.104.618 1.902 4.268-.5c.228.372.485.725.77 1.055l-1.796 3.905 1.618 1.176 3.158-2.913c.4.167.814.303 1.243.404L315 113h2l.843-4.213c.43-.1.844-.237 1.243-.404l3.158 2.913 1.618-1.176-1.795-3.905c.284-.33.54-.683.77-1.056l4.267.5.618-1.903-3.748-2.104c.017-.215.026-.433.026-.653 0-.22-.01-.438-.026-.653l3.748-2.104-.618-1.902-4.268.5c-.228-.372-.485-.725-.77-1.055l1.796-3.905-1.618-1.176-3.158 2.913c-.4-.167-.814-.303-1.243-.404L317 89h-2l-.843 4.213c-.43.1-.844.237-1.243.404l-3.158-2.913-1.618 1.176 1.795 3.905zM316 106c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM75.734 179.206c-.562.453-1.075.966-1.528 1.528l-2.098-.6-1 1.732 1.567 1.515c-.258.666-.448 1.366-.56 2.09L70 186v2l2.116.53c.11.724.3 1.424.56 2.09l-1.568 1.514 1 1.732 2.098-.6c.453.562.966 1.075 1.528 1.528l-.6 2.098 1.732 1 1.515-1.567c.666.258 1.366.448 2.09.56L81 199h2l.53-2.116c.724-.11 1.424-.3 2.09-.56l1.514 1.568 1.732-1-.6-2.098c.562-.453 1.075-.966 1.528-1.528l2.098.6 1-1.732-1.567-1.515c.258-.666.448-1.366.56-2.09L94 188v-2l-2.116-.53c-.11-.724-.3-1.424-.56-2.09l1.568-1.514-1-1.732-2.098.6c-.453-.562-.966-1.075-1.528-1.528l.6-2.098-1.732-1-1.515 1.567c-.666-.258-1.366-.448-2.09-.56L83 175h-2l-.53 2.116c-.724.11-1.424.3-2.09.56l-1.514-1.568-1.732 1 .6 2.098zm2.146.935c-1.12.676-2.064 1.62-2.74 2.74l-.145.253C74.36 184.28 74 185.597 74 187s.36 2.72.995 3.867l.146.253c.676 1.12 1.62 2.064 2.74 2.74l.253.145c1.146.634 2.464.995 3.867.995s2.72-.36 3.867-.995l.253-.146c1.12-.676 2.064-1.62 2.74-2.74l.145-.253c.634-1.146.995-2.464.995-3.867s-.36-2.72-.995-3.867l-.146-.253c-.676-1.12-1.62-2.064-2.74-2.74l-.253-.145C84.72 179.36 83.403 179 82 179s-2.72.36-3.867.995l-.253.146zM82 193c3.314 0 6-2.686 6-6s-2.686-6-6-6-6 2.686-6 6 2.686 6 6 6zm0-2c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zM360 139.08c-1.242.543-2.43 1.183-3.558 1.912l3.558 3.8v-5.712zm0 22.678l-14.172 6.646c-.54-2.044-.828-4.19-.828-6.404 0-7.82 3.59-14.8 9.21-19.384l5.79 10.497v8.645zm0 23.162c-6.088-2.66-10.912-7.675-13.32-13.893l13.32-2.56v16.453zm0-43.638c-.13.063-.26.127-.388.192l.388.414v-.606zm0 18.284l-12.73 5.97c-.178-1.153-.27-2.334-.27-3.536 0-6.328 2.556-12.06 6.69-16.218l6.31 11.44v2.344zm0 23.152c-4.502-2.177-8.186-5.778-10.47-10.218l10.47-2.01v12.228zm0 7.928l-4.46 6.58-4.11-2.004 2.536-7.862c-1.856-1.176-3.574-2.55-5.124-4.09l-7.085 4.234-2.877-3.553 5.652-6.087c-1.144-1.833-2.095-3.798-2.826-5.867l-8.236.702-1.028-4.455 7.733-2.988c-.116-1.07-.175-2.155-.175-3.255s.06-2.186.175-3.255l-7.733-2.988 1.028-4.455 8.236.702c.73-2.07 1.682-4.034 2.826-5.867l-5.652-6.088 2.877-3.554 7.085 4.235c1.55-1.54 3.268-2.914 5.124-4.09l-2.535-7.862 4.11-2.004 4.46 6.58v57.292zm0 3.537l-3.792 5.594-7.19-3.507 2.602-8.07c-1.075-.757-2.1-1.577-3.074-2.457l-7.27 4.346-5.034-6.218 5.816-6.265c-.633-1.13-1.2-2.303-1.693-3.512l-8.458.72-1.8-7.795 7.95-3.073c-.037-.644-.057-1.293-.057-1.947 0-.654.02-1.303.058-1.947l-7.95-3.073 1.8-7.795 8.457.72c.494-1.21 1.06-2.382 1.693-3.512l-5.816-6.265 5.035-6.217 7.27 4.347c.972-.88 1.998-1.7 3.073-2.456l-2.602-8.07 7.19-3.507 3.792 5.594v64.366zM34.172 168.404c.54-2.044.828-4.19.828-6.404 0-7.82-3.59-14.8-9.21-19.384l-8.673 15.726c.386.75.657 1.57.79 2.434l16.265 7.628zm-.85 2.623c-3.464 8.94-11.917 15.39-21.942 15.936l2.227-17.82c.77-.39 1.468-.9 2.07-1.506l17.644 3.39zM0 139.08c3.062-1.338 6.444-2.08 10-2.08 4.997 0 9.652 1.466 13.558 3.992l-12.278 13.11c-.417-.067-.844-.102-1.28-.102-.436 0-.863.035-1.28.102L0 144.792v-5.712zm0 22.678l2.093-.982c.133-.865.404-1.684.79-2.434L0 153.112v8.646zm0 23.162c2.664 1.164 5.57 1.877 8.62 2.043l-2.227-17.82c-.77-.39-1.468-.9-2.07-1.506l-4.323.83v16.453zm0-43.638C3.024 139.82 6.416 139 10 139c3.738 0 7.268.892 10.388 2.474l-9.87 10.54c-.172-.01-.345-.014-.518-.014-.173 0-.346.004-.517.013L0 141.888v-.606zm0 18.284l.34-.16c.09-.336.197-.665.32-.986L0 157.223v2.343zm0 23.152c1.972.954 4.102 1.634 6.34 1.992l-1.792-14.326c-.29-.188-.57-.39-.836-.608L0 170.49v12.228zm13.66 1.992c7.344-1.174 13.526-5.824 16.81-12.21l-14.182-2.724c-.267.217-.547.42-.836.608l-1.79 14.326zm19.07-19.174c.178-1.153.27-2.334.27-3.536 0-6.328-2.556-12.06-6.69-16.218l-6.97 12.638c.123.32.23.65.32.987l13.07 6.13zM0 133.354l.193.285c2.027-.7 4.153-1.19 6.35-1.443L7.713 124h4.573l1.17 8.197c2.198.252 4.324.742 6.35 1.442l4.654-6.866 4.11 2.004-2.536 7.862c1.856 1.176 3.574 2.55 5.124 4.09l7.085-4.234 2.877 3.553-5.652 6.087c1.144 1.833 2.095 3.798 2.826 5.867l8.236-.702 1.028 4.455-7.733 2.988c.116 1.07.175 2.155.175 3.255s-.06 2.186-.175 3.255l7.733 2.988-1.028 4.455-8.236-.702c-.73 2.07-1.682 4.034-2.826 5.867l5.652 6.088-2.877 3.554-7.085-4.235c-1.55 1.54-3.268 2.914-5.124 4.09l2.535 7.862-4.11 2.004-4.653-6.865c-2.027.7-4.153 1.19-6.35 1.443L12.287 200H7.713l-1.17-8.197c-2.198-.252-4.324-.742-6.35-1.442l-.194.286v-57.292zm0-3.537l.995 1.468c1.238-.363 2.507-.652 3.802-.864L6 122h8l1.203 8.42c1.295.213 2.564.502 3.802.865l4.787-7.062 7.19 3.507-2.602 8.07c1.075.757 2.1 1.577 3.074 2.457l7.27-4.346 5.034 6.218-5.816 6.265c.633 1.13 1.2 2.303 1.693 3.512l8.458-.72 1.8 7.795-7.95 3.073c.037.644.057 1.293.057 1.947 0 .654-.02 1.303-.058 1.947l7.95 3.073-1.8 7.795-8.457-.72c-.494 1.21-1.06 2.382-1.693 3.512l5.816 6.265-5.035 6.217-7.27-4.347c-.972.88-1.998 1.7-3.073 2.456l2.602 8.07-7.19 3.507-4.787-7.062c-1.238.363-2.507.652-3.802.864L14 202H6l-1.203-8.42c-1.295-.213-2.564-.502-3.802-.865L0 194.183v-64.366zM10 156c-3.314 0-6 2.686-6 6s2.686 6 6 6 6-2.686 6-6-2.686-6-6-6zm0 2c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zM149.716 360c3.863-2.626 8.393-4.344 13.284-4.847V360h-13.284zm32.568 0c-3.863-2.626-8.393-4.344-13.284-4.847V360h13.284zm-28.666 0c2.29-1.183 4.77-2.05 7.382-2.538V360h-7.382zm24.764 0c-2.29-1.183-4.77-2.05-7.382-2.538V360h7.382zm-40.84 0l-4.07-5.698 2.83-2.83 6.728 4.807c.69-.574 1.405-1.123 2.138-1.644l-2.9-7.74 3.464-2 5.25 6.376c.816-.374 1.648-.72 2.495-1.034l-.797-8.22 3.864-1.036 3.422 7.522c.88-.15 1.773-.266 2.675-.35L164 340h4l1.36 8.155c.9.083 1.793.2 2.674.35l3.422-7.523 3.864 1.035-.797 8.22c.847.315 1.68.66 2.495 1.035l5.25-6.377 3.464 2-2.9 7.74c.733.522 1.447 1.07 2.138 1.644l6.728-4.807 2.83 2.83-4.07 5.697h-56.915zm2.426 0l-3.902-5.463.47-.47 6.635 4.737c1.37-1.242 2.84-2.373 4.4-3.38l-2.86-7.63.58-.334 5.175 6.288c1.637-.842 3.35-1.555 5.128-2.126l-.785-8.105.644-.172 3.372 7.414c1.786-.385 3.624-.63 5.503-.72l1.34-8.04h.666l1.34 8.04c1.88.09 3.717.335 5.503.72l3.372-7.415.644.172-.785 8.105c1.777.57 3.49 1.284 5.128 2.126l5.176-6.288.58.334-2.86 7.63c1.56 1.007 3.03 2.138 4.4 3.38l6.633-4.738.47.47-3.9 5.464h-52.065zM360 52.702l-6.476 3.74C351.26 51.424 350 45.86 350 40c0-5.86 1.26-11.425 3.524-16.44L360 27.297v25.404zm0-39.16c-.873.988-1.697 2.02-2.47 3.093L360 18.06v-4.518zm0 52.916c-.873-.988-1.697-2.02-2.47-3.093L360 61.94v4.518zm0-16.066l-5.505 3.18C352.883 49.355 352 44.78 352 40c0-4.78.883-9.356 2.495-13.57L360 29.607v20.784zM357.58 0l1.507 3.278c-2.097 1.768-4.04 3.712-5.81 5.81L343.9 4.775l-1.646 2.265 6.995 7.584c-1.447 2.316-2.7 4.764-3.74 7.323l-10.24-1.2-.864 2.66 8.99 5.05c-.648 2.627-1.08 5.34-1.276 8.12L332 38.6v2.8l10.12 2.024c.196 2.78.628 5.492 1.277 8.12l-8.99 5.048.864 2.662 10.24-1.2c1.04 2.558 2.293 5.006 3.74 7.322l-6.996 7.583 1.646 2.264 9.378-4.31c1.768 2.096 3.712 4.04 5.81 5.808l-4.312 9.378 2.265 1.646 2.96-2.73V0h-2.42zm-2.158 0l1.252 2.725c-1.388 1.242-2.707 2.56-3.95 3.95l-9.502-4.37-3.526 4.855 7.085 7.68c-.935 1.607-1.785 3.27-2.542 4.983l-10.374-1.217-1.854 5.706 9.11 5.115c-.39 1.806-.68 3.65-.868 5.523L330 37v6l10.252 2.05c.188 1.874.48 3.717.868 5.523l-9.11 5.115 1.854 5.706 10.374-1.217c.757 1.713 1.607 3.376 2.543 4.982l-7.084 7.68 3.526 4.854 9.503-4.368c1.242 1.388 2.56 2.707 3.95 3.95l-4.37 9.502 4.855 3.526 2.84-2.62V0h-4.578zM0 354.984l4.624 4.265c2.316-1.447 4.764-2.7 7.323-3.74l-1.2-10.24 2.66-.864 5.05 8.99c2.627-.648 5.34-1.08 8.12-1.276L28.6 342h2.8l2.024 10.12c2.78.196 5.492.628 8.12 1.277l5.048-8.99 2.662.864-1.2 10.24c2.558 1.04 5.006 2.293 7.322 3.74l7.583-6.996 2.264 1.646-2.804 6.1H0v-5.016zm0-2.67l4.84 4.467c1.607-.935 3.27-1.785 4.983-2.542l-1.217-10.374 5.706-1.854 5.115 9.11c1.806-.39 3.65-.68 5.523-.868L27 340h6l2.05 10.252c1.874.188 3.717.48 5.523.868l5.115-9.11 5.706 1.854-1.217 10.374c1.713.757 3.376 1.607 4.982 2.543l7.68-7.084 4.854 3.526L64.578 360H0v-7.685zM360 244.514l-1.437-.207-.8 1.386 1.998 2.54.24.163v-3.882zm0 14.442l-4-.392-3.162.66-.278 1.576 2.746 1.703 4.694 1.205v-4.752zm0 13.336l-4.694 1.205-2.746 1.703.278 1.576 3.163.66 4-.392v-4.752zm0 15.312l-.24.164-1.997 2.54.8 1.385 1.437-.207v-3.882zm0 5.758l-2.57.37-2-3.464 3.33-4.232 1.24-.848v8.174zm0-14.314l-3.652.358-5.27-1.1-.696-3.94 4.577-2.838 5.04-1.295v8.815zm0-13.28l-5.04-1.296-4.578-2.837.695-3.94 5.27-1.1 3.653.357v8.815zm0-14.956l-1.24-.848-3.33-4.232 2-3.464 2.57.37v8.174zM360 354.984l-2.96-2.73-2.264 1.646 2.804 6.1H360v-5.016zm0-2.67l-2.84-2.618-4.854 3.526 3.116 6.778H360v-7.685z'/%3E%3C/g%3E%3C/svg%3E"); +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/FullScreenPattern/index.js b/FrontEnd/src/components/BasicComponents/FullScreenPattern/index.js new file mode 100644 index 0000000..875c0ef --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/FullScreenPattern/index.js @@ -0,0 +1,2 @@ +import FullScreenPattern from'./FullScreenPattern' +export default FullScreenPattern \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/HighlightedSpan/HighlightedSpan.js b/FrontEnd/src/components/BasicComponents/HighlightedSpan/HighlightedSpan.js new file mode 100644 index 0000000..21e2361 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/HighlightedSpan/HighlightedSpan.js @@ -0,0 +1,15 @@ +import React, { Component } from 'react' +import classes from './HighlightedSpan.scss' + +const HighlightedSpan = ({children, isHighlighted, isClickable = false, ...otherProps}) => { + const classNames = `${isHighlighted ? classes.highlighted : '' } ${isClickable ? classes.clickable : ''}` + return {children} +} + +HighlightedSpan.propTypes = { + children: React.PropTypes.any, + isHighlighted: React.PropTypes.bool.isRequired, + isClickable: React.PropTypes.bool +} + +export default HighlightedSpan \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/HighlightedSpan/HighlightedSpan.scss b/FrontEnd/src/components/BasicComponents/HighlightedSpan/HighlightedSpan.scss new file mode 100644 index 0000000..28a7838 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/HighlightedSpan/HighlightedSpan.scss @@ -0,0 +1,20 @@ +span.clickable { + cursor: pointer; cursor: hand; +} + +span.clickable:hover { + cursor: pointer; cursor: hand; + border-radius: 4px; + background-color: #B2EBF2; +} + +span.clickable:active { + cursor: pointer; cursor: hand; + border-radius: 4px; + background-color: #80DEEA; +} + +span.highlighted { + background-color: #fff176; + color: rgb(158, 158, 158); +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/HighlightedSpan/index.js b/FrontEnd/src/components/BasicComponents/HighlightedSpan/index.js new file mode 100644 index 0000000..3324581 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/HighlightedSpan/index.js @@ -0,0 +1,3 @@ +import HighlightedSpan from './HighlightedSpan' + +export default HighlightedSpan \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/InfiniteScroll/InfiniteScroll.js b/FrontEnd/src/components/BasicComponents/InfiniteScroll/InfiniteScroll.js new file mode 100644 index 0000000..a8eb492 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/InfiniteScroll/InfiniteScroll.js @@ -0,0 +1,74 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import deepEqual from 'deep-equal' +import { bindMethods } from './bindMethods.js' + +export default class InfiniteScroll extends React.Component { + constructor(props) { + super(props) + bindMethods(this, ['scrollListener', 'attachScrollListener', 'detachScrollListener']) + } + + componentDidMount() { + this.attachScrollListener() + } + + shouldComponentUpdate(nextProps) { + return !deepEqual(this.props.children, nextProps.children) + } + + componentWillUnmount() { + this.detachScrollListener() + } + + render() { + return null + } + + safeCallOnScrollDown(isFirstPage) { + if (this.props.onScrollDown) { + this.props.onScrollDown(isFirstPage) + } + } + + scrollListener() { + const { hasMore, currentPage, anchorEl, threshold, loadMore } = this.props + let el = anchorEl + + this.safeCallOnScrollDown(el.scrollTop < el.offsetHeight * 0.75) + + if (el.scrollHeight > 0 && (el.scrollHeight - el.scrollTop - el.offsetHeight < threshold)) { + { hasMore && loadMore(currentPage + 1) } + } + } + + attachScrollListener() { + const el = this.props.anchorEl + + el.addEventListener('scroll', this.scrollListener) + el.addEventListener('resize', this.scrollListener) + this.scrollListener() + } + + detachScrollListener() { + const el = this.props.anchorEl + + el.removeEventListener('scroll', this.scrollListener) + el.removeEventListener('resize', this.scrollListener) + } +} + +InfiniteScroll.defaultProps = { + currentPage: 0, + hasMore: true, + threshold: 250 +} + +InfiniteScroll.PropTypes = { + currentPage: React.PropTypes.number.isRequired, + hasMore: React.PropTypes.bool, + loadMore: React.PropTypes.func.isRequired, + threshold: React.PropTypes.number, + onScrollDown: React.PropTypes.func, + anchorEl: React.PropTypes.object.isRequired +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/InfiniteScroll/bindMethods.js b/FrontEnd/src/components/BasicComponents/InfiniteScroll/bindMethods.js new file mode 100644 index 0000000..7b2df61 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/InfiniteScroll/bindMethods.js @@ -0,0 +1,8 @@ +export function bindMethods(component, names) { + if(typeof names === 'string') { + names = [names]; + } + names.forEach((name) => + component[name] = component[name].bind(component) + ); +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/InfiniteScroll/index.js b/FrontEnd/src/components/BasicComponents/InfiniteScroll/index.js new file mode 100644 index 0000000..f83c256 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/InfiniteScroll/index.js @@ -0,0 +1,3 @@ +import InfiniteScroll from './InfiniteScroll' + +export default InfiniteScroll \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/LoadingIndicator/LoadingIndicator.js b/FrontEnd/src/components/BasicComponents/LoadingIndicator/LoadingIndicator.js new file mode 100644 index 0000000..b8285f8 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/LoadingIndicator/LoadingIndicator.js @@ -0,0 +1,22 @@ +import React from 'react' +import CircularProgress from 'material-ui/CircularProgress' +import classes from './LoadingIndicator.scss' + +const LoadingIndicator = (props) => { + const { small, medium, large, freezed = false, blurred = false, color = '#00bcd4' } = props + const indicatorSize = (small ? 23 : (medium ? 40 : (large ? 50 : 40))) + const mode = freezed ? 'determinate' : 'indeterminate' + const className = blurred ? classes.circularProgressBlurred : classes.circularProgress + return
+ +
+} + +LoadingIndicator.propTypes = { + small: React.PropTypes.bool, + medium: React.PropTypes.bool, + large: React.PropTypes.bool, + freezed: React.PropTypes.bool +} + +export default LoadingIndicator diff --git a/FrontEnd/src/components/BasicComponents/LoadingIndicator/LoadingIndicator.scss b/FrontEnd/src/components/BasicComponents/LoadingIndicator/LoadingIndicator.scss new file mode 100644 index 0000000..937a46c --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/LoadingIndicator/LoadingIndicator.scss @@ -0,0 +1,17 @@ +div.circularProgress { + display: flex; + justify-content: center; +} + +div.circularProgressBlurred { + display: flex; + justify-content: center; + -webkit-filter: blur(3px); + filter: blur(3px); + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/LoadingIndicator/index.js b/FrontEnd/src/components/BasicComponents/LoadingIndicator/index.js new file mode 100644 index 0000000..d1223a2 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/LoadingIndicator/index.js @@ -0,0 +1,3 @@ +import LoadingIndicator from './LoadingIndicator' + +export default LoadingIndicator \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/NotificationIndicator/NotificationIndicator.js b/FrontEnd/src/components/BasicComponents/NotificationIndicator/NotificationIndicator.js new file mode 100644 index 0000000..32e4734 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/NotificationIndicator/NotificationIndicator.js @@ -0,0 +1,26 @@ +import React from 'react' +import Snackbar from 'material-ui/Snackbar' +import classes from './NotificationIndicator.scss' + +export const NotificationIndicator = ({close, isOpen, message, reason}) => { + const ERROR_COLOR = '#FF3333' + const INFO_COLOR = '#8BC34A' + + const isError = reason === 'error' + const textColor = isError ? ERROR_COLOR : INFO_COLOR + + return ( close() } + contentStyle={{ color: textColor, fontWeight: '600', display: 'flex', justifyContent: 'center', userSelect: 'none', cursor: 'default' }} + />) +} + +NotificationIndicator.propTypes = { + close: React.PropTypes.func.isRequired, + message: React.PropTypes.string.isRequired, + isOpen: React.PropTypes.bool.isRequired, + reason: React.PropTypes.string +} +export default NotificationIndicator diff --git a/FrontEnd/src/components/BasicComponents/NotificationIndicator/NotificationIndicator.scss b/FrontEnd/src/components/BasicComponents/NotificationIndicator/NotificationIndicator.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/BasicComponents/NotificationIndicator/index.js b/FrontEnd/src/components/BasicComponents/NotificationIndicator/index.js new file mode 100644 index 0000000..0453f13 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/NotificationIndicator/index.js @@ -0,0 +1,2 @@ +import NotificationIndicator from'./NotificationIndicator' +export default NotificationIndicator \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/TagsInput/TagsInput.js b/FrontEnd/src/components/BasicComponents/TagsInput/TagsInput.js new file mode 100644 index 0000000..b62494b --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/TagsInput/TagsInput.js @@ -0,0 +1,241 @@ +import React, { Component } from 'react' + +import AutosizeInput from 'react-input-autosize' +import Autosuggest from 'react-autosuggest' +import FontIcon from 'material-ui/FontIcon' + +import { Tag } from './components' +import classes from './TagsInput.scss' + +class TagsInput extends Component { + constructor() { + super() + this.state = { + inputValue: '', + suggestions: [] + } + } + + addTag(tagName) { + if (!tagName) { + return + } + + const tagType = 'manual' + + if (!this.props.tags.find(t => (t.name === tagName))) { + this.props.onAddTag(tagType, tagName) + } + + this.setState({ ...this.state, inputValue: '' }) + } + + removeTag(tagType, tagName) { + const currentTags = this.props.tags.map(t => t.name) + if (!currentTags || currentTags.length === 0) { + return + } + this.props.onRemoveTag(tagType, tagName) + } + + removeLastTag() { + const currentTags = this.props.tags + if (!currentTags || currentTags.length === 0) { + return + } + + const lastTag = currentTags[currentTags.length - 1] + if (lastTag.isFetching) { + return + } + + this.props.onRemoveTag(lastTag.type, lastTag.name) + } + + onChange(value) { + this.setState({ ...this.state, inputValue: value.trim() }) + value = value.replace(/[\s\,\;]/gim, ',') + + const newTags = value.split(',').map(t => t.trim().toLowerCase()) + + if (newTags.length > 1 && newTags[0] != '') { + this.addTag(newTags[0]) + } + } + + onKeyPress(event) { + if (event.charCode === 13) { // onEnter + this.addTag(this.state.inputValue) + return + } + } + + onKeyDown(event) { + if (event.keyCode === 8) { // onBackspace + if (!this.state.inputValue) { + this.removeLastTag() + return + } + } + } + + focusOnInput() { + if (!this.refs.suggestInput) { + return + } + this.refs.suggestInput.input.focus() + } + + autosizeInput(inputProps) { + return ( + + ) + } + + getSuggestions(value) { + + const inputValue = value.trim().toLowerCase() + const inputLength = inputValue.length + const suggestions = this.props.suggestions + + return inputLength === 0 ? suggestions.slice(0, 10) : suggestions.filter(suggestion => + suggestion.toLowerCase().slice(0, inputLength) === inputValue + ).slice(0, 10) + } + + onSuggestionsFetchRequested({ value }) { + this.setState({ + suggestions: this.getSuggestions(value) + }) + } + + onSuggestionsClearRequested = () => { + this.setState({ + suggestions: [] + }) + } + + render() { + const props = this.props + + const theme = { + container: { + display: 'inline-block', + position: 'relative', + margin: '4px', + overflow: 'visible' + }, + inputOpen: { + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0 + }, + suggestionsContainer: { + display: 'none' + }, + suggestionsContainerOpen: { + display: 'block', + position: 'absolute', + top: 25, + width: 120, + backgroundColor: '#fff', + boxShadow: '0 0 7px rgba(0, 0, 0, 0.4)', + borderRadius: '2px', + fontSize: 12, + zIndex: 2 + }, + suggestionsList: { + margin: 0, + padding: 0, + listStyleType: 'none', + overflow: 'hidden', + textOverflow: 'ellipsis' + }, + suggestion: { + cursor: 'pointer', + padding: '2px 4px' + }, + suggestionHighlighted: { + backgroundColor: 'rgba(0, 188, 212, 0.15)' + } + } + + const { performSearchByTag, showRemoveIcon = true, showAddField = true, style = {} } = this.props + + return ( +
{ + if (e.target.className == 'TAGS_CONTAINER') { + this.focusOnInput() + } + }}> + {this.props.tags.map((tag, idx) => + this.removeTag(tagType, tagName)} + onClick={(tagName) => performSearchByTag(tagName)} + tagName={tag.name} + tagType={tag.type} + isHighlighted={!!tag.highlight && !!tag.highlight.name} + isFetching={tag.isFetching} + showRemoveIcon={showRemoveIcon} + />) + } + {showAddField && s} + renderSuggestion={(suggestion) => {suggestion}} + onSuggestionSelected={(e, { suggestion, suggegstionValue, suggestionIndex, sectionIndex, method }) => { + this.addTag(suggestion) + }} + shouldRenderSuggestions={(value) => true} + onSuggestionsFetchRequested={e => this.onSuggestionsFetchRequested(e)} + onSuggestionsClearRequested={e => this.onSuggestionsClearRequested(e)} + inputProps={{ + value: this.state.inputValue, + onChange: (e, { newValue, method }) => this.onChange(newValue), + onKeyPress: (event) => this.onKeyPress(event), + onKeyDown: (event) => this.onKeyDown(event) + }} + theme={theme} + renderInputComponent={(inputProps) => this.autosizeInput(inputProps)} + />} +
+ ) + } +} + +TagsInput.propTypes = { + tags: React.PropTypes.array.isRequired, + suggestion: React.PropTypes.array, + onAddTag: React.PropTypes.func, + onRemoveTag: React.PropTypes.func, + showRemoveIcon: React.PropTypes.bool, + showAddField: React.PropTypes.bool, + performSearchByTag: React.PropTypes.func.isRequired, + style: React.PropTypes.object +} + +export default TagsInput + + + + diff --git a/FrontEnd/src/components/BasicComponents/TagsInput/TagsInput.scss b/FrontEnd/src/components/BasicComponents/TagsInput/TagsInput.scss new file mode 100644 index 0000000..88e05b9 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/TagsInput/TagsInput.scss @@ -0,0 +1,8 @@ +.tagInput { + border:none; + background-image:none; + background-color:transparent; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/Tag.js b/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/Tag.js new file mode 100644 index 0000000..ccdfdab --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/Tag.js @@ -0,0 +1,51 @@ +import React, { Component } from 'react' + +import ClearIcon from 'material-ui/svg-icons/content/clear' +import { LoadingIndicator } from 'components/BasicComponents' +import classes from './Tag.scss' + +const Tag = ({ tagName, tagType, onRemove, onClick, isHighlighted, isFetching, showRemoveIcon = true }) => { + const onRemoveCallback = onRemove + ? onRemove + : () => { } + + const onClickCallback = onClick + ? onClick + : () => { } + + return ( +
{ + e.stopPropagation() + onClickCallback(tagName) + }}> + {tagName} + {!isFetching && showRemoveIcon && { + e.stopPropagation() + onRemoveCallback(tagType, tagName) + }} + hoverColor='#FF5722' + style={{ color: 'inherit', width: '1em', height: '1em' }} + />} +
+ ) +} + +Tag.propTypes = { + tagName: React.PropTypes.string.isRequired, + tagType: React.PropTypes.string.isRequired, + onRemove: React.PropTypes.func, + onClick: React.PropTypes.func, + isHighlighted: React.PropTypes.bool, + showRemoveIcon: React.PropTypes.bool +} + +export default Tag + + + + diff --git a/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/Tag.scss b/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/Tag.scss new file mode 100644 index 0000000..5cf80a1 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/Tag.scss @@ -0,0 +1,41 @@ +.tag { + margin: 4px; + cursor: pointer; + word-wrap: break-word; + word-break: break-all; + font-size: 12px; + font-family: Roboto, sans-serif; + color: rgb(0, 188, 212); + padding: 2px; + background-color: rgba(0, 188, 212, 0.08); + transition: background-color 0.5s ease; + border-radius: 3px; +} + +.loading { + background-color: rgba(0, 188, 212, 0.2); +} + +.highlight { + background-color: #fff176; + color: rgb(158, 158, 158); +} + +.source { + background-color: #DFFBD8; + color: rgb(158, 158, 158); +} + +.auto { + background-color: #F7E2E2; + color: rgb(158, 158, 158); +} + +.tag > .removeTagButton { + display: block; + margin: 2px 1px 0 1px; +} + +.tag:hover { + background-color: #B2EBF2; +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/index.js b/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/index.js new file mode 100644 index 0000000..7d4ed1c --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/TagsInput/components/Tag/index.js @@ -0,0 +1,3 @@ +import Tag from './Tag' + +export default Tag \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/TagsInput/components/index.js b/FrontEnd/src/components/BasicComponents/TagsInput/components/index.js new file mode 100644 index 0000000..6c1aeca --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/TagsInput/components/index.js @@ -0,0 +1,5 @@ +import Tag from './Tag' + +export { + Tag +} \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/TagsInput/index.js b/FrontEnd/src/components/BasicComponents/TagsInput/index.js new file mode 100644 index 0000000..3761930 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/TagsInput/index.js @@ -0,0 +1,3 @@ +import TagsInput from './TagsInput' + +export default TagsInput \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/UpdatedDateTimeLabel.js b/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/UpdatedDateTimeLabel.js new file mode 100644 index 0000000..4f48ca0 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/UpdatedDateTimeLabel.js @@ -0,0 +1,24 @@ +import React, { Component } from 'react' +import HighlightedSpan from '../HighlightedSpan' + +import classes from './UpdatedDateTimeLabel.scss' + +const UpdatedDateTimeLabel = ({ meta, searchQuery, formatFunc, ...otherProps }) => { + const WHEN_QUERY = /((^|\s)when:)((today)|(yesterday)|(thisweek)|(thismonth)|(thisyear))/im + + const updatedDatetimeHighlighted = searchQuery ? WHEN_QUERY.test(searchQuery) : false + const updatedDatetime = meta.updated_datetime + const displayedUpdatedDateTime = updatedDatetime && formatFunc ? formatFunc(updatedDatetime) : updatedDatetime + + return ( + {displayedUpdatedDateTime} + ) +} + +UpdatedDateTimeLabel.propTypes = { + meta: React.PropTypes.object.isRequired, + searchQuery: React.PropTypes.string.isRequired, + formatFunc: React.PropTypes.func +} + +export default UpdatedDateTimeLabel \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/UpdatedDateTimeLabel.scss b/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/UpdatedDateTimeLabel.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/index.js b/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/index.js new file mode 100644 index 0000000..8e6a5a9 --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/UpdatedDateTimeLabel/index.js @@ -0,0 +1,3 @@ +import UpdatedDateTimeLabel from './UpdatedDateTimeLabel' + +export default UpdatedDateTimeLabel \ No newline at end of file diff --git a/FrontEnd/src/components/BasicComponents/index.js b/FrontEnd/src/components/BasicComponents/index.js new file mode 100644 index 0000000..f2f0f0e --- /dev/null +++ b/FrontEnd/src/components/BasicComponents/index.js @@ -0,0 +1,33 @@ +import NotificationIndicator from './NotificationIndicator' +import InfiniteScroll from './InfiniteScroll' +import CodeEditor from './CodeEditor' +import AmbarResponsiveLogo from './AmbarResponsiveLogo' +import FullScreenLoader from './FullScreenLoader' +import FullScreenPattern from './FullScreenPattern' +import AuthPageTemplate from './AuthPageTemplate' +import LoadingIndicator from './LoadingIndicator' +import FileAvatar from './FileAvatar' +import HighlightedSpan from './HighlightedSpan' +import TagsInput from './TagsInput' +import ClickableFilePath from './ClickableFilePath' +import AuthorLabel from './AuthorLabel' +import FileSizeLabel from './FileSizeLabel' +import UpdatedDateTimeLabel from './UpdatedDateTimeLabel' + +export { + NotificationIndicator, + InfiniteScroll, + CodeEditor, + AmbarResponsiveLogo, + FullScreenLoader, + FullScreenPattern, + AuthPageTemplate, + LoadingIndicator, + FileAvatar, + HighlightedSpan, + TagsInput, + ClickableFilePath, + AuthorLabel, + FileSizeLabel, + UpdatedDateTimeLabel +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/Search.js b/FrontEnd/src/components/Search/Search.js new file mode 100644 index 0000000..3312ca3 --- /dev/null +++ b/FrontEnd/src/components/Search/Search.js @@ -0,0 +1,169 @@ +import React, { Component } from 'react' +import { titles } from 'utils/' + +import { SearchResults, ImagePreview, SearchInput, SideMenu } from './components' +import { InfiniteScroll } from 'components/BasicComponents' +import UploadContainer from 'routes/SearchPage/containers/UploadModalContainer' +import ImagePreviewContainer from 'routes/SearchPage/containers/ImagePreviewContainer' + +import { cyan100, cyan300, cyan400 } from 'material-ui/styles/colors' +import MoreHoriz from 'material-ui/svg-icons/navigation/more-horiz' +import MediaQuery from 'react-responsive' +import ArrowUpward from 'material-ui/svg-icons/navigation/arrow-upward' +import FloatingActionButton from 'material-ui/FloatingActionButton' +import FlatButton from 'material-ui/FlatButton' + +import Dialog from 'material-ui/Dialog' + +import classes from './Search.scss' + +const Desktop = ({ children }) => + +class Search extends Component { + + timeoutId = null + + componentDidMount() { + const { setPageTitle, setAppHeader, loadTags, search, searchQuery, setQueryFromGetParam, setQuery, localization } = this.props + + setPageTitle(localization.searchPage.pageTitle) + setAppHeader({ + left: () => {localization.searchPage.pageTitle}, + center: (state) => { + return ( + ) + } + }) + loadTags() + setQueryFromGetParam() + } + + componentWillUnmount() { + const { cleanUpSearchResult } = this.props + cleanUpSearchResult() + } + + render() { + const { + search, + searchView, + fetching, + searchQuery, + hasMore, + scrolledDown, + setScrolledDown, + setPageTitle, + currentPage, + mode, + toggleUploadModal, + setAppHeader, + performSearchByQuery, + performSearchBySize, + performSearchByWhen, + performSearchByShow, + performSearchByTag, + setSearchResultView, + allTags, + localization + } = this.props + + return ( +
+ +
+ +
+
+ + { + (matches) => { + return (
{ this.containerNode = container }}> + + {this.containerNode && { + search(newPage, searchQuery) + }} + hasMore={hasMore} + onScrollDown={(isFirstPage) => setScrolledDown(!isFirstPage)} + />} +
) + } + } +
+
+
+ { this.containerNode.scrollTop = 0 }} + className={scrolledDown ? '' : 'hiddenWithAnimation'}> + + +
+
+ + +
+ ) + } +} + +Search.propTypes = { + searchView: React.PropTypes.string.isRequired, + setPageTitle: React.PropTypes.func.isRequired, + + setScrolledDown: React.PropTypes.func.isRequired, + scrolledDown: React.PropTypes.bool.isRequired, + + fetching: React.PropTypes.bool.isRequired, + + currentPage: React.PropTypes.number.isRequired, + hasMore: React.PropTypes.bool.isRequired, + + searchQuery: React.PropTypes.string.isRequired, + + loadTags: React.PropTypes.func.isRequired, + allTags: React.PropTypes.array.isRequired, + + toggleUploadModal: React.PropTypes.func.isRequired, + + setQuery: React.PropTypes.func.isRequired, + search: React.PropTypes.func.isRequired, + performSearchByQuery: React.PropTypes.func.isRequired, + performSearchBySize: React.PropTypes.func.isRequired, + performSearchByWhen: React.PropTypes.func.isRequired, + performSearchByShow: React.PropTypes.func.isRequired, + performSearchByTag: React.PropTypes.func.isRequired, + + setSearchResultView: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default Search \ No newline at end of file diff --git a/FrontEnd/src/components/Search/Search.scss b/FrontEnd/src/components/Search/Search.scss new file mode 100644 index 0000000..6feabd5 --- /dev/null +++ b/FrontEnd/src/components/Search/Search.scss @@ -0,0 +1,15 @@ +.header { + font-size: 16px; + font-weight: 700; +} + +.filter { + input[type="text"] { + height: 34px; + } +} + +.uploadFileBtn { + margin-top: 20px; +} + diff --git a/FrontEnd/src/components/Search/components/EmptyCard/EmptyCard.js b/FrontEnd/src/components/Search/components/EmptyCard/EmptyCard.js new file mode 100644 index 0000000..3c34704 --- /dev/null +++ b/FrontEnd/src/components/Search/components/EmptyCard/EmptyCard.js @@ -0,0 +1,34 @@ +import React, { Component } from 'react' +import { Card, CardActions, CardHeader, CardText, CardTitle } from 'material-ui/Card' +import Paper from 'material-ui/Paper' + +import classes from './EmptyCard.scss' + +const EmptyCard = (props) => { + const {title, textElement} = props + + return ( + + + {title}} + /> + + {textElement} + + + + ) +} + +EmptyCard.propTypes = { + title: React.PropTypes.string.isRequired, + textElement: React.PropTypes.object.isRequired +} + +export default EmptyCard + + + + diff --git a/FrontEnd/src/components/Search/components/EmptyCard/EmptyCard.scss b/FrontEnd/src/components/Search/components/EmptyCard/EmptyCard.scss new file mode 100644 index 0000000..026c4ae --- /dev/null +++ b/FrontEnd/src/components/Search/components/EmptyCard/EmptyCard.scss @@ -0,0 +1,12 @@ +.emptyCard { + margin: 10px; +} + +.emptyCardHeaderTitle { + font-size: 15px; + font-weight: 600; +} + +.emptyCardTitle { + padding-bottom: 0 !important; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/EmptyCard/index.js b/FrontEnd/src/components/Search/components/EmptyCard/index.js new file mode 100644 index 0000000..b7df7d9 --- /dev/null +++ b/FrontEnd/src/components/Search/components/EmptyCard/index.js @@ -0,0 +1,3 @@ +import EmptyCard from './EmptyCard' + +export default EmptyCard \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/EmptySearchResultsCard/EmptySearchResultsCard.js b/FrontEnd/src/components/Search/components/EmptySearchResultsCard/EmptySearchResultsCard.js new file mode 100644 index 0000000..700673f --- /dev/null +++ b/FrontEnd/src/components/Search/components/EmptySearchResultsCard/EmptySearchResultsCard.js @@ -0,0 +1,37 @@ +import React, { Component } from 'react' +import HintCard from '../HintCard' +import classes from './EmptySearchResultsCard.scss' + +class EmptySearchResultsCard extends Component { + render() { + const { searchQuery, performSearchByQuery, localization } = this.props + + if (searchQuery != '') { + return (
+ {searchQuery} - {localization.searchPage.nothingFoundDescriptionLabel}} + performSearchByQuery={performSearchByQuery} + localization={localization} + /> +
) + } + + return (
+ {localization.searchPage.searchTipsDescriptionLabel}} + performSearchByQuery={performSearchByQuery} + localization={localization} + /> +
) + } +} + +EmptySearchResultsCard.propTypes = { + searchQuery: React.PropTypes.string.isRequired, + performSearchByQuery: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default EmptySearchResultsCard diff --git a/FrontEnd/src/components/Search/components/EmptySearchResultsCard/EmptySearchResultsCard.scss b/FrontEnd/src/components/Search/components/EmptySearchResultsCard/EmptySearchResultsCard.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/Search/components/EmptySearchResultsCard/index.js b/FrontEnd/src/components/Search/components/EmptySearchResultsCard/index.js new file mode 100644 index 0000000..014a13a --- /dev/null +++ b/FrontEnd/src/components/Search/components/EmptySearchResultsCard/index.js @@ -0,0 +1,3 @@ +import EmptySearchResultsCard from './EmptySearchResultsCard' + +export default EmptySearchResultsCard \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/HintCard/HintCard.js b/FrontEnd/src/components/Search/components/HintCard/HintCard.js new file mode 100644 index 0000000..a9acc5d --- /dev/null +++ b/FrontEnd/src/components/Search/components/HintCard/HintCard.js @@ -0,0 +1,94 @@ +import React, { Component } from 'react' +import FlatButton from 'material-ui/FlatButton' +import EmptyCard from '../EmptyCard' +import classes from './HintCard.scss' + +const HintCard = (props) => { + const { title, description, performSearchByQuery, localization } = props + + const hintText = (

{localization.searchPage.refineTipsLabel}

+
    +
  • { performSearchByQuery('*') }}> + * + - {localization.searchPage.allFilesQueryLabel} +
  • +
  • { performSearchByQuery('John Smith') }}> + John Smith + - {localization.searchPage.simpleQueryLabel} +
  • +
  • { performSearchByQuery('"John Smith"') }}> + "John Smith" + - {localization.searchPage.pharseQueryLabel} +
  • +
  • { performSearchByQuery('"John Smith"~10') }}> + "John Smith"~10 + - {localization.searchPage.pharseQueryWithDistanceLabel} +
  • +
  • { performSearchByQuery('John~3') }}> + John~3 + - {localization.searchPage.fuzzyQueryLabel} +
  • +
  • { performSearchByQuery('filename:*.txt') }}> + filename:*.txt + - {localization.searchPage.filenameQueryLabel} +
  • +
  • { performSearchByQuery('size>1M') }}> + size>1M + - {localization.searchPage.sizeQueryLabel} +
  • +
  • { performSearchByQuery('when:today') }}> + when:today + - {localization.searchPage.whenQueryLabel} +
  • +
  • + { performSearchByQuery('author:*') }}> + author:* + - {localization.searchPage.authorQueryLabel} +
  • +
  • + { performSearchByQuery('tags:ocr,ui-upload') }}> + tags:ocr,ui-upload + - {localization.searchPage.tagsQueryLabel} +
  • +
  • + { performSearchByQuery('entities:"hello@ambar.cloud"') }}> + entities:"hello@ambar.cloud" + - {localization.searchPage.entitiesQueryLabel} +
  • +
  • + { performSearchByQuery('show:removed') }}> + show:removed + - {localization.searchPage.removedQueryLabel} +
  • +
+
) + + const emailText = (

+ {localization.searchPage.haveQuestionsLabel} {localization.searchPage.dropMessageLabel} +

) + + const textElement = (
+

{description}

+ {hintText} + {emailText} +
) + + return ( + + ) +} + +HintCard.propTypes = { + title: React.PropTypes.string.isRequired, + description: React.PropTypes.object.isRequired, + performSearchByQuery: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default HintCard + + + + diff --git a/FrontEnd/src/components/Search/components/HintCard/HintCard.scss b/FrontEnd/src/components/Search/components/HintCard/HintCard.scss new file mode 100644 index 0000000..55bda56 --- /dev/null +++ b/FrontEnd/src/components/Search/components/HintCard/HintCard.scss @@ -0,0 +1,22 @@ +.link, .link:hover,.link:visited { + color: #00acc1; + text-decoration: underline; + cursor: pointer; cursor: hand; +} + +span.clickableSpan { + color: #444477; + display: inline-block; +} + +span.clickableSpan:hover { + border-radius: 4px; + background-color: #B2EBF2; + cursor: pointer; cursor: hand; +} + +span.clickableSpan:active { + border-radius: 4px; + background-color: #80DEEA; + cursor: pointer; cursor: hand; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/HintCard/index.js b/FrontEnd/src/components/Search/components/HintCard/index.js new file mode 100644 index 0000000..8c345e9 --- /dev/null +++ b/FrontEnd/src/components/Search/components/HintCard/index.js @@ -0,0 +1,3 @@ +import HintCard from './HintCard' + +export default HintCard \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/ImagePreview/ImagePreview.js b/FrontEnd/src/components/Search/components/ImagePreview/ImagePreview.js new file mode 100644 index 0000000..175d332 --- /dev/null +++ b/FrontEnd/src/components/Search/components/ImagePreview/ImagePreview.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react' +import classes from './ImagePreview.scss' + +const ImagePreview = (props) => { + const { toggle, imageUrl, visible } = props + + const className = visible ? 'imagePreviewOverlayDiv' : 'imagePreviewOverlayDiv invisible' + + if (visible) { + return ( +
toggle()}> + +
+ ) + } + + return (
) +} + +ImagePreview.propTypes = { + visible: React.PropTypes.bool.isRequired, + imageUrl: React.PropTypes.string.isRequired, + toggle: React.PropTypes.func.isRequired +} + +export default ImagePreview \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/ImagePreview/ImagePreview.scss b/FrontEnd/src/components/Search/components/ImagePreview/ImagePreview.scss new file mode 100644 index 0000000..d274b02 --- /dev/null +++ b/FrontEnd/src/components/Search/components/ImagePreview/ImagePreview.scss @@ -0,0 +1,36 @@ +:global .imagePreviewOverlayDiv { + position: fixed; + z-index: 1500; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(0,0,0,0.541176); + opacity: 1; + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome and Opera */ + -webkit-transition: opacity 0.2s ease-in-out; + -moz-transition: opacity 0.2s ease-in-out; + -ms-transition: opacity 0.2s ease-in-out; + -o-transition: opacity 0.2s ease-in-out; + transition: opacity 0.2s ease-in-out; +} + +:global .imagePreviewOverlayDiv.invisible { + opacity: 0; +} + +.imagePreview { + max-width: 80%; + max-height: 80%; + box-shadow: rgba(0, 0, 0, 0.247059) 0px 14px 45px, rgba(0, 0, 0, 0.219608) 0px 10px 18px; + border-radius: 2px; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/ImagePreview/index.js b/FrontEnd/src/components/Search/components/ImagePreview/index.js new file mode 100644 index 0000000..226a868 --- /dev/null +++ b/FrontEnd/src/components/Search/components/ImagePreview/index.js @@ -0,0 +1,3 @@ +import ImagePreview from './ImagePreview' + +export default ImagePreview \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/SearchInput/SearchInput.js b/FrontEnd/src/components/Search/components/SearchInput/SearchInput.js new file mode 100644 index 0000000..b22503f --- /dev/null +++ b/FrontEnd/src/components/Search/components/SearchInput/SearchInput.js @@ -0,0 +1,79 @@ +import React, { Component } from 'react' +import TextField from 'material-ui/TextField' +import MenuItem from 'material-ui/MenuItem' +import RaisedButton from 'material-ui/RaisedButton' +import SearchIcon from 'material-ui/svg-icons/action/search' +import MediaQuery from 'react-responsive' +import classes from './SearchInput.scss' + +class SearchInput extends Component { + static timeoutId = null + + componentDidMount() { + this.refs.search_input.focus() + } + + shouldComponentUpdate(nextProp) { + return this.props.query !== nextProp.query + } + + render() { + const { search, setQuery, query, localization } = this.props + + const hintText = + {localization.searchPage.searchInputHintLabel} + {localization.searchPage.pageTitle} + + + return ( +
this.search_container = container} + > +
+ search(0, query)} /> +
+
+ { + if (event.charCode === 13) { + search(0, query) + return + } + }} + onKeyDown={(event) => { + clearTimeout(this.timeoutId) + }} + onChange={(event, newValue) => { + clearTimeout(this.timeoutId) + setQuery(newValue) + + this.timeoutId = setTimeout(() => { + search(0, newValue) + }, 500) + }} + underlineShow={false} + /> +
+
+ ) + } +} + +SearchInput.propTypes = { + query: React.PropTypes.string.isRequired, + search: React.PropTypes.func.isRequired, + setQuery: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default SearchInput \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/SearchInput/SearchInput.scss b/FrontEnd/src/components/Search/components/SearchInput/SearchInput.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/Search/components/SearchInput/index.js b/FrontEnd/src/components/Search/components/SearchInput/index.js new file mode 100644 index 0000000..2956329 --- /dev/null +++ b/FrontEnd/src/components/Search/components/SearchInput/index.js @@ -0,0 +1,3 @@ +import SearchInput from './SearchInput' + +export default SearchInput \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/SearchResults/SearchResults.js b/FrontEnd/src/components/Search/components/SearchResults/SearchResults.js new file mode 100644 index 0000000..6024e6b --- /dev/null +++ b/FrontEnd/src/components/Search/components/SearchResults/SearchResults.js @@ -0,0 +1,45 @@ +import React, { Component } from 'react' +import { constants } from 'utils' +import FolderViewContainer from 'routes/SearchPage/containers/FolderViewContainer' +import TableViewContainer from 'routes/SearchPage/containers/TableViewContainer' +import DetailedViewContainer from 'routes/SearchPage/containers/DetailedViewContainer' +import StatisticsViewContainer from 'routes/SearchPage/containers/StatisticsViewContainer' + +import classes from './SearchResults.scss' + +class SearchResults extends Component { + + getView(searchView) { + switch (searchView) { + case constants.TABLE_VIEW: + return + case constants.FOLDER_VIEW: + return + case constants.DETAILED_VIEW: + return + case constants.STATISTICS_VIEW: + return + default: + return + } + } + + render() { + const { + searchView, + hits, + folderHits, + searchQuery, + performSearchByQuery, + localization + } = this.props + + return this.getView(searchView) + } +} + +SearchResults.propTypes = { + searchView: React.PropTypes.string.isRequired +} + +export default SearchResults diff --git a/FrontEnd/src/components/Search/components/SearchResults/SearchResults.scss b/FrontEnd/src/components/Search/components/SearchResults/SearchResults.scss new file mode 100644 index 0000000..03d65dc --- /dev/null +++ b/FrontEnd/src/components/Search/components/SearchResults/SearchResults.scss @@ -0,0 +1,7 @@ +:global { + .hiddenWithAnimation { + visibility: hidden; + opacity: 0; + transition: visibility 0s, opacity 1s linear; + } +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/SearchResults/index.js b/FrontEnd/src/components/Search/components/SearchResults/index.js new file mode 100644 index 0000000..bafa7d4 --- /dev/null +++ b/FrontEnd/src/components/Search/components/SearchResults/index.js @@ -0,0 +1,3 @@ +import SearchResults from './SearchResults' + +export default SearchResults \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/SideMenu/SideMenu.js b/FrontEnd/src/components/Search/components/SideMenu/SideMenu.js new file mode 100644 index 0000000..b56477f --- /dev/null +++ b/FrontEnd/src/components/Search/components/SideMenu/SideMenu.js @@ -0,0 +1,130 @@ +import React, { Component } from 'react' +import RaisedButton from 'material-ui/RaisedButton' +import { List, ListItem } from 'material-ui/List' +import UploadFileIcon from 'material-ui/svg-icons/file/file-upload' +import Subheader from 'material-ui/Subheader' +import Divider from 'material-ui/Divider' +import { TagsInput } from 'components/BasicComponents' +import classes from './SideMenu.scss' +import { constants } from 'utils' + +const listItemStyle = { fontSize: '15px', padding: '7px 7px 7px 23px' } +const StyledListItem = (props) => + +const SecondaryText = (props) =>
+ +const subHeaderStyle = { fontSize: '15px', color: '#777777', lineHeight: '20px', cursor: 'default', fontFamily: 'Roboto, sans-serif' } +const MenuLabel = ({ children, ...props }) => {children} + +class SideMenu extends Component { + render() { + const { + performSearchByQuery, + performSearchBySize, + performSearchByWhen, + performSearchByShow, + performSearchByTag, + toggleUploadModal, + setSearchResultView, + searchView, + allTags, + localization + } = this.props + + return ( +
+ } + onTouchTap={toggleUploadModal} + /> + + {localization.searchPage.viewLabel} + + setSearchResultView(constants.DETAILED_VIEW)} + /> + setSearchResultView(constants.TABLE_VIEW)} + /> + setSearchResultView(constants.FOLDER_VIEW)} + /> + setSearchResultView(constants.STATISTICS_VIEW)} + /> + + {allTags.length > 0 && +
+ + + {localization.searchPage.tagsLabel} + + +
} + + {localization.searchPage.timeRangeLabel} + + performSearchByWhen('today')} /> + performSearchByWhen('yesterday')} /> + performSearchByWhen('thisweek')} /> + performSearchByWhen('thismonth')} /> + performSearchByWhen('thisyear')} /> + + + + + {localization.searchPage.trashLabel} + performSearchByShow('removed')} + /> + + + + performSearchByQuery('')} + style={{ color: '#dd6666' }} + /> + +
+ ) + } +} + +SideMenu.propTypes = { + performSearchByQuery: React.PropTypes.func.isRequired, + performSearchBySize: React.PropTypes.func.isRequired, + performSearchByWhen: React.PropTypes.func.isRequired, + performSearchByShow: React.PropTypes.func.isRequired, + performSearchByTag: React.PropTypes.func.isRequired, + toggleUploadModal: React.PropTypes.func.isRequired, + setSearchResultView: React.PropTypes.func.isRequired, + searchView: React.PropTypes.string.isRequired, + allTags: React.PropTypes.array.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default SideMenu + + + + diff --git a/FrontEnd/src/components/Search/components/SideMenu/SideMenu.scss b/FrontEnd/src/components/Search/components/SideMenu/SideMenu.scss new file mode 100644 index 0000000..ad7d844 --- /dev/null +++ b/FrontEnd/src/components/Search/components/SideMenu/SideMenu.scss @@ -0,0 +1,11 @@ +.sideMenuContainer { + padding-top: 20px; + display: flex; + flex-direction: column; +} + +.sideMenuList { + list-style-type: none; + padding: 0; + margin: 0; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/SideMenu/index.js b/FrontEnd/src/components/Search/components/SideMenu/index.js new file mode 100644 index 0000000..ed42b5f --- /dev/null +++ b/FrontEnd/src/components/Search/components/SideMenu/index.js @@ -0,0 +1,3 @@ +import SideMenu from './SideMenu' + +export default SideMenu \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/UploadFileModal/UploadFileModal.js b/FrontEnd/src/components/Search/components/UploadFileModal/UploadFileModal.js new file mode 100644 index 0000000..0cf73f8 --- /dev/null +++ b/FrontEnd/src/components/Search/components/UploadFileModal/UploadFileModal.js @@ -0,0 +1,112 @@ +import React, { Component } from 'react' +import FlatButton from 'material-ui/FlatButton' +import Dialog from 'material-ui/Dialog' +import Dropzone from 'react-dropzone' +import AutoComplete from 'material-ui/AutoComplete' +import UploadIcon from 'material-ui/svg-icons/file/cloud-upload' +import Avatar from 'material-ui/Avatar' +import Chip from 'material-ui/Chip' +import FileIcon from 'material-ui/svg-icons/file/attachment' +import CircularProgress from 'material-ui/CircularProgress' + +const UploadFileModal = (props) => { + const { + open, + fetching, + toggleModal, + addFilesToUpload, + removeFileToUpload, + filesToUpload, + uploadFiles, + localization + } = props + + const onDrop = (acceptedFiles, rejectedFiles) => addFilesToUpload(acceptedFiles) + const isUploadButtonDisabled = fetching || filesToUpload.length === 0 + + const uploadFileModalActions = [ + , + uploadFiles()} + /> + ] + + const uploadFrameStyle = { + width: '100%', + height: '150px', + borderWidth: '2px', + borderColor: '#BDBDBD', + borderStyle: 'dashed', + borderRadius: '5px', + backgroundColor: '#E0E0E0' + } + + const uploadFrameActiveStyle = { + borderColor: '#00BCD4' + } + + return ( + +
+ + {!fetching &&
+ +
{localization.uploadModal.hintLabel}
+
} + {fetching &&
+ +
} +
+ {filesToUpload.length > 0 &&
+ {filesToUpload.map((file, idx) => + { + if (fetching) return + removeFileToUpload(file) + }}> + } /> + {file.name} + ) + } +
+ } +
+
) +} + +UploadFileModal.propTypes = { + open: React.PropTypes.bool.isRequired, + fetching: React.PropTypes.bool.isRequired, + uploadFiles: React.PropTypes.func.isRequired, + toggleModal: React.PropTypes.func.isRequired, + addFilesToUpload: React.PropTypes.func.isRequired, + removeFileToUpload: React.PropTypes.func.isRequired, + filesToUpload: React.PropTypes.array.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default UploadFileModal \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/UploadFileModal/UploadFileModal.scss b/FrontEnd/src/components/Search/components/UploadFileModal/UploadFileModal.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/Search/components/UploadFileModal/index.js b/FrontEnd/src/components/Search/components/UploadFileModal/index.js new file mode 100644 index 0000000..2c74d62 --- /dev/null +++ b/FrontEnd/src/components/Search/components/UploadFileModal/index.js @@ -0,0 +1,3 @@ +import UploadFileModal from './UploadFileModal' + +export default UploadFileModal \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/DetailedView.js b/FrontEnd/src/components/Search/components/Views/DetailedView/DetailedView.js new file mode 100644 index 0000000..d7ff7e9 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/DetailedView.js @@ -0,0 +1,51 @@ +import React, { Component } from 'react' + +import EmptySearchResultsContainer from 'routes/SearchPage/containers/EmptySearchResultsContainer' +import DetailedCard from './components/DetailedCard' +import classes from './DetailedView.scss' + +class DetailedView extends Component { + componentDidMount() { + const { + search, + searchQuery + } = this.props + + search(0, searchQuery) + } + + render() { + const { + hits, + searchQuery, + urls + } = this.props + + if (!searchQuery || !hits || hits.size === 0) { + return + } + + return ( +
+ {Array.from(hits.values()).map((hit, idx) => + + )} +
+ ) + } +} + +DetailedView.propTypes = { + hits: React.PropTypes.object.isRequired, + search: React.PropTypes.func.isRequired, + searchQuery: React.PropTypes.string.isRequired, + urls: React.PropTypes.object.isRequired +} + +export default DetailedView diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/DetailedView.scss b/FrontEnd/src/components/Search/components/Views/DetailedView/DetailedView.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/DetailedCard.js b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/DetailedCard.js new file mode 100644 index 0000000..8c445e3 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/DetailedCard.js @@ -0,0 +1,162 @@ +import React, { Component } from 'react' +import { LoadingIndicator, TagsInput } from 'components/BasicComponents' + +import { Card, CardActions, CardText, CardTitle } from 'material-ui/Card' +import MediaQuery from 'react-responsive' +import Paper from 'material-ui/Paper' +import { Divider, FlatButton } from 'material-ui' +import FileDownloadIcon from 'material-ui/svg-icons/file/file-download' +import DeleteIcon from 'material-ui/svg-icons/action/delete' +import UndoIcon from 'material-ui/svg-icons/content/undo' +import DetailedCardHeader from './components/DetailedCardHeader' +import { files } from 'utils/' + +import classes from './DetailedCard.scss' + +class DetailedCard extends Component { + startLoadingHighlight() { + const { searchQuery, hit: { file_id: fileId }, loadHighlight } = this.props + loadHighlight(fileId, searchQuery) + } + + render() { + const { + hit: { + fetching: fetching, + meta: meta, + content: content, + sha256: sha256, + tags: tags, + file_id: fileId, + isHidden: isHidden, + hidden_mark: hidden_mark + }, + allTags, + thumbnailUri, + downloadUri, + searchQuery, + loadHighlight, + performSearchByAuthor, + performSearchByPathToFile, + toggleImagePreview, + addTagToFile, + removeTagFromFile, + performSearchByTag, + hideFile, + showFile, + localization, + preserveOriginals + } = this.props + + const contentHighlight = content && content.highlight && content.highlight.text ? content.highlight.text : undefined + + return ( + + + + {!isHidden &&
+ addTagToFile(fileId, tagType, tagName)} + onRemoveTag={(tagType, tagName) => removeTagFromFile(fileId, tagType, tagName)} + performSearchByTag={performSearchByTag} + suggestions={allTags.map(t => t.name)} + /> +
+
+ {fetching && + + + } + {!fetching && !contentHighlight && + this.startLoadingHighlight()}> + Если у общества нет цветовой дифференциации штанов - то у общества
+ нет цели, а если нет цели - то... +
+ } + {!fetching && contentHighlight && contentHighlight.map((hl, idx) => + ) + } +
+ {!fetching && contentHighlight && content.thumb_available && + +
+ { toggleImagePreview(thumbnailUri) }} + className={classes.searchResultRowCardTextThumbnailImage} + src={thumbnailUri} /> +
+
+ } +
+
} + +
+ {!isHidden &&
+ {preserveOriginals && } + label={localization.searchPage.downloadLabel} + title={localization.searchPage.downloadDescriptionLabel} + primary={true} + onTouchTap={() => { window.open(downloadUri) }} + />} +
} +
+ {!hidden_mark && } + secondary={true} + label={localization.searchPage.removeLabel} + title={localization.searchPage.removeDescriptionLabel} + style={{ color: 'grey' }} + onTouchTap={() => hideFile(fileId)} + />} + {(isHidden || hidden_mark) && } + label={localization.searchPage.restoreLabel} + title={localization.searchPage.restoreDescriptionLabel} + primary={true} + onTouchTap={() => showFile(fileId)} + />} +
+
} +
+
+
+ ) + } +} + + +DetailedCard.propTypes = { + hit: React.PropTypes.object.isRequired, + allTags: React.PropTypes.array.isRequired, + searchQuery: React.PropTypes.string.isRequired, + thumbnailUri: React.PropTypes.string.isRequired, + downloadUri: React.PropTypes.string.isRequired, + loadHighlight: React.PropTypes.func.isRequired, + performSearchByAuthor: React.PropTypes.func.isRequired, + performSearchByPathToFile: React.PropTypes.func.isRequired, + toggleImagePreview: React.PropTypes.func.isRequired, + addTagToFile: React.PropTypes.func.isRequired, + removeTagFromFile: React.PropTypes.func.isRequired, + performSearchByTag: React.PropTypes.func.isRequired, + hideFile: React.PropTypes.func.isRequired, + showFile: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired, + preserveOriginals: React.PropTypes.bool.isRequired +} + +export default DetailedCard + + + + diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/DetailedCard.scss b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/DetailedCard.scss new file mode 100644 index 0000000..3ad1b7f --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/DetailedCard.scss @@ -0,0 +1,60 @@ +.searchResultRowCard { + margin: 10px; +} + +.searchResultRowCardTextContainer { + display: flex; + justify-content: space-between; + align-items: stretch; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #eeeeee; + + em { + background-color: #fff6a9; + border: 1px solid #e6d9c4; + border-radius: 3px; + font-style: normal; + } +} + +.searchResultRowCardTextDiv { + width: 100%; + word-wrap: break-word; + word-break: break-word; +} + +.searchResultRowCardTextWithBorder { + border-bottom: 1px solid #eeeeee; +} + +.searchResultRowCardTextThumbnailContainer { + border-left: 1px solid #eeeeee; +} + +.searchResultRowCardTextThumbnailImage { + max-width: 250px; +} + +.searchResultRowCardTextThumbnailImage:hover { + cursor: pointer; + box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 15px; + transition: box-shadow 0.1s linear; +} + +.searchResultRowCardFooter { + display: flex; + justify-content: space-between; + overflow: hidden; +} + +.blurred { + -webkit-filter: blur(3px); + filter: blur(3px); + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/DetailedCardHeader.js b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/DetailedCardHeader.js new file mode 100644 index 0000000..507a70f --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/DetailedCardHeader.js @@ -0,0 +1,77 @@ +import React, { Component } from 'react' +import { CardHeader } from 'material-ui/Card' +import { files } from 'utils/' +import moment from 'moment' +import { FileAvatar, ClickableFilePath, AuthorLabel, FileSizeLabel, UpdatedDateTimeLabel } from 'components/BasicComponents' + +import classes from './DetailedCardHeader.scss' + +const getHumanizedTime = (date) => { + const start = moment.utc() + const end = moment.utc(date) + + let diff = moment.duration(end.diff(start)) + if (Math.floor(Math.abs(diff.asDays())) > 6) { + return end.format('DD.MM.YYYY') + } + + return diff.humanize(true) +} + +const DetailedCardHeader = (props) => { + const { meta, content, searchQuery, performSearchByPathToFile, performSearchByAuthor, localization } = props + + const headerContainerStyle = { + display: 'flex', + justifyContent: 'space-between', + paddingTop: '10px', + paddingLeft: '10px', + paddingRight: '10px', + paddingBottom: '5px', + fontSize: '12px', + color: '#9E9E9E' + } + + return ( +
+
+
+ +
+
+
+
+ {meta.short_name} +  –  + + + {content.author && {localization.searchPage.byLabel}  + + } + +
+
+
+
+
{meta.updated_datetime && {localization.searchPage.lastModifiedLabel}: }
+
+ ) +} + +DetailedCardHeader.propTypes = { + meta: React.PropTypes.object.isRequired, + content: React.PropTypes.object.isRequired, + searchQuery: React.PropTypes.string.isRequired, + performSearchByPathToFile: React.PropTypes.func.isRequired, + performSearchByAuthor: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default DetailedCardHeader + + + + diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/DetailedCardHeader.scss b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/DetailedCardHeader.scss new file mode 100644 index 0000000..e5015ed --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/DetailedCardHeader.scss @@ -0,0 +1,28 @@ +.metaShortName { + color: rgba(0, 0, 0, 0.87); + font-size: 15px; + font-weight: 600; +} + +.searchResultRowCardHeaderSubTitle { + color: #9E9E9E; + font-size: 12px; +} + +.resultAvatar:hover { + cursor: pointer !important; + filter: brightness(1.1); +} + +.resultAvatar:active { + filter: brightness(1.2); +} + +div.spanHighlighted { + border-radius: 4px; + background-color: #fff176; + font-size: 12px; + color: #707070; + margin-right: 3px; +} + diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/index.js b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/index.js new file mode 100644 index 0000000..bdf12fc --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/components/DetailedCardHeader/index.js @@ -0,0 +1,3 @@ +import DetailedCardHeader from './DetailedCardHeader' + +export default DetailedCardHeader \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/index.js b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/index.js new file mode 100644 index 0000000..37b1e15 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/components/DetailedCard/index.js @@ -0,0 +1,3 @@ +import DetailedCard from './DetailedCard' + +export default DetailedCard \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/DetailedView/index.js b/FrontEnd/src/components/Search/components/Views/DetailedView/index.js new file mode 100644 index 0000000..45bed73 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/DetailedView/index.js @@ -0,0 +1,3 @@ +import DetailedView from './DetailedView' + +export default DetailedView \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/FolderView/FolderView.js b/FrontEnd/src/components/Search/components/Views/FolderView/FolderView.js new file mode 100644 index 0000000..fd3d403 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/FolderView/FolderView.js @@ -0,0 +1,113 @@ +import React, { Component } from 'react' +import moment from 'moment' +import classes from './FolderView.scss' +import EmptySearchResultsContainer from 'routes/SearchPage/containers/EmptySearchResultsContainer' + +import { Intent, Icon, Button, Tree } from "@blueprintjs/core" + +class FolderView extends Component { + componentDidMount() { + const { + search, + searchQuery + } = this.props + + search(0, searchQuery) + } + + render() { + const { + performSearchByPathToFile, + searchQuery, + localization, + folderHits, + toggleTreeNode, + toggleAll, + toggleImagePreview, + urls + } = this.props + + const totalHitsCount = folderHits.reduce((totalCount, hit) => totalCount + hit.hitsCount, 0) + + if (!searchQuery || !folderHits || totalHitsCount === 0) { + return + } + + const createTreeContents = (hits) => { + return hits.map(folderHit => { + const onSearchClick = () => folderHit.type != 'mixed' ? + performSearchByPathToFile(`${folderHit.path}*`) : + performSearchByPathToFile(`${folderHit.parentPath}*`) + + return { + key: folderHit.path, + hasCaret: folderHit.childNodes.length > 0, + isExpanded: folderHit.isExpanded, + iconName: folderHit.type == 'folder' + ? folderHit.isExpanded + ? 'pt-icon-folder-open' + : 'pt-icon-folder-close' + : folderHit.type == 'source' + ? 'pt-icon-database' + : folderHit.type == 'mixed' + ? 'pt-icon-more' + : folderHit.contentType.includes('image/') + ? 'pt-icon-media' + : 'document', + label:
+ {folderHit.type != 'mixed' && {folderHit.name}} + {folderHit.hitsCount} + {folderHit.type !== 'file' && +
, + className: 'treeNode', + childNodes: createTreeContents(folderHit.childNodes) + } + }) + } + + const treeContents = createTreeContents(folderHits) + + return ( +
+
+ + +
+
+ toggleTreeNode(node.key)} + onNodeExpand={(node) => toggleTreeNode(node.key)} + /> +
+
+ ) + } +} + +FolderView.propTypes = { + folderHits: React.PropTypes.array.isRequired, + localization: React.PropTypes.object.isRequired, + search: React.PropTypes.func.isRequired, + performSearchByPathToFile: React.PropTypes.func.isRequired, + searchQuery: React.PropTypes.string.isRequired, + toggleTreeNode: React.PropTypes.func.isRequired, + toggleAll: React.PropTypes.func.isRequired, + toggleImagePreview: React.PropTypes.func.isRequired, + urls: React.PropTypes.object.isRequired +} + +export default FolderView diff --git a/FrontEnd/src/components/Search/components/Views/FolderView/FolderView.scss b/FrontEnd/src/components/Search/components/Views/FolderView/FolderView.scss new file mode 100644 index 0000000..1de3e8a --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/FolderView/FolderView.scss @@ -0,0 +1,46 @@ +div.folderViewButtonsContainer { + background-color: #f4f4f4; + box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 15px; + display: flex; +} + +div.folderViewButtonsContainer button { + margin-left: 20px; +} + +div.folderViewTreeContainer { +} + +:global .treeNode button { + opacity: 0; + margin-left: 4px; + -webkit-transition: opacity 0.2s ease-in-out; + -moz-transition: opacity 0.2s ease-in-out; + -ms-transition: opacity 0.2s ease-in-out; + -o-transition: opacity 0.2s ease-in-out; + transition: opacity 0.2s ease-in-out; +} + +:global .treeNode > .pt-tree-node-content:hover button { + opacity: 1 !important; +} + +div.treeNodeNameAndHitsCountContainer { + display: flex; + align-items: center; +} + +span.treeNodeName { + font-size: 14px; +} + +span.treeNodeHitsCount { + margin: 4px; + word-wrap: break-word; + word-break: break-all; + font-size: 13px; + font-family: Roboto,sans-serif; + color: #888888; + padding: 2px; + border-radius: 3px; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/FolderView/index.js b/FrontEnd/src/components/Search/components/Views/FolderView/index.js new file mode 100644 index 0000000..8c4a559 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/FolderView/index.js @@ -0,0 +1,3 @@ +import FolderView from './FolderView' + +export default FolderView \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/StatisticsView.js b/FrontEnd/src/components/Search/components/Views/StatisticsView/StatisticsView.js new file mode 100644 index 0000000..fe77bf4 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/StatisticsView.js @@ -0,0 +1,80 @@ +import React, { Component } from 'react' +import { files } from 'utils' +import EmptySearchResultsContainer from 'routes/SearchPage/containers/EmptySearchResultsContainer' +import TagsWithCount from './components/TagWithCount' +import ExtensionsPieChart from './components/ExtensionsPieChart' +import classes from './StatisticsView.scss' + +const AUTO_TAG_COLOR = '#e6c2be' +const SOURCE_TAG_COLOR = '#c6e6be' +const OTHER_TAG_COLOR = '#bedbe6' + +class StatisticsView extends Component { + componentDidMount() { + const { + search, + searchQuery + } = this.props + + search(0, searchQuery) + } + + render() { + const { + performSearchByPathToFile, + performSearchByTag, + searchQuery, + localization, + stats + } = this.props + + if (!searchQuery || !stats || stats.total === 0 ) { + return + } + + return ( +
+
+
+

{localization.searchPage.statsSummaryLabel}

+
    +
  • {localization.searchPage.statsFilesCountLabel}: {stats.summary.data.count} ({files.formatFileSize(stats.summary.data.sum)})
  • +
  • {localization.searchPage.statsMinimumFileSizeLabel}: {files.formatFileSize(stats.summary.data.min)}
  • +
  • {localization.searchPage.statsAverageFileSizeLabel}: {files.formatFileSize(stats.summary.data.avg)}
  • +
  • {localization.searchPage.statsMaximumFileSizeLabel}: {files.formatFileSize(stats.summary.data.max)}
  • +
+
+
+

{localization.searchPage.statsExtensionsTypesLabel} ({stats.extensions.data.length})

+
+ performSearchByPathToFile(`*${extensionName}`)} /> +
+
+ {stats.tags.total > 0 &&
+

{localization.searchPage.tagsLabel} ({stats.tags.data.length})

+ {stats.tags.data.map((tag, id) => ( + performSearchByTag(tag.name))} + count={`${tag.hits_percent.toFixed(2)}%`} + /> + ))} +
} +
+
+ ) + } +} + +StatisticsView.propTypes = { + stats: React.PropTypes.object, + localization: React.PropTypes.object.isRequired, + searchQuery: React.PropTypes.string.isRequired, + search: React.PropTypes.func.isRequired, + performSearchByPathToFile: React.PropTypes.func.isRequired, + performSearchByTag: React.PropTypes.func.isRequired +} + +export default StatisticsView diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/StatisticsView.scss b/FrontEnd/src/components/Search/components/Views/StatisticsView/StatisticsView.scss new file mode 100644 index 0000000..3d0490a --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/StatisticsView.scss @@ -0,0 +1,27 @@ +.statisticsContainer { + margin: 10px; + display: flex; + flex-flow: row; + flex-wrap: wrap; + justify-content: baseline; + font-family: Roboto,sans-serif; +} + +.statisticsContainer h3 { + font-size: 21px; +} + +.statisticsItem { + width: 50%; +} + +ul.summary { + list-style: none; + padding-left: 0; +} + + +.extensionsChart { + display: flex; + justify-content: center; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/ExtensionsPieChart.js b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/ExtensionsPieChart.js new file mode 100644 index 0000000..107f092 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/ExtensionsPieChart.js @@ -0,0 +1,45 @@ +import React, { Component } from 'react' +import { PieChart, Pie, Tooltip, Cell } from 'recharts' +import classes from './ExtensionsPieChart.scss' + +const colors = ['#B2EBF2','#80DEEA','#4DD0E1','#26C6DA','#00BCD4','#00ACC1','#0097A7','#00838F'] +const otherColor = '#DCE775' + +const DEFAULT_ON_CLICK = () => { } + +class ExtensionsPieChart extends Component { + render() { + const { data, onClick = DEFAULT_ON_CLICK } = this.props + + return ( + + onClick(e.name)} + isAnimationActive={false} + data={data} + dataKey={'hits_count'} + nameKey={'extension'} + outerRadius='100%' + innerRadius='50%' + labelLine={false} + label={(node) => node.extension} + cx='50%' + cy='50%' + > + { data.map((entry, index) => + ) } + + + ) + } +} + +ExtensionsPieChart.propTypes = { + data: React.PropTypes.object.isRequired, + onClick: React.PropTypes.func +} + +export default ExtensionsPieChart \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/ExtensionsPieChart.scss b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/ExtensionsPieChart.scss new file mode 100644 index 0000000..6a2c7d9 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/ExtensionsPieChart.scss @@ -0,0 +1,12 @@ +:global text.recharts-text.recharts-pie-label-text { + fill: #848484; +} + +:global path.recharts-sector { + cursor: pointer; +} + +:global path.recharts-sector:hover { + stroke-width: 2px; + stroke: yellow; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/index.js b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/index.js new file mode 100644 index 0000000..dbd9786 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/ExtensionsPieChart/index.js @@ -0,0 +1,3 @@ +import ExtensionsPieChart from './ExtensionsPieChart' + +export default ExtensionsPieChart \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/TagWithCount.js b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/TagWithCount.js new file mode 100644 index 0000000..83a4e94 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/TagWithCount.js @@ -0,0 +1,26 @@ +import React, { Component } from 'react' +import classes from './TagWithCount.scss' + +const DEFAULT_ON_CLICK = () => { } + +const TagWithCount = ({ label, count, labelColor = '#c6e6be' , containerClasses = '', labelClasses = '', countClasses = '', onClick = DEFAULT_ON_CLICK, ...otherProps }) => { + return ( + + {label} + {count} + + ) +} + +TagWithCount.propTypes = { + label: React.PropTypes.string.isRequired, + count: React.PropTypes.string.isRequired, + onClick: React.PropTypes.func, + labelColor: React.PropTypes.string, + containerClasses: React.PropTypes.string, + labelClasses: React.PropTypes.string, + countClasses: React.PropTypes.string +} + +export default TagWithCount + diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/TagWithCount.scss b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/TagWithCount.scss new file mode 100644 index 0000000..0fd870a --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/TagWithCount.scss @@ -0,0 +1,26 @@ +.tagContainer { + margin: 3px; + font-size: 12px; + display: inline-block; + cursor: pointer; + font-family: Roboto,sans-serif; + overflow-x: hidden; +} + +.tagLabel { + padding: 2px; + color: #848484; + border-radius: 3px 0 0 3px; + max-width: 200px; + white-space: nowrap; + display: inline-block; + text-overflow: ellipsis; +} + +.tagCount { + display: inline-block; + background-color: #a7a7a7; + color: #fefefe; + padding: 2px; + border-radius: 0 3px 3px 0; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/index.js b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/index.js new file mode 100644 index 0000000..9898df1 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/components/TagWithCount/index.js @@ -0,0 +1,3 @@ +import TagWithCount from './TagWithCount' + +export default TagWithCount \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/StatisticsView/index.js b/FrontEnd/src/components/Search/components/Views/StatisticsView/index.js new file mode 100644 index 0000000..93ad5fb --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/StatisticsView/index.js @@ -0,0 +1,3 @@ +import StatisticsView from './StatisticsView' + +export default StatisticsView \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/TableView/TableView.js b/FrontEnd/src/components/Search/components/Views/TableView/TableView.js new file mode 100644 index 0000000..340df2e --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/TableView/TableView.js @@ -0,0 +1,85 @@ +import React, { Component } from 'react' +import moment from 'moment' + +import { + Table, + TableBody, + TableHeader, + TableHeaderColumn, + TableRow, + TableRowColumn, +} from 'material-ui/Table' + +import EmptySearchResultsContainer from 'routes/SearchPage/containers/EmptySearchResultsContainer' +import TableViewRow from './components/TableRow' +import classes from './TableView.scss' + +class TableView extends Component { + componentDidMount() { + const { + search, + searchQuery + } = this.props + + search(0, searchQuery) + } + + render() { + const { + hits, + urls, + localization, + searchQuery + } = this.props + + if (!searchQuery || !hits || hits.size === 0) { + return + } + + return ( + + + + + {localization.searchPage.fileNameLabel} + {localization.searchPage.fileSizeLabel} + {localization.searchPage.tagsLabel} + {localization.searchPage.authorLabel} + {localization.searchPage.lastModifiedLabel} + {localization.searchPage.actionsLabel} + + + + {Array.from(hits.values()).map((hit, idx) => + + )} + +
+ ) + } +} + +TableView.propTypes = { + hits: React.PropTypes.object.isRequired, + localization: React.PropTypes.object.isRequired, + allTags: React.PropTypes.array.isRequired, + searchQuery: React.PropTypes.string.isRequired, + performSearchByAuthor: React.PropTypes.func.isRequired, + performSearchByPathToFile: React.PropTypes.func.isRequired, + toggleImagePreview: React.PropTypes.func.isRequired, + addTagToFile: React.PropTypes.func.isRequired, + removeTagFromFile: React.PropTypes.func.isRequired, + performSearchByTag: React.PropTypes.func.isRequired, + hideFile: React.PropTypes.func.isRequired, + showFile: React.PropTypes.func.isRequired, + preserveOriginals: React.PropTypes.bool.isRequired, + search: React.PropTypes.func.isRequired +} + +export default TableView diff --git a/FrontEnd/src/components/Search/components/Views/TableView/TableView.scss b/FrontEnd/src/components/Search/components/Views/TableView/TableView.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/TableRow.js b/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/TableRow.js new file mode 100644 index 0000000..c31af76 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/TableRow.js @@ -0,0 +1,129 @@ +import React, { Component } from 'react' + +import FileDownloadIcon from 'material-ui/svg-icons/file/file-download' +import ImagePreviewIcon from 'material-ui/svg-icons/image/image' +import DeleteIcon from 'material-ui/svg-icons/action/delete' +import IconButton from 'material-ui/IconButton' +import UndoIcon from 'material-ui/svg-icons/content/undo' + +import { files } from 'utils/' +import moment from 'moment' +import { + Table, + TableBody, + TableHeader, + TableHeaderColumn, + TableRow, + TableRowColumn, +} from 'material-ui/Table' +import { FileAvatar, TagsInput, ClickableFilePath, AuthorLabel, FileSizeLabel, UpdatedDateTimeLabel } from 'components/BasicComponents' + +import classes from './TableRow.scss' + +const getFormattedTime = (date) => { + return moment(date).format('DD.MM.YYYY HH:mm') +} + +class TableRowResult extends Component { + + render() { + const { + hit: { + fetching: fetching, + meta: meta, + content: content, + sha256: sha256, + tags: tags, + file_id: fileId, + isHidden: isHidden, + hidden_mark: hidden_mark + }, + allTags, + searchQuery, + thumbnailUri, + downloadUri, + performSearchByAuthor, + performSearchByPathToFile, + toggleImagePreview, + addTagToFile, + removeTagFromFile, + performSearchByTag, + hideFile, + showFile, + localization, + preserveOriginals + } = this.props + + const contentHighlight = content && content.highlight && content.highlight.text ? content.highlight.text : undefined + + return ( + + + + + + {meta.short_name} + + + + + addTagToFile(fileId, tagType, tagName)} + onRemoveTag={(tagType, tagName) => removeTagFromFile(fileId, tagType, tagName)} + performSearchByTag={performSearchByTag} + suggestions={allTags.map(t => t.name)} + /> + + + + + + + {preserveOriginals && { window.open(downloadUri) }} + title={localization.searchPage.downloadDescriptionLabel}> + + } + { + toggleImagePreview(thumbnailUri) + }} + title={localization.searchPage.imagePreviewLabel}> + + + {!hidden_mark && hideFile(fileId)} title={localization.searchPage.removeLabel}> + + } + {(isHidden || hidden_mark) && showFile(fileId)} title={localization.searchPage.restoreLabel}> + + } + + + ) + } +} + + +TableRowResult.propTypes = { + hit: React.PropTypes.object.isRequired, + allTags: React.PropTypes.array.isRequired, + searchQuery: React.PropTypes.string.isRequired, + thumbnailUri: React.PropTypes.string.isRequired, + downloadUri: React.PropTypes.string.isRequired, + performSearchByAuthor: React.PropTypes.func.isRequired, + performSearchByPathToFile: React.PropTypes.func.isRequired, + toggleImagePreview: React.PropTypes.func.isRequired, + addTagToFile: React.PropTypes.func.isRequired, + removeTagFromFile: React.PropTypes.func.isRequired, + performSearchByTag: React.PropTypes.func.isRequired, + hideFile: React.PropTypes.func.isRequired, + showFile: React.PropTypes.func.isRequired, + preserveOriginals: React.PropTypes.bool.isRequired +} + +export default TableRowResult + + + + diff --git a/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/TableRow.scss b/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/TableRow.scss new file mode 100644 index 0000000..a994304 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/TableRow.scss @@ -0,0 +1,53 @@ +.searchResultRowCard { + margin: 10px; +} + +.searchResultRowCardTextContainer { + display: flex; + justify-content: space-between; + align-items: stretch; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #eeeeee; +} + +.searchResultRowCardTextDiv { + width: 100%; + word-wrap: break-word; + word-break: break-word; +} + +.searchResultRowCardTextWithBorder { + border-bottom: 1px solid #eeeeee; +} + +.searchResultRowCardTextThumbnailContainer { + border-left: 1px solid #eeeeee; +} + +.searchResultRowCardTextThumbnailImage { + max-width: 250px; +} + +.searchResultRowCardTextThumbnailImage:hover { + cursor: pointer; + box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 15px; + transition: box-shadow 0.1s linear; +} + +.searchResultRowCardFooter { + display: flex; + justify-content: space-between; + overflow: hidden; +} + +.blurred { + -webkit-filter: blur(3px); + filter: blur(3px); + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + diff --git a/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/index.js b/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/index.js new file mode 100644 index 0000000..f0c6f08 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/TableView/components/TableRow/index.js @@ -0,0 +1,3 @@ +import TableRow from './TableRow' + +export default TableRow \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/Views/TableView/index.js b/FrontEnd/src/components/Search/components/Views/TableView/index.js new file mode 100644 index 0000000..79756b6 --- /dev/null +++ b/FrontEnd/src/components/Search/components/Views/TableView/index.js @@ -0,0 +1,3 @@ +import TableView from './TableView' + +export default TableView \ No newline at end of file diff --git a/FrontEnd/src/components/Search/components/index.js b/FrontEnd/src/components/Search/components/index.js new file mode 100644 index 0000000..97c97ca --- /dev/null +++ b/FrontEnd/src/components/Search/components/index.js @@ -0,0 +1,15 @@ +import HintCard from './HintCard' +import ImagePreview from './ImagePreview' +import SearchInput from './SearchInput' +import SearchResults from './SearchResults' +import SideMenu from './SideMenu' +import UploadFileModal from './UploadFileModal' + +export { + HintCard, + ImagePreview, + SearchInput, + SearchResults, + SideMenu, + UploadFileModal +} \ No newline at end of file diff --git a/FrontEnd/src/components/Search/index.js b/FrontEnd/src/components/Search/index.js new file mode 100644 index 0000000..9b16ddd --- /dev/null +++ b/FrontEnd/src/components/Search/index.js @@ -0,0 +1,3 @@ +import Search from './Search' + +export default Search \ No newline at end of file diff --git a/FrontEnd/src/components/Settings/Settings.js b/FrontEnd/src/components/Settings/Settings.js new file mode 100644 index 0000000..af52aaa --- /dev/null +++ b/FrontEnd/src/components/Settings/Settings.js @@ -0,0 +1,54 @@ +import React, { Component } from 'react' + +import PipelineCard from './components/PipelineCard' +import classes from './Settings.scss' + +class Settings extends Component { + componentDidMount() { + const { + loadPipelineLog, + pipeline, + setPageTitle, + setAppHeader, + localization + } = this.props + + setPageTitle(localization.settingsPage.pageTitle) + setAppHeader({ left: () => localization.settingsPage.pageTitle }) + loadPipelineLog(pipeline) + } + + render() { + const { + fetching, + crawlers, + startStopCrawler, + setSettingsModalOpen, + refreshCrawler, + pipeline, + loadPipelineLog, + localization } = this.props + + return ( +
+ {!fetching && + + } +
+ ) + } +} + +Settings.propTypes = { + fetching: React.PropTypes.bool.isRequired, + pipeline: React.PropTypes.object.isRequired, + loadPipelineLog: React.PropTypes.func.isRequired, + setPageTitle: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default Settings \ No newline at end of file diff --git a/FrontEnd/src/components/Settings/Settings.scss b/FrontEnd/src/components/Settings/Settings.scss new file mode 100644 index 0000000..5695064 --- /dev/null +++ b/FrontEnd/src/components/Settings/Settings.scss @@ -0,0 +1,3 @@ +.settingsCard { + margin: 10px; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Settings/components/LogView/LogView.js b/FrontEnd/src/components/Settings/components/LogView/LogView.js new file mode 100644 index 0000000..c522b71 --- /dev/null +++ b/FrontEnd/src/components/Settings/components/LogView/LogView.js @@ -0,0 +1,31 @@ +import React from 'react' +import classes from './LogView.scss' + +const red600 = '#E53935' +const lightGreen600 = '#7CB342' +const lime600 = '#C0CA33' + +const LogView = ({log, style}) => ( +
+ {log.records.map((record, idx) => { + const logRecordColor = record.type === 'info' + ? lime600 + : record.type === 'error' + ? red600 + : lightGreen600 + + return ( +

{record.created_datetime}: [{record.source_id}] [{record.type}] {record.message}

+ ) + })} +

+ . +

+
+) + +LogView.propTypes = { + log: React.PropTypes.object.isRequired +} + +export default LogView \ No newline at end of file diff --git a/FrontEnd/src/components/Settings/components/LogView/LogView.scss b/FrontEnd/src/components/Settings/components/LogView/LogView.scss new file mode 100644 index 0000000..0ac40af --- /dev/null +++ b/FrontEnd/src/components/Settings/components/LogView/LogView.scss @@ -0,0 +1,32 @@ +.logFrame { + background-color: #263238; + font-weight: 700; + font-family: "Courier New", monospace; + margin-left: -16px; + margin-right: -16px; + padding: 7px; + height: 230px; + overflow-y: hidden; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + p { + margin: 0 + } +} + + + +:global { + .blink { + animation: blinker 0.5s linear infinite; + color: #7CB342; + } + + @keyframes :global(blinker) { + 50% { opacity: 0; } +} +} + + diff --git a/FrontEnd/src/components/Settings/components/LogView/index.js b/FrontEnd/src/components/Settings/components/LogView/index.js new file mode 100644 index 0000000..dcff213 --- /dev/null +++ b/FrontEnd/src/components/Settings/components/LogView/index.js @@ -0,0 +1,3 @@ +import LogView from './LogView' + +export default LogView \ No newline at end of file diff --git a/FrontEnd/src/components/Settings/components/PipelineCard/PipelineCard.js b/FrontEnd/src/components/Settings/components/PipelineCard/PipelineCard.js new file mode 100644 index 0000000..24b8869 --- /dev/null +++ b/FrontEnd/src/components/Settings/components/PipelineCard/PipelineCard.js @@ -0,0 +1,45 @@ +import React, { Component } from 'react' +import { Card, CardText, CardTitle } from 'material-ui/Card' +import Paper from 'material-ui/Paper' +import LogView from '../LogView' + +import classes from './PipelineCard.scss' +import formClasses from '../../Settings.scss' + +class PipelineCard extends Component { + componentDidMount() { + const { pipeline, loadPipelineLog } = this.props + this.updateDescriptor = setInterval(() => loadPipelineLog(pipeline), 3 * 1000) + } + + componentWillUnmount() { + clearInterval(this.updateDescriptor) + } + + render() { + const { pipeline: { log }, localization } = this.props + + return ( + + + + + + + + + ) + } +} + +PipelineCard.propTypes = { + pipeline: React.PropTypes.object.isRequired, + loadPipelineLog: React.PropTypes.func.isRequired +} + +export default PipelineCard diff --git a/FrontEnd/src/components/Settings/components/PipelineCard/PipelineCard.scss b/FrontEnd/src/components/Settings/components/PipelineCard/PipelineCard.scss new file mode 100644 index 0000000..02daa1d --- /dev/null +++ b/FrontEnd/src/components/Settings/components/PipelineCard/PipelineCard.scss @@ -0,0 +1,3 @@ +div.test { + +} \ No newline at end of file diff --git a/FrontEnd/src/components/Settings/components/PipelineCard/index.js b/FrontEnd/src/components/Settings/components/PipelineCard/index.js new file mode 100644 index 0000000..030af24 --- /dev/null +++ b/FrontEnd/src/components/Settings/components/PipelineCard/index.js @@ -0,0 +1,3 @@ +import PipelineCard from './PipelineCard' + +export default PipelineCard \ No newline at end of file diff --git a/FrontEnd/src/components/Settings/index.js b/FrontEnd/src/components/Settings/index.js new file mode 100644 index 0000000..bfa762c --- /dev/null +++ b/FrontEnd/src/components/Settings/index.js @@ -0,0 +1,3 @@ +import Settings from './Settings' + +export default Settings \ No newline at end of file diff --git a/FrontEnd/src/components/Statistics/Statistics.js b/FrontEnd/src/components/Statistics/Statistics.js new file mode 100644 index 0000000..522fd19 --- /dev/null +++ b/FrontEnd/src/components/Statistics/Statistics.js @@ -0,0 +1,114 @@ +import React, { Component } from 'react' +import { PieChart, Pie, Legend, Tooltip, Cell, ResponsiveContainer } from 'recharts' +import { Card, CardActions, CardHeader, CardText, CardTitle } from 'material-ui/Card' +import Paper from 'material-ui/Paper' +import { files } from 'utils' +import { Link } from 'react-router' +import MediaQuery from 'react-responsive' +import ContentTypeChart from './components/ContentTypeChart' +import ProcessingRateChart from './components/ProcessingRateChart' +import classes from './Statistics.scss' + +const StatisticsCard = ({ title, children }) => { + return ( + + + + + {children} + + + + ) +} + +const ChartCard = ({ children }) => { + return ( + + {(matches) => { + if (matches) { + return
{children}
+ } else { + return
{children}
+ } + } + } +
+ ) +} + +class Statistics extends Component { + + componentDidMount() { + const { loadStatistics, setPageTitle, setAppHeader, localization } = this.props + setPageTitle(localization.statisticsPage.pageTitle) + setAppHeader({left: () => localization.statisticsPage.pageTitle}) + loadStatistics() + } + + render() { + const { fetching, data, localization } = this.props + + const chartCardStyle = { display: 'flex', minWidth: '50%', maxWidth: '100%' } + + return ( +
+ {!fetching && data.procTotal.totalCount > 0 && +
+
+ + + + +

+ {localization.statisticsPage.filesCountLabel}:  + {data.procTotal.totalCount} ({files.formatFileSize(data.procTotal.sizeDataInBytes.sum)}) +

+

+ {localization.statisticsPage.averageFileSizeLabel}:  + {files.formatFileSize(data.procTotal.sizeDataInBytes.avg)} +

+

+ {localization.statisticsPage.maximumFileSizeLabel}:  + {files.formatFileSize(data.procTotal.sizeDataInBytes.max)} +

+
+
+
+
+ + + + + + + + + + +
+ } + {!fetching && data.procTotal.totalCount === 0 && +
+ +
+ Oops +
+

{localization.statisticsPage.emptyStatisticsDescriptionLabel}

+
+
+ } +
+ ) + } +} + +Statistics.propTypes = { + fetching: React.PropTypes.bool.isRequired, + data: React.PropTypes.object.isRequired, + loadStatistics: React.PropTypes.func.isRequired, + setPageTitle: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default Statistics \ No newline at end of file diff --git a/FrontEnd/src/components/Statistics/Statistics.scss b/FrontEnd/src/components/Statistics/Statistics.scss new file mode 100644 index 0000000..7733b0a --- /dev/null +++ b/FrontEnd/src/components/Statistics/Statistics.scss @@ -0,0 +1,24 @@ +.statisticsCard { + width: 100%; + margin: 10px; +} + +.statisticsCardsContainer { + display: flex; + justify-content: center; + flex-flow: row; + align-items: stretch; +} + +.fullWidth { + width:100%; +} + +.statisticsCardTitle { + font-size: 15px; + font-weight: 600; +} + +.link, .link:hover,.link:visited { + color: #00acc1; +} \ No newline at end of file diff --git a/FrontEnd/src/components/Statistics/components/ContentTypeChart/ContentTypeChart.js b/FrontEnd/src/components/Statistics/components/ContentTypeChart/ContentTypeChart.js new file mode 100644 index 0000000..1da53a9 --- /dev/null +++ b/FrontEnd/src/components/Statistics/components/ContentTypeChart/ContentTypeChart.js @@ -0,0 +1,52 @@ +import React, { Component } from 'react' +import { PieChart, Pie, Legend, Tooltip, Cell, ResponsiveContainer } from 'recharts' +// import classes from './ContentTypeChart.scss' + +const minTresholdInPercents = 0.05 +const colors = ['#B2EBF2','#80DEEA','#4DD0E1','#26C6DA','#00BCD4','#00ACC1','#0097A7','#00838F'] +const otherColor = '#DCE775' + +const renderCustomizedLabel = (minThreshold) => ({name, value, percent}) => { + if (minThreshold > value) { + return undefined + } + return name +} + +class ContentTypeChart extends Component { + render() { + const {data, minThreshold, total} = this.props.data + + const filteredData = data.filter(item => item.value >= minThreshold) + + const otherDataSum = data + .filter(item => item.value < minThreshold) + .map(item => item.value) + .reduce((a, b) => (a + b), 0) + + filteredData.push({name: 'Other', value: otherDataSum}) + + return ( + + + + { filteredData.map((entry, index) => ) } + + + + ) + } +} + +ContentTypeChart.propTypes = { + data: React.PropTypes.object.isRequired +} + +export default ContentTypeChart \ No newline at end of file diff --git a/FrontEnd/src/components/Statistics/components/ContentTypeChart/ContentTypeChart.scss b/FrontEnd/src/components/Statistics/components/ContentTypeChart/ContentTypeChart.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/Statistics/components/ContentTypeChart/index.js b/FrontEnd/src/components/Statistics/components/ContentTypeChart/index.js new file mode 100644 index 0000000..4ee0680 --- /dev/null +++ b/FrontEnd/src/components/Statistics/components/ContentTypeChart/index.js @@ -0,0 +1,3 @@ +import ContentTypeChart from './ContentTypeChart' + +export default ContentTypeChart \ No newline at end of file diff --git a/FrontEnd/src/components/Statistics/components/ProcessingRateChart/ProcessingRateChart.js b/FrontEnd/src/components/Statistics/components/ProcessingRateChart/ProcessingRateChart.js new file mode 100644 index 0000000..ac4d209 --- /dev/null +++ b/FrontEnd/src/components/Statistics/components/ProcessingRateChart/ProcessingRateChart.js @@ -0,0 +1,44 @@ +import React, { Component } from 'react' +import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts' +// import classes from './ProcessingRateChart.scss' + +const colors = ['#80DEEA','#4DD0E1','#26C6DA','#00BCD4','#00ACC1','#0097A7','#00838F'] + +const renderCustomizedLabel = ({ name, value, percent }) => { + return `${name} (${(percent * 100).toFixed(0)}%)` +} + +class ProcessingRateChart extends Component { + render() { + const { data, names } = this.props.data + + return ( + + + + + + + {Array.from(names).map((name, idx) => + () + ) + } + + + ) + } +} + +ProcessingRateChart.propTypes = { + data: React.PropTypes.object.isRequired +} + +export default ProcessingRateChart \ No newline at end of file diff --git a/FrontEnd/src/components/Statistics/components/ProcessingRateChart/ProcessingRateChart.scss b/FrontEnd/src/components/Statistics/components/ProcessingRateChart/ProcessingRateChart.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/components/Statistics/components/ProcessingRateChart/index.js b/FrontEnd/src/components/Statistics/components/ProcessingRateChart/index.js new file mode 100644 index 0000000..17e3f3c --- /dev/null +++ b/FrontEnd/src/components/Statistics/components/ProcessingRateChart/index.js @@ -0,0 +1,3 @@ +import ProcessingRateChart from './ProcessingRateChart' + +export default ProcessingRateChart \ No newline at end of file diff --git a/FrontEnd/src/components/Statistics/index.js b/FrontEnd/src/components/Statistics/index.js new file mode 100644 index 0000000..80810cb --- /dev/null +++ b/FrontEnd/src/components/Statistics/index.js @@ -0,0 +1,3 @@ +import Statistics from './Statistics' + +export default Statistics \ No newline at end of file diff --git a/FrontEnd/src/containers/AppContainer.js b/FrontEnd/src/containers/AppContainer.js new file mode 100644 index 0000000..a92bb96 --- /dev/null +++ b/FrontEnd/src/containers/AppContainer.js @@ -0,0 +1,46 @@ +import React, { Component, PropTypes } from 'react' +import { Router } from 'react-router' +import { Provider } from 'react-redux' +import getMuiTheme from 'material-ui/styles/getMuiTheme' +import injectTapEventPlugin from 'react-tap-event-plugin' + +class AppContainer extends Component { + static propTypes = { + history: PropTypes.object.isRequired, + routes: PropTypes.object.isRequired, + store: PropTypes.object.isRequired + } + + static childContextTypes = + { + muiTheme: React.PropTypes.object + } + + constructor(args) { + try{ + injectTapEventPlugin() + } + catch(exc) { console.error(exc) } + super(args) + } + + getChildContext() { + return { + muiTheme: getMuiTheme() + } + } + + render() { + const { history, routes, store } = this.props + + return ( + +
+ +
+
+ ) + } +} + +export default AppContainer diff --git a/FrontEnd/src/index.html b/FrontEnd/src/index.html new file mode 100644 index 0000000..bb4f708 --- /dev/null +++ b/FrontEnd/src/index.html @@ -0,0 +1,25 @@ + + + + Loading... + + + + + + + + + + + + + + + +
+ + diff --git a/FrontEnd/src/layouts/CoreLayout/CoreLayout.js b/FrontEnd/src/layouts/CoreLayout/CoreLayout.js new file mode 100644 index 0000000..d7bfc5b --- /dev/null +++ b/FrontEnd/src/layouts/CoreLayout/CoreLayout.js @@ -0,0 +1,49 @@ +import React, { Component } from 'react' +import { FullScreenLoader, NotificationIndicator } from 'components/BasicComponents' +import classes from './CoreLayout.scss' +import '../../../node_modules/@blueprintjs/core/dist/blueprint.css' +import '../../styles/core.scss' + +class CoreLayout extends Component { + componentDidMount() { + const { loadConfig } = this.props + loadConfig() + } + + render() { + const { + children, + fetching, + isError, + errorMessage, + setPageTitle, + isNotificationOpen, + notificationMessage, + notificationReason, + closeNotification } = this.props + + return ( +
+ {fetching && } + {!fetching && React.cloneElement(this.props.children, { setPageTitle: setPageTitle })} + closeNotification()} + /> +
) + } +} + +CoreLayout.propTypes = { + children: React.PropTypes.element.isRequired, + loadConfig: React.PropTypes.func.isRequired, + fetching: React.PropTypes.bool.isRequired, + isNotificationOpen: React.PropTypes.bool.isRequired, + notificationMessage: React.PropTypes.string, + notificationReason: React.PropTypes.string, + closeNotification: React.PropTypes.func.isRequired +} + +export default CoreLayout diff --git a/FrontEnd/src/layouts/CoreLayout/CoreLayout.scss b/FrontEnd/src/layouts/CoreLayout/CoreLayout.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/layouts/CoreLayout/index.js b/FrontEnd/src/layouts/CoreLayout/index.js new file mode 100644 index 0000000..7fe88c1 --- /dev/null +++ b/FrontEnd/src/layouts/CoreLayout/index.js @@ -0,0 +1,3 @@ +import CoreLayout from './CoreLayout' + +export default CoreLayout diff --git a/FrontEnd/src/layouts/MainLayout/MainLayout.js b/FrontEnd/src/layouts/MainLayout/MainLayout.js new file mode 100644 index 0000000..0c1abe0 --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/MainLayout.js @@ -0,0 +1,98 @@ +import React, { Component, PropTypes } from 'react' +import MainMenu from './components/MainMenu' +import RateUs from './components/RateUs' +import { AmbarResponsiveLogo } from 'components/BasicComponents' +import AppBarTitle from './components/AppBarTitle' +import AppBar from 'material-ui/AppBar' +import MediaQuery from 'react-responsive' +import LinearProgress from 'material-ui/LinearProgress' + +import classes from './MainLayout.scss' + +class MainLayout extends Component { + render() { + const { + children, + fetching, + changeLocation, + location, + toggleSideMenu, + isSideMenuOpen, + header, + mode, + version, + allowedRoutes, + setPageTitle, + setAppHeader, + showRateUsModal, + toggleRateUsModal, + auth, + state, + localization + } = this.props + + return ( +
+
+ {fetching && } + } + style={{ position: 'fixed', top: 0, left: 0 }} + zDepth={2} + onRightIconButtonTouchTap={toggleSideMenu} + iconElementRight={} + iconElementLeft={
+ {mode !== 'ee' && + + } + +
} + /> +
+
+ {React.cloneElement(children, { setPageTitle: setPageTitle, setAppHeader: setAppHeader })} +
+
+
+
+ ) + } + + static propTypes = { + version: React.PropTypes.string.isRequired, + children: React.PropTypes.element.isRequired, + fetching: React.PropTypes.bool.isRequired, + + isSideMenuOpen: React.PropTypes.bool.isRequired, + toggleSideMenu: React.PropTypes.func.isRequired, + + location: React.PropTypes.string.isRequired, + changeLocation: React.PropTypes.func.isRequired, + header: React.PropTypes.object.isRequired, + + showRateUsModal: React.PropTypes.bool.isRequired, + toggleRateUsModal: React.PropTypes.func.isRequired, + + setAppHeader: React.PropTypes.func.isRequired, + setPageTitle: React.PropTypes.func.isRequired, + + auth: React.PropTypes.string.isRequired, + + state: React.PropTypes.object.isRequired + } +} + +export default MainLayout diff --git a/FrontEnd/src/layouts/MainLayout/MainLayout.scss b/FrontEnd/src/layouts/MainLayout/MainLayout.scss new file mode 100644 index 0000000..1456055 --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/MainLayout.scss @@ -0,0 +1,17 @@ +:global .pageContainer { + max-width: 1200px; + margin: 0 auto; +} + +:global ::-webkit-scrollbar { + width: 0.4em; +} + +:global ::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +:global ::-webkit-scrollbar-thumb { + background-color: darkgrey; + outline: 1px solid slategrey; +} \ No newline at end of file diff --git a/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/AppBarTitle.js b/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/AppBarTitle.js new file mode 100644 index 0000000..96b7c87 --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/AppBarTitle.js @@ -0,0 +1,23 @@ +import React from 'react' +import classes from './AppBarTitle.scss' + +export const AppBarTitle = ({data, fetching, currentApplicationState }) => { + return ( +
+
+ {data.left ? data.left(currentApplicationState) :
} +
+ {data.center ? data.center(currentApplicationState) :
} +
+ {data.right ? data.right(currentApplicationState) :
} +
+
+)} + +AppBarTitle.propTypes = { + fetching: React.PropTypes.bool.isRequired, + data: React.PropTypes.object.isRequired, + currentApplicationState: React.PropTypes.object.isRequired +} + +export default AppBarTitle diff --git a/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/AppBarTitle.scss b/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/AppBarTitle.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/index.js b/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/index.js new file mode 100644 index 0000000..0397b55 --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/AppBarTitle/index.js @@ -0,0 +1,3 @@ +import AppBarTitle from './AppBarTitle' + +export default AppBarTitle diff --git a/FrontEnd/src/layouts/MainLayout/components/MainMenu/MainMenu.js b/FrontEnd/src/layouts/MainLayout/components/MainMenu/MainMenu.js new file mode 100644 index 0000000..a122146 --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/MainMenu/MainMenu.js @@ -0,0 +1,82 @@ +import React from 'react' + +import SearchIcon from 'material-ui/svg-icons/action/search' +import SettingsIcon from 'material-ui/svg-icons/action/settings' +import AccountIcon from 'material-ui/svg-icons/action/account-box' +import HelpIcon from 'material-ui/svg-icons/action/help' +import StatisticsIcon from 'material-ui/svg-icons/editor/insert-chart' +import MenuIcon from 'material-ui/svg-icons/navigation/menu' +import IconButton from 'material-ui/IconButton' + +import Menu from 'material-ui/Menu' +import MenuItem from 'material-ui/MenuItem' +import Divider from 'material-ui/Divider' +import IconMenu from 'material-ui/IconMenu' + +import classes from './MainMenu.scss' + +const innerMenuItemStyle = { paddingLeft: '50px' } +const menuItemStyle = { WebkitAppearance: 'none' } +const selectedMenuItemStyle = { color: '#212121', fontWeight: '600' } + +const SEARCH_PAGE_LOCATION = '/' +const SETTINGS_PAGE_LOCATION = '/settings' +const STAT_PAGE_LOCATION = '/statistics' +const ACCOUNT_PAGE_LOCATION = '/account' + +export const SideMenu = ({ isOpen, currentLocation, changeLocation, toggleMainMenu, localization }) => { + return ( + } + anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }} + targetOrigin={{ horizontal: 'left', vertical: 'top' }} + open={isOpen} + onTouchTap={() => toggleMainMenu()} + onRequestChange={(open, reason) => { + if (reason === 'clickAway') { + toggleMainMenu() + } + }} + > + + changeLocation(SEARCH_PAGE_LOCATION)} + value={SEARCH_PAGE_LOCATION} + leftIcon={} + innerDivStyle={innerMenuItemStyle} + style={menuItemStyle}> + {localization.mainMenu.searchLabel} + + changeLocation(SETTINGS_PAGE_LOCATION)} + value={SETTINGS_PAGE_LOCATION} + leftIcon={} + innerDivStyle={innerMenuItemStyle} + style={menuItemStyle}> + {localization.mainMenu.settingsLabel} + + changeLocation(STAT_PAGE_LOCATION)} + value={STAT_PAGE_LOCATION} + leftIcon={} + innerDivStyle={innerMenuItemStyle} + style={menuItemStyle}> + {localization.mainMenu.statisticsLabel} + + + + ) +} + +SideMenu.propTypes = { + isOpen: React.PropTypes.bool.isRequired, + currentLocation: React.PropTypes.string.isRequired, + changeLocation: React.PropTypes.func.isRequired, + toggleMainMenu: React.PropTypes.func.isRequired, + localization: React.PropTypes.object.isRequired +} + +export default SideMenu diff --git a/FrontEnd/src/layouts/MainLayout/components/MainMenu/MainMenu.scss b/FrontEnd/src/layouts/MainLayout/components/MainMenu/MainMenu.scss new file mode 100644 index 0000000..e69de29 diff --git a/FrontEnd/src/layouts/MainLayout/components/MainMenu/index.js b/FrontEnd/src/layouts/MainLayout/components/MainMenu/index.js new file mode 100644 index 0000000..33681ae --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/MainMenu/index.js @@ -0,0 +1,3 @@ +import MainMenu from './MainMenu' + +export default MainMenu diff --git a/FrontEnd/src/layouts/MainLayout/components/RateUs/RateUs.js b/FrontEnd/src/layouts/MainLayout/components/RateUs/RateUs.js new file mode 100644 index 0000000..4aea9d8 --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/RateUs/RateUs.js @@ -0,0 +1,70 @@ +import React, { Component } from 'react' +import FlatButton from 'material-ui/FlatButton' +import Dialog from 'material-ui/Dialog' + +import FacebookIcon from './assets/facebook.svg' +import GithubIcon from './assets/github.svg' +import TwitterIcon from './assets/twitter.svg' + +import classes from './RateUs.scss' + +class RateUs extends Component { + constructor() { + super() + } + + render() { + const { isOpen, toggle } = this.props + + const goToUrl = (url) => { + window.open(url) + } + + return ( +
+ toggle(true)} /> + toggle(false)} + > +
+
+ Rate Us +
+
+

+ Let's spread the word that Ambar is awesome! Help us make Ambar even better, follow us on Twitter or give us your stars on Github. +

+

+ Together we will build the best document search system in the world! +

+
+ goToUrl('https://github.com/RD17/ambar')} + icon={} + /> + goToUrl('https://twitter.com/intent/tweet?text=%23Ambar%20is%20awesome%20%23DocumentSearchSystem!%20Check%20it%20out%20on%20https%3A%2F%2Fambar.cloud')} + icon={} + /> +
+
+
+
+
+ ) + } +} + +RateUs.propTypes = { + isOpen: React.PropTypes.bool.isRequired, + toggle: React.PropTypes.func.isRequired +} + +export default RateUs diff --git a/FrontEnd/src/layouts/MainLayout/components/RateUs/RateUs.scss b/FrontEnd/src/layouts/MainLayout/components/RateUs/RateUs.scss new file mode 100644 index 0000000..e08d09c --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/RateUs/RateUs.scss @@ -0,0 +1,19 @@ +.stampIcon:hover { + filter: saturate(2); +} + +.stampIcon:active{ + filter: saturate(3); +} + +.stampIconContainer { + cursor: pointer; +} + +.rateUsText { + display: flex; + flex-direction: column; +} +.rateUsText p { + margin-top: 0; +} \ No newline at end of file diff --git a/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/facebook.svg b/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/facebook.svg new file mode 100644 index 0000000..962fc2f --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/facebook.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/github.svg b/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/github.svg new file mode 100644 index 0000000..bf0cf26 --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/github.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/twitter.svg b/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/twitter.svg new file mode 100644 index 0000000..c0364cc --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/RateUs/assets/twitter.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/layouts/MainLayout/components/RateUs/index.js b/FrontEnd/src/layouts/MainLayout/components/RateUs/index.js new file mode 100644 index 0000000..90452bd --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/components/RateUs/index.js @@ -0,0 +1,3 @@ +import RateUs from './RateUs' + +export default RateUs \ No newline at end of file diff --git a/FrontEnd/src/layouts/MainLayout/index.js b/FrontEnd/src/layouts/MainLayout/index.js new file mode 100644 index 0000000..0a38c9f --- /dev/null +++ b/FrontEnd/src/layouts/MainLayout/index.js @@ -0,0 +1,3 @@ +import MainLayout from './MainLayout' + +export default MainLayout \ No newline at end of file diff --git a/FrontEnd/src/main.js b/FrontEnd/src/main.js new file mode 100644 index 0000000..dd14b0d --- /dev/null +++ b/FrontEnd/src/main.js @@ -0,0 +1,92 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import createBrowserHistory from 'history/lib/createBrowserHistory' +import { useRouterHistory } from 'react-router' +import { syncHistoryWithStore } from 'react-router-redux' +import createStore from './store/createStore' +import AppContainer from './containers/AppContainer' + +String.prototype.capitalize = function() { + return this.charAt(0).toUpperCase() + this.slice(1); +} + +// ======================================================== +// Browser History Setup +// ======================================================== +const browserHistory = useRouterHistory(createBrowserHistory)({ + basename: __BASENAME__ +}) + +// ======================================================== +// Store and History Instantiation +// ======================================================== +// Create redux store and sync with react-router-redux. We have installed the +// react-router-redux reducer under the routerKey "router" in src/routes/index.js, +// so we need to provide a custom `selectLocationState` to inform +// react-router-redux of its location. +const initialState = window.___INITIAL_STATE__ +const store = createStore(initialState, browserHistory) +const history = syncHistoryWithStore(browserHistory, store, { + selectLocationState: (state) => state.router +}) + +// ======================================================== +// Developer Tools Setup +// ======================================================== +if (__DEBUG__) { + if (window.devToolsExtension) { + window.devToolsExtension.open() + } +} + +// ======================================================== +// Render Setup +// ======================================================== +const MOUNT_NODE = document.getElementById('root') + +let render = () => { + const routes = require('./routes/index').default(store) + ReactDOM.render( + , + MOUNT_NODE + ) +} + +// This code is excluded from production bundle +if (__DEV__) { + if (module.hot) { + // Development render functions + const renderApp = render + + const renderError = (error) => { + const RedBox = require('redbox-react').default + ReactDOM.render(, MOUNT_NODE) + } + + // Wrap render in try/catch + render = () => { + try { + renderApp() + } catch (error) { + renderError(error) + } + } + + // Setup hot module replacement + module.hot.accept('./routes/index', () => { + setTimeout(() => { + ReactDOM.unmountComponentAtNode(MOUNT_NODE) + render() + }) + }) + } +} + +// ======================================================== +// Go! +// ======================================================== +render() diff --git a/FrontEnd/src/models/crawlersModel.js b/FrontEnd/src/models/crawlersModel.js new file mode 100644 index 0000000..38fcb3b --- /dev/null +++ b/FrontEnd/src/models/crawlersModel.js @@ -0,0 +1,35 @@ +import moment from 'moment' +import { dates, urls } from 'utils/' + +const getCawlerJson = (crawler) => JSON.stringify({ + ...crawler, +}, null, 2) + +const parseCrawlerFromApi = (apiResp) => ({ + settings: { + ...apiResp, + }, + meta: { + fetching: false, + state: apiResp.state, + json: getCawlerJson(apiResp) + }, + log: { + fetching: false, + records: [] + }, + displayArgs: { + isSettingsModalOpen: false + } +}) + +export const fromApi = (resp) => { + let crawlers = new Map() + resp.map((crawlerFromApi) => { + const crawler = parseCrawlerFromApi(crawlerFromApi) + crawlers.set(crawler.settings.id, crawler) + }) + return crawlers +} + +export const fromApiSingle = (resp) => parseCrawlerFromApi(resp) \ No newline at end of file diff --git a/FrontEnd/src/models/folderHitsModel.js b/FrontEnd/src/models/folderHitsModel.js new file mode 100644 index 0000000..64d3f7f --- /dev/null +++ b/FrontEnd/src/models/folderHitsModel.js @@ -0,0 +1,21 @@ +import moment from 'moment' +import { dates, urls } from 'utils/' + +export const fromApi = (resp) => { + const transformModelToView = (hit) => ({ + path: hit.path, + name: hit.name, + type: hit.type, + childNodes: hit.children.map(child => transformModelToView(child)), + hitsCount: hit.hits_count, + isExpanded: false, + depth: hit.depth, + parentPath: hit.parent_path, + thumbAvailable: hit.thumb_available, + contentType: hit.content_type, + sha256: hit.sha256, + fileId: hit.file_id, + }) + + return resp.tree.map(node => transformModelToView(node)) +} diff --git a/FrontEnd/src/models/hitsModel.js b/FrontEnd/src/models/hitsModel.js new file mode 100644 index 0000000..5fa1f6e --- /dev/null +++ b/FrontEnd/src/models/hitsModel.js @@ -0,0 +1,28 @@ +import moment from 'moment' +import { dates, urls } from 'utils/' + +export const fromApi = (resp) => { + let hits = new Map() + resp.hits.forEach((hit) => { + hits.set(hit.file_id, { + ...hit, + fetching: false + }) + }) + return hits +} + +export const contentHighlightFromApi = (resp) => { + return resp.highlight +} + +export const getHit = (state, fileId) => { + const hit = state.hits.get(fileId) + return hit +} + +export const updateHits = (state, fileId, hit) => { + const newState = { ...state, hits: new Map(state.hits) } + newState.hits.set(fileId, hit) + return newState +} diff --git a/FrontEnd/src/models/index.js b/FrontEnd/src/models/index.js new file mode 100644 index 0000000..9e8eb09 --- /dev/null +++ b/FrontEnd/src/models/index.js @@ -0,0 +1,9 @@ +import * as hitsModel from './hitsModel' +import * as crawlersModel from './crawlersModel' +import * as folderHitsModel from './folderHitsModel' + +export { + hitsModel, + crawlersModel, + folderHitsModel +} \ No newline at end of file diff --git a/FrontEnd/src/routes/CoreLayout/containers/CoreLayoutContainer.js b/FrontEnd/src/routes/CoreLayout/containers/CoreLayoutContainer.js new file mode 100644 index 0000000..40056ba --- /dev/null +++ b/FrontEnd/src/routes/CoreLayout/containers/CoreLayoutContainer.js @@ -0,0 +1,20 @@ +import { connect } from 'react-redux' +import { loadConfig, setPageTitle, closeNotification } from '../modules/CoreLayout' +import CoreLayout from 'layouts/CoreLayout/CoreLayout' + +const mapDispatchToProps = { + loadConfig, + setPageTitle, + closeNotification +} + +const mapStateToProps = (state) => { + return ({ + fetching: state['core'].fetching, + isNotificationOpen: state['core'].isNotificationOpen, + notificationMessage: state['core'].notificationMessage, + notificationReason: state['core'].notificationReason + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(CoreLayout) diff --git a/FrontEnd/src/routes/CoreLayout/index.js b/FrontEnd/src/routes/CoreLayout/index.js new file mode 100644 index 0000000..f020f6d --- /dev/null +++ b/FrontEnd/src/routes/CoreLayout/index.js @@ -0,0 +1,8 @@ +import { injectReducer } from '../../store/reducers' +import CoreLayout from './containers/CoreLayoutContainer' +import reducer from './modules/CoreLayout' + +export default (store) => { + injectReducer(store, { key: 'core', reducer }) + return CoreLayout +} \ No newline at end of file diff --git a/FrontEnd/src/routes/CoreLayout/modules/CoreLayout.js b/FrontEnd/src/routes/CoreLayout/modules/CoreLayout.js new file mode 100644 index 0000000..51415ab --- /dev/null +++ b/FrontEnd/src/routes/CoreLayout/modules/CoreLayout.js @@ -0,0 +1,152 @@ +import { titles, stateValueExtractor, urls, constants, analytics } from 'utils' +import 'whatwg-fetch' + +const CHANGE_FIELD = 'CORE.CHANGE_FIELD' +const HANDLE_ERROR = 'CORE.HANDLE_ERROR' +const CLOSE_NOTIFICATION = 'CORE.CLOSE_NOTIFICATION' +const SHOW_INFO = 'CORE.SHOW_INFO' + +export const loadConfig = () => { + return (dispatch, getState) => { + dispatch(startLoadingIndicator()) + + getApiUrl() + .then(apiUrl => dispatch(changeField('urls', urls(apiUrl)))) + .then(() => getLocalizationsJson()) + .then(localizations => dispatch(changeField('localizations', JSON.parse(localizations)))) + .then(() => { + const urls = stateValueExtractor.getUrls(getState()) + return getWebApiInfo(urls.ambarWebApiGetInfo()) + }) + .then(apiInfo => { + const urls = stateValueExtractor.getUrls(getState()) + + dispatch(changeField('version', apiInfo.version)) + dispatch(changeField('lang', apiInfo.uiLang)) + + analytics(apiInfo.analyticsToken) + analytics().register({ apiUrl: urls.apiHost }) + + }) + .then(() => dispatch(stopLoadingIndicator())) + .catch(error => { + console.error(`Failed to start. Error: ${error}`) + dispatch(handleError(error)) + }) + } +} + +export const setPageTitle = (title) => { + return (dispatch, getState) => { + titles.setPageTitle(title) + } +} + +const startLoadingIndicator = () => { + return (dispatch, getState) => { + dispatch(changeField('fetching', true)) + } +} + +const stopLoadingIndicator = () => { + return (dispatch, getState) => { + dispatch(changeField('fetching', false)) + } +} + +const getApiUrl = () => new Promise((resolve, reject) => { + fetch('apiUrl.txt', { + method: 'GET' + }) + .then(resp => resolve(resp.text())) + .catch(err => reject(err)) +}) + +const getLocalizationsJson = () => new Promise((resolve, reject) => { + fetch('localizations.json', { + method: 'GET' + }) + .then(resp => resolve(resp.text())) + .catch(err => reject(err)) +}) + +const getWebApiInfo = (url) => new Promise((resolve, reject) => { + fetch(url, { + method: 'GET' + }) + .then(resp => resolve(resp.json())) + .catch(err => reject(err)) +}) + +export function showInfo(message) { + return { + type: SHOW_INFO, + message + } +} + +export function handleError(error, showErrorMessage = false) { + if (error.constructor === Response) { + error = `Response ${error.status} ${error.statusText} at ${error.url}` + } + analytics().event('ERROR', { description: error ? error.toString() : 'no info' }) + console.log(error) + + return { + type: HANDLE_ERROR, + error, + showErrorMessage + } +} + +export function closeNotification() { + return { + type: CLOSE_NOTIFICATION + } +} + +const changeField = (fieldName, value) => { + return { + type: CHANGE_FIELD, + fieldName, + value + } +} + +const ACTION_HANDLERS = { + [CHANGE_FIELD]: (state, action) => { + const newState = { ...state } + newState[action.fieldName] = action.value + + return newState + }, + [HANDLE_ERROR]: (state, action) => { + return ({ ...state, isNotificationOpen: true, fetching: false, notificationMessage: action.showErrorMessage ? action.error : constants.errorMessage, notificationReason: 'error' }) + }, + [SHOW_INFO]: (state, action) => { + return ({ ...state, isNotificationOpen: true, fetching: false, notificationMessage: action.message, notificationReason: 'info' }) + }, + [CLOSE_NOTIFICATION]: (state, action) => { + return ({ ...state, isNotificationOpen: false }) + } +} + +const initialState = { + urls: {}, + localizations: {}, + lang: 'en', + integrations: {}, + mode: 'ce', + version: '0.0', + fetching: true, + isNotificationOpen: false, + notificationMessage: '', + notificationReason: 'error', + preserveOriginals: false, + auth: 'basic' +} + +export default function coreLayoutReducer(state = initialState, action) { + const handler = ACTION_HANDLERS[action.type] + return handler ? handler(state, action) : state +} \ No newline at end of file diff --git a/FrontEnd/src/routes/MainLayout/containers/MainLayoutContainer.js b/FrontEnd/src/routes/MainLayout/containers/MainLayoutContainer.js new file mode 100644 index 0000000..6e165f0 --- /dev/null +++ b/FrontEnd/src/routes/MainLayout/containers/MainLayoutContainer.js @@ -0,0 +1,38 @@ +import { connect } from 'react-redux' +import { stateValueExtractor } from 'utils/' +import { + postConfigRequest, + checkIfAllowed, + toggleSideMenu, + changeLocation, + setAppHeader, + toggleRateUsModal +} from '../modules/MainLayout' + +import MainLayout from 'layouts/MainLayout/MainLayout' + +const mapDispatchToProps = { + postConfigRequest, + toggleSideMenu, + changeLocation, + setAppHeader, + toggleRateUsModal +} + +const mapStateToProps = (state, ownProps) => { + return ({ + fetching: state['global'].fetching, + children: ownProps.children, + location: state['router'].locationBeforeTransitions.pathname, + isSideMenuOpen: state['global'].isSideMenuOpen, + header: state['global'].header, + mode: state['core'].mode, + version: state['core'].version, + showRateUsModal: state['global'].showRateUsModal, + auth: state['core'].auth, + state: state, + localization: stateValueExtractor.getLocalization(state) + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(MainLayout) \ No newline at end of file diff --git a/FrontEnd/src/routes/MainLayout/index.js b/FrontEnd/src/routes/MainLayout/index.js new file mode 100644 index 0000000..816ec16 --- /dev/null +++ b/FrontEnd/src/routes/MainLayout/index.js @@ -0,0 +1,8 @@ +import { injectReducer } from '../../store/reducers' +import MainLayout from './containers/MainLayoutContainer' +import reducer from './modules/MainLayout' + +export default (store) => { + injectReducer(store, { key: 'global', reducer }) + return MainLayout +} \ No newline at end of file diff --git a/FrontEnd/src/routes/MainLayout/modules/MainLayout.js b/FrontEnd/src/routes/MainLayout/modules/MainLayout.js new file mode 100644 index 0000000..4c9d993 --- /dev/null +++ b/FrontEnd/src/routes/MainLayout/modules/MainLayout.js @@ -0,0 +1,110 @@ +import { urls, titles, stateValueExtractor, analytics } from 'utils' +import { push } from 'react-router-redux' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' + +import 'whatwg-fetch' + +export const START_LOADING_INDICATOR = 'MAIN.START_LOADING_INDICATOR' +export const STOP_LOADING_INDICATOR = 'MAIN.STOP_LOADING_INDICATOR' +export const CHANGE_SIDE_MENU_STATE = 'MAIN.CHANGE_SIDE_MENU_STATE' +export const SET_APP_HEADER = 'MAIN.SET_APP_HEADER' +const CHANGE_FIELD = 'MAIN.CHANGE_FIELD' + +export const toggleSideMenu = () => { + return (dispatch, getState) => { + const isSideMenuOpen = getState().global.isSideMenuOpen + dispatch(changeSideMenuState(!isSideMenuOpen)) + } +} + +export const changeLocation = (location) => { + return (dispatch, getState) => { + const currentLocation = getState()['router'].locationBeforeTransitions.pathname + if (currentLocation !== location) { + dispatch(startLoadingIndicator()) + dispatch(push(location)) + } + + dispatch(toggleSideMenu()) + } +} + +export function startLoadingIndicator() { + return { + type: START_LOADING_INDICATOR + } +} + +export function stopLoadingIndicator() { + return { + type: STOP_LOADING_INDICATOR + } +} + +export const toggleRateUsModal = (value) => { + return (dispatch, getState) => { + dispatch(changeField('showRateUsModal', value)) + analytics().event('ACCOUNT.RATE_US_MODAL_OPENED') + } +} + +export const setAppHeader = (header) => { + return { + type: SET_APP_HEADER, + header + } +} + +function changeSideMenuState(isSideMenuOpen) { + return { + type: CHANGE_SIDE_MENU_STATE, + isSideMenuOpen + } +} + +const changeField = (fieldName, value) => { + return { + type: CHANGE_FIELD, + fieldName, + value + } +} + +const ACTION_HANDLERS = { + [START_LOADING_INDICATOR]: (state, action) => { + return ({ ...state, fetching: true, isError: false }) + }, + [STOP_LOADING_INDICATOR]: (state, action) => { + return ({ ...state, fetching: false }) + }, + [CHANGE_SIDE_MENU_STATE]: (state, action) => { + return ({ ...state, isSideMenuOpen: action.isSideMenuOpen }) + }, + [SET_APP_HEADER]: (state, action) => { + return ({ ...state, header: action.header }) + }, + [CHANGE_FIELD]: (state, action) => { + const newState = {...state} + newState[action.fieldName] = action.value + + return newState + } +} + +const initial_state = { + isSideMenuOpen: false, + fetching: true, + header: { + left: () => 'Loading...' + }, + showRateUsModal: false +} + +export default function mainLayoutReducer(state = initial_state, action) { + const handler = ACTION_HANDLERS[action.type] + + return handler ? handler(state, action) : state +} + + + diff --git a/FrontEnd/src/routes/SearchPage/containers/DetailedViewContainer.js b/FrontEnd/src/routes/SearchPage/containers/DetailedViewContainer.js new file mode 100644 index 0000000..94b5dd4 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/DetailedViewContainer.js @@ -0,0 +1,44 @@ +import { connect } from 'react-redux' +import { stateValueExtractor } from 'utils/' + +import { toggleImagePreview } from '../modules/ImagePreview' +import { addTagToFile, removeTagFromFile } from '../modules/TagsReducer' +import { hideFile, showFile } from '../modules/FileVisibilityReducer' +import { loadHighlight } from '../modules/DetailedView' + +import { + performSearchByPathToFile, + performSearchByAuthor, + performSearchByQuery, + performSearchByTag, + search +} from '../modules/SearchReducer' + +import DetailedView from 'components/Search/components/Views/DetailedView' + +const mapDispatchToProps = { + search, + performSearchByPathToFile, + performSearchByAuthor, + performSearchByQuery, + performSearchByTag, + toggleImagePreview, + addTagToFile, + removeTagFromFile, + hideFile, + showFile, + loadHighlight +} + +const mapStateToProps = (state, ownProps) => { + return ({ + hits: state['searchPage'].hits, + localization: stateValueExtractor.getLocalization(state), + urls: stateValueExtractor.getUrls(state), + allTags: state['searchPage'].tags, + searchQuery: state['searchPage'].searchQuery, + preserveOriginals: state['core'].preserveOriginals + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(DetailedView) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/containers/EmptySearchResultsContainer.js b/FrontEnd/src/routes/SearchPage/containers/EmptySearchResultsContainer.js new file mode 100644 index 0000000..e123200 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/EmptySearchResultsContainer.js @@ -0,0 +1,17 @@ +import { connect } from 'react-redux' +import { performSearchByQuery } from '../modules/SearchReducer' +import { stateValueExtractor } from 'utils/' +import EmptySearchResultsCardView from 'components/Search/components/EmptySearchResultsCard' + +const mapDispatchToProps = { + performSearchByQuery +} + +const mapStateToProps = (state, ownProps) => { + return ({ + searchQuery: state['searchPage'].searchQuery, + localization: stateValueExtractor.getLocalization(state) + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(EmptySearchResultsCardView) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/containers/FolderViewContainer.js b/FrontEnd/src/routes/SearchPage/containers/FolderViewContainer.js new file mode 100644 index 0000000..b6a3e07 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/FolderViewContainer.js @@ -0,0 +1,25 @@ +import { connect } from 'react-redux' +import { stateValueExtractor } from 'utils/' +import { toggleTreeNode, toggleAll } from '../modules/FolderView' +import { search, performSearchByPathToFile } from '../modules/SearchReducer' +import { toggleImagePreview } from '../modules/ImagePreview' +import FolderView from 'components/Search/components/Views/FolderView' + +const mapDispatchToProps = { + search, + performSearchByPathToFile, + toggleTreeNode, + toggleAll, + toggleImagePreview +} + +const mapStateToProps = (state, ownProps) => { + return ({ + folderHits: state['searchPage'].folderHits, + searchQuery: state['searchPage'].searchQuery, + localization: stateValueExtractor.getLocalization(state), + urls: stateValueExtractor.getUrls(state), + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(FolderView) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/containers/ImagePreviewContainer.js b/FrontEnd/src/routes/SearchPage/containers/ImagePreviewContainer.js new file mode 100644 index 0000000..0a50e59 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/ImagePreviewContainer.js @@ -0,0 +1,20 @@ +import { connect } from 'react-redux' + +import { + toggleImagePreview +} from '../modules/ImagePreview' + +import ImagePreview from 'components/Search/components/ImagePreview' + +const mapDispatchToProps = { + toggle: toggleImagePreview +} + +const mapStateToProps = (state, ownProps) => { + return ({ + visible: state['searchPage'].isImagePreviewOpen, + imageUrl: state['searchPage'].imagePreviewUrl + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(ImagePreview) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/containers/SearchPageContainer.js b/FrontEnd/src/routes/SearchPage/containers/SearchPageContainer.js new file mode 100644 index 0000000..653c01a --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/SearchPageContainer.js @@ -0,0 +1,58 @@ +import { connect } from 'react-redux' +import { stateValueExtractor, constants } from 'utils/' + +import { loadTags } from '../modules/TagsReducer' +import { toggleUploadModal } from '../modules/UploadModal' + +import { + setScrolledDown, + setQueryFromGetParam, + setSearchResultView +} from '../modules/SearchPage' + +import { + setQuery, + search, + cleanUpSearchResult, + performSearchByQuery, + performSearchBySize, + performSearchByWhen, + performSearchByShow, + performSearchByTag +} from '../modules/SearchReducer' + +import Search from 'components/Search' + +const mapDispatchToProps = { + search, + performSearchByQuery, + performSearchBySize, + performSearchByWhen, + performSearchByShow, + performSearchByTag, + loadTags, + setScrolledDown, + toggleUploadModal, + cleanUpSearchResult, + setQueryFromGetParam, + setQuery, + setSearchResultView +} + +const mapStateToProps = (state) => { + return ({ + hasMore: state['searchPage'].hasMore, + searchQuery: state['searchPage'].searchQuery, + fetching: state['global'].fetching, + hits: Array.from(state['searchPage'].hits.values()), + folderHits: state['searchPage'].folderHits, + scrolledDown: state['searchPage'].scrolledDown, + currentPage: state['searchPage'].currentPage, + mode: state['core'].mode, + searchView: state['searchPage'].searchView, + allTags: state['searchPage'].tags, + localization: stateValueExtractor.getLocalization(state) + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(Search) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/containers/StatisticsViewContainer.js b/FrontEnd/src/routes/SearchPage/containers/StatisticsViewContainer.js new file mode 100644 index 0000000..9dfc406 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/StatisticsViewContainer.js @@ -0,0 +1,21 @@ +import { connect } from 'react-redux' +import { stateValueExtractor } from 'utils/' +import { search, performSearchByPathToFile, performSearchByTag, performSearchByNamedEntity } from '../modules/SearchReducer' +import StatisticsView from 'components/Search/components/Views/StatisticsView' + +const mapDispatchToProps = { + search, + performSearchByPathToFile, + performSearchByTag, + performSearchByNamedEntity +} + +const mapStateToProps = (state, ownProps) => { + return ({ + stats: state['searchPage'].stats, + searchQuery: state['searchPage'].searchQuery, + localization: stateValueExtractor.getLocalization(state) + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(StatisticsView) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/containers/TableViewContainer.js b/FrontEnd/src/routes/SearchPage/containers/TableViewContainer.js new file mode 100644 index 0000000..fcde619 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/TableViewContainer.js @@ -0,0 +1,42 @@ +import { connect } from 'react-redux' +import { stateValueExtractor } from 'utils/' + +import { toggleImagePreview } from '../modules/ImagePreview' +import { addTagToFile, removeTagFromFile} from '../modules/TagsReducer' +import { hideFile, showFile } from '../modules/FileVisibilityReducer' + +import { + search, + performSearchByPathToFile, + performSearchByAuthor, + performSearchByQuery, + performSearchByTag +} from '../modules/SearchReducer' + +import TableView from 'components/Search/components/Views/TableView' + +const mapDispatchToProps = { + search, + performSearchByPathToFile, + performSearchByAuthor, + performSearchByQuery, + performSearchByTag, + toggleImagePreview, + addTagToFile, + removeTagFromFile, + hideFile, + showFile +} + +const mapStateToProps = (state, ownProps) => { + return ({ + hits: state['searchPage'].hits, + localization: stateValueExtractor.getLocalization(state), + urls: stateValueExtractor.getUrls(state), + allTags: state['searchPage'].tags, + searchQuery: state['searchPage'].searchQuery, + preserveOriginals: state['core'].preserveOriginals + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(TableView) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/containers/UploadModalContainer.js b/FrontEnd/src/routes/SearchPage/containers/UploadModalContainer.js new file mode 100644 index 0000000..19a8a2e --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/containers/UploadModalContainer.js @@ -0,0 +1,29 @@ +import { connect } from 'react-redux' +import { stateValueExtractor } from 'utils/' + +import { + toggleUploadModal, + addFilesToUpload, + removeFileToUpload, + uploadFiles +} from '../modules/UploadModal' + +import UploadModal from 'components/Search/components/UploadFileModal' + +const mapDispatchToProps = { + toggleModal: toggleUploadModal, + addFilesToUpload, + removeFileToUpload, + uploadFiles +} + +const mapStateToProps = (state, ownProps) => { + return ({ + fetching: state['searchPage'].isFilesUploading, + open: state['searchPage'].isUploadModalOpen, + filesToUpload: state['searchPage'].filesToUpload, + localization: stateValueExtractor.getLocalization(state) + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(UploadModal) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/index.js b/FrontEnd/src/routes/SearchPage/index.js new file mode 100644 index 0000000..1474bbc --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/index.js @@ -0,0 +1,14 @@ +import { injectReducer } from '../../store/reducers' + +export default (store) => ({ + getComponent (nextState, cb) { + require.ensure([], (require) => { + const searchPage = require('./containers/SearchPageContainer').default + + const searchPageReducer = require('./modules/index').default + injectReducer(store, { key: 'searchPage', reducer: searchPageReducer }) + + cb(null, searchPage) + }, 'searchPage') + } +}) \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/DetailedView.js b/FrontEnd/src/routes/SearchPage/modules/DetailedView.js new file mode 100644 index 0000000..49f4df9 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/DetailedView.js @@ -0,0 +1,66 @@ +import { stateValueExtractor } from 'utils/' +import { hitsModel } from 'models/' +import { analytics } from 'utils' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { startLoadingIndicator, stopLoadingIndicator } from 'routes/MainLayout/modules/MainLayout' + +export const START_STOP_HIGHLIGHT_LOADING = 'DETAILED_VIEW.START_STOP_HIGHLIGHT_LOADING' +export const SET_CONTENT_HIGHLIGHT = 'DETAILED_VIEW.SET_CONTENT_HIGHLIGHT' + +export const loadHighlight = (fileId, query) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + return new Promise((resolve) => { + dispatch(startStopHighlightLoadingIndicator(fileId, true)) + fetch(urls.ambarWebApiLoadContentHightlight(fileId, query), { + method: 'GET', + ...defaultSettings + }) + .then((resp) => { + if (resp.status == 200) { return resp.json() } + else { throw resp } + }) + .then((resp) => { + dispatch(setContentHighlight(fileId, hitsModel.contentHighlightFromApi(resp))) + dispatch(startStopHighlightLoadingIndicator(fileId, false)) + analytics().event('SEARCH.LOAD_HIGHLIGHT') + }) + .catch((errorPayload) => { + dispatch(startStopHighlightLoadingIndicator(fileId, false)) + dispatch(handleError(errorPayload)) + console.error('loadHighlight', errorPayload) + }) + }) + } +} + +const setContentHighlight = (fileId, highlight) => { + return { + type: SET_CONTENT_HIGHLIGHT, + fileId, + highlight + } +} + +const startStopHighlightLoadingIndicator = (fileId, fetching) => { + return { + type: START_STOP_HIGHLIGHT_LOADING, + fileId, + fetching + } +} + +export const ACTION_HANDLERS = { + [START_STOP_HIGHLIGHT_LOADING]: (state, action) => { + const oldHit = hitsModel.getHit(state, action.fileId) + const hit = { ...oldHit, fetching: action.fetching } + return hitsModel.updateHits(state, action.fileId, hit) + }, + [SET_CONTENT_HIGHLIGHT]: (state, action) => { + const oldHit = hitsModel.getHit(state, action.fileId) + const hit = { ...oldHit, content: { ...oldHit.content, highlight: action.highlight } } + return hitsModel.updateHits(state, action.fileId, hit) + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/FileVisibilityReducer.js b/FrontEnd/src/routes/SearchPage/modules/FileVisibilityReducer.js new file mode 100644 index 0000000..9346ef5 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/FileVisibilityReducer.js @@ -0,0 +1,72 @@ +import { stateValueExtractor, analytics } from 'utils' +import { hitsModel } from 'models/' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { startLoadingIndicator, stopLoadingIndicator } from 'routes/MainLayout/modules/MainLayout' + +export const TOGGLE_IS_HIDDEN_FILE = 'FILE_VISIBILITY.TOGGLE_IS_HIDDEN_FILE' + +export const hideFile = (fileId) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + dispatch(toggleIsHiddenFile(fileId, true)) + + fetch(urls.ambarWebApiHideFile(fileId), { + method: 'PUT', + ...defaultSettings + }) + .then(resp => { + if (resp.status == 200) { + analytics().event('FILE.HIDE') + return + } + else { throw resp } + }) + .catch((errorPayload) => { + dispatch(handleError(errorPayload)) + console.error('hideFile', errorPayload) + }) + } +} + +export const showFile = (fileId) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + dispatch(toggleIsHiddenFile(fileId, false)) + + fetch(urls.ambarWebApiUnhideFile(fileId), { + method: 'PUT', + ...defaultSettings + }) + .then(resp => { + if (resp.status == 200) { + analytics().event('FILE.SHOW') + return + } + else { throw resp } + }) + .catch((errorPayload) => { + dispatch(handleError(errorPayload)) + console.error('showFile', errorPayload) + }) + } +} + +const toggleIsHiddenFile = (fileId, value) => { + return { + type: TOGGLE_IS_HIDDEN_FILE, + fileId: fileId, + value: value + } +} + +export const ACTION_HANDLERS = { + [TOGGLE_IS_HIDDEN_FILE]: (state, action) => { + const oldHit = hitsModel.getHit(state, action.fileId) + const hit = { ...oldHit, isHidden: action.value, hidden_mark: action.value ? {} : null } + return hitsModel.updateHits(state, action.fileId, hit) + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/FolderView.js b/FrontEnd/src/routes/SearchPage/modules/FolderView.js new file mode 100644 index 0000000..ce41097 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/FolderView.js @@ -0,0 +1,77 @@ +import { stateValueExtractor } from 'utils/' +import { folderHitsModel } from 'models/' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { startLoadingIndicator, stopLoadingIndicator } from 'routes/MainLayout/modules/MainLayout' +import 'whatwg-fetch' + +export const TOGGLE_NODE = 'FOLDER_VIEW.TOGGLE_NODE' +export const TOGGLE_ALL = 'FOLDER_VIEW.TOGGLE_ALL' + +export const toggleTreeNode = (nodePath) => { + return { + type: TOGGLE_NODE, + nodePath + } +} + +export const toggleAll = (value) => { + return { + type: TOGGLE_ALL, + value: value + } +} + +const findNodeByPath = (node, path) => { + if (node.path === path) { + return node + } + + if (!node) { + return null + } + + for (const childNode in node.childNodes) { + const result = findNodeByPath(node.childNodes[childNode], path) + if (result != null) { + return result + } + } + + return null +} + +const toggleExpanded = (node, value) => { + if (!node) { + return + } + + node.isExpanded = value + node.childNodes.forEach(childNode => toggleExpanded(childNode, value)) +} + +export const ACTION_HANDLERS = { + [TOGGLE_NODE]: (state, action) => { + let newState = { ...state } + + let folderHits = JSON.parse(JSON.stringify(state.folderHits)) + + for (const node in folderHits) { + const result = findNodeByPath(folderHits[node], action.nodePath) + if (result != null) { + result.isExpanded = !result.isExpanded + break + } + } + newState.folderHits = folderHits + + return newState + }, + [TOGGLE_ALL]: (state, action) => { + let newState = { ...state } + let folderHits = JSON.parse(JSON.stringify(state.folderHits)) + folderHits.forEach(node => toggleExpanded(node, action.value)) + newState.folderHits = folderHits + + return newState + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/ImagePreview.js b/FrontEnd/src/routes/SearchPage/modules/ImagePreview.js new file mode 100644 index 0000000..725fe53 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/ImagePreview.js @@ -0,0 +1,24 @@ +import { analytics } from 'utils' + +export const TOGGLE_IMAGE_PREVIEW_MODAL = 'IMAGE_PREVIEW.TOGGLE_IMAGE_PREVIEW_MODAL' + +export const toggleImagePreview = (imageUrl) => { + analytics().event('IMAGE_PREVIEW.TOGGLE_IMAGE_PREIVEW') + + return { + type: TOGGLE_IMAGE_PREVIEW_MODAL, + imageUrl + } +} + +export const ACTION_HANDLERS = { + [TOGGLE_IMAGE_PREVIEW_MODAL]: (state, action) => { + const newState = { + ...state, + isImagePreviewOpen: !state.isImagePreviewOpen, + imagePreviewUrl: action.imageUrl ? action.imageUrl : state.imagePreviewUrl + } + + return newState + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/SearchPage.js b/FrontEnd/src/routes/SearchPage/modules/SearchPage.js new file mode 100644 index 0000000..e9160d6 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/SearchPage.js @@ -0,0 +1,51 @@ +import { analytics } from 'utils' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { search, updateQuery } from 'routes/SearchPage/modules/SearchReducer' + +export const UPDATE_SCROLLED_DOWN = 'SEARCH_PAGE.UPDATE_SCROLLED_DOWN' +export const SET_SEARCH_RESULT_VIEW = 'SEARCH_PAGE.SET_SEARCH_RESULT_VIEW' + +const REQUEST_SIZE = 25 + +export const setScrolledDown = (scrolledDown) => { + return (dispatch, getState) => { + dispatch(updateScrolledDown(scrolledDown)) + } +} + +export const updateScrolledDown = (scrolledDown) => { + return { + type: UPDATE_SCROLLED_DOWN, + scrolledDown + } +} + +export const setSearchResultView = (view) => { + return { + type: SET_SEARCH_RESULT_VIEW, + view: view + } +} + +export const setQueryFromGetParam = () => { + return (dispatch, getState) => { + const query = getState().router.locationBeforeTransitions.query.query + const doSearch = getState().router.locationBeforeTransitions.query.doSearch + + const safeQuery = !query ? '' : query + + dispatch(updateQuery(safeQuery)) + dispatch(search(0, safeQuery)) + } +} + +export const ACTION_HANDLERS = { + [UPDATE_SCROLLED_DOWN]: (state, action) => { + const newState = { ...state, scrolledDown: action.scrolledDown } + return newState + }, + [SET_SEARCH_RESULT_VIEW]: (state, action) => { + const newState = { ...state, searchView: action.view } + return newState + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/SearchReducer.js b/FrontEnd/src/routes/SearchPage/modules/SearchReducer.js new file mode 100644 index 0000000..cb3dbca --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/SearchReducer.js @@ -0,0 +1,311 @@ +import { stateValueExtractor, constants, titles, analytics } from 'utils/' +import { hitsModel, folderHitsModel } from 'models/' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { startLoadingIndicator, stopLoadingIndicator } from 'routes/MainLayout/modules/MainLayout' +import * as Regexes from 'utils/regexes' + +export const FILL_HITS = 'SEARCH.FILL_HITS' +export const FILL_SEARCH_FOLDER_HITS = 'SEARCH.FILL_SEARCH_FOLDER_HITS' +export const FILL_STATS_DATA = 'SEARCH.FILL_STATS_DATA' +export const UPDATE_QUERY = 'SEARCH.UPDATE_QUERY' + +const REQUEST_SIZE = 25 + +export const performSearchByQuery = (query) => { + return (dispatch, getState) => { + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const performSearchByPathToFile = (path) => { + return (dispatch, getState) => { + let query = getState()['searchPage'].searchQuery.replace(Regexes.FILE_NAME_QUERY_REGEX, '') + path = path.replace(/\s/gim, '?') + query = `${query} filename:${path}` + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const performSearchByAuthor = (author) => { + return (dispatch, getState) => { + let query = getState()['searchPage'].searchQuery.replace(Regexes.AUTHOR_QUERY_REGEX, '') + author = author.replace(/\s/gim, '?') + query = `${query} author:${author}` + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const performSearchByTag = (tag) => { + return (dispatch, getState) => { + let query = getState()['searchPage'].searchQuery.replace(Regexes.TAGS_QUERY_REGEX, '') + query = `${query} tags:${tag}` + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const performSearchByNamedEntity = (namedEntity) => { + return (dispatch, getState) => { + let query = getState()['searchPage'].searchQuery.replace(Regexes.NAMED_ENTITIES_QUERY_REGEX, '') + query = `${query} entities:"${namedEntity}"` + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const performSearchBySize = (symbol, size) => { + return (dispatch, getState) => { + let query = getState()['searchPage'].searchQuery.replace(Regexes.SIZE_QUERY_REGEX, '') + query = `${query} size${symbol}${size}` + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const performSearchByWhen = (when) => { + return (dispatch, getState) => { + let query = getState()['searchPage'].searchQuery.replace(Regexes.WHEN_QUERY_REGEX, '') + query = `${query} when:${when}` + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const performSearchByShow = (show) => { + return (dispatch, getState) => { + let query = getState()['searchPage'].searchQuery.replace(Regexes.SHOW_QUERY_REGEX, '') + query = `${query} show:${show}` + dispatch(setQuery(query)) + dispatch(search(0, query)) + } +} + +export const setQuery = (query) => { + return (dispatch, getState) => { + dispatch(updateQuery(query)) + } +} + +export const updateQuery = (query) => { + return { + type: UPDATE_QUERY, + query + } +} + +export const search = (page, query) => { + return (dispatch, getState) => { + const fetching = getState()['global'].fetching + if (fetching) { + return + } + + changeBrowserAddressStringToQuery(query) + titles.setPageTitle(query != '' ? query : stateValueExtractor.getLocalization(getState()).searchPage.pageTitle) + + if ((!query) || (query == '')) { + dispatch(cleanUpSearchResult()) + return + } + + const searchView = getState()['searchPage'].searchView + + switch (searchView) { + case constants.FOLDER_VIEW: + dispatch(performSearchFolder(query)) + break; + case constants.STATISTICS_VIEW: + dispatch(performSearchStats(query)) + break; + default: + dispatch(performSearch(page, query)) + } + } +} + +export const cleanUpSearchResult = () => { + return (dispatch, getState) => { + dispatch(fillHits(true, new Map(), 0, '', false, 0)) + dispatch(fillSearchFolderHits([])) + } +} + +const performSearch = (page, query) => { + return (dispatch, getState) => { + + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + return new Promise((resolve) => { + dispatch(startLoadingIndicator()) + fetch(urls.ambarWebApiSearchByStringQuery(query, page, REQUEST_SIZE), { + method: 'GET', + ...defaultSettings + }) + .then((resp) => { + if (resp.status === 200) { return resp.json() } + else { throw resp } + }) + .then((data) => { + const hits = hitsModel.fromApi(data) + const hasMore = (hits.size > 0) + const clean = (page == 0) + dispatch(stopLoadingIndicator()) + dispatch(fillHits(clean, hits, data.found, query, hasMore, page)) + + if (page === 0) { analytics().event('SEARCH.PERFORM', { query: query }) } + }) + .catch((errorPayload) => { + dispatch(stopLoadingIndicator()) + dispatch(handleError(errorPayload)) + console.error('performSearch', errorPayload) + }) + }) + } +} + +export const performSearchFolder = (query) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + return new Promise((resolve) => { + dispatch(startLoadingIndicator()) + fetch(urls.ambarWebApiSearchTree(query), { + method: 'GET', + ...defaultSettings + }) + .then((resp) => { + if (resp.status === 200) { return resp.json() } + else { throw resp } + }) + .then((data) => { + dispatch(stopLoadingIndicator()) + dispatch(fillSearchFolderHits(folderHitsModel.fromApi(data))) + }) + .catch((errorPayload) => { + dispatch(stopLoadingIndicator()) + dispatch(handleError(errorPayload)) + console.error('performSearchFolder', errorPayload) + }) + }) + } +} + +export const performSearchStats = (query) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + return new Promise((resolve) => { + dispatch(startLoadingIndicator()) + fetch(urls.ambarWebApiSearchStats(query), { + method: 'GET', + ...defaultSettings + }) + .then((resp) => { + if (resp.status === 200) { return resp.json() } + else { throw resp } + }) + .then((data) => { + dispatch(stopLoadingIndicator()) + dispatch(fillStatsData(data)) + }) + .catch((errorPayload) => { + dispatch(stopLoadingIndicator()) + dispatch(handleError(errorPayload)) + console.error('performSearchStats', errorPayload) + }) + }) + } +} + +const fillStatsData = (data) => { + return { + type: FILL_STATS_DATA, + data + } +} + +const fillSearchFolderHits = (hits) => { + return { + type: FILL_SEARCH_FOLDER_HITS, + hits + } +} + +const fillHits = (clean, hits, found, searchQuery, hasMore, currentPage) => { + return { + type: FILL_HITS, + clean, + hits, + found, + searchQuery, + hasMore, + currentPage + } +} + +const changeBrowserAddressStringToQuery = (query) => { + if (history.pushState) { + var newUri = `${window.location.protocol}//${window.location.host}${window.location.pathname}?query=${encodeURIComponent(query)}`; + window.history.pushState({ path: newUri }, '', newUri); + } +} + + +const foldersTreeToMap = (node, map) => { + if (!node) { + return + } + + map.set(node.path, node.isExpanded) + node.childNodes.forEach(childNode => foldersTreeToMap(childNode, map)) +} + +const setNewExpandedValues = (node, map) => { + if (!node) { + return + } + + node.isExpanded = map.has(node.path) ? map.get(node.path) : false + node.childNodes.forEach(childNode => setNewExpandedValues(childNode, map)) +} + +export const ACTION_HANDLERS = { + [FILL_HITS]: (state, action) => { + let newState = { ...state } + if (action.clean) { + newState.hits = action.hits + } + else { + newState.hits = new Map([...state.hits, ...action.hits]) + } + newState.fetching = false + newState.hasMore = action.hasMore + newState.currentPage = action.currentPage + return newState + }, + [FILL_SEARCH_FOLDER_HITS]: (state, action) => { + if (!state.folderHits) { + return { ...state, folderHits: action.hits } + } + + const map = new Map() + state.folderHits.forEach(hit => foldersTreeToMap(hit, map)) + + const newHits = action.hits + newHits.forEach(hit => setNewExpandedValues(hit, map)) + + return { ...state, folderHits: newHits } + }, + [UPDATE_QUERY]: (state, action) => { + return ({ ...state, searchQuery: action.query }) + }, + [FILL_STATS_DATA]: (state, action) => { + return ({ ...state, stats: action.data }) + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/TagsReducer.js b/FrontEnd/src/routes/SearchPage/modules/TagsReducer.js new file mode 100644 index 0000000..a534db6 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/TagsReducer.js @@ -0,0 +1,160 @@ +import { stateValueExtractor, constants, analytics } from 'utils/' +import { hitsModel } from 'models/' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { startLoadingIndicator, stopLoadingIndicator } from 'routes/MainLayout/modules/MainLayout' + +export const SET_TAGS = 'TAGS.SET_TAGS' +export const ADD_TAG = 'TAGS.ADD_TAG' +export const REMOVE_TAG = 'TAGS.REMOVE_TAG' +export const MARK_TAG_AS_CREATED = 'TAGS.MARK_TAG_AS_CREATED' + +export const loadTags = () => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + dispatch(startLoadingIndicator()) + + fetch(urls.ambarWebApiGetAllTags(), { + method: 'GET', + ...defaultSettings + }) + .then(resp => { + if (resp.status == 200) { + return resp.json() + } + else { throw resp } + }) + .then(tags => { + dispatch(setTags(tags)) + dispatch(stopLoadingIndicator()) + }) + .catch((errorPayload) => { + dispatch(stopLoadingIndicator()) + dispatch(handleError(errorPayload)) + console.error('loadTags', errorPayload) + }) + + dispatch(stopLoadingIndicator()) + } +} + +export const addTagToFile = (fileId, tagType, tagName) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + dispatch(addTag(fileId, tagType, tagName)) + + fetch(urls.ambarWebApiAddTagToFile(fileId, tagType, tagName), { + method: 'POST', + ...defaultSettings + }) + .then(resp => { + if (resp.status == 200 || resp.status == 201) { + dispatch(markTagAsCreated(fileId, tagType, tagName)) + analytics().event('TAGS.ADD', { name: tagName }) + return resp.json() + } + else { throw resp } + }) + .then((data) => { + dispatch(setTags(data.tags)) + }) + .catch((errorPayload) => { + dispatch(handleError(errorPayload)) + console.error('addTagToFile', errorPayload) + }) + } +} + +export const removeTagFromFile = (fileId, tagType, tagName) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + dispatch(removeTag(fileId, tagType, tagName)) + + fetch(urls.ambarWebApiDeleteTagFromFile(fileId, tagType, tagName), { + method: 'DELETE', + ...defaultSettings + }) + .then(resp => { + if (resp.status == 200) { + analytics().event('TAGS.REMOVED', { name: tagName }) + return resp.json() + } + else { throw resp } + }) + .then((data) => { + dispatch(setTags(data.tags)) + }) + .catch((errorPayload) => { + dispatch(handleError(errorPayload)) + console.error('removeTagFromFile', errorPayload) + }) + } +} + +export const setTags = (tags) => { + return { + type: SET_TAGS, + tags + } +} + +const addTag = (fileId, tagType, tagName) => { + return { + type: ADD_TAG, + tagName: tagName, + tagType: tagType, + fileId: fileId + } +} + +const removeTag = (fileId, tagType, tagName) => { + return { + type: REMOVE_TAG, + tagName: tagName, + tagType: tagType, + fileId: fileId + } +} + +const markTagAsCreated = (fileId, tagType, tagName) => { + return { + type: MARK_TAG_AS_CREATED, + tagName: tagName, + tagType: tagType, + fileId: fileId + } +} + +export const ACTION_HANDLERS = { + [SET_TAGS]: (state, action) => { + return ({ ...state, tags: action.tags }) + }, + [ADD_TAG]: (state, action) => { + const oldHit = hitsModel.getHit(state, action.fileId) + const hit = { ...oldHit, tags: [...oldHit.tags, { name: action.tagName, type: action.tagType, isFetching: true }] } + return hitsModel.updateHits(state, action.fileId, hit) + }, + [REMOVE_TAG]: (state, action) => { + const oldHit = hitsModel.getHit(state, action.fileId) + const hit = { ...oldHit, tags: [...oldHit.tags.filter(t => !((t.name === action.tagName) && (t.type === action.tagType)))] } + return hitsModel.updateHits(state, action.fileId, hit) + }, + [MARK_TAG_AS_CREATED]: (state, action) => { + const oldHit = hitsModel.getHit(state, action.fileId) + const hit = { ...oldHit } + hit.tags = hit.tags.map(tag => { + if ((tag.name === action.tagName) && (tag.type === action.tagType)) { + tag.isFetching = false + } + + return tag + }) + + return hitsModel.updateHits(state, action.fileId, hit) + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/UploadModal.js b/FrontEnd/src/routes/SearchPage/modules/UploadModal.js new file mode 100644 index 0000000..fb57759 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/UploadModal.js @@ -0,0 +1,115 @@ +import { stateValueExtractor } from 'utils/' +import { analytics, FormDataPolyfill } from 'utils' +import { handleError, showInfo } from 'routes/CoreLayout/modules/CoreLayout' +import 'whatwg-fetch' + +export const TOGGLE_UPLOAD_MODAL = 'SEARCH_UPLOAD_MODAL.TOGGLE_UPLOAD_MODAL' +export const ADD_FILES_TO_UPLOAD = 'SEARCH_UPLOAD_MODAL.ADD_FILES_TO_UPLOAD' +export const REMOVE_FILE_TO_UPLOAD = 'SEARCH_UPLOAD_MODAL.REMOVE_FILE_TO_UPLOAD' +export const FILES_UPLOADING = 'SEARCH_UPLOAD_MODAL.FILES_UPLOADING' +export const CLEAN_FILES_TO_UPLOAD = 'SEARCH_UPLOAD_MODAL.CLEAN_FILES_TO_UPLOAD' + +export const uploadFiles = () => { + return (dispatch, getState) => { + dispatch(filesUploading(true)) + + const urls = stateValueExtractor.getUrls(getState()) + + const { filesToUpload } = getState()['searchPage'] + + const uploadPromises = filesToUpload.map(file => new Promise((resolve, reject) => { + const form = new FormDataPolyfill() + form.set(file.name, file, file.name) + + fetch(urls.ambarWebApiPostFile(file.name), { + method: 'POST', + body: form._asNative(), + mode: 'cors', + credentials: 'include' + }).then((resp) => { + if (resp.status >= 400) { + throw resp + } + else { resolve() } + }) + .catch((errorPayload) => reject(errorPayload)) + })) + + Promise.all(uploadPromises) + .then((values) => { + dispatch(filesUploading(false)) + dispatch(toggleUploadModal()) + dispatch(cleanFilesToUpload()) + dispatch(showInfo('Files succesfully uploaded')) + analytics().event('SEARCH.UPLOAD_FILES', { count: uploadPromises.length }) + }) + .catch((errorPayload) => { + dispatch(filesUploading(false)) + + if (errorPayload.status === 507) { + dispatch(handleError('No free space left in your account', true)) + } else { + dispatch(handleError(errorPayload)) + analytics().event('SEARCH.UPLOAD_FILES_ERROR', { error: errorPayload }) + } + + console.error('uploadFile', errorPayload) + }) + } +} + +export const toggleUploadModal = () => { + return { + type: TOGGLE_UPLOAD_MODAL + } +} + +export const addFilesToUpload = (files) => { + return { + type: ADD_FILES_TO_UPLOAD, + files: files + } +} + +export const removeFileToUpload = (file) => { + return { + type: REMOVE_FILE_TO_UPLOAD, + file: file + } +} + +export const filesUploading = (isUploading) => { + return { + type: FILES_UPLOADING, + isUploading: isUploading + } +} + +export const cleanFilesToUpload = () => { + return { + type: CLEAN_FILES_TO_UPLOAD + } +} + +export const ACTION_HANDLERS = { + [TOGGLE_UPLOAD_MODAL]: (state, action) => { + const newState = { ...state, isUploadModalOpen: !state.isUploadModalOpen } + return newState + }, + [ADD_FILES_TO_UPLOAD]: (state, action) => { + const newState = { ...state, filesToUpload: [...state.filesToUpload, ...action.files] } + return newState + }, + [REMOVE_FILE_TO_UPLOAD]: (state, action) => { + const newState = { ...state, filesToUpload: state.filesToUpload.filter(f => f !== action.file) } + return newState + }, + [FILES_UPLOADING]: (state, action) => { + const newState = { ...state, isFilesUploading: action.isUploading } + return newState + }, + [CLEAN_FILES_TO_UPLOAD]: (state, action) => { + const newState = { ...state, filesToUpload: [] } + return newState + } +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SearchPage/modules/index.js b/FrontEnd/src/routes/SearchPage/modules/index.js new file mode 100644 index 0000000..2d3c4c0 --- /dev/null +++ b/FrontEnd/src/routes/SearchPage/modules/index.js @@ -0,0 +1,42 @@ +import { constants } from 'utils' +import { ACTION_HANDLERS as DetailedViewActions } from './DetailedView' +import { ACTION_HANDLERS as SearchPageActions } from './SearchPage' +import { ACTION_HANDLERS as UploadModalActions } from './UploadModal' +import { ACTION_HANDLERS as FolderViewActions } from './FolderView' +import { ACTION_HANDLERS as ImagePreviewActions } from './ImagePreview' +import { ACTION_HANDLERS as TagsReducerActions } from './TagsReducer' +import { ACTION_HANDLERS as FileVisibilityActions } from './FileVisibilityReducer' +import { ACTION_HANDLERS as SearchActions } from './SearchReducer' + +const initialState = { + searchQuery: '', + currentPage: 0, + hits: new Map(), + hasMore: false, + scrolledDown: false, + isUploadModalOpen: false, + filesToUpload: [], + isFilesUploading: false, + isImagePreviewOpen: false, + imagePreviewUrl: '', + searchView: constants.DETAILED_VIEW, + tags: [], + folderHits: [], + stats: null +} + +export default function reducer(state = initialState, action) { + const ACTION_HANDLERS = { + ...DetailedViewActions, + ...SearchPageActions, + ...UploadModalActions, + ...FolderViewActions, + ...ImagePreviewActions, + ...TagsReducerActions, + ...FileVisibilityActions, + ...SearchActions + } + + let handler = ACTION_HANDLERS[action.type] + return handler ? handler(state, action) : state +} \ No newline at end of file diff --git a/FrontEnd/src/routes/SettingsPage/containers/SettingsPageContainer.js b/FrontEnd/src/routes/SettingsPage/containers/SettingsPageContainer.js new file mode 100644 index 0000000..d21f3ef --- /dev/null +++ b/FrontEnd/src/routes/SettingsPage/containers/SettingsPageContainer.js @@ -0,0 +1,23 @@ +import { connect } from 'react-redux' +import { stateValueExtractor } from 'utils/' +import { + loadPipelineLog, + setSettingsModalOpen, +} from '../modules/SettingsPage' + +import Settings from 'components/Settings' + +const mapDispatchToProps = { + loadPipelineLog, + setSettingsModalOpen, +} + +const mapStateToProps = (state) => { + return ({ + fetching: state['global'].fetching, + pipeline: state['settingsPage'].pipeline, + localization: stateValueExtractor.getLocalization(state) + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(Settings) \ No newline at end of file diff --git a/FrontEnd/src/routes/SettingsPage/index.js b/FrontEnd/src/routes/SettingsPage/index.js new file mode 100644 index 0000000..0eeace1 --- /dev/null +++ b/FrontEnd/src/routes/SettingsPage/index.js @@ -0,0 +1,13 @@ +import { injectReducer } from '../../store/reducers' + +export default (store) => ({ + path: 'settings', + getComponent (nextState, cb) { + require.ensure([], (require) => { + const settingsPage = require('./containers/SettingsPageContainer').default + const reducer = require('./modules/SettingsPage').default + injectReducer(store, { key: 'settingsPage', reducer }) + cb(null, settingsPage) + }, 'settingsPage') + } +}) \ No newline at end of file diff --git a/FrontEnd/src/routes/SettingsPage/modules/SettingsPage.js b/FrontEnd/src/routes/SettingsPage/modules/SettingsPage.js new file mode 100644 index 0000000..36bd5ba --- /dev/null +++ b/FrontEnd/src/routes/SettingsPage/modules/SettingsPage.js @@ -0,0 +1,89 @@ +import { stateValueExtractor } from 'utils/' +import { crawlersModel } from 'models/' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { startLoadingIndicator, stopLoadingIndicator } from 'routes/MainLayout/modules/MainLayout' +import 'whatwg-fetch' + +const UPDATE_CRAWLER = 'SETTINGS.UPDATE_CRAWLER' +const FILL_CRAWLERS = 'SETTINGS.FILL_CRAWLERS' +const UPDATE_NEW_CRAWLER = 'SETTINGS.UPDATE_NEW_CRAWLER' +const UPDATE_PIPELINE = 'SETTINGS.UPDATE_PIPELINE' + +const REQUEST_SIZE = 10 +const PIPELINE_LOG_SIZE = 30 + + +export const loadPipelineLog = (pipeline) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + dispatch(stopLoadingIndicator()) + + fetch(urls.ambarWebApiGetLogs(PIPELINE_LOG_SIZE), { + method: 'GET', + ...defaultSettings + }) + .then((resp) => { + if (resp.status == 200) { return resp.json() } + else { throw resp } + }) + .then((data) => { + dispatch(updatePipeline({ ...pipeline, log: { records: data } })) + }) + .catch((errorPayload) => { + dispatch(updatePipeline({ ...pipeline, log: { ...pipeline.log } })) + console.error('loadPipelineLog', errorPayload) + }) + } +} + + +const fillCrawlers = (crawlers) => { + return { + type: FILL_CRAWLERS, + crawlers + } +} + +const updateCrawler = (crawler) => { + return { + type: UPDATE_CRAWLER, + crawler + } +} + +const updatePipeline = (pipeline) => { + return { + type: UPDATE_PIPELINE, + pipeline + } +} + + +const ACTION_HANDLERS = { + [FILL_CRAWLERS]: (state, action) => { + let newState = { ...state } + newState.crawlers = action.crawlers + return newState + }, + [UPDATE_CRAWLER]: (state, action) => { + let newState = { ...state } + newState.crawlers = new Map(state.crawlers) + newState.crawlers.set(action.crawler.settings.id, action.crawler) + return newState + }, + [UPDATE_PIPELINE]: (state, action) => { + return { ...state, pipeline: action.pipeline } + } +} + +const initialState = { + crawlers: new Map(), + pipeline: { log: { records: [] } } +} + +export default function settingsPageReducer(state = initialState, action) { + const handler = ACTION_HANDLERS[action.type] + return handler ? handler(state, action) : state +} \ No newline at end of file diff --git a/FrontEnd/src/routes/StatisticsPage/containers/StatisticsPageContainer.js b/FrontEnd/src/routes/StatisticsPage/containers/StatisticsPageContainer.js new file mode 100644 index 0000000..91187cd --- /dev/null +++ b/FrontEnd/src/routes/StatisticsPage/containers/StatisticsPageContainer.js @@ -0,0 +1,18 @@ +import { connect } from 'react-redux' +import { loadStatistics } from '../modules/StatisticsPage' +import { stateValueExtractor } from 'utils/' +import Statistics from 'components/Statistics' + +const mapDispatchToProps = { + loadStatistics +} + +const mapStateToProps = (state) => { + return ({ + fetching: state['statisticsPage'].fetching, + data: state['statisticsPage'].data, + localization: stateValueExtractor.getLocalization(state) + }) +} + +export default connect(mapStateToProps, mapDispatchToProps)(Statistics) \ No newline at end of file diff --git a/FrontEnd/src/routes/StatisticsPage/index.js b/FrontEnd/src/routes/StatisticsPage/index.js new file mode 100644 index 0000000..4f86b3e --- /dev/null +++ b/FrontEnd/src/routes/StatisticsPage/index.js @@ -0,0 +1,13 @@ +import { injectReducer } from '../../store/reducers' + +export default (store) => ({ + path: 'statistics', + getComponent (nextState, cb) { + require.ensure([], (require) => { + const statisticsPage = require('./containers/StatisticsPageContainer').default + const reducer = require('./modules/StatisticsPage').default + injectReducer(store, { key: 'statisticsPage', reducer }) + cb(null, statisticsPage) + }, 'statisticsPage') + } +}) \ No newline at end of file diff --git a/FrontEnd/src/routes/StatisticsPage/modules/StatisticsPage.js b/FrontEnd/src/routes/StatisticsPage/modules/StatisticsPage.js new file mode 100644 index 0000000..8991bc1 --- /dev/null +++ b/FrontEnd/src/routes/StatisticsPage/modules/StatisticsPage.js @@ -0,0 +1,73 @@ +import { stateValueExtractor, errors } from 'utils' +import { handleError } from 'routes/CoreLayout/modules/CoreLayout' +import { startLoadingIndicator, stopLoadingIndicator } from 'routes/MainLayout/modules/MainLayout' +import 'whatwg-fetch' + +export const START_STOP_LOADING = 'STAT.START_STOP_LOADING' +export const SET_STATISTICS = 'STAT.SET_STATISTICS' + +export const loadStatistics = (page, query) => { + return (dispatch, getState) => { + const urls = stateValueExtractor.getUrls(getState()) + const defaultSettings = stateValueExtractor.getDefaultSettings(getState()) + + return new Promise((resolve) => { + dispatch(startLoadingIndicator()) + dispatch(startStopLoadingIndicator(true)) + + fetch(urls.ambarWebApiGetStats(), { + method: 'GET', + ...defaultSettings + }) + .then((resp) => { + if (resp.status == 200) { return resp.json() } + else { throw resp } + }) + .then((data) => { + dispatch(setStatistics(data)) + dispatch(stopLoadingIndicator()) + dispatch(startStopLoadingIndicator(false)) + }) + .catch((errorPayload) => { + dispatch(stopLoadingIndicator()) + dispatch(startStopLoadingIndicator(false)) + dispatch(handleError(errorPayload)) + console.error('loadStatistics', errorPayload) + }) + }) + + } +} + +const setStatistics = (data) => { + return { + type: SET_STATISTICS, + data + } +} + +const startStopLoadingIndicator = (fetching) => { + return { + type: START_STOP_LOADING, + fetching + } +} + +const ACTION_HANDLERS = { + [START_STOP_LOADING]: (state, action) => { + return { ...state, fetching: action.fetching } + }, + [SET_STATISTICS]: (state, action) => { + return { ...state, data: action.data } + } +} + +const initialState = { + data: {}, + fetching: true +} + +export default function statisticsPageReducer(state = initialState, action) { + const handler = ACTION_HANDLERS[action.type] + return handler ? handler(state, action) : state +} \ No newline at end of file diff --git a/FrontEnd/src/routes/index.js b/FrontEnd/src/routes/index.js new file mode 100644 index 0000000..ffc432d --- /dev/null +++ b/FrontEnd/src/routes/index.js @@ -0,0 +1,23 @@ +import MainLayout from './MainLayout' +import CoreLayout from './CoreLayout' + +import SearchPage from './SearchPage' +import SettingsPage from './SettingsPage' +import StatisticsPage from './StatisticsPage' + +export const createRoutes = (store) => ({ + path: '/', + component: CoreLayout(store), + childRoutes: [ + { + component: MainLayout(store), + indexRoute: SearchPage(store), + childRoutes: [ + SettingsPage(store), + StatisticsPage(store) + ] + } + ] +}) + +export default createRoutes diff --git a/FrontEnd/src/static/ambar-blue.svg b/FrontEnd/src/static/ambar-blue.svg new file mode 100644 index 0000000..d269eb8 --- /dev/null +++ b/FrontEnd/src/static/ambar-blue.svg @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/FrontEnd/src/static/ambar-logo-full.svg b/FrontEnd/src/static/ambar-logo-full.svg new file mode 100644 index 0000000..dde80ca --- /dev/null +++ b/FrontEnd/src/static/ambar-logo-full.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/static/ambar.svg b/FrontEnd/src/static/ambar.svg new file mode 100644 index 0000000..1905315 --- /dev/null +++ b/FrontEnd/src/static/ambar.svg @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/FrontEnd/src/static/android-chrome-192x192.png b/FrontEnd/src/static/android-chrome-192x192.png new file mode 100644 index 0000000..dbcc92c Binary files /dev/null and b/FrontEnd/src/static/android-chrome-192x192.png differ diff --git a/FrontEnd/src/static/android-chrome-384x384.png b/FrontEnd/src/static/android-chrome-384x384.png new file mode 100644 index 0000000..2554f1a Binary files /dev/null and b/FrontEnd/src/static/android-chrome-384x384.png differ diff --git a/FrontEnd/src/static/animated-owl.gif b/FrontEnd/src/static/animated-owl.gif new file mode 100644 index 0000000..e20d80f Binary files /dev/null and b/FrontEnd/src/static/animated-owl.gif differ diff --git a/FrontEnd/src/static/apiUrl.txt b/FrontEnd/src/static/apiUrl.txt new file mode 100644 index 0000000..28719b1 --- /dev/null +++ b/FrontEnd/src/static/apiUrl.txt @@ -0,0 +1 @@ +http://ambar:8080 \ No newline at end of file diff --git a/FrontEnd/src/static/apple-touch-icon-114x114.png b/FrontEnd/src/static/apple-touch-icon-114x114.png new file mode 100644 index 0000000..2e9f0ed Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-114x114.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-120x120.png b/FrontEnd/src/static/apple-touch-icon-120x120.png new file mode 100644 index 0000000..9e9ff89 Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-120x120.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-144x144.png b/FrontEnd/src/static/apple-touch-icon-144x144.png new file mode 100644 index 0000000..154d8eb Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-144x144.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-152x152.png b/FrontEnd/src/static/apple-touch-icon-152x152.png new file mode 100644 index 0000000..6c07976 Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-152x152.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-180x180.png b/FrontEnd/src/static/apple-touch-icon-180x180.png new file mode 100644 index 0000000..f828c0b Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-180x180.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-57x57.png b/FrontEnd/src/static/apple-touch-icon-57x57.png new file mode 100644 index 0000000..f54d3b9 Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-57x57.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-60x60.png b/FrontEnd/src/static/apple-touch-icon-60x60.png new file mode 100644 index 0000000..26106f0 Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-60x60.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-72x72.png b/FrontEnd/src/static/apple-touch-icon-72x72.png new file mode 100644 index 0000000..ba8aac9 Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-72x72.png differ diff --git a/FrontEnd/src/static/apple-touch-icon-76x76.png b/FrontEnd/src/static/apple-touch-icon-76x76.png new file mode 100644 index 0000000..044cb8e Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon-76x76.png differ diff --git a/FrontEnd/src/static/apple-touch-icon.png b/FrontEnd/src/static/apple-touch-icon.png new file mode 100644 index 0000000..f828c0b Binary files /dev/null and b/FrontEnd/src/static/apple-touch-icon.png differ diff --git a/FrontEnd/src/static/browserconfig.xml b/FrontEnd/src/static/browserconfig.xml new file mode 100644 index 0000000..5aecc91 --- /dev/null +++ b/FrontEnd/src/static/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #00aba9 + + + diff --git a/FrontEnd/src/static/dropbox.svg b/FrontEnd/src/static/dropbox.svg new file mode 100644 index 0000000..60ff613 --- /dev/null +++ b/FrontEnd/src/static/dropbox.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/static/favicon-16x16.png b/FrontEnd/src/static/favicon-16x16.png new file mode 100644 index 0000000..8dd2e2e Binary files /dev/null and b/FrontEnd/src/static/favicon-16x16.png differ diff --git a/FrontEnd/src/static/favicon-32x32.png b/FrontEnd/src/static/favicon-32x32.png new file mode 100644 index 0000000..81bb745 Binary files /dev/null and b/FrontEnd/src/static/favicon-32x32.png differ diff --git a/FrontEnd/src/static/favicon.ico b/FrontEnd/src/static/favicon.ico new file mode 100644 index 0000000..70895e5 Binary files /dev/null and b/FrontEnd/src/static/favicon.ico differ diff --git a/FrontEnd/src/static/humans.txt b/FrontEnd/src/static/humans.txt new file mode 100644 index 0000000..5a6f627 --- /dev/null +++ b/FrontEnd/src/static/humans.txt @@ -0,0 +1 @@ +# RD17 TEAM \ No newline at end of file diff --git a/FrontEnd/src/static/localizations.json b/FrontEnd/src/static/localizations.json new file mode 100644 index 0000000..3c89fc9 --- /dev/null +++ b/FrontEnd/src/static/localizations.json @@ -0,0 +1,376 @@ +{ + "en": { + "searchPage": { + "uploadLabel": "Upload Files", + "viewLabel": "View", + "detailedViewLabel": "Detailed", + "tableViewLabel": "Table", + "tagsLabel": "Tags", + "timeRangeLabel": "Time Range", + "trashLabel": "Trash", + "removedFilesLabel": "Removed Files", + "clearQueryLabel": "Clear Query", + "todayLabel": "Today", + "yesterdayLabel": "Yesterday", + "thisWeekLabel": "This Week", + "thisMonthLabel": "This Month", + "thisYearLabel": "This Year", + "lastModifiedLabel": "Last modified", + "byLabel": "by", + "downloadLabel": "Download", + "downloadDescriptionLabel": "Download File", + "previewLabel": "Preview", + "previewDescriptionLabel": "Text Preview", + "removeLabel": "Remove", + "removeDescriptionLabel": "Remove File", + "restoreLabel": "Restore", + "restoreDescriptionLabel": "Restore File", + "imagePreviewLabel": "Image Preview", + "fileNameLabel": "File Name", + "fileSizeLabel": "Size", + "authorLabel": "Author", + "actionsLabel": "Actions", + "nothingFoundLabel": "Nothing Found", + "nothingFoundDescriptionLabel": "search query, did not match any documents", + "searchTipsLabel": "Few tips for search", + "searchTipsDescriptionLabel": "Just type your query in search input above and hit \"Enter\"", + "refineTipsLabel": "Try these tips to refine your search", + "allFilesQueryLabel": "show all files", + "simpleQueryLabel": "search for both \"John\" and \"Smith\" words in file content and meta", + "pharseQueryLabel": "search for \"John Smith\" phrase in file content and meta", + "pharseQueryWithDistanceLabel": "search for both \"John\" and \"Smith\" words with maximum distance of 10 words in file content and meta", + "fuzzyQueryLabel": "fuzzy search for word \"John\" in all files with maximum of 3 replacements", + "filenameQueryLabel": "search for \".txt\" in file fullname", + "sizeQueryLabel": "search for all files larger than 1 MB (options: M for MegaBytes, K for KiloBytes)", + "whenQueryLabel": "search for all files modified today (options: today, yesterday, thisweek, thismonth, thisyear)", + "authorQueryLabel": "search only in file author field", + "tagsQueryLabel": "search for files tagged with ocr and ui-upload tag", + "entitiesQueryLabel": "search for files containing \"hello@ambar.cloud\" named entity", + "removedQueryLabel": "search in removed files (options: removed, all)", + "haveQuestionsLabel": "Have any questions?", + "dropMessageLabel": "Drop us a message", + "pageTitle": "Search", + "searchInputHintLabel": "Type query here and hit \"Enter\"", + "folderViewLabel": "Folders", + "expandAllLabel": "Expand All", + "collapseAllLabel": "Collapse All", + "performSearchByFolderLabel": "Search folder", + "statsSummaryLabel": "Summary", + "statsFilesCountLabel": "Files Found", + "statsAverageFileSizeLabel": "Avg. File Size", + "statsMaximumFileSizeLabel": "Max. File Size", + "statsMinimumFileSizeLabel": "Min. File Size", + "namedEntitiesLabel": "Named Entities", + "statsExtensionsTypesLabel": "Extensions", + "statisticsViewLabel": "Statistics" + }, + "uploadModal": { + "cancelLabel": "Cancel", + "uploadLabel": "Upload", + "titleLabel": "Upload Files", + "hintLabel": "Drop some files here" + }, + "mainMenu": { + "searchLabel": "Search", + "settingsLabel": "Logs", + "statisticsLabel": "Statistics", + "accountLabel": "Account", + "logOutLabel": "Log Out" + }, + "statisticsPage": { + "pageTitle": "Statistics", + "summaryLabel": "Summary", + "filesCountLabel": "Files in search index", + "averageFileSizeLabel": "Average file size", + "maximumFileSizeLabel": "Maximum file size", + "contentTypesLabel": "Content Types", + "processingRateLabel": "Processing Rate", + "emptyStatisticsLabel": "No files - No statistics", + "emptyStatisticsDescriptionLabel": "Oops, your Ambar is empty... Upload files manually on Search Page or create crawler on Settings Page" + }, + "settingsPage": { + "pageTitle": "Logs", + "noCrawlersLabel": "No crawlers", + "noCrawlersDescriptionLabel": "No crawlers defined yet...", + "noCrawlersHintLabel": "Use \"Plus\" button to create your first crawler", + "closeLabel": "Close", + "cancelLabel": "Cancel", + "createLabel": "Create", + "deleteLabel": "Delete", + "saveLabel": "Save", + "editCrawlerModalTitleLabel": "Crawler Settings", + "pipelineLabel": "Logs", + "pipelineDescriptionLabel": "Pipeline & Crawlers logs", + "crawlerLabel": "Crawler", + "crawlerSettingsLabel": "Settings", + "crawlerStopLabel": "Stop", + "crawlerStartLabel": "Start", + "crawlerUndefinedStateLabel": "Undefined", + "crawlerIdleStateLabel": "Idle", + "crawlerRunningStateLabel": "Running" + }, + "accountPage": { + "pageTitle": "Account", + "cancelLabel": "Cancel", + "deleteLabel": "Delete", + "informationLabel": "Information", + "nameLabel": "Name", + "emailLabel": "E-mail", + "planLabel": "Plan", + "uploadedLabel": "Uploaded", + "langAnalyzerLabel": "Language Analyzer", + "logOutLabel": "Log Out", + "accountDeletionLabel": "Delete Account", + "accountDeletionModalTitle": "Are you sure?", + "accountDeletionWarnLabel": "Your Ambar account and all your data will be deleted. Nobody, even Ambar support team will not be able to recover it. Click \"DELETE\" button to delete your Ambar account forever.", + "changePasswordLabel": "Change Password", + "oldPasswordLabel": "Old Password", + "newPasswordLabel": "New Password", + "newPasswordConfirmationLabel": "Confirm New Password", + "performPasswordChangeLabel": "Change Password", + "passwordChangedLabel": "Password successfully changed", + "fieldRequiredLabel": "Field is required", + "weakPasswordLabel": "Password is too weak", + "differentPasswordsLabel": "Passwords are not equal", + "addDigitsLabel": "Add at least one digit [0-9]", + "addLowerCaseCharLabel":"Add at least one lower-case char [a-z]", + "addUpperCaseCharLabel": "Add at least one upper-case char [A-Z]", + "tooShortPasswordLabel": "Password should be at least 8 characters long" + }, + "loginPage": { + "pageTitle": "Ambar | Login", + "loginLabel": "Login", + "emailLabel": "E-mail", + "passwordLabel": "Password", + "performLoginLabel": "Login", + "forgotPasswordLabel": "Forgot password?", + "signupLabel": "Sign Up", + "emailRequiredLabel": "E-mail is requried", + "passwordRequiredLabel": "Password is requried" + }, + "resetPasswordPage": { + "pageTitle": "Reset Password", + "emailLabel": "Your Account Email", + "resetLabel": "Reset", + "emailRequiredLabel": "E-mail is required", + "emailAddressInvalidLabel": "E-mail address is invalid" + }, + "signupPage": { + "pageTitle": "Sign Up", + "emailLabel": "E-mail", + "nameLabel": "Name", + "langAnalyzerLabel": "Language Analyzer", + "performSignupLabel": "Sing Up", + "haveAccountLabel": "Already have an account?", + "nameRequiredLabel": "Name is required", + "emailRequiredLabel": "E-mail is required", + "emailAddressInvalidLabel": "E-mail address is invalid" + }, + "checkEmailPage": { + "pageTitle": "Check Your Inbox", + "hintLabel": "Hedwig is on its way! The message will be delivered very soon" + }, + "setPasswordPage": { + "pageTitle": "Set Password", + "emailLabel": "E-mail", + "passwordLabel": "Password", + "passwordConfirmationLabel": "Password Confirmation", + "setPasswordLabel": "Submit", + "brokenLinkLabel": "Your link is broken or expired. Please, request another one", + "passwordRequiredLabel": "Password is required", + "passwordWeakLabel": "Password is too weak", + "diffPasswordsLabel": "Passwords are not equal", + "addDigitsLabel": "Add at least one digit [0-9]", + "addLowerCaseCharLabel":"Add at least one lower-case char [a-z]", + "addUpperCaseCharLabel": "Add at least one upper-case char [A-Z]", + "tooShortPasswordLabel": "Password should be at least 8 characters long" + } + }, + "ru": { + "searchPage": { + "uploadLabel": "Загрузить", + "viewLabel": "Вид", + "detailedViewLabel": "Детальный", + "tableViewLabel": "Таблица", + "tagsLabel": "Теги", + "timeRangeLabel": "Период", + "trashLabel": "Корзина", + "removedFilesLabel": "Удаленные", + "clearQueryLabel": "Очистить запрос", + "todayLabel": "Сегодня", + "yesterdayLabel": "Вчера", + "thisWeekLabel": "Эта неделя", + "thisMonthLabel": "Этот месяц", + "thisYearLabel": "Этот год", + "lastModifiedLabel": "Изменен", + "byLabel": "от", + "downloadLabel": "Скачать", + "downloadDescriptionLabel": "Скачать файл", + "previewLabel": "Просмотр", + "previewDescriptionLabel": "Просмотр текста", + "removeLabel": "Удалить", + "removeDescriptionLabel": "Удалить файл", + "restoreLabel": "Восстановить", + "restoreDescriptionLabel": "Восстановить файл", + "imagePreviewLabel": "Просмотр изображения", + "fileNameLabel": "Имя файла", + "fileSizeLabel": "Размер", + "authorLabel": "Автор", + "actionsLabel": "Действия", + "nothingFoundLabel": "Ничего не найдено", + "nothingFoundDescriptionLabel": "по этому запросу ничего не нашлось", + "searchTipsLabel": "Советы по составлению запроса", + "searchTipsDescriptionLabel": "Введите запрос в поле поиска и нажмите клавишу \"Enter\"", + "refineTipsLabel": "Используйте эти команды для уточнения поискового запроса", + "allFilesQueryLabel": "показать все файлы", + "simpleQueryLabel": "поиск слов \"John\" и \"Smith\" в содержимом и мета-данных файла", + "pharseQueryLabel": "поиск фразы \"John Smith\" в содержимом и мета-данных файла", + "pharseQueryWithDistanceLabel": "поиск слов \"John\" и \"Smith\" в содержимом и мета-данных файла с максимальным расстоянием 10 слов друг от друга", + "fuzzyQueryLabel": "нечеткий поиск слова \"John\" с максимум 3-мя изменениями в содержимом и мета-данных файла", + "filenameQueryLabel": "поиск \".txt\" в полном пути к файлу", + "sizeQueryLabel": "поиск файлов с размером более 1 МБ (возможные значения: M для МегаБайт, K для КилоБайт)", + "whenQueryLabel": "поиск файлов измененных сегодня (возможные значения: today, yesterday, thisweek, thismonth, thisyear)", + "authorQueryLabel": "поиск в поле автор файла", + "tagsQueryLabel": "поиск файлов с тегами ocr и ui-upload", + "entitiesQueryLabel": "поиск файлов содержащих в себе именнованную сущность \"hello@ambar.cloud\"", + "removedQueryLabel": "поиск в удаленных файлах (возможные значения: removed, all)", + "haveQuestionsLabel": "Остались вопросы?", + "dropMessageLabel": "Напишите нам", + "pageTitle": "Поиск", + "searchInputHintLabel": "Введите запрос и нажмите клавишу \"Enter\"", + "folderViewLabel": "Папки", + "expandAllLabel": "Раскрыть все", + "collapseAllLabel": "Свернуть все", + "performSearchByFolderLabel": "Поиск в папке", + "statsSummaryLabel": "Общие сведения", + "statsFilesCountLabel": "Найдено файлов", + "statsAverageFileSizeLabel": "Средний размер файла", + "statsMaximumFileSizeLabel": "Максимальный размер файла", + "statsMinimumFileSizeLabel": "Минимальный размер файла", + "namedEntitiesLabel": "Именованные сущности", + "statsExtensionsTypesLabel": "Расширения", + "statisticsViewLabel": "Статистика" + }, + "uploadModal": { + "cancelLabel": "Отмена", + "uploadLabel": "Загрузить", + "titleLabel": "Загрузить файлы", + "hintLabel": "Переместите файлы сюда" + }, + "mainMenu": { + "searchLabel": "Поиск", + "settingsLabel": "Логи", + "statisticsLabel": "Статистика", + "accountLabel": "Профиль", + "logOutLabel": "Выйти" + }, + "statisticsPage": { + "pageTitle": "Статистика", + "summaryLabel": "Общие сведения", + "filesCountLabel": "Количество файлов в поисковом индексе", + "averageFileSizeLabel": "Средний размер файла", + "maximumFileSizeLabel": "Максимальный размер файла", + "contentTypesLabel": "Типы файлов", + "processingRateLabel": "Скорость обработки", + "emptyStatisticsLabel": "Какая статистика без файлов?", + "emptyStatisticsDescriptionLabel": "Упс, похоже в Ambar нет ни одного файла... Загрузите файлы самостоятельно на странице поиска или создайте краулер на странице настроек" + }, + "settingsPage": { + "pageTitle": "Логи", + "noCrawlersLabel": "Нет краулеров", + "noCrawlersDescriptionLabel": "Пока не создан ни один краулер", + "noCrawlersHintLabel": "Нажмите кнопку \"Плюс\" чтобы создать краулер", + "closeLabel": "Закрыть", + "cancelLabel": "Отмена", + "createLabel": "Создать", + "deleteLabel": "Удалить", + "saveLabel": "Сохранить", + "editCrawlerModalTitleLabel": "Настройка краулера", + "pipelineLabel": "Логи", + "pipelineDescriptionLabel": "Логи краулеров и обработчика файлов", + "crawlerLabel": "Краулер", + "crawlerSettingsLabel": "Настройки", + "crawlerStopLabel": "Стоп", + "crawlerStartLabel": "Старт", + "crawlerUndefinedStateLabel": "Неопределен", + "crawlerIdleStateLabel": "Простаивает", + "crawlerRunningStateLabel": "Работает" + }, + "accountPage": { + "pageTitle": "Профиль", + "cancelLabel": "Отмена", + "deleteLabel": "Удалить", + "informationLabel": "Информация", + "nameLabel": "Ник", + "emailLabel": "Эл. почта", + "planLabel": "План", + "uploadedLabel": "Загружено", + "langAnalyzerLabel": "Морфология", + "logOutLabel": "Выйти", + "accountDeletionLabel": "Удалить профиль", + "accountDeletionModalTitle": "Вы уверены?", + "accountDeletionWarnLabel": "Ваш профиль и все данные в Ambar будет удалены безвозвратно. Нажмите кнопку \"УДАЛИТЬ\" если вы осознаете что делаете.", + "changePasswordLabel": "Изменение пароля", + "oldPasswordLabel": "Старый пароль", + "newPasswordLabel": "Новый пароль", + "newPasswordConfirmationLabel": "Подтверждение пароля", + "performPasswordChangeLabel": "Изменить пароль", + "passwordChangedLabel": "Пароль успешно изменен", + "fieldRequiredLabel": "Обязательное поле", + "weakPasswordLabel": "Слишком простой пароль", + "differentPasswordsLabel": "Пароли не совпадают", + "addDigitsLabel": "Добавьте по крайней мере одну цифру [0-9]", + "addLowerCaseCharLabel":"Добавьте по крайней мере один символ нижнего регистра [a-z]", + "addUpperCaseCharLabel": "Добавьте по крайней мере один символ верхнего регистра [A-Z]", + "tooShortPasswordLabel": "Длина пароля должна быть не менее 8 символов" + }, + "loginPage": { + "pageTitle": "Ambar | Вход", + "loginLabel": "Вход", + "emailLabel": "Эл. почта", + "passwordLabel": "Пароль", + "performLoginLabel": "Войти", + "forgotPasswordLabel": "Забыли пароль?", + "signupLabel": "Зарегистрироваться", + "emailRequiredLabel": "Укажите эл. почту", + "passwordRequiredLabel": "Пароль обязателен" + }, + "resetPasswordPage": { + "pageTitle": "Восстнановление пароля", + "emailLabel": "Ваша эл. почта", + "resetLabel": "Восстановить", + "emailRequiredLabel": "Укажите эл. почту", + "emailAddressInvalidLabel": "Неправильный адрес эл. почты" + }, + "signupPage": { + "pageTitle": "Регистрация", + "emailLabel": "Эл. почта", + "nameLabel": "Ник", + "langAnalyzerLabel": "Морфология", + "performSignupLabel": "Зарегистрировать", + "haveAccountLabel": "Уже зарегистрированы?", + "nameRequiredLabel": "Укажите ник", + "emailRequiredLabel": "Укажите эл. почту", + "emailAddressInvalidLabel": "Неправильный адрес эл. почты" + }, + "checkEmailPage": { + "pageTitle": "Проверьте ваш почтовый ящик", + "hintLabel": "Букля уже в пути! Сообщение очень скоро будет у вас..." + }, + "setPasswordPage": { + "pageTitle": "Создание пароля", + "emailLabel": "Эл. почта", + "passwordLabel": "Пароль", + "passwordConfirmationLabel": "Подтверждение пароля", + "setPasswordLabel": "Установить", + "brokenLinkLabel": "Ваша ссылка не валидна или просрочена. Пожалуйста, запросите сссылку повторно", + "passwordRequiredLabel": "Пароль обязателен", + "passwordWeakLabel": "Слишком простой пароль", + "diffPasswordsLabel": "Пароли не совпадают", + "addDigitsLabel": "Добавьте по крайней мере одну цифру [0-9]", + "addLowerCaseCharLabel":"Добавьте по крайней мере один символ нижнего регистра [a-z]", + "addUpperCaseCharLabel": "Добавьте по крайней мере один символ верхнего регистра [A-Z]", + "tooShortPasswordLabel": "Длина пароля должна быть не менее 8 символов" + } + } +} \ No newline at end of file diff --git a/FrontEnd/src/static/manifest.json b/FrontEnd/src/static/manifest.json new file mode 100644 index 0000000..23a4ac0 --- /dev/null +++ b/FrontEnd/src/static/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Ambar", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/FrontEnd/src/static/mstile-150x150.png b/FrontEnd/src/static/mstile-150x150.png new file mode 100644 index 0000000..6e3ad11 Binary files /dev/null and b/FrontEnd/src/static/mstile-150x150.png differ diff --git a/FrontEnd/src/static/owl-blue.svg b/FrontEnd/src/static/owl-blue.svg new file mode 100644 index 0000000..a8d49f5 --- /dev/null +++ b/FrontEnd/src/static/owl-blue.svg @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/static/owl-green.svg b/FrontEnd/src/static/owl-green.svg new file mode 100644 index 0000000..a8d49f5 --- /dev/null +++ b/FrontEnd/src/static/owl-green.svg @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/static/owl.svg b/FrontEnd/src/static/owl.svg new file mode 100644 index 0000000..f0ab929 --- /dev/null +++ b/FrontEnd/src/static/owl.svg @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/static/post-owl.jpeg b/FrontEnd/src/static/post-owl.jpeg new file mode 100644 index 0000000..7baf6a6 Binary files /dev/null and b/FrontEnd/src/static/post-owl.jpeg differ diff --git a/FrontEnd/src/static/rate-us-owl.gif b/FrontEnd/src/static/rate-us-owl.gif new file mode 100644 index 0000000..02be73d Binary files /dev/null and b/FrontEnd/src/static/rate-us-owl.gif differ diff --git a/FrontEnd/src/static/robots.txt b/FrontEnd/src/static/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/FrontEnd/src/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/FrontEnd/src/static/safari-pinned-tab.svg b/FrontEnd/src/static/safari-pinned-tab.svg new file mode 100644 index 0000000..a6896c0 --- /dev/null +++ b/FrontEnd/src/static/safari-pinned-tab.svg @@ -0,0 +1,38 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + + + diff --git a/FrontEnd/src/static/stamp-icon.png b/FrontEnd/src/static/stamp-icon.png new file mode 100644 index 0000000..420ac41 Binary files /dev/null and b/FrontEnd/src/static/stamp-icon.png differ diff --git a/FrontEnd/src/static/web.config b/FrontEnd/src/static/web.config new file mode 100644 index 0000000..3deb05e --- /dev/null +++ b/FrontEnd/src/static/web.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FrontEnd/src/store/createStore.js b/FrontEnd/src/store/createStore.js new file mode 100644 index 0000000..666076b --- /dev/null +++ b/FrontEnd/src/store/createStore.js @@ -0,0 +1,44 @@ +import { applyMiddleware, compose, createStore } from 'redux' +import { routerMiddleware } from 'react-router-redux' +import thunk from 'redux-thunk' +import makeRootReducer from './reducers' + +export default (initialState = {}, history) => { + // ====================================================== + // Middleware Configuration + // ====================================================== + const middleware = [thunk, routerMiddleware(history)] + + // ====================================================== + // Store Enhancers + // ====================================================== + const enhancers = [] + if (__DEBUG__) { + const devToolsExtension = window.devToolsExtension + if (typeof devToolsExtension === 'function') { + enhancers.push(devToolsExtension()) + } + } + + // ====================================================== + // Store Instantiation and HMR Setup + // ====================================================== + const store = createStore( + makeRootReducer(), + initialState, + compose( + applyMiddleware(...middleware), + ...enhancers + ) + ) + store.asyncReducers = {} + + if (module.hot) { + module.hot.accept('./reducers', () => { + const reducers = require('./reducers').default + store.replaceReducer(reducers(store.asyncReducers)) + }) + } + + return store +} diff --git a/FrontEnd/src/store/reducers.js b/FrontEnd/src/store/reducers.js new file mode 100644 index 0000000..3162282 --- /dev/null +++ b/FrontEnd/src/store/reducers.js @@ -0,0 +1,17 @@ +import { combineReducers } from 'redux' +import { routerReducer as router } from 'react-router-redux' + +export const makeRootReducer = (asyncReducers) => { + return combineReducers({ + // Add sync reducers here + router, + ...asyncReducers + }) +} + +export const injectReducer = (store, { key, reducer }) => { + store.asyncReducers[key] = reducer + store.replaceReducer(makeRootReducer(store.asyncReducers)) +} + +export default makeRootReducer diff --git a/FrontEnd/src/styles/core.scss b/FrontEnd/src/styles/core.scss new file mode 100644 index 0000000..635161e --- /dev/null +++ b/FrontEnd/src/styles/core.scss @@ -0,0 +1,22 @@ + +:global { + + // Some best-practice CSS that's useful for most apps + // Just remove them if they're not what you want + html { + box-sizing: border-box; + } + + html, + body { + margin: 0; + padding: 0; + height: 100%; + } + + *, + *:before, + *:after { + box-sizing: inherit; + } +} diff --git a/FrontEnd/src/utils/analytics.js b/FrontEnd/src/utils/analytics.js new file mode 100644 index 0000000..769be12 --- /dev/null +++ b/FrontEnd/src/utils/analytics.js @@ -0,0 +1,43 @@ +const safeCall = (func) => { + try { + func() + } catch (e) { + console.warn('Analytics error', e) + } +} + +const mixpanelAnalytics = { + event: (name, data) => safeCall(() => mixpanel.track(name, data)), + register: (data) => safeCall(() => mixpanel.register(data)), + userSet: (data) => safeCall(() => mixpanel.people.set(data)), + userIncrement: (key) => safeCall(() => mixpanel.people.increment(key, 1)), + alias: (newId) => safeCall(() => mixpanel.alias(newId)), + identify: (id) => safeCall(() => mixpanel.identify(id)), + reset: () => safeCall(() => mixpanel.reset()) +} + +const dummyAnalytics = { + event: (name, data) => {}, + register: (data) => { }, + userSet: (data) => { }, + userIncrement: (key) => { }, + alias: (newId) => { }, + identify: (id) => { }, + reset: () => { } +} + +let analytics = dummyAnalytics + +export default (token = null) => { + if (token && token != '') { + mixpanel.init(token) + analytics = mixpanelAnalytics + } + + return analytics +} + + + + + diff --git a/FrontEnd/src/utils/constants.js b/FrontEnd/src/utils/constants.js new file mode 100644 index 0000000..6fdf0d4 --- /dev/null +++ b/FrontEnd/src/utils/constants.js @@ -0,0 +1,5 @@ +export const errorMessage = 'Oops... Something went wrong. Please reload the page' +export const FOLDER_VIEW = 'FOLDER_VIEW' +export const DETAILED_VIEW = 'DETAILED_VIEW' +export const TABLE_VIEW = 'TABLE_VIEW' +export const STATISTICS_VIEW = 'STATISTICS_VIEW' \ No newline at end of file diff --git a/FrontEnd/src/utils/dates.js b/FrontEnd/src/utils/dates.js new file mode 100644 index 0000000..3af3e8a --- /dev/null +++ b/FrontEnd/src/utils/dates.js @@ -0,0 +1,34 @@ +import moment from 'moment' + +export const DateFormat = 'DD.MM.YYYY' +export const DateTimeFormat = 'DD.MM.YYYY HH:mm' + +export const pad = (num, size) => { + const s = "00" + num + return s.substr(s.length - size) +} + +export const toDate = (day, month, year) => { + let res = ''; + + if (day) + res += pad(day, 2) + '.' + + if (month) + res += pad(month, 2) + '.' + + if (year) + res += year + + return res +} + +export const dateToInts = (date) => { + const momentDate = moment(date, DateFormat) + + return { + d: momentDate.date(), + m: momentDate.month() + 1, //because motnhs are ZERO indexed + y: momentDate.year() + } +} \ No newline at end of file diff --git a/FrontEnd/src/utils/dom.js b/FrontEnd/src/utils/dom.js new file mode 100644 index 0000000..81cb232 --- /dev/null +++ b/FrontEnd/src/utils/dom.js @@ -0,0 +1,21 @@ +export const scrollToClass = (className) => { + const elems = document.getElementsByClassName(className) + + if (elems.length > 0) + elems[0].scrollIntoView(false) +} + +export const tryScrollToClass = (className) => { + setTimeout(() => scrollToClass(className), 500) +} + +export const focusClass = (className) => { + const elems = document.getElementsByClassName(className) + + if (elems.length > 0) + elems[0].focus() //Hacky, but can not find any other solution +} + +export const tryFocusClass = (className) => { + setTimeout(() => focusClass(className), 500) +} \ No newline at end of file diff --git a/FrontEnd/src/utils/files.js b/FrontEnd/src/utils/files.js new file mode 100644 index 0000000..cc928f8 --- /dev/null +++ b/FrontEnd/src/utils/files.js @@ -0,0 +1,61 @@ +import { postAttachedFilesUrl } from './urls' +import 'whatwg-fetch' + +export const bytesToMegaBytes = (bytesCount) => { + return bytesCount / (1024 * 1024) +} + +export const fileSizeIsNotTooLarge = (fileSize) => { + const maxFileSize = 3 //MB + return bytesToMegaBytes(fileSize) > maxFileSize +} + +export const getFileSize = (file) => { + if (file && file[0]) { + return file[0].size + } + + return null +} + +export const fileIsTooLarge = (file) => { + const size = getFileSize(file) + + if (size == null) + return false + + return fileSizeIsNotTooLarge(size) +} + +export const formatFileSize = (sizeInBytes) => { + const sizeInKBytes = sizeInBytes / 1024 + + if (sizeInKBytes < 1) { + return `${sizeInBytes} bytes` + } + + const sizeInMBytes = sizeInKBytes / 1024 + if (sizeInMBytes < 1) { + return `${sizeInKBytes.toFixed(2)} KB` + } + + const sizeInGbytes = sizeInMBytes / 1024 + if (sizeInGbytes < 1) { + return `${sizeInMBytes.toFixed(2)} MB` + } + + return `${sizeInGbytes.toFixed(2)} GB` +} + +export const getExtension = (meta) => { + let extension = (typeof meta.extension !== 'string') && meta.extension.length && meta.extension.length > 0 + ? meta.extension[0] + : meta.extension + return extension ? extension.replace('.', '').toLowerCase() : '' +} + +export const doesFileContainText = (meta) => { + const extension = getExtension(meta) + const EXCLUDED_EXTENSIONS = ['zip'] // extensions that doesn't contain text + return EXCLUDED_EXTENSIONS.indexOf(extension) == -1 +} diff --git a/FrontEnd/src/utils/formDataPolyfill.js b/FrontEnd/src/utils/formDataPolyfill.js new file mode 100644 index 0000000..3cd674c --- /dev/null +++ b/FrontEnd/src/utils/formDataPolyfill.js @@ -0,0 +1,289 @@ +const map = new WeakMap +const wm = (o) => map.get(o) + +function normalizeValue([value, filename]) { + if (value instanceof Blob) + value = new File([value], filename, { + type: value.type, + lastModified: value.lastModified + }) + + return value +} + +function stringify(name) { + if (!arguments.length) + throw new TypeError('1 argument required, but only 0 present.') + + return [name + ''] +} + +function normalizeArgs(name, value, filename) { + if (arguments.length < 2) + throw new TypeError(`2 arguments required, but only ${arguments.length} present.`) + + return value instanceof Blob + ? [name + '', value, filename !== undefined + ? filename + '' + : value[Symbol.toStringTag] === 'File' + ? value.name + : 'Blob'] + : [name + '', value + ''] +} + +/** + * @implements {Iterable} + */ +class FormDataPolyfill { + + /** + * FormData class + * + * @param {HTMLElement=} form + */ + constructor(form) { + map.set(this, Object.create(null)) + + if (!form) + return this + + for (let {name, type, value, files, checked, selectedOptions} of Array.from(form.elements)) { + if(!name) continue + + if (type === 'file') + for (let file of files) + this.append(name, file) + else if (type === 'select-multiple' || type === 'select-one') + for (let elm of selectedOptions) + this.append(name, elm.value) + else if (type === 'checkbox') + if (checked) this.append(name, value) + else + this.append(name, value) + } + } + + + /** + * Append a field + * + * @param {String} name field name + * @param {String|Blob|File} value string / blob / file + * @param {String=} filename filename to use with blob + * @return {Undefined} + */ + append(name, value, filename) { + let map = wm(this) + + if (!map[name]) + map[name] = [] + + map[name].push([value, filename]) + } + + + /** + * Delete all fields values given name + * + * @param {String} name Field name + * @return {Undefined} + */ + delete(name) { + delete wm(this)[name] + } + + + /** + * Iterate over all fields as [name, value] + * + * @return {Iterator} + */ + *entries() { + let map = wm(this) + + for (let name in map) + for (let value of map[name]) + yield [name, normalizeValue(value)] + } + + /** + * Iterate over all fields + * + * @param {Function} callback Executed for each item with parameters (value, name, thisArg) + * @param {Object=} thisArg `this` context for callback function + * @return {Undefined} + */ + forEach(callback, thisArg) { + for (let [name, value] of this) + callback.call(thisArg, value, name, this) + } + + + /** + * Return first field value given name + * + * @param {String} name Field name + * @return {String|File} value Fields value + */ + get(name) { + let map = wm(this) + return map[name] ? normalizeValue(map[name][0]) : null + } + + + /** + * Return all fields values given name + * + * @param {String} name Fields name + * @return {Array} [value, value] + */ + getAll(name) { + return (wm(this)[name] || []).map(normalizeValue) + } + + + /** + * Check for field name existence + * + * @param {String} name Field name + * @return {boolean} + */ + has(name) { + return name in wm(this) + } + + + /** + * Iterate over all fields name + * + * @return {Iterator} + */ + *keys() { + for (let [name] of this) + yield name + } + + + /** + * Overwrite all values given name + * + * @param {String} name Filed name + * @param {String} value Field value + * @param {String=} filename Filename (optional) + * @return {Undefined} + */ + set(name, value, filename) { + wm(this)[name] = [[value, filename]] + } + + + /** + * Iterate over all fields + * + * @return {Iterator} + */ + *values() { + for (let [name, value] of this) + yield value + } + + + /** + * Non standard but it has been proposed: https://github.com/w3c/FileAPI/issues/40 + * + * @return {ReadableStream} + */ + stream() { + try { + return this._blob().stream() + } catch(e) { + throw new Error('Include https://github.com/jimmywarting/Screw-FileReader for streaming support') + } + } + + + /** + * Return a native (perhaps degraded) FormData with only a `append` method + * Can throw if it's not supported + * + * @return {FormData} + */ + _asNative() { + let fd = new FormData + + for (let [name, value] of this) + fd.append(name, value) + + return fd + } + + + /** + * [_blob description] + * + * @return {Blob} [description] + */ + _blob() { + var boundary = '----formdata-polyfill-' + Math.random() + var chunks = [] + + for (let [name, value] of this) { + chunks.push(`--${boundary}\r\n`) + + if (value[Symbol.toStringTag] === 'File') { + chunks.push( + `Content-Disposition: form-data; name="${name}"; filename="${value.name}"\r\n`, + `Content-Type: ${value.type}\r\n\r\n`, + value, + '\r\n' + ) + } else { + chunks.push( + `Content-Disposition: form-data; name="${name}"\r\n\r\n${value}\r\n` + ) + } + } + + chunks.push(`--${boundary}--`) + + return new Blob(chunks, {type: 'multipart/form-data; boundary=' + boundary}) + } + + + /** + * The class itself is iterable + * alias for formdata.entries() + * + * @return {Iterator} + */ + [Symbol.iterator]() { + return this.entries() + } + + + /** + * Create the default string description. + * It is accessed internally by the Object.prototype.toString(). + * + * @return {String} FormData + */ + get [Symbol.toStringTag]() { + return 'FormData' + } +} + +for (let [method, overide] of [ + ['append', normalizeArgs], + ['delete', stringify], + ['get', stringify], + ['getAll', stringify], + ['has', stringify], + ['set', normalizeArgs] +]) { + let orig = FormDataPolyfill.prototype[method] + FormDataPolyfill.prototype[method] = function() { + return orig.apply(this, overide(...arguments)) + } +} + +export default FormDataPolyfill \ No newline at end of file diff --git a/FrontEnd/src/utils/index.js b/FrontEnd/src/utils/index.js new file mode 100644 index 0000000..f91e054 --- /dev/null +++ b/FrontEnd/src/utils/index.js @@ -0,0 +1,12 @@ +import * as validators from './validators' +import urls from './urls' +import * as dates from './dates' +import * as files from './files' +import * as dom from './dom' +import * as stateValueExtractor from './stateValueExtractor' +import * as titles from './titles' +import * as constants from './constants' +import FormDataPolyfill from './formDataPolyfill' +import analytics from './analytics' + +export { validators, urls, dates, files, dom, stateValueExtractor, titles, constants, analytics, FormDataPolyfill } \ No newline at end of file diff --git a/FrontEnd/src/utils/regexes.js b/FrontEnd/src/utils/regexes.js new file mode 100644 index 0000000..80d918b --- /dev/null +++ b/FrontEnd/src/utils/regexes.js @@ -0,0 +1,7 @@ + +export const SIZE_QUERY_REGEX = /((^|\s)size(<|>)[=]{0,1})([0-9]*)([k|m]{0,1})/im +export const WHEN_QUERY_REGEX = /((^|\s)when:)((today)|(yesterday)|(thisweek)|(thismonth)|(thisyear))/im +export const SHOW_QUERY_REGEX = /((^|\s)show:)((removed)|(all))/im +export const FILE_NAME_QUERY_REGEX = /((^|\s)filename:)([^\s]*)/im +export const AUTHOR_QUERY_REGEX = /((^|\s)author:)([^\s]*)/im +export const TAGS_QUERY_REGEX = /((^|\s)tags:)([a-zA-Z0-9\-\_\,\*]*)/im diff --git a/FrontEnd/src/utils/stateValueExtractor.js b/FrontEnd/src/utils/stateValueExtractor.js new file mode 100644 index 0000000..ae9a130 --- /dev/null +++ b/FrontEnd/src/utils/stateValueExtractor.js @@ -0,0 +1,22 @@ +import urls from './urls.js' + +export const getUrls = (state) => state['core'].urls +export const getLocalization = (state) => { + const lang = state['core'].lang + const defaultLang = 'en' + + return state['core'].localizations[lang] + ? state['core'].localizations[lang] + : state['core'].localizations[defaultLang] +} + +export const getDefaultSettings = () => { + return { + mode: 'cors', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + } + } +} \ No newline at end of file diff --git a/FrontEnd/src/utils/titles.js b/FrontEnd/src/utils/titles.js new file mode 100644 index 0000000..d3a64f9 --- /dev/null +++ b/FrontEnd/src/utils/titles.js @@ -0,0 +1,7 @@ +import analytics from './analytics' + +export const setPageTitle = (title) => { + document.title = title + analytics().register({ title: title }) + analytics().event('LOCATION_CHANGED') + } \ No newline at end of file diff --git a/FrontEnd/src/utils/urls.js b/FrontEnd/src/utils/urls.js new file mode 100644 index 0000000..29c81dc --- /dev/null +++ b/FrontEnd/src/utils/urls.js @@ -0,0 +1,56 @@ +const init = (apiHost) => { + + return { + apiHost: apiHost, + ambarWebApiSearchByStringQuery: (query, page, size) => `${apiHost}/api/search?query=${encodeURIComponent(query)}&page=${page}&size=${size}`, + ambarWebApiLoadContentHightlight: (fileId, query) => `${apiHost}/api/search/${fileId}/?query=${encodeURIComponent(query)}`, + ambarWebApiLoadFullContentHightlight: (fileId, query) => `${apiHost}/api/search/${fileId}/full?query=${encodeURIComponent(query)}`, + ambarWebApiGetFile: (metaId) => `${apiHost}/api/files/${metaId}`, + ambarWebApiGetFileText: (metaId) => `${apiHost}/api/files/${metaId}/text`, + + ambarWebApiGetCrawlers: () => `${apiHost}/api/crawlers`, + ambarWebApiGetCrawler: (crawlerId) => `${apiHost}/api/crawlers/${crawlerId}`, + ambarWebApiStartStopCrawler: (crawlerId, startStopCommand) => `${apiHost}/api/crawlers/${crawlerId}/${startStopCommand}`, + ambarWebApiGetLogs: (recordsCount) => `${apiHost}/api/logs/?recordsCount=${recordsCount}`, + + ambarWebApiGetStats: () => `${apiHost}/api/stats`, + ambarWebApiGetInfo: () => `${apiHost}/api/`, + ambarWebApiGetSources: () => `${apiHost}/api/sources`, + ambarWebApiPostFile: (fileName) => `${apiHost}/api/files/uiupload/${fileName}`, + ambarWebApiGetThumbnail: (sha) => `${apiHost}/api/thumbs/${sha}`, + + ambarWebApiUserInfo: () => `${apiHost}/api/users`, + + ambarWebApiAddTagToFile: (fileId, tagType, tagName) => `${apiHost}/api/tags/${fileId}/${tagType}/${tagName}`, + ambarWebApiDeleteTagFromFile: (fileId, tagType, tagName) => `${apiHost}/api/tags/${fileId}/${tagType}/${tagName}`, + ambarWebApiGetAllTags: () => `${apiHost}/api/tags`, + + ambarWebApiHideFile: (fileId) => `${apiHost}/api/files/hide/${fileId}`, + ambarWebApiUnhideFile: (fileId) => `${apiHost}/api/files/unhide/${fileId}`, + + ambarWebApiSearchTree: (query) => `${apiHost}/api/search/tree?query=${query}`, + ambarWebApiSearchStats: (query) => `${apiHost}/api/search/stats?query=${query}`, + + getParamsFromQuery: (query) => { + if (!query) { + return {}; + } + + return (/^[?#]/.test(query) ? query.slice(1) : query) + .split('&') + .reduce((params, param) => { + let [key, value] = param.split('='); + params[key] = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : ''; + return params; + }, {}) + } + } +} + +export default (apiHost) => { + if (!apiHost) { + throw new Error('Can not initialize config. ApiHost is undefined') + } + + return init(apiHost) +} diff --git a/FrontEnd/src/utils/validators.js b/FrontEnd/src/utils/validators.js new file mode 100644 index 0000000..cb210a3 --- /dev/null +++ b/FrontEnd/src/utils/validators.js @@ -0,0 +1,32 @@ +const MIN_PASSWORD_LENGTH = 8 + +export const isValidEmail = (email) => { + const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + + return re.test(email) +} + +export const isStrongPassword = (password) => { + const re = /^(?=(.*[A-Z])+)(?=(.*[0-9])+)(?=(.*[a-z])+).{8,}$/ + + return re.test(password) +} + +export const doesPasswordHaveMinLength = (password) => { + return password.length >= MIN_PASSWORD_LENGTH +} + +export const doesPasswordHaveOneUpperChar = (password) => { + const upperCaseChar = /[A-Z]/ + return upperCaseChar.test(password) +} + +export const doesPasswordHaveOneLowerChar = (password) => { + const lowCaseChar = /[a-z]/ + return lowCaseChar.test(password) +} + +export const doesPasswordHaveOneDigit = (password) => { + const digitRe = /\d/ + return digitRe.test(password) +} \ No newline at end of file diff --git a/FrontEnd/yarn.lock b/FrontEnd/yarn.lock new file mode 100644 index 0000000..740d4a4 --- /dev/null +++ b/FrontEnd/yarn.lock @@ -0,0 +1,5530 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@blueprintjs/core@^1.32.0": + version "1.32.0" + resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-1.32.0.tgz#49a3659124f63054d50adb864eb4505a6a99099b" + dependencies: + "@types/dom4" "^1.5.20" + "@types/tether" "^1.1.27" + classnames "^2.2" + dom4 "^1.8" + normalize.css "4.1.1" + pure-render-decorator "^1.1" + tether "^1.4" + tslib "^1.5.0" + +"@types/dom4@^1.5.20": + version "1.5.20" + resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-1.5.20.tgz#ccf636d3b794fe65a4191ebc7ff979a78efea6c2" + +"@types/tether@^1.1.27": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@types/tether/-/tether-1.4.3.tgz#bbcb46a35dfbeeaaf60d60afaba3d872b6e1ebf5" + +Base64@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028" + +abbrev@1, abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@^1.2.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-jsx@^3.0.0, acorn-jsx@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.0, acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.3.tgz#1a3e850b428e73ba6b09d1cc527f5aaad4d03ef1" + +ajv-keywords@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.2.0.tgz#676c4f087bfe1e8b12dca6fda2f3c74f417b099c" + +ajv@^4.7.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.9.1.tgz#08e1b0a5fddc8b844d28ca7b03510e78812ee3a0" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-html@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.6.tgz#bda8e33dd2ee1c20f54c08eb405713cbfc0ed80e" + +ansi-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" + +any-promise@^1.0.0, any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-index@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + dependencies: + debug "^2.2.0" + es6-symbol "^3.0.2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@~2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + +async@1.x, async@^1.3.0, async@^1.4.0, async@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + +async@^2.0.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" + dependencies: + lodash "^4.14.0" + +async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +attr-accept@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.0.tgz#b5cd35227f163935a8f1de10ed3eba16941f6be6" + +autoprefixer@^6.3.1: + version "6.5.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.5.3.tgz#2d853af66d04449fcf50db3066279ab54c3e4b01" + dependencies: + browserslist "~1.4.0" + caniuse-db "^1.0.30000578" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.5" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-cli@^6.5.1: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.18.0.tgz#92117f341add9dead90f6fa7d0a97c0cc08ec186" + dependencies: + babel-core "^6.18.0" + babel-polyfill "^6.16.0" + babel-register "^6.18.0" + babel-runtime "^6.9.0" + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.0.0" + glob "^5.0.5" + lodash "^4.2.0" + output-file-sync "^1.1.0" + path-is-absolute "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + v8flags "^2.0.10" + optionalDependencies: + chokidar "^1.0.0" + +babel-code-frame@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^2.0.0" + +babel-core@^6.1.4, babel-core@^6.18.0, babel-core@^6.3.17: + version "6.18.2" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.18.2.tgz#d8bb14dd6986fa4f3566a26ceda3964fa0e04e5b" + dependencies: + babel-code-frame "^6.16.0" + babel-generator "^6.18.0" + babel-helpers "^6.16.0" + babel-messages "^6.8.0" + babel-register "^6.18.0" + babel-runtime "^6.9.1" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-eslint@^6.0.0-beta.6: + version "6.1.2" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-6.1.2.tgz#5293419fe3672d66598d327da9694567ba6a5f2f" + dependencies: + babel-traverse "^6.0.20" + babel-types "^6.0.19" + babylon "^6.0.18" + lodash.assign "^4.0.0" + lodash.pickby "^4.0.0" + +babel-generator@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.19.0.tgz#9b2f244204777a3d6810ec127c673c87b349fac5" + dependencies: + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-bindify-decorators@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.18.0.tgz#fc00c573676a6e702fffa00019580892ec8780a5" + dependencies: + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-builder-binary-assignment-operator-visitor@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.18.0.tgz#8ae814989f7a53682152e3401a04fabd0bb333a6" + dependencies: + babel-helper-explode-assignable-expression "^6.18.0" + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-builder-react-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.18.0.tgz#ab02f19a2eb7ace936dd87fa55896d02be59bf71" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.18.0" + esutils "^2.0.0" + lodash "^4.2.0" + +babel-helper-call-delegate@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.18.0.tgz#05b14aafa430884b034097ef29e9f067ea4133bd" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-define-map@^6.18.0, babel-helper-define-map@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.18.0.tgz#8d6c85dc7fbb4c19be3de40474d18e97c3676ec2" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.18.0.tgz#14b8e8c2d03ad735d4b20f1840b24cd1f65239fe" + dependencies: + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-explode-class@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.18.0.tgz#c44f76f4fa23b9c5d607cbac5d4115e7a76f62cb" + dependencies: + babel-helper-bindify-decorators "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6" + dependencies: + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-get-function-arity@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-hoist-variables@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.18.0.tgz#a835b5ab8b46d6de9babefae4d98ea41e866b82a" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-optimise-call-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.18.0.tgz#9261d0299ee1a4f08a6dd28b7b7c777348fd8f0f" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-regex@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.18.0.tgz#ae0ebfd77de86cb2f1af258e2cc20b5fe893ecc6" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.16.0, babel-helper-remap-async-to-generator@^6.16.2: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.18.0.tgz#336cdf3cab650bb191b02fc16a3708e7be7f9ce5" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.18.0.tgz#28ec69877be4144dbd64f4cc3a337e89f29a924e" + dependencies: + babel-helper-optimise-call-expression "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helpers@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3" + dependencies: + babel-runtime "^6.0.0" + babel-template "^6.16.0" + +babel-loader@^6.2.0: + version "6.2.8" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.8.tgz#30d7183aef60afc140b36443676b7acb4c12ac9c" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.11" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-check-es2015-constants@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz#dbf024c32ed37bfda8dee1e76da02386a8d26fe7" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-do-expressions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0, babel-plugin-syntax-flow@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-function-bind@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46" + +babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.3.13: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.13.0.tgz#2b84b7d53dd744f94ff1fad7669406274b23f541" + +babel-plugin-transform-async-generator-functions@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.17.0.tgz#d0b5a2b2f0940f2b245fa20a00519ed7bc6cae54" + dependencies: + babel-helper-remap-async-to-generator "^6.16.2" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-async-to-generator@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz#19ec36cb1486b59f9f468adfa42ce13908ca2999" + dependencies: + babel-helper-remap-async-to-generator "^6.16.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-class-constructor-call@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.18.0.tgz#80855e38a1ab47b8c6c647f8ea1bcd2c00ca3aae" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-class-properties@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.19.0.tgz#1274b349abaadc835164e2004f4a2444a2788d5f" + dependencies: + babel-helper-function-name "^6.18.0" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.9.1" + babel-template "^6.15.0" + +babel-plugin-transform-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.13.0.tgz#82d65c1470ae83e2d13eebecb0a1c2476d62da9d" + dependencies: + babel-helper-define-map "^6.8.0" + babel-helper-explode-class "^6.8.0" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-types "^6.13.0" + +babel-plugin-transform-do-expressions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.8.0.tgz#fda692af339835cc255bb7544efb8f7c1306c273" + dependencies: + babel-plugin-syntax-do-expressions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-arrow-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz#ed95d629c4b5a71ae29682b998f70d9833eb366d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoping@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.18.0.tgz#3bfdcfec318d46df22525cdea88f1978813653af" + dependencies: + babel-runtime "^6.9.0" + babel-template "^6.15.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.18.0.tgz#ffe7a17321bf83e494dcda0ae3fc72df48ffd1d9" + dependencies: + babel-helper-define-map "^6.18.0" + babel-helper-function-name "^6.18.0" + babel-helper-optimise-call-expression "^6.18.0" + babel-helper-replace-supers "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-template "^6.14.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-computed-properties@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz#f51010fd61b3bd7b6b60a5fdfd307bb7a5279870" + dependencies: + babel-helper-define-map "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-destructuring@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533" + dependencies: + babel-runtime "^6.9.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz#fd8f7f7171fc108cc1c70c3164b9f15a81c25f7d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-for-of@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.18.0.tgz#4c517504db64bf8cfc119a6b8f177211f2028a70" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-function-name@^6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz#8c135b17dbd064e5bba56ec511baaee2fca82719" + dependencies: + babel-helper-function-name "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.9.0" + +babel-plugin-transform-es2015-literals@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz#50aa2e5c7958fc2ab25d74ec117e0cc98f046468" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-modules-amd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.18.0.tgz#49a054cbb762bdf9ae2d8a807076cfade6141e40" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.18.0.tgz#c15ae5bb11b32a0abdcc98a5837baa4ee8d67bcc" + dependencies: + babel-plugin-transform-strict-mode "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.19.0.tgz#50438136eba74527efa00a5b0fefaf1dc4071da6" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.11.6" + babel-template "^6.14.0" + +babel-plugin-transform-es2015-modules-umd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.18.0.tgz#23351770ece5c1f8e83ed67cb1d7992884491e50" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-object-super@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz#1b858740a5a4400887c23dcff6f4d56eea4a24c5" + dependencies: + babel-helper-replace-supers "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-parameters@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.18.0.tgz#9b2cfe238c549f1635ba27fc1daa858be70608b1" + dependencies: + babel-helper-call-delegate "^6.18.0" + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.9.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.18.0.tgz#e2ede3b7df47bf980151926534d1dd0cbea58f43" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-spread@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz#0217f737e3b821fa5a669f187c6ed59205f05e9c" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-sticky-regex@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz#e73d300a440a35d5c64f5c2a344dc236e3df47be" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-template-literals@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz#86eb876d0a2c635da4ec048b4f7de9dfc897e66b" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.18.0.tgz#0b14c48629c90ff47a0650077f6aa699bee35798" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-unicode-regex@^6.3.13: + version "6.11.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz#6298ceabaad88d50a3f4f392d8de997260f6ef2c" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.8.0.tgz#db25742e9339eade676ca9acec46f955599a68a4" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.8.0" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-export-extensions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.8.0.tgz#fa80ff655b636549431bfd38f6b817bd82e47f5b" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-flow-strip-types@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.18.0.tgz#4d3e642158661e9b40db457c004a30817fa32592" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-function-bind@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.8.0.tgz#e7f334ce69f50d28fe850a822eaaab9fa4f4d821" + dependencies: + babel-plugin-syntax-function-bind "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-object-rest-spread@^6.16.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.19.0.tgz#f6ac428ee3cb4c6aa00943ed1422ce813603b34c" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-react-display-name@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.8.0.tgz#f7a084977383d728bdbdc2835bba0159577f660e" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-react-jsx-self@^6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.11.0.tgz#605c9450c1429f97a930f7e1dfe3f0d9d0dbd0f4" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.9.0" + +babel-plugin-transform-react-jsx-source@^6.3.13: + version "6.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.9.0.tgz#af684a05c2067a86e0957d4f343295ccf5dccf00" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.9.0" + +babel-plugin-transform-react-jsx@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.8.0.tgz#94759942f70af18c617189aa7f3593f1644a71ab" + dependencies: + babel-helper-builder-react-jsx "^6.8.0" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-regenerator@^6.16.0: + version "6.16.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.16.1.tgz#a75de6b048a14154aae14b0122756c5bed392f59" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.16.0" + private "~0.1.5" + +babel-plugin-transform-runtime@^6.3.13: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.15.0.tgz#3d75b4d949ad81af157570273846fb59aeb0d57c" + dependencies: + babel-runtime "^6.9.0" + +babel-plugin-transform-strict-mode@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.18.0.tgz#df7cf2991fe046f44163dcd110d5ca43bc652b9d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-polyfill@^6.16.0, babel-polyfill@^6.9.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422" + dependencies: + babel-runtime "^6.9.1" + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-preset-es2015-loose@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015-loose/-/babel-preset-es2015-loose-7.0.0.tgz#fd80c85d3b20cbf309bd0ce30a36380c5784bf06" + dependencies: + modify-babel-preset "^1.0.0" + +babel-preset-es2015@^6.14.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.18.0.tgz#b8c70df84ec948c43dcf2bf770e988eb7da88312" + dependencies: + babel-plugin-check-es2015-constants "^6.3.13" + babel-plugin-transform-es2015-arrow-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoped-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoping "^6.18.0" + babel-plugin-transform-es2015-classes "^6.18.0" + babel-plugin-transform-es2015-computed-properties "^6.3.13" + babel-plugin-transform-es2015-destructuring "^6.18.0" + babel-plugin-transform-es2015-duplicate-keys "^6.6.0" + babel-plugin-transform-es2015-for-of "^6.18.0" + babel-plugin-transform-es2015-function-name "^6.9.0" + babel-plugin-transform-es2015-literals "^6.3.13" + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-plugin-transform-es2015-modules-systemjs "^6.18.0" + babel-plugin-transform-es2015-modules-umd "^6.18.0" + babel-plugin-transform-es2015-object-super "^6.3.13" + babel-plugin-transform-es2015-parameters "^6.18.0" + babel-plugin-transform-es2015-shorthand-properties "^6.18.0" + babel-plugin-transform-es2015-spread "^6.3.13" + babel-plugin-transform-es2015-sticky-regex "^6.3.13" + babel-plugin-transform-es2015-template-literals "^6.6.0" + babel-plugin-transform-es2015-typeof-symbol "^6.18.0" + babel-plugin-transform-es2015-unicode-regex "^6.3.13" + babel-plugin-transform-regenerator "^6.16.0" + +babel-preset-react@^6.3.13: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.16.0.tgz#aa117d60de0928607e343c4828906e4661824316" + dependencies: + babel-plugin-syntax-flow "^6.3.13" + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-flow-strip-types "^6.3.13" + babel-plugin-transform-react-display-name "^6.3.13" + babel-plugin-transform-react-jsx "^6.3.13" + babel-plugin-transform-react-jsx-self "^6.11.0" + babel-plugin-transform-react-jsx-source "^6.3.13" + +babel-preset-stage-0@^6.3.13: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.16.0.tgz#f5a263c420532fd57491f1a7315b3036e428f823" + dependencies: + babel-plugin-transform-do-expressions "^6.3.13" + babel-plugin-transform-function-bind "^6.3.13" + babel-preset-stage-1 "^6.16.0" + +babel-preset-stage-1@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.16.0.tgz#9d31fbbdae7b17c549fd3ac93e3cf6902695e479" + dependencies: + babel-plugin-transform-class-constructor-call "^6.3.13" + babel-plugin-transform-export-extensions "^6.3.13" + babel-preset-stage-2 "^6.16.0" + +babel-preset-stage-2@^6.16.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.18.0.tgz#9eb7bf9a8e91c68260d5ba7500493caaada4b5b5" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.18.0" + babel-plugin-transform-decorators "^6.13.0" + babel-preset-stage-3 "^6.17.0" + +babel-preset-stage-3@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.17.0.tgz#b6638e46db6e91e3f889013d8ce143917c685e39" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.3.13" + babel-plugin-transform-async-generator-functions "^6.17.0" + babel-plugin-transform-async-to-generator "^6.16.0" + babel-plugin-transform-exponentiation-operator "^6.3.13" + babel-plugin-transform-object-rest-spread "^6.16.0" + +babel-register@^6.18.0, babel-register@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68" + dependencies: + babel-core "^6.18.0" + babel-runtime "^6.11.6" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.0.0, babel-runtime@^6.20.0, babel-runtime@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-runtime@^6.11.6, babel-runtime@^6.3.19, babel-runtime@^6.9.0, babel-runtime@^6.9.1: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" + dependencies: + babel-runtime "^6.9.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.0.20, babel-traverse@^6.16.0, babel-traverse@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.19.0.tgz#68363fb821e26247d52a519a84b2ceab8df4f55a" + dependencies: + babel-code-frame "^6.16.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.0.19, babel-types@^6.13.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.8.0, babel-types@^6.9.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.19.0.tgz#8db2972dbed01f1192a8b602ba1e1e4c516240b9" + dependencies: + babel-runtime "^6.9.1" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.0.18, babylon@^6.11.0: + version "6.14.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815" + +balanced-match@^0.4.1, balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +better-npm-run@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/better-npm-run/-/better-npm-run-0.0.10.tgz#1fe03fe5251df0d411bfe4f8e23e84cd746aa2ff" + dependencies: + dotenv "^2.0.0" + object-assign "^4.0.1" + +big.js@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.4.6: + version "3.4.6" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.6.tgz#01da8d821d87813d158967e743d5fe6c62cf8c0f" + +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +bowser@^1.6.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.1.tgz#9157e9498f456e937173a2918f3b2161e5353eb3" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +brace@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/brace/-/brace-0.8.0.tgz#e826c6d5054cae5f607ad7b1c81236dd2cf01978" + dependencies: + w3c-blob "0.0.1" + +brace@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/brace/-/brace-0.9.0.tgz#ad034bae65220eb676d949cb280383fa8e12fa72" + dependencies: + w3c-blob "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browserify-zlib@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserslist@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.4.0.tgz#9cfdcf5384d9158f5b70da2aa00b30e8ff019049" + dependencies: + caniuse-db "^1.0.30000539" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer@^4.9.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +caniuse-db@^1.0.30000539, caniuse-db@^1.0.30000578: + version "1.0.30000592" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000592.tgz#7b916023941df4063d9d946a1f9ad0d5edaf2bcd" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chain-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" + dependencies: + ansi-styles "~1.0.0" + has-color "~0.1.0" + strip-ansi "~0.1.0" + +change-emitter@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.2.tgz#6b88ca4d5d864e516f913421b11899a860aee8db" + +chokidar@^1.0.0, chokidar@^1.4.3: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +circular-json@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +clap@^1.0.9: + version "1.1.2" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.2.tgz#316545bf22229225a2cecaa6824cd2f56a9709ed" + dependencies: + chalk "^1.1.3" + +classnames@2.2.5, classnames@^2.2, classnames@^2.2.3, classnames@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" + +clean-css@3.4.x: + version "3.4.21" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.21.tgz#2101d5dbd19d63dbc16a75ebd570e7c33948f65b" + dependencies: + commander "2.8.x" + source-map "0.4.x" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +co-request@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/co-request/-/co-request-0.2.1.tgz#6428c002ad4229b3eda6725022aeccf273bee3fb" + dependencies: + request "*" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +coa@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.3.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.8.2.tgz#be868184d7c8631766d54e7078e2672d7c7e3339" + dependencies: + color-name "^1.1.1" + +color-name@^1.0.0, color-name@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@2.8.x: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commander@2.9.x, commander@^2.8.1, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.6: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +configstore@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" + dependencies: + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + object-assign "^4.0.1" + os-tmpdir "^1.0.0" + osenv "^0.1.0" + uuid "^2.0.1" + write-file-atomic "^1.1.2" + xdg-basedir "^2.0.0" + +connect-history-api-fallback@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-0.0.1.tgz#92577db527ba6c4cf0a4568d84bc031f441e21f2" + +content-disposition@~0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" + +content-type@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +cookies@~0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.6.2.tgz#6ac1b052895208e8fc4c4f5f86a9ed31b9cb5ccf" + dependencies: + depd "~1.1.0" + keygrip "~1.0.1" + +core-js@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +create-react-class@^15.5.2: + version "15.5.3" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.3.tgz#fb0f7cae79339e9a179e194ef466efa3923820fe" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@~3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.2.8.tgz#b9b11dbe6d9651dd882a01e6cc467df718ecf189" + dependencies: + pbkdf2-compat "2.0.1" + ripemd160 "0.2.0" + sha.js "2.2.6" + +css-color-names@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-in-js-utils@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-1.0.3.tgz#9ac7e02f763cf85d94017666565ed68a5b5f3215" + dependencies: + hyphenate-style-name "^1.0.2" + +css-loader@^0.23.0: + version "0.23.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.23.1.tgz#9fa23f2b5c0965235910ad5ecef3b8a36390fe50" + dependencies: + css-selector-tokenizer "^0.5.1" + cssnano ">=2.6.1 <4" + loader-utils "~0.2.2" + lodash.camelcase "^3.0.1" + object-assign "^4.0.1" + postcss "^5.0.6" + postcss-modules-extract-imports "^1.0.0" + postcss-modules-local-by-default "^1.0.1" + postcss-modules-scope "^1.0.0" + postcss-modules-values "^1.1.0" + source-list-map "^0.1.4" + +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-selector-tokenizer@^0.5.1: + version "0.5.4" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.5.4.tgz#139bafd34a35fd0c1428487049e0699e6f6a2c21" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + +css-selector-tokenizer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz#6445f582c7930d241dcc5007a43d6fcb8f073152" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + +"cssnano@>=2.6.1 <4", cssnano@^3.3.2: + version "3.8.1" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.8.1.tgz#008a482148ee948cf0af2ee6e44bd97c53f886ec" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +csso@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.2.1.tgz#51fbb5347e50e81e6ed51668a48490ae6fe2afe2" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +d3-array@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.1.tgz#d1ca33de2f6ac31efadb8e050a021d7e2396d5dc" + +d3-collection@1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.4.tgz#342dfd12837c90974f33f1cc0a785aea570dcdc2" + +d3-color@1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.3.tgz#bc7643fca8e53a8347e2fbdaffa236796b58509b" + +d3-format@1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.2.0.tgz#6b480baa886885d4651dc248a8f4ac9da16db07a" + +d3-interpolate@1, d3-interpolate@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.5.tgz#69e099ff39214716e563c9aec3ea9d1ea4b8a79f" + dependencies: + d3-color "1" + +d3-path@1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.5.tgz#241eb1849bd9e9e8021c0d0a799f8a0e8e441764" + +d3-scale@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.6.tgz#bce19da80d3a0cf422c9543ae3322086220b34ed" + dependencies: + d3-array "^1.2.0" + d3-collection "1" + d3-color "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-shape@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.2.0.tgz#45d01538f064bafd05ea3d6d2cb748fd8c41f777" + dependencies: + d3-path "1" + +d3-time-format@2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.0.tgz#a1d9540a1dc498817d44066b121b19a4a83e3531" + dependencies: + d3-time "1" + +d3-time@1: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.7.tgz#94caf6edbb7879bb809d0d1f7572bc48482f7270" + +d@^0.1.1, d@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + dependencies: + es5-ext "~0.10.2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@*, debug@^2.1.1, debug@^2.2.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + dependencies: + ms "0.7.2" + +debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-equal@^1.0.0, deep-equal@^1.0.1, deep-equal@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@^1.1.0, depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +dom-converter@~0.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" + dependencies: + utila "~0.3" + +dom-helpers@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +dom4@^1.8: + version "1.8.5" + resolved "https://registry.yarnpkg.com/dom4/-/dom4-1.8.5.tgz#4de3a2e59af45b2af8b30bc595713ecae5037037" + +domain-browser@^1.1.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" + dependencies: + domelementtype "1" + +domutils@1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +dotenv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-2.0.0.tgz#bd759c357aaa70365e01c96b7b0bec08a6e0d949" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +duplexify@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604" + dependencies: + end-of-stream "1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e" + dependencies: + once "~1.3.0" + +enhanced-resolve@~0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.2.0" + tapable "^0.1.8" + +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +errno@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + dependencies: + prr "~0.0.0" + +error-ex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + dependencies: + is-arrayish "^0.2.1" + +error-inject@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + +error-stack-parser@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-1.3.6.tgz#e0e73b93e417138d1cd7c0b746b1a4a14854c292" + dependencies: + stackframe "^0.3.1" + +es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: + version "0.10.12" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + dependencies: + d "^0.1.1" + es5-ext "^0.10.7" + es6-symbol "3" + +es6-map@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-set "~0.1.3" + es6-symbol "~3.1.0" + event-emitter "~0.3.4" + +es6-promise@^3.0.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + +es6-set@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-symbol "3" + event-emitter "~0.3.4" + +es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + +es6-weak-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + dependencies: + d "^0.1.1" + es5-ext "^0.10.8" + es6-iterator "2" + es6-symbol "3" + +escape-html@~1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@1.8.x, escodegen@^1.6.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-config-standard-jsx@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-2.0.0.tgz#26650353bda0d273368f5357c236af9ff54edf1e" + +eslint-config-standard-react@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-react/-/eslint-config-standard-react-3.0.0.tgz#f28857a9a5828b19edd034d0b7f1959054ea9020" + dependencies: + eslint-config-standard-jsx "^2.0.0" + +eslint-config-standard@^5.1.0: + version "5.3.5" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-5.3.5.tgz#2b42bb5c9f0049b8527868e109c34ee22b13dcf6" + +eslint-plugin-babel@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-3.3.0.tgz#2f494aedcf6f4aa4e75b9155980837bc1fbde193" + +eslint-plugin-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-2.0.1.tgz#a9759cefa5e38ab11bb2ef65a04ef042309aa0a4" + +eslint-plugin-react@^6.0.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.8.0.tgz#741ab5438a094532e5ce1bbb935d6832356f492d" + dependencies: + doctrine "^1.2.2" + jsx-ast-utils "^1.3.4" + +eslint-plugin-standard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz#3589699ff9c917f2c25f76a916687f641c369ff3" + +eslint@^3.0.1: + version "3.11.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.11.1.tgz#408be581041385cba947cd8d1cd2227782b55dbf" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + escope "^3.6.0" + espree "^3.3.1" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.2.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~1.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" + dependencies: + acorn "^4.0.1" + acorn-jsx "^3.0.0" + +esprima@2.7.x, esprima@^2.1.0, esprima@^2.6.0, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.0, esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +event-emitter@~0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.7" + +event-stream@~3.3.0: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extract-text-webpack-plugin@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-1.0.1.tgz#c95bf3cbaac49dc96f1dc6e072549fbb654ccd2c" + dependencies: + async "^1.5.0" + loader-utils "^0.2.3" + webpack-sources "^0.1.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fast-levenshtein@~2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" + +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + +fbjs@^0.8.0, fbjs@^0.8.16: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + +fbjs@^0.8.1, fbjs@^0.8.4, fbjs@^0.8.6: + version "0.8.6" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.6.tgz#7eb67d6986b2d5007a9b6e92e0e7cb6f75cad290" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + ua-parser-js "^0.7.9" + +fbjs@^0.8.9: + version "0.8.12" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +file-loader@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42" + dependencies: + loader-utils "~0.2.5" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +flat-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" + dependencies: + circular-json "^0.3.0" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +fresh@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +from@~0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc" + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-readdir-recursive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.15" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.15.tgz#fa63f590f3c2ad91275e4972a6cea545fb0aae44" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +gauge@~2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-color "^0.1.7" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" + dependencies: + globule "^1.0.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^5.0.15, glob@^5.0.5: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.0.0, globals@^9.2.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f" + dependencies: + glob "~7.1.1" + lodash "~4.16.4" + minimatch "~3.0.2" + +got@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" + dependencies: + duplexify "^3.2.0" + infinity-agent "^2.0.0" + is-redirect "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + nested-error-stacks "^1.0.0" + object-assign "^3.0.0" + prepend-http "^1.0.0" + read-all-stream "^3.0.0" + timed-out "^2.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +handlebars@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-color@^0.1.7, has-color@~0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +he@1.1.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.0.tgz#29319d49beec13a9b1f3c4f9b2a6dde4859bb2a7" + +history@^2.0.0, history@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/history/-/history-2.1.2.tgz#4aa2de897a0e4867e4539843be6ecdb2986bfdec" + dependencies: + deep-equal "^1.0.0" + invariant "^2.0.0" + query-string "^3.0.0" + warning "^2.0.0" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +hoist-non-react-statics@^1.0.0, hoist-non-react-statics@^1.0.3, hoist-non-react-statics@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +html-entities@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" + +html-minifier@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.2.3.tgz#d2ff536e24d95726c332493d8f77d84dbed85372" + dependencies: + camel-case "3.0.x" + clean-css "3.4.x" + commander "2.9.x" + he "1.1.x" + ncname "1.0.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "2.7.x" + +html-webpack-plugin@^2.7.1: + version "2.24.1" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-2.24.1.tgz#7f45fc678f66eac2d433f22336b4399da023b57e" + dependencies: + bluebird "^3.4.6" + html-minifier "^3.1.0" + loader-utils "^0.2.16" + lodash "^4.16.4" + pretty-error "^2.0.2" + toposort "^1.0.0" + +htmlparser2@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" + dependencies: + domelementtype "1" + domhandler "2.1" + domutils "1.1" + readable-stream "1.0" + +http-assert@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.2.0.tgz#d6392e6f6519def4e340266b35096db6d3feba00" + dependencies: + deep-equal "~1.0.0" + http-errors "~1.4.0" + +http-browserify@^1.3.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/http-browserify/-/http-browserify-1.7.0.tgz#33795ade72df88acfbfd36773cefeda764735b20" + dependencies: + Base64 "~0.2.0" + inherits "~2.0.1" + +http-errors@^1.2.8, http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-errors@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.4.0.tgz#6c0242dea6b3df7afda153c71089b31c6e82aabf" + dependencies: + inherits "2.0.1" + statuses ">= 1.2.1 < 2" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.0.tgz#b3ffdfe734b2a3d4a9efd58e8654c91fce86eafd" + +hyphenate-style-name@^1.0.0, hyphenate-style-name@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" + +iconv-lite@^0.2.11: + version "0.2.11" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" + +iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + +icss-replace-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ignore-by-default@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +ignore@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" + +immutability-helper@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-2.5.0.tgz#01ea7204334997c645bdfa7eb22e8b84c970946e" + dependencies: + invariant "^2.2.0" + +imports-loader@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.6.5.tgz#ae74653031d59e37b3c2fb2544ac61aeae3530a6" + dependencies: + loader-utils "0.2.x" + source-map "0.1.x" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +infinity-agent@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inline-style-prefixer@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.3.tgz#eca9767080b29a8afcf13299fe6358e1f320bbeb" + dependencies: + bowser "^1.6.0" + css-in-js-utils "^1.0.3" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +interpret@^0.6.4: + version "0.6.6" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" + +interpret@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + +invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ip@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.4.tgz#de8247ffef940451832550fba284945e6e039bfb" + +is-absolute-url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.0.0.tgz#9c4b20b0e5c0cbef9a479a367ede6f991679f359" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-generator-function@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.3.tgz#d374ca57e807444fa2658be3728ed6b174b326b1" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.0.0, is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + dependencies: + html-comment-regex "^1.1.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +isparta-loader@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isparta-loader/-/isparta-loader-2.0.0.tgz#4425f496c93f765bbceb4dd938576da307566ed1" + dependencies: + isparta "4.x.x" + +isparta@4.x.x: + version "4.0.0" + resolved "https://registry.yarnpkg.com/isparta/-/isparta-4.0.0.tgz#1de91996f480b22dcb1aca8510255bae1574446e" + dependencies: + babel-core "^6.1.4" + escodegen "^1.6.1" + esprima "^2.1.0" + istanbul "^0.4.0" + mkdirp "^0.5.0" + nomnomnomnom "^2.0.0" + object-assign "^4.0.1" + source-map "^0.5.0" + which "^1.0.9" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul@^0.4.0: + version "0.4.5" + resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-base64@^2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" + +js-tokens@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" + +js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + +js-yaml@3.x, js-yaml@^3.5.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +js-yaml@~3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-loader@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +jsx-ast-utils@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.3.4.tgz#0257ed1cc4b1e65b39d7d9940f9fb4f20f7ba0a9" + dependencies: + acorn-jsx "^3.0.1" + object-assign "^4.1.0" + +keycode@^2.1.8: + version "2.1.9" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" + +keygrip@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.1.tgz#b02fa4816eef21a8c4b35ca9e52921ffc89a30e9" + +kind-of@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" + dependencies: + is-buffer "^1.0.2" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + +koa-compose@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + dependencies: + any-promise "^1.1.0" + +koa-connect-history-api-fallback@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/koa-connect-history-api-fallback/-/koa-connect-history-api-fallback-0.3.1.tgz#068ffee68f3a7e85e998b63d0c5a3f05b68d534d" + dependencies: + connect-history-api-fallback "^1.1.0" + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + +koa-proxy@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/koa-proxy/-/koa-proxy-0.6.0.tgz#99f1860ff65fe167a865a5649d57a7dd3ad5cab0" + dependencies: + co-request "^0.2.0" + iconv-lite "^0.2.11" + +koa-send@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-3.2.0.tgz#a4063c2631b7ebed9f9fc2a77568799ba606449b" + dependencies: + co "^4.6.0" + debug "*" + mz "^2.3.1" + resolve-path "^1.3.1" + +koa-static@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-3.0.0.tgz#40442233d2c0b35c225e450199c10bf8a539e416" + dependencies: + debug "*" + koa-send "^3.2.0" + +koa@^2.0.0-alpha.3: + version "2.0.0" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.0.0.tgz#da865ae8ee4afae070425290455d2cdf4885f9dc" + dependencies: + accepts "^1.2.2" + content-disposition "~0.5.0" + content-type "^1.0.0" + cookies "~0.6.1" + debug "*" + delegates "^1.0.0" + depd "^1.1.0" + destroy "^1.0.3" + error-inject "~1.0.0" + escape-html "~1.0.1" + fresh "^0.3.0" + http-assert "^1.1.0" + http-errors "^1.2.8" + is-generator-function "^1.0.3" + koa-compose "^3.0.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + mime-types "^2.0.7" + on-finished "^2.1.0" + only "0.0.2" + parseurl "^1.3.0" + statuses "^1.2.0" + type-is "^1.5.5" + vary "^1.0.0" + +latest-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" + dependencies: + package-json "^1.0.0" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.14, loader-utils@^0.2.15, loader-utils@^0.2.16, loader-utils@^0.2.3, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5: + version "0.2.16" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +lodash-es@^4.2.1: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.2.tgz#59011b585166e613eb9dd5fc256b2cd1a30f3712" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._createcompounder@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._createcompounder/-/lodash._createcompounder-3.0.0.tgz#5dd2cb55372d6e70e0e2392fb2304d6631091075" + dependencies: + lodash.deburr "^3.0.0" + lodash.words "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + +lodash.assign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.assign@^4.0.0, lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.camelcase@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-3.0.1.tgz#932c8b87f8a4377897c67197533282f97aeac298" + dependencies: + lodash._createcompounder "^3.0.0" + +lodash.clonedeep@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.deburr@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-3.2.0.tgz#6da8f54334a366a7cf4c4c76ef8d80aa1b365ed5" + dependencies: + lodash._root "^3.0.0" + +lodash.defaults@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" + dependencies: + lodash.assign "^3.0.0" + lodash.restparam "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.isequal@^4.1.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.4.0.tgz#6295768e98e14dc15ce8d362ef6340db82852031" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.merge@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + +lodash.pickby@^4.0.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + +lodash.words@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.words/-/lodash.words-3.2.0.tgz#4e2a8649bc08745b17c695b1a3ce8fee596623b3" + dependencies: + lodash._root "^3.0.0" + +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" + +lodash@^4.16.4, lodash@~4.17.4: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@~4.16.4: + version "4.16.6" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8" + dependencies: + js-tokens "^2.0.0" + +loose-envify@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lower-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.3.tgz#c92393d976793eee5ba4edb583cf8eae35bd9bfb" + +lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lru-cache@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + +macaddress@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +matchmedia@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/matchmedia/-/matchmedia-0.1.2.tgz#cfd47f2bf68fbc7f5ea1bd3a3cf1715ecba3c1bd" + dependencies: + css-mediaquery "^0.1.2" + +material-ui@^0.18.1: + version "0.18.1" + resolved "https://registry.yarnpkg.com/material-ui/-/material-ui-0.18.1.tgz#1c8a47d7e930ff0b07064dd8633035984a5a3569" + dependencies: + babel-runtime "^6.23.0" + inline-style-prefixer "^3.0.2" + keycode "^2.1.8" + lodash.merge "^4.6.0" + lodash.throttle "^4.1.1" + prop-types "^15.5.7" + react-event-listener "^0.4.5" + react-transition-group "^1.1.2" + recompose "0.23.4" + simple-assign "^0.1.0" + warning "^3.0.0" + +math-expression-evaluator@^1.2.14: + version "1.2.17" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +memory-fs@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + +memory-fs@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" + +mime-types@^2.0.7, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" + dependencies: + mime-db "~1.25.0" + +mime@1.2.x: + version "1.2.11" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + +mime@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +modify-babel-preset@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/modify-babel-preset/-/modify-babel-preset-1.2.0.tgz#d1b7c8c24896e19dbc4847347213e6b7144d1bc7" + dependencies: + require-relative "^0.8.7" + +moment@^2.14.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +mz@^2.3.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.6.0.tgz#c8b8521d958df0a4f2768025db69c719ee4ef1ce" + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@^2.3.0, nan@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +ncname@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" + dependencies: + xml-char-classes "^1.0.0" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +nested-error-stacks@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf" + dependencies: + inherits "~2.0.1" + +no-case@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.0.tgz#ca2825ccb76b18e6f79d573dcfbf1eace33dd164" + dependencies: + lower-case "^1.1.1" + +node-fetch@^1.0.1: + version "1.6.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-gyp@^3.3.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3" + osenv "0" + path-array "^1.0.0" + request "2" + rimraf "2" + semver "2.x || 3.x || 4 || 5" + tar "^2.0.0" + which "1" + +node-libs-browser@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.6.0.tgz#244806d44d319e048bc8607b5cc4eaf9a29d2e3c" + dependencies: + assert "^1.1.1" + browserify-zlib "~0.1.4" + buffer "^4.9.0" + console-browserify "^1.1.0" + constants-browserify "0.0.1" + crypto-browserify "~3.2.6" + domain-browser "^1.1.1" + events "^1.0.0" + http-browserify "^1.3.2" + https-browserify "0.0.0" + os-browserify "~0.1.2" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "~0.2.0" + readable-stream "^1.1.13" + stream-browserify "^1.0.0" + string_decoder "~0.10.25" + timers-browserify "^1.0.1" + tty-browserify "0.0.0" + url "~0.10.1" + util "~0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.29: + version "0.6.32" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +node-sass@^3.7.0: + version "3.13.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-3.13.0.tgz#d08b95bdebf40941571bd2c16a9334b980f8924f" + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.3.2" + node-gyp "^3.3.1" + npmlog "^4.0.0" + request "^2.61.0" + sass-graph "^2.1.1" + +nodemon@^1.8.1: + version "1.11.0" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c" + dependencies: + chokidar "^1.4.3" + debug "^2.2.0" + es6-promise "^3.0.2" + ignore-by-default "^1.0.0" + lodash.defaults "^3.1.2" + minimatch "^3.0.0" + ps-tree "^1.0.1" + touch "1.0.0" + undefsafe "0.0.3" + update-notifier "0.5.0" + +nomnomnomnom@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nomnomnomnom/-/nomnomnomnom-2.0.1.tgz#b2239f031c8d04da67e32836e1e3199e12f7a8e2" + dependencies: + chalk "~0.4.0" + underscore "~1.6.0" + +"nopt@2 || 3", nopt@3.x, nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^1.4.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.8.0.tgz#a9550b079aa3523c85d78df24eef1959fce359ab" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize.css@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-4.1.1.tgz#4f0b1d5a235383252b04d8566b866cc5fcad9f0c" + +"npmlog@0 || 1 || 2 || 3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.6.0" + set-blocking "~2.0.0" + +npmlog@^4.0.0, npmlog@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.1.tgz#d14f503b4cd79710375553004ba96e6662fbc0b8" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-finished@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@1.x, once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +only@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + +optimist@^0.6.1, optimist@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1, optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-browserify@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@0, osenv@^0.1.0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.3.tgz#83cf05c6d6458fc4d5ac6362ea325d92f2754217" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +package-json@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0" + dependencies: + got "^3.2.0" + registry-url "^3.0.0" + +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +param-case@2.1.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.0.tgz#2619f90fd6c829ed0b958f1c84ed03a745a6d70a" + dependencies: + no-case "^2.2.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parseurl@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-array@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + dependencies: + array-index "^1.0.0" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-is-absolute@1.0.1, path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + +pbkdf2-compat@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-colormin@^2.1.8: + version "2.2.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.1.tgz#dc5421b6ae6f779ef6bfd47352b94abe59d0316b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-convert-values@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.5.0.tgz#570aceb04b3061fb25f6f46bd0329e7ab6263c0b" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-duplicates@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.0.2.tgz#02be520e91571ffb10738766a981d5770989bb32" + dependencies: + postcss "^5.0.4" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" + dependencies: + postcss "^5.0.4" + uniqid "^4.0.0" + +postcss-loader@^0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-0.9.1.tgz#87a3e70f58e46d68a75badc6725d9ea4773fd1d7" + dependencies: + loader-utils "^0.2.14" + postcss "^5.0.19" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.1.tgz#ff59b5dec6d586ce2cea183138f55c5876fa9cdc" + dependencies: + postcss "^5.0.4" + +postcss-merge-rules@^2.0.3: + version "2.0.10" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.0.10.tgz#54b360be804e7e69a5c7222635247b92a3569e9b" + dependencies: + postcss "^5.0.4" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-params@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.0.5.tgz#82d602643b8616a61fb3634d7ede0289836d67f9" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.0.7.tgz#bfb9248fe14db33770f036572de6b4897c48d81c" + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-modules-extract-imports@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.0.1.tgz#8fb3fef9a6dd0420d3f6d4353cf1ff73f2b2a341" + dependencies: + postcss "^5.0.4" + +postcss-modules-local-by-default@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.1.1.tgz#29a10673fa37d19251265ca2ba3150d9040eb4ce" + dependencies: + css-selector-tokenizer "^0.6.0" + postcss "^5.0.4" + +postcss-modules-scope@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.0.2.tgz#ff977395e5e06202d7362290b88b1e8cd049de29" + dependencies: + css-selector-tokenizer "^0.6.0" + postcss "^5.0.4" + +postcss-modules-values@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.2.2.tgz#f0e7d476fe1ed88c5e4c7f97533a3e772ad94ca1" + dependencies: + icss-replace-symbols "^1.0.2" + postcss "^5.0.14" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + dependencies: + postcss "^5.0.5" + +postcss-normalize-url@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.7.tgz#6bd90d0a4bc5a1df22c26ea65c53257dc3829f4e" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-ordered-values@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.2.tgz#be8b511741fab2dac8e614a2302e9d10267b0771" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-reduce-idents@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.3.1.tgz#024e8e219f52773313408573db9645ba62d2d2fe" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.0.tgz#8f739b938289ef2e48936d7101783e4741ca9bbb" + dependencies: + postcss "^5.0.4" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-selector-parser@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.2.tgz#3d70f5adda130da51c7c0c2fc023f56b1374fe08" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.5" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.5.tgz#46fc0363f01bab6a36a9abb01c229fcc45363094" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.5: + version "5.2.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.6.tgz#a252cd67cd52585035f17e9ad12b35137a7bdd9e" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.1.2" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +pretty-error@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.0.2.tgz#a7db19cbb529ca9f0af3d3a2f77d5caf8e5dec23" + dependencies: + renderkid "~2.0.0" + utila "~0.4" + +private@^0.1.6, private@~0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@^0.11.0, process@~0.11.0: + version "0.11.9" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +promise@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" + dependencies: + asap "~2.0.3" + +prop-types@^15.5.10, prop-types@^15.6.0: + version "15.6.0" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8: + version "15.5.10" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.3.1" + +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +ps-tree@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + dependencies: + event-stream "~3.3.0" + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +pure-render-decorator@^1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pure-render-decorator/-/pure-render-decorator-1.2.1.tgz#568870eeca17a1cee536b4fe94a3477fcd31eeb9" + dependencies: + fbjs "^0.8.0" + +q@^1.1.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +query-string@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-3.0.3.tgz#ae2e14b4d05071d4e9b9eb4873c35b0dcd42e638" + dependencies: + strict-uri-encode "^1.0.0" + +query-string@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.2.3.tgz#9f27273d207a25a8ee4c7b8c74dcd45d556db822" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0, querystring@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +raf@^3.2.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" + dependencies: + performance-now "^2.1.0" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +range-parser@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +rc@^1.0.1, rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +react-ace@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-4.1.0.tgz#659faa010d173f60d6a8940f0b325c5e422cab54" + dependencies: + brace "^0.8.0" + lodash.isequal "^4.1.1" + +react-addons-css-transition-group@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/react-addons-css-transition-group/-/react-addons-css-transition-group-15.6.2.tgz#9e4376bcf40b5217d14ec68553081cee4b08a6d6" + dependencies: + react-transition-group "^1.2.0" + +react-addons-test-utils@^15.0.0: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.1.tgz#1e4caab151bf27cce26df5f9cb714f4fd8359ae1" + +react-autosuggest@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/react-autosuggest/-/react-autosuggest-9.0.1.tgz#b56eaf8fc3dd46d36b92c5395b6b07174bc10912" + dependencies: + prop-types "^15.5.8" + react-autowhatever "^10.0.0" + shallow-equal "^1.0.0" + +react-autowhatever@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/react-autowhatever/-/react-autowhatever-10.0.0.tgz#2d7fd54f0a330e33c06c53a83ef789da0ebb65bf" + dependencies: + prop-types "^15.5.8" + react-themeable "^1.1.0" + section-iterator "^2.0.0" + +react-dom@^15.0.0: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.1.tgz#d54c913261aaedb17adc20410d029dcc18a1344a" + dependencies: + fbjs "^0.8.1" + loose-envify "^1.1.0" + object-assign "^4.1.0" + +react-dropzone@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-3.9.2.tgz#84703d1ee20ea4118f64fa38c14218415fecb1e9" + dependencies: + attr-accept "^1.0.3" + +react-event-listener@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.4.5.tgz#e3e895a0970cf14ee8f890113af68197abf3d0b1" + dependencies: + babel-runtime "^6.20.0" + fbjs "^0.8.4" + prop-types "^15.5.4" + warning "^3.0.0" + +react-input-autosize@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-1.1.4.tgz#cbc45072d4084ddc57806db8e3b34e644b8366ac" + dependencies: + create-react-class "^15.5.2" + prop-types "^15.5.8" + +react-input-mask@^0.7.2: + version "0.7.5" + resolved "https://registry.yarnpkg.com/react-input-mask/-/react-input-mask-0.7.5.tgz#37d3924670582ad3c155214d4b3e140c235e685d" + +react-redux@^4.0.0: + version "4.4.6" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-4.4.6.tgz#4b9d32985307a11096a2dd61561980044fcc6209" + dependencies: + hoist-non-react-statics "^1.0.3" + invariant "^2.0.0" + lodash "^4.2.0" + loose-envify "^1.1.0" + +react-resize-detector@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-1.1.0.tgz#4a9831fa3caad32230478dd0185cbd2aa91a5ebf" + dependencies: + prop-types "^15.5.10" + +react-responsive@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-1.2.6.tgz#0173b3a59ef094011f79464ce618e2e26fe117fc" + dependencies: + hyphenate-style-name "^1.0.0" + matchmedia "^0.1.2" + +react-router-redux@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.7.tgz#9b1fde4e70106c50f47214e12bdd888cfb96e2a6" + +react-router@^2.2.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-2.8.1.tgz#73e9491f6ceb316d0f779829081863e378ee4ed7" + dependencies: + history "^2.1.2" + hoist-non-react-statics "^1.2.0" + invariant "^2.2.1" + loose-envify "^1.2.0" + warning "^3.0.0" + +react-smooth@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-1.0.0.tgz#b29dbebddddb06d21b5b08962167fb9eac1897d8" + dependencies: + lodash "~4.17.4" + prop-types "^15.6.0" + raf "^3.2.0" + react-transition-group "^2.2.1" + +react-spinkit@^1.1.11: + version "1.1.11" + resolved "https://registry.yarnpkg.com/react-spinkit/-/react-spinkit-1.1.11.tgz#a08e37437d46af16ce7b9c87904b8e786b1359a3" + dependencies: + classnames "^2.2.3" + object-assign "^4.1.0" + +react-tap-event-plugin@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/react-tap-event-plugin/-/react-tap-event-plugin-2.0.1.tgz#316beb3bc6556e29ec869a7293e89c826a9074d2" + dependencies: + fbjs "^0.8.6" + +react-themeable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e" + dependencies: + object-assign "^3.0.0" + +react-transition-group@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.1.3.tgz#5e02cf6e44a863314ff3c68a0c826c2d9d70b221" + dependencies: + chain-function "^1.0.0" + dom-helpers "^3.2.0" + prop-types "^15.5.6" + warning "^3.0.0" + +react-transition-group@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6" + dependencies: + chain-function "^1.0.0" + dom-helpers "^3.2.0" + loose-envify "^1.3.1" + prop-types "^15.5.6" + warning "^3.0.0" + +react-transition-group@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.2.1.tgz#e9fb677b79e6455fd391b03823afe84849df4a10" + dependencies: + chain-function "^1.0.0" + classnames "^2.2.5" + dom-helpers "^3.2.0" + loose-envify "^1.3.1" + prop-types "^15.5.8" + warning "^3.0.0" + +react@^15.0.0: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react/-/react-15.4.1.tgz#498e918602677a3983cd0fd206dfe700389a0dd6" + dependencies: + fbjs "^0.8.4" + loose-envify "^1.1.0" + object-assign "^4.1.0" + +read-all-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" + dependencies: + pinkie-promise "^2.0.0" + readable-stream "^2.0.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@1.0: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^1.0.27-1, readable-stream@^1.1.13: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +recharts-scale@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.3.2.tgz#dac7621714a4765d152cb2adbc30c73b831208c9" + +recharts@1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-1.0.0-beta.1.tgz#0530554b12f1c9d717887f25d529dd3724f3ecf7" + dependencies: + classnames "2.2.5" + core-js "2.5.1" + d3-interpolate "^1.1.5" + d3-scale "1.0.6" + d3-shape "1.2.0" + lodash "~4.17.4" + prop-types "^15.6.0" + react-resize-detector "1.1.0" + react-smooth "1.0.0" + recharts-scale "0.3.2" + reduce-css-calc "1.3.0" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +recompose@0.23.4: + version "0.23.4" + resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.23.4.tgz#af09e4e08424effa449c9b793037166f7b30644a" + dependencies: + change-emitter "^0.1.2" + fbjs "^0.8.1" + hoist-non-react-statics "^1.0.0" + symbol-observable "^1.0.4" + +redbox-react@^1.2.10: + version "1.3.3" + resolved "https://registry.yarnpkg.com/redbox-react/-/redbox-react-1.3.3.tgz#63ec9c2cb9c620c46e2b9f8543b4898f1b787e41" + dependencies: + error-stack-parser "^1.3.6" + object-assign "^4.0.1" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +reduce-css-calc@1.3.0, reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + dependencies: + balanced-match "^0.4.2" + +redux-thunk@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.1.0.tgz#c724bfee75dbe352da2e3ba9bc14302badd89a98" + +redux@^3.0.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d" + dependencies: + lodash "^4.2.1" + lodash-es "^4.2.1" + loose-envify "^1.1.0" + symbol-observable "^1.0.2" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.10.0: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.9.5: + version "0.9.6" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +registry-url@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + +renderkid@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.0.tgz#1859753e7a5adbf35443aba0d4e4579e78abee85" + dependencies: + css-select "^1.1.0" + dom-converter "~0.1" + htmlparser2 "~3.3.0" + strip-ansi "^3.0.0" + utila "~0.3" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@*, request@2, request@^2.61.0, request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +require-relative@^0.8.7: + version "0.8.7" + resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-path@^1.3.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.3.3.tgz#4d83aba6468c2b8e632a575e3f52b0fa0dbe1a5c" + dependencies: + http-errors "~1.5.0" + path-is-absolute "1.0.1" + +resolve@1.1.x, resolve@^1.1.6: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +ripemd160@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +sass-graph@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.1.2.tgz#965104be23e8103cb7e5f710df65935b317da57b" + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + yargs "^4.7.1" + +sass-loader@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-4.0.2.tgz#a616eb770366543e64f547c8630f39c4da75f15d" + dependencies: + async "^2.0.1" + loader-utils "^0.2.15" + object-assign "^4.1.0" + +sax@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + +section-iterator@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.3, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + +sha.js@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" + +shallow-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.0.0.tgz#508d1838b3de590ab8757b011b25e430900945f7" + +shelljs@^0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-assign@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/simple-assign/-/simple-assign-0.1.0.tgz#17fd3066a5f3d7738f50321bb0f14ca281cc4baa" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^0.1.4, source-list-map@~0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.7.tgz#d4b5ce2a46535c72c7e8527c71a77d250618172e" + +source-map-support@^0.4.2: + version "0.4.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.6.tgz#32552aa64b458392a85eab3b0b5ee61527167aeb" + dependencies: + source-map "^0.5.3" + +source-map@0.1.x: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + dependencies: + amdefine ">=0.0.4" + +source-map@0.4.x, source-map@^0.4.4, source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + dependencies: + amdefine ">=0.0.4" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stackframe@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-0.3.1.tgz#33aa84f1177a5548c8935533cbfeb3420975f5a4" + +"statuses@>= 1.2.1 < 2", "statuses@>= 1.3.1 < 2", statuses@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stream-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-1.0.0.tgz#bf9b4abfb42b274d751479e44e0ff2656b6f1193" + dependencies: + inherits "~2.0.1" + readable-stream "^1.0.27-1" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" + dependencies: + strip-ansi "^3.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string_decoder@~0.10.25, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +style-loader@^0.13.0: + version "0.13.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.1.tgz#468280efbc0473023cd3a6cd56e33b5a1d7fc3a9" + dependencies: + loader-utils "^0.2.7" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0, supports-color@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" + dependencies: + has-flag "^1.0.0" + +svgo@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.1.tgz#287320fed972cb097e72c2bb1685f96fe08f8034" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.2.1" + js-yaml "~3.6.1" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +symbol-observable@^1.0.2, symbol-observable@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tapable@^0.1.8, tapable@~0.1.8: + version "0.1.10" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@^2.0.0, tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tether@^1.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/tether/-/tether-1.4.1.tgz#78112ef21adf2aea68cd90e72185f43d9ffc44e8" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.2.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.2.1.tgz#251fd1c80aff6e5cf57cb179ab1fcb724269bd11" + dependencies: + any-promise "^1.0.0" + +through@2, through@^2.3.6, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +toposort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.0.tgz#b66cf385a1a8a8e68e45b8259e7f55875e8b06ef" + +touch@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de" + dependencies: + nopt "~1.0.10" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tslib@^1.5.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.0.tgz#dc604ebad64bcbf696d613da6c954aa0e7ea1eb6" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.4" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.4.tgz#8c9dbfb52795686f166cd2023794bcf103d13c2b" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-is@^1.5.5: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +ua-parser-js@^0.7.9: + version "0.7.12" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" + +uglify-js@2.7.x, uglify-js@^2.6, uglify-js@~2.7.3: + version "2.7.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +undefsafe@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" + +underscore@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqid@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.0.tgz#33d9679f65022f48988a03fd24e7dcaf8f109eca" + dependencies: + macaddress "^0.2.8" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +update-notifier@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc" + dependencies: + chalk "^1.0.0" + configstore "^1.0.0" + is-npm "^1.0.0" + latest-version "^1.0.0" + repeating "^1.1.2" + semver-diff "^2.0.0" + string-length "^1.0.0" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + +url-loader@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.7.tgz#67e8779759f8000da74994906680c943a9b0925d" + dependencies: + loader-utils "0.2.x" + mime "1.2.x" + +url@~0.10.1: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@~0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +utila@~0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +v8flags@^2.0.10: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +validator@^5.5.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-5.7.0.tgz#7a87a58146b695ac486071141c0c49d67da05e5c" + +vary@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + +vendors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +w3c-blob@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/w3c-blob/-/w3c-blob-0.0.1.tgz#b0cd352a1a50f515563420ffd5861f950f1d85b8" + +warning@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-2.1.0.tgz#21220d9c63afc77a8c92111e011af705ce0c6901" + dependencies: + loose-envify "^1.0.0" + +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + +watchpack@^0.2.1: + version "0.2.9" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" + dependencies: + async "^0.9.0" + chokidar "^1.0.0" + graceful-fs "^4.1.2" + +webpack-core@~0.6.0: + version "0.6.8" + resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.8.tgz#edf9135de00a6a3c26dd0f14b208af0aa4af8d0a" + dependencies: + source-list-map "~0.1.0" + source-map "~0.4.1" + +webpack-dev-middleware@^1.6.1: + version "1.8.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.8.4.tgz#e8765c9122887ce9e3abd4cc9c3eb31b61e0948d" + dependencies: + memory-fs "~0.3.0" + mime "^1.3.4" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + +webpack-hot-middleware@^2.6.0: + version "2.13.2" + resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.13.2.tgz#6500b15e6d4f1a9590f8df708183f4d2ac2c3e9e" + dependencies: + ansi-html "0.0.6" + html-entities "^1.2.0" + querystring "^0.2.0" + strip-ansi "^3.0.0" + +webpack-sources@^0.1.0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.3.tgz#15ce2fb79d0a1da727444ba7c757bf164294f310" + dependencies: + source-list-map "~0.1.0" + source-map "~0.5.3" + +webpack@^1.12.14: + version "1.13.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.13.3.tgz#e79c46fe5a37c5ca70084ba0894c595cdcb42815" + dependencies: + acorn "^3.0.0" + async "^1.3.0" + clone "^1.0.2" + enhanced-resolve "~0.9.0" + interpret "^0.6.4" + loader-utils "^0.2.11" + memory-fs "~0.3.0" + mkdirp "~0.5.0" + node-libs-browser "^0.6.0" + optimist "~0.6.0" + supports-color "^3.1.0" + tapable "~0.1.8" + uglify-js "~2.7.3" + watchpack "^0.2.1" + webpack-core "~0.6.0" + +whatwg-fetch@>=0.10.0, whatwg-fetch@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.1.tgz#078b9461bbe91cea73cbce8bb122a05f9e92b772" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@1, which@^1.0.9, which@^1.1.1, which@^1.2.9: + version "1.2.12" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + dependencies: + isexe "^1.1.1" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@^1.0.0, wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + dependencies: + graceful-fs "^4.1.2" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +xdg-basedir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + dependencies: + os-homedir "^1.0.0" + +xml-char-classes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + +yargs-parser@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.0.6" + +yargs@^4.0.0, yargs@^4.7.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.0.3" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.1" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^2.4.1" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" diff --git a/Install.md b/Install.md new file mode 100644 index 0000000..25d312e --- /dev/null +++ b/Install.md @@ -0,0 +1,61 @@ +# Install docker and docker-compose + +To install and configure Ambar you need an expertise in unix, Docker and Docker Compose. +If you have any difficulties installing and running Ambar you can request a dedicated support session by mailing us on hello@ambar.cloud + +Please refer to official [Docker](https://docs.docker.com/install/) and [Docker Compose](https://docs.docker.com/compose/install/) installation instructions. + +To check if everything is installed correctly please run: + +``` +> docker -v +Docker version 18.03.0-ce, build 0520e24 + +> docker-compose -v +docker-compose version 1.20.1, build 5d8c71b +``` + +# Set up your environment + +To make Ambar run properly on your host, you shoud set these system parameters (as superuser): + +``` +sysctl -w vm.max_map_count=262144 +sysctl -w net.ipv4.ip_local_port_range="15000 61000" +sysctl -w net.ipv4.tcp_fin_timeout=30 +sysctl -w net.core.somaxconn=1024 +sysctl -w net.core.netdev_max_backlog=2000 +sysctl -w net.ipv4.tcp_max_syn_backlog=2048 +sysctl -w vm.overcommit_memory=1 +``` + +To keep these setting after reboot you should add them into your `/etc/sysctl.conf` file. + + +# Create docker-compose file + +Download latest [docker-compose file](...) from our GitHub. + +Then modify it: + +- Replace ```${dataPath}``` values with desired path to the folder where you want Ambar to store all its data. +- Replace ```${langAnalyzer}``` value with language analyzer you want Ambar apply while indexing your documents, supported analyzers: English ```ambar_en```, Russian ```ambar_ru```, German ```ambar_de```, Italian ```ambar_it```, Polish ```ambar_pl```, Chinese ```ambar_cn```, CJK ```ambar_cjk``` +- Replace ```${ambarHostIpAddress}``` value with the IP address of your Ambar server + +## Set up your crawlers + +- Find ```crawler0``` block - this is a template for your new crawler +- Replace ```${crawlerName}``` with desired name for your crawler (only lowercase latin letters and dashes are supported) +- Replace ```${pathToCrawl}``` with path to a local folder to be crawled, if you want to crawl SMB or FTP - just mount it with standard unix tools + +You can add additional crawlers by copying ```crawler0``` segment and editing its settings (don't forget to edit the service name, e.g. to ```crawler1```). + +# Start Ambar + +Run ```docker-compose pull``` to pull latest Ambar images. + +To start Ambar run ```docker-compose up -d```. + +Ambar UI will be accessible on ```http://${ambarHostIpAddress}/``` + +If you have any difficulties installing and running Ambar you can request a dedicated support session by mailing us on hello@ambar.cloud \ No newline at end of file diff --git a/LocalCrawler/.babelrc b/LocalCrawler/.babelrc new file mode 100644 index 0000000..7b7355a --- /dev/null +++ b/LocalCrawler/.babelrc @@ -0,0 +1,9 @@ +{ + "presets": [ + "es2015", "stage-0" + ], + "sourceMaps": true, + "retainLines": true +} + + diff --git a/LocalCrawler/.eslintignore b/LocalCrawler/.eslintignore new file mode 100644 index 0000000..f517d4c --- /dev/null +++ b/LocalCrawler/.eslintignore @@ -0,0 +1,6 @@ +blueprints/**/files/** +coverage/** +node_modules/** +dist/** +*.spec.js +src/index.html diff --git a/LocalCrawler/.eslintrc b/LocalCrawler/.eslintrc new file mode 100644 index 0000000..b4ddbd5 --- /dev/null +++ b/LocalCrawler/.eslintrc @@ -0,0 +1,22 @@ +{ + "extends": "eslint:recommended", + "env": { + "browser": true, + "commonjs": true, + "node": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 2017, + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true + } + }, + "rules": { + "no-console": "off", + "strict": ["error", "global"], + "curly": "warn", + "no-unused-vars": "warn" + } +} \ No newline at end of file diff --git a/LocalCrawler/.gitignore b/LocalCrawler/.gitignore new file mode 100644 index 0000000..2cd8e26 --- /dev/null +++ b/LocalCrawler/.gitignore @@ -0,0 +1,5 @@ +/dist +/logs +/npm-debug.log +/node_modules +.DS_Store diff --git a/LocalCrawler/.vscode/launch.json b/LocalCrawler/.vscode/launch.json new file mode 100644 index 0000000..6e321f6 --- /dev/null +++ b/LocalCrawler/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/debug.js", + "stopOnEntry": false, + "args": [], + "cwd": "${workspaceRoot}", + "preLaunchTask": null, + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "sourceMaps": true, + "outFiles": [] + }, + { + "name": "Attach", + "type": "node", + "request": "attach", + "port": 5858, + "address": "localhost", + "restart": false, + "sourceMaps": false, + "outFiles": [], + "localRoot": "${workspaceRoot}", + "remoteRoot": null + }, + { + "name": "Attach to Process", + "type": "node", + "request": "attach", + "processId": "${command.PickProcess}", + "port": 5858, + "sourceMaps": false, + "outFiles": [] + } + ] +} \ No newline at end of file diff --git a/LocalCrawler/.vscode/settings.json b/LocalCrawler/.vscode/settings.json new file mode 100644 index 0000000..e02dd17 --- /dev/null +++ b/LocalCrawler/.vscode/settings.json @@ -0,0 +1,4 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "javascript.validate.enable": false +} \ No newline at end of file diff --git a/LocalCrawler/Dockerfile b/LocalCrawler/Dockerfile new file mode 100644 index 0000000..dfb86bf --- /dev/null +++ b/LocalCrawler/Dockerfile @@ -0,0 +1,14 @@ +FROM node:8.10 + +# Set a timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +COPY . . +RUN yarn install +RUN yarn run build + +CMD node dist + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f localhost:8082/api/ || exit 1 \ No newline at end of file diff --git a/LocalCrawler/debug.js b/LocalCrawler/debug.js new file mode 100644 index 0000000..eb7b6e6 --- /dev/null +++ b/LocalCrawler/debug.js @@ -0,0 +1,2 @@ +require('babel-register'); +require('./src/index.js'); \ No newline at end of file diff --git a/LocalCrawler/jsconfig.json b/LocalCrawler/jsconfig.json new file mode 100644 index 0000000..0136d6f --- /dev/null +++ b/LocalCrawler/jsconfig.json @@ -0,0 +1,16 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=759670 + // for the documentation about the jsconfig.json format + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "allowSyntheticDefaultImports": true + }, + "exclude": [ + "node_modules", + "bower_components", + "jspm_packages", + "tmp", + "temp" + ] +} diff --git a/LocalCrawler/package.json b/LocalCrawler/package.json new file mode 100644 index 0000000..d5ef4ea --- /dev/null +++ b/LocalCrawler/package.json @@ -0,0 +1,51 @@ +{ + "name": "local-crawler", + "version": "0.1", + "description": "Crawler for local folders", + "main": "dist", + "scripts": { + "dev": "nodemon -w src --exec \"yarn run lint && babel-node src\"", + "build": "yarn run lint && babel src -s -D -d dist", + "start": "node dist", + "prestart": "npm run -s build", + "lint": "eslint --ext js src" + }, + "babel": { + "presets": [ + "es2015", + "stage-0" + ], + "sourceMaps": true, + "retainLines": true + }, + "author": "RD17", + "license": "MIT", + "dependencies": { + "babel-eslint": "^7.1.0", + "babel-polyfill": "^6.26.0", + "body-parser": "^1.13.3", + "bytes": "^3.0.0", + "chokidar": "^2.0.3", + "compression": "^1.5.2", + "cors": "^2.7.1", + "eslint-plugin-babel": "^3.3.0", + "eslint-plugin-promise": "^3.3.0", + "express": "^4.13.3", + "idempotent-babel-polyfill": "^0.1.1", + "moment": "^2.15.0", + "request": "^2.85.0", + "request-promise-native": "^1.0.5", + "resource-router-middleware": "^0.5.1", + "whatwg-url": "^4.7.0" + }, + "devDependencies": { + "babel-cli": "^6.9.0", + "babel-core": "^6.9.0", + "babel-plugin-syntax-flow": "^6.18.0", + "babel-preset-es2015": "^6.9.0", + "babel-preset-stage-0": "^6.5.0", + "babel-register": "^6.18.0", + "eslint": "^3.1.1", + "nodemon": "^1.9.2" + } +} diff --git a/LocalCrawler/src/api/index.js b/LocalCrawler/src/api/index.js new file mode 100644 index 0000000..aa55be0 --- /dev/null +++ b/LocalCrawler/src/api/index.js @@ -0,0 +1,17 @@ +import { version, name, description } from '../../package.json' +import { Router } from 'express' +// import config from '../config' + +export default () => { + let api = Router() + + api.get('/', (req, res) => { + res.json({ + name: name, + version: version, + description: description + }) + }) + + return api +} diff --git a/LocalCrawler/src/config.js b/LocalCrawler/src/config.js new file mode 100644 index 0000000..a01584d --- /dev/null +++ b/LocalCrawler/src/config.js @@ -0,0 +1,25 @@ +const defaultConfig = { + "port": 8082, + "bodyLimit": "10mb", + "crawlPath": "C:\\TEST", + "apiUrl": "http://ambar:8081", + "allowedFilesRegex": '(\\.doc[a-z]*$)|(\\.xls[a-z]*$)|(\\.txt$)|(\\.pst$)|(\\.csv$)|(\\.htm[a-z]*$)|(\\.ppt[a-z]*$)|(\\.pdf$)|(\\.msg$)|(\\.zip$)|(\\.eml$)|(\\.rtf$)|(\\.md$)|(\\.png$)|(\\.bmp$)|(\\.tif[f]*$)|(\\.jp[e]*g$)', + "name": "local_crawler", + "maxFileSize": "30mb" +} + +let config = null + +const init = () => { + config = { ...defaultConfig, ...process.env } + + return config +} + +export default (() => { + return config === null + ? init() + : config +})() + + diff --git a/LocalCrawler/src/index.js b/LocalCrawler/src/index.js new file mode 100644 index 0000000..5aca9e1 --- /dev/null +++ b/LocalCrawler/src/index.js @@ -0,0 +1,34 @@ +import http from 'http' +import express from 'express' +import cors from 'cors' +import bodyParser from 'body-parser' +import api from './api' +import config from './config' + +import 'babel-core/register' +import 'idempotent-babel-polyfill' + +import { FileWatchService, ApiProxy } from './services' + +ApiProxy.logData(config.name, 'info', 'Crawler initialized') +FileWatchService.startWatch() + +let app = express() +app.server = http.createServer(app) + +app.use(cors({ + credentials: true, + origin: true +})) + +app.use(bodyParser.json({ + limit: config.bodyLimit +})) + +// api router +app.use('/api', api()) +app.server.listen(process.env.PORT || config.port) + +console.log(`Started on ${app.server.address().address}:${app.server.address().port}`) + +export default app \ No newline at end of file diff --git a/LocalCrawler/src/services/ApiProxy.js b/LocalCrawler/src/services/ApiProxy.js new file mode 100644 index 0000000..6085ada --- /dev/null +++ b/LocalCrawler/src/services/ApiProxy.js @@ -0,0 +1,113 @@ +import moment from 'moment' +import requestLib from 'request-promise-native' +import fs from 'fs' +import config from '../config' + +const request = requestLib.defaults() + +export const doesParsedContentExist = (sha) => new Promise((resolve, reject) => { + const options = { + uri: `${config.apiUrl}/api/files/content/${encodeURIComponent(sha)}/parsed`, + method: 'HEAD', + simple: false, + resolveWithFullResponse: true + } + + return request(options) + .then(response => { + resolve(response.statusCode === 302) + }) + .catch(err => { + console.log(err) + reject(err) + }) +}) + +export const doesFileMetaExist = (meta) => new Promise((resolve, reject) => { + const options = { + uri: `${config.apiUrl}/api/files/meta/exists`, + method: 'POST', + body: JSON.stringify(meta), + headers: { + 'Content-Type': 'application/json' + }, + simple: false, + resolveWithFullResponse: true + } + + return request(options) + .then(response => { + resolve(response.statusCode === 200) + }) + .catch(err => { + console.log(err) + reject(err) + }) +}) + +export const addFileMeta = (meta, sha, crawlerId) => new Promise((resolve, reject) => { + const options = { + uri: `${config.apiUrl}/api/files/meta/${encodeURIComponent(sha)}/${encodeURIComponent(crawlerId)}`, + method: 'POST', + body: JSON.stringify(meta), + headers: { + 'Content-Type': 'application/json' + } + } + + return request(options) + .then(() => { resolve()}) + .catch(err => { + console.log(err) + reject(err) + }) +}) + +export const addFileContent = (filePath, sha) => new Promise((resolve, reject) => { + const options = { + uri: `${config.apiUrl}/api/files/content/${encodeURIComponent(sha)}`, + method: 'POST', + formData: [ + fs.createReadStream(filePath) + ], + simple: false, + resolveWithFullResponse: true + } + + return request(options) + .then(response => { + resolve(response.statusCode === 304 || response.statusCode === 201) + }) + .catch(err => { + console.log(err) + reject(err) + }) +}) + +export const logData = (sourceId, type, message) => new Promise((resolve, reject) => { + + console.log(`[${type}] ${message}`) + + const record = { + source_id: sourceId, + type: type, + message: message, + created_datetime: moment().format('YYYY-MM-DD HH:mm:ss.SSS') + } + + const options = { + uri: `${config.apiUrl}/api/logs`, + method: 'POST', + body: JSON.stringify(record), + headers: { + 'Content-Type': 'application/json' + } + } + + return request(options) + .then(() => { resolve()}) + .catch(err => { + console.log(err) + reject(err) + }) +}) \ No newline at end of file diff --git a/LocalCrawler/src/services/FileService.js b/LocalCrawler/src/services/FileService.js new file mode 100644 index 0000000..faada57 --- /dev/null +++ b/LocalCrawler/src/services/FileService.js @@ -0,0 +1,15 @@ +import crypto from 'crypto' +import fs from 'fs' + +export const getFileMeta = (path) => fs.stat(path) + +export const getFileSha = (path) => new Promise((resolve) => { + const shaSum = crypto.createHash('sha256') + const readStream = fs.ReadStream(path) + + readStream.on('data', (data) => shaSum.update(data)) + readStream.on('end', () => { + const result = shaSum.digest('hex') + resolve(result) + }) +}) \ No newline at end of file diff --git a/LocalCrawler/src/services/FileWatchService.js b/LocalCrawler/src/services/FileWatchService.js new file mode 100644 index 0000000..111122d --- /dev/null +++ b/LocalCrawler/src/services/FileWatchService.js @@ -0,0 +1,116 @@ +import moment from 'moment' +import chokidar from 'chokidar' +import path from 'path' +import config from '../config' +import bytes from 'bytes' + +import * as ApiProxy from './ApiProxy' +import * as FileService from './FileService' + +const WAIT_MS = 500 + +let tasks = [] + +const allowedFilesRegex = new RegExp(config.allowedFilesRegex, 'gi') + +export const startWatch = () => { + processTasks() + + chokidar.watch(config.crawlPath, { usePolling: true }) + .on('all', (event, pathToFile, stat) => { + if (event === 'add' || event === 'change') { + tasks.push({ event, pathToFile, stat }) + } + }) +} + +const processTasks = async () => { + //eslint-disable-next-line no-constant-condition + while (true) { + if (tasks.length === 0) { + await sleep() + continue + } + + const { pathToFile, stat } = tasks[0] + tasks = tasks.slice(1) + + try { + await tryAddFile(pathToFile, stat) + } catch (err) { + await ApiProxy.logData(config.name, 'error', `failed to submit ${pathToFile}`) + } + } +} + +const sleep = () => new Promise((resolve) => { + setTimeout(() => { + resolve() + }, WAIT_MS) +}) + +const shouldIgnore = (pathToFile, stat) => { + if (!stat) { + return false + } + + const maxFileSizeBytes = bytes.parse(config.maxFileSize) + + if (stat.size === 0) { + return true + } + + if (stat.size > maxFileSizeBytes) { + return true + } + + if (!allowedFilesRegex.test(pathToFile)) { + return true + } + + if (!path.extname(pathToFile)) { + return true + } + + return false +} + +const tryAddFile = async (pathToFile, stat) => { + let normalizedPath = path.normalize(pathToFile) + + normalizedPath = `//${normalizedPath.replace(config.crawlPath, config.name)}`.replace(/\\/g, '/') + + if (shouldIgnore(normalizedPath, stat)) { + await ApiProxy.logData(config.name, 'info', `${normalizedPath} ignoring`) + return + } + + const meta = { + full_name: normalizedPath, + updated_datetime: moment(stat.mtime).format('YYYY-MM-DD HH:mm:ss.SSS'), + created_datetime: moment(stat.atime).format('YYYY-MM-DD HH:mm:ss.SSS'), + source_id: config.name, + short_name: path.basename(normalizedPath), + extension: path.extname(normalizedPath), + extra: [] + } + + const metaExists = await ApiProxy.doesFileMetaExist(meta) + if (metaExists) { + await ApiProxy.logData(config.name, 'info', `${normalizedPath} meta exists`) + return + } + + const sha = await FileService.getFileSha(pathToFile) + const contentExist = await ApiProxy.doesParsedContentExist(sha) + + if (contentExist) { + await ApiProxy.logData(config.name, 'info', `${normalizedPath} - content found`) + } else { + await ApiProxy.addFileContent(pathToFile, sha) + await ApiProxy.logData(config.name, 'info', `${normalizedPath} - content added`) + } + + await ApiProxy.addFileMeta(meta, sha, config.name) + await ApiProxy.logData(config.name, 'info', `${normalizedPath} - meta updated`) +} \ No newline at end of file diff --git a/LocalCrawler/src/services/index.js b/LocalCrawler/src/services/index.js new file mode 100644 index 0000000..014a5ad --- /dev/null +++ b/LocalCrawler/src/services/index.js @@ -0,0 +1,7 @@ +import * as ApiProxy from './ApiProxy' +import * as FileWatchService from './FileWatchService' + +export { + ApiProxy, + FileWatchService +} \ No newline at end of file diff --git a/LocalCrawler/yarn.lock b/LocalCrawler/yarn.lock new file mode 100644 index 0000000..d7dcbc8 --- /dev/null +++ b/LocalCrawler/yarn.lock @@ -0,0 +1,3910 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abbrev@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + +accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +ajv-keywords@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv@^4.7.0: + version "4.11.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.3.tgz#ce30bdb90d1254f762c75af915fb3a63e7183d22" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^4.9.1: + version "4.11.8" + resolved "http://192.168.1.113:4873/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +anymatch@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3: + version "1.1.1" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "http://192.168.1.113:4873/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +array-unique@^0.3.2: + version "0.3.2" + resolved "http://192.168.1.113:4873/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "http://192.168.1.113:4873/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.0.0: + version "2.1.0" + resolved "http://192.168.1.113:4873/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "http://192.168.1.113:4873/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1: + version "1.7.0" + resolved "http://192.168.1.113:4873/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + +aws4@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +babel-cli@^6.9.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.23.0.tgz#52ff946a2b0f64645c35e7bd5eea267aa0948c0f" + dependencies: + babel-core "^6.23.0" + babel-polyfill "^6.23.0" + babel-register "^6.23.0" + babel-runtime "^6.22.0" + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.0.0" + glob "^7.0.0" + lodash "^4.2.0" + output-file-sync "^1.1.0" + path-is-absolute "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + v8flags "^2.0.10" + optionalDependencies: + chokidar "^1.6.1" + +babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +babel-core@^6.23.0, babel-core@^6.9.0: + version "6.23.1" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.23.1.tgz#c143cb621bb2f621710c220c5d579d15b8a442df" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.23.0" + babel-helpers "^6.23.0" + babel-messages "^6.23.0" + babel-register "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.1" + babel-types "^6.23.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-eslint@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.1.tgz#8a6a884f085aa7060af69cfc77341c2f99370fb2" + dependencies: + babel-code-frame "^6.16.0" + babel-traverse "^6.15.0" + babel-types "^6.15.0" + babylon "^6.13.0" + lodash.pickby "^4.6.0" + +babel-generator@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.23.0.tgz#6b8edab956ef3116f79d8c84c5a3c05f32a74bc5" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +babel-helper-bindify-decorators@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.22.0.tgz#d7f5bc261275941ac62acfc4e20dacfb8a3fe952" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-builder-binary-assignment-operator-visitor@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd" + dependencies: + babel-helper-explode-assignable-expression "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-call-delegate@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-define-map@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz#1444f960c9691d69a2ced6a205315f8fd00804e7" + dependencies: + babel-helper-function-name "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-explode-class@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.22.0.tgz#646304924aa6388a516843ba7f1855ef8dfeb69b" + dependencies: + babel-helper-bindify-decorators "^6.22.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6" + dependencies: + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-helper-get-function-arity@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-hoist-variables@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-optimise-call-expression@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz#f3ee7eed355b4282138b33d02b78369e470622f5" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.23.0" + +babel-helper-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz#eeaf8ad9b58ec4337ca94223bacdca1f8d9b4bfd" + dependencies: + babel-helper-optimise-call-expression "^6.23.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-helpers@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-do-expressions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-function-bind@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-generator-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.22.0.tgz#a720a98153a7596f204099cd5409f4b3c05bab46" + dependencies: + babel-helper-remap-async-to-generator "^6.22.0" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e" + dependencies: + babel-helper-remap-async-to-generator "^6.22.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-constructor-call@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.22.0.tgz#11a4d2216abb5b0eef298b493748f4f2f4869120" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-class-properties@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.23.0.tgz#187b747ee404399013563c993db038f34754ac3b" + dependencies: + babel-helper-function-name "^6.23.0" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-plugin-transform-decorators@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.22.0.tgz#c03635b27a23b23b7224f49232c237a73988d27c" + dependencies: + babel-helper-explode-class "^6.22.0" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-do-expressions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb" + dependencies: + babel-plugin-syntax-do-expressions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz#e48895cf0b375be148cd7c8879b422707a053b51" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1" + dependencies: + babel-helper-define-map "^6.23.0" + babel-helper-function-name "^6.23.0" + babel-helper-optimise-call-expression "^6.23.0" + babel-helper-replace-supers "^6.23.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-destructuring@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-for-of@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.23.0.tgz#cba7aa6379fb7ec99250e6d46de2973aaffa7b92" + dependencies: + babel-plugin-transform-strict-mode "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-types "^6.23.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz#ae3469227ffac39b0310d90fec73bfdc4f6317b0" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-plugin-transform-es2015-modules-umd@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.23.0.tgz#8d284ae2e19ed8fe21d2b1b26d6e7e0fcd94f0f1" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" + dependencies: + babel-helper-replace-supers "^6.22.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz#3a2aabb70c8af945d5ce386f1a4250625a83ae3b" + dependencies: + babel-helper-call-delegate "^6.22.0" + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.22.0" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-function-bind@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz#c6fb8e96ac296a310b8cf8ea401462407ddf6a97" + dependencies: + babel-plugin-syntax-function-bind "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" + dependencies: + regenerator-transform "0.9.8" + +babel-plugin-transform-strict-mode@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-polyfill@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" + dependencies: + babel-runtime "^6.22.0" + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "http://192.168.1.113:4873/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-es2015@^6.9.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz#af5a98ecb35eb8af764ad8a5a05eb36dc4386835" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.22.0" + babel-plugin-transform-es2015-classes "^6.22.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-plugin-transform-es2015-modules-systemjs "^6.22.0" + babel-plugin-transform-es2015-modules-umd "^6.22.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.22.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + +babel-preset-stage-0@^6.5.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.22.0.tgz#707eeb5b415da769eff9c42f4547f644f9296ef9" + dependencies: + babel-plugin-transform-do-expressions "^6.22.0" + babel-plugin-transform-function-bind "^6.22.0" + babel-preset-stage-1 "^6.22.0" + +babel-preset-stage-1@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.22.0.tgz#7da05bffea6ad5a10aef93e320cfc6dd465dbc1a" + dependencies: + babel-plugin-transform-class-constructor-call "^6.22.0" + babel-plugin-transform-export-extensions "^6.22.0" + babel-preset-stage-2 "^6.22.0" + +babel-preset-stage-2@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.22.0.tgz#ccd565f19c245cade394b21216df704a73b27c07" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.22.0" + babel-plugin-transform-decorators "^6.22.0" + babel-preset-stage-3 "^6.22.0" + +babel-preset-stage-3@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.22.0.tgz#a4e92bbace7456fafdf651d7a7657ee0bbca9c2e" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.18.0, babel-register@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.23.0.tgz#c9aa3d4cca94b51da34826c4a0f9e08145d74ff3" + dependencies: + babel-core "^6.23.0" + babel-runtime "^6.22.0" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.22.0.tgz#1cf8b4ac67c77a4ddb0db2ae1f74de52ac4ca611" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-runtime@^6.26.0: + version "6.26.0" + resolved "http://192.168.1.113:4873/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.22.0, babel-template@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.15.0, babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1: + version "6.23.1" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48" + dependencies: + babel-code-frame "^6.22.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" + babylon "^6.15.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.15.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf" + dependencies: + babel-runtime "^6.22.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" + +balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +base@^0.11.1: + version "0.11.2" + resolved "http://192.168.1.113:4873/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +body-parser@^1.13.3: + version "1.16.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.16.1.tgz#51540d045adfa7a0c6995a014bb6b1ed9b802329" + dependencies: + bytes "2.4.0" + content-type "~1.0.2" + debug "2.6.1" + depd "~1.1.0" + http-errors "~1.5.1" + iconv-lite "0.4.15" + on-finished "~2.3.0" + qs "6.2.1" + raw-body "~2.2.0" + type-is "~1.6.14" + +boom@2.x.x: + version "2.10.1" + resolved "http://192.168.1.113:4873/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "http://192.168.1.113:4873/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +bytes@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + +bytes@^3.0.0: + version "3.0.0" + resolved "http://192.168.1.113:4873/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + +cache-base@^1.0.1: + version "1.0.1" + resolved "http://192.168.1.113:4873/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.4.3, chokidar@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chokidar@^2.0.3: + version "2.0.3" + resolved "http://192.168.1.113:4873/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.0" + optionalDependencies: + fsevents "^1.1.2" + +circular-json@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +class-utils@^0.3.5: + version "0.3.6" + resolved "http://192.168.1.113:4873/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.8.1: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "http://192.168.1.113:4873/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +compressible@~2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + dependencies: + mime-db ">= 1.24.0 < 2" + +compression@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + dependencies: + accepts "~1.3.3" + bytes "2.3.0" + compressible "~2.0.8" + debug "~2.2.0" + on-headers "~1.0.1" + vary "~1.1.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.6: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" + dependencies: + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + object-assign "^4.0.1" + os-tmpdir "^1.0.0" + osenv "^0.1.0" + uuid "^2.0.1" + write-file-atomic "^1.1.2" + xdg-basedir "^2.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "http://192.168.1.113:4873/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-js@^2.5.0: + version "2.5.5" + resolved "http://192.168.1.113:4873/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@^2.7.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.1.tgz#6181aa56abb45a2825be3304703747ae4e9d2383" + dependencies: + vary "^1" + +cryptiles@2.x.x: + version "2.0.5" + resolved "http://192.168.1.113:4873/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + +d@^0.1.1, d@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + dependencies: + es5-ext "~0.10.2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@2.6.1, debug@^2.1.1, debug@^2.2.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" + dependencies: + ms "0.7.2" + +debug@^2.3.3: + version "2.6.9" + resolved "http://192.168.1.113:4873/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "http://192.168.1.113:4873/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +define-property@^0.2.5: + version "0.2.5" + resolved "http://192.168.1.113:4873/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "http://192.168.1.113:4873/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "http://192.168.1.113:4873/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +duplexify@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604" + dependencies: + end-of-stream "1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +end-of-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e" + dependencies: + once "~1.3.0" + +es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: + version "0.10.12" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + dependencies: + d "^0.1.1" + es5-ext "^0.10.7" + es6-symbol "3" + +es6-map@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-set "~0.1.3" + es6-symbol "~3.1.0" + event-emitter "~0.3.4" + +es6-promise@^3.0.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + +es6-set@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-symbol "3" + event-emitter "~0.3.4" + +es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + +es6-weak-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + dependencies: + d "^0.1.1" + es5-ext "^0.10.8" + es6-iterator "2" + es6-symbol "3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-plugin-babel@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-3.3.0.tgz#2f494aedcf6f4aa4e75b9155980837bc1fbde193" + +eslint-plugin-promise@^3.3.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.4.1.tgz#6911a9010bf84e17d82e19e0ab0f80ab3ad6db4c" + +eslint@^3.1.1: + version "3.15.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.15.0.tgz#bdcc6a6c5ffe08160e7b93c066695362a91e30f2" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + escope "^3.6.0" + espree "^3.4.0" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.14.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~2.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" + dependencies: + acorn "4.0.4" + acorn-jsx "^3.0.0" + +esprima@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-emitter@~0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.7" + +event-stream@~3.3.0: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "http://192.168.1.113:4873/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express@^4.13.3: + version "4.14.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.14.1.tgz#646c237f766f148c2120aff073817b9e4d7e0d33" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.2" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "~2.2.0" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + finalhandler "0.5.1" + fresh "0.3.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.3" + qs "6.2.0" + range-parser "~1.2.0" + send "0.14.2" + serve-static "~1.11.2" + type-is "~1.6.14" + utils-merge "1.0.0" + vary "~1.1.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "http://192.168.1.113:4873/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "http://192.168.1.113:4873/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.0, extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "http://192.168.1.113:4873/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.1.tgz#2c400d8d4530935bc232549c5fa385ec07de6fcd" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + statuses "~1.3.1" + unpipe "~1.0.0" + +flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-in@^1.0.2: + version "1.0.2" + resolved "http://192.168.1.113:4873/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "http://192.168.1.113:4873/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "http://192.168.1.113:4873/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +from@~0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc" + +fs-readdir-recursive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.17" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.17.tgz#8537f3f12272678765b4fd6528c0f1f66f8f4558" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fsevents@^1.1.2: + version "1.1.3" + resolved "http://192.168.1.113:4873/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.39" + +fstream-ignore@^1.0.5, fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +fstream@^1.0.10: + version "1.0.11" + resolved "http://192.168.1.113:4873/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gauge@~2.7.3: + version "2.7.4" + resolved "http://192.168.1.113:4873/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "http://192.168.1.113:4873/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.0.0, globals@^9.14.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" + dependencies: + duplexify "^3.2.0" + infinity-agent "^2.0.0" + is-redirect "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + nested-error-stacks "^1.0.0" + object-assign "^3.0.0" + prepend-http "^1.0.0" + read-all-stream "^3.0.0" + timed-out "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +har-schema@^1.0.5: + version "1.0.5" + resolved "http://192.168.1.113:4873/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~4.2.1: + version "4.2.1" + resolved "http://192.168.1.113:4873/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "http://192.168.1.113:4873/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "http://192.168.1.113:4873/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hawk@3.1.3, hawk@~3.1.3: + version "3.1.3" + resolved "http://192.168.1.113:4873/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "http://192.168.1.113:4873/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +http-errors@~1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-signature@~1.1.0: + version "1.1.1" + resolved "http://192.168.1.113:4873/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + +idempotent-babel-polyfill@^0.1.1: + version "0.1.1" + resolved "http://192.168.1.113:4873/idempotent-babel-polyfill/-/idempotent-babel-polyfill-0.1.1.tgz#f85d2ecaf36b05a652457b25c804289512360d94" + dependencies: + babel-polyfill "^6.26.0" + +ignore-by-default@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +ignore@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.2.tgz#1c51e1ef53bab6ddc15db4d9ac4ec139eceb3410" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +infinity-agent@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +interpret@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + +invariant@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +ipaddr.js@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "http://192.168.1.113:4873/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "http://192.168.1.113:4873/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "http://192.168.1.113:4873/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "http://192.168.1.113:4873/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "http://192.168.1.113:4873/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "http://192.168.1.113:4873/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "http://192.168.1.113:4873/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-my-json-valid@^2.10.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "http://192.168.1.113:4873/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-odd@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "http://192.168.1.113:4873/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-windows@^1.0.2: + version "1.0.2" + resolved "http://192.168.1.113:4873/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "http://192.168.1.113:4873/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + +js-yaml@^3.5.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.1.tgz#782ba50200be7b9e5a8537001b7804db3ad02628" + dependencies: + argparse "^1.0.7" + esprima "^3.1.1" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + +kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "http://192.168.1.113:4873/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "http://192.168.1.113:4873/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "http://192.168.1.113:4873/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +latest-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" + dependencies: + package-json "^1.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.assign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.defaults@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" + dependencies: + lodash.assign "^3.0.0" + lodash.restparam "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.pickby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +map-cache@^0.2.2: + version "0.2.2" + resolved "http://192.168.1.113:4873/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +map-visit@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.4: + version "3.1.10" + resolved "http://192.168.1.113:4873/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +"mime-db@>= 1.24.0 < 2": + version "1.26.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" + +mime-db@~1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" + +mime-db@~1.33.0: + version "1.33.0" + resolved "http://192.168.1.113:4873/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.17: + version "2.1.17" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" + dependencies: + mime-db "~1.30.0" + +mime-types@~2.1.7: + version "2.1.18" + resolved "http://192.168.1.113:4873/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + +mime@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +minimatch@^3.0.0, minimatch@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "http://192.168.1.113:4873/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment@^2.15.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +ms@2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +nan@^2.3.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" + +nanomatch@^1.2.9: + version "1.2.9" + resolved "http://192.168.1.113:4873/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-odd "^2.0.0" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +nested-error-stacks@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf" + dependencies: + inherits "~2.0.1" + +node-pre-gyp@^0.6.29: + version "0.6.33" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.33.tgz#640ac55198f6a925972e0c16c4ac26a034d5ecc9" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +node-pre-gyp@^0.6.39: + version "0.6.39" + resolved "http://192.168.1.113:4873/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" + dependencies: + detect-libc "^1.0.2" + hawk "3.1.3" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +nodemon@^1.9.2: + version "1.11.0" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c" + dependencies: + chokidar "^1.4.3" + debug "^2.2.0" + es6-promise "^3.0.2" + ignore-by-default "^1.0.0" + lodash.defaults "^3.1.2" + minimatch "^3.0.0" + ps-tree "^1.0.1" + touch "1.0.0" + undefsafe "0.0.3" + update-notifier "0.5.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "http://192.168.1.113:4873/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "http://192.168.1.113:4873/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npmlog@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "http://192.168.1.113:4873/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1, oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "http://192.168.1.113:4873/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "http://192.168.1.113:4873/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "http://192.168.1.113:4873/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.0: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +osenv@^0.1.4: + version "0.1.5" + resolved "http://192.168.1.113:4873/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +package-json@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0" + dependencies: + got "^3.2.0" + registry-url "^3.0.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "http://192.168.1.113:4873/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "http://192.168.1.113:4873/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + +performance-now@^0.2.0: + version "0.2.0" + resolved "http://192.168.1.113:4873/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "http://192.168.1.113:4873/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6: + version "0.1.7" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +proxy-addr@~1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.2.0" + +ps-tree@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + dependencies: + event-stream "~3.3.0" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +qs@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" + +qs@~6.4.0: + version "6.4.0" + resolved "http://192.168.1.113:4873/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.15" + unpipe "1.0.0" + +rc@^1.0.1, rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +rc@^1.1.7: + version "1.2.6" + resolved "http://192.168.1.113:4873/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-all-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" + dependencies: + pinkie-promise "^2.0.0" + readable-stream "^2.0.0" + +readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@^2.1.4: + version "2.3.6" + resolved "http://192.168.1.113:4873/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "http://192.168.1.113:4873/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "http://192.168.1.113:4873/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "http://192.168.1.113:4873/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +registry-url@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "http://192.168.1.113:4873/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.5: + version "1.0.5" + resolved "http://192.168.1.113:4873/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + +request@2.81.0: + version "2.81.0" + resolved "http://192.168.1.113:4873/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +request@^2.79.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +request@^2.85.0: + version "2.85.0" + resolved "http://192.168.1.113:4873/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "http://192.168.1.113:4873/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" + +resource-router-middleware@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/resource-router-middleware/-/resource-router-middleware-0.5.1.tgz#cceba87013a73e6daf55e612b7e8eb10ffa9381a" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "http://192.168.1.113:4873/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +rimraf@^2.5.1, rimraf@^2.6.1: + version "2.6.2" + resolved "http://192.168.1.113:4873/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "http://192.168.1.113:4873/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +semver@^5.0.3, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +semver@^5.3.0: + version "5.5.0" + resolved "http://192.168.1.113:4873/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +send@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.2.tgz#39b0438b3f510be5dc6f667a11f71689368cdeef" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.5.1" + mime "1.3.4" + ms "0.7.2" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + +serve-static@~1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.2.tgz#2cf9889bd4435a320cc36895c9aa57bd662e6ac7" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.14.2" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "http://192.168.1.113:4873/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + +shelljs@^0.7.5: + version "0.7.6" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "http://192.168.1.113:4873/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "http://192.168.1.113:4873/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "http://192.168.1.113:4873/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sntp@1.x.x: + version "1.0.9" + resolved "http://192.168.1.113:4873/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + +source-map-resolve@^0.5.0: + version "0.5.1" + resolved "http://192.168.1.113:4873/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + dependencies: + atob "^2.0.0" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.2: + version "0.4.11" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322" + dependencies: + source-map "^0.5.3" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "http://192.168.1.113:4873/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.0, source-map@^0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@^0.5.6: + version "0.5.7" + resolved "http://192.168.1.113:4873/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "http://192.168.1.113:4873/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "http://192.168.1.113:4873/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.3.1 < 2", statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +string-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" + dependencies: + strip-ansi "^3.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "http://192.168.1.113:4873/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4, stringstream@~0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tar-pack@^3.4.0: + version "3.4.1" + resolved "http://192.168.1.113:4873/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@^2.2.1, tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through@2, through@^2.3.6, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "http://192.168.1.113:4873/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "http://192.168.1.113:4873/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "http://192.168.1.113:4873/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +touch@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de" + dependencies: + nopt "~1.0.10" + +tough-cookie@>=2.3.3, tough-cookie@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" + dependencies: + punycode "^1.4.1" + +tough-cookie@~2.3.0: + version "2.3.4" + resolved "http://192.168.1.113:4873/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-is@~1.6.14: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uid-number@^0.0.6, uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +undefsafe@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" + +union-value@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unset-value@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.0.0: + version "1.0.4" + resolved "http://192.168.1.113:4873/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" + +update-notifier@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc" + dependencies: + chalk "^1.0.0" + configstore "^1.0.0" + is-npm "^1.0.0" + latest-version "^1.0.0" + repeating "^1.1.2" + semver-diff "^2.0.0" + string-length "^1.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "http://192.168.1.113:4873/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +use@^3.1.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" + dependencies: + kind-of "^6.0.2" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.0.0: + version "3.2.1" + resolved "http://192.168.1.113:4873/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +uuid@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + +v8flags@^2.0.10: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + +vary@^1, vary@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + +whatwg-url@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5" + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^1.1.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +xdg-basedir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + dependencies: + os-homedir "^1.0.0" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" diff --git a/MongoDB/.gitignore b/MongoDB/.gitignore new file mode 100644 index 0000000..eb87e33 --- /dev/null +++ b/MongoDB/.gitignore @@ -0,0 +1,371 @@ + +# Created by https://www.gitignore.io/api/python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +.venv/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.vcxproj.filters + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ +Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ + diff --git a/MongoDB/Dockerfile b/MongoDB/Dockerfile new file mode 100644 index 0000000..0497979 --- /dev/null +++ b/MongoDB/Dockerfile @@ -0,0 +1,74 @@ +FROM debian:jessie + +# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added +RUN groupadd -r mongodb && useradd -r -g mongodb mongodb + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + numactl \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Set a timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# grab gosu for easy step-down from root +ENV GOSU_VERSION 1.7 +RUN set -x \ + && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \ + && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \ + && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \ + && export GNUPGHOME="$(mktemp -d)" \ + && gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \ + && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \ + && rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \ + && chmod +x /usr/local/bin/gosu \ + && gosu nobody true \ + && apt-get purge -y --auto-remove ca-certificates wget + +ENV GPG_KEYS \ +# pub 4096R/A15703C6 2016-01-11 [expires: 2018-01-10] +# Key fingerprint = 0C49 F373 0359 A145 1858 5931 BC71 1F9B A157 03C6 +# uid MongoDB 3.4 Release Signing Key + 0C49F3730359A14518585931BC711F9BA15703C6 +RUN set -ex; \ + export GNUPGHOME="$(mktemp -d)"; \ + for key in $GPG_KEYS; do \ + gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \ + done; \ + gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mongodb.gpg; \ + rm -r "$GNUPGHOME"; \ + apt-key list + +ENV MONGO_MAJOR 3.4 +ENV MONGO_VERSION 3.4.2 +ENV MONGO_PACKAGE mongodb-org + +RUN echo "deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/$MONGO_MAJOR main" > /etc/apt/sources.list.d/mongodb-org.list + +RUN set -x \ + && apt-get update \ + && apt-get install -y \ + ${MONGO_PACKAGE}=$MONGO_VERSION \ + ${MONGO_PACKAGE}-server=$MONGO_VERSION \ + ${MONGO_PACKAGE}-shell=$MONGO_VERSION \ + ${MONGO_PACKAGE}-mongos=$MONGO_VERSION \ + ${MONGO_PACKAGE}-tools=$MONGO_VERSION \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /var/lib/mongodb \ + && mv /etc/mongod.conf /etc/mongod.conf.orig \ + && touch /etc/mongod.conf \ + && chown mongodb:mongodb /etc/mongod.conf + +RUN mkdir -p /data/db /data/configdb \ + && chown -R mongodb:mongodb /data/db /data/configdb +VOLUME /data/db /data/configdb + +COPY docker-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +CMD ["/entrypoint.sh"] + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f localhost:27017 || exit 1 \ No newline at end of file diff --git a/MongoDB/docker-entrypoint.sh b/MongoDB/docker-entrypoint.sh new file mode 100644 index 0000000..eac945e --- /dev/null +++ b/MongoDB/docker-entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +echo "storage:" > /etc/mongod.conf +echo " wiredTiger:" >> /etc/mongod.conf +echo " engineConfig:" >> /etc/mongod.conf +echo " cacheSizeGB: ${cacheSizeGB}" >> /etc/mongod.conf + +exec mongod --config /etc/mongod.conf \ No newline at end of file diff --git a/Pipeline/.vscode/settings.json b/Pipeline/.vscode/settings.json new file mode 100644 index 0000000..3af58ad --- /dev/null +++ b/Pipeline/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.linting.pylintEnabled": false, + "python.formatting.provider": "yapf" +} \ No newline at end of file diff --git a/Pipeline/Dockerfile b/Pipeline/Dockerfile new file mode 100644 index 0000000..f7119a3 --- /dev/null +++ b/Pipeline/Dockerfile @@ -0,0 +1,42 @@ +FROM python:3 + +RUN apt-get update && apt-get install -y \ + curl \ + gcc \ + imagemagick \ + libleptonica-dev \ + tesseract-ocr \ + tesseract-ocr-dev \ + libtesseract3 \ + libtesseract-dev \ + tesseract-ocr-eng \ + tesseract-ocr-rus \ + tesseract-ocr-ita \ + tesseract-ocr-deu \ + tesseract-ocr-fra \ + tesseract-ocr-spa \ + tesseract-ocr-nld \ + tesseract-ocr-pol \ + default-jre \ + default-jdk \ + readpst + +# Set timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +COPY . . + +RUN pip install --no-cache-dir -r requirements.txt +RUN pip install git+git://github.com/kivy/pyjnius.git + +RUN mv jars/* /usr/lib/jvm/default-java/jre/lib/ext/ + +RUN mkdir /pst-temp + +ENV JAVA_HOME /usr/lib/jvm/default-java + +CMD python ./pipeline.py -id $id -api_url $api_url -rabbit_host $rabbit_host + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD if (pidof -x python > /dev/null) then (exit 0) else (exit 1) fi \ No newline at end of file diff --git a/Pipeline/apiproxy.py b/Pipeline/apiproxy.py new file mode 100644 index 0000000..37d1559 --- /dev/null +++ b/Pipeline/apiproxy.py @@ -0,0 +1,340 @@ +import io +import re +import requests + +class ApiProxy: + def __init__(self, ApiUrl, ApiCallTimeoutSeconds): + self.apiUrl = ApiUrl + self.apiCallTimeoutSeconds = ApiCallTimeoutSeconds + + def GetTaggingRules(self): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/tags/service/taggingrules'.format(self.apiUrl) + req = requests.get(apiUri, timeout = self.apiCallTimeoutSeconds) + if req.status_code == 200: + try: + apiResp.payload = req.json() + except: + apiResp.result = 'error' + apiResp.message = str(ex) + else: + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def IndexLogRecord(self, AmbarLogRecord): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/logs'.format(self.apiUrl) + req = requests.post(apiUri, json = AmbarLogRecord.Dict, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def CheckIfParsedAmbarFileContentExists(self, Sha): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/content/{1}/parsed'.format(self.apiUrl, Sha) + req = requests.head(apiUri, timeout = self.apiCallTimeoutSeconds) + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def CreateAmbarFileContent(self, FileData, Sha256): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/content/{1}'.format(self.apiUrl, Sha256) + files = {'file': (Sha256, FileData)} + req = requests.post(apiUri, files = files, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def RemoveFileContent(self, sha): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/content/{1}'.format(self.apiUrl, sha) + req = requests.delete(apiUri, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def GetFileContent(self, sha): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/content/{1}'.format(self.apiUrl, sha) + req = requests.get(apiUri, timeout = self.apiCallTimeoutSeconds) + if req.status_code == 200: + contentDispositionHeader = req.headers['content-disposition'] + reRes = re.search("filename\*=UTF-8\'\'(.+)", contentDispositionHeader) + if reRes: + apiResp.sha = reRes.group(1) + apiResp.payload = req.content + else: + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def GetParsedFileContent(self, Sha): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/content/{1}/parsed'.format(self.apiUrl, Sha) + req = requests.get(apiUri, timeout = self.apiCallTimeoutSeconds) + if req.status_code == 200: + contentDispositionHeader = req.headers['content-disposition'] + reRes = re.search("filename\*=UTF-8\'\'(.+)", contentDispositionHeader) + if reRes: + apiResp.sha = reRes.group(1) + apiResp.payload = req.content + else: + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def GetParsedFileContentFields(self, Sha): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/content/{1}/fields'.format(self.apiUrl, Sha) + req = requests.get(apiUri, timeout = self.apiCallTimeoutSeconds) + if req.status_code == 200: + try: + apiResp.payload = req.json() + except: + apiResp.result = 'error' + apiResp.message = str(ex) + else: + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def EnqueueAmbarFileMeta(self, AmbarFileMeta, Sha, CrawlerId): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/meta/{1}/{2}'.format(self.apiUrl, Sha, CrawlerId) + req = requests.post(apiUri, json = AmbarFileMeta.Dict, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def SubmitProcessedFile(self, FileId, AmbarFileBytes): + apiResp = RestApiResponse() + try: + files = {'file': (FileId, AmbarFileBytes)} + apiUri = '{0}/api/files/file/{1}/processed'.format(self.apiUrl, FileId) + req = requests.post(apiUri, files=files, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def RemoveAutoTags(self, FileId): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/files/autotags/{1}'.format(self.apiUrl, FileId) + req = requests.delete(apiUri, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def AddFileTag(self, FileId, TagType, TagName): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/tags/service/{1}/{2}/{3}'.format(self.apiUrl, FileId, TagType, TagName) + req = requests.post(apiUri, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def CallExternalNER(self, ExternalNERUri, FileId, Sha): + apiResp = RestApiResponse() + try: + body = { 'fileId': FileId, 'sha': Sha } + req = requests.post(ExternalNERUri, json=body, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def SubmitExtractedContent(self, Sha256, AmbarFileContentTextBytes): + apiResp = RestApiResponse() + try: + files = {'file': (Sha256, AmbarFileContentTextBytes)} + apiUri = '{0}/api/files/content/{1}/extracted'.format(self.apiUrl, Sha256) + req = requests.post(apiUri, files=files, timeout = self.apiCallTimeoutSeconds) + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def SubmitThumbnail(self, ThumbId, ThumbData): + apiResp = RestApiResponse() + try: + files = {'file': (ThumbId, ThumbData)} + apiUri = '{0}/api/thumbs/{1}'.format(self.apiUrl, ThumbId) + req = requests.post(apiUri, files=files, timeout = self.apiCallTimeoutSeconds) + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + + def GetAmbarCrawlerFileRegex(self, CrawlerId): + apiResp = RestApiResponse() + try: + apiUri = '{0}/api/crawlers/{1}'.format(self.apiUrl, CrawlerId) + req = requests.get(apiUri, timeout = self.apiCallTimeoutSeconds) + if req.status_code == 200: + try: + apiResp.payload = req.json()['file_regex'] + except: + apiResp.result = 'error' + apiResp.message = str(ex) + else: + try: + apiResp.message = req.text + except: + pass + apiResp.result = 'ok' + apiResp.code = req.status_code + except requests.exceptions.RequestException as ex: + apiResp.result = 'error' + apiResp.message = str(ex) + return apiResp + +class RestApiResponse: + def __init__(self): + self.result = 'ok' + self.code = 0 + self.payload = None + self.message = None + + @property + def Success(self): + return True if self.result == 'ok' else False + @property + def Error(self): + return True if self.result == 'error' else False + + @property + def Ok(self): + return True if self.code == 200 else False + @property + def Created(self): + return True if self.code == 201 else False + @property + def NoContent(self): + return True if self.code == 204 else False + @property + def Found(self): + return True if self.code == 302 else False + @property + def BadRequest(self): + return True if self.code == 400 else False + @property + def Unauthorized(self): + return True if self.code == 401 else False + @property + def NotFound(self): + return True if self.code == 404 else False + @property + def Conflict(self): + return True if self.code == 409 else False + @property + def InternalServerError(self): + return True if self.code == 500 else False + @property + def InsufficientStorage(self): + return True if self.code == 507 else False \ No newline at end of file diff --git a/Pipeline/containerprocessors/__init__.py b/Pipeline/containerprocessors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Pipeline/containerprocessors/archiveprocessor.py b/Pipeline/containerprocessors/archiveprocessor.py new file mode 100644 index 0000000..c13eba5 --- /dev/null +++ b/Pipeline/containerprocessors/archiveprocessor.py @@ -0,0 +1,106 @@ +from model import AmbarFileMeta, AmbarFileContent +from zipfile import ZipFile, ZipInfo +from datetime import datetime +from hashlib import sha256 +import hashlib +import re +import io + +class ArchiveProcessor(): + def __init__(self, Logger, ApiProxy): + self.logger = Logger + self.apiProxy = ApiProxy + + def Process(self, FileData, FileMeta, SourceId): + self.logger.LogMessage('verbose','unzipping {0}'.format(FileMeta.full_name)) + + ##TODO: Get fileRegex from crawler settings + fileRegex = re.compile('(\\.doc[a-z]*$)|(\\.xls[a-z]*$)|(\\.txt$)|(\\.csv$)|(\\.htm[a-z]*$)|(\\.ppt[a-z]*$)|(\\.pdf$)|(\\.msg$)|(\\.zip$)|(\\.eml$)|(\\.rtf$)|(\\.md$)|(\\.png$)|(\\.bmp$)|(\\.tif[f]*$)|(\\.jp[e]*g$)',re.I) + + try: + with ZipFile(io.BytesIO(FileData)) as zipFile: + for zipFileInfo in zipFile.infolist(): + try: + unicodeName = zipFileInfo.filename.encode('CP437').decode('CP866') + except: + unicodeName = zipFileInfo.filename + + if not fileRegex.search(unicodeName): + self.logger.LogMessage('verbose','ignoring {0}/{1}'.format(FileMeta.full_name, unicodeName)) + continue + + fullNameInArchive = '{0}/{1}'.format(FileMeta.full_name, unicodeName) + createUpdateTime = datetime( + zipFileInfo.date_time[0], + zipFileInfo.date_time[1], + zipFileInfo.date_time[2], + zipFileInfo.date_time[3], + zipFileInfo.date_time[4], + zipFileInfo.date_time[5]) + + fileData=zipFile.open(zipFileInfo.filename).read() + sha = sha256(fileData).hexdigest() + size = zipFileInfo.file_size + + if size == 0: + continue + + ## checking content existance + apiResp = self.apiProxy.CheckIfParsedAmbarFileContentExists(sha) + + if not apiResp.Success: + self.logger.LogMessage('error', 'error checking content existance {0} {1}'.format(fullNameInArchive, apiResp.message)) + continue + + if not (apiResp.Found or apiResp.NotFound): + self.logger.LogMessage('error', 'unexpected response on checking content existance {0} {1} {2}'.format(fullNameInArchive, apiResp.code, apiResp.message)) + continue + + if apiResp.NotFound: + self.logger.LogMessage('verbose', 'content not found {0}'.format(fullNameInArchive)) + + ## creating content + createContentApiResp = self.apiProxy.CreateAmbarFileContent(fileData, sha) + + if not createContentApiResp.Success: + self.logger.LogMessage('error', 'error creating content {0} {1}'.format(fullNameInArchive, createContentApiResp.message)) + continue + + if not (createContentApiResp.Found or createContentApiResp.Created): + self.logger.LogMessage('error', 'unexpected response on create content {0} {1} {2}'.format(fullNameInArchive, createContentApiResp.code, createContentApiResp.message)) + continue + + if createContentApiResp.Found: + self.logger.LogMessage('verbose', 'content found {0}'.format(fullNameInArchive)) + + if createContentApiResp.Created: + self.logger.LogMessage('verbose', 'content created {0}'.format(fullNameInArchive)) + + if apiResp.Found: + self.logger.LogMessage('verbose', 'content found {0}'.format(fullNameInArchive)) + + ## sending meta back to queue + fileMeta = AmbarFileMeta.InitWithoutId(createUpdateTime, createUpdateTime, unicodeName, fullNameInArchive, FileMeta.source_id) + + apiResp = self.apiProxy.EnqueueAmbarFileMeta(fileMeta, sha, SourceId) + + if not apiResp.Success: + self.logger.LogMessage('error', 'error adding meta {0} {1}'.format(fileMeta.full_name, apiResp.message)) + continue + + if apiResp.BadRequest: + self.logger.LogMessage('verbose', 'bad meta, ignoring... {0}'.format(fileMeta.full_name)) + continue + + if apiResp.InsufficientStorage: + self.logger.LogMessage('verbose', 'insufficient storage'.format(fileMeta.full_name)) + continue + + if not apiResp.Ok: + self.logger.LogMessage('error', 'unexpected response on adding meta {0} {1} {2}'.format(fileMeta.full_name, apiResp.code, apiResp.message)) + continue + + self.logger.LogMessage('verbose', 'meta added {0}'.format(fileMeta.full_name)) + + except Exception as ex: + self.logger.LogMessage('info','unable to unpack {0} {1}'.format(FileMeta.full_name, ex)) \ No newline at end of file diff --git a/Pipeline/containerprocessors/pstprocessor.py b/Pipeline/containerprocessors/pstprocessor.py new file mode 100644 index 0000000..0b005c0 --- /dev/null +++ b/Pipeline/containerprocessors/pstprocessor.py @@ -0,0 +1,166 @@ +from model import AmbarFileMeta, AmbarFileContent +from datetime import datetime +from hashlib import sha256 +from subprocess import call +from os import walk, path +import hashlib +import re +import io + +class PstProcessor(): + def __init__(self, Logger, ApiProxy): + self.logger = Logger + self.apiProxy = ApiProxy + + self.tempPath = '/pst-temp' + self.pstFileName = 'archive.pst' + + def CleanUpTemp(self): + retcode = -1 + try: + retcode = call('rm -rf {0}/*'.format(self.tempPath), shell=True) + + if retcode != 0: + self.logger.LogMessage('info', 'error cleaning temp dir, code: {0}'.format(retcode)) + return False + except Exception as e: + self.logger.LogMessage('info', 'error cleaning temp dir') + return False + + return True + + def ExtractPstArchive(self): + retcode = -1 + + cmd = 'readpst -o {0} -D -j 1 -r -tea -u -w -e {0}/{1}'.format(self.tempPath, self.pstFileName) + + try: + retcode = call(cmd, shell=True) + + if retcode != 0: + self.logger.LogMessage('info', 'error extracting pst, code: {0}'.format(retcode)) + return False + except Exception as e: + self.logger.LogMessage('error', 'error extracting pst {0}'.format(repr(e))) + return False + + return True + + def WriteFileData(self, FileData): + try: + f = open('{0}/{1}'.format(self.tempPath, self.pstFileName), 'wb') + f.write(FileData) + f.close() + except Exception as e: + self.logger.LogMessage('error', 'error writing file {0}'.format(repr(e))) + return False + + return True + + def ReadFileData(self, FilePath): + try: + f = open(FilePath, 'rb') + fileData = f.read() + f.close() + return fileData + except Exception as e: + self.logger.LogMessage('error', 'error reading file {0} {1}'.format(FilePath, e)) + + return None + + def Process(self, FileData, FileMeta, SourceId): + self.logger.LogMessage('verbose', 'processing pst archive {0}'.format(FileMeta.full_name)) + + try: + if not self.CleanUpTemp(): + return + + if not self.WriteFileData(FileData): + return + + if not self.ExtractPstArchive(): + return + + for (dirpath, dirnames, filenames) in walk(self.tempPath): + for fileName in filenames: + self.logger.LogMessage('verbose', 'enqueuing file {0} from pst archive {1}'.format(fileName, FileMeta.full_name)) + + fullNameInArchive = '{0}{1}'.format(FileMeta.full_name, path.join(dirpath.replace(self.tempPath,''), fileName)) + fullNameInFs = path.join(dirpath, fileName) + + fileData = self.ReadFileData(fullNameInFs) + + if not fileData: + continue + + sha = sha256(fileData).hexdigest() + size = len(fileData) + + if size == 0: + continue + + # checking content existance + apiResp = self.apiProxy.CheckIfParsedAmbarFileContentExists(sha) + + if not apiResp.Success: + self.logger.LogMessage('error', 'error checking content existance {0} {1}'.format(fullNameInArchive, apiResp.message)) + continue + + if not (apiResp.Found or apiResp.NotFound): + self.logger.LogMessage('error', 'unexpected response on checking content existance {0} {1} {2}'.format(fullNameInArchive, apiResp.code, apiResp.message)) + continue + + if apiResp.NotFound: + self.logger.LogMessage( + 'verbose', 'content not found {0}'.format(fullNameInArchive)) + + # creating content + createContentApiResp = self.apiProxy.CreateAmbarFileContent(fileData, sha) + + if not createContentApiResp.Success: + self.logger.LogMessage('error', 'error creating content {0} {1}'.format(fullNameInArchive, createContentApiResp.message)) + continue + + if not (createContentApiResp.Found or createContentApiResp.Created): + self.logger.LogMessage('error', 'unexpected response on create content {0} {1} {2}'.format(fullNameInArchive, createContentApiResp.code, createContentApiResp.message)) + continue + + if createContentApiResp.Found: + self.logger.LogMessage('verbose', 'content found {0}'.format(fullNameInArchive)) + + if createContentApiResp.Created: + self.logger.LogMessage('verbose', 'content created {0}'.format(fullNameInArchive)) + + if apiResp.Found: + self.logger.LogMessage('verbose', 'content found {0}'.format(fullNameInArchive)) + + # sending meta back to queue + fileMeta = AmbarFileMeta.InitWithoutId(FileMeta.created_datetime, FileMeta.updated_datetime, fileName, fullNameInArchive, FileMeta.source_id) + + apiResp = self.apiProxy.EnqueueAmbarFileMeta( + fileMeta, sha, SourceId) + + if not apiResp.Success: + self.logger.LogMessage('error', 'error adding meta {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + continue + + if apiResp.BadRequest: + self.logger.LogMessage('verbose', 'bad meta, ignoring... {0}'.format(fileMeta.full_name)) + continue + + if apiResp.InsufficientStorage: + self.logger.LogMessage('verbose', 'insufficient storage'.format(fileMeta.full_name)) + continue + + if not apiResp.Ok: + self.logger.LogMessage('error', 'unexpected response on adding meta {0} {1} {2}'.format(fileMeta.full_name, apiResp.code, apiResp.message)) + continue + + self.logger.LogMessage('verbose', 'meta added {0}'.format(fileMeta.full_name)) + + self.CleanUpTemp() + + except Exception as ex: + self.logger.LogMessage( + 'info', 'unable to unpack {0} {1}'.format(FileMeta.full_name, ex)) diff --git a/Pipeline/contentprocessors/__init__.py b/Pipeline/contentprocessors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Pipeline/contentprocessors/autotagger.py b/Pipeline/contentprocessors/autotagger.py new file mode 100644 index 0000000..5cdf5a4 --- /dev/null +++ b/Pipeline/contentprocessors/autotagger.py @@ -0,0 +1,84 @@ +from model import AmbarTaggingRule +from apiproxy import ApiProxy +from logger import AmbarLogger +from parsers.contenttypeanalyzer import ContentTypeAnalyzer +import re + +class AutoTagger: + def __init__(self, Logger, ApiProxy): + self.logger = Logger + self.apiProxy = ApiProxy + self.AUTO_TAG_TYPE = 'auto' + self.SOURCE_TAG_TYPE = 'source' + + def AutoTagAmbarFile(self, AmbarFile): + self.SetOCRTag(AmbarFile) + self.SetSourceIdTag(AmbarFile) + self.SetArchiveTag(AmbarFile) + self.SetImageTag(AmbarFile) + + for rule in self.GetTaggingRules(): + self.ProcessTaggingRule(rule, AmbarFile) + + def ProcessTaggingRule(self, TaggingRuleToProcess, AmbarFile): + try: + if TaggingRuleToProcess.field == 'content': + match = re.search(TaggingRuleToProcess.regex, AmbarFile['content']['text']) + elif TaggingRuleToProcess.field == 'path': + match = re.search(TaggingRuleToProcess.regex, AmbarFile['meta']['full_name']) + else: + self.logger.LogMessage('error', 'error applying autotagging rule {0}, no such field known {1}'.format(TaggingRuleToProcess.name, TaggingRuleToProcess.field)) + return + + if match: + for tag in TaggingRuleToProcess.tags: + self.AddTagToAmbarFile(AmbarFile['file_id'], AmbarFile['meta']['full_name'], self.AUTO_TAG_TYPE, tag) + except Exception as ex: + self.logger.LogMessage('error', 'error applying autotagging rule {0} to {1} {2}'.format(TaggingRuleToProcess.name, AmbarFile['meta']['full_name'], str(ex))) + + def GetTaggingRules(self): + taggingRules = [] + + apiResp = self.apiProxy.GetTaggingRules() + + if not apiResp.Success: + self.logger.LogMessage('error', 'error retrieving autotagging rules {0}'.format(apiResp.message)) + return taggingRules + + if not (apiResp.Ok): + self.logger.LogMessage('error', 'error retrieving autotagging rules, unexpected response code {0} {1}'.format(apiResp.code, apiResp.message)) + return taggingRules + + for ruleDict in apiResp.payload: + taggingRules.append(AmbarTaggingRule.Init(ruleDict)) + + return taggingRules + + def SetSourceIdTag(self, AmbarFile): + self.AddTagToAmbarFile(AmbarFile['file_id'], AmbarFile['meta']['full_name'] ,self.SOURCE_TAG_TYPE, AmbarFile['meta']['source_id']) + + def SetOCRTag(self, AmbarFile): + if AmbarFile['content']['ocr_performed']: + self.AddTagToAmbarFile(AmbarFile['file_id'], AmbarFile['meta']['full_name'], self.AUTO_TAG_TYPE, 'ocr') + + def SetArchiveTag(self, AmbarFile): + if ContentTypeAnalyzer.IsArchive(AmbarFile['meta']['full_name']): + self.AddTagToAmbarFile(AmbarFile['file_id'], AmbarFile['meta']['full_name'], self.AUTO_TAG_TYPE, 'archive') + + def SetImageTag(self, AmbarFile): + if ContentTypeAnalyzer.IsImageByContentType(AmbarFile['content']['type']): + self.AddTagToAmbarFile(AmbarFile['file_id'], AmbarFile['meta']['full_name'], self.AUTO_TAG_TYPE, 'image') + + def AddTagToAmbarFile(self, FileId, FullName, TagType, Tag): + apiResp = self.apiProxy.AddFileTag(FileId, TagType, Tag) + + if not apiResp.Success: + self.logger.LogMessage('error', 'error adding {0} tag to file {1} {2}'.format(Tag, FullName, apiResp.message)) + return False + + if not (apiResp.Ok or apiResp.Created): + self.logger.LogMessage('error', 'error adding {0} tag to file, unexpected response code {1} {2} {3}'.format(Tag, FullName, apiResp.code, apiResp.message)) + return False + + self.logger.LogMessage('verbose', '{0} tag added to {1}'.format(Tag, FullName)) + diff --git a/Pipeline/jars/jai-imageio-core-1.3.1.jar b/Pipeline/jars/jai-imageio-core-1.3.1.jar new file mode 100644 index 0000000..3c74884 Binary files /dev/null and b/Pipeline/jars/jai-imageio-core-1.3.1.jar differ diff --git a/Pipeline/jars/levigo-jbig2-imageio-1.6.5.jar b/Pipeline/jars/levigo-jbig2-imageio-1.6.5.jar new file mode 100644 index 0000000..f8b824d Binary files /dev/null and b/Pipeline/jars/levigo-jbig2-imageio-1.6.5.jar differ diff --git a/Pipeline/jars/pdfbox-app-2.0.7.jar b/Pipeline/jars/pdfbox-app-2.0.7.jar new file mode 100644 index 0000000..d696695 Binary files /dev/null and b/Pipeline/jars/pdfbox-app-2.0.7.jar differ diff --git a/Pipeline/jars/tika-app-1.17.jar b/Pipeline/jars/tika-app-1.17.jar new file mode 100644 index 0000000..7b8f8f1 Binary files /dev/null and b/Pipeline/jars/tika-app-1.17.jar differ diff --git a/Pipeline/logger.py b/Pipeline/logger.py new file mode 100644 index 0000000..b4f7b27 --- /dev/null +++ b/Pipeline/logger.py @@ -0,0 +1,29 @@ +from datetime import datetime +from model import AmbarLogRecord +import sys + +class AmbarLogger: + def __init__(self, ApiProxy, Name, Verbose = True): + """SourceId - crawler id from AmbarCrawlerSettings + """ + self.apiProxy = ApiProxy + self.name = Name + self.verbose = Verbose + + def SendLogMessageToES(self, MessageType, Message): + apiResp = self.apiProxy.IndexLogRecord(AmbarLogRecord.Init('pipeline', MessageType, '[{0}] {1}'.format(self.name, Message))) + if not (apiResp.Ok or apiResp.Created): + print('{0}: [{1}] [{2}] {3} {4}'.format(datetime.now(), 'error', self.name, apiResp.code, apiResp.message), file=sys.stderr) + + def LogMessage(self, MessageType, Message): + """Writing message into stdout, stderr and ES (calling WebApi) + MessageType: verbose, info, error + All messages are logged into ES + Error messages are logged into stderr + Info messages are logged into stdout + If in config.json set "Verbose": true then all messages except for errors are logged into stdout + """ + if self.verbose or MessageType!='verbose': + print('{0}: [{1}] [{2}] {3}'.format(datetime.now(), MessageType, self.name, Message), file=(sys.stderr if MessageType == 'error' else sys.stdout)) + self.SendLogMessageToES(MessageType, Message) + \ No newline at end of file diff --git a/Pipeline/model.py b/Pipeline/model.py new file mode 100644 index 0000000..faec44c --- /dev/null +++ b/Pipeline/model.py @@ -0,0 +1,235 @@ +from datetime import datetime +from hashlib import sha256 +from os import path +import re +import io +import hashlib +import base64 +import json + +class ExternalNER: + def __init__(self): + self.id = '' + self.uri = '' + + @classmethod + def Init(cls, Id, Uri): + eNER = cls() + eNER.id = Id.lower() + eNER.uri = Uri.lower() + return eNER + + @classmethod + def InitFromArray(cls, Array): + eNERs = [] + + for item in Array: + eNER = cls() + eNER.id = item + eNER.uri = item + eNERs.append(eNER) + + return eNERs + + def __iter__(self): + yield 'id', self.id + yield 'uri', self.uri + + @property + def Dict(self): + return dict(self) + +class AmbarTaggingRule: + def __init__(self): + self.field = '' + self.regex = '' + self.tags = [] + self.name = '' + self.enabled = False + + @classmethod + def Init(cls, TaggingRuleDictionary): + taggingRule = cls() + taggingRule.field = TaggingRuleDictionary['field'] + taggingRule.regex = TaggingRuleDictionary['regex'] + taggingRule.tags = TaggingRuleDictionary['tags'] + taggingRule.enabled = TaggingRuleDictionary['enabled'] + taggingRule.name = TaggingRuleDictionary['name'] + return taggingRule + +class AmbarLogRecord: + def __init__(self): + self.created_datetime = datetime.now() + self.indexed_datetime = datetime.now() + self.source_id = '' + self.type = '' + self.message = '' + + @classmethod + def Init(cls, SourceId, Type, Message): + logRecord = cls() + logRecord.created_datetime = datetime.now() + logRecord.indexed_datetime = datetime.now() + logRecord.source_id = str(SourceId) + logRecord.type = str(Type) + logRecord.message = str(Message) + return logRecord + + def __iter__(self): + yield 'created_datetime', self.created_datetime.strftime( + '%Y-%m-%d %H:%M:%S.%f')[:-3] + yield 'indexed_datetime', self.indexed_datetime.strftime( + '%Y-%m-%d %H:%M:%S.%f')[:-3] + yield 'source_id', self.source_id + yield 'type', self.type + yield 'message', self.message + + @property + def Dict(self): + return dict(self) + +class AmbarFileContent: + def __init__(self): + self.processed_datetime = '' + self.size = 0 + self.state = 'new' + self.title = '' + self.language = '' + self.type = '' + self.author = '' + self.length = '' + self.text = '' + self.thumb_available = False + self.ocr_performed = False + + @classmethod + def Init(cls, ParserResponse, FileSize): + fileContent = cls() + fileContent.processed_datetime = datetime.now().strftime( + '%Y-%m-%d %H:%M:%S.%f')[:-3] + fileContent.size = FileSize + fileContent.state = 'processed' + fileContent.title = ParserResponse.meta[ + 'title'] if 'title' in ParserResponse.meta else '' + fileContent.language = ParserResponse.meta[ + 'language'] if 'language' in ParserResponse.meta else '' + fileContent.type = ParserResponse.meta[ + 'Content-Type'] if 'Content-Type' in ParserResponse.meta else '' + fileContent.author = ParserResponse.meta[ + 'Author'] if 'Author' in ParserResponse.meta else '' + fileContent.length = len(ParserResponse.text) + fileContent.text = ParserResponse.text + fileContent.ocr_performed = ParserResponse.ocrPerformed + ## non serializable content + fileContent.initialized = True + fileContent.message = 'ok' + return fileContent + + def __iter__(self): + yield 'processed_datetime', self.processed_datetime + yield 'size', self.size + yield 'state', self.state + yield 'title', self.title + yield 'language', self.language + yield 'type', self.type + yield 'author', self.author + yield 'length', self.length + yield 'text', self.text + yield 'thumb_available', self.thumb_available + yield 'ocr_performed', self.ocr_performed + + @property + def Dict(self): + return dict(self) + +class AmbarFileMeta: + def __init__(self): + self.id = '' + self.full_name = '' + self.full_name_parts = [] + self.short_name = '' + self.extension = '' + self.extra = [] + self.source_id = '' + self.created_datetime = '' + self.updated_datetime = '' + ## non serializable content + self.initialized = False + self.message = '' + + @classmethod + def ParseFullNameIntoParts(cls, FullName): + fullNameParts = [] + for match in re.finditer(r'/', FullName): + if match.start() > 1: + fullNameParts.append(FullName[:match.start() + 1]) + fullNameParts.append(FullName) + return fullNameParts + + @classmethod + def InitFromDictWithId(cls, MetaDict): + amFileMeta = cls() + try: + amFileMeta.full_name = MetaDict['full_name'] + amFileMeta.full_name_parts = AmbarFileMeta.ParseFullNameIntoParts(MetaDict['full_name']) + amFileMeta.short_name = MetaDict['short_name'] + amFileMeta.extension = MetaDict['extension'] + amFileMeta.extra = MetaDict['extra'] + amFileMeta.source_id = MetaDict['source_id'] + amFileMeta.created_datetime = MetaDict['created_datetime'] + amFileMeta.updated_datetime = MetaDict['updated_datetime'] + amFileMeta.id = MetaDict['id'] + ## non serializable content + amFileMeta.initialized = True + amFileMeta.message = 'ok' + except Exception as ex: + amFileMeta.initialized = False + amFileMeta.message = str(ex) + return amFileMeta + + @classmethod + def InitWithoutId(cls, CreateTime, UpdateTime, ShortName, FullName, + AmbarCrawlerId): + amFileMeta = cls() + try: + amFileMeta.full_name = FullName + amFileMeta.full_name_parts = AmbarFileMeta.ParseFullNameIntoParts(FullName) + amFileMeta.short_name = ShortName + amFileMeta.extension = path.splitext(ShortName)[1] if path.splitext(ShortName)[1] != '' else path.splitext(ShortName)[0] + amFileMeta.extra = [] + amFileMeta.source_id = AmbarCrawlerId + if type(CreateTime) is str: + amFileMeta.created_datetime = CreateTime + else: + amFileMeta.created_datetime = CreateTime.strftime( + '%Y-%m-%d %H:%M:%S.%f')[:-3] + if type(UpdateTime) is str: + amFileMeta.updated_datetime = UpdateTime + else: + amFileMeta.updated_datetime = UpdateTime.strftime( + '%Y-%m-%d %H:%M:%S.%f')[:-3] + ## non serializable content + amFileMeta.initialized = True + amFileMeta.message = 'ok' + except Exception as ex: + amFileMeta.initialized = False + amFileMeta.message = str(ex) + return amFileMeta + + def __iter__(self): + yield 'id', self.id + yield 'full_name', self.full_name + yield 'full_name_parts', self.full_name_parts + yield 'short_name', self.short_name + yield 'extension', self.extension + extraArr = [] + for extra in self.extra: + extraArr.append(dict(extra)) + yield 'extra', extraArr + yield 'source_id', self.source_id + yield 'created_datetime', self.created_datetime + yield 'updated_datetime', self.updated_datetime + + @property + def Dict(self): + return dict(self) \ No newline at end of file diff --git a/Pipeline/parsers/__init__.py b/Pipeline/parsers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Pipeline/parsers/binarystringparser.py b/Pipeline/parsers/binarystringparser.py new file mode 100644 index 0000000..d92b148 --- /dev/null +++ b/Pipeline/parsers/binarystringparser.py @@ -0,0 +1,13 @@ +import chardet + +class BinaryStringParser: + + @classmethod + def Parse(cls, BinaryString): + parsedString = '' + try: + detectedEncoding = chardet.detect(BinaryString) + parsedString = BinaryString.decode(detectedEncoding['encoding'],'ignore') + return parsedString + except Exception as ex: + return parsedString \ No newline at end of file diff --git a/Pipeline/parsers/contenttypeanalyzer.py b/Pipeline/parsers/contenttypeanalyzer.py new file mode 100644 index 0000000..76a36b5 --- /dev/null +++ b/Pipeline/parsers/contenttypeanalyzer.py @@ -0,0 +1,27 @@ +import re + +class ContentTypeAnalyzer: + + @classmethod + def IsImageByContentType(cls, ContentType): + regex = re.compile(r'^image\/',re.I) + return regex.match(ContentType) + + @classmethod + def IsPdfByContentType(cls, ContentType): + return True if ContentType == 'application/pdf' else False + + @classmethod + def IsArchive(cls, FileName): + regex = re.compile('(\\.zip$)', re.I) + return True if regex.search(FileName) else False + + @classmethod + def IsPst(cls, FileName): + regex = re.compile('(\\.pst$)', re.I) + return True if regex.search(FileName) else False + + @classmethod + def IsPdf(cls, FileName): + regex = re.compile('(\\.pdf$)', re.I) + return True if regex.search(FileName) else False \ No newline at end of file diff --git a/Pipeline/parsers/fileparser.py b/Pipeline/parsers/fileparser.py new file mode 100644 index 0000000..8f64506 --- /dev/null +++ b/Pipeline/parsers/fileparser.py @@ -0,0 +1,16 @@ +from parsers.tikaparser import TikaParser +from parsers.pdfparser import PDFParser +from parsers.contenttypeanalyzer import ContentTypeAnalyzer + +class FileParser: + def __init__(self, Logger, ParserCallTimeoutSeconds, OcrPdfSymbolsPerPageThreshold, OcrPdfMaxPageCount): + self.logger = Logger + self.parserCallTimeoutSeconds = ParserCallTimeoutSeconds + self.pdfParser = PDFParser(self.logger, OcrPdfSymbolsPerPageThreshold, OcrPdfMaxPageCount, self.parserCallTimeoutSeconds) + self.tikaParser = TikaParser(self.logger, self.parserCallTimeoutSeconds) + + def Parse(self, FileName, FileData): + if ContentTypeAnalyzer.IsPdf(FileName): + return self.pdfParser.Parse(FileName, FileData) + + return self.tikaParser.Parse(FileName, FileData) \ No newline at end of file diff --git a/Pipeline/parsers/fileparserresponse.py b/Pipeline/parsers/fileparserresponse.py new file mode 100644 index 0000000..2c9f9eb --- /dev/null +++ b/Pipeline/parsers/fileparserresponse.py @@ -0,0 +1,8 @@ +class FileParserResponse: + def __init__(self): + self.meta = {} + self.text = '' + self.thumbnail = None + self.success = False + self.message = '' + self.ocrPerformed = False \ No newline at end of file diff --git a/Pipeline/parsers/ocrproxy.py b/Pipeline/parsers/ocrproxy.py new file mode 100644 index 0000000..257f7ab --- /dev/null +++ b/Pipeline/parsers/ocrproxy.py @@ -0,0 +1,65 @@ +from PIL import Image +import pyocr +import pyocr.builders +import sys +import re +import io + +class OCRProxyResponse: + def __init__(self): + self.text = '' + self.success = False + self.message = '' + +class OCRProxy: + def __init__(self): + self.ocr = None + self.lang = None + + for tool in pyocr.get_available_tools(): + if tool.get_name() == 'Tesseract (sh)': + self.ocr = tool + break + + if self.ocr: + self.lang = '+'.join(self.ocr.get_available_languages()) + + def PerformOCR(self, ImageData): + resp = OCRProxyResponse() + + if not self.ocr: + resp.success = False + resp.message = 'No OCR foud!' + return resp + + try: + image = Image.open(io.BytesIO(ImageData)) + + if 'compression' in image.info and image.info['compression']=='tiff_jpeg': + resp.success = False + resp.message = 'Unsupported compression type' + return resp + + text = self.ocr.image_to_string( + image, + lang = self.lang, + builder = pyocr.builders.TextBuilder() + ) + resp.text = text + resp.success = True + except Exception as ex: + resp.success = False + resp.message = str(ex) + + return resp + + @classmethod + def GetLanguages(cls): + lang = '' + for tool in pyocr.get_available_tools(): + if tool.get_name() == 'Tesseract (sh)': + ocr = tool + break + if ocr: + lang = '+'.join(ocr.get_available_languages()) + return lang \ No newline at end of file diff --git a/Pipeline/parsers/pdfparser.py b/Pipeline/parsers/pdfparser.py new file mode 100644 index 0000000..7092cc1 --- /dev/null +++ b/Pipeline/parsers/pdfparser.py @@ -0,0 +1,160 @@ +from jnius import autoclass +from jnius import cast +from parsers.fileparserresponse import FileParserResponse +from parsers.ocrproxy import OCRProxy, OCRProxyResponse +from parsers.binarystringparser import BinaryStringParser +import io +import sys +import re + +class PDFParser: + def __init__(self, Logger, OcrSymbolsPerPageThreshold, OcrMaxPageCount, ParserCallTimeoutSeconds): + self.logger = Logger + self.ocrProxy = OCRProxy() + self.parserCallTimeoutSeconds = ParserCallTimeoutSeconds + self.ocrSymbolsPerPageThreshold = OcrSymbolsPerPageThreshold + self.ocrMaxPageCount = OcrMaxPageCount + self.ByteArrayInputStream = autoclass('java.io.ByteArrayInputStream') + self.ByteArrayOutputStream = autoclass('java.io.ByteArrayOutputStream') + self.PDDocument = autoclass('org.apache.pdfbox.pdmodel.PDDocument') + self.PDPage = autoclass('org.apache.pdfbox.pdmodel.PDPage') + self.PDAnnotation = autoclass('org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation') + self.PDDocumentInformation = autoclass('org.apache.pdfbox.pdmodel.PDDocumentInformation') + self.PDFRenderer = autoclass('org.apache.pdfbox.rendering.PDFRenderer') + self.PDFTextStripper = autoclass('org.apache.pdfbox.text.PDFTextStripper') + self.ImageType = autoclass('org.apache.pdfbox.rendering.ImageType') + self.BufferedImage = autoclass('java.awt.image.BufferedImage') + self.ImageIO = autoclass('javax.imageio.ImageIO') + self.MemoryCacheImageOutputStream = autoclass('javax.imageio.stream.MemoryCacheImageOutputStream') + self.System = autoclass('java.lang.System') + self.System.setProperty('org.apache.pdfbox.rendering.UsePureJavaCMYKConversion', 'true') + + def Parse(self, FileName, FileData): + resp = FileParserResponse() + + try: + inputStream = self.ByteArrayInputStream(FileData) + document = self.PDDocument.load(inputStream) + metadata = document.getDocumentInformation() + resp.meta['Author'] = metadata.getAuthor() + resp.meta['title'] = metadata.getTitle() + resp.meta['Content-Type'] = 'application/pdf' + resp.meta['Content-Length'] = sys.getsizeof(FileData) + + if document.getNumberOfPages() == 0: + resp.success = True + return resp + + ## generating thumbnail + resp.thumbnail = self.GenerateThumbnail(document) + + ## parsing text + pdfStripper = self.PDFTextStripper() + + for pageNumber in range(0, document.getNumberOfPages()): + pdfStripper.setStartPage(pageNumber + 1) + pdfStripper.setEndPage(pageNumber + 1) + + try: + parsedText = pdfStripper.getText(document) + except Exception as convEx: + parsedText = BinaryStringParser.Parse(convEx.object) + + if ((pageNumber < self.ocrMaxPageCount) or (self.ocrMaxPageCount == -1)) and ((self.GetSymbolsCount(parsedText) < self.ocrSymbolsPerPageThreshold) or (self.ocrSymbolsPerPageThreshold == -1)): + self.logger.LogMessage('info','performing ocr on page {0} of pdf {1}'.format(pageNumber + 1, FileName)) + ocrResp = self.PerformOCROnPage(document, pageNumber) + + if not ocrResp.success: + self.logger.LogMessage('info','could not perform ocr on page {0} of pdf {1} {2}'.format(pageNumber + 1, FileName, ocrResp.message)) + + if ocrResp.success: + parsedText = '{0}\r\n{1}'.format(parsedText, ocrResp.text) + resp.ocrPerformed = True + + ##parsing annotations + try: + pdfPage = document.getPage(pageNumber) + pdfAnnotations = pdfPage.getAnnotations() + + annotationsText = '' + + if pdfAnnotations.size() > 0: + for pdfAnnotationNumber in range(0, pdfAnnotations.size()): + pdfAnnotationContents = pdfAnnotations.get(pdfAnnotationNumber).getContents() + if pdfAnnotationContents and pdfAnnotationContents != '': + annotationsText = '{0}{1}\r\n----\r\n'.format(annotationsText, pdfAnnotationContents) + + if annotationsText != '': + parsedText = '{0}\r\n----Annotations start----\r\n{1}----Annotations end----'.format(parsedText, annotationsText[:-6]) + + pdfPage = None + pdfAnnotations = None + except Exception as ex: + self.logger.LogMessage('info','could not extract annotations from page {0} of pdf {1}'.format(pageNumber + 1, FileName)) + + parsedText = self.NormalizeText(parsedText) + resp.text = '{0}\r\n{1}'.format(resp.text, parsedText) + + inputStream = None + document = None + self.System.gc() + + resp.success = True + except Exception as ex: + resp.message = str(ex) + resp.success = False + + return resp + + def GenerateThumbnail(self, document): + try: + pdfRenderer = self.PDFRenderer(document) + bufferedImage = pdfRenderer.renderImageWithDPI(0, 75, self.ImageType.RGB) + byteStream = self.ByteArrayOutputStream() + imageStream = self.MemoryCacheImageOutputStream(byteStream) + self.ImageIO.write(bufferedImage, "jpg", imageStream) + imageData = bytearray(byteStream.toByteArray()) + + pdfRenderer = None + bufferedImage = None + byteStream = None + imageStream = None + self.System.gc() + + return (imageData, 'image/jpeg') + except Exception as ex: + self.logger.LogMessage('info','unable to generate thumbnail for pdf {0}'.format(str(ex))) + return None + + def PerformOCROnPage(self, document, pageNumber): + ocrResp = OCRProxyResponse() + + try: + pdfRenderer = self.PDFRenderer(document) + bufferedImage = pdfRenderer.renderImageWithDPI(pageNumber, 200, self.ImageType.RGB) + byteStream = self.ByteArrayOutputStream() + imageStream = self.MemoryCacheImageOutputStream(byteStream) + self.ImageIO.write(bufferedImage, "jpg", imageStream) + imageData = bytearray(byteStream.toByteArray()) + + ocrResp = self.ocrProxy.PerformOCR(imageData) + + pdfRenderer = None + bufferedImage = None + byteStream = None + imageStream = None + self.System.gc() + except Exception as ex: + ocrResp.success = False + ocrResp.message = str(ex) + + return ocrResp + + def NormalizeText(self, Text): + regex = re.compile(r'([\s]*[\r]*\n){2,}') + return re.sub(regex, '\r\n', Text) + + def GetSymbolsCount(self, Text): + regex = re.compile(r'[^a-zа-яёй]+', re.I) + strippedText = re.sub(regex, '', Text) + return len(strippedText) \ No newline at end of file diff --git a/Pipeline/parsers/tikaparser.py b/Pipeline/parsers/tikaparser.py new file mode 100644 index 0000000..0ac477d --- /dev/null +++ b/Pipeline/parsers/tikaparser.py @@ -0,0 +1,85 @@ +from jnius import autoclass +import re +import io +from PIL import Image +from parsers.contenttypeanalyzer import ContentTypeAnalyzer +from parsers.ocrproxy import OCRProxy, OCRProxyResponse +from parsers.fileparserresponse import FileParserResponse +from parsers.binarystringparser import BinaryStringParser + +class TikaParser: + def __init__(self, Logger, TikaCallTimeoutSeconds): + self.logger = Logger + self.ocrProxy = OCRProxy() + self.ByteArrayInputStream = autoclass('java.io.ByteArrayInputStream') + self.Metadata = autoclass('org.apache.tika.metadata.Metadata') + self.AutoDetectParser = autoclass('org.apache.tika.parser.AutoDetectParser') + self.BodyContentHandler = autoclass('org.apache.tika.sax.BodyContentHandler') + self.TikaConfig = autoclass('org.apache.tika.config.TikaConfig') + + self.config = self.TikaConfig('/tika-config.xml') + self.parser = self.AutoDetectParser(self.config) + + def Parse(self, FileName, FileData): + resp = FileParserResponse() + + try: + meta = self.Metadata() + if FileName and FileName != '': + meta.set(self.Metadata.RESOURCE_NAME_KEY, FileName) + contentHandler = self.BodyContentHandler(-1) + inputStream = self.ByteArrayInputStream(FileData) + self.parser.parse(inputStream, contentHandler, meta) + + try: + resp.text = contentHandler.toString() + except Exception as convEx: + resp.text = BinaryStringParser.Parse(convEx.object) + + for name in meta.names(): + try: + resp.meta[name] = meta.get(name) + except: + resp.meta[name] = '' + + inputStream = None + contentHandler = None + + if 'Content-Type' in resp.meta and ContentTypeAnalyzer.IsImageByContentType(resp.meta['Content-Type']): + self.logger.LogMessage('info','performing ocr on {0}'.format(FileName)) + ocrResp = self.ocrProxy.PerformOCR(FileData) + + if ocrResp.success: + resp.text = self.NormalizeText('{0}{1}'.format(resp.text, ocrResp.text)) + resp.ocrPerformed = True + + if not ocrResp.success: + self.logger.LogMessage('info','could not perform ocr on {0} {1}'.format(FileName, ocrResp.message)) + + resp.thumbnail = self.GenerateThumbnail(FileData) + + resp.success = True + except Exception as ex: + resp.success = False + resp.message = str(ex) + + return resp + + def GenerateThumbnail(self, ImageData, MaxWidth = 1000, MaxHeigh = 5000, Quality = 70, Dpi = 50): + try: + image = Image.open(io.BytesIO(ImageData)) + + if 'compression' in image.info and image.info['compression']=='tiff_jpeg': + return None + + image.thumbnail((MaxWidth,MaxHeigh)) + bytesIO = io.BytesIO() + image.convert('RGB').save(bytesIO, format='JPEG', quality=Quality) + return (bytesIO.getvalue(), 'image/jpeg') + except: + pass + return None + + def NormalizeText(self, Text): + regex = re.compile(r'([\s]*[\r]*\n){2,}') + return re.sub(regex, '\r\n', Text) diff --git a/Pipeline/pipeline.py b/Pipeline/pipeline.py new file mode 100644 index 0000000..504756f --- /dev/null +++ b/Pipeline/pipeline.py @@ -0,0 +1,300 @@ +# import jnius_config +# jnius_config.add_options('-Xmx256m') +from apiproxy import ApiProxy +from logger import AmbarLogger +from parsers.fileparser import FileParser +from parsers.contenttypeanalyzer import ContentTypeAnalyzer +from contentprocessors.autotagger import AutoTagger +from model import AmbarFileContent, AmbarFileMeta +from containerprocessors.archiveprocessor import ArchiveProcessor +from containerprocessors.pstprocessor import PstProcessor +from datetime import datetime +import gc +import io +import sys +import argparse +import os +import time +import hashlib +import pika +import json +import base64 +from hashlib import sha256 + +RABBIT_QUEUE_NAME = 'AMBAR_PIPELINE_QUEUE' +RABBIT_HEARTBEAT = 0 +API_CALL_TIMEOUT_SECONDS = 1200 +PARSE_TIMEOUT_SECONDS = 1200 + +parser = argparse.ArgumentParser() +parser.add_argument('-id', default='0') +parser.add_argument('-api_url', default='http://ambar:8081') +parser.add_argument('-rabbit_host', default='amqp://ambar') + +ocrPdfSymbolsPerPageThreshold = int(os.getenv('ocrPdfSymbolsPerPageThreshold', 1000)) +ocrPdfMaxPageCount = int(os.getenv('ocrPdfSymbolsPerPageThreshold', 5)) +preserveOriginals = True if os.getenv('preserveOriginals', 'False') == 'True' else False + +args = parser.parse_args() + +# instantiating Api proxy +apiProxy = ApiProxy(args.api_url, API_CALL_TIMEOUT_SECONDS) +# instantiating logger +logger = AmbarLogger(apiProxy, args.id) +# instantiating ArchiveProcessor +archiveProcessor = ArchiveProcessor(logger, apiProxy) +# instantiating PstProcessor +pstProcessor = PstProcessor(logger, apiProxy) +# instantiating Parser +fileParser = FileParser(logger, PARSE_TIMEOUT_SECONDS, ocrPdfSymbolsPerPageThreshold, ocrPdfMaxPageCount) +# instantiating AutoTagger +autoTagger = AutoTagger(logger, apiProxy) +# checking whether to preserve originals or not +preserveOriginals = True if preserveOriginals else False + +# reporting start +logger.LogMessage('info', 'started') + +# connecting to Rabbit +logger.LogMessage( + 'info', 'connecting to Rabbit {0}...'.format(args.rabbit_host)) +try: + rabbitConnection = pika.BlockingConnection(pika.URLParameters( + '{0}?heartbeat={1}'.format(args.rabbit_host, RABBIT_HEARTBEAT))) + rabbitChannel = rabbitConnection.channel() + rabbitChannel.basic_qos(prefetch_count=1, all_channels=True) + logger.LogMessage('info', 'connected to Rabbit!') +except Exception as e: + logger.LogMessage('error', 'error initializing connection to Rabbit {0}'.format(repr(e))) + exit(1) + +# starting pipeline +logger.LogMessage('info', 'waiting for messages...') + + +def ProcessFile(sha, fileId, meta, sourceId): + try: + logger.LogMessage('verbose', 'task received {0}'.format(sha)) + + fileMeta = AmbarFileMeta.InitFromDictWithId(meta) + + if not fileMeta.initialized: + logger.LogMessage( + 'error', 'error initializing file meta {0}'.format(fileMeta.message)) + return False + + hasParsedContent = False + fileContent = {} + + apiResp = apiProxy.GetParsedFileContentFields(sha) + + if not apiResp.Success: + logger.LogMessage('error', 'error retrieving parsed file content fields {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if not (apiResp.Ok or apiResp.NotFound): + logger.LogMessage('error', 'error retrieving parsed file content fields {0} {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + if apiResp.Ok: + hasParsedContent = True + fileContent = apiResp.payload + + if hasParsedContent: + apiResp = apiProxy.GetParsedFileContent(sha) + + if not apiResp.Success: + logger.LogMessage('error', 'error retrieving parsed file content {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if not (apiResp.Ok or apiResp.NotFound): + logger.LogMessage('error', 'error retrieving parsed file content {0} {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + if apiResp.NotFound: + hasParsedContent = False + + if apiResp.Ok: + hasParsedContent = True + fileContent['text'] = apiResp.payload.decode('utf-8', 'ignore') + logger.LogMessage( + 'verbose', 'parsed content found {0}'.format(fileMeta.full_name)) + + if not hasParsedContent: + apiResp = apiProxy.GetFileContent(sha) + + if not apiResp.Success: + logger.LogMessage('error', 'error retrieving file content {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if apiResp.NotFound: + logger.LogMessage( + 'verbose', 'file content not found {0}'.format(fileMeta.full_name)) + return False + + if not apiResp.Ok: + logger.LogMessage('error', 'error retrieving file content {0} {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + # file received + fileData = apiResp.payload + logger.LogMessage( + 'verbose', 'file content received {0}'.format(fileMeta.full_name)) + + # checking received sha with calculated payload sha + calculatedSha = sha256(fileData).hexdigest() + if (calculatedSha != sha): + logger.LogMessage('error', 'calculated sha ({0}) is not equal to received sha ({1}) for {2}'.format( + calculatedSha, sha, fileMeta.full_name)) + return False + + # checking if file is archive + if ContentTypeAnalyzer.IsArchive(fileMeta.short_name): + archiveProcessor.Process(fileData, fileMeta, sourceId) + + # checking if file is pst + if ContentTypeAnalyzer.IsPst(fileMeta.short_name): + pstProcessor.Process(fileData, fileMeta, sourceId) + + # extracting + logger.LogMessage('verbose', 'parsing {0}'.format(fileMeta.full_name)) + fileParserResp = fileParser.Parse(fileMeta.short_name, fileData) + + if not fileParserResp.success: + logger.LogMessage('error', 'error parsing {0} {1}'.format( + fileMeta.full_name, fileParserResp.message)) + return False + + logger.LogMessage( + 'verbose', 'successfully parsed {0}'.format(fileMeta.full_name)) + + # building Ambar File Content + fileContent = AmbarFileContent.Init(fileParserResp, sys.getsizeof(fileData)) + + # submitting thumbnail + if fileParserResp.thumbnail: + logger.LogMessage( + 'verbose', 'submitting thumbnail {0}'.format(fileMeta.full_name)) + apiResp = apiProxy.SubmitThumbnail( + sha, fileParserResp.thumbnail[0]) + + if not apiResp.Success: + logger.LogMessage('error', 'error submitting thumbnail to Api {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if not apiResp.Ok: + logger.LogMessage('error', 'error submitting thumbnail to Api, unexpected response code {0} {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + fileContent.thumb_available = True + logger.LogMessage('verbose', 'thumbnail submited {0}'.format(fileMeta.full_name)) + + # submitting parsed text to Api + if not ContentTypeAnalyzer.IsArchive(fileMeta.short_name) and not ContentTypeAnalyzer.IsPst(fileMeta.short_name): + logger.LogMessage('verbose', 'submitting parsed text {0}'.format(fileMeta.full_name)) + + apiResp = apiProxy.SubmitExtractedContent( + sha, fileContent.text.encode(encoding='utf_8', errors='ignore')) + + if not apiResp.Success: + logger.LogMessage('error', 'error submitting parsed text to Api {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if not apiResp.Ok: + logger.LogMessage('error', 'error submitting parsed text to Api, unexpected response code {0} {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + logger.LogMessage('verbose', 'parsed text submited {0}'.format(fileMeta.full_name)) + + # submitting processed file to Api + logger.LogMessage('verbose', 'submitting parsed content {0}'.format(fileMeta.full_name)) + + ambarFile = {} + ambarFile['content'] = fileContent.Dict if isinstance(fileContent, AmbarFileContent) else fileContent + ambarFile['meta'] = fileMeta.Dict + ambarFile['sha256'] = sha + ambarFile['file_id'] = fileId + ambarFile['indexed_datetime'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] + + apiResp = apiProxy.SubmitProcessedFile(fileId, json.dumps( + dict(ambarFile)).encode(encoding='utf_8', errors='ignore')) + + if not apiResp.Success: + logger.LogMessage('error', 'error submitting parsed content to Api {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if not (apiResp.Ok or apiResp.Created): + logger.LogMessage('error', 'error submitting parsed content to Api, unexpected response code {0} {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + logger.LogMessage( + 'verbose', 'parsed content submited {0}'.format(fileMeta.full_name)) + + # removing original file + if not preserveOriginals: + apiResp = apiProxy.RemoveFileContent(sha) + + if not apiResp.Success: + logger.LogMessage('error', 'error removing original file from Ambar for {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if not (apiResp.Ok or apiResp.NotFound): + logger.LogMessage('error', 'error removing original file from Ambar for {0}, unexpected response code {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + if apiResp.Ok: + logger.LogMessage( + 'verbose', 'original file removed from Ambar for {0}'.format(fileMeta.full_name)) + + ## tags + apiResp = apiProxy.RemoveAutoTags(fileId) + if not apiResp.Success: + logger.LogMessage('error', 'error removing autotags {0} {1}'.format( + fileMeta.full_name, apiResp.message)) + return False + + if not apiResp.Ok: + logger.LogMessage('error', 'error removing autotags, unexpected response code {0} {1} {2}'.format( + fileMeta.full_name, apiResp.code, apiResp.message)) + return False + + autoTagger.AutoTagAmbarFile(ambarFile) + + return True + except Exception as e: + logger.LogMessage('error', 'error processing task {0} {1}'.format(sha, repr(e))) + return False + +# main callback on receiving message from Rabbit + +def RabbitConsumeCallback(channel, method, properties, body): + bodyObject = json.loads(body.decode('utf-8')) + sha = bodyObject['sha'] + fileId = bodyObject['fileId'] + meta = bodyObject['meta'] + sourceId = bodyObject['sourceId'] + if (ProcessFile(sha, fileId, meta, sourceId)): + channel.basic_ack(delivery_tag=method.delivery_tag) + else: + channel.basic_nack(delivery_tag=method.delivery_tag, requeue=False) + gc.collect() + + +rabbitChannel.basic_consume(RabbitConsumeCallback, queue=RABBIT_QUEUE_NAME) +rabbitChannel.start_consuming() + +exit(0) diff --git a/Pipeline/requirements.txt b/Pipeline/requirements.txt new file mode 100644 index 0000000..8d98a5b Binary files /dev/null and b/Pipeline/requirements.txt differ diff --git a/Pipeline/tika-config.xml b/Pipeline/tika-config.xml new file mode 100644 index 0000000..7745b23 --- /dev/null +++ b/Pipeline/tika-config.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Rabbit/.gitignore b/Rabbit/.gitignore new file mode 100644 index 0000000..eb87e33 --- /dev/null +++ b/Rabbit/.gitignore @@ -0,0 +1,371 @@ + +# Created by https://www.gitignore.io/api/python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +.venv/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.vcxproj.filters + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ +Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ + diff --git a/Rabbit/Dockerfile b/Rabbit/Dockerfile new file mode 100644 index 0000000..52adabc --- /dev/null +++ b/Rabbit/Dockerfile @@ -0,0 +1,14 @@ +FROM rabbitmq:3-management + +RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y curl + +# Set a timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +COPY rabbitmq.config /etc/rabbitmq/rabbitmq.config + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f localhost:15672 || exit 1 + + diff --git a/Rabbit/rabbitmq.config b/Rabbit/rabbitmq.config new file mode 100644 index 0000000..35e2aa3 --- /dev/null +++ b/Rabbit/rabbitmq.config @@ -0,0 +1,3 @@ +[ + { rabbit, [ { loopback_users, [ ] }, { heartbeat, 0} ] } +]. diff --git a/Redis/Dockerfile b/Redis/Dockerfile new file mode 100644 index 0000000..aed6b6c --- /dev/null +++ b/Redis/Dockerfile @@ -0,0 +1,11 @@ +FROM redis:4.0.2-alpine + +RUN apk add --update curl && \ + rm -rf /var/cache/apk/* + +COPY redis.conf /usr/local/etc/redis/redis.conf + +CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ] + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f localhost:6379 || exit 1 \ No newline at end of file diff --git a/Redis/redis.conf b/Redis/redis.conf new file mode 100644 index 0000000..d38e140 --- /dev/null +++ b/Redis/redis.conf @@ -0,0 +1,1293 @@ +# Redis configuration file example. +# +# Note that in order to read the configuration file, Redis must be +# started with the file path as first argument: +# +# ./redis-server /path/to/redis.conf + +# Note on units: when memory size is needed, it is possible to specify +# it in the usual form of 1k 5GB 4M and so forth: +# +# 1k => 1000 bytes +# 1kb => 1024 bytes +# 1m => 1000000 bytes +# 1mb => 1024*1024 bytes +# 1g => 1000000000 bytes +# 1gb => 1024*1024*1024 bytes +# +# units are case insensitive so 1GB 1Gb 1gB are all the same. + +################################## INCLUDES ################################### + +# Include one or more other config files here. This is useful if you +# have a standard template that goes to all Redis servers but also need +# to customize a few per-server settings. Include files can include +# other files, so use this wisely. +# +# Notice option "include" won't be rewritten by command "CONFIG REWRITE" +# from admin or Redis Sentinel. Since Redis always uses the last processed +# line as value of a configuration directive, you'd better put includes +# at the beginning of this file to avoid overwriting config change at runtime. +# +# If instead you are interested in using includes to override configuration +# options, it is better to use include as the last line. +# +# include /path/to/local.conf +# include /path/to/other.conf + +################################## MODULES ##################################### + +# Load modules at startup. If the server is not able to load modules +# it will abort. It is possible to use multiple loadmodule directives. +# +# loadmodule /path/to/my_module.so +# loadmodule /path/to/other_module.so + +################################## NETWORK ##################################### + +# By default, if no "bind" configuration directive is specified, Redis listens +# for connections from all the network interfaces available on the server. +# It is possible to listen to just one or multiple selected interfaces using +# the "bind" configuration directive, followed by one or more IP addresses. +# +# Examples: +# +# bind 192.168.1.100 10.0.0.1 +# bind 127.0.0.1 ::1 +# +# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the +# internet, binding to all the interfaces is dangerous and will expose the +# instance to everybody on the internet. So by default we uncomment the +# following bind directive, that will force Redis to listen only into +# the IPv4 lookback interface address (this means Redis will be able to +# accept connections only from clients running into the same computer it +# is running). +# +# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES +# JUST COMMENT THE FOLLOWING LINE. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# bind 127.0.0.1 + +# Protected mode is a layer of security protection, in order to avoid that +# Redis instances left open on the internet are accessed and exploited. +# +# When protected mode is on and if: +# +# 1) The server is not binding explicitly to a set of addresses using the +# "bind" directive. +# 2) No password is configured. +# +# The server only accepts connections from clients connecting from the +# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain +# sockets. +# +# By default protected mode is enabled. You should disable it only if +# you are sure you want clients from other hosts to connect to Redis +# even if no authentication is configured, nor a specific set of interfaces +# are explicitly listed using the "bind" directive. +protected-mode no + +# Accept connections on the specified port, default is 6379 (IANA #815344). +# If port 0 is specified Redis will not listen on a TCP socket. +port 6379 + +# TCP listen() backlog. +# +# In high requests-per-second environments you need an high backlog in order +# to avoid slow clients connections issues. Note that the Linux kernel +# will silently truncate it to the value of /proc/sys/net/core/somaxconn so +# make sure to raise both the value of somaxconn and tcp_max_syn_backlog +# in order to get the desired effect. +tcp-backlog 511 + +# Unix socket. +# +# Specify the path for the Unix socket that will be used to listen for +# incoming connections. There is no default, so Redis will not listen +# on a unix socket when not specified. +# +# unixsocket /tmp/redis.sock +# unixsocketperm 700 + +# Close the connection after a client is idle for N seconds (0 to disable) +timeout 0 + +# TCP keepalive. +# +# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence +# of communication. This is useful for two reasons: +# +# 1) Detect dead peers. +# 2) Take the connection alive from the point of view of network +# equipment in the middle. +# +# On Linux, the specified value (in seconds) is the period used to send ACKs. +# Note that to close the connection the double of the time is needed. +# On other kernels the period depends on the kernel configuration. +# +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 300 + +################################# GENERAL ##################################### + +# By default Redis does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +daemonize no + +# If you run Redis from upstart or systemd, Redis can interact with your +# supervision tree. Options: +# supervised no - no supervision interaction +# supervised upstart - signal upstart by putting Redis into SIGSTOP mode +# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET +# supervised auto - detect upstart or systemd method based on +# UPSTART_JOB or NOTIFY_SOCKET environment variables +# Note: these supervision methods only signal "process is ready." +# They do not enable continuous liveness pings back to your supervisor. +supervised no + +# If a pid file is specified, Redis writes it where specified at startup +# and removes it at exit. +# +# When the server runs non daemonized, no pid file is created if none is +# specified in the configuration. When the server is daemonized, the pid file +# is used even if not specified, defaulting to "/var/run/redis.pid". +# +# Creating a pid file is best effort: if Redis is not able to create it +# nothing bad happens, the server will start and run normally. +pidfile /var/run/redis_6379.pid + +# Specify the server verbosity level. +# This can be one of: +# debug (a lot of information, useful for development/testing) +# verbose (many rarely useful info, but not a mess like the debug level) +# notice (moderately verbose, what you want in production probably) +# warning (only very important / critical messages are logged) +loglevel notice + +# Specify the log file name. Also the empty string can be used to force +# Redis to log on the standard output. Note that if you use standard +# output for logging but daemonize, logs will be sent to /dev/null +logfile "" + +# To enable logging to the system logger, just set 'syslog-enabled' to yes, +# and optionally update the other syslog parameters to suit your needs. +# syslog-enabled no + +# Specify the syslog identity. +# syslog-ident redis + +# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. +# syslog-facility local0 + +# Set the number of databases. The default database is DB 0, you can select +# a different one on a per-connection basis using SELECT where +# dbid is a number between 0 and 'databases'-1 +databases 16 + +# By default Redis shows an ASCII art logo only when started to log to the +# standard output and if the standard output is a TTY. Basically this means +# that normally a logo is displayed only in interactive sessions. +# +# However it is possible to force the pre-4.0 behavior and always show a +# ASCII art logo in startup logs by setting the following option to yes. +always-show-logo yes + +################################ SNAPSHOTTING ################################ +# +# Save the DB on disk: +# +# save +# +# Will save the DB if both the given number of seconds and the given +# number of write operations against the DB occurred. +# +# In the example below the behaviour will be to save: +# after 900 sec (15 min) if at least 1 key changed +# after 300 sec (5 min) if at least 10 keys changed +# after 60 sec if at least 10000 keys changed +# +# Note: you can disable saving completely by commenting out all "save" lines. +# +# It is also possible to remove all the previously configured save +# points by adding a save directive with a single empty string argument +# like in the following example: +# +# save "" + +save "" +#save 900 1 +#save 300 10 +#save 60 10000 + +# By default Redis will stop accepting writes if RDB snapshots are enabled +# (at least one save point) and the latest background save failed. +# This will make the user aware (in a hard way) that data is not persisting +# on disk properly, otherwise chances are that no one will notice and some +# disaster will happen. +# +# If the background saving process will start working again Redis will +# automatically allow writes again. +# +# However if you have setup your proper monitoring of the Redis server +# and persistence, you may want to disable this feature so that Redis will +# continue to work as usual even if there are problems with disk, +# permissions, and so forth. +stop-writes-on-bgsave-error yes + +# Compress string objects using LZF when dump .rdb databases? +# For default that's set to 'yes' as it's almost always a win. +# If you want to save some CPU in the saving child set it to 'no' but +# the dataset will likely be bigger if you have compressible values or keys. +rdbcompression yes + +# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. +# This makes the format more resistant to corruption but there is a performance +# hit to pay (around 10%) when saving and loading RDB files, so you can disable it +# for maximum performances. +# +# RDB files created with checksum disabled have a checksum of zero that will +# tell the loading code to skip the check. +rdbchecksum yes + +# The filename where to dump the DB +dbfilename dump.rdb + +# The working directory. +# +# The DB will be written inside this directory, with the filename specified +# above using the 'dbfilename' configuration directive. +# +# The Append Only File will also be created inside this directory. +# +# Note that you must specify a directory here, not a file name. +dir ./ + +################################# REPLICATION ################################# + +# Master-Slave replication. Use slaveof to make a Redis instance a copy of +# another Redis server. A few things to understand ASAP about Redis replication. +# +# 1) Redis replication is asynchronous, but you can configure a master to +# stop accepting writes if it appears to be not connected with at least +# a given number of slaves. +# 2) Redis slaves are able to perform a partial resynchronization with the +# master if the replication link is lost for a relatively small amount of +# time. You may want to configure the replication backlog size (see the next +# sections of this file) with a sensible value depending on your needs. +# 3) Replication is automatic and does not need user intervention. After a +# network partition slaves automatically try to reconnect to masters +# and resynchronize with them. +# +# slaveof + +# If the master is password protected (using the "requirepass" configuration +# directive below) it is possible to tell the slave to authenticate before +# starting the replication synchronization process, otherwise the master will +# refuse the slave request. +# +# masterauth + +# When a slave loses its connection with the master, or when the replication +# is still in progress, the slave can act in two different ways: +# +# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will +# still reply to client requests, possibly with out of date data, or the +# data set may just be empty if this is the first synchronization. +# +# 2) if slave-serve-stale-data is set to 'no' the slave will reply with +# an error "SYNC with master in progress" to all the kind of commands +# but to INFO and SLAVEOF. +# +slave-serve-stale-data yes + +# You can configure a slave instance to accept writes or not. Writing against +# a slave instance may be useful to store some ephemeral data (because data +# written on a slave will be easily deleted after resync with the master) but +# may also cause problems if clients are writing to it because of a +# misconfiguration. +# +# Since Redis 2.6 by default slaves are read-only. +# +# Note: read only slaves are not designed to be exposed to untrusted clients +# on the internet. It's just a protection layer against misuse of the instance. +# Still a read only slave exports by default all the administrative commands +# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve +# security of read only slaves using 'rename-command' to shadow all the +# administrative / dangerous commands. +slave-read-only yes + +# Replication SYNC strategy: disk or socket. +# +# ------------------------------------------------------- +# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY +# ------------------------------------------------------- +# +# New slaves and reconnecting slaves that are not able to continue the replication +# process just receiving differences, need to do what is called a "full +# synchronization". An RDB file is transmitted from the master to the slaves. +# The transmission can happen in two different ways: +# +# 1) Disk-backed: The Redis master creates a new process that writes the RDB +# file on disk. Later the file is transferred by the parent +# process to the slaves incrementally. +# 2) Diskless: The Redis master creates a new process that directly writes the +# RDB file to slave sockets, without touching the disk at all. +# +# With disk-backed replication, while the RDB file is generated, more slaves +# can be queued and served with the RDB file as soon as the current child producing +# the RDB file finishes its work. With diskless replication instead once +# the transfer starts, new slaves arriving will be queued and a new transfer +# will start when the current one terminates. +# +# When diskless replication is used, the master waits a configurable amount of +# time (in seconds) before starting the transfer in the hope that multiple slaves +# will arrive and the transfer can be parallelized. +# +# With slow disks and fast (large bandwidth) networks, diskless replication +# works better. +repl-diskless-sync no + +# When diskless replication is enabled, it is possible to configure the delay +# the server waits in order to spawn the child that transfers the RDB via socket +# to the slaves. +# +# This is important since once the transfer starts, it is not possible to serve +# new slaves arriving, that will be queued for the next RDB transfer, so the server +# waits a delay in order to let more slaves arrive. +# +# The delay is specified in seconds, and by default is 5 seconds. To disable +# it entirely just set it to 0 seconds and the transfer will start ASAP. +repl-diskless-sync-delay 5 + +# Slaves send PINGs to server in a predefined interval. It's possible to change +# this interval with the repl_ping_slave_period option. The default value is 10 +# seconds. +# +# repl-ping-slave-period 10 + +# The following option sets the replication timeout for: +# +# 1) Bulk transfer I/O during SYNC, from the point of view of slave. +# 2) Master timeout from the point of view of slaves (data, pings). +# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). +# +# It is important to make sure that this value is greater than the value +# specified for repl-ping-slave-period otherwise a timeout will be detected +# every time there is low traffic between the master and the slave. +# +# repl-timeout 60 + +# Disable TCP_NODELAY on the slave socket after SYNC? +# +# If you select "yes" Redis will use a smaller number of TCP packets and +# less bandwidth to send data to slaves. But this can add a delay for +# the data to appear on the slave side, up to 40 milliseconds with +# Linux kernels using a default configuration. +# +# If you select "no" the delay for data to appear on the slave side will +# be reduced but more bandwidth will be used for replication. +# +# By default we optimize for low latency, but in very high traffic conditions +# or when the master and slaves are many hops away, turning this to "yes" may +# be a good idea. +repl-disable-tcp-nodelay no + +# Set the replication backlog size. The backlog is a buffer that accumulates +# slave data when slaves are disconnected for some time, so that when a slave +# wants to reconnect again, often a full resync is not needed, but a partial +# resync is enough, just passing the portion of data the slave missed while +# disconnected. +# +# The bigger the replication backlog, the longer the time the slave can be +# disconnected and later be able to perform a partial resynchronization. +# +# The backlog is only allocated once there is at least a slave connected. +# +# repl-backlog-size 1mb + +# After a master has no longer connected slaves for some time, the backlog +# will be freed. The following option configures the amount of seconds that +# need to elapse, starting from the time the last slave disconnected, for +# the backlog buffer to be freed. +# +# Note that slaves never free the backlog for timeout, since they may be +# promoted to masters later, and should be able to correctly "partially +# resynchronize" with the slaves: hence they should always accumulate backlog. +# +# A value of 0 means to never release the backlog. +# +# repl-backlog-ttl 3600 + +# The slave priority is an integer number published by Redis in the INFO output. +# It is used by Redis Sentinel in order to select a slave to promote into a +# master if the master is no longer working correctly. +# +# A slave with a low priority number is considered better for promotion, so +# for instance if there are three slaves with priority 10, 100, 25 Sentinel will +# pick the one with priority 10, that is the lowest. +# +# However a special priority of 0 marks the slave as not able to perform the +# role of master, so a slave with priority of 0 will never be selected by +# Redis Sentinel for promotion. +# +# By default the priority is 100. +slave-priority 100 + +# It is possible for a master to stop accepting writes if there are less than +# N slaves connected, having a lag less or equal than M seconds. +# +# The N slaves need to be in "online" state. +# +# The lag in seconds, that must be <= the specified value, is calculated from +# the last ping received from the slave, that is usually sent every second. +# +# This option does not GUARANTEE that N replicas will accept the write, but +# will limit the window of exposure for lost writes in case not enough slaves +# are available, to the specified number of seconds. +# +# For example to require at least 3 slaves with a lag <= 10 seconds use: +# +# min-slaves-to-write 3 +# min-slaves-max-lag 10 +# +# Setting one or the other to 0 disables the feature. +# +# By default min-slaves-to-write is set to 0 (feature disabled) and +# min-slaves-max-lag is set to 10. + +# A Redis master is able to list the address and port of the attached +# slaves in different ways. For example the "INFO replication" section +# offers this information, which is used, among other tools, by +# Redis Sentinel in order to discover slave instances. +# Another place where this info is available is in the output of the +# "ROLE" command of a master. +# +# The listed IP and address normally reported by a slave is obtained +# in the following way: +# +# IP: The address is auto detected by checking the peer address +# of the socket used by the slave to connect with the master. +# +# Port: The port is communicated by the slave during the replication +# handshake, and is normally the port that the slave is using to +# list for connections. +# +# However when port forwarding or Network Address Translation (NAT) is +# used, the slave may be actually reachable via different IP and port +# pairs. The following two options can be used by a slave in order to +# report to its master a specific set of IP and port, so that both INFO +# and ROLE will report those values. +# +# There is no need to use both the options if you need to override just +# the port or the IP address. +# +# slave-announce-ip 5.5.5.5 +# slave-announce-port 1234 + +################################## SECURITY ################################### + +# Require clients to issue AUTH before processing any other +# commands. This might be useful in environments in which you do not trust +# others with access to the host running redis-server. +# +# This should stay commented out for backward compatibility and because most +# people do not need auth (e.g. they run their own servers). +# +# Warning: since Redis is pretty fast an outside user can try up to +# 150k passwords per second against a good box. This means that you should +# use a very strong password otherwise it will be very easy to break. +# +# requirepass foobared + +# Command renaming. +# +# It is possible to change the name of dangerous commands in a shared +# environment. For instance the CONFIG command may be renamed into something +# hard to guess so that it will still be available for internal-use tools +# but not available for general clients. +# +# Example: +# +# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 +# +# It is also possible to completely kill a command by renaming it into +# an empty string: +# +# rename-command CONFIG "" +# +# Please note that changing the name of commands that are logged into the +# AOF file or transmitted to slaves may cause problems. + +################################### CLIENTS #################################### + +# Set the max number of connected clients at the same time. By default +# this limit is set to 10000 clients, however if the Redis server is not +# able to configure the process file limit to allow for the specified limit +# the max number of allowed clients is set to the current file limit +# minus 32 (as Redis reserves a few file descriptors for internal uses). +# +# Once the limit is reached Redis will close all the new connections sending +# an error 'max number of clients reached'. +# +# maxclients 10000 + +############################## MEMORY MANAGEMENT ################################ + +# Set a memory usage limit to the specified amount of bytes. +# When the memory limit is reached Redis will try to remove keys +# according to the eviction policy selected (see maxmemory-policy). +# +# If Redis can't remove keys according to the policy, or if the policy is +# set to 'noeviction', Redis will start to reply with errors to commands +# that would use more memory, like SET, LPUSH, and so on, and will continue +# to reply to read-only commands like GET. +# +# This option is usually useful when using Redis as an LRU or LFU cache, or to +# set a hard memory limit for an instance (using the 'noeviction' policy). +# +# WARNING: If you have slaves attached to an instance with maxmemory on, +# the size of the output buffers needed to feed the slaves are subtracted +# from the used memory count, so that network problems / resyncs will +# not trigger a loop where keys are evicted, and in turn the output +# buffer of slaves is full with DELs of keys evicted triggering the deletion +# of more keys, and so forth until the database is completely emptied. +# +# In short... if you have slaves attached it is suggested that you set a lower +# limit for maxmemory so that there is some free RAM on the system for slave +# output buffers (but this is not needed if the policy is 'noeviction'). +# +# maxmemory + +# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory +# is reached. You can select among five behaviors: +# +# volatile-lru -> Evict using approximated LRU among the keys with an expire set. +# allkeys-lru -> Evict any key using approximated LRU. +# volatile-lfu -> Evict using approximated LFU among the keys with an expire set. +# allkeys-lfu -> Evict any key using approximated LFU. +# volatile-random -> Remove a random key among the ones with an expire set. +# allkeys-random -> Remove a random key, any key. +# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) +# noeviction -> Don't evict anything, just return an error on write operations. +# +# LRU means Least Recently Used +# LFU means Least Frequently Used +# +# Both LRU, LFU and volatile-ttl are implemented using approximated +# randomized algorithms. +# +# Note: with any of the above policies, Redis will return an error on write +# operations, when there are no suitable keys for eviction. +# +# At the date of writing these commands are: set setnx setex append +# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd +# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby +# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby +# getset mset msetnx exec sort +# +# The default is: +# +# maxmemory-policy noeviction + +# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated +# algorithms (in order to save memory), so you can tune it for speed or +# accuracy. For default Redis will check five keys and pick the one that was +# used less recently, you can change the sample size using the following +# configuration directive. +# +# The default of 5 produces good enough results. 10 Approximates very closely +# true LRU but costs more CPU. 3 is faster but not very accurate. +# +# maxmemory-samples 5 + +############################# LAZY FREEING #################################### + +# Redis has two primitives to delete keys. One is called DEL and is a blocking +# deletion of the object. It means that the server stops processing new commands +# in order to reclaim all the memory associated with an object in a synchronous +# way. If the key deleted is associated with a small object, the time needed +# in order to execute th DEL command is very small and comparable to most other +# O(1) or O(log_N) commands in Redis. However if the key is associated with an +# aggregated value containing millions of elements, the server can block for +# a long time (even seconds) in order to complete the operation. +# +# For the above reasons Redis also offers non blocking deletion primitives +# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and +# FLUSHDB commands, in order to reclaim memory in background. Those commands +# are executed in constant time. Another thread will incrementally free the +# object in the background as fast as possible. +# +# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. +# It's up to the design of the application to understand when it is a good +# idea to use one or the other. However the Redis server sometimes has to +# delete keys or flush the whole database as a side effect of other operations. +# Specifically Redis deletes objects independently of an user call in the +# following scenarios: +# +# 1) On eviction, because of the maxmemory and maxmemory policy configurations, +# in order to make room for new data, without going over the specified +# memory limit. +# 2) Because of expire: when a key with an associated time to live (see the +# EXPIRE command) must be deleted from memory. +# 3) Because of a side effect of a command that stores data on a key that may +# already exist. For example the RENAME command may delete the old key +# content when it is replaced with another one. Similarly SUNIONSTORE +# or SORT with STORE option may delete existing keys. The SET command +# itself removes any old content of the specified key in order to replace +# it with the specified string. +# 4) During replication, when a slave performs a full resynchronization with +# its master, the content of the whole database is removed in order to +# load the RDB file just transfered. +# +# In all the above cases the default is to delete objects in a blocking way, +# like if DEL was called. However you can configure each case specifically +# in order to instead release memory in a non-blocking way like if UNLINK +# was called, using the following configuration directives: + +lazyfree-lazy-eviction no +lazyfree-lazy-expire no +lazyfree-lazy-server-del no +slave-lazy-flush no + +############################## APPEND ONLY MODE ############################### + +# By default Redis asynchronously dumps the dataset on disk. This mode is +# good enough in many applications, but an issue with the Redis process or +# a power outage may result into a few minutes of writes lost (depending on +# the configured save points). +# +# The Append Only File is an alternative persistence mode that provides +# much better durability. For instance using the default data fsync policy +# (see later in the config file) Redis can lose just one second of writes in a +# dramatic event like a server power outage, or a single write if something +# wrong with the Redis process itself happens, but the operating system is +# still running correctly. +# +# AOF and RDB persistence can be enabled at the same time without problems. +# If the AOF is enabled on startup Redis will load the AOF, that is the file +# with the better durability guarantees. +# +# Please check http://redis.io/topics/persistence for more information. + +appendonly no + +# The name of the append only file (default: "appendonly.aof") + +appendfilename "appendonly.aof" + +# The fsync() call tells the Operating System to actually write data on disk +# instead of waiting for more data in the output buffer. Some OS will really flush +# data on disk, some other OS will just try to do it ASAP. +# +# Redis supports three different modes: +# +# no: don't fsync, just let the OS flush the data when it wants. Faster. +# always: fsync after every write to the append only log. Slow, Safest. +# everysec: fsync only one time every second. Compromise. +# +# The default is "everysec", as that's usually the right compromise between +# speed and data safety. It's up to you to understand if you can relax this to +# "no" that will let the operating system flush the output buffer when +# it wants, for better performances (but if you can live with the idea of +# some data loss consider the default persistence mode that's snapshotting), +# or on the contrary, use "always" that's very slow but a bit safer than +# everysec. +# +# More details please check the following article: +# http://antirez.com/post/redis-persistence-demystified.html +# +# If unsure, use "everysec". + +# appendfsync always +appendfsync everysec +# appendfsync no + +# When the AOF fsync policy is set to always or everysec, and a background +# saving process (a background save or AOF log background rewriting) is +# performing a lot of I/O against the disk, in some Linux configurations +# Redis may block too long on the fsync() call. Note that there is no fix for +# this currently, as even performing fsync in a different thread will block +# our synchronous write(2) call. +# +# In order to mitigate this problem it's possible to use the following option +# that will prevent fsync() from being called in the main process while a +# BGSAVE or BGREWRITEAOF is in progress. +# +# This means that while another child is saving, the durability of Redis is +# the same as "appendfsync none". In practical terms, this means that it is +# possible to lose up to 30 seconds of log in the worst scenario (with the +# default Linux settings). +# +# If you have latency problems turn this to "yes". Otherwise leave it as +# "no" that is the safest pick from the point of view of durability. + +no-appendfsync-on-rewrite no + +# Automatic rewrite of the append only file. +# Redis is able to automatically rewrite the log file implicitly calling +# BGREWRITEAOF when the AOF log size grows by the specified percentage. +# +# This is how it works: Redis remembers the size of the AOF file after the +# latest rewrite (if no rewrite has happened since the restart, the size of +# the AOF at startup is used). +# +# This base size is compared to the current size. If the current size is +# bigger than the specified percentage, the rewrite is triggered. Also +# you need to specify a minimal size for the AOF file to be rewritten, this +# is useful to avoid rewriting the AOF file even if the percentage increase +# is reached but it is still pretty small. +# +# Specify a percentage of zero in order to disable the automatic AOF +# rewrite feature. + +auto-aof-rewrite-percentage 100 +auto-aof-rewrite-min-size 64mb + +# An AOF file may be found to be truncated at the end during the Redis +# startup process, when the AOF data gets loaded back into memory. +# This may happen when the system where Redis is running +# crashes, especially when an ext4 filesystem is mounted without the +# data=ordered option (however this can't happen when Redis itself +# crashes or aborts but the operating system still works correctly). +# +# Redis can either exit with an error when this happens, or load as much +# data as possible (the default now) and start if the AOF file is found +# to be truncated at the end. The following option controls this behavior. +# +# If aof-load-truncated is set to yes, a truncated AOF file is loaded and +# the Redis server starts emitting a log to inform the user of the event. +# Otherwise if the option is set to no, the server aborts with an error +# and refuses to start. When the option is set to no, the user requires +# to fix the AOF file using the "redis-check-aof" utility before to restart +# the server. +# +# Note that if the AOF file will be found to be corrupted in the middle +# the server will still exit with an error. This option only applies when +# Redis will try to read more data from the AOF file but not enough bytes +# will be found. +aof-load-truncated yes + +# When rewriting the AOF file, Redis is able to use an RDB preamble in the +# AOF file for faster rewrites and recoveries. When this option is turned +# on the rewritten AOF file is composed of two different stanzas: +# +# [RDB file][AOF tail] +# +# When loading Redis recognizes that the AOF file starts with the "REDIS" +# string and loads the prefixed RDB file, and continues loading the AOF +# tail. +# +# This is currently turned off by default in order to avoid the surprise +# of a format change, but will at some point be used as the default. +aof-use-rdb-preamble no + +################################ LUA SCRIPTING ############################### + +# Max execution time of a Lua script in milliseconds. +# +# If the maximum execution time is reached Redis will log that a script is +# still in execution after the maximum allowed time and will start to +# reply to queries with an error. +# +# When a long running script exceeds the maximum execution time only the +# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be +# used to stop a script that did not yet called write commands. The second +# is the only way to shut down the server in the case a write command was +# already issued by the script but the user doesn't want to wait for the natural +# termination of the script. +# +# Set it to 0 or a negative value for unlimited execution without warnings. +lua-time-limit 5000 + +################################ REDIS CLUSTER ############################### +# +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however +# in order to mark it as "mature" we need to wait for a non trivial percentage +# of users to deploy it in production. +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# Normal Redis instances can't be part of a Redis Cluster; only nodes that are +# started as cluster nodes can. In order to start a Redis instance as a +# cluster node enable the cluster support uncommenting the following: +# +# cluster-enabled yes + +# Every cluster node has a cluster configuration file. This file is not +# intended to be edited by hand. It is created and updated by Redis nodes. +# Every Redis Cluster node requires a different cluster configuration file. +# Make sure that instances running in the same system do not have +# overlapping cluster configuration file names. +# +# cluster-config-file nodes-6379.conf + +# Cluster node timeout is the amount of milliseconds a node must be unreachable +# for it to be considered in failure state. +# Most other internal time limits are multiple of the node timeout. +# +# cluster-node-timeout 15000 + +# A slave of a failing master will avoid to start a failover if its data +# looks too old. +# +# There is no simple way for a slave to actually have an exact measure of +# its "data age", so the following two checks are performed: +# +# 1) If there are multiple slaves able to failover, they exchange messages +# in order to try to give an advantage to the slave with the best +# replication offset (more data from the master processed). +# Slaves will try to get their rank by offset, and apply to the start +# of the failover a delay proportional to their rank. +# +# 2) Every single slave computes the time of the last interaction with +# its master. This can be the last ping or command received (if the master +# is still in the "connected" state), or the time that elapsed since the +# disconnection with the master (if the replication link is currently down). +# If the last interaction is too old, the slave will not try to failover +# at all. +# +# The point "2" can be tuned by user. Specifically a slave will not perform +# the failover if, since the last interaction with the master, the time +# elapsed is greater than: +# +# (node-timeout * slave-validity-factor) + repl-ping-slave-period +# +# So for example if node-timeout is 30 seconds, and the slave-validity-factor +# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the +# slave will not try to failover if it was not able to talk with the master +# for longer than 310 seconds. +# +# A large slave-validity-factor may allow slaves with too old data to failover +# a master, while a too small value may prevent the cluster from being able to +# elect a slave at all. +# +# For maximum availability, it is possible to set the slave-validity-factor +# to a value of 0, which means, that slaves will always try to failover the +# master regardless of the last time they interacted with the master. +# (However they'll always try to apply a delay proportional to their +# offset rank). +# +# Zero is the only value able to guarantee that when all the partitions heal +# the cluster will always be able to continue. +# +# cluster-slave-validity-factor 10 + +# Cluster slaves are able to migrate to orphaned masters, that are masters +# that are left without working slaves. This improves the cluster ability +# to resist to failures as otherwise an orphaned master can't be failed over +# in case of failure if it has no working slaves. +# +# Slaves migrate to orphaned masters only if there are still at least a +# given number of other working slaves for their old master. This number +# is the "migration barrier". A migration barrier of 1 means that a slave +# will migrate only if there is at least 1 other working slave for its master +# and so forth. It usually reflects the number of slaves you want for every +# master in your cluster. +# +# Default is 1 (slaves migrate only if their masters remain with at least +# one slave). To disable migration just set it to a very large value. +# A value of 0 can be set but is useful only for debugging and dangerous +# in production. +# +# cluster-migration-barrier 1 + +# By default Redis Cluster nodes stop accepting queries if they detect there +# is at least an hash slot uncovered (no available node is serving it). +# This way if the cluster is partially down (for example a range of hash slots +# are no longer covered) all the cluster becomes, eventually, unavailable. +# It automatically returns available as soon as all the slots are covered again. +# +# However sometimes you want the subset of the cluster which is working, +# to continue to accept queries for the part of the key space that is still +# covered. In order to do so, just set the cluster-require-full-coverage +# option to no. +# +# cluster-require-full-coverage yes + +# In order to setup your cluster make sure to read the documentation +# available at http://redis.io web site. + +########################## CLUSTER DOCKER/NAT support ######################## + +# In certain deployments, Redis Cluster nodes address discovery fails, because +# addresses are NAT-ted or because ports are forwarded (the typical case is +# Docker and other containers). +# +# In order to make Redis Cluster working in such environments, a static +# configuration where each node known its public address is needed. The +# following two options are used for this scope, and are: +# +# * cluster-announce-ip +# * cluster-announce-port +# * cluster-announce-bus-port +# +# Each instruct the node about its address, client port, and cluster message +# bus port. The information is then published in the header of the bus packets +# so that other nodes will be able to correctly map the address of the node +# publishing the information. +# +# If the above options are not used, the normal Redis Cluster auto-detection +# will be used instead. +# +# Note that when remapped, the bus port may not be at the fixed offset of +# clients port + 10000, so you can specify any port and bus-port depending +# on how they get remapped. If the bus-port is not set, a fixed offset of +# 10000 will be used as usually. +# +# Example: +# +# cluster-announce-ip 10.1.1.5 +# cluster-announce-port 6379 +# cluster-announce-bus-port 6380 + +################################## SLOW LOG ################################### + +# The Redis Slow Log is a system to log queries that exceeded a specified +# execution time. The execution time does not include the I/O operations +# like talking with the client, sending the reply and so forth, +# but just the time needed to actually execute the command (this is the only +# stage of command execution where the thread is blocked and can not serve +# other requests in the meantime). +# +# You can configure the slow log with two parameters: one tells Redis +# what is the execution time, in microseconds, to exceed in order for the +# command to get logged, and the other parameter is the length of the +# slow log. When a new command is logged the oldest one is removed from the +# queue of logged commands. + +# The following time is expressed in microseconds, so 1000000 is equivalent +# to one second. Note that a negative number disables the slow log, while +# a value of zero forces the logging of every command. +slowlog-log-slower-than 10000 + +# There is no limit to this length. Just be aware that it will consume memory. +# You can reclaim memory used by the slow log with SLOWLOG RESET. +slowlog-max-len 128 + +################################ LATENCY MONITOR ############################## + +# The Redis latency monitoring subsystem samples different operations +# at runtime in order to collect data related to possible sources of +# latency of a Redis instance. +# +# Via the LATENCY command this information is available to the user that can +# print graphs and obtain reports. +# +# The system only logs operations that were performed in a time equal or +# greater than the amount of milliseconds specified via the +# latency-monitor-threshold configuration directive. When its value is set +# to zero, the latency monitor is turned off. +# +# By default latency monitoring is disabled since it is mostly not needed +# if you don't have latency issues, and collecting data has a performance +# impact, that while very small, can be measured under big load. Latency +# monitoring can easily be enabled at runtime using the command +# "CONFIG SET latency-monitor-threshold " if needed. +latency-monitor-threshold 0 + +############################# EVENT NOTIFICATION ############################## + +# Redis can notify Pub/Sub clients about events happening in the key space. +# This feature is documented at http://redis.io/topics/notifications +# +# For instance if keyspace events notification is enabled, and a client +# performs a DEL operation on key "foo" stored in the Database 0, two +# messages will be published via Pub/Sub: +# +# PUBLISH __keyspace@0__:foo del +# PUBLISH __keyevent@0__:del foo +# +# It is possible to select the events that Redis will notify among a set +# of classes. Every class is identified by a single character: +# +# K Keyspace events, published with __keyspace@__ prefix. +# E Keyevent events, published with __keyevent@__ prefix. +# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... +# $ String commands +# l List commands +# s Set commands +# h Hash commands +# z Sorted set commands +# x Expired events (events generated every time a key expires) +# e Evicted events (events generated when a key is evicted for maxmemory) +# A Alias for g$lshzxe, so that the "AKE" string means all the events. +# +# The "notify-keyspace-events" takes as argument a string that is composed +# of zero or multiple characters. The empty string means that notifications +# are disabled. +# +# Example: to enable list and generic events, from the point of view of the +# event name, use: +# +# notify-keyspace-events Elg +# +# Example 2: to get the stream of the expired keys subscribing to channel +# name __keyevent@0__:expired use: +# +# notify-keyspace-events Ex +# +# By default all notifications are disabled because most users don't need +# this feature and the feature has some overhead. Note that if you don't +# specify at least one of K or E, no events will be delivered. +notify-keyspace-events "" + +############################### ADVANCED CONFIG ############################### + +# Hashes are encoded using a memory efficient data structure when they have a +# small number of entries, and the biggest entry does not exceed a given +# threshold. These thresholds can be configured using the following directives. +hash-max-ziplist-entries 512 +hash-max-ziplist-value 64 + +# Lists are also encoded in a special way to save a lot of space. +# The number of entries allowed per internal list node can be specified +# as a fixed maximum size or a maximum number of elements. +# For a fixed maximum size, use -5 through -1, meaning: +# -5: max size: 64 Kb <-- not recommended for normal workloads +# -4: max size: 32 Kb <-- not recommended +# -3: max size: 16 Kb <-- probably not recommended +# -2: max size: 8 Kb <-- good +# -1: max size: 4 Kb <-- good +# Positive numbers mean store up to _exactly_ that number of elements +# per list node. +# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), +# but if your use case is unique, adjust the settings as necessary. +list-max-ziplist-size -2 + +# Lists may also be compressed. +# Compress depth is the number of quicklist ziplist nodes from *each* side of +# the list to *exclude* from compression. The head and tail of the list +# are always uncompressed for fast push/pop operations. Settings are: +# 0: disable all list compression +# 1: depth 1 means "don't start compressing until after 1 node into the list, +# going from either the head or tail" +# So: [head]->node->node->...->node->[tail] +# [head], [tail] will always be uncompressed; inner nodes will compress. +# 2: [head]->[next]->node->node->...->node->[prev]->[tail] +# 2 here means: don't compress head or head->next or tail->prev or tail, +# but compress all nodes between them. +# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] +# etc. +list-compress-depth 0 + +# Sets have a special encoding in just one case: when a set is composed +# of just strings that happen to be integers in radix 10 in the range +# of 64 bit signed integers. +# The following configuration setting sets the limit in the size of the +# set in order to use this special memory saving encoding. +set-max-intset-entries 512 + +# Similarly to hashes and lists, sorted sets are also specially encoded in +# order to save a lot of space. This encoding is only used when the length and +# elements of a sorted set are below the following limits: +zset-max-ziplist-entries 128 +zset-max-ziplist-value 64 + +# HyperLogLog sparse representation bytes limit. The limit includes the +# 16 bytes header. When an HyperLogLog using the sparse representation crosses +# this limit, it is converted into the dense representation. +# +# A value greater than 16000 is totally useless, since at that point the +# dense representation is more memory efficient. +# +# The suggested value is ~ 3000 in order to have the benefits of +# the space efficient encoding without slowing down too much PFADD, +# which is O(N) with the sparse encoding. The value can be raised to +# ~ 10000 when CPU is not a concern, but space is, and the data set is +# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. +hll-sparse-max-bytes 3000 + +# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in +# order to help rehashing the main Redis hash table (the one mapping top-level +# keys to values). The hash table implementation Redis uses (see dict.c) +# performs a lazy rehashing: the more operation you run into a hash table +# that is rehashing, the more rehashing "steps" are performed, so if the +# server is idle the rehashing is never complete and some more memory is used +# by the hash table. +# +# The default is to use this millisecond 10 times every second in order to +# actively rehash the main dictionaries, freeing memory when possible. +# +# If unsure: +# use "activerehashing no" if you have hard latency requirements and it is +# not a good thing in your environment that Redis can reply from time to time +# to queries with 2 milliseconds delay. +# +# use "activerehashing yes" if you don't have such hard requirements but +# want to free memory asap when possible. +activerehashing yes + +# The client output buffer limits can be used to force disconnection of clients +# that are not reading data from the server fast enough for some reason (a +# common reason is that a Pub/Sub client can't consume messages as fast as the +# publisher can produce them). +# +# The limit can be set differently for the three different classes of clients: +# +# normal -> normal clients including MONITOR clients +# slave -> slave clients +# pubsub -> clients subscribed to at least one pubsub channel or pattern +# +# The syntax of every client-output-buffer-limit directive is the following: +# +# client-output-buffer-limit +# +# A client is immediately disconnected once the hard limit is reached, or if +# the soft limit is reached and remains reached for the specified number of +# seconds (continuously). +# So for instance if the hard limit is 32 megabytes and the soft limit is +# 16 megabytes / 10 seconds, the client will get disconnected immediately +# if the size of the output buffers reach 32 megabytes, but will also get +# disconnected if the client reaches 16 megabytes and continuously overcomes +# the limit for 10 seconds. +# +# By default normal clients are not limited because they don't receive data +# without asking (in a push way), but just after a request, so only +# asynchronous clients may create a scenario where data is requested faster +# than it can read. +# +# Instead there is a default limit for pubsub and slave clients, since +# subscribers and slaves receive data in a push fashion. +# +# Both the hard or the soft limit can be disabled by setting them to zero. +client-output-buffer-limit normal 0 0 0 +client-output-buffer-limit slave 256mb 64mb 60 +client-output-buffer-limit pubsub 32mb 8mb 60 + +# Redis calls an internal function to perform many background tasks, like +# closing connections of clients in timeout, purging expired keys that are +# never requested, and so forth. +# +# Not all tasks are performed with the same frequency, but Redis checks for +# tasks to perform according to the specified "hz" value. +# +# By default "hz" is set to 10. Raising the value will use more CPU when +# Redis is idle, but at the same time will make Redis more responsive when +# there are many keys expiring at the same time, and timeouts may be +# handled with more precision. +# +# The range is between 1 and 500, however a value over 100 is usually not +# a good idea. Most users should use the default of 10 and raise this up to +# 100 only in environments where very low latency is required. +hz 10 + +# When a child rewrites the AOF file, if the following option is enabled +# the file will be fsync-ed every 32 MB of data generated. This is useful +# in order to commit the file to the disk more incrementally and avoid +# big latency spikes. +aof-rewrite-incremental-fsync yes + +# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good +# idea to start with the default settings and only change them after investigating +# how to improve the performances and how the keys LFU change over time, which +# is possible to inspect via the OBJECT FREQ command. +# +# There are two tunable parameters in the Redis LFU implementation: the +# counter logarithm factor and the counter decay time. It is important to +# understand what the two parameters mean before changing them. +# +# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis +# uses a probabilistic increment with logarithmic behavior. Given the value +# of the old counter, when a key is accessed, the counter is incremented in +# this way: +# +# 1. A random number R between 0 and 1 is extracted. +# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). +# 3. The counter is incremented only if R < P. +# +# The default lfu-log-factor is 10. This is a table of how the frequency +# counter changes with a different number of accesses with different +# logarithmic factors: +# +# +--------+------------+------------+------------+------------+------------+ +# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | +# +--------+------------+------------+------------+------------+------------+ +# | 0 | 104 | 255 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 1 | 18 | 49 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 10 | 10 | 18 | 142 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 100 | 8 | 11 | 49 | 143 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# +# NOTE: The above table was obtained by running the following commands: +# +# redis-benchmark -n 1000000 incr foo +# redis-cli object freq foo +# +# NOTE 2: The counter initial value is 5 in order to give new objects a chance +# to accumulate hits. +# +# The counter decay time is the time, in minutes, that must elapse in order +# for the key counter to be divided by two (or decremented if it has a value +# less <= 10). +# +# The default value for the lfu-decay-time is 1. A Special value of 0 means to +# decay the counter every time it happens to be scanned. +# +# lfu-log-factor 10 +# lfu-decay-time 1 + +########################### ACTIVE DEFRAGMENTATION ####################### +# +# WARNING THIS FEATURE IS EXPERIMENTAL. However it was stress tested +# even in production and manually tested by multiple engineers for some +# time. +# +# What is active defragmentation? +# ------------------------------- +# +# Active (online) defragmentation allows a Redis server to compact the +# spaces left between small allocations and deallocations of data in memory, +# thus allowing to reclaim back memory. +# +# Fragmentation is a natural process that happens with every allocator (but +# less so with Jemalloc, fortunately) and certain workloads. Normally a server +# restart is needed in order to lower the fragmentation, or at least to flush +# away all the data and create it again. However thanks to this feature +# implemented by Oran Agra for Redis 4.0 this process can happen at runtime +# in an "hot" way, while the server is running. +# +# Basically when the fragmentation is over a certain level (see the +# configuration options below) Redis will start to create new copies of the +# values in contiguous memory regions by exploiting certain specific Jemalloc +# features (in order to understand if an allocation is causing fragmentation +# and to allocate it in a better place), and at the same time, will release the +# old copies of the data. This process, repeated incrementally for all the keys +# will cause the fragmentation to drop back to normal values. +# +# Important things to understand: +# +# 1. This feature is disabled by default, and only works if you compiled Redis +# to use the copy of Jemalloc we ship with the source code of Redis. +# This is the default with Linux builds. +# +# 2. You never need to enable this feature if you don't have fragmentation +# issues. +# +# 3. Once you experience fragmentation, you can enable this feature when +# needed with the command "CONFIG SET activedefrag yes". +# +# The configuration parameters are able to fine tune the behavior of the +# defragmentation process. If you are not sure about what they mean it is +# a good idea to leave the defaults untouched. + +# Enabled active defragmentation +# activedefrag yes + +# Minimum amount of fragmentation waste to start active defrag +# active-defrag-ignore-bytes 100mb + +# Minimum percentage of fragmentation to start active defrag +# active-defrag-threshold-lower 10 + +# Maximum percentage of fragmentation at which we use maximum effort +# active-defrag-threshold-upper 100 + +# Minimal effort for defrag in CPU percentage +# active-defrag-cycle-min 25 + +# Maximal effort for defrag in CPU percentage +# active-defrag-cycle-max 75 \ No newline at end of file diff --git a/ServiceApi/.babelrc b/ServiceApi/.babelrc new file mode 100644 index 0000000..457a3ac --- /dev/null +++ b/ServiceApi/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": [ + "es2015", + "stage-0" + ], + "sourceMaps": true, + "retainLines": true +} \ No newline at end of file diff --git a/ServiceApi/.eslintignore b/ServiceApi/.eslintignore new file mode 100644 index 0000000..f517d4c --- /dev/null +++ b/ServiceApi/.eslintignore @@ -0,0 +1,6 @@ +blueprints/**/files/** +coverage/** +node_modules/** +dist/** +*.spec.js +src/index.html diff --git a/ServiceApi/.eslintrc b/ServiceApi/.eslintrc new file mode 100644 index 0000000..559d574 --- /dev/null +++ b/ServiceApi/.eslintrc @@ -0,0 +1,22 @@ +{ + "extends": "eslint:recommended", + "env": { + "browser": true, + "commonjs": true, + "node": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 2017, + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true + } + }, + "rules": { + "no-console": 1, + "strict": ["error", "global"], + "curly": "warn", + "no-unused-vars": "warn" + } +} \ No newline at end of file diff --git a/ServiceApi/.gitignore b/ServiceApi/.gitignore new file mode 100644 index 0000000..2cd8e26 --- /dev/null +++ b/ServiceApi/.gitignore @@ -0,0 +1,5 @@ +/dist +/logs +/npm-debug.log +/node_modules +.DS_Store diff --git a/ServiceApi/.vscode/launch.json b/ServiceApi/.vscode/launch.json new file mode 100644 index 0000000..6e321f6 --- /dev/null +++ b/ServiceApi/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/debug.js", + "stopOnEntry": false, + "args": [], + "cwd": "${workspaceRoot}", + "preLaunchTask": null, + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "sourceMaps": true, + "outFiles": [] + }, + { + "name": "Attach", + "type": "node", + "request": "attach", + "port": 5858, + "address": "localhost", + "restart": false, + "sourceMaps": false, + "outFiles": [], + "localRoot": "${workspaceRoot}", + "remoteRoot": null + }, + { + "name": "Attach to Process", + "type": "node", + "request": "attach", + "processId": "${command.PickProcess}", + "port": 5858, + "sourceMaps": false, + "outFiles": [] + } + ] +} \ No newline at end of file diff --git a/ServiceApi/.vscode/settings.json b/ServiceApi/.vscode/settings.json new file mode 100644 index 0000000..e02dd17 --- /dev/null +++ b/ServiceApi/.vscode/settings.json @@ -0,0 +1,4 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "javascript.validate.enable": false +} \ No newline at end of file diff --git a/ServiceApi/Dockerfile b/ServiceApi/Dockerfile new file mode 100644 index 0000000..89241f8 --- /dev/null +++ b/ServiceApi/Dockerfile @@ -0,0 +1,14 @@ +FROM node:8.10 + +# Set a timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +COPY . . +RUN yarn install +RUN yarn run build + +CMD node dist + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f localhost:8081/api || exit 1 diff --git a/ServiceApi/apidoc.json b/ServiceApi/apidoc.json new file mode 100644 index 0000000..2de70a9 --- /dev/null +++ b/ServiceApi/apidoc.json @@ -0,0 +1,11 @@ +{ + "name": "Ambar Web API", + "version": "0.9.5", + "description": "Ambar Web API documentation", + "title": "Custom apiDoc browser title", + "url" : "https://api.github.com/v1", + "template": { + "withCompare": true, + "withGenerator": true + } +} \ No newline at end of file diff --git a/ServiceApi/debug.js b/ServiceApi/debug.js new file mode 100644 index 0000000..eb7b6e6 --- /dev/null +++ b/ServiceApi/debug.js @@ -0,0 +1,2 @@ +require('babel-register'); +require('./src/index.js'); \ No newline at end of file diff --git a/ServiceApi/jsconfig.json b/ServiceApi/jsconfig.json new file mode 100644 index 0000000..0136d6f --- /dev/null +++ b/ServiceApi/jsconfig.json @@ -0,0 +1,16 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=759670 + // for the documentation about the jsconfig.json format + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "allowSyntheticDefaultImports": true + }, + "exclude": [ + "node_modules", + "bower_components", + "jspm_packages", + "tmp", + "temp" + ] +} diff --git a/ServiceApi/package.json b/ServiceApi/package.json new file mode 100644 index 0000000..8fa9be0 --- /dev/null +++ b/ServiceApi/package.json @@ -0,0 +1,59 @@ +{ + "name": "ambar-serviceapi", + "version": "1.3.0", + "description": "Ambar ServiceAPI", + "main": "dist", + "scripts": { + "dev": "nodemon -w src --exec \"yarn run lint && babel-node src\"", + "build": "yarn run lint && babel src -s -D -d dist", + "start": "node dist", + "prestart": "npm run -s build", + "lint": "eslint --ext js src", + "docs": "apidoc -i src/api -o doc/ && apidoc-markdown -p doc/ -o API_DOC.md" + }, + "babel": { + "presets": [ + "es2015", + "stage-0" + ], + "sourceMaps": true, + "retainLines": true + }, + "author": "RD17 ", + "license": "MIT", + "dependencies": { + "JSONStream": "^1.2.1", + "amqplib": "^0.5.1", + "babel-eslint": "^7.1.0", + "babel-plugin-remove-code": "^0.0.6", + "bluebird": "^3.4.7", + "body-parser": "^1.13.3", + "combined-stream2": "^1.1.2", + "compression": "^1.5.2", + "cors": "^2.7.1", + "cron": "^1.1.1", + "cron-parser": "^2.3.1", + "elasticsearch": "^12.1.3", + "eslint-plugin-babel": "^3.3.0", + "eslint-plugin-promise": "^3.3.0", + "express": "^4.13.3", + "file-type": "^3.8.0", + "gridfs-stream": "^1.1.1", + "moment": "^2.15.0", + "mongodb": "^2.2.10", + "multer": "^1.2.0", + "redis": "^2.6.3", + "request": "^2.76.0", + "resource-router-middleware": "^0.5.1", + "streamifier": "^0.1.1" + }, + "devDependencies": { + "babel-cli": "^6.9.0", + "babel-core": "^6.9.0", + "babel-preset-es2015": "^6.9.0", + "babel-preset-stage-0": "^6.5.0", + "babel-register": "^6.18.0", + "eslint": "^4.19.1", + "nodemon": "^1.9.2" + } +} diff --git a/ServiceApi/src/api/files.js b/ServiceApi/src/api/files.js new file mode 100644 index 0000000..95a76b9 --- /dev/null +++ b/ServiceApi/src/api/files.js @@ -0,0 +1,284 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import { + CryptoService, + EsLowLevelProxy, + EsProxy, + CacheProxy, + GridFsProxy, + FileUploader, + QueueProxy +} from '../services' +import * as MetaBuilder from '../utils/MetaBuilder' + +const generateMetaId = (source_id, full_name, created_datetime, updated_datetime) => { + return CryptoService.getSha256(`${source_id}${full_name}${created_datetime}${updated_datetime}`) +} + +const generateFileId = (source_id, full_name) => { + return CryptoService.getSha256(`${source_id}${full_name}`) +} + +const generateExtractedTextFileName = (sha) => `text_${sha}` + +export default ({ storage }) => { + let api = Router() + + //////////////// CALLED FROM CRAWLERS //////////////////////////////////// + /** + * Check if partial meta exists in ES (TURBO) + */ + api.post('/meta/exists', (req, res, next) => { + const { body: { full_name, updated_datetime, created_datetime, source_id } } = req + + if (!full_name || !updated_datetime || !created_datetime || !source_id) { + res.status(400).json(new ErrorResponse('Required field is missing')) + return + } + + const metaId = generateMetaId(source_id, full_name, created_datetime, updated_datetime) + + CacheProxy.checkIfMetaIdExists(storage.redis, metaId) + .then((redisResult) => { + if (redisResult) { + return 200 + } + + return EsProxy.checkIfMetaIdExists(storage.elasticSearch, metaId) + .then(exists => { + if (exists) { + CacheProxy.addMetaId(storage.redis, metaId) + return 200 + } + return 404 + }) + }) + .then((statusToSend) => { + res.sendStatus(statusToSend) + }) + .catch(next) + }) + + /** + * Enqueue meta for specified sha (enqueuing message to pipeline) + */ + api.post('/meta/:sha/:sourceId', (req, res, next) => { + const { body: requestBody, params: { sha, sourceId: sourceId } } = req + + if (!requestBody) { + res.status(400).json(new ErrorResponse('Empty request')) + return + } + + const meta = MetaBuilder.buildMeta(requestBody) + + if (!meta || !sha) { + res.status(400).json(new ErrorResponse('Invalid request')) + return + } + + QueueProxy.enqueuePipelineMessage(storage, { sha: sha, fileId: generateFileId(meta.source_id, meta.full_name), sourceId: sourceId, meta: meta }) + .then(() => { + CacheProxy.addMetaId(storage.redis, meta.id) + res.sendStatus(200) + }) + .catch(next) + }) + + /* + * Check if parsed content exists + */ + api.head('/content/:sha/parsed', (req, res, next) => { + const sha = req.params.sha + + const fileName = generateExtractedTextFileName(sha) + + GridFsProxy.checkIfFileExist(storage.mongoDb, fileName) + .then(found => found ? sha : null) + .then(sha => { + if (!sha) { + res.sendStatus(404) + return + } + + res.sendStatus(302) + }) + .catch(next) + }) + + /** + * Create content + */ + api.post('/content/:sha', FileUploader, (req, res, next) => { + let { params: { sha: clientHash }, files } = req + const fileContent = (Buffer.isBuffer(files[0].buffer) && Buffer.byteLength(files[0].buffer) > 0) ? files[0].buffer : new Buffer(0) + const serverHash = CryptoService.getSha256(fileContent) + + if (serverHash.toLowerCase() !== clientHash.toLowerCase()) { + res.status(400).json(new ErrorResponse(`Server hash isn't equal client hash. Server hash: '${serverHash}'`)) + return + } + + GridFsProxy.checkIfFileExist(storage.mongoDb, serverHash) + .then(found => { + if (found) { + res.sendStatus(302) + return + } + + return GridFsProxy.uploadFile(storage.mongoDb, serverHash, fileContent) + .then(() => res.sendStatus(201)) + }) + .catch(next) + }) + + //////////////// CALLED FROM PIPELINE //////////////////////////////////// + /** + * Get file content by sha + */ + api.get('/content/:sha', (req, res, next) => { + const sha = req.params.sha + + GridFsProxy.checkIfFileExist(storage.mongoDb, sha) + .then(found => found ? sha : null) + .then(sha => { + if (!sha) { + res.sendStatus(404) + return + } + + res.writeHead(200, { + 'Content-Type': 'application/octet-stream', + 'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(sha)}` + }) + + GridFsProxy.downloadFile(storage.mongoDb, sha).pipe(res) + + return + }) + .catch(next) + }) + + /** + * Delete file content by sha + */ + api.delete('/content/:sha', (req, res, next) => { + const sha = req.params.sha + + GridFsProxy.checkIfFileExist(storage.mongoDb, sha) + .then(found => found ? sha : null) + .then(sha => { + if (!sha) { + res.sendStatus(404) + return + } + + return GridFsProxy.removeFile(storage.mongoDb, sha) + .then(() => res.sendStatus(200)) + }) + .catch(next) + }) + + /** + * Get parsed file content by sha + */ + api.get('/content/:sha/parsed', (req, res, next) => { + const sha = req.params.sha + + const fileName = generateExtractedTextFileName(sha) + + GridFsProxy.checkIfFileExist(storage.mongoDb, fileName) + .then(found => found ? fileName : null) + .then(fileName => { + if (!fileName) { + res.sendStatus(404) + return + } + + res.writeHead(200, { + 'Content-Type': 'application/octet-stream', + 'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(fileName)}` + }) + + GridFsProxy.downloadFile(storage.mongoDb, fileName).pipe(res) + + return + }) + .catch(next) + }) + + /** + * Get file content fields from ES + */ + api.get('/content/:sha/fields', (req, res, next) => { + const { params: { sha } } = req + + EsProxy.getFileBySha(storage.elasticSearch, sha) + .then(ambarFile => { + if (!ambarFile) { + res.sendStatus(404) + return + } + + res.status(200).json(ambarFile.content) + }) + .catch(next) + }) + + /** + * Update or create ambar file + */ + api.post('/file/:fileId/processed', FileUploader, (req, res, next) => { + const { params: { fileId }, files } = req + + const file = (Buffer.isBuffer(files[0].buffer) && Buffer.byteLength(files[0].buffer) > 0) ? files[0].buffer : new Buffer(0) + + EsLowLevelProxy.updateFile(fileId, file) + .then((result) => { + if (result === 'created') { + res.sendStatus(201) + return + } + + if (result === 'updated') { + res.sendStatus(200) + return + } + + throw new Error(result) + }) + .catch(next) + }) + + /** + * Upload parsed text to GridFS + */ + api.post('/content/:sha/extracted', FileUploader, (req, res, next) => { + const { params: { sha }, files } = req + + const extractedTextFileName = generateExtractedTextFileName(sha) + + const file = (Buffer.isBuffer(files[0].buffer) && Buffer.byteLength(files[0].buffer) > 0) ? files[0].buffer : new Buffer(0) + + GridFsProxy.uploadPlainTextFile(storage.mongoDb, extractedTextFileName, file) + .then(() => { + res.sendStatus(200) + }) + .catch(next) + }) + + /** + * Delete aututags and NEs + */ + api.delete('/autotags/:fileId', (req, res, next) => { + const { params: { fileId } } = req + + EsProxy.deleteAutoTags(storage.elasticSearch, fileId) + .then(() => { + res.sendStatus(200) + }) + .catch(next) + }) + + return api +} \ No newline at end of file diff --git a/ServiceApi/src/api/index.js b/ServiceApi/src/api/index.js new file mode 100644 index 0000000..3037221 --- /dev/null +++ b/ServiceApi/src/api/index.js @@ -0,0 +1,23 @@ +import { version } from '../../package.json' +import { Router } from 'express' +import files from './files' +import logs from './logs' +import thumbs from './thumbs' +import tags from './tags' + +export default ({ config, storage }) => { + let api = Router() + + api.use('/files', files({ config, storage })) + api.use('/logs', logs({ config, storage })) + api.use('/thumbs', thumbs({ config, storage })) + api.use('/tags', tags({ config, storage })) + + api.get('/', (req, res) => { + res.json({ + version: version + }) + }) + + return api +} diff --git a/ServiceApi/src/api/logs.js b/ServiceApi/src/api/logs.js new file mode 100644 index 0000000..e23e7fd --- /dev/null +++ b/ServiceApi/src/api/logs.js @@ -0,0 +1,24 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import { EsProxy } from '../services' + +export default ({ storage }) => { + let api = Router() + + /** + * Submit log record + */ + api.post('/', (req, res) => { + const { body: logItem } = req + + if (!logItem) { + res.status(400).json(new ErrorResponse('Bad request')) + return + } + + res.sendStatus(200) //Immediately send response + EsProxy.indexLogItem(storage.elasticSearch, logItem) + }) + + return api +} diff --git a/ServiceApi/src/api/tags.js b/ServiceApi/src/api/tags.js new file mode 100644 index 0000000..2e1c523 --- /dev/null +++ b/ServiceApi/src/api/tags.js @@ -0,0 +1,58 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import { + CryptoService, + MongoProxy, + CacheProxy +} from '../services' + +const AUTO_TAG_TYPE = 'auto' +const SOURCE_TAG_TYPE = 'source' + +const generateTagId = (fileId, tagType, tagName) => { + return CryptoService.getSha256(`tag_${fileId.trim().toLowerCase()}${tagType.trim().toLowerCase()}${tagName.trim().toLowerCase()}`) +} + +export default ({ storage }) => { + let api = Router() + + /** + * Add tag for specified file id + */ + api.post('/service/:fileId/:tagType/:tagName', (req, res, next) => { + const { params: { fileId, tagName, tagType } } = req + + if (!tagName || !fileId || !tagType || ((tagType.toLowerCase() != AUTO_TAG_TYPE) && (tagType.toLowerCase() != SOURCE_TAG_TYPE))) { + res.status(400).json(new ErrorResponse('Required field is missing')) + return + } + + const type = tagType.toLowerCase() + const tagId = generateTagId(fileId, type, tagName) + + const tag = { + id: tagId, + type: type, + name: tagName.toLowerCase() + } + + CacheProxy.addTag(storage.redis, storage.elasticSearch, fileId, tag) + .then(() => { + res.sendStatus(200) + }) + .catch(next) + }) + + /** + * Get tagging rules + */ + api.get('/service/taggingrules', (req, res, next) => { + MongoProxy.getTaggingRules(storage.mongoDb) + .then(rules => { + res.status(200).json(rules) + }) + .catch(next) + }) + + return api +} \ No newline at end of file diff --git a/ServiceApi/src/api/thumbs.js b/ServiceApi/src/api/thumbs.js new file mode 100644 index 0000000..2ff41c4 --- /dev/null +++ b/ServiceApi/src/api/thumbs.js @@ -0,0 +1,29 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import { MongoProxy, FileUploader } from '../services' + +export default ({ storage }) => { + let api = Router() + + /** + * Add or update thumbnail + */ + api.post('/:id', FileUploader, (req, res, next) => { + const { params: { id: thumbId }, files } = req + + if (!files) { + res.status(400).json(new ErrorResponse('Request body is empty')) + return + } + + const fileContent = Buffer.byteLength(files[0].buffer) > 0 ? files[0].buffer : new Buffer(0) + + MongoProxy.createThumbnail(storage.mongoDb, thumbId, fileContent) + .then(() => { + res.sendStatus(200) + }) + .catch(next) + }) + + return api +} \ No newline at end of file diff --git a/ServiceApi/src/config.js b/ServiceApi/src/config.js new file mode 100644 index 0000000..cb520be --- /dev/null +++ b/ServiceApi/src/config.js @@ -0,0 +1,34 @@ +const defaultConfig = { + "localPort": 8081, + "bodyLimit": "1024mb", + "corsHeaders": ["Link"], + "mongoDbUrl": "mongodb://ambar:27017/ambar_data", + "elasticSearchUrl": "http://ambar:9200", + "redisHost": "ambar", + "redisPort": "6379", + "rabbitHost": "amqp://ambar", + "defaultAccountName": "Administrator", + "defaultAccountEmail": "admin", + "defaultAccountRole": "admin", + "langAnalyzer": "ambar_en", + "defaultTaggingRules": [] +} + +let config = null + +const init = () => { + const env = process.env + + return { + ...defaultConfig, + ...env + } +} + +export default (() => { + return config === null + ? init() + : config +})() + + diff --git a/ServiceApi/src/index.js b/ServiceApi/src/index.js new file mode 100644 index 0000000..48414a7 --- /dev/null +++ b/ServiceApi/src/index.js @@ -0,0 +1,52 @@ +import http from 'http' +import express from 'express' +import cors from 'cors' +import bodyParser from 'body-parser' +import api from './api' +import config from './config' +import { ErrorHandlerService, EsProxy, MongoProxy, StorageService } from './services' + +const createLogRecord = (type, message) => ({ + type: type, + source_id: 'serviceapi', + message: message +}) + +let app = express() + +app.server = http.createServer(app) + +app.use(cors({ + credentials: true, + origin: true +})) + +app.use(bodyParser.json({ + limit: config.bodyLimit +})) + +// connect to storage +StorageService.initializeStorage() + .then((storage) => + MongoProxy.initDefaultTaggingRules(storage.mongoDb) + .then(() => { + app.use('/api', api({ config, storage })) + app.use(ErrorHandlerService(storage.elasticSearch)) + app.server.listen(process.env.PORT || config.localPort) + + //eslint-disable-next-line no-console + console.log(`Started on ${app.server.address().address}:${app.server.address().port}`) + + EsProxy.indexLogItem( + storage.elasticSearch, + createLogRecord('info', `Started on ${app.server.address().address}:${app.server.address().port}`) + ) + }) + ) + .catch((err) => { + //eslint-disable-next-line no-console + console.log('Catastrophic failure!', err.toString()) + process.exit(1) + }) + +export default app \ No newline at end of file diff --git a/ServiceApi/src/services/CacheProxy.js b/ServiceApi/src/services/CacheProxy.js new file mode 100644 index 0000000..9ab2783 --- /dev/null +++ b/ServiceApi/src/services/CacheProxy.js @@ -0,0 +1,93 @@ +import { EsProxy, DateTimeService } from './index' + +const TAGS_HASH_NAME = 'tags' + +export const checkIfMetaIdExists = (redis, metaId) => redis.getAsync(`meta:${metaId}`) +export const addMetaId = (redis, metaId) => { redis.set(`meta:${metaId}`, DateTimeService.getCurrentDateTime()) } + +export const addTag = (redis, elasticSearch, fileId, tag) => new Promise((resolve, reject) => { + EsProxy.indexTag(elasticSearch, fileId, tag) + .then((esResult) => + hasTagsInRedis(redis) + .then(hasTags => { + if (hasTags && esResult.result == 'created') { + return getTagFilesCount(redis, tag.name, tag.type) + .then(filesCount => { + setTagFilesCount(redis, tag.name, tag.type, filesCount + 1) + }) + } + return Promise.resolve() + })) + .then(() => getTags(redis, elasticSearch)) + .then(tags => resolve(tags)) + .catch(err => reject(err)) +}) + +const transformTagsStat = (redisResp) => !redisResp ? [] : Object.keys(redisResp).map(tagName => ({ + name: tagName.split(' ')[1], + type: tagName.split(' ')[0], + filesCount: parseInt(redisResp[tagName]) +})).sort((tagA, tagB) => tagB.filesCount - tagA.filesCount) + +const hasTagsInRedis = (redis) => new Promise((resolve, reject) => { + redis.existsAsync(TAGS_HASH_NAME) + .then(res => resolve(res == 1 ? true : false)) + .catch(err => reject(err)) +}) + +const getTagFilesCount = (redis, tagName, tagType) => redis.hgetAsync(TAGS_HASH_NAME, `${tagType} ${tagName}`).then(filesCount => { + return !filesCount ? 0 : parseInt(filesCount) +}) + +const setTagFilesCount = (redis, tagName, tagType, filesCount) => { + if (filesCount == 0) { + redis.hdel(TAGS_HASH_NAME, `${tagType} ${tagName}`) + return + } + + redis.hset(TAGS_HASH_NAME, `${tagType} ${tagName}`, filesCount) +} + +export const getTags = (redis, elasticSearch) => new Promise((resolve, reject) => { + hasTagsInRedis(redis) + .then(hasTags => { + if (!hasTags) { + return setTagsFromEs(redis, elasticSearch) + } + return Promise.resolve() + }) + .then(() => redis.hgetallAsync(TAGS_HASH_NAME)) + .then((redisResult) => { + resolve(transformTagsStat(redisResult)) + }) + .catch(err => reject(err)) +}) + +const setTagsFromEs = (redis, elasticSearch) => new Promise((resolve, reject) => { + EsProxy.getTagsStat(elasticSearch) + .then(tags => { + if (tags.length == 0) { + resolve() + return + } + + const tagsArray = [] + let idx = 0 + + tags.forEach(tag => { + tagsArray[idx] = `${tag.type} ${tag.name}` + idx++ + tagsArray[idx] = tag.filesCount + idx++ + }); + + redis.hmset(TAGS_HASH_NAME, tagsArray, (err, res) => { + if (err) { + reject(err) + return + } + resolve(res) + }) + }) + .catch(err => reject(err)) +}) \ No newline at end of file diff --git a/ServiceApi/src/services/CryptoService.js b/ServiceApi/src/services/CryptoService.js new file mode 100644 index 0000000..8b8415b --- /dev/null +++ b/ServiceApi/src/services/CryptoService.js @@ -0,0 +1,12 @@ +import crypto from 'crypto' +import bluebird from 'bluebird' + +const pbkdf2 = bluebird.promisify(crypto.pbkdf2); + +export const getSha256 = (data) => crypto.createHash('sha256').update(data).digest('hex') +export const getSha1 = (data) => crypto.createHash('sha1').update(data).digest('hex') + +export const getPasswordHash = (password, salt) => pbkdf2(password, salt, 8192, 512, 'sha512').then((hash) => hash.toString('hex')) + +export const generateRandom = (length = 256) => crypto.randomBytes(length).toString('hex') + diff --git a/ServiceApi/src/services/DateTimeService.js b/ServiceApi/src/services/DateTimeService.js new file mode 100644 index 0000000..e6ca1ca --- /dev/null +++ b/ServiceApi/src/services/DateTimeService.js @@ -0,0 +1,23 @@ +import moment from 'moment' +import parser from 'cron-parser' + +const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSS' + +export const getCurrentDateTime = () => moment().format(DATETIME_FORMAT) +export const getCurrentDateTimeAddDays = (days) => moment().add(days, 'days').format(DATETIME_FORMAT) +export const getCurrentDateTimeMinusMinutes = (minutes) => moment().subtract({ minutes: minutes }).format(DATETIME_FORMAT) +export const getStartOfToday = () => moment().startOf('day').format(DATETIME_FORMAT) +export const getStartOfYesterday = () => moment().subtract({ days: 1 }).startOf('day').format(DATETIME_FORMAT) +export const getStartOfThisWeek = () => moment().startOf('isoWeek').format(DATETIME_FORMAT) +export const getStartOfThisMonth = () => moment().startOf('month').format(DATETIME_FORMAT) +export const getStartOfThisYear = () => moment().startOf('year').format(DATETIME_FORMAT) +export const parseDateTime = (dateStr) => moment(dateStr, DATETIME_FORMAT, true) +export const getDateTimeDifferenceFromNowInHumanForm = (dateStr) => moment.duration(moment().diff(moment(dateStr, DATETIME_FORMAT, true))).humanize() +export const getDateTimeDifferenceFromNow = (dateStr) => moment().diff(moment(dateStr, DATETIME_FORMAT, true)) +export const isSame = (dateA, dateB) => parseDateTime(dateA).isSame(parseDateTime(dateB)) +export const getCronIntervalInMs = (cronSchedule) => { + const interval = parser.parseExpression(cronSchedule) + const nextRun = interval.next()._date + const nextNextRun = interval.next()._date + return moment(nextNextRun).diff(nextRun) +} diff --git a/ServiceApi/src/services/ErrorHandlerService.js b/ServiceApi/src/services/ErrorHandlerService.js new file mode 100644 index 0000000..c40bc17 --- /dev/null +++ b/ServiceApi/src/services/ErrorHandlerService.js @@ -0,0 +1,25 @@ +import { EsProxy, DateTimeService } from './index' +import ErrorResponse from '../utils/ErrorResponse' + +export default (esClient) => (err, req, res, next) => { + + //eslint-disable-next-line no-console + console.error(err) + + const message = (err instanceof Error) + ? `${err.message}\n ${err.stack}` + : (typeof err === 'string' || err instanceof String) ? err : JSON.stringify(err) + + EsProxy.indexLogItem(esClient, { + created_datetime: DateTimeService.getCurrentDateTime(), + source_id: 'serviceapi', + type: 'error', + message: message + }) + + if (res.headersSent) { + return next(err) + } + + res.status(500).json(new ErrorResponse(message)) +} \ No newline at end of file diff --git a/ServiceApi/src/services/EsLowLevelProxy.js b/ServiceApi/src/services/EsLowLevelProxy.js new file mode 100644 index 0000000..194709b --- /dev/null +++ b/ServiceApi/src/services/EsLowLevelProxy.js @@ -0,0 +1,63 @@ +import request from 'request' +import config from '../config' +import { createReadStream } from 'streamifier' +import combinedStream from 'combined-stream2' + +const ENC_UTF8 = 'utf-8' +const ES_FILE_INDEX_NAME = "ambar_file_data" +const ES_FILE_TYPE_NAME = "ambar_file" + +const bodyToStream = (body, contentToken, data) => { + const stringifiedBody = JSON.stringify(body) + const start = stringifiedBody.indexOf(contentToken) + + const prefix = stringifiedBody.substring(0, start - 1) + const suffix = stringifiedBody.substring(start + contentToken.length + 1) + + const contentRequestStream = combinedStream.create() + const dataStream = createReadStream(data) + + contentRequestStream.append(Buffer.from(prefix, ENC_UTF8)) + contentRequestStream.append(dataStream) + contentRequestStream.append(Buffer.from(suffix, ENC_UTF8)) + + return contentRequestStream +} + +/** + * Low level update by query implementation to bypass large JSON files problem + */ +export const updateFile = (fileId, data) => { + const contentToken = '@content' + + const body = { + doc: contentToken, + doc_as_upsert: true + } + + const bodyStream = bodyToStream(body, contentToken, data) + + return new Promise((resolve, reject) => { + bodyStream.pipe(request.post({ + url: `${config.elasticSearchUrl}/${ES_FILE_INDEX_NAME}/${ES_FILE_TYPE_NAME}/${fileId}/_update?retry_on_conflict=5&refresh=true`, + headers: { + 'Content-Type': 'application/json' + } + }, (err, resp) => { + if (err) { + reject(err) + return + } + + const response = JSON.parse(resp.body) + + if (response.result === 'updated' || response.result === 'created') { + resolve(response.result) + return + } + + reject(response) + } + )) + }) +} \ No newline at end of file diff --git a/ServiceApi/src/services/EsProxy/AmbarFileDataMapping.json b/ServiceApi/src/services/EsProxy/AmbarFileDataMapping.json new file mode 100644 index 0000000..fabfb46 --- /dev/null +++ b/ServiceApi/src/services/EsProxy/AmbarFileDataMapping.json @@ -0,0 +1,400 @@ +{ + "settings": { + "number_of_shards": 8, + "index.query.default_field": "content.text", + "index.mapper.dynamic": false, + "analysis": { + "char_filter": { + "russian_cf": { + "type": "mapping", + "mappings": [ + "ё => е", + "Ё => Е", + "Й => И", + "й => и", + ": => \\u0020" + ] + } + }, + "filter": { + "russian_stop": { + "type": "stop", + "stopwords": "_russian_" + }, + "russian_stemmer": { + "type": "stemmer", + "language": "russian" + }, + "russian_stop_alt": { + "type": "stop", + "stopwords": "а,без,более,бы,был,была,были,было,быть,в,вам,вас,весь,во,вот,все,всего,всех,вы,где,да,даже,для,до,его,ее,если,есть,еще,же,за,здесь,и,из,или,им,их,к,как,ко,когда,кто,ли,либо,мне,может,мы,на,надо,наш,не,него,нее,нет,ни,них,но,ну,о,об,однако,он,она,они,оно,от,очень,по,под,при,с,со,так,также,такой,там,те,тем,то,того,тоже,той,только,том,ты,у,уже,хотя,чего,чей,чем,что,чтобы,чье,чья,эта,эти,это,я,a,an,and,are,as,at,be,but,by,for,if,in,into,is,it,no,not,of,on,or,such,that,the,their,then,there,these,they,this,to,was,will,with" + }, + "ambar_word_delimiter": { + "type": "word_delimiter", + "generate_word_parts": true, + "generate_number_parts": true, + "catenate_words": true, + "catenate_numbers": true, + "catenate_all": true, + "split_on_case_change": true, + "split_on_numerics": true, + "preserve_original": true + }, + "english_stop": { + "type": "stop", + "stopwords": "_english_" + }, + "english_stemmer": { + "type": "stemmer", + "language": "english" + }, + "english_possessive_stemmer": { + "type": "stemmer", + "language": "possessive_english" + }, + "italian_elision": { + "type": "elision", + "articles": [ + "c", + "l", + "all", + "dall", + "dell", + "nell", + "sull", + "coll", + "pell", + "gl", + "agl", + "dagl", + "degl", + "negl", + "sugl", + "un", + "m", + "t", + "s", + "v", + "d" + ] + }, + "italian_stop": { + "type": "stop", + "stopwords": "_italian_" + }, + "italian_stemmer": { + "type": "stemmer", + "language": "light_italian" + }, + "german_stop": { + "type": "stop", + "stopwords": "_german_" + }, + "german_stemmer": { + "type": "stemmer", + "language": "light_german" + } + }, + "analyzer": { + "ambar_keyword": { + "tokenizer": "keyword", + "filter": [ + "lowercase" + ] + }, + "ambar_ru_old": { + "tokenizer": "standard", + "char_filter": [ + "russian_cf" + ], + "filter": [ + "lowercase", + "russian_stop", + "russian_stemmer", + "ambar_word_delimiter" + ] + }, + "ambar_ru": { + "tokenizer": "standard", + "char_filter": [ + "russian_cf" + ], + "filter": [ + "lowercase", + "russian_morphology", + "english_morphology", + "russian_stop_alt", + "ambar_word_delimiter" + ] + }, + "ambar_en": { + "tokenizer": "standard", + "filter": [ + "english_possessive_stemmer", + "lowercase", + "english_stop", + "english_stemmer", + "ambar_word_delimiter" + ] + }, + "ambar_it": { + "tokenizer": "standard", + "filter": [ + "italian_elision", + "lowercase", + "italian_stop", + "italian_stemmer" + ] + }, + "ambar_de": { + "tokenizer": "standard", + "filter": [ + "lowercase", + "german_stop", + "german_normalization", + "german_stemmer" + ] + }, + "ambar_cjk": { + "tokenizer": "standard", + "filter": [ + "cjk_width", + "lowercase", + "cjk_bigram", + "english_stop" + ] + }, + "ambar_pl": { + "tokenizer": "standard", + "filter": [ + "lowercase", + "polish_stem" + ] + }, + "ambar_cn": { + "tokenizer": "smartcn_tokenizer", + "filter": [ + "lowercase" + ] + } + } + } + }, + "mappings": { + "ambar_file_hidden_mark": { + "_parent": { + "type": "ambar_file" + }, + "properties": { + "id": { + "type": "keyword" + }, + "indexed_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + } + } + }, + "ambar_file_tag": { + "_parent": { + "type": "ambar_file" + }, + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "type": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "indexed_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + } + } + }, + "ambar_file": { + "_source": { + "excludes": [ + "content.text" + ] + }, + "_all": { + "enabled": false + }, + "properties": { + "sha256": { + "type": "keyword" + }, + "file_id": { + "type": "keyword" + }, + "indexed_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + }, + "content": { + "properties": { + "author": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "text": { + "type": "text", + "analyzer": "${ANALYZER}", + "term_vector": "with_positions_offsets", + "store": true + }, + "type": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "language": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "title": { + "type": "text", + "analyzer": "${ANALYZER}" + }, + "processed_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + }, + "size": { + "type": "long" + }, + "state": { + "type": "keyword" + }, + "thumb_available": { + "type": "boolean" + }, + "ocr_performed": { + "type": "boolean" + } + } + }, + "meta": { + "properties": { + "created_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + }, + "full_name": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "full_name_parts": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "id": { + "type": "keyword" + }, + "short_name": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "extension": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "extra": { + "properties": { + "type": { + "type": "keyword" + }, + "value": { + "type": "text" + } + } + }, + "source_id": { + "type": "text", + "analyzer": "ambar_keyword", + "fielddata": true, + "fields": { + "analyzed": { + "type": "text", + "analyzer": "${ANALYZER}" + } + } + }, + "updated_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/ServiceApi/src/services/EsProxy/AmbarLogMapping.json b/ServiceApi/src/services/EsProxy/AmbarLogMapping.json new file mode 100644 index 0000000..79d3fd6 --- /dev/null +++ b/ServiceApi/src/services/EsProxy/AmbarLogMapping.json @@ -0,0 +1,31 @@ +{ + "settings": { + "number_of_shards": 10 + }, + "mappings": { + "ambar_log_record": { + "properties": { + "created_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + }, + "indexed_datetime": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss.SSS" + }, + "source_id": { + "type": "keyword" + }, + "dest_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "message": { + "type": "text" + } + } + } + } +} \ No newline at end of file diff --git a/ServiceApi/src/services/EsProxy/EsProxy.js b/ServiceApi/src/services/EsProxy/EsProxy.js new file mode 100644 index 0000000..8bc2775 --- /dev/null +++ b/ServiceApi/src/services/EsProxy/EsProxy.js @@ -0,0 +1,261 @@ +import config from '../../config' +import { DateTimeService } from '../index' +import * as EsQueryBuilder from '../../utils/EsQueryBuilder' +import * as AmbarLogMapping from './AmbarLogMapping.json' +import * as AmbarFileDataMapping from './AmbarFileDataMapping.json' + +const MAPPING_ANALYZER_REGEX = /\$\{ANALYZER\}/g + +const ES_LOG_INDEX_NAME = "ambar_log_record_data" +const ES_LOG_TYPE_NAME = "ambar_log_record" +const ES_FILE_INDEX_NAME = "ambar_file_data" +const ES_FILE_TYPE_NAME = "ambar_file" +const ES_FILE_TAG_TYPE_NAME = "ambar_file_tag" + +const transformTagsStat = (esResponse) => { + const resp = [] + + esResponse.aggregations.tags.buckets.forEach(tag => { + tag.type.buckets.forEach(tagType => { + resp.push({ name: tag.key, type: tagType.key, filesCount: tagType.doc_count }) + }) + }) + + return resp +} + +const normalizeHitContentHighlights = (hit) => { + const ALLOWED_TAGS = ['br', 'em', 'em class="entity"'] + const SEPARATOR_TAG = '
' + const SPACE_CHAR = ' ' + + if (!hit.content) { + return hit + } + + if (!hit.content.highlight) { + return hit + } + + if (!hit.content.highlight.text) { + return hit + } + + hit.content.highlight.text = hit.content.highlight.text.map(hl => { + let strippedHl = hl + .replace(//gim, '>') + + ALLOWED_TAGS.forEach(tag => { + strippedHl = strippedHl + .replace(new RegExp(`(<${tag}>)`, 'gim'), `<${tag}>`) + .replace(new RegExp(`(<${tag}/>)`, 'gim'), `<${tag}/>`) + .replace(new RegExp(`(</${tag}>)`, 'gim'), ``) + }) + + strippedHl = strippedHl.replace(/(?:\r\n|\r|\n)/gi, SEPARATOR_TAG) + .replace(/((\s*)){2,}/gi, SEPARATOR_TAG) + .replace(/(( )+)/gi, SPACE_CHAR) + .replace(/(?:\t)+/gi, SPACE_CHAR) + .replace(/[\s]+/gi, SPACE_CHAR) + + return strippedHl + }) + + return hit +} + +const mergeAnalyzedFieldsHighlight = (highlight) => { + if (!highlight) { + return highlight + } + + Object.keys(highlight).filter(key => /\.analyzed$/.test(key)).forEach(key => { + const originalKey = key.replace(/\.analyzed$/, '') + if (!highlight[originalKey]) { + highlight[originalKey] = [] + } + highlight[originalKey].concat(highlight[key]) + delete highlight[key] + }) + + return highlight +} + +const transformHit = (hit) => { + const transformedHit = { + ...hit._source, + tags: [], + score: hit._score, + hidden_mark: undefined + } + + const highlight = mergeAnalyzedFieldsHighlight(hit.highlight) + + if (highlight) { + Object.keys(highlight).forEach(key => { + if (key.startsWith('meta.')) { + if (!transformedHit.meta.highlight) { + transformedHit.meta.highlight = {} + } + transformedHit.meta.highlight[key.replace('meta.', '')] = highlight[key] + } + if (key.startsWith('content.')) { + if (!transformedHit.content.highlight) { + transformedHit.content.highlight = {} + } + transformedHit.content.highlight[key.replace('content.', '')] = highlight[key] + } + }) + } + + if (hit.inner_hits && hit.inner_hits.ambar_file_tag) { + transformedHit.tags = hit.inner_hits.ambar_file_tag.hits.hits.map(hit => { + return hit.highlight ? { ...hit._source, highlight: hit.highlight } : hit._source + }) + } + + if (hit.inner_hits && hit.inner_hits.ambar_file_hidden_mark && hit.inner_hits.ambar_file_hidden_mark.hits.hits.length > 0) { + transformedHit.hidden_mark = hit.inner_hits.ambar_file_hidden_mark.hits.hits[0]._source + } + + return transformedHit +} + +export const getTagsStat = (esClient) => new Promise((resolve, reject) => + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TAG_TYPE_NAME, + body: EsQueryBuilder.getTagsStatsQuery() + }) + .then(result => { + resolve(transformTagsStat(result)) + }) + .catch(err => reject(err)) +) + +export const checkIfMetaIdExists = (esClient, metaId) => new Promise((resolve, reject) => { + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + _source: false, + body: { + query: { + term: { 'meta.id': metaId } + } + } + }) + .then(result => resolve(result.hits.total > 0 ? true : false)) + .catch(err => reject(err)) +}) + +export const getFileBySha = (esClient, sha) => new Promise((resolve, reject) => { + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: { + from: 0, + size: 1, + query: { + term: { 'sha256': sha } + } + } + }) + .then(result => resolve(result.hits.total > 0 ? normalizeHitContentHighlights(transformHit(result.hits.hits[0])) : null)) + .catch(err => reject(err)) +}) + +export const indexTag = (esClient, fileId, tag) => new Promise((resolve, reject) => { + tag.indexed_datetime = DateTimeService.getCurrentDateTime() + esClient.index({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TAG_TYPE_NAME, + parent: fileId, + refresh: true, + id: tag.id, + body: tag + }) + .then(res => resolve(res)) + .catch(err => reject(err)) +}) + +export const indexLogItem = (esClient, logItem) => { + logItem.indexed_datetime = DateTimeService.getCurrentDateTime() + esClient.index({ + index: ES_LOG_INDEX_NAME, + type: ES_LOG_TYPE_NAME, + body: logItem + }) +} + +export const createLogIndexIfNotExists = (esClient) => new Promise((resolve, reject) => { + esClient.indices.create({ + index: ES_LOG_INDEX_NAME, + body: AmbarLogMapping + }) + .then(() => resolve()) + .catch(err => { + if (err.status === 400) { + resolve() // Log index already exists + return + } + + reject(err) + }) +}) + +export const createFilesIndex = (esClient) => new Promise((resolve, reject) => { + let mappings = JSON.parse(JSON.stringify({ ...AmbarFileDataMapping }).replace(MAPPING_ANALYZER_REGEX, config.langAnalyzer)) + + esClient.indices.create({ + index: ES_FILE_INDEX_NAME, + body: mappings + }) + .then(result => resolve(result)) + .catch(err => reject(err)) +}) + +export const deleteAutoTags = (esClient, fileId) => new Promise((resolve, reject) => { + removeAutoTags(esClient, fileId) + .then(result => resolve(result)) + .catch(err => reject(err)) +}) + +const removeAutoTags = (esClient, fileId) => new Promise((resolve, reject) => { + esClient.deleteByQuery({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TAG_TYPE_NAME, + body: { + query: { + bool: { + must: [ + { + parent_id: { + type: ES_FILE_TAG_TYPE_NAME, + id: fileId + } + }, + { + bool: { + should: [ + { + term: { + type: 'auto' + } + }, + { + term: { + type: 'source' + } + } + ] + } + } + ] + } + } + } + }) + .then(res => resolve(res)) + .catch(err => reject(err)) +}) \ No newline at end of file diff --git a/ServiceApi/src/services/EsProxy/index.js b/ServiceApi/src/services/EsProxy/index.js new file mode 100644 index 0000000..2de924d --- /dev/null +++ b/ServiceApi/src/services/EsProxy/index.js @@ -0,0 +1 @@ +export * from './EsProxy' \ No newline at end of file diff --git a/ServiceApi/src/services/FileUploader.js b/ServiceApi/src/services/FileUploader.js new file mode 100644 index 0000000..77f6592 --- /dev/null +++ b/ServiceApi/src/services/FileUploader.js @@ -0,0 +1,35 @@ +import multer from 'multer' +import ErrorResponse from '../utils/ErrorResponse' + +const MAX_FILE_SIZE_MB = 512 +const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024 + +const upload = multer({ + limits: { + fileSize: MAX_FILE_SIZE_BYTES, + files: 1 + } +}) + +const uploader = (req, res, next) => upload.any()(req, res, err => { + if (err) { + switch (err.code) { + case 'LIMIT_FILE_SIZE': + res.status(400).json(new ErrorResponse(`File is too large (> ${MAX_FILE_SIZE_MB} Mb)`)) + break + default: + res.status(500).json(new ErrorResponse(err.message)) + } + } else { + const files = req.files + + if (!files || files.length === 0 || files.some(f => !f.buffer)) { + res.status(400).json(new ErrorResponse('No files are attached or some attachments are empty')) + return + } + + next() + } +}) + +export default uploader \ No newline at end of file diff --git a/ServiceApi/src/services/GridFsProxy.js b/ServiceApi/src/services/GridFsProxy.js new file mode 100644 index 0000000..ca8b4bb --- /dev/null +++ b/ServiceApi/src/services/GridFsProxy.js @@ -0,0 +1,61 @@ +import GridFs from 'gridfs-stream' +import mongo from 'mongodb' +import { createReadStream } from 'streamifier' + +const createGridFsInstance = (mongoDbInstance) => { + return GridFs(mongoDbInstance, mongo) +} + +export const uploadFile = (mongo, fileName, buffer) => new Promise((resolve, reject) => { + const gfs = createGridFsInstance(mongo) + + const writeStream = gfs.createWriteStream({ filename: fileName, mode: 'w' }) + + writeStream.on('close', (result) => resolve(result)) + writeStream.on('error', (error) => reject(error)) + + createReadStream(buffer).pipe(writeStream) +}) + +export const uploadPlainTextFile = (mongo, fileName, buffer) => new Promise((resolve, reject) => { + const gfs = createGridFsInstance(mongo) + + const writeStream = gfs.createWriteStream({ filename: fileName, mode: 'w', content_type: 'text/plain' }) + + writeStream.on('close', (result) => resolve(result)) + writeStream.on('error', (error) => reject(error)) + + createReadStream(buffer).pipe(writeStream) +}) + +export const checkIfFileExist = (mongo, fileName) => new Promise((resolve, reject) => { + const gfs = createGridFsInstance(mongo) + + gfs.exist({ filename: fileName }, (err, found) => { + if (err) { + reject(err) + return + } + + resolve(found) + }) +}) + +export const removeFile = (mongo, fileName) => new Promise((resolve, reject) => { + const gfs = createGridFsInstance(mongo) + + gfs.remove({ filename: fileName }, (err) => { + if (err) { + reject(err) + return + } + + resolve() + }); +}) + +export const downloadFile = (mongo, fileName) => { + const gfs = createGridFsInstance(mongo) + const readStream = gfs.createReadStream({ filename: fileName }) + return readStream +} \ No newline at end of file diff --git a/ServiceApi/src/services/MongoProxy.js b/ServiceApi/src/services/MongoProxy.js new file mode 100644 index 0000000..b478a99 --- /dev/null +++ b/ServiceApi/src/services/MongoProxy.js @@ -0,0 +1,100 @@ +import config from '../config' +import { CryptoService } from './index' + +const THUMBNAIL_DATA = 'thumbnail_data' +const USER_DATA = 'user_data' +const USER_ROLE_DATA = 'user_role_data' +const AUTO_TAGGING_RULE_DATA = 'auto_tagging_rule_data' + +//TAGGING RULES +export const initDefaultTaggingRules = (db) => new Promise((resolve, reject) => { + const promises = config.defaultTaggingRules.map(taggingRule => + new Promise((iResolve, iReject) => { + const ruleId = CryptoService.getSha1(`taggingRule_${taggingRule.name}`) + + db.collection(AUTO_TAGGING_RULE_DATA) + .updateOne({ id: ruleId }, { ...taggingRule, id: ruleId }, { upsert: true }, (err, result) => { + if (err) { + iReject(err) + return + } + + iResolve(result) + }) + })) + + Promise.all(promises) + .then(() => resolve()) + .catch(err => reject(err)) +}) + +export const getTaggingRules = (db) => new Promise((resolve, reject) => { + db.collection(AUTO_TAGGING_RULE_DATA) + .find() + .toArray( + (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) +////////////////////////////////////////////////////////////////////////////////////// + +// THUMBNAILS +export const createThumbnail = (db, thumbId, thumbData) => new Promise((resolve, reject) => { + db.collection(THUMBNAIL_DATA) + .updateOne({ id: thumbId }, { id: thumbId, data: thumbData }, { upsert: true }, (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) +////////////////////////////////////////////////////////////////////////////////////// + +// USERS +export const getUserByEmail = (db, email) => new Promise((resolve, reject) => { + db.collection(USER_DATA) + .findOne( + { email: email }, + (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) + +export const createUpdateUser = (db, user) => new Promise((resolve, reject) => { + db.collection(USER_DATA) + .updateOne({ email: user.email }, user, { upsert: true }, (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) +////////////////////////////////////////////////////////////////////////////////////// + +/// ROLES +export const createUpdateUserRole = (db, role) => new Promise((resolve, reject) => { + db.collection(USER_ROLE_DATA) + .updateOne({ name: role.name }, role, { upsert: true }, (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) + diff --git a/ServiceApi/src/services/QueueProxy.js b/ServiceApi/src/services/QueueProxy.js new file mode 100644 index 0000000..6e293bb --- /dev/null +++ b/ServiceApi/src/services/QueueProxy.js @@ -0,0 +1,80 @@ +import amqp from 'amqplib' +import config from '../config' + +export const AMBAR_PIPELINE_QUEUE = "AMBAR_PIPELINE_QUEUE" +export const AMBAR_PIPELINE_QUEUE_MAX_PRIORITY = 2 +export const AMBAR_PIPELINE_EXCHANGE = "AMBAR_PIPELINE_EXCHANGE" +export const AMBAR_PIPELINE_WAITING_QUEUE = "AMBAR_PIPELINE_WAITING_QUEUE" +export const AMBAR_PIPELINE_WAITING_EXCHANGE = "AMBAR_PIPELINE_WAITING_EXCHANGE" + +export const AMBAR_PIPELINE_WAITING_QUEUE_TTL = 60 * 60 * 1000 + +export const AMBAR_CRAWLER_QUEUE = "AMBAR_CRAWLER_QUEUE" +export const AMBAR_CRAWLER_EXCHANGE = "AMBAR_CRAWLER_EXCHANGE" + +export const AMBAR_CRAWLER_MESSAGE_DEFAULT_TTL = 10 * 1000 + +const getPipelineMessagePriority = (storage, fileName) => new Promise((resolve) => { + const regex = /(\.jp[e]*g$)|(\.png$)|(\.bmp$)|(\.tif[f]*$)|(\.pdf$)/i + const priority = regex.test(fileName) ? 1 : 2 + resolve(priority) +}) + +export const enqueuePipelineMessage = (storage, message) => new Promise((resolve, reject) => { + const fileName = message.meta.short_name + + storage.rabbit.createConfirmChannel() + .then(channel => { + return getPipelineMessagePriority(storage, fileName) + .then(priority => { + channel.publish(AMBAR_PIPELINE_EXCHANGE, '', Buffer.from(JSON.stringify(message)), { priority: priority }) + return channel.waitForConfirms() + .then(() => channel.close()) + }) + }) + .then(() => resolve()) + .catch(err => reject(err)) +}) + +export const enqueueCrawlerMessage = (storage, message, ttl = AMBAR_CRAWLER_MESSAGE_DEFAULT_TTL) => new Promise((resolve, reject) => { + storage.rabbit.createConfirmChannel() + .then(channel => { + channel.publish(AMBAR_CRAWLER_EXCHANGE, '', Buffer.from(JSON.stringify(message)), { expiration: ttl }) + return channel.waitForConfirms() + .then(() => channel.close()) + }) + .then(() => resolve()) + .catch(err => reject(err)) +}) + +export const initRabbit = new Promise((resolve, reject) => { + amqp.connect(`${config.rabbitHost}?heartbeat=60`) + .then((conn) => { + conn.on('error', (err) => { + //eslint-disable-next-line no-console + console.error('Rabbit error!') + throw err + }) + + return conn.createChannel() + .then((channel) => channel.assertExchange(AMBAR_PIPELINE_EXCHANGE, 'fanout', { durable: false }) + .then(() => channel.assertExchange(AMBAR_PIPELINE_WAITING_EXCHANGE, + 'fanout', { durable: false })) + .then(() => channel.assertQueue(AMBAR_PIPELINE_QUEUE, + { durable: false, arguments: { 'x-dead-letter-exchange': AMBAR_PIPELINE_WAITING_EXCHANGE, 'x-max-priority': AMBAR_PIPELINE_QUEUE_MAX_PRIORITY } })) + .then(() => channel.assertQueue(AMBAR_PIPELINE_WAITING_QUEUE, + { durable: false, arguments: { 'x-dead-letter-exchange': AMBAR_PIPELINE_EXCHANGE, 'x-message-ttl': AMBAR_PIPELINE_WAITING_QUEUE_TTL } })) + .then(() => channel.bindQueue(AMBAR_PIPELINE_QUEUE, + AMBAR_PIPELINE_EXCHANGE)) + .then(() => channel.bindQueue(AMBAR_PIPELINE_WAITING_QUEUE, + AMBAR_PIPELINE_WAITING_EXCHANGE)) + .then(() => channel.assertExchange(AMBAR_CRAWLER_EXCHANGE, 'fanout', { durable: false })) + .then(() => channel.assertQueue(AMBAR_CRAWLER_QUEUE, { durable: false })) + .then(() => channel.bindQueue(AMBAR_CRAWLER_QUEUE, + AMBAR_CRAWLER_EXCHANGE)) + .then(() => channel.close()) + ) + .then(() => resolve(conn)) + }) + .catch(err => reject(err)) +}) diff --git a/ServiceApi/src/services/StorageService.js b/ServiceApi/src/services/StorageService.js new file mode 100644 index 0000000..1005901 --- /dev/null +++ b/ServiceApi/src/services/StorageService.js @@ -0,0 +1,78 @@ +import { MongoClient } from 'mongodb' +import elasticsearch from 'elasticsearch' +import redis from 'redis' +import bluebird from 'bluebird' +import { MongoProxy, EsProxy, QueueProxy, DateTimeService } from './index' +import config from '../config' + +const generateDefaultUser = () => new Promise((resolve) => { + resolve({ + name: config.defaultAccountName, + email: config.defaultAccountEmail, + lang_analyzer: config.langAnalyzer, + role: config.defaultAccountRole, + password_hash: null, + password_salt: null, + state: 'active', + set_password_key: null, + set_password_key_expiration: null, + created: DateTimeService.getCurrentDateTime() + }) +}) + +const generateDefaultUserRole = () => ({ + name: 'admin', + acc_type: 'allow_all', + acc_rules: [] +}) + +const initDefaultUserAndRole = (storage) => new Promise((resolve, reject) => { + MongoProxy.getUserByEmail(storage.mongoDb, config.defaultAccountEmail) + .then((user) => { + if (user) { + resolve() + return + } + + return generateDefaultUser() + .then((generatedUser) => MongoProxy.createUpdateUser(storage.mongoDb, generatedUser)) + .then(() => MongoProxy.createUpdateUserRole(storage.mongoDb, generateDefaultUserRole())) + .then(() => EsProxy.createFilesIndex(storage.elasticSearch)) + .then(() => resolve()) + }) + .catch((err) => { reject(err) }) +}) + +export const initializeStorage = () => new Promise((resolve, reject) => { + const esClient = new elasticsearch.Client({ + host: config.elasticSearchUrl + }) + + bluebird.promisifyAll(redis.RedisClient.prototype) + bluebird.promisifyAll(redis.Multi.prototype) + + const redisClient = redis.createClient({ host: config.redisHost, port: config.redisPort }) + + const mongoPromise = new Promise((resolve, reject) => { + MongoClient.connect(config.mongoDbUrl, (err, db) => { + if (err) { + //eslint-disable-next-line no-console + console.error(err) + reject(err) + } + resolve(db) + }) + }) + + Promise.all([mongoPromise, QueueProxy.initRabbit, EsProxy.createLogIndexIfNotExists(esClient)]) + .then(([mongoConnection, rabbitConnection]) => ({ + elasticSearch: esClient, + mongoDb: mongoConnection, + redis: redisClient, + rabbit: rabbitConnection + })) + .then(storage => initDefaultUserAndRole(storage) + .then(() => resolve(storage)) + ) + .catch(err => reject(err)) +}) diff --git a/ServiceApi/src/services/index.js b/ServiceApi/src/services/index.js new file mode 100644 index 0000000..91addc1 --- /dev/null +++ b/ServiceApi/src/services/index.js @@ -0,0 +1,25 @@ +import * as CryptoService from './CryptoService' +import * as EsLowLevelProxy from './EsLowLevelProxy' +import * as EsProxy from './EsProxy/' +import * as MongoProxy from './MongoProxy' +import FileUploader from './FileUploader' +import * as DateTimeService from './DateTimeService' +import * as GridFsProxy from './GridFsProxy' +import * as CacheProxy from './CacheProxy' +import ErrorHandlerService from './ErrorHandlerService' +import * as QueueProxy from './QueueProxy' +import * as StorageService from './StorageService' + +export { + CryptoService, + EsLowLevelProxy, + EsProxy, + MongoProxy, + FileUploader, + DateTimeService, + GridFsProxy, + CacheProxy, + ErrorHandlerService, + QueueProxy, + StorageService +} \ No newline at end of file diff --git a/ServiceApi/src/utils/ErrorResponse.js b/ServiceApi/src/utils/ErrorResponse.js new file mode 100644 index 0000000..f6f2197 --- /dev/null +++ b/ServiceApi/src/utils/ErrorResponse.js @@ -0,0 +1,7 @@ +class ErrorResponse { + constructor(errorMessage) { + this.message = errorMessage.toString() + } +} + +export default ErrorResponse \ No newline at end of file diff --git a/ServiceApi/src/utils/EsQueryBuilder.js b/ServiceApi/src/utils/EsQueryBuilder.js new file mode 100644 index 0000000..49ff39f --- /dev/null +++ b/ServiceApi/src/utils/EsQueryBuilder.js @@ -0,0 +1,20 @@ +const MAX_TAGS_TO_RETRIEVE = 100 + +/////////////////////////////////////// Index Name ///////////////////////////////////////////////////////// +const ES_FILE_INDEX_NAME = "ambar_file_data" + +export const AMBAR_FILE_INDEX_PREFIX = `${ES_FILE_INDEX_NAME}_` + +/////////////////////////////////////// Tags queries /////////////////////////////////////////////////////// + +export const getTagsStatsQuery = () => ( + { + from: 0, + size: 0, + aggs: { + tags: { + terms: { field: 'name', size: MAX_TAGS_TO_RETRIEVE }, + aggs: { type: { terms: { field: 'type' } } } + } + } + }) diff --git a/ServiceApi/src/utils/MetaBuilder.js b/ServiceApi/src/utils/MetaBuilder.js new file mode 100644 index 0000000..c6612f3 --- /dev/null +++ b/ServiceApi/src/utils/MetaBuilder.js @@ -0,0 +1,63 @@ +import { CryptoService, DateTimeService } from '../services' + +const FILE_EXTENSION_REGEX = /(?:\.([^.]+))?$/ + +const generateMetaId = (source_id, full_name, created_datetime, updated_datetime) => { + return CryptoService.getSha256(`${source_id}${full_name}${created_datetime}${updated_datetime}`) +} + +export const buildMeta = (data) => { + const { short_name, full_name, extension, extra, created_datetime, updated_datetime, source_id } = data + + if (!short_name + || !full_name + || !source_id + || !extension + || !created_datetime + || !updated_datetime) { + return null + } + + const meta = { + id: generateMetaId(source_id, full_name, created_datetime, updated_datetime), + short_name: short_name.toLowerCase(), + full_name: full_name.toLowerCase(), + source_id: source_id, + extension: extension, + created_datetime: created_datetime, + updated_datetime: updated_datetime, + extra: extra, + indexed_datetime: DateTimeService.getCurrentDateTime() + } + + return meta +} + +export const buildShortMeta = (shortName, sourceId) => { + + const short_name = shortName.toLowerCase() + const full_name = `//${sourceId.toLowerCase()}/${shortName.toLowerCase()}` + const source_id = sourceId + let extension = '' + let calculatedExtension = FILE_EXTENSION_REGEX.exec(short_name) + if ((calculatedExtension) && (calculatedExtension.length > 0)) { + extension = calculatedExtension[0] + } + const created_datetime = DateTimeService.getCurrentDateTime() + const updated_datetime = DateTimeService.getCurrentDateTime() + const extra = [] + + const meta = { + id: generateMetaId(source_id, full_name, created_datetime, updated_datetime), + short_name: short_name, + full_name: full_name, + source_id: source_id, + extension: extension, + created_datetime: created_datetime, + updated_datetime: updated_datetime, + extra: extra, + indexed_datetime: DateTimeService.getCurrentDateTime() + } + + return meta +} \ No newline at end of file diff --git a/ServiceApi/yarn.lock b/ServiceApi/yarn.lock new file mode 100644 index 0000000..b1278b3 --- /dev/null +++ b/ServiceApi/yarn.lock @@ -0,0 +1,3295 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +JSONStream@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.2.1.tgz#32aa5790e799481083b49b4b7fa94e23bae69bf9" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^5.5.0: + version "5.5.3" + resolved "http://192.168.1.113:4873/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" + +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "http://192.168.1.113:4873/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + +ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "http://192.168.1.113:4873/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +amqplib@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.5.1.tgz#7cccfebabe56c2e984ea7a2243f7cefe6fbfc6cf" + dependencies: + bitsyntax "~0.0.4" + bluebird "^3.4.6" + buffer-more-ints "0.0.2" + readable-stream "1.x >=1.1.9" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + +ansi-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "http://192.168.1.113:4873/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "http://192.168.1.113:4873/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +append-field@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/append-field/-/append-field-0.1.0.tgz#6ddc58fa083c7bc545d3c5995b2830cc2366d44a" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@~2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-cli@^6.9.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.18.0.tgz#92117f341add9dead90f6fa7d0a97c0cc08ec186" + dependencies: + babel-core "^6.18.0" + babel-polyfill "^6.16.0" + babel-register "^6.18.0" + babel-runtime "^6.9.0" + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.0.0" + glob "^5.0.5" + lodash "^4.2.0" + output-file-sync "^1.1.0" + path-is-absolute "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + v8flags "^2.0.10" + optionalDependencies: + chokidar "^1.0.0" + +babel-code-frame@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^2.0.0" + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "http://192.168.1.113:4873/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.18.0, babel-core@^6.9.0: + version "6.18.2" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.18.2.tgz#d8bb14dd6986fa4f3566a26ceda3964fa0e04e5b" + dependencies: + babel-code-frame "^6.16.0" + babel-generator "^6.18.0" + babel-helpers "^6.16.0" + babel-messages "^6.8.0" + babel-register "^6.18.0" + babel-runtime "^6.9.1" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-eslint@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.1.tgz#8a6a884f085aa7060af69cfc77341c2f99370fb2" + dependencies: + babel-code-frame "^6.16.0" + babel-traverse "^6.15.0" + babel-types "^6.15.0" + babylon "^6.13.0" + lodash.pickby "^4.6.0" + +babel-generator@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.19.0.tgz#9b2f244204777a3d6810ec127c673c87b349fac5" + dependencies: + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-bindify-decorators@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.18.0.tgz#fc00c573676a6e702fffa00019580892ec8780a5" + dependencies: + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-builder-binary-assignment-operator-visitor@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.18.0.tgz#8ae814989f7a53682152e3401a04fabd0bb333a6" + dependencies: + babel-helper-explode-assignable-expression "^6.18.0" + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-call-delegate@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.18.0.tgz#05b14aafa430884b034097ef29e9f067ea4133bd" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-define-map@^6.18.0, babel-helper-define-map@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.18.0.tgz#8d6c85dc7fbb4c19be3de40474d18e97c3676ec2" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.18.0.tgz#14b8e8c2d03ad735d4b20f1840b24cd1f65239fe" + dependencies: + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-explode-class@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.18.0.tgz#c44f76f4fa23b9c5d607cbac5d4115e7a76f62cb" + dependencies: + babel-helper-bindify-decorators "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6" + dependencies: + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-get-function-arity@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-hoist-variables@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.18.0.tgz#a835b5ab8b46d6de9babefae4d98ea41e866b82a" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-optimise-call-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.18.0.tgz#9261d0299ee1a4f08a6dd28b7b7c777348fd8f0f" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-regex@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.18.0.tgz#ae0ebfd77de86cb2f1af258e2cc20b5fe893ecc6" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.16.0, babel-helper-remap-async-to-generator@^6.16.2: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.18.0.tgz#336cdf3cab650bb191b02fc16a3708e7be7f9ce5" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.18.0.tgz#28ec69877be4144dbd64f4cc3a337e89f29a924e" + dependencies: + babel-helper-optimise-call-expression "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helpers@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3" + dependencies: + babel-runtime "^6.0.0" + babel-template "^6.16.0" + +babel-messages@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-check-es2015-constants@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz#dbf024c32ed37bfda8dee1e76da02386a8d26fe7" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-remove-code@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-code/-/babel-plugin-remove-code-0.0.6.tgz#742b6e8e6429133ead20abc3511dd4a2eebe5085" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-do-expressions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-function-bind@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.3.13: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.13.0.tgz#2b84b7d53dd744f94ff1fad7669406274b23f541" + +babel-plugin-transform-async-generator-functions@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.17.0.tgz#d0b5a2b2f0940f2b245fa20a00519ed7bc6cae54" + dependencies: + babel-helper-remap-async-to-generator "^6.16.2" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-async-to-generator@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz#19ec36cb1486b59f9f468adfa42ce13908ca2999" + dependencies: + babel-helper-remap-async-to-generator "^6.16.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-class-constructor-call@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.18.0.tgz#80855e38a1ab47b8c6c647f8ea1bcd2c00ca3aae" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-class-properties@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.19.0.tgz#1274b349abaadc835164e2004f4a2444a2788d5f" + dependencies: + babel-helper-function-name "^6.18.0" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.9.1" + babel-template "^6.15.0" + +babel-plugin-transform-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.13.0.tgz#82d65c1470ae83e2d13eebecb0a1c2476d62da9d" + dependencies: + babel-helper-define-map "^6.8.0" + babel-helper-explode-class "^6.8.0" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-types "^6.13.0" + +babel-plugin-transform-do-expressions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.8.0.tgz#fda692af339835cc255bb7544efb8f7c1306c273" + dependencies: + babel-plugin-syntax-do-expressions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-arrow-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz#ed95d629c4b5a71ae29682b998f70d9833eb366d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoping@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.18.0.tgz#3bfdcfec318d46df22525cdea88f1978813653af" + dependencies: + babel-runtime "^6.9.0" + babel-template "^6.15.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.18.0.tgz#ffe7a17321bf83e494dcda0ae3fc72df48ffd1d9" + dependencies: + babel-helper-define-map "^6.18.0" + babel-helper-function-name "^6.18.0" + babel-helper-optimise-call-expression "^6.18.0" + babel-helper-replace-supers "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-template "^6.14.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-computed-properties@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz#f51010fd61b3bd7b6b60a5fdfd307bb7a5279870" + dependencies: + babel-helper-define-map "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-destructuring@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533" + dependencies: + babel-runtime "^6.9.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz#fd8f7f7171fc108cc1c70c3164b9f15a81c25f7d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-for-of@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.18.0.tgz#4c517504db64bf8cfc119a6b8f177211f2028a70" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-function-name@^6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz#8c135b17dbd064e5bba56ec511baaee2fca82719" + dependencies: + babel-helper-function-name "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.9.0" + +babel-plugin-transform-es2015-literals@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz#50aa2e5c7958fc2ab25d74ec117e0cc98f046468" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-modules-amd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.18.0.tgz#49a054cbb762bdf9ae2d8a807076cfade6141e40" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.18.0.tgz#c15ae5bb11b32a0abdcc98a5837baa4ee8d67bcc" + dependencies: + babel-plugin-transform-strict-mode "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.19.0.tgz#50438136eba74527efa00a5b0fefaf1dc4071da6" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.11.6" + babel-template "^6.14.0" + +babel-plugin-transform-es2015-modules-umd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.18.0.tgz#23351770ece5c1f8e83ed67cb1d7992884491e50" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-object-super@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz#1b858740a5a4400887c23dcff6f4d56eea4a24c5" + dependencies: + babel-helper-replace-supers "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-parameters@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.18.0.tgz#9b2cfe238c549f1635ba27fc1daa858be70608b1" + dependencies: + babel-helper-call-delegate "^6.18.0" + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.9.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.18.0.tgz#e2ede3b7df47bf980151926534d1dd0cbea58f43" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-spread@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz#0217f737e3b821fa5a669f187c6ed59205f05e9c" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-sticky-regex@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz#e73d300a440a35d5c64f5c2a344dc236e3df47be" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-template-literals@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz#86eb876d0a2c635da4ec048b4f7de9dfc897e66b" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.18.0.tgz#0b14c48629c90ff47a0650077f6aa699bee35798" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-unicode-regex@^6.3.13: + version "6.11.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz#6298ceabaad88d50a3f4f392d8de997260f6ef2c" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.8.0.tgz#db25742e9339eade676ca9acec46f955599a68a4" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.8.0" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-export-extensions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.8.0.tgz#fa80ff655b636549431bfd38f6b817bd82e47f5b" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-function-bind@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.8.0.tgz#e7f334ce69f50d28fe850a822eaaab9fa4f4d821" + dependencies: + babel-plugin-syntax-function-bind "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-object-rest-spread@^6.16.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.19.0.tgz#f6ac428ee3cb4c6aa00943ed1422ce813603b34c" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-regenerator@^6.16.0: + version "6.16.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.16.1.tgz#a75de6b048a14154aae14b0122756c5bed392f59" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.16.0" + private "~0.1.5" + +babel-plugin-transform-strict-mode@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.18.0.tgz#df7cf2991fe046f44163dcd110d5ca43bc652b9d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-polyfill@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422" + dependencies: + babel-runtime "^6.9.1" + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-preset-es2015@^6.9.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.18.0.tgz#b8c70df84ec948c43dcf2bf770e988eb7da88312" + dependencies: + babel-plugin-check-es2015-constants "^6.3.13" + babel-plugin-transform-es2015-arrow-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoped-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoping "^6.18.0" + babel-plugin-transform-es2015-classes "^6.18.0" + babel-plugin-transform-es2015-computed-properties "^6.3.13" + babel-plugin-transform-es2015-destructuring "^6.18.0" + babel-plugin-transform-es2015-duplicate-keys "^6.6.0" + babel-plugin-transform-es2015-for-of "^6.18.0" + babel-plugin-transform-es2015-function-name "^6.9.0" + babel-plugin-transform-es2015-literals "^6.3.13" + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-plugin-transform-es2015-modules-systemjs "^6.18.0" + babel-plugin-transform-es2015-modules-umd "^6.18.0" + babel-plugin-transform-es2015-object-super "^6.3.13" + babel-plugin-transform-es2015-parameters "^6.18.0" + babel-plugin-transform-es2015-shorthand-properties "^6.18.0" + babel-plugin-transform-es2015-spread "^6.3.13" + babel-plugin-transform-es2015-sticky-regex "^6.3.13" + babel-plugin-transform-es2015-template-literals "^6.6.0" + babel-plugin-transform-es2015-typeof-symbol "^6.18.0" + babel-plugin-transform-es2015-unicode-regex "^6.3.13" + babel-plugin-transform-regenerator "^6.16.0" + +babel-preset-stage-0@^6.5.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.16.0.tgz#f5a263c420532fd57491f1a7315b3036e428f823" + dependencies: + babel-plugin-transform-do-expressions "^6.3.13" + babel-plugin-transform-function-bind "^6.3.13" + babel-preset-stage-1 "^6.16.0" + +babel-preset-stage-1@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.16.0.tgz#9d31fbbdae7b17c549fd3ac93e3cf6902695e479" + dependencies: + babel-plugin-transform-class-constructor-call "^6.3.13" + babel-plugin-transform-export-extensions "^6.3.13" + babel-preset-stage-2 "^6.16.0" + +babel-preset-stage-2@^6.16.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.18.0.tgz#9eb7bf9a8e91c68260d5ba7500493caaada4b5b5" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.18.0" + babel-plugin-transform-decorators "^6.13.0" + babel-preset-stage-3 "^6.17.0" + +babel-preset-stage-3@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.17.0.tgz#b6638e46db6e91e3f889013d8ce143917c685e39" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.3.13" + babel-plugin-transform-async-generator-functions "^6.17.0" + babel-plugin-transform-async-to-generator "^6.16.0" + babel-plugin-transform-exponentiation-operator "^6.3.13" + babel-plugin-transform-object-rest-spread "^6.16.0" + +babel-register@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68" + dependencies: + babel-core "^6.18.0" + babel-runtime "^6.11.6" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.9.0, babel-runtime@^6.9.1: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" + dependencies: + babel-runtime "^6.9.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.19.0.tgz#68363fb821e26247d52a519a84b2ceab8df4f55a" + dependencies: + babel-code-frame "^6.16.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.13.0, babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.8.0, babel-types@^6.9.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.19.0.tgz#8db2972dbed01f1192a8b602ba1e1e4c516240b9" + dependencies: + babel-runtime "^6.9.1" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.13.0: + version "6.14.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815" + +balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +bitsyntax@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.0.4.tgz#eb10cc6f82b8c490e3e85698f07e83d46e0cba82" + dependencies: + buffer-more-ints "0.0.2" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^2.6.2, bluebird@^2.8.1: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + +bluebird@^3.4.6, bluebird@^3.4.7: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + +body-parser@^1.13.3: + version "1.15.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67" + dependencies: + bytes "2.4.0" + content-type "~1.0.2" + debug "~2.2.0" + depd "~1.1.0" + http-errors "~1.5.0" + iconv-lite "0.4.13" + on-finished "~2.3.0" + qs "6.2.0" + raw-body "~2.1.7" + type-is "~1.6.13" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "http://192.168.1.113:4873/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +bson@~0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/bson/-/bson-0.5.7.tgz#0d11fe0936c1fee029e11f7063f5d0ab2422ea3e" + +buffer-from@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + +buffer-more-ints@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +busboy@^0.2.11: + version "0.2.13" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.13.tgz#90fc4f6a3967d815616fc976bfa8e56aed0c58b6" + dependencies: + dicer "0.2.5" + readable-stream "1.1.x" + +bytes@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.1.0: + version "2.3.2" + resolved "http://192.168.1.113:4873/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "http://192.168.1.113:4873/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + +chokidar@^1.0.0, chokidar@^1.4.3: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +circular-json@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "http://192.168.1.113:4873/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.9.0: + version "1.9.1" + resolved "http://192.168.1.113:4873/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "http://192.168.1.113:4873/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +combined-stream2@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/combined-stream2/-/combined-stream2-1.1.2.tgz#f6e14b7a015666f8c7b0a1fac506240164ac3570" + dependencies: + bluebird "^2.8.1" + debug "^2.1.1" + stream-length "^1.0.1" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.8.1, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +compressible@~2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + dependencies: + mime-db ">= 1.24.0 < 2" + +compression@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + dependencies: + accepts "~1.3.3" + bytes "2.3.0" + compressible "~2.0.8" + debug "~2.2.0" + on-headers "~1.0.1" + vary "~1.1.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +concat-stream@^1.6.0: + version "1.6.2" + resolved "http://192.168.1.113:4873/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" + dependencies: + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + object-assign "^4.0.1" + os-tmpdir "^1.0.0" + osenv "^0.1.0" + uuid "^2.0.1" + write-file-atomic "^1.1.2" + xdg-basedir "^2.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +content-disposition@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@^2.7.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.1.tgz#6181aa56abb45a2825be3304703747ae4e9d2383" + dependencies: + vary "^1" + +cron-parser@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.3.1.tgz#2c01573ac1cbaf938136b727b640de61a29b5117" + dependencies: + is-nan "^1.2.1" + moment-timezone "^0.5.0" + +cron@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cron/-/cron-1.1.1.tgz#02719d4ef480dfc8ee24d81a3603460ba39013ce" + dependencies: + moment-timezone "~0.5.5" + +cross-spawn@^5.1.0: + version "5.1.0" + resolved "http://192.168.1.113:4873/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@^2.1.1, debug@^2.2.0, debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@^3.1.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +define-properties@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +dicer@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" + dependencies: + readable-stream "1.1.x" + streamsearch "0.1.2" + +doctrine@^2.1.0: + version "2.1.0" + resolved "http://192.168.1.113:4873/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + dependencies: + esutils "^2.0.2" + +double-ended-queue@^2.1.0-0: + version "2.1.0-0" + resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +duplexify@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604" + dependencies: + end-of-stream "1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +elasticsearch@^12.1.3: + version "12.1.3" + resolved "https://registry.yarnpkg.com/elasticsearch/-/elasticsearch-12.1.3.tgz#5108e67ae5d83e5e7f30d3d294fd7017df0e3771" + dependencies: + chalk "^1.0.0" + forever-agent "^0.6.0" + lodash "^4.12.0" + promise "^7.1.1" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +end-of-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e" + dependencies: + once "~1.3.0" + +es6-promise@3.2.1, es6-promise@^3.0.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.2.1.tgz#ec56233868032909207170c39448e24449dd1fc4" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +eslint-plugin-babel@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-3.3.0.tgz#2f494aedcf6f4aa4e75b9155980837bc1fbde193" + +eslint-plugin-promise@^3.3.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.4.0.tgz#6ba9048c2df57be77d036e0c68918bc9b4fc4195" + +eslint-scope@^3.7.1: + version "3.7.1" + resolved "http://192.168.1.113:4873/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.19.1: + version "4.19.1" + resolved "http://192.168.1.113:4873/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +espree@^3.5.4: + version "3.5.4" + resolved "http://192.168.1.113:4873/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + dependencies: + acorn "^5.5.0" + acorn-jsx "^3.0.0" + +esprima@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esquery@^1.0.0: + version "1.0.1" + resolved "http://192.168.1.113:4873/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.0.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-stream@~3.3.0: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express@^4.13.3: + version "4.14.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.1" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "~2.2.0" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + finalhandler "0.5.0" + fresh "0.3.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.2" + qs "6.2.0" + range-parser "~1.2.0" + send "0.14.1" + serve-static "~1.11.1" + type-is "~1.6.13" + utils-merge "1.0.0" + vary "~1.1.0" + +extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +external-editor@^2.0.4: + version "2.2.0" + resolved "http://192.168.1.113:4873/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "http://192.168.1.113:4873/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" + +figures@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + statuses "~1.3.0" + unpipe "~1.0.0" + +flat-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" + dependencies: + circular-json "^0.3.0" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flushwritable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/flushwritable/-/flushwritable-1.0.0.tgz#3e328d8fde412ad47e738e3be750b4d290043498" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@^0.6.0, forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fresh@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +from@~0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc" + +fs-readdir-recursive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.15" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.15.tgz#fa63f590f3c2ad91275e4972a6cea545fb0aae44" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "http://192.168.1.113:4873/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^5.0.5: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.3, glob@^7.0.5: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2: + version "7.1.2" + resolved "http://192.168.1.113:4873/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.0.1: + version "11.4.0" + resolved "http://192.168.1.113:4873/globals/-/globals-11.4.0.tgz#b85c793349561c16076a3c13549238a27945f1bc" + +globals@^9.0.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" + dependencies: + duplexify "^3.2.0" + infinity-agent "^2.0.0" + is-redirect "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + nested-error-stacks "^1.0.0" + object-assign "^3.0.0" + prepend-http "^1.0.0" + read-all-stream "^3.0.0" + timed-out "^2.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.4: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +gridfs-stream@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/gridfs-stream/-/gridfs-stream-1.1.1.tgz#3dd3a100ec2021a181282f6eb46709636074df89" + dependencies: + flushwritable "^1.0.0" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "http://192.168.1.113:4873/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +iconv-lite@^0.4.17: + version "0.4.21" + resolved "http://192.168.1.113:4873/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" + dependencies: + safer-buffer "^2.1.0" + +ignore-by-default@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +ignore@^3.3.3: + version "3.3.7" + resolved "http://192.168.1.113:4873/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +infinity-agent@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inquirer@^3.0.6: + version "3.3.0" + resolved "http://192.168.1.113:4873/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +invariant@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +ipaddr.js@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-nan@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.2.1.tgz#9faf65b6fb6db24b7f5c0628475ea71f988401e2" + dependencies: + define-properties "^1.1.1" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-promise@^2.1.0: + version "2.1.0" + resolved "http://192.168.1.113:4873/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-tokens@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "http://192.168.1.113:4873/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.9.1: + version "3.11.0" + resolved "http://192.168.1.113:4873/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "http://192.168.1.113:4873/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "http://192.168.1.113:4873/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonparse@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.2.0.tgz#5c0c5685107160e72fe7489bddea0b44c2bc67bd" + +jsonpointer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +kind-of@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" + dependencies: + is-buffer "^1.0.2" + +latest-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" + dependencies: + package-json "^1.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.assign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.defaults@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" + dependencies: + lodash.assign "^3.0.0" + lodash.restparam "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.pickby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash@^4.12.0, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" + +lodash@^4.17.4: + version "4.17.5" + resolved "http://192.168.1.113:4873/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + +loose-envify@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8" + dependencies: + js-tokens "^2.0.0" + +lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lru-cache@^4.0.1: + version "4.1.2" + resolved "http://192.168.1.113:4873/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +"mime-db@>= 1.24.0 < 2", mime-db@~1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" + +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" + dependencies: + mime-db "~1.25.0" + +mime@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "http://192.168.1.113:4873/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimatch@^3.0.4: + version "3.0.4" + resolved "http://192.168.1.113:4873/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment-timezone@^0.5.0, moment-timezone@~0.5.5: + version "0.5.10" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.10.tgz#3766249c2d317d08f07d896d3033c26f87c4ae2b" + dependencies: + moment ">= 2.6.0" + +"moment@>= 2.6.0", moment@^2.15.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +mongodb-core@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.0.14.tgz#4e8743b87343d169a7622535edbd47dcacd790be" + dependencies: + bson "~0.5.7" + require_optional "~1.0.0" + +mongodb@^2.2.10: + version "2.2.12" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.12.tgz#2a86f10228f911e9d6fefdbd7d922188d7b730f9" + dependencies: + es6-promise "3.2.1" + mongodb-core "2.0.14" + readable-stream "2.1.5" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +multer@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.2.0.tgz#5be1a45259fb04d2753d33c7c2a1caf5224705a2" + dependencies: + append-field "^0.1.0" + busboy "^0.2.11" + concat-stream "^1.5.0" + mkdirp "^0.5.1" + object-assign "^3.0.0" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + +mute-stream@0.0.7: + version "0.0.7" + resolved "http://192.168.1.113:4873/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +nested-error-stacks@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf" + dependencies: + inherits "~2.0.1" + +node-pre-gyp@^0.6.29: + version "0.6.32" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +nodemon@^1.9.2: + version "1.11.0" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c" + dependencies: + chokidar "^1.4.3" + debug "^2.2.0" + es6-promise "^3.0.2" + ignore-by-default "^1.0.0" + lodash.defaults "^3.1.2" + minimatch "^3.0.0" + ps-tree "^1.0.1" + touch "1.0.0" + undefsafe "0.0.3" + update-notifier "0.5.0" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +npmlog@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.1.tgz#d14f503b4cd79710375553004ba96e6662fbc0b8" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-finished@^2.3.0, on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "http://192.168.1.113:4873/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.3.tgz#83cf05c6d6458fc4d5ac6362ea325d92f2754217" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +package-json@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0" + dependencies: + got "^3.2.0" + registry-url "^3.0.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pluralize@^7.0.0: + version "7.0.0" + resolved "http://192.168.1.113:4873/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6, private@~0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +progress@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + +promise@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" + dependencies: + asap "~2.0.3" + +proxy-addr@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.1.1" + +ps-tree@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + dependencies: + event-stream "~3.3.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "http://192.168.1.113:4873/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@~2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" + +rc@^1.0.1, rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +read-all-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" + dependencies: + pinkie-promise "^2.0.0" + readable-stream "^2.0.0" + +readable-stream@1.1.x, "readable-stream@1.x >=1.1.9": + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@2.1.5, readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@^2.2.2: + version "2.3.6" + resolved "http://192.168.1.113:4873/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +redis-commands@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.0.tgz#4307d8094aee1315829ab6729b37b99f62365d63" + +redis-parser@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.3.0.tgz#313a47965e49ee35ab3a86c93388b403d76237f6" + +redis@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/redis/-/redis-2.6.3.tgz#84305b92553c6a1f09c7c47c30b11ace7dbb7ad4" + dependencies: + double-ended-queue "^2.1.0-0" + redis-commands "^1.2.0" + redis-parser "^2.0.0" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.9.5: + version "0.9.6" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpp@^1.0.1: + version "1.1.0" + resolved "http://192.168.1.113:4873/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +registry-url@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@^2.76.0, request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +require-uncached@^1.0.3: + version "1.0.3" + resolved "http://192.168.1.113:4873/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +require_optional@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.0.tgz#52a86137a849728eb60a55533617f8f914f59abf" + dependencies: + resolve-from "^2.0.0" + semver "^5.1.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + +resource-router-middleware@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/resource-router-middleware/-/resource-router-middleware-0.5.1.tgz#cceba87013a73e6daf55e612b7e8eb10ffa9381a" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +run-async@^2.2.0: + version "2.3.0" + resolved "http://192.168.1.113:4873/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "http://192.168.1.113:4873/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "http://192.168.1.113:4873/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "http://192.168.1.113:4873/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +safer-buffer@^2.1.0: + version "2.1.2" + resolved "http://192.168.1.113:4873/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +semver@^5.0.3, semver@^5.1.0, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +semver@^5.3.0: + version "5.5.0" + resolved "http://192.168.1.113:4873/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +send@0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.5.0" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.0" + +serve-static@~1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.14.1" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "http://192.168.1.113:4873/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +source-map-support@^0.4.2: + version "0.4.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.6.tgz#32552aa64b458392a85eab3b0b5ee61527167aeb" + dependencies: + source-map "^0.5.3" + +source-map@^0.5.0, source-map@^0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +"statuses@>= 1.3.1 < 2", statuses@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +stream-length@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stream-length/-/stream-length-1.0.2.tgz#8277f3cbee49a4daabcfdb4e2f4a9b5e9f2c9f00" + dependencies: + bluebird "^2.6.2" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +streamifier@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" + +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + +string-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" + dependencies: + strip-ansi "^3.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "http://192.168.1.113:4873/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "http://192.168.1.113:4873/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "http://192.168.1.113:4873/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.3.0: + version "5.3.0" + resolved "http://192.168.1.113:4873/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" + dependencies: + has-flag "^3.0.0" + +table@4.0.2: + version "4.0.2" + resolved "http://192.168.1.113:4873/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" + +tmp@^0.0.33: + version "0.0.33" + resolved "http://192.168.1.113:4873/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +touch@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de" + dependencies: + nopt "~1.0.10" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.4" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.4.tgz#8c9dbfb52795686f166cd2023794bcf103d13c2b" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-is@^1.6.4, type-is@~1.6.13: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@^0.0.6, typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +undefsafe@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +update-notifier@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc" + dependencies: + chalk "^1.0.0" + configstore "^1.0.0" + is-npm "^1.0.0" + latest-version "^1.0.0" + repeating "^1.1.2" + semver-diff "^2.0.0" + string-length "^1.0.0" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +v8flags@^2.0.10: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + +vary@^1, vary@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +which@^1.2.9: + version "1.3.0" + resolved "http://192.168.1.113:4873/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + dependencies: + graceful-fs "^4.1.2" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +xdg-basedir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + dependencies: + os-homedir "^1.0.0" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yallist@^2.1.2: + version "2.1.2" + resolved "http://192.168.1.113:4873/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" diff --git a/SupportAndPricing.md b/SupportAndPricing.md new file mode 100644 index 0000000..630ddfb --- /dev/null +++ b/SupportAndPricing.md @@ -0,0 +1,17 @@ +# Support & Pricing + +To get support mail us on hello@ambar.cloud + +- Install & Configure Ambar on your machine - 999$ +- Mount external data source - 99$ +- Add automatic tagging rule - 299$ +- Add password protection to Ambar UI - 299$ +- Add custom file extractor - 599$ +- Dedicated support - 199$/hour +- Custom feature - 299$/hour + + + + + + diff --git a/WebApi/.babelrc b/WebApi/.babelrc new file mode 100644 index 0000000..457a3ac --- /dev/null +++ b/WebApi/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": [ + "es2015", + "stage-0" + ], + "sourceMaps": true, + "retainLines": true +} \ No newline at end of file diff --git a/WebApi/.eslintignore b/WebApi/.eslintignore new file mode 100644 index 0000000..f517d4c --- /dev/null +++ b/WebApi/.eslintignore @@ -0,0 +1,6 @@ +blueprints/**/files/** +coverage/** +node_modules/** +dist/** +*.spec.js +src/index.html diff --git a/WebApi/.eslintrc b/WebApi/.eslintrc new file mode 100644 index 0000000..559d574 --- /dev/null +++ b/WebApi/.eslintrc @@ -0,0 +1,22 @@ +{ + "extends": "eslint:recommended", + "env": { + "browser": true, + "commonjs": true, + "node": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 2017, + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true + } + }, + "rules": { + "no-console": 1, + "strict": ["error", "global"], + "curly": "warn", + "no-unused-vars": "warn" + } +} \ No newline at end of file diff --git a/WebApi/.gitignore b/WebApi/.gitignore new file mode 100644 index 0000000..2cd8e26 --- /dev/null +++ b/WebApi/.gitignore @@ -0,0 +1,5 @@ +/dist +/logs +/npm-debug.log +/node_modules +.DS_Store diff --git a/WebApi/.vscode/launch.json b/WebApi/.vscode/launch.json new file mode 100644 index 0000000..6e321f6 --- /dev/null +++ b/WebApi/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/debug.js", + "stopOnEntry": false, + "args": [], + "cwd": "${workspaceRoot}", + "preLaunchTask": null, + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "sourceMaps": true, + "outFiles": [] + }, + { + "name": "Attach", + "type": "node", + "request": "attach", + "port": 5858, + "address": "localhost", + "restart": false, + "sourceMaps": false, + "outFiles": [], + "localRoot": "${workspaceRoot}", + "remoteRoot": null + }, + { + "name": "Attach to Process", + "type": "node", + "request": "attach", + "processId": "${command.PickProcess}", + "port": 5858, + "sourceMaps": false, + "outFiles": [] + } + ] +} \ No newline at end of file diff --git a/WebApi/.vscode/settings.json b/WebApi/.vscode/settings.json new file mode 100644 index 0000000..e02dd17 --- /dev/null +++ b/WebApi/.vscode/settings.json @@ -0,0 +1,4 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "javascript.validate.enable": false +} \ No newline at end of file diff --git a/WebApi/Dockerfile b/WebApi/Dockerfile new file mode 100644 index 0000000..232c5e9 --- /dev/null +++ b/WebApi/Dockerfile @@ -0,0 +1,13 @@ +FROM node:8.10 + +# Set a timezone +ENV TZ=UTC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +COPY . . +RUN yarn install +RUN yarn run build +CMD node dist + +HEALTHCHECK --interval=5s --timeout=30s --retries=50 \ + CMD curl -f localhost:8080/api || exit 1 \ No newline at end of file diff --git a/WebApi/apidoc.json b/WebApi/apidoc.json new file mode 100644 index 0000000..2de70a9 --- /dev/null +++ b/WebApi/apidoc.json @@ -0,0 +1,11 @@ +{ + "name": "Ambar Web API", + "version": "0.9.5", + "description": "Ambar Web API documentation", + "title": "Custom apiDoc browser title", + "url" : "https://api.github.com/v1", + "template": { + "withCompare": true, + "withGenerator": true + } +} \ No newline at end of file diff --git a/WebApi/debug.js b/WebApi/debug.js new file mode 100644 index 0000000..eb7b6e6 --- /dev/null +++ b/WebApi/debug.js @@ -0,0 +1,2 @@ +require('babel-register'); +require('./src/index.js'); \ No newline at end of file diff --git a/WebApi/jsconfig.json b/WebApi/jsconfig.json new file mode 100644 index 0000000..0136d6f --- /dev/null +++ b/WebApi/jsconfig.json @@ -0,0 +1,16 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=759670 + // for the documentation about the jsconfig.json format + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "allowSyntheticDefaultImports": true + }, + "exclude": [ + "node_modules", + "bower_components", + "jspm_packages", + "tmp", + "temp" + ] +} diff --git a/WebApi/package.json b/WebApi/package.json new file mode 100644 index 0000000..cb90b26 --- /dev/null +++ b/WebApi/package.json @@ -0,0 +1,57 @@ +{ + "name": "ambar-webapi", + "version": "1.3.0", + "description": "Ambar WebAPI", + "main": "dist", + "scripts": { + "dev": "nodemon -w src --exec \"yarn run lint && babel-node src\"", + "build": "yarn run lint && babel src -s -D -d dist", + "lint": "eslint --ext js src", + "start": "node dist", + "docs": "apidoc -i src/api -o doc/ && apidoc-markdown -p doc/ -o API_DOC.md" + }, + "babel": { + "presets": [ + "es2015", + "stage-0" + ], + "sourceMaps": true, + "retainLines": true + }, + "author": "RD17 ", + "license": "MIT", + "dependencies": { + "JSONStream": "^1.2.1", + "amqplib": "^0.5.1", + "babel-eslint": "^7.1.0", + "babel-plugin-remove-code": "^0.0.6", + "bluebird": "^3.4.7", + "body-parser": "^1.13.3", + "compression": "^1.5.2", + "cors": "^2.7.1", + "cron-parser": "^2.3.1", + "elasticsearch": "^12.1.3", + "eslint-plugin-babel": "^3.3.0", + "eslint-plugin-promise": "^3.3.0", + "express": "^4.13.3", + "gridfs-stream": "^1.1.1", + "minimist": "^1.2.0", + "moment": "^2.15.0", + "mongodb": "^2.2.10", + "multer": "^1.2.0", + "redis": "^2.6.3", + "request": "^2.76.0", + "request-promise-native": "^1.0.5", + "resource-router-middleware": "^0.5.1", + "streamifier": "^0.1.1" + }, + "devDependencies": { + "babel-cli": "^6.9.0", + "babel-core": "^6.9.0", + "babel-preset-es2015": "^6.9.0", + "babel-preset-stage-0": "^6.5.0", + "babel-register": "^6.18.0", + "eslint": "^4.19.1", + "nodemon": "^1.9.2" + } +} diff --git a/WebApi/src/api/files.js b/WebApi/src/api/files.js new file mode 100644 index 0000000..4ba8d45 --- /dev/null +++ b/WebApi/src/api/files.js @@ -0,0 +1,266 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import { + CryptoService, + EsProxy, + CacheProxy, + GridFsProxy, + MongoProxy, + FileUploader, + QueueProxy +} from '../services' +import * as MetaBuilder from '../utils/MetaBuilder' + +const generateFileId = (source_id, full_name) => { + return CryptoService.getSha256(`${source_id}${full_name}`) +} + +const generateExtractedTextFileName = (sha) => `text_${sha}` + +export default ({ storage }) => { + let api = Router() + + //////////////// CALLED FROM UI /////////////////////////////////////////// + /** + * @api {get} api/files/:uri Download File Content by Secure Uri + * @apiGroup Files + * + * @apiSuccessExample HTTP/1.1 200 OK + * Octet-Stream + * + * @apiErrorExample {json} HTTP/1.1 404 Not Found + * File meta or content not found + */ + api.get('/:id', (req, res, next) => { + const uri = req.params.id + + let result + + try { + result = CryptoService.decryptDownloadUri(uri) + } catch (err) { + res.status(400).json(new ErrorResponse('Uri is broken')) + return + } + + const { fileId } = result + + EsProxy.getFileByFileId(storage.elasticSearch, fileId, false) + .then(file => { + if (file === null) { + res.status(404).json(new ErrorResponse('File meta not found')) + return + } + + return GridFsProxy.checkIfFileExists(storage.mongoDb, file.sha256) + .then(fileExsists => ({ + fileExsists: fileExsists, + fileMeta: file.meta, + fileSha: file.sha256, + fileType: file.content.type + })) + .then(result => { + if (!result.fileExsists) { + res.status(404).json(new ErrorResponse('File content not found')) + return + } + + const { fileMeta: { short_name: fileName }, fileSha, fileType } = result + + res.writeHead(200, { + 'Content-Type': fileType, + 'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(fileName)}` + }) + + GridFsProxy.downloadFile(storage.mongoDb, fileSha).pipe(res) + }) + }) + .catch(next) + }) + + /** + * @api {get} api/files/:uri/text Download Parsed Text by Secure Uri + * @apiGroup Files + * + * @apiSuccessExample HTTP/1.1 200 OK + * Octet-Stream + * + * @apiErrorExample {json} HTTP/1.1 404 Not Found + * File meta or content not found + */ + api.get('/:id/text', (req, res, next) => { + const uri = req.params.id + + let result + try { + result = CryptoService.decryptDownloadUri(uri) + } catch (err) { + res.status(400).json(new ErrorResponse('Uri is broken')) + return + } + + const { fileId } = result + + EsProxy.getFileByFileId(storage.elasticSearch, fileId, false) + .then(file => { + if (file === null) { + res.status(404).json(new ErrorResponse('File meta not found')) + return + } + + const extractedTextFileName = generateExtractedTextFileName(file.sha256) + + return GridFsProxy.checkIfFileExists(storage.mongoDb, extractedTextFileName) + .then(fileExsists => ({ + fileExsists: fileExsists, + fileMeta: file.meta, + fileType: 'text/plain' + })) + .then(result => { + if (!result.fileExsists) { + res.status(404).json(new ErrorResponse('Parsed content not found')) + return + } + + const { fileMeta: { short_name: fileName }, fileType } = result + + res.writeHead(200, { + 'Content-Type': fileType, + 'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(`${fileName}.txt`)}` + }) + + GridFsProxy.downloadFile(storage.mongoDb, extractedTextFileName).pipe(res) + }) + }) + .catch(next) + }) + + /** + * @api {post} api/files/uiupload/:filename Upload File + * @apiGroup Files + * @apiDescription New source named `uiupload` with description `Automatically created on UI upload` will be created if source didn't exist. + * + * @apiHeader {String} ambar-email User email + * @apiHeader {String} ambar-email-token User token + * + * @apiExample {curl} Upload File test.txt + * curl -X POST \ + * http://ambar_api_address/api/files/uiupload/test.txt \ + * -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \ + * -F file=@test.txt + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * { "fileId": xxxxx } + * + * @apiErrorExample {json} HTTP/1.1 400 Bad Request + * Wrong request data + * + * @apiErrorExample {json} HTTP/1.1 404 Not Found + * File meta or content not found + */ + api.post('/uiupload/:fileName', FileUploader, (req, res, next) => { + let { params: { fileName: fileName }, files } = req + + const sourceId = 'ui-upload' + const fileContent = (Buffer.isBuffer(files[0].buffer) && Buffer.byteLength(files[0].buffer) > 0) ? files[0].buffer : new Buffer(0) + const size = Buffer.byteLength(fileContent) + + if (size == 0) { + res.status(400).json(new ErrorResponse('File is empty!')) + return + } + + const sha = CryptoService.getSha256(fileContent) + const meta = MetaBuilder.buildShortMeta(fileName, sourceId) + + MongoProxy.getBucketById(storage.mongoDb, sourceId) + .then(bucket => { + if (!bucket) { + return MongoProxy.createBucket(storage.mongoDb, { id: sourceId, description: 'Automatically created on UI upload' }) + } + return true + }) + .then(() => GridFsProxy.checkIfFileExists(storage.mongoDb, sha)) + .then(found => { + if (!found) { + return GridFsProxy.uploadFile(storage.mongoDb, sha, fileContent) + } + }) + .then(() => QueueProxy.enqueuePipelineMessage(storage, { sha: sha, fileId: generateFileId(meta.source_id, meta.full_name), sourceId: sourceId, meta: meta })) + .then(() => { + CacheProxy.addMetaId(storage.redis, meta.id) + res.status(200).json({ fileId: generateFileId(meta.source_id, meta.full_name) }) + }) + .catch(next) + }) + + /** + * @api {put} api/files/hide/:fileId Hide File + * @apiGroup Files + * @apiDescription Hide file by file id + * + * @apiHeader {String} ambar-email User email + * @apiHeader {String} ambar-email-token User token + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * HTTP/1.1 200 OK + * + * @apiErrorExample {json} HTTP/1.1 404 NotFound + * File not found + */ + api.put('/hide/:fileId', (req, res, next) => { + const fileId = req.params.fileId + + EsProxy.checkIfFileExists(storage.elasticSearch, fileId) + .then(fileExists => { + if (!fileExists) { + res.sendStatus(404) + return + } + + return EsProxy.hideFile(storage.elasticSearch, fileId) + .then(() => res.sendStatus(200)) + }) + .catch(next) + }) + + /** + * @api {put} api/files/unhide/:fileId Unhide File + * @apiGroup Files + * @apiDescription Unhide file by file id + * + * @apiHeader {String} ambar-email User email + * @apiHeader {String} ambar-email-token User token + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * HTTP/1.1 200 OK + * + * @apiErrorExample {json} HTTP/1.1 404 NotFound + * File not found + */ + api.put('/unhide/:fileId', (req, res, next) => { + const fileId = req.params.fileId + + EsProxy.checkIfFileExists(storage.elasticSearch, fileId) + .then(fileExists => { + if (!fileExists) { + res.sendStatus(404) + return + } + + return EsProxy.unHideFile(storage.elasticSearch, fileId) + .then(() => res.sendStatus(200)) + .catch(err => { + if ((err.statusCode) && (err.statusCode == 404)) { + res.sendStatus(200) + return + } + + throw new Error(err) + }) + }) + .catch(next) + }) + + return api +} \ No newline at end of file diff --git a/WebApi/src/api/index.js b/WebApi/src/api/index.js new file mode 100644 index 0000000..c01cd0e --- /dev/null +++ b/WebApi/src/api/index.js @@ -0,0 +1,30 @@ +import { version } from '../../package.json' +import { Router } from 'express' +import files from './files' +import logs from './logs' +import search from './search' +import stats from './stats' +import thumbs from './thumbs' +import tags from './tags' + +export default ({ config, storage }) => { + let api = Router() + + api.use('/files', files({ config, storage })) + api.use('/logs', logs({ config, storage })) + api.use('/search', search({ config, storage })) + api.use('/stats', stats({ config, storage })) + api.use('/thumbs', thumbs({ config, storage })) + api.use('/tags', tags({ config, storage })) + + api.get('/', (req, res) => { + res.json({ + version: version, + analyticsToken: config.analyticsToken, + uiLang: config.uiLang, + rawConfig: config + }) + }) + + return api +} diff --git a/WebApi/src/api/logs.js b/WebApi/src/api/logs.js new file mode 100644 index 0000000..28efb36 --- /dev/null +++ b/WebApi/src/api/logs.js @@ -0,0 +1,44 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import { EsProxy } from '../services' + +const DEFAULT_RECORDS_COUNT = 10 +const MAX_RECORDS_COUNT = 100 + + +export default ({ storage }) => { + let api = Router() + + /** + * Submit log record + */ + api.post('/', (req, res) => { + const { body: logItem } = req + + if (!logItem) { + res.status(400).json(new ErrorResponse('Bad request')) + return + } + + res.sendStatus(200) //Immediately send response + EsProxy.indexLogItem(storage.elasticSearch, logItem) + }) + + /** + * Get log records + */ + api.get('/', (req, res, next) => { + const { query: { recordsCount = DEFAULT_RECORDS_COUNT } } = req + + if (recordsCount > MAX_RECORDS_COUNT && recordsCount <= 0) { + res.status(400).json(new ErrorResponse(`RecordsCount should be greater than 0 and lower than ${MAX_RECORDS_COUNT}`)) + return + } + + EsProxy.getLastLogRecords(storage.elasticSearch, recordsCount) + .then(response => res.status(200).json(response)) + .catch(next) + }) + + return api +} diff --git a/WebApi/src/api/search.js b/WebApi/src/api/search.js new file mode 100644 index 0000000..476f687 --- /dev/null +++ b/WebApi/src/api/search.js @@ -0,0 +1,216 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import * as QueryParser from '../utils/QueryParser' +import { EsProxy, CryptoService } from '../services' + +const DEFAULT_PAGE = 0 +const DEFAULT_SIZE = 10 +const MAX_SIZE = 200 + +const hrTimeToMilliSeconds = (hrTime) => (hrTime[0] * 1e9 + hrTime[1]) / 1e6 + +export default ({ storage }) => { + let api = Router() + + /** + * @api {get} api/search Search For Documents By Query + * @apiGroup Search + * + * @apiParam {String} query URI_ENCODED query string. Check details of query syntax [here](https://blog.ambar.cloud/mastering-ambar-search-queries/). + * @apiParam {Number} [page=0] page to return + * @apiParam {Number} [size=10] number of results to return per page. Maximum is 100. + * + * @apiHeader {String} ambar-email User email. + * @apiHeader {String} ambar-email-token User token. + * + * @apiExample {curl} Search For `John` + * curl -i http://ambar_api_address/api/search?query=John + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * + * @apiErrorExample {json} HTTP/1.1 400 BadRequest + * HTTP/1.1 400 BadRequest + */ + api.get('/', (req, res, next) => { + const { query: { query: queryStr, page: pageStr = DEFAULT_PAGE, size: sizeStr = DEFAULT_SIZE } } = req + const page = parseInt(pageStr) + const size = parseInt(sizeStr) + const query = decodeURI(queryStr) + + if (!Number.isInteger(page) || page < 0) { + res.status(400).json(new ErrorResponse('Page is invalid')) + return + } + + if (!Number.isInteger(size) || size < 1 || size > MAX_SIZE) { + res.status(400).json(new ErrorResponse('Size is invalid')) + return + } + + let parsedQuery = QueryParser.parseEsStringQuery(query) + + const startTime = process.hrtime() + + EsProxy.searchFiles(storage.elasticSearch, parsedQuery, page, size) + .then((results) => res.status(200).json({ + ...results, + hits: results.hits + .map((hit) => { + hit.meta['download_uri'] = CryptoService.encryptDownloadUri(hit.file_id) + return hit + }), + took: hrTimeToMilliSeconds(process.hrtime(startTime)) + })) + .catch(next) + }) + + /** + * @api {get} api/search/tree Get documents tree by query + * @apiGroup Search + * + * @apiParam {String} query URI_ENCODED query string. Check details of query syntax [here](https://blog.ambar.cloud/mastering-ambar-search-queries/). + * + * @apiHeader {String} ambar-email User email. + * @apiHeader {String} ambar-email-token User token. + * + * curl -i http://ambar_api_address/api/search/tree?query=John + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * + * @apiErrorExample {json} HTTP/1.1 400 BadRequest + * HTTP/1.1 400 BadRequest + */ + api.get('/tree', (req, res, next) => { + const { query: { query: queryStr } } = req + const query = decodeURI(queryStr) + + let parsedQuery = QueryParser.parseEsStringQuery(query) + + const startTime = process.hrtime() + + EsProxy.getFilesTreeByQuery(storage.elasticSearch, parsedQuery) + .then((results) => res.status(200).json({ + ...results, + took: hrTimeToMilliSeconds(process.hrtime(startTime)) + })) + .catch(next) + }) + + /** + * @api {get} api/search/stats Get documents stats by query + * @apiGroup Search + * + * @apiParam {String} query URI_ENCODED query string. Check details of query syntax [here](https://blog.ambar.cloud/mastering-ambar-search-queries/). + * + * @apiHeader {String} ambar-email User email. + * @apiHeader {String} ambar-email-token User token. + * + * curl -i http://ambar_api_address/api/search/stats?query=John + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * + * @apiErrorExample {json} HTTP/1.1 400 BadRequest + * HTTP/1.1 400 BadRequest + */ + api.get('/stats', (req, res, next) => { + const { query: { query: queryStr } } = req + const query = decodeURI(queryStr) + + let parsedQuery = QueryParser.parseEsStringQuery(query) + + const startTime = process.hrtime() + + EsProxy.getFilesStatsByQuery(storage.elasticSearch, parsedQuery) + .then((results) => res.status(200).json({ + ...results, + took: hrTimeToMilliSeconds(process.hrtime(startTime)) + })) + .catch(next) + }) + + /** + * @api {get} api/search/:fileId Retrieve File Highlight by Query and fileId + * @apiGroup Search + * + * @apiDescription This method is useful for getting higlights of large files > 30 MB + * + * @apiParam {String} fileId file fileId + * @apiParam {String} query query string + * + * @apiHeader {String} ambar-email User email. + * @apiHeader {String} ambar-email-token User token. + * + * @apiExample {curl} Retrieve Higlights for File with fileId `318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3` + * curl -i http://ambar:8004/api/search/318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3?query=John + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * + * @apiErrorExample {json} HTTP/1.1 400 BadRequest + * HTTP/1.1 400 BadRequest + */ + api.get('/:fileId', (req, res, next) => { + const { params: { fileId: fileId }, query: { query: query } } = req + + if (!query || query === '') { + res.status(400).json(new ErrorResponse('Query is empty')) + return + } + + let parsedQuery = QueryParser.parseEsStringQuery(query) + + EsProxy.getFileHighlightByFileId(storage.elasticSearch, parsedQuery, fileId) + .then((hit) => { + let highlight = hit.content && hit.content.highlight ? hit.content.highlight : null + if (!highlight) { + highlight = { 'text': [''] } + } + + res.status(200).json({ highlight: highlight }) + + return + }) + .catch(next) + }) + + /** + * @api {get} api/search/:fileId/full Retrieve Full File Highlight by Query and fileId + * @apiGroup Search + * + * @apiDescription This method is useful for getting higlights of large files > 30 MB + * + * @apiParam {String} fileId file fileId + * @apiParam {String} query query string + * + * @apiHeader {String} ambar-email User email. + * @apiHeader {String} ambar-email-token User token. + * + * @apiExample {curl} Retrieve Full Higlight for File with fileId `318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3` + * curl -i http://ambar:8004/api/search/318be2290125e0a6cfb7229133ba3c4632068ae04942ed5c7c660718d9d41eb3/full?query=John + * + * @apiSuccessExample {json} HTTP/1.1 200 OK + * Aesop, by some strange accident it seems to have entirely
disappeared, and to have been lost sight of. His name is
mentioned by Avienus; by Suidas, a celebrated critic, at the
close of the eleventh century, who gives in his lexicon several
isolated verses of his version of the fables; and by John
Tzetzes, a grammarian and poet of Constantinople, who lived
during the latter half of the twelfth century. Nevelet, in the
preface to the volume which we have described, points out that
the Fables of Planudes could not be the work of Aesop, as they
contain a reference in two places to Holy + * + * @apiErrorExample {json} HTTP/1.1 400 BadRequest + * HTTP/1.1 400 BadRequest + */ + api.get('/:fileId/full', (req, res, next) => { + const { params: { fileId: fileId }, query: { query: query } } = req + + if (!query || query === '') { + res.status(400).json(new ErrorResponse('Query is empty')) + return + } + + let parsedQuery = QueryParser.parseEsStringQuery(query) + + EsProxy.getFullFileHighlightByFileId(storage.elasticSearch, parsedQuery, fileId) + .then((hit) => { + res.status(200).json(hit) + + return + }) + .catch(next) + }) + + return api +} diff --git a/WebApi/src/api/stats.js b/WebApi/src/api/stats.js new file mode 100644 index 0000000..41b24b0 --- /dev/null +++ b/WebApi/src/api/stats.js @@ -0,0 +1,125 @@ +import { Router } from 'express' +import moment from 'moment' +import * as QueryParser from '../utils/QueryParser' +import { EsProxy } from '../services' + +const MIN_THRESHOLD_CONTENT_TYPE = 0.05 +const DAYS_SPAN = 30 + +export default ({ storage }) => { + let api = Router() + + const buildProcRateStats = (esResponse) => { + const procRate = { + data: [], + names: [] + } + + const names = new Set() + const dates = [] + + esResponse.proc_rate.buckets.forEach((dateBucket) => { + dateBucket.source.buckets.forEach((nameBucket) => { + names.add(nameBucket.key) + }) + }) + + procRate.names = Array.from(names) + + let dateSpan = DAYS_SPAN - 1 + while (dateSpan >= 0) { + dates.push(moment().startOf('day').add(-dateSpan, 'days')) + dateSpan-- + } + + dates.forEach((date) => { + const dateItem = { + date: date.format('YYYY-MM-DD') + } + names.forEach((name) => { + dateItem[name] = 0 + const esDateBucket = esResponse.proc_rate.buckets.find((bucket) => (moment(bucket.key).startOf('day').isSame(date))) + if (esDateBucket) { + const esNameBucket = esDateBucket.source.buckets.find((bucket) => (bucket.key == name)) + if (esNameBucket) { + dateItem[name] = esNameBucket.doc_count + } + } + }) + procRate.data.push(dateItem) + }) + + return procRate + } + + const buildContentTypeStats = (esResponse) => { + const contentTypeTotal = esResponse.content_type.buckets.reduce((sum, bucket) => { + return sum + bucket.doc_count + }, 0) + + const contentType = { + total: contentTypeTotal, + minThreshold: MIN_THRESHOLD_CONTENT_TYPE * contentTypeTotal, + data: esResponse.content_type.buckets.map((bucket) => ({ name: bucket.key, value: bucket.doc_count, sizeDataInBytes: bucket.size })) + } + + return contentType + } + + const buildProcTotalStats = (esResponse) => { + const procTotalStats = { + totalCount: esResponse.proc_total.count, + sizeDataInBytes: { + sum: esResponse.proc_total.sum, + avg: esResponse.proc_total.avg, + min: esResponse.proc_total.min, + max: esResponse.proc_total.max + } + } + + return procTotalStats + } + + const esStatsToView = (esResponse) => { + const res = { + contentType: buildContentTypeStats(esResponse), + procRate: buildProcRateStats(esResponse), + procTotal: buildProcTotalStats(esResponse) + } + + return (res) + } + + /** + * Get Statistics + */ + api.get('/', (req, res, next) => { + EsProxy.getStats(storage.elasticSearch) + .then(response => res.status(200).json(esStatsToView(response.aggregations))) + .catch(next) + }) + + /** + * Get Combined Statistics + */ + api.get('/combined', (req, res, next) => { + let parsedQuery = QueryParser.parseEsStringQuery('*') + + EsProxy.getFilesStatsByQuery(storage.elasticSearch, parsedQuery, 10000) + .then((results) => res.status(200).json(results)) + .catch(next) + }) + + /** + * Get Combined Statistics + */ + api.get('/processing', (req, res, next) => { + let parsedQuery = QueryParser.parseEsStringQuery('*') + + EsProxy.getProcessingStats(storage.elasticSearch, parsedQuery, 10000) + .then((results) => res.status(200).json(results)) + .catch(next) + }) + + return api +} diff --git a/WebApi/src/api/tags.js b/WebApi/src/api/tags.js new file mode 100644 index 0000000..52eaf54 --- /dev/null +++ b/WebApi/src/api/tags.js @@ -0,0 +1,161 @@ +import { Router } from 'express' +import ErrorResponse from '../utils/ErrorResponse' +import { + CryptoService, + CacheProxy +} from '../services' + +const MANUAL_TAG_TYPE = 'manual' + +const generateTagId = (fileId, tagType, tagName) => { + return CryptoService.getSha256(`tag_${fileId.trim().toLowerCase()}${tagType.trim().toLowerCase()}${tagName.trim().toLowerCase()}`) +} + +export default ({ storage }) => { + let api = Router() + + //////////////// CALLED FROM UI //////////////////////////////////// + /** + * @api {get} api/tags/ Get Tags + * @apiGroup Tags + * + * @apiHeader {String} ambar-email User email + * @apiHeader {String} ambar-email-token User token + * + * + * @apiSuccessExample HTTP/1.1 200 OK +[ + { + "name":"ocr", + "filesCount":3 + }, + { + "name":"test", + "filesCount":2 + }, + { + "name":"pdf", + "filesCount":1 + } +] + * + */ + api.get('/', (req, res, next) => { + CacheProxy.getTags(storage.redis, storage.elasticSearch) + .then(tags => { + res.status(200).json(tags) + }) + .catch(next) + }) + + /** + * @api {post} api/tags/:fileId/:tagType/:tagName Add Tag For File + * @apiGroup Tags + * + * @apiHeader {String} ambar-email User email + * @apiHeader {String} ambar-email-token User token + * + * @apiParam {String} fileId File Id to add tag to. + * @apiParam {String} tagType Tag type to add. + * @apiParam {String} tagName Tag name to add. + * + * @apiSuccessExample HTTP/1.1 200 OK + { + "tagId":"e9536a83e64ff03617ab0379d835ac7bbf213bafb95cb42907a56e735472d4fc", + "tags":[ + { + "name":"ocr", + "filesCount":3 + }, + { + "name":"test", + "filesCount":2 + }, + { + "name":"pdf", + "filesCount":1 + } + ] + } + * + */ + api.post('/:fileId/:tagType/:tagName', (req, res, next) => { + const { params: { fileId, tagType, tagName } } = req + + if (!tagName || !fileId || !tagType || tagType.toLowerCase() != MANUAL_TAG_TYPE) { + res.status(400).json(new ErrorResponse('Required field is missing')) + return + } + + const type = tagType.toLowerCase() + const tagId = generateTagId(fileId, type, tagName) + + const tag = { + id: tagId, + type: type.toLowerCase(), + name: tagName.trim().toLowerCase() + } + + CacheProxy.addTag(storage.redis, storage.elasticSearch, fileId, tag) + .then(tags => { + res.status(200).json({ tagId: tagId, tags: tags }) + }) + .catch(next) + }) + + /** + * @api {delete} api/tags/:fileId/:tagType/:tagName Delete Tag From File + * @apiGroup Tags + * + * @apiHeader {String} ambar-email User email + * @apiHeader {String} ambar-email-token User token + * + * @apiParam {String} fileId File Id to delete tag from. + * @apiParam {String} tagType Tag type to delete. + * @apiParam {String} tagName Tag name to delete. + * + * @apiSuccessExample HTTP/1.1 200 OK + { + "tags":[ + { + "name":"ocr", + "filesCount":3 + }, + { + "name":"test", + "filesCount":2 + }, + { + "name":"pdf", + "filesCount":1 + } + ] + } + * + */ + api.delete('/:fileId/:tagType/:tagName', (req, res, next) => { + const { params: { fileId, tagType, tagName } } = req + + if (!fileId || !tagName || !tagType) { + res.status(400).json(new ErrorResponse('Required field is missing')) + return + } + + const type = tagType.toLowerCase() + const tagId = generateTagId(fileId, type, tagName) + + const tag = { + id: tagId, + type: type.toLowerCase(), + name: tagName.trim().toLowerCase() + } + + CacheProxy.removeTag(storage.redis, storage.elasticSearch, fileId, tag) + .then(tags => { + res.status(200).json({ tags: tags }) + }) + .catch(next) + }) + + return api +} \ No newline at end of file diff --git a/WebApi/src/api/thumbs.js b/WebApi/src/api/thumbs.js new file mode 100644 index 0000000..6ad4cda --- /dev/null +++ b/WebApi/src/api/thumbs.js @@ -0,0 +1,39 @@ +import { Router } from 'express' +import { MongoProxy } from '../services' + +export default ({ storage}) => { + let api = Router() + + /** + * @api {get} api/thumbs/:id Get Thumbnail by Id + * @apiGroup Thumbnails + * + * @apiSuccessExample HTTP/1.1 200 OK + * Octet-Stream + * + * @apiErrorExample {json} HTTP/1.1 404 NotFound + * HTTP/1.1 404 NotFound + */ + + api.get('/:id', (req, res, next) => { + const {params: {id: thumbId}} = req + + MongoProxy.getThumbnailById(storage.mongoDb, thumbId) + .then((thumb) => { + if (!thumb) { + res.sendStatus(404) + return + } + + res.status(200) + .header({ + 'Content-Type': 'image/jpeg', + 'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(thumbId)}.jpeg` + }) + .send(thumb.data.buffer) + }) + .catch(next) + }) + + return api +} \ No newline at end of file diff --git a/WebApi/src/config.js b/WebApi/src/config.js new file mode 100644 index 0000000..21aec76 --- /dev/null +++ b/WebApi/src/config.js @@ -0,0 +1,48 @@ +import parseArgs from 'minimist' + +const defaultConfig = { + "localPort": 8080, + "bodyLimit": "1024mb", + "corsHeaders": ["Link"], + "mongoDbUrl": "mongodb://ambar:27017/ambar_data", + "elasticSearchUrl": "http://ambar:9200", + "redisHost": "ambar", + "redisPort": "6379", + "apiUrl": "http://ambar:8080", + "serviceApiUrl": "http://localhost:8081", + "rabbitHost": "amqp://ambar", + "uiLang": "en", + "analyticsToken": "", +} + +const intParamsList = ['localPort'] + +let config = null + +const init = () => { + const options = parseArgs(process.argv.slice(2)) + + const receivedConfig = options.config && options.config != '' ? JSON.parse(new Buffer(options.config, 'base64').toString('utf8')) : {} + + Object.keys(receivedConfig).forEach(key => { + if (intParamsList.includes(key)) { + receivedConfig[key] = parseInt(receivedConfig[key]) + } + }) + + const env = process.env + + return { + ...defaultConfig, + ...receivedConfig, + ...env + } +} + +export default (() => { + return config === null + ? init() + : config +})() + + diff --git a/WebApi/src/index.js b/WebApi/src/index.js new file mode 100644 index 0000000..bc9180f --- /dev/null +++ b/WebApi/src/index.js @@ -0,0 +1,49 @@ +import http from 'http' +import express from 'express' +import cors from 'cors' +import bodyParser from 'body-parser' +import api from './api' +import config from './config' +import { ErrorHandlerService, EsProxy, StorageService } from './services' + +const createLogRecord = (type, message) => ({ + type: type, + source_id: 'webapi', + message: message +}) + +let app = express() + +app.server = http.createServer(app) + +app.use(cors({ + credentials: true, + origin: true +})) + +app.use(bodyParser.json({ + limit: config.bodyLimit +})) + +// connect to storage +StorageService.initializeStorage() + .then((storage) => { + app.use('/api', api({ config, storage })) + app.use(ErrorHandlerService(storage.elasticSearch)) + app.server.listen(process.env.PORT || config.localPort) + + //eslint-disable-next-line no-console + console.log(`Started on ${app.server.address().address}:${app.server.address().port}`) + + EsProxy.indexLogItem( + storage.elasticSearch, + createLogRecord('info', `Started on ${app.server.address().address}:${app.server.address().port}`) + ) + }) + .catch((err) => { + //eslint-disable-next-line no-console + console.log('Catastrophic failure!', err) + process.exit(1) + }) + +export default app \ No newline at end of file diff --git a/WebApi/src/services/CacheProxy.js b/WebApi/src/services/CacheProxy.js new file mode 100644 index 0000000..ef5a322 --- /dev/null +++ b/WebApi/src/services/CacheProxy.js @@ -0,0 +1,118 @@ +import { EsProxy, DateTimeService } from './index' + +const TAGS_HASH_NAME = 'tags' + +export const addMetaId = (redis, metaId) => { redis.set(`meta:${metaId}`, DateTimeService.getCurrentDateTime()) } + +export const checkIfTokenExists = (redis, token) => redis.getAsync(token) +export const addToken = (redis, token, ttlSeconds) => { + redis.set(token, DateTimeService.getCurrentDateTime()) + redis.expire(token, ttlSeconds) +} +export const removeToken = (redis, token) => { + redis.del(token) +} + +export const addTag = (redis, elasticSearch, fileId, tag) => new Promise((resolve, reject) => { + EsProxy.indexTag(elasticSearch, fileId, tag) + .then((esResult) => + hasTagsInRedis(redis) + .then(hasTags => { + if (hasTags && esResult.result == 'created') { + return getTagFilesCount(redis, tag.name, tag.type) + .then(filesCount => { + setTagFilesCount(redis, tag.name, tag.type, filesCount + 1) + }) + } + return Promise.resolve() + })) + .then(() => getTags(redis, elasticSearch)) + .then(tags => resolve(tags)) + .catch(err => reject(err)) +}) + +export const removeTag = (redis, elasticSearch, fileId, tag) => new Promise((resolve, reject) => { + EsProxy.deleteTag(elasticSearch, fileId, tag.id) + .then(() => hasTagsInRedis(redis)) + .then(hasTags => { + if (hasTags) { + return getTagFilesCount(redis, tag.name, tag.type) + .then(filesCount => { + setTagFilesCount(redis, tag.name, tag.type, filesCount - 1) + }) + } + return Promise.resolve() + }) + .then(() => getTags(redis, elasticSearch)) + .then(tags => resolve(tags)) + .catch(err => reject(err)) +}) + +const transformTagsStat = (redisResp) => !redisResp ? [] : Object.keys(redisResp).map(tagName => ({ + name: tagName.split(' ')[1], + type: tagName.split(' ')[0], + filesCount: parseInt(redisResp[tagName]) +})).sort((tagA, tagB) => tagB.filesCount - tagA.filesCount) + +const hasTagsInRedis = (redis) => new Promise((resolve, reject) => { + redis.existsAsync(TAGS_HASH_NAME) + .then(res => resolve(res == 1 ? true : false)) + .catch(err => reject(err)) +}) + +const getTagFilesCount = (redis, tagName, tagType) => redis.hgetAsync(TAGS_HASH_NAME, `${tagType} ${tagName}`).then(filesCount => { + return !filesCount ? 0 : parseInt(filesCount) +}) + +const setTagFilesCount = (redis, tagName, tagType, filesCount) => { + if (filesCount == 0) { + redis.hdel(TAGS_HASH_NAME, `${tagType} ${tagName}`) + return + } + + redis.hset(TAGS_HASH_NAME, `${tagType} ${tagName}`, filesCount) +} + +export const getTags = (redis, elasticSearch) => new Promise((resolve, reject) => { + hasTagsInRedis(redis) + .then(hasTags => { + if (!hasTags) { + return setTagsFromEs(redis, elasticSearch) + } + return Promise.resolve() + }) + .then(() => redis.hgetallAsync(TAGS_HASH_NAME)) + .then((redisResult) => { + resolve(transformTagsStat(redisResult)) + }) + .catch(err => reject(err)) +}) + +const setTagsFromEs = (redis, elasticSearch) => new Promise((resolve, reject) => { + EsProxy.getTagsStat(elasticSearch) + .then(tags => { + if (tags.length == 0) { + resolve() + return + } + + const tagsArray = [] + let idx = 0 + + tags.forEach(tag => { + tagsArray[idx] = `${tag.type} ${tag.name}` + idx++ + tagsArray[idx] = tag.filesCount + idx++ + }); + + redis.hmset(TAGS_HASH_NAME, tagsArray, (err, res) => { + if (err) { + reject(err) + return + } + resolve(res) + }) + }) + .catch(err => reject(err)) +}) \ No newline at end of file diff --git a/WebApi/src/services/CryptoService.js b/WebApi/src/services/CryptoService.js new file mode 100644 index 0000000..c4b053e --- /dev/null +++ b/WebApi/src/services/CryptoService.js @@ -0,0 +1,28 @@ +import crypto from 'crypto' +import bluebird from 'bluebird' + +const pbkdf2 = bluebird.promisify(crypto.pbkdf2); + +const DOWNLOAD_URI_CIPHER_KEY = 'BfeZp2UV' + +export const getSha256 = (data) => crypto.createHash('sha256').update(data).digest('hex') +export const getSha1 = (data) => crypto.createHash('sha1').update(data).digest('hex') + +export const getPasswordHash = (password, salt) => pbkdf2(password, salt, 8192, 512, 'sha512').then((hash) => hash.toString('hex')) + +export const generateRandom = (length = 256) => crypto.randomBytes(length).toString('hex') + +export const encryptDownloadUri = (fileId) => { + const cipher = crypto.createCipher('aes192', DOWNLOAD_URI_CIPHER_KEY) + const uri = { fileId: fileId } + + return cipher.update(JSON.stringify(uri), 'utf8', 'hex') + cipher.final('hex') +} + +export const decryptDownloadUri = (uri) => { + const decipher = crypto.createDecipher('aes192', DOWNLOAD_URI_CIPHER_KEY) + const decryptedUri = decipher.update(uri, 'hex', 'utf8') + decipher.final('utf8') + + return JSON.parse(decryptedUri) +} + diff --git a/WebApi/src/services/DateTimeService.js b/WebApi/src/services/DateTimeService.js new file mode 100644 index 0000000..e6ca1ca --- /dev/null +++ b/WebApi/src/services/DateTimeService.js @@ -0,0 +1,23 @@ +import moment from 'moment' +import parser from 'cron-parser' + +const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSS' + +export const getCurrentDateTime = () => moment().format(DATETIME_FORMAT) +export const getCurrentDateTimeAddDays = (days) => moment().add(days, 'days').format(DATETIME_FORMAT) +export const getCurrentDateTimeMinusMinutes = (minutes) => moment().subtract({ minutes: minutes }).format(DATETIME_FORMAT) +export const getStartOfToday = () => moment().startOf('day').format(DATETIME_FORMAT) +export const getStartOfYesterday = () => moment().subtract({ days: 1 }).startOf('day').format(DATETIME_FORMAT) +export const getStartOfThisWeek = () => moment().startOf('isoWeek').format(DATETIME_FORMAT) +export const getStartOfThisMonth = () => moment().startOf('month').format(DATETIME_FORMAT) +export const getStartOfThisYear = () => moment().startOf('year').format(DATETIME_FORMAT) +export const parseDateTime = (dateStr) => moment(dateStr, DATETIME_FORMAT, true) +export const getDateTimeDifferenceFromNowInHumanForm = (dateStr) => moment.duration(moment().diff(moment(dateStr, DATETIME_FORMAT, true))).humanize() +export const getDateTimeDifferenceFromNow = (dateStr) => moment().diff(moment(dateStr, DATETIME_FORMAT, true)) +export const isSame = (dateA, dateB) => parseDateTime(dateA).isSame(parseDateTime(dateB)) +export const getCronIntervalInMs = (cronSchedule) => { + const interval = parser.parseExpression(cronSchedule) + const nextRun = interval.next()._date + const nextNextRun = interval.next()._date + return moment(nextNextRun).diff(nextRun) +} diff --git a/WebApi/src/services/ErrorHandlerService.js b/WebApi/src/services/ErrorHandlerService.js new file mode 100644 index 0000000..e54a591 --- /dev/null +++ b/WebApi/src/services/ErrorHandlerService.js @@ -0,0 +1,25 @@ +import { EsProxy, DateTimeService } from './index' +import ErrorResponse from '../utils/ErrorResponse' + +export default (esClient) => (err, req, res, next) => { + + //eslint-disable-next-line no-console + console.error(err) + + const message = (err instanceof Error) + ? `${err.message}\n ${err.stack}` + : (typeof err === 'string' || err instanceof String) ? err : JSON.stringify(err) + + EsProxy.indexLogItem(esClient, { + created_datetime: DateTimeService.getCurrentDateTime(), + source_id: 'webapi', + type: 'error', + message: message + }) + + if (res.headersSent) { + return next(err) + } + + res.status(500).json(new ErrorResponse(message)) +} \ No newline at end of file diff --git a/WebApi/src/services/EsProxy/EsProxy.js b/WebApi/src/services/EsProxy/EsProxy.js new file mode 100644 index 0000000..4ab6cea --- /dev/null +++ b/WebApi/src/services/EsProxy/EsProxy.js @@ -0,0 +1,596 @@ +import moment from 'moment' +import { DateTimeService, CryptoService } from '../index' +import * as EsQueryBuilder from '../../utils/EsQueryBuilder' + +const MIN_THRESHOLD_EXTENSION = 0.03 + +const ES_LOG_INDEX_NAME = "ambar_log_record_data" +const ES_LOG_TYPE_NAME = "ambar_log_record" +const ES_FILE_INDEX_NAME = "ambar_file_data" +const ES_FILE_TYPE_NAME = "ambar_file" +const ES_FILE_TAG_TYPE_NAME = "ambar_file_tag" +const ES_FILE_HIDDEN_MARK_TYPE_NAME = "ambar_file_hidden_mark" + +const getHiddenMarkId = (fileId) => CryptoService.getSha256(`hiddenmark_${fileId}`) + +const normalizeHitsScore = (hits, maxScore) => hits.map(hit => ({ + ...hit, + _score: hit._score / maxScore +})) + +const transformTagsStat = (esResponse) => { + const resp = [] + + esResponse.aggregations.tags.buckets.forEach(tag => { + tag.type.buckets.forEach(tagType => { + resp.push({ name: tag.key, type: tagType.key, filesCount: tagType.doc_count }) + }) + }) + + return resp +} + +const mergeAnalyzedFieldsHighlight = (highlight) => { + if (!highlight) { + return highlight + } + + Object.keys(highlight).filter(key => /\.analyzed$/.test(key)).forEach(key => { + const originalKey = key.replace(/\.analyzed$/, '') + if (!highlight[originalKey]) { + highlight[originalKey] = [] + } + highlight[originalKey].concat(highlight[key]) + delete highlight[key] + }) + + return highlight +} + +const normalizeHitContentHighlights = (hit) => { + const ALLOWED_TAGS = ['br', 'em', 'em class="entity"'] + const SEPARATOR_TAG = '
' + const SPACE_CHAR = ' ' + + if (!hit.content) { + return hit + } + + if (!hit.content.highlight) { + return hit + } + + if (!hit.content.highlight.text) { + return hit + } + + hit.content.highlight.text = hit.content.highlight.text.map(hl => { + let strippedHl = hl + .replace(//gim, '>') + + ALLOWED_TAGS.forEach(tag => { + strippedHl = strippedHl + .replace(new RegExp(`(<${tag}>)`, 'gim'), `<${tag}>`) + .replace(new RegExp(`(<${tag}/>)`, 'gim'), `<${tag}/>`) + .replace(new RegExp(`(</${tag}>)`, 'gim'), ``) + }) + + strippedHl = strippedHl.replace(/(?:\r\n|\r|\n)/gi, SEPARATOR_TAG) + .replace(/((\s*)){2,}/gi, SEPARATOR_TAG) + .replace(/(( )+)/gi, SPACE_CHAR) + .replace(/(?:\t)+/gi, SPACE_CHAR) + .replace(/[\s]+/gi, SPACE_CHAR) + + return strippedHl + }) + + return hit +} + +const transformHit = (hit) => { + const transformedHit = { + ...hit._source, + tags: [], + score: hit._score, + hidden_mark: undefined + } + + const highlight = mergeAnalyzedFieldsHighlight(hit.highlight) + + if (highlight) { + Object.keys(highlight).forEach(key => { + if (key.startsWith('meta.')) { + if (!transformedHit.meta.highlight) { + transformedHit.meta.highlight = {} + } + transformedHit.meta.highlight[key.replace('meta.', '')] = highlight[key] + } + if (key.startsWith('content.')) { + if (!transformedHit.content.highlight) { + transformedHit.content.highlight = {} + } + transformedHit.content.highlight[key.replace('content.', '')] = highlight[key] + } + }) + } + + if (hit.inner_hits && hit.inner_hits.ambar_file_tag) { + transformedHit.tags = hit.inner_hits.ambar_file_tag.hits.hits.map(hit => { + return hit.highlight ? { ...hit._source, highlight: hit.highlight } : hit._source + }) + } + + if (hit.inner_hits && hit.inner_hits.ambar_file_hidden_mark && hit.inner_hits.ambar_file_hidden_mark.hits.hits.length > 0) { + transformedHit.hidden_mark = hit.inner_hits.ambar_file_hidden_mark.hits.hits[0]._source + } + + return transformedHit +} + +const getPathType = (fullPath) => /\/$/g.test(fullPath) ? 'folder' : 'file' +const getPathDepth = (fullPath) => getPathType(fullPath) === 'folder' ? + fullPath.match(/\//g).length - 3 : + fullPath.match(/\//g).length - 2 +const getParentPath = (fullPath) => getPathType(fullPath) === 'file' ? + fullPath.slice(0, fullPath.lastIndexOf('/') + 1) : + fullPath.slice(0, fullPath.slice(0, -1).lastIndexOf('/') + 1) +const getPathName = (fullPath) => getPathType(fullPath) === 'file' ? + fullPath.slice(fullPath.lastIndexOf('/') + 1) : + fullPath.slice(fullPath.slice(0, fullPath.length - 1).lastIndexOf('/') + 1, -1) +const calculateTreeNodeChildrenCount = (treeNode) => treeNode.children.length > 0 ? + treeNode.children.reduce((sum, node) => sum + node.hits_count, 0) : + 0 + +const normalizeTreeAggregationResult = (esResult) => { + const result = { + total: esResult.hits.total, + tree: [] + } + + const plainTree = esResult.aggregations.full_name_parts.buckets + //.filter(bucket => getPathType(bucket.key) != 'file') + .map(bucket => ({ + path: bucket.key, + name: getPathName(bucket.key), + parent_path: getParentPath(bucket.key), + depth: getPathDepth(bucket.key), + type: getPathDepth(bucket.key) === 0 ? 'source' : getPathType(bucket.key), + thumb_available: getPathType(bucket.key) === 'file' ? + bucket.thumb_available.buckets[0].key === 1 ? + true : + false : + null, + file_id: getPathType(bucket.key) === 'file' ? + bucket.file_id.buckets[0].key : + null, + content_type: getPathType(bucket.key) === 'file' ? + bucket.content_type.buckets[0].key : + null, + sha256: getPathType(bucket.key) === 'file' ? + bucket.sha256.buckets[0].key : + null, + hits_count: bucket.doc_count, + children: [] + })) + + plainTree + .filter(node => node.depth > 0) + .forEach(node => + plainTree + .filter(treeNode => treeNode.depth === node.depth - 1) + .filter(treeNode => treeNode.path === node.parent_path) + .forEach(treeNode => treeNode.children.push(node))) + + plainTree + .filter(treeNode => treeNode.type != 'file') + .filter(treeNode => treeNode.children.length > 0) + .filter(treeNode => calculateTreeNodeChildrenCount(treeNode) != treeNode.hits_count) + .forEach(treeNode => treeNode.children.push({ + path: `${treeNode.path}...`, + name: '...', + parent_path: treeNode.path, + depth: treeNode.depth + 1, + type: 'mixed', + thumb_available: null, + file_id: null, + content_type: null, + sha256: null, + hits_count: treeNode.hits_count - calculateTreeNodeChildrenCount(treeNode), + children: [] + })) + + return { ...result, tree: plainTree.filter(node => node.depth === 0) } +} + +const normalizeStatsAggregationResult = (esResult) => { + const result = { + total: esResult.hits.total, + summary: {}, + tags: {} + } + + result.summary = { + data: esResult.aggregations.summary + } + + result.extensions = { + total: esResult.hits.total, + data: esResult.aggregations.extensions.buckets + .filter(bucket => bucket.doc_count > MIN_THRESHOLD_EXTENSION * esResult.hits.total) + .map(bucket => ({ + extension: bucket.key, + hits_percent: bucket.doc_count / esResult.hits.total * 100, + hits_count: bucket.doc_count, + size: bucket.size.sum + })) + } + const presentExtensionsHitsCount = result.extensions.data.reduce((sum, bucket) => sum + bucket.hits_count, 0) + if (presentExtensionsHitsCount < esResult.hits.total) { + result.extensions.data.push({ + extension: 'Others', + hits_percent: (esResult.hits.total - presentExtensionsHitsCount) / esResult.hits.total * 100, + hits_count: esResult.hits.total - presentExtensionsHitsCount, + size: 0 + }) + } + + result.tags = { + total: esResult.aggregations.tags.doc_count, + data: esResult.aggregations.tags.names.buckets + .map(bucket => ({ + name: bucket.key, + type: bucket.types.buckets[0].key, + hits_percent: bucket.doc_count / esResult.aggregations.tags.doc_count * 100, + hits_count: bucket.doc_count + })) + } + + return result +} + +export const getShortStats = (esClient) => new Promise((resolve, reject) => + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: EsQueryBuilder.getShortStatsQuery() + }) + .then(result => { + resolve(result) + }) + .catch(err => reject(err)) +) + +export const getTagsStat = (esClient) => new Promise((resolve, reject) => + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TAG_TYPE_NAME, + body: EsQueryBuilder.getTagsStatsQuery() + }) + .then(result => { + resolve(transformTagsStat(result)) + }) + .catch(err => reject(err)) +) + +export const getFilesTreeByQuery = (esClient, request) => new Promise((resolve, reject) => { + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: EsQueryBuilder.getFilesTreeQuery(request) + }) + .then(result => resolve(normalizeTreeAggregationResult(result))) + .catch(err => reject(err)) +}) + +export const getFilesStatsByQuery = (esClient, request, maxItemsToRetrieve) => new Promise((resolve, reject) => { + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: EsQueryBuilder.getFilesStatsQuery(request, maxItemsToRetrieve) + }) + .then(result => resolve(normalizeStatsAggregationResult(result))) + .catch(err => reject(err)) +}) + +export const searchFiles = (esClient, request, from, size) => { + const requests = [ + { index: ES_FILE_INDEX_NAME, type: ES_FILE_TYPE_NAME }, + EsQueryBuilder.getFilesWithHighlightsQuery(request, from * size, size), + { index: ES_FILE_INDEX_NAME, type: ES_FILE_TYPE_NAME }, + EsQueryBuilder.getFilesWithoutHighlightsQuery(request, from * size, size) + ] + + return new Promise((resolve, reject) => + esClient.msearch({ + body: requests + }) + .then(results => { + const result = results.responses + const maxScore = Math.max(result[0].hits.max_score, result[1].hits.max_score) + + const resultHits = normalizeHitsScore(result[0].hits.hits, maxScore) + .concat(normalizeHitsScore(result[1].hits.hits, maxScore)) + .sort((a, b) => b._score - a._score) + .map((hit) => normalizeHitContentHighlights(transformHit(hit))) + .filter((hit) => (hit.content.highlight && + hit.content.highlight.text && + hit.content.highlight.text.length > 0 && + !hit.content.highlight.text.some(text => //.test(text)) && + !hit.meta.highlight && + !hit.content.highlight.author && + request.content != '*' && + request.content != '') + ? false + : true) + + resolve({ + total: result[0].hits.total + result[1].hits.total, + hits: resultHits + }) + }) + .catch(err => reject(err)) + ) +} + +export const getFileHighlightByFileId = (esClient, request, fileId) => new Promise((resolve, reject) => { + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: EsQueryBuilder.getFileHighlightQuery(request, fileId) + }) + .then(result => { + if (result.hits.hits && result.hits.hits.length === 1) { + resolve( + normalizeHitContentHighlights( + transformHit(result.hits.hits[0]) + ) + ) + } + else { + resolve({}) + } + }) + .catch(err => reject(err)) +}) + +export const getFullFileHighlightByFileId = (esClient, request, fileId) => new Promise((resolve, reject) => { + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: EsQueryBuilder.getFullFileHighlightQuery(request, fileId) + }) + .then(result => { + if (result.hits.hits && result.hits.hits.length === 1) { + resolve( + normalizeHitContentHighlights(transformHit(result.hits.hits[0])) + ) + } + else { + resolve({}) + } + }) + .catch(err => reject(err)) +}) + +export const checkIfFileExists = (esClient, fileId) => new Promise((resolve, reject) => { + esClient.get({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + _source: false, + id: fileId + }) + .then(result => { + resolve(result.found) + }) + .catch(err => { + if (err.statusCode == 404) { + resolve(false) + return + } + reject(err) + }) +}) + +export const getFileByFileId = (esClient, fileId, includeChildren = false) => new Promise((resolve, reject) => { + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: { + query: { + bool: { + must: [ + { term: { 'file_id': fileId } } + ], + should: includeChildren ? [ + { + has_child: { + type: 'ambar_file_tag', + query: { + match_all: {} + }, + inner_hits: {} + } + }, + { + has_child: { + type: 'ambar_file_hidden_mark', + query: { + match_all: {} + }, + inner_hits: {} + } + } + ] : [], + minimum_should_match: 0 + } + } + } + }) + .then(result => resolve(result.hits.total > 0 ? normalizeHitContentHighlights(transformHit(result.hits.hits[0])) : null)) + .catch(err => reject(err)) +}) + +export const hideFile = (esClient, fileId) => new Promise((resolve, reject) => { + const hiddenMark = { + id: getHiddenMarkId(fileId), + indexed_datetime: DateTimeService.getCurrentDateTime() + } + + esClient.index({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_HIDDEN_MARK_TYPE_NAME, + parent: fileId, + refresh: true, + id: hiddenMark.id, + body: hiddenMark + }) + .then(res => resolve(res)) + .catch(err => reject(err)) +}) + +export const unHideFile = (esClient, fileId) => new Promise((resolve, reject) => { + const hiddenMarkId = getHiddenMarkId(fileId) + + esClient.delete({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_HIDDEN_MARK_TYPE_NAME, + routing: fileId, + refresh: true, + id: hiddenMarkId + }) + .then(res => resolve(res)) + .catch(err => reject(err)) +}) + +export const indexTag = (esClient, fileId, tag) => new Promise((resolve, reject) => { + tag.indexed_datetime = DateTimeService.getCurrentDateTime() + esClient.index({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TAG_TYPE_NAME, + parent: fileId, + refresh: true, + id: tag.id, + body: tag + }) + .then(res => resolve(res)) + .catch(err => reject(err)) +}) + +export const deleteTag = (esClient, fileId, tagId) => new Promise((resolve, reject) => { + esClient.delete({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TAG_TYPE_NAME, + routing: fileId, + refresh: true, + id: tagId + }) + .then(res => resolve(res)) + .catch(err => reject(err)) +}) + +export const indexLogItem = (esClient, logItem) => { + logItem.indexed_datetime = DateTimeService.getCurrentDateTime() + esClient.index({ + index: ES_LOG_INDEX_NAME, + type: ES_LOG_TYPE_NAME, + body: logItem + }) +} + +export const getLastLogRecords = (esClient, numberOfRecords) => new Promise((resolve, reject) => { + let query = { + from: 0, + size: numberOfRecords, + query: { match_all: {} }, + sort: { created_datetime: { order: 'desc' } } + } + + return esClient.search({ + index: ES_LOG_INDEX_NAME, + type: ES_LOG_TYPE_NAME, + body: query + }) + .then(result => resolve(result.hits.hits.map(hit => hit._source).reverse())) + .catch(err => reject(err)) +}) + +export const getStats = (esClient) => new Promise((resolve, reject) => + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: EsQueryBuilder.getStatsQuery() + }) + .then(result => { + resolve(result) + }) + .catch(err => reject(err)) +) + +const normalizeProcessingStats = (esResponse) => { + const ITEMS_COUNT = 10 + + const procRate = { + hours: [], + days: [], + months: [] + } + + const dates = [] + let dateSpan = ITEMS_COUNT - 1 + while (dateSpan >= 0) { + dates.push(moment().startOf('day').add(-dateSpan, 'days')) + dateSpan-- + } + dates.forEach((date) => { + const dateItem = { + date: date.format('DD.MM.YYYY'), + count: 0, + size: 0 + } + + const esDateBucket = esResponse.aggregations.days.buckets.find((bucket) => (moment(bucket.key).startOf('day').isSame(date))) + if (esDateBucket) { + dateItem.count = esDateBucket.doc_count + dateItem.size = esDateBucket.size.value + } + + procRate.days.push(dateItem) + }) + + const months = [] + let monthsSpan = ITEMS_COUNT - 1 + while (monthsSpan >= 0) { + months.push(moment().startOf('month').add(-monthsSpan, 'months')) + monthsSpan-- + } + months.forEach((month) => { + const monthItem = { + date: month.format('MM.YYYY'), + count: 0, + size: 0 + } + + const esDateBucket = esResponse.aggregations.months.buckets.find((bucket) => (moment(bucket.key).startOf('day').isSame(month))) + if (esDateBucket) { + monthItem.count = esDateBucket.doc_count + monthItem.size = esDateBucket.size.value + } + + procRate.months.push(monthItem) + }) + + return procRate +} + +export const getProcessingStats = (esClient) => new Promise((resolve, reject) => + esClient.search({ + index: ES_FILE_INDEX_NAME, + type: ES_FILE_TYPE_NAME, + body: EsQueryBuilder.getProcessingStatsQuery() + }) + .then(result => { + resolve(normalizeProcessingStats(result)) + }) + .catch(err => reject(err)) +) \ No newline at end of file diff --git a/WebApi/src/services/EsProxy/index.js b/WebApi/src/services/EsProxy/index.js new file mode 100644 index 0000000..2de924d --- /dev/null +++ b/WebApi/src/services/EsProxy/index.js @@ -0,0 +1 @@ +export * from './EsProxy' \ No newline at end of file diff --git a/WebApi/src/services/FileUploader.js b/WebApi/src/services/FileUploader.js new file mode 100644 index 0000000..819aaaf --- /dev/null +++ b/WebApi/src/services/FileUploader.js @@ -0,0 +1,35 @@ +import multer from 'multer' +import ErrorResponse from '../utils/ErrorResponse' + +const MAX_FILE_SIZE_MB = 512 +const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024 + +const upload = multer({ + limits: { + fileSize: MAX_FILE_SIZE_BYTES, + files: 1 + } +}) + +const uploader = (req, res, next) => upload.any() (req, res, err => { + if (err) { + switch (err.code) { + case 'LIMIT_FILE_SIZE': + res.status(400).json(new ErrorResponse(`File is too large (> ${MAX_FILE_SIZE_MB} Mb)`)) + break + default: + res.status(500).json(new ErrorResponse(err.message)) + } + } else { + const files = req.files + + if (!files || files.length === 0 || files.some(f => !f.buffer)) { + res.status(400).json(new ErrorResponse('No files are attached or some attachments are empty')) + return + } + + next() + } +}) + +export default uploader \ No newline at end of file diff --git a/WebApi/src/services/GridFsProxy.js b/WebApi/src/services/GridFsProxy.js new file mode 100644 index 0000000..b57267e --- /dev/null +++ b/WebApi/src/services/GridFsProxy.js @@ -0,0 +1,37 @@ +import GridFs from 'gridfs-stream' +import mongo from 'mongodb' +import { createReadStream } from 'streamifier' + +const createGridFsInstance = (mongoDbInstance) => { + return GridFs(mongoDbInstance, mongo) +} + +export const uploadFile = (mongo, fileName, buffer) => new Promise((resolve, reject) => { + const gfs = createGridFsInstance(mongo) + + const writeStream = gfs.createWriteStream({ filename: fileName, mode: 'w' }) + + writeStream.on('close', (result) => resolve(result)) + writeStream.on('error', (error) => reject(error)) + + createReadStream(buffer).pipe(writeStream) +}) + +export const checkIfFileExists = (mongo, fileName) => new Promise((resolve, reject) => { + const gfs = createGridFsInstance(mongo) + + gfs.exist({ filename: fileName }, (err, found) => { + if (err) { + reject(err) + return + } + + resolve(found) + }) +}) + +export const downloadFile = (mongo, fileName) => { + const gfs = createGridFsInstance(mongo) + const readStream = gfs.createReadStream({ filename: fileName }) + return readStream +} \ No newline at end of file diff --git a/WebApi/src/services/MongoProxy.js b/WebApi/src/services/MongoProxy.js new file mode 100644 index 0000000..597517c --- /dev/null +++ b/WebApi/src/services/MongoProxy.js @@ -0,0 +1,104 @@ +const BUCKET_DATA = 'bucket_data' +const THUMBNAIL_DATA = 'thumbnail_data' +const USER_DATA = 'user_data' + +// BUCKETS +export const getBucketById = (db, bucketId) => new Promise((resolve, reject) => { + db.collection(BUCKET_DATA) + .findOne( + { id: bucketId }, + (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) + +export const createBucket = (db, bucket) => new Promise((resolve, reject) => { + db.collection(BUCKET_DATA) + .insertOne(bucket, (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) +////////////////////////////////////////////////////////////////////////////////////// + +// THUMBNAILS +export const getThumbnailById = (db, thumbId) => new Promise((resolve, reject) => { + db.collection(THUMBNAIL_DATA) + .findOne( + { id: thumbId }, + (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) +////////////////////////////////////////////////////////////////////////////////////// + +// USERS +export const getUserByEmail = (db, email) => new Promise((resolve, reject) => { + db.collection(USER_DATA) + .findOne( + { email: email }, + (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) + +export const createUpdateUser = (db, user) => new Promise((resolve, reject) => { + db.collection(USER_DATA) + .updateOne({ email: user.email }, user, { upsert: true }, (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) + +export const deleteUser = (db, user) => new Promise((resolve, reject) => { + db.collection(USER_DATA) + .deleteOne({ email: user.email }, + null, + (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) + +export const getUsersCount = (db, defaultEmail) => new Promise((resolve, reject) => { + db.collection(USER_DATA) + .count({ + email: { $ne: defaultEmail } + }, + (err, result) => { + if (err) { + reject(err) + return + } + + resolve(result) + }) +}) +////////////////////////////////////////////////////////////////////////////////////// diff --git a/WebApi/src/services/QueueProxy.js b/WebApi/src/services/QueueProxy.js new file mode 100644 index 0000000..d401139 --- /dev/null +++ b/WebApi/src/services/QueueProxy.js @@ -0,0 +1,40 @@ +import amqp from 'amqplib' +import config from '../config' + +export const AMBAR_PIPELINE_EXCHANGE = "AMBAR_PIPELINE_EXCHANGE" + +const getPipelineMessagePriority = (storage, fileName) => new Promise((resolve) => { + const regex = /(\.jp[e]*g$)|(\.png$)|(\.bmp$)|(\.tif[f]*$)|(\.pdf$)/i + const priority = regex.test(fileName) ? 1 : 2 + resolve(priority) +}) + +export const enqueuePipelineMessage = (storage, message) => new Promise((resolve, reject) => { + const fileName = message.meta.short_name + + storage.rabbit.createConfirmChannel() + .then(channel => { + return getPipelineMessagePriority(storage, fileName) + .then(priority => { + channel.publish(AMBAR_PIPELINE_EXCHANGE, '', Buffer.from(JSON.stringify(message)), { priority: priority }) + return channel.waitForConfirms() + .then(() => channel.close()) + }) + }) + .then(() => resolve()) + .catch(err => reject(err)) +}) + +export const initRabbit = new Promise((resolve, reject) => { + amqp.connect(`${config.rabbitHost}?heartbeat=60`) + .then((conn) => { + conn.on('error', (err) => { + //eslint-disable-next-line no-console + console.error('Rabbit error!') + throw err + }) + + resolve(conn) + }) + .catch(err => reject(err)) +}) diff --git a/WebApi/src/services/StorageService.js b/WebApi/src/services/StorageService.js new file mode 100644 index 0000000..a7ba6c6 --- /dev/null +++ b/WebApi/src/services/StorageService.js @@ -0,0 +1,38 @@ +import { MongoClient } from 'mongodb' +import elasticsearch from 'elasticsearch' +import redis from 'redis' +import bluebird from 'bluebird' +import { QueueProxy } from './index.js' +import config from '../config' + +export const initializeStorage = () => new Promise((resolve, reject) => { + const esClient = new elasticsearch.Client({ + host: config.elasticSearchUrl + }) + + bluebird.promisifyAll(redis.RedisClient.prototype) + bluebird.promisifyAll(redis.Multi.prototype) + + const redisClient = redis.createClient({ host: config.redisHost, port: config.redisPort }) + + const mongoPromise = new Promise((resolve, reject) => { + MongoClient.connect(config.mongoDbUrl, (err, db) => { + if (err) { + reject(err) + } + resolve(db) + }) + }) + + Promise.all([mongoPromise, QueueProxy.initRabbit]) + .then(([mongoConnection, rabbitConnection]) => { + const result = { + elasticSearch: esClient, + mongoDb: mongoConnection, + redis: redisClient, + rabbit: rabbitConnection + } + resolve(result) + }) + .catch(err => reject(err)) +}) diff --git a/WebApi/src/services/index.js b/WebApi/src/services/index.js new file mode 100644 index 0000000..19ec987 --- /dev/null +++ b/WebApi/src/services/index.js @@ -0,0 +1,23 @@ +import * as CryptoService from './CryptoService' +import * as EsProxy from './EsProxy/' +import * as MongoProxy from './MongoProxy' +import FileUploader from './FileUploader' +import * as DateTimeService from './DateTimeService' +import * as GridFsProxy from './GridFsProxy' +import * as CacheProxy from './CacheProxy' +import ErrorHandlerService from './ErrorHandlerService' +import * as QueueProxy from './QueueProxy' +import * as StorageService from './StorageService' + +export { + CryptoService, + EsProxy, + MongoProxy, + FileUploader, + DateTimeService, + GridFsProxy, + CacheProxy, + ErrorHandlerService, + QueueProxy, + StorageService +} \ No newline at end of file diff --git a/WebApi/src/utils/ErrorResponse.js b/WebApi/src/utils/ErrorResponse.js new file mode 100644 index 0000000..f6f2197 --- /dev/null +++ b/WebApi/src/utils/ErrorResponse.js @@ -0,0 +1,7 @@ +class ErrorResponse { + constructor(errorMessage) { + this.message = errorMessage.toString() + } +} + +export default ErrorResponse \ No newline at end of file diff --git a/WebApi/src/utils/EsQueryBuilder.js b/WebApi/src/utils/EsQueryBuilder.js new file mode 100644 index 0000000..c5af5de --- /dev/null +++ b/WebApi/src/utils/EsQueryBuilder.js @@ -0,0 +1,477 @@ +const FULL_FILE_FRAGMENT_SIZE = 10 * 1024 * 1024 +const FRAGMENT_SIZE = 500 +const NUMBER_OF_FRAGMENTS = 50 +const PHRASE_LIMIT = 1024 +const LARGE_FILE_SIZE_BYTES = 50000000 +const MAX_TAGS_TO_RETRIEVE = 200 +const MAX_TAGS_TO_RETRIEVE_IN_AGG = 50 + +const ES_FILE_INDEX_NAME = "ambar_file_data" +const ES_FILE_TAG_TYPE_NAME = "ambar_file_tag" +const ES_FILE_HIDDEN_MARK_TYPE_NAME = "ambar_file_hidden_mark" + +/////////////////////////////////////// Index Name ///////////////////////////////////////////////////////// + +export const AMBAR_FILE_INDEX_PREFIX = `${ES_FILE_INDEX_NAME}_` + +/////////////////////////////////////// Tags queries /////////////////////////////////////////////////////// + +export const getTagsStatsQuery = () => ( + { + from: 0, + size: 0, + aggs: { + tags: { + terms: { field: 'name', size: MAX_TAGS_TO_RETRIEVE }, + aggs: { type: { terms: { field: 'type' } } } + } + } + }) + +/////////////////////////////////////// Stats queries /////////////////////////////////////////////////////// + +export const getStatsQuery = () => ( + { + "from": 0, + "size": 0, + "aggs": { + "content_type": { + "terms": { "field": "content.type" }, + "aggs": { + "size": { "stats": { "field": "content.size" } } + } + }, + "proc_rate": { + "date_histogram": { + "field": "indexed_datetime", + "interval": "day" + }, + "aggs": { + "source": { + "terms": { "field": "meta.source_id" } + } + } + }, + "proc_total": { + "stats": { "field": "content.size" } + } + } + } +) + +export const getShortStatsQuery = () => ( + { + "from": 0, + "size": 0, + "aggs": { + "proc_total": { + "stats": { "field": "content.size" } + } + } + } +) + +export const getProcessingStatsQuery = () => ( + { + "from": 0, + "size": 0, + "aggs": { + "hours": { + "date_histogram": { + "field": "indexed_datetime", + "interval": "hour", + "format": "HH dd.MM.yyyy", + "order": { "_key": "desc" } + }, + "aggs": { + "size": { + "sum": { "field": "content.size" } + } + } + }, + "days": { + "date_histogram": { + "field": "indexed_datetime", + "interval": "day", + "format": "dd.MM.yyyy", + "order": { "_key": "desc" } + }, + "aggs": { + "size": { + "sum": { "field": "content.size" } + } + } + }, + "months": { + "date_histogram": { + "field": "indexed_datetime", + "interval": "month", + "format": "MM.yyyy", + "order": { "_key": "desc" } + }, + "aggs": { + "size": { + "sum": { "field": "content.size" } + } + } + } + } + } +) +/////////////////////////////////////// Search queries ////////////////////////////////////////////////////// + +export const getFilesWithHighlightsQuery = (request, from, size) => getFilesQuery(request, from, size, true, false, true) +export const getFilesWithoutHighlightsQuery = (request, from, size) => getFilesQuery(request, from, size, false, true, false) +export const getFileHighlightQuery = (request, fileId) => getFilesQuery(request, 0, 1, false, false, true, fileId) +export const getFullFileHighlightQuery = (request, fileId) => getFilesQuery(request, 0, 1, false, false, true, fileId, true) +export const getFilesTreeQuery = (request) => { + const { mustList } = getBoolSubqueries(request, false, false) + + return { + from: 0, + size: 0, + query: { + bool: { + must: mustList + } + }, + aggs: { + full_name_parts: { + terms: { + field: 'meta.full_name_parts', + size: 200 + }, + aggs: { + file_id: { + terms: { + field: 'file_id', + size: 1 + } + }, + thumb_available: { + terms: { + field: 'content.thumb_available', + size: 1 + } + }, + content_type: { + terms: { + field: 'content.type', + size: 1 + } + }, + sha256: { + terms: { + field: 'sha256', + size: 1 + } + } + } + } + } + } +} +export const getFilesStatsQuery = (request, maxItemsToRetrieve) => { + const { mustList } = getBoolSubqueries(request, false, false) + + return { + from: 0, + size: 0, + query: { + bool: { + must: mustList + } + }, + aggs: { + extensions: { + terms: { field: "meta.extension" }, + aggs: { + size: { stats: { field: "content.size" } } + } + }, + summary: { + stats: { field: "content.size" } + }, + tags: { + children: { + type: ES_FILE_TAG_TYPE_NAME + }, + aggs: { + names: { + terms: { + field: 'name', + size: maxItemsToRetrieve ? maxItemsToRetrieve : MAX_TAGS_TO_RETRIEVE_IN_AGG + }, + aggs: { + types: { + terms: { + field: 'type', + size: 1 + } + } + } + } + } + } + } + } +} + +const isWildcardQuery = (query) => /[*?]/g.test(query) + +const getBoolSubqueries = (queries, onlySmallFiles, onlyLargeFiles, fileId = null) => { + const mustList = [] + const contentShouldList = [] + const tagQueriesList = [] + + if (queries.content && queries.content != '') { + contentShouldList.push({ + simple_query_string: { + query: queries.content, + fields: ['content.text', 'content.author.analyzed', 'meta.source_id.analyzed', 'meta.full_name.analyzed'], + default_operator: 'and' + } + }) + } + + if (fileId && fileId != '') { + mustList.push({ term: { file_id: fileId } }) + } + + if (onlySmallFiles) { + mustList.push({ range: { 'content.size': { lt: LARGE_FILE_SIZE_BYTES } } }) + } + + if (onlyLargeFiles) { + mustList.push({ range: { 'content.size': { gte: LARGE_FILE_SIZE_BYTES } } }) + } + + mustList.push({ term: { 'content.state': 'processed' } }) + + if (queries.name && queries.name != '') { + mustList.push(isWildcardQuery(queries.name) ? { wildcard: { 'meta.full_name': queries.name.toLowerCase() } } : { match: { 'meta.full_name.analyzed': queries.name } }) + } + + if (queries.author && queries.author != '') { + mustList.push(isWildcardQuery(queries.author) ? { wildcard: { 'content.author': queries.author.toLowerCase() } } : { match: { 'content.author.analyzed': queries.author } }) + } + + if (queries.source && queries.source.length > 0) { + const sourceShouldList = queries.source.map(source => (isWildcardQuery(source) ? { wildcard: { 'meta.source_id': source.toLowerCase() } } : { match: { 'meta.source_id.analyzed': source } })) + mustList.push({ + bool: { + should: sourceShouldList, + minimum_should_match: 1 + } + }) + } + + if (queries.size && queries.size.gte) { + mustList.push({ range: { 'content.size': { gte: queries.size.gte } } }) + } + + if (queries.size && queries.size.lte) { + mustList.push({ range: { 'content.size': { lte: queries.size.lte } } }) + } + + if (queries.when && queries.when.gte) { + mustList.push({ range: { 'meta.updated_datetime': { gte: queries.when.gte } } }) + } + + if (queries.when && queries.when.lte) { + mustList.push({ range: { 'meta.updated_datetime': { lte: queries.when.lte } } }) + } + + if (queries.tags && queries.tags.length > 0) { + queries.tags.forEach(tag => { + tagQueriesList.push({ + term: { + name: tag + } + }) + }) + } + + if (tagQueriesList.length > 0) { + tagQueriesList.forEach(tagQuery => { + mustList.push({ + has_child: { + type: ES_FILE_TAG_TYPE_NAME, + query: tagQuery + } + }) + }) + } + + if (contentShouldList.length > 0) { + mustList.push({ + bool: { + should: contentShouldList, + minimum_should_match: 1 + } + }) + } + + if (queries.withoutHiddenMarkOnly) { + mustList.push({ + bool: { + must: [ + { + has_child: { + type: ES_FILE_HIDDEN_MARK_TYPE_NAME, + query: { + match_all: {} + } + } + } + ] + } + }) + } + + if (queries.withHiddenMarkOnly) { + mustList.push({ + bool: { + must_not: [ + { + has_child: { + type: ES_FILE_HIDDEN_MARK_TYPE_NAME, + query: { + match_all: {} + } + } + } + ] + } + }) + } + + return { + mustList, + contentShouldList, + tagQueriesList + } +} + +const getFilesQuery = (queries, from, size, onlySmallFiles, onlyLargeFiles, includeContentHighlight, fileId = null, fullFileHighlight = false) => { + const { mustList, contentShouldList, tagQueriesList } = getBoolSubqueries(queries, onlySmallFiles, onlyLargeFiles, fileId) + + let highlightFields = { + 'content.author': { + pre_tags: [''], + post_tags: [''], + fragment_size: FRAGMENT_SIZE, + number_of_fragments: NUMBER_OF_FRAGMENTS + }, + 'content.author.analyzed': { + pre_tags: [''], + post_tags: [''], + fragment_size: FRAGMENT_SIZE, + number_of_fragments: NUMBER_OF_FRAGMENTS + }, + 'meta.full_name': { + pre_tags: [''], + post_tags: [''], + fragment_size: FRAGMENT_SIZE, + number_of_fragments: NUMBER_OF_FRAGMENTS + }, + 'meta.source_id': { + pre_tags: [''], + post_tags: [''], + fragment_size: FRAGMENT_SIZE, + number_of_fragments: NUMBER_OF_FRAGMENTS + }, + 'meta.full_name.analyzed': { + pre_tags: [''], + post_tags: [''], + fragment_size: FRAGMENT_SIZE, + number_of_fragments: NUMBER_OF_FRAGMENTS + }, + 'meta.source_id.analyzed': { + pre_tags: [''], + post_tags: [''], + fragment_size: FRAGMENT_SIZE, + number_of_fragments: NUMBER_OF_FRAGMENTS + } + } + + if (includeContentHighlight) { + highlightFields = { + ...highlightFields, 'content.text': { + highlight_query: { + bool: { + should: contentShouldList, + minimum_should_match: 1 + } + }, + type: 'fvh', + fragment_size: fullFileHighlight ? FULL_FILE_FRAGMENT_SIZE : FRAGMENT_SIZE, + number_of_fragments: fullFileHighlight ? 1 : NUMBER_OF_FRAGMENTS, + phrase_limit: fullFileHighlight ? undefined : PHRASE_LIMIT, + no_match_size: fullFileHighlight ? FULL_FILE_FRAGMENT_SIZE : FRAGMENT_SIZE + } + } + } + + const resultingQuery = { + from: from, + size: size, + query: { + bool: { + must: mustList, + should: [ + { + has_child: { + type: ES_FILE_TAG_TYPE_NAME, + query: { + match_all: {} + }, + inner_hits: { + from: 0, + size: MAX_TAGS_TO_RETRIEVE, + highlight: { + fields: { + 'name': { + pre_tags: [''], + post_tags: [''], + fragment_size: FRAGMENT_SIZE, + number_of_fragments: NUMBER_OF_FRAGMENTS, + highlight_query: { + bool: { + should: tagQueriesList + } + } + } + }, + require_field_match: true + } + } + } + }, + { + has_child: { + type: ES_FILE_HIDDEN_MARK_TYPE_NAME, + query: { + match_all: {} + }, + inner_hits: { + from: 0, + size: 1 + } + } + } + ], + minimum_should_match: 0 + } + }, + highlight: { + order: 'score', + fields: highlightFields, + require_field_match: true + } + } + + return resultingQuery +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/WebApi/src/utils/MetaBuilder.js b/WebApi/src/utils/MetaBuilder.js new file mode 100644 index 0000000..f0db09f --- /dev/null +++ b/WebApi/src/utils/MetaBuilder.js @@ -0,0 +1,36 @@ +import { CryptoService, DateTimeService } from '../services' + +const FILE_EXTENSION_REGEX = /(?:\.([^.]+))?$/ + +const generateMetaId = (source_id, full_name, created_datetime, updated_datetime) => { + return CryptoService.getSha256(`${source_id}${full_name}${created_datetime}${updated_datetime}`) +} + +export const buildShortMeta = (shortName, sourceId) => { + + const short_name = shortName.toLowerCase() + const full_name = `//${sourceId.toLowerCase()}/${shortName.toLowerCase()}` + const source_id = sourceId + let extension = '' + let calculatedExtension = FILE_EXTENSION_REGEX.exec(short_name) + if ((calculatedExtension) && (calculatedExtension.length > 0)) { + extension = calculatedExtension[0] + } + const created_datetime = DateTimeService.getCurrentDateTime() + const updated_datetime = DateTimeService.getCurrentDateTime() + const extra = [] + + const meta = { + id: generateMetaId(source_id, full_name, created_datetime, updated_datetime), + short_name: short_name, + full_name: full_name, + source_id: source_id, + extension: extension, + created_datetime: created_datetime, + updated_datetime: updated_datetime, + extra: extra, + indexed_datetime: DateTimeService.getCurrentDateTime() + } + + return meta +} \ No newline at end of file diff --git a/WebApi/src/utils/QueryParser.js b/WebApi/src/utils/QueryParser.js new file mode 100644 index 0000000..6f4b3f1 --- /dev/null +++ b/WebApi/src/utils/QueryParser.js @@ -0,0 +1,125 @@ +import { DateTimeService } from '../services' + +const FILE_NAME_QUERY = /((^|\s)filename:)([^\s]*)/im + +const SOURCE_QUERY = /((^|\s)source:)([a-zA-Z0-9\-,*]*)/im + +const SIZE_GTE_QUERY = /((^|\s)size>[=]{0,1})([0-9]*)([k|m]{0,1})/im +const SIZE_LTE_QUERY = /((^|\s)size<[=]{0,1})([0-9]*)([k|m]{0,1})/im + +const AUTHOR_QUERY = /((^|\s)author:)([^\s]*)/im + +const WHEN_QUERY = /((^|\s)when:)((today)|(yesterday)|(thisweek)|(thismonth)|(thisyear))/im + +const TAGS_QUERY = /((^|\s)tags:)([^\s]*)/im + +const SHOW_QUERY = /((^|\s)show:)((removed)|(all))/im + +const normalizeString = (string) => string.replace(/[\s]+/gi, ' ').trim() + +const multiplySize = (size, multiplier) => { + if (multiplier.toLowerCase() === 'k') { + return size * 1024 + } + if (multiplier.toLowerCase() === 'm') { + return size * 1024 * 1024 + } + return size +} + +export const parseEsStringQuery = (query) => { + var content = '' + var name = '' + var source = [] + var author = '' + var size = { gte: null, lte: null } + var when = { gte: null, lte: null } + var tags = [] + + content = normalizeString(query.replace(FILE_NAME_QUERY, '').replace(SOURCE_QUERY, '').replace(SIZE_GTE_QUERY, '').replace(SIZE_LTE_QUERY, '').replace(AUTHOR_QUERY, '').replace(WHEN_QUERY, '').replace(TAGS_QUERY, '').replace(SHOW_QUERY, '')) + + var authorMatch = query.match(AUTHOR_QUERY) + if (authorMatch && authorMatch[3]) { + author = authorMatch[3] + } + + var nameMatch = query.match(FILE_NAME_QUERY) + if (nameMatch && nameMatch[3]) { + name = nameMatch[3] + } + + var sourceMatch = query.match(SOURCE_QUERY) + if (sourceMatch && sourceMatch[3]) { + source = sourceMatch[3].split(',') + } + + var tagsMatch = query.match(TAGS_QUERY) + if (tagsMatch && tagsMatch[3]) { + tags = tagsMatch[3].split(',') + } + + var whenMatch = query.match(WHEN_QUERY) + if (whenMatch && whenMatch[3]) { + switch (whenMatch[3].toLowerCase()) { + case 'today': { + when.gte = DateTimeService.getStartOfToday() + } break + case 'yesterday': { + when.gte = DateTimeService.getStartOfYesterday() + when.lte = DateTimeService.getStartOfToday() + } break + case 'thisweek': { + when.gte = DateTimeService.getStartOfThisWeek() + } break + case 'thismonth': { + when.gte = DateTimeService.getStartOfThisMonth() + } break + case 'thisyear': { + when.gte = DateTimeService.getStartOfThisYear() + } break + } + } + + var sizeGteMatch = query.match(SIZE_GTE_QUERY) + if (sizeGteMatch && sizeGteMatch[3]) { + size.gte = parseInt(sizeGteMatch[3]) + if (sizeGteMatch[4] && sizeGteMatch[4] !== '') { + size.gte = multiplySize(size.gte, sizeGteMatch[4]) + } + } + + var sizeLteMatch = query.match(SIZE_LTE_QUERY) + if (sizeLteMatch && sizeLteMatch[3]) { + size.lte = parseInt(sizeLteMatch[3]) + if (sizeLteMatch[4] && sizeLteMatch[4] !== '') { + size.lte = multiplySize(size.lte, sizeLteMatch[4]) + } + } + + let withoutHiddenMarkOnly = false + let withHiddenMarkOnly = true + + var showMatch = query.match(SHOW_QUERY) + if (showMatch && showMatch[3]) { + switch (showMatch[3].toLowerCase()) { + case 'all': { + withHiddenMarkOnly = false + } break + case 'removed': { + withoutHiddenMarkOnly = true + withHiddenMarkOnly = false + } break + } + } + return { + content: content, + name: name, + source: source, + size: size, + author: author, + when: when, + tags: tags, + withoutHiddenMarkOnly: withoutHiddenMarkOnly, + withHiddenMarkOnly: withHiddenMarkOnly + } +} \ No newline at end of file diff --git a/WebApi/yarn.lock b/WebApi/yarn.lock new file mode 100644 index 0000000..4f16ebd --- /dev/null +++ b/WebApi/yarn.lock @@ -0,0 +1,3291 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +JSONStream@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.2.1.tgz#32aa5790e799481083b49b4b7fa94e23bae69bf9" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^5.5.0: + version "5.5.3" + resolved "http://192.168.1.113:4873/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" + +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "http://192.168.1.113:4873/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + +ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "http://192.168.1.113:4873/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +amqplib@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.5.1.tgz#7cccfebabe56c2e984ea7a2243f7cefe6fbfc6cf" + dependencies: + bitsyntax "~0.0.4" + bluebird "^3.4.6" + buffer-more-ints "0.0.2" + readable-stream "1.x >=1.1.9" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + +ansi-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "http://192.168.1.113:4873/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "http://192.168.1.113:4873/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +append-field@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/append-field/-/append-field-0.1.0.tgz#6ddc58fa083c7bc545d3c5995b2830cc2366d44a" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@~2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-cli@^6.9.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.18.0.tgz#92117f341add9dead90f6fa7d0a97c0cc08ec186" + dependencies: + babel-core "^6.18.0" + babel-polyfill "^6.16.0" + babel-register "^6.18.0" + babel-runtime "^6.9.0" + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.0.0" + glob "^5.0.5" + lodash "^4.2.0" + output-file-sync "^1.1.0" + path-is-absolute "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + v8flags "^2.0.10" + optionalDependencies: + chokidar "^1.0.0" + +babel-code-frame@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^2.0.0" + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "http://192.168.1.113:4873/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.18.0, babel-core@^6.9.0: + version "6.18.2" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.18.2.tgz#d8bb14dd6986fa4f3566a26ceda3964fa0e04e5b" + dependencies: + babel-code-frame "^6.16.0" + babel-generator "^6.18.0" + babel-helpers "^6.16.0" + babel-messages "^6.8.0" + babel-register "^6.18.0" + babel-runtime "^6.9.1" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-eslint@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.1.tgz#8a6a884f085aa7060af69cfc77341c2f99370fb2" + dependencies: + babel-code-frame "^6.16.0" + babel-traverse "^6.15.0" + babel-types "^6.15.0" + babylon "^6.13.0" + lodash.pickby "^4.6.0" + +babel-generator@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.19.0.tgz#9b2f244204777a3d6810ec127c673c87b349fac5" + dependencies: + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-bindify-decorators@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.18.0.tgz#fc00c573676a6e702fffa00019580892ec8780a5" + dependencies: + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-builder-binary-assignment-operator-visitor@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.18.0.tgz#8ae814989f7a53682152e3401a04fabd0bb333a6" + dependencies: + babel-helper-explode-assignable-expression "^6.18.0" + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-call-delegate@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.18.0.tgz#05b14aafa430884b034097ef29e9f067ea4133bd" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-define-map@^6.18.0, babel-helper-define-map@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.18.0.tgz#8d6c85dc7fbb4c19be3de40474d18e97c3676ec2" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.18.0.tgz#14b8e8c2d03ad735d4b20f1840b24cd1f65239fe" + dependencies: + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-explode-class@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.18.0.tgz#c44f76f4fa23b9c5d607cbac5d4115e7a76f62cb" + dependencies: + babel-helper-bindify-decorators "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6" + dependencies: + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-get-function-arity@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-hoist-variables@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.18.0.tgz#a835b5ab8b46d6de9babefae4d98ea41e866b82a" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-optimise-call-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.18.0.tgz#9261d0299ee1a4f08a6dd28b7b7c777348fd8f0f" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-regex@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.18.0.tgz#ae0ebfd77de86cb2f1af258e2cc20b5fe893ecc6" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.16.0, babel-helper-remap-async-to-generator@^6.16.2: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.18.0.tgz#336cdf3cab650bb191b02fc16a3708e7be7f9ce5" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.18.0.tgz#28ec69877be4144dbd64f4cc3a337e89f29a924e" + dependencies: + babel-helper-optimise-call-expression "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helpers@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3" + dependencies: + babel-runtime "^6.0.0" + babel-template "^6.16.0" + +babel-messages@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-check-es2015-constants@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz#dbf024c32ed37bfda8dee1e76da02386a8d26fe7" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-remove-code@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-code/-/babel-plugin-remove-code-0.0.6.tgz#742b6e8e6429133ead20abc3511dd4a2eebe5085" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-do-expressions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-function-bind@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.3.13: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.13.0.tgz#2b84b7d53dd744f94ff1fad7669406274b23f541" + +babel-plugin-transform-async-generator-functions@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.17.0.tgz#d0b5a2b2f0940f2b245fa20a00519ed7bc6cae54" + dependencies: + babel-helper-remap-async-to-generator "^6.16.2" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-async-to-generator@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz#19ec36cb1486b59f9f468adfa42ce13908ca2999" + dependencies: + babel-helper-remap-async-to-generator "^6.16.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-class-constructor-call@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.18.0.tgz#80855e38a1ab47b8c6c647f8ea1bcd2c00ca3aae" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-class-properties@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.19.0.tgz#1274b349abaadc835164e2004f4a2444a2788d5f" + dependencies: + babel-helper-function-name "^6.18.0" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.9.1" + babel-template "^6.15.0" + +babel-plugin-transform-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.13.0.tgz#82d65c1470ae83e2d13eebecb0a1c2476d62da9d" + dependencies: + babel-helper-define-map "^6.8.0" + babel-helper-explode-class "^6.8.0" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-types "^6.13.0" + +babel-plugin-transform-do-expressions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.8.0.tgz#fda692af339835cc255bb7544efb8f7c1306c273" + dependencies: + babel-plugin-syntax-do-expressions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-arrow-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz#ed95d629c4b5a71ae29682b998f70d9833eb366d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoping@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.18.0.tgz#3bfdcfec318d46df22525cdea88f1978813653af" + dependencies: + babel-runtime "^6.9.0" + babel-template "^6.15.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.18.0.tgz#ffe7a17321bf83e494dcda0ae3fc72df48ffd1d9" + dependencies: + babel-helper-define-map "^6.18.0" + babel-helper-function-name "^6.18.0" + babel-helper-optimise-call-expression "^6.18.0" + babel-helper-replace-supers "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-template "^6.14.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-computed-properties@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz#f51010fd61b3bd7b6b60a5fdfd307bb7a5279870" + dependencies: + babel-helper-define-map "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-destructuring@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533" + dependencies: + babel-runtime "^6.9.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz#fd8f7f7171fc108cc1c70c3164b9f15a81c25f7d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-for-of@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.18.0.tgz#4c517504db64bf8cfc119a6b8f177211f2028a70" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-function-name@^6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz#8c135b17dbd064e5bba56ec511baaee2fca82719" + dependencies: + babel-helper-function-name "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.9.0" + +babel-plugin-transform-es2015-literals@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz#50aa2e5c7958fc2ab25d74ec117e0cc98f046468" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-modules-amd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.18.0.tgz#49a054cbb762bdf9ae2d8a807076cfade6141e40" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.18.0.tgz#c15ae5bb11b32a0abdcc98a5837baa4ee8d67bcc" + dependencies: + babel-plugin-transform-strict-mode "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.19.0.tgz#50438136eba74527efa00a5b0fefaf1dc4071da6" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.11.6" + babel-template "^6.14.0" + +babel-plugin-transform-es2015-modules-umd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.18.0.tgz#23351770ece5c1f8e83ed67cb1d7992884491e50" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-object-super@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz#1b858740a5a4400887c23dcff6f4d56eea4a24c5" + dependencies: + babel-helper-replace-supers "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-parameters@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.18.0.tgz#9b2cfe238c549f1635ba27fc1daa858be70608b1" + dependencies: + babel-helper-call-delegate "^6.18.0" + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.9.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.18.0.tgz#e2ede3b7df47bf980151926534d1dd0cbea58f43" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-spread@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz#0217f737e3b821fa5a669f187c6ed59205f05e9c" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-sticky-regex@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz#e73d300a440a35d5c64f5c2a344dc236e3df47be" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-template-literals@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz#86eb876d0a2c635da4ec048b4f7de9dfc897e66b" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.18.0.tgz#0b14c48629c90ff47a0650077f6aa699bee35798" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-unicode-regex@^6.3.13: + version "6.11.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz#6298ceabaad88d50a3f4f392d8de997260f6ef2c" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.8.0.tgz#db25742e9339eade676ca9acec46f955599a68a4" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.8.0" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-export-extensions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.8.0.tgz#fa80ff655b636549431bfd38f6b817bd82e47f5b" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-function-bind@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.8.0.tgz#e7f334ce69f50d28fe850a822eaaab9fa4f4d821" + dependencies: + babel-plugin-syntax-function-bind "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-object-rest-spread@^6.16.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.19.0.tgz#f6ac428ee3cb4c6aa00943ed1422ce813603b34c" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-regenerator@^6.16.0: + version "6.16.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.16.1.tgz#a75de6b048a14154aae14b0122756c5bed392f59" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.16.0" + private "~0.1.5" + +babel-plugin-transform-strict-mode@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.18.0.tgz#df7cf2991fe046f44163dcd110d5ca43bc652b9d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-polyfill@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422" + dependencies: + babel-runtime "^6.9.1" + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-preset-es2015@^6.9.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.18.0.tgz#b8c70df84ec948c43dcf2bf770e988eb7da88312" + dependencies: + babel-plugin-check-es2015-constants "^6.3.13" + babel-plugin-transform-es2015-arrow-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoped-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoping "^6.18.0" + babel-plugin-transform-es2015-classes "^6.18.0" + babel-plugin-transform-es2015-computed-properties "^6.3.13" + babel-plugin-transform-es2015-destructuring "^6.18.0" + babel-plugin-transform-es2015-duplicate-keys "^6.6.0" + babel-plugin-transform-es2015-for-of "^6.18.0" + babel-plugin-transform-es2015-function-name "^6.9.0" + babel-plugin-transform-es2015-literals "^6.3.13" + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-plugin-transform-es2015-modules-systemjs "^6.18.0" + babel-plugin-transform-es2015-modules-umd "^6.18.0" + babel-plugin-transform-es2015-object-super "^6.3.13" + babel-plugin-transform-es2015-parameters "^6.18.0" + babel-plugin-transform-es2015-shorthand-properties "^6.18.0" + babel-plugin-transform-es2015-spread "^6.3.13" + babel-plugin-transform-es2015-sticky-regex "^6.3.13" + babel-plugin-transform-es2015-template-literals "^6.6.0" + babel-plugin-transform-es2015-typeof-symbol "^6.18.0" + babel-plugin-transform-es2015-unicode-regex "^6.3.13" + babel-plugin-transform-regenerator "^6.16.0" + +babel-preset-stage-0@^6.5.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.16.0.tgz#f5a263c420532fd57491f1a7315b3036e428f823" + dependencies: + babel-plugin-transform-do-expressions "^6.3.13" + babel-plugin-transform-function-bind "^6.3.13" + babel-preset-stage-1 "^6.16.0" + +babel-preset-stage-1@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.16.0.tgz#9d31fbbdae7b17c549fd3ac93e3cf6902695e479" + dependencies: + babel-plugin-transform-class-constructor-call "^6.3.13" + babel-plugin-transform-export-extensions "^6.3.13" + babel-preset-stage-2 "^6.16.0" + +babel-preset-stage-2@^6.16.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.18.0.tgz#9eb7bf9a8e91c68260d5ba7500493caaada4b5b5" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.18.0" + babel-plugin-transform-decorators "^6.13.0" + babel-preset-stage-3 "^6.17.0" + +babel-preset-stage-3@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.17.0.tgz#b6638e46db6e91e3f889013d8ce143917c685e39" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.3.13" + babel-plugin-transform-async-generator-functions "^6.17.0" + babel-plugin-transform-async-to-generator "^6.16.0" + babel-plugin-transform-exponentiation-operator "^6.3.13" + babel-plugin-transform-object-rest-spread "^6.16.0" + +babel-register@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68" + dependencies: + babel-core "^6.18.0" + babel-runtime "^6.11.6" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.9.0, babel-runtime@^6.9.1: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" + dependencies: + babel-runtime "^6.9.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.19.0.tgz#68363fb821e26247d52a519a84b2ceab8df4f55a" + dependencies: + babel-code-frame "^6.16.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.13.0, babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.8.0, babel-types@^6.9.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.19.0.tgz#8db2972dbed01f1192a8b602ba1e1e4c516240b9" + dependencies: + babel-runtime "^6.9.1" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.13.0: + version "6.14.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815" + +balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +bitsyntax@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.0.4.tgz#eb10cc6f82b8c490e3e85698f07e83d46e0cba82" + dependencies: + buffer-more-ints "0.0.2" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.4.6, bluebird@^3.4.7: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + +body-parser@^1.13.3: + version "1.15.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67" + dependencies: + bytes "2.4.0" + content-type "~1.0.2" + debug "~2.2.0" + depd "~1.1.0" + http-errors "~1.5.0" + iconv-lite "0.4.13" + on-finished "~2.3.0" + qs "6.2.0" + raw-body "~2.1.7" + type-is "~1.6.13" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "http://192.168.1.113:4873/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +bson@~0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/bson/-/bson-0.5.7.tgz#0d11fe0936c1fee029e11f7063f5d0ab2422ea3e" + +buffer-from@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + +buffer-more-ints@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +busboy@^0.2.11: + version "0.2.13" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.13.tgz#90fc4f6a3967d815616fc976bfa8e56aed0c58b6" + dependencies: + dicer "0.2.5" + readable-stream "1.1.x" + +bytes@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.1.0: + version "2.3.2" + resolved "http://192.168.1.113:4873/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "http://192.168.1.113:4873/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + +chokidar@^1.0.0, chokidar@^1.4.3: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +circular-json@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "http://192.168.1.113:4873/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.9.0: + version "1.9.1" + resolved "http://192.168.1.113:4873/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "http://192.168.1.113:4873/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.8.1, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +compressible@~2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + dependencies: + mime-db ">= 1.24.0 < 2" + +compression@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + dependencies: + accepts "~1.3.3" + bytes "2.3.0" + compressible "~2.0.8" + debug "~2.2.0" + on-headers "~1.0.1" + vary "~1.1.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +concat-stream@^1.6.0: + version "1.6.2" + resolved "http://192.168.1.113:4873/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" + dependencies: + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + object-assign "^4.0.1" + os-tmpdir "^1.0.0" + osenv "^0.1.0" + uuid "^2.0.1" + write-file-atomic "^1.1.2" + xdg-basedir "^2.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +content-disposition@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@^2.7.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.1.tgz#6181aa56abb45a2825be3304703747ae4e9d2383" + dependencies: + vary "^1" + +cron-parser@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.3.1.tgz#2c01573ac1cbaf938136b727b640de61a29b5117" + dependencies: + is-nan "^1.2.1" + moment-timezone "^0.5.0" + +cross-spawn@^5.1.0: + version "5.1.0" + resolved "http://192.168.1.113:4873/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@^2.1.1, debug@^2.2.0, debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@^3.1.0: + version "3.1.0" + resolved "http://192.168.1.113:4873/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +define-properties@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +dicer@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" + dependencies: + readable-stream "1.1.x" + streamsearch "0.1.2" + +doctrine@^2.1.0: + version "2.1.0" + resolved "http://192.168.1.113:4873/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + dependencies: + esutils "^2.0.2" + +double-ended-queue@^2.1.0-0: + version "2.1.0-0" + resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +duplexify@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604" + dependencies: + end-of-stream "1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +elasticsearch@^12.1.3: + version "12.1.3" + resolved "https://registry.yarnpkg.com/elasticsearch/-/elasticsearch-12.1.3.tgz#5108e67ae5d83e5e7f30d3d294fd7017df0e3771" + dependencies: + chalk "^1.0.0" + forever-agent "^0.6.0" + lodash "^4.12.0" + promise "^7.1.1" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +end-of-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e" + dependencies: + once "~1.3.0" + +es6-promise@3.2.1, es6-promise@^3.0.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.2.1.tgz#ec56233868032909207170c39448e24449dd1fc4" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +eslint-plugin-babel@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-3.3.0.tgz#2f494aedcf6f4aa4e75b9155980837bc1fbde193" + +eslint-plugin-promise@^3.3.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.4.0.tgz#6ba9048c2df57be77d036e0c68918bc9b4fc4195" + +eslint-scope@^3.7.1: + version "3.7.1" + resolved "http://192.168.1.113:4873/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.19.1: + version "4.19.1" + resolved "http://192.168.1.113:4873/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +espree@^3.5.4: + version "3.5.4" + resolved "http://192.168.1.113:4873/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + dependencies: + acorn "^5.5.0" + acorn-jsx "^3.0.0" + +esprima@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esquery@^1.0.0: + version "1.0.1" + resolved "http://192.168.1.113:4873/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.0.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-stream@~3.3.0: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express@^4.13.3: + version "4.14.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.1" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "~2.2.0" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + finalhandler "0.5.0" + fresh "0.3.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.2" + qs "6.2.0" + range-parser "~1.2.0" + send "0.14.1" + serve-static "~1.11.1" + type-is "~1.6.13" + utils-merge "1.0.0" + vary "~1.1.0" + +extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +external-editor@^2.0.4: + version "2.2.0" + resolved "http://192.168.1.113:4873/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "http://192.168.1.113:4873/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" + +figures@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + statuses "~1.3.0" + unpipe "~1.0.0" + +flat-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" + dependencies: + circular-json "^0.3.0" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flushwritable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/flushwritable/-/flushwritable-1.0.0.tgz#3e328d8fde412ad47e738e3be750b4d290043498" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@^0.6.0, forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fresh@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +from@~0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc" + +fs-readdir-recursive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.15" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.15.tgz#fa63f590f3c2ad91275e4972a6cea545fb0aae44" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "http://192.168.1.113:4873/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^5.0.5: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.3, glob@^7.0.5: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2: + version "7.1.2" + resolved "http://192.168.1.113:4873/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.0.1: + version "11.4.0" + resolved "http://192.168.1.113:4873/globals/-/globals-11.4.0.tgz#b85c793349561c16076a3c13549238a27945f1bc" + +globals@^9.0.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" + dependencies: + duplexify "^3.2.0" + infinity-agent "^2.0.0" + is-redirect "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + nested-error-stacks "^1.0.0" + object-assign "^3.0.0" + prepend-http "^1.0.0" + read-all-stream "^3.0.0" + timed-out "^2.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.4: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +gridfs-stream@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/gridfs-stream/-/gridfs-stream-1.1.1.tgz#3dd3a100ec2021a181282f6eb46709636074df89" + dependencies: + flushwritable "^1.0.0" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "http://192.168.1.113:4873/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +iconv-lite@^0.4.17: + version "0.4.21" + resolved "http://192.168.1.113:4873/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" + dependencies: + safer-buffer "^2.1.0" + +ignore-by-default@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +ignore@^3.3.3: + version "3.3.7" + resolved "http://192.168.1.113:4873/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +infinity-agent@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inquirer@^3.0.6: + version "3.3.0" + resolved "http://192.168.1.113:4873/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +invariant@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +ipaddr.js@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-nan@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.2.1.tgz#9faf65b6fb6db24b7f5c0628475ea71f988401e2" + dependencies: + define-properties "^1.1.1" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-promise@^2.1.0: + version "2.1.0" + resolved "http://192.168.1.113:4873/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-tokens@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "http://192.168.1.113:4873/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.9.1: + version "3.11.0" + resolved "http://192.168.1.113:4873/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "http://192.168.1.113:4873/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "http://192.168.1.113:4873/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonparse@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.2.0.tgz#5c0c5685107160e72fe7489bddea0b44c2bc67bd" + +jsonpointer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +kind-of@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" + dependencies: + is-buffer "^1.0.2" + +latest-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" + dependencies: + package-json "^1.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.assign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.defaults@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" + dependencies: + lodash.assign "^3.0.0" + lodash.restparam "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.pickby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash@^4.12.0, lodash@^4.13.1, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" + +lodash@^4.17.4: + version "4.17.5" + resolved "http://192.168.1.113:4873/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + +loose-envify@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8" + dependencies: + js-tokens "^2.0.0" + +lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lru-cache@^4.0.1: + version "4.1.2" + resolved "http://192.168.1.113:4873/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +"mime-db@>= 1.24.0 < 2", mime-db@~1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" + +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" + dependencies: + mime-db "~1.25.0" + +mime@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "http://192.168.1.113:4873/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimatch@^3.0.4: + version "3.0.4" + resolved "http://192.168.1.113:4873/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment-timezone@^0.5.0: + version "0.5.10" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.10.tgz#3766249c2d317d08f07d896d3033c26f87c4ae2b" + dependencies: + moment ">= 2.6.0" + +"moment@>= 2.6.0", moment@^2.15.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +mongodb-core@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.0.14.tgz#4e8743b87343d169a7622535edbd47dcacd790be" + dependencies: + bson "~0.5.7" + require_optional "~1.0.0" + +mongodb@^2.2.10: + version "2.2.12" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.12.tgz#2a86f10228f911e9d6fefdbd7d922188d7b730f9" + dependencies: + es6-promise "3.2.1" + mongodb-core "2.0.14" + readable-stream "2.1.5" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +multer@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.2.0.tgz#5be1a45259fb04d2753d33c7c2a1caf5224705a2" + dependencies: + append-field "^0.1.0" + busboy "^0.2.11" + concat-stream "^1.5.0" + mkdirp "^0.5.1" + object-assign "^3.0.0" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + +mute-stream@0.0.7: + version "0.0.7" + resolved "http://192.168.1.113:4873/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +nested-error-stacks@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf" + dependencies: + inherits "~2.0.1" + +node-pre-gyp@^0.6.29: + version "0.6.32" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +nodemon@^1.9.2: + version "1.11.0" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c" + dependencies: + chokidar "^1.4.3" + debug "^2.2.0" + es6-promise "^3.0.2" + ignore-by-default "^1.0.0" + lodash.defaults "^3.1.2" + minimatch "^3.0.0" + ps-tree "^1.0.1" + touch "1.0.0" + undefsafe "0.0.3" + update-notifier "0.5.0" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +npmlog@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.1.tgz#d14f503b4cd79710375553004ba96e6662fbc0b8" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-finished@^2.3.0, on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "http://192.168.1.113:4873/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.3.tgz#83cf05c6d6458fc4d5ac6362ea325d92f2754217" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +package-json@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0" + dependencies: + got "^3.2.0" + registry-url "^3.0.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pluralize@^7.0.0: + version "7.0.0" + resolved "http://192.168.1.113:4873/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6, private@~0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +progress@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + +promise@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" + dependencies: + asap "~2.0.3" + +proxy-addr@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.1.1" + +ps-tree@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + dependencies: + event-stream "~3.3.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "http://192.168.1.113:4873/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@~2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" + +rc@^1.0.1, rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +read-all-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" + dependencies: + pinkie-promise "^2.0.0" + readable-stream "^2.0.0" + +readable-stream@1.1.x, "readable-stream@1.x >=1.1.9": + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@2.1.5, readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@^2.2.2: + version "2.3.6" + resolved "http://192.168.1.113:4873/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +redis-commands@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.0.tgz#4307d8094aee1315829ab6729b37b99f62365d63" + +redis-parser@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.3.0.tgz#313a47965e49ee35ab3a86c93388b403d76237f6" + +redis@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/redis/-/redis-2.6.3.tgz#84305b92553c6a1f09c7c47c30b11ace7dbb7ad4" + dependencies: + double-ended-queue "^2.1.0-0" + redis-commands "^1.2.0" + redis-parser "^2.0.0" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.9.5: + version "0.9.6" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpp@^1.0.1: + version "1.1.0" + resolved "http://192.168.1.113:4873/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +registry-url@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + +request@^2.76.0, request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +require-uncached@^1.0.3: + version "1.0.3" + resolved "http://192.168.1.113:4873/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +require_optional@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.0.tgz#52a86137a849728eb60a55533617f8f914f59abf" + dependencies: + resolve-from "^2.0.0" + semver "^5.1.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + +resource-router-middleware@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/resource-router-middleware/-/resource-router-middleware-0.5.1.tgz#cceba87013a73e6daf55e612b7e8eb10ffa9381a" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "http://192.168.1.113:4873/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +run-async@^2.2.0: + version "2.3.0" + resolved "http://192.168.1.113:4873/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "http://192.168.1.113:4873/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "http://192.168.1.113:4873/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "http://192.168.1.113:4873/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +safer-buffer@^2.1.0: + version "2.1.2" + resolved "http://192.168.1.113:4873/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +semver@^5.0.3, semver@^5.1.0, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +semver@^5.3.0: + version "5.5.0" + resolved "http://192.168.1.113:4873/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +send@0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.5.0" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.0" + +serve-static@~1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.14.1" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "http://192.168.1.113:4873/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@1.0.0: + version "1.0.0" + resolved "http://192.168.1.113:4873/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +source-map-support@^0.4.2: + version "0.4.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.6.tgz#32552aa64b458392a85eab3b0b5ee61527167aeb" + dependencies: + source-map "^0.5.3" + +source-map@^0.5.0, source-map@^0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +"statuses@>= 1.3.1 < 2", statuses@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +streamifier@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" + +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + +string-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" + dependencies: + strip-ansi "^3.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "http://192.168.1.113:4873/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "http://192.168.1.113:4873/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "http://192.168.1.113:4873/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "http://192.168.1.113:4873/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.3.0: + version "5.3.0" + resolved "http://192.168.1.113:4873/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" + dependencies: + has-flag "^3.0.0" + +table@4.0.2: + version "4.0.2" + resolved "http://192.168.1.113:4873/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" + +tmp@^0.0.33: + version "0.0.33" + resolved "http://192.168.1.113:4873/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +touch@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de" + dependencies: + nopt "~1.0.10" + +tough-cookie@>=2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" + dependencies: + punycode "^1.4.1" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.4" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.4.tgz#8c9dbfb52795686f166cd2023794bcf103d13c2b" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-is@^1.6.4, type-is@~1.6.13: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@^0.0.6, typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +undefsafe@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +update-notifier@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc" + dependencies: + chalk "^1.0.0" + configstore "^1.0.0" + is-npm "^1.0.0" + latest-version "^1.0.0" + repeating "^1.1.2" + semver-diff "^2.0.0" + string-length "^1.0.0" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +v8flags@^2.0.10: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + +vary@^1, vary@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +which@^1.2.9: + version "1.3.0" + resolved "http://192.168.1.113:4873/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + dependencies: + graceful-fs "^4.1.2" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +xdg-basedir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + dependencies: + os-homedir "^1.0.0" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yallist@^2.1.2: + version "2.1.2" + resolved "http://192.168.1.113:4873/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6a04d55 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,159 @@ +version: "2.1" +networks: + internal_network: +services: + db: + restart: always + networks: + - internal_network + image: ambar/ambar-mongodb:latest + environment: + - cacheSizeGB=2 + volumes: + - ${dataPath}/db:/data/db + expose: + - "27017" + ports: + - "27017:27017" + es: + restart: always + networks: + - internal_network + image: ambar/ambar-es:latest + expose: + - "9200" + ports: + - "9200:9200" + environment: + - cluster.name=ambar-es + - ES_JAVA_OPTS=-Xms2g -Xmx2g + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 + hard: 65536 + cap_add: + - IPC_LOCK + volumes: + - ${dataPath}/es:/usr/share/elasticsearch/data + rabbit: + restart: always + networks: + - internal_network + image: ambar/ambar-rabbit:latest + hostname: rabbit + expose: + - "15672" + - "5672" + ports: + - "15672:15672" + - "5672:5672" + volumes: + - ${dataPath}/rabbit:/var/lib/rabbitmq + redis: + restart: always + sysctls: + - net.core.somaxconn=1024 + networks: + - internal_network + image: ambar/ambar-redis:latest + expose: + - "6379" + ports: + - "6379:6379" + serviceapi: + depends_on: + redis: + condition: service_healthy + rabbit: + condition: service_healthy + es: + condition: service_healthy + db: + condition: service_healthy + restart: always + networks: + - internal_network + image: ambar/ambar-serviceapi:latest + expose: + - "8081" + ports: + - "8081:8081" + environment: + - mongoDbUrl=mongodb://db:27017/ambar_data + - elasticSearchUrl=http://es:9200 + - redisHost=redis + - redisPort=6379 + - rabbitHost=amqp://rabbit + - langAnalyzer=${langAnalyzer} + volumes: + - /var/run/docker.sock:/var/run/docker.sock + webapi: + depends_on: + serviceapi: + condition: service_healthy + restart: always + networks: + - internal_network + image: ambar/ambar-webapi:latest + expose: + - "8080" + ports: + - "8080:8080" + environment: + - analyticsToken=cda4b0bb11a1f32aed7564b08c455992 + - uiLang=en + - mongoDbUrl=mongodb://db:27017/ambar_data + - elasticSearchUrl=http://es:9200 + - redisHost=redis + - redisPort=6379 + - serviceApiUrl=http://serviceapi:8081 + - rabbitHost=amqp://rabbit + volumes: + - /var/run/docker.sock:/var/run/docker.sock + frontend: + depends_on: + webapi: + condition: service_healthy + image: ambar/ambar-frontend:latest + restart: always + networks: + - internal_network + ports: + - "80:80" + expose: + - "80" + environment: + - api=http://${ambarHostIpAddress}:8080 + pipeline0: + depends_on: + serviceapi: + condition: service_healthy + image: ambar/ambar-pipeline:latest + restart: always + networks: + - internal_network + environment: + - id=0 + - api_url=http://serviceapi:8081 + - rabbit_host=amqp://rabbit + crawler0: + depends_on: + serviceapi: + condition: service_healthy + image: ambar/ambar-local-crawler + restart: always + networks: + - internal_network + environment: + - apiUrl=http://serviceapi:8081 + - crawlPath=/usr/data + - name=${crawlerName} + volumes: + - ${pathToCrawl}:/usr/data + + + + \ No newline at end of file