diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 1320b9a3..00000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["@babel/preset-env"] -} diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c6fb6646..2b834108 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -17,4 +17,4 @@ values = [bumpversion:part:build] -[bumpversion:file:setup.py] +[bumpversion:file:idr_gallery/version.py] diff --git a/.gitignore b/.gitignore index 48dceaee..1d600a5f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ dist omero_gallery.egg-info .omero -node_modules/ diff --git a/MANIFEST.in b/MANIFEST.in index 05099bdd..fdd6eb63 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include README.rst include LICENSE -recursive-include omero_gallery * \ No newline at end of file +recursive-include idr_gallery * diff --git a/README.rst b/README.rst index 29cb9d9e..59f0c080 100644 --- a/README.rst +++ b/README.rst @@ -4,8 +4,8 @@ .. image:: https://badge.fury.io/py/omero-gallery.svg :target: https://badge.fury.io/py/omero-gallery -OMERO.gallery -============= +IDR gallery +=========== This is an OMERO.web plugin (Django app) that provides a 'gallery' view of images in OMERO, ideal for public browsing without editing. @@ -25,65 +25,21 @@ Install the app using `pip `_: :: - $ pip install -U omero-gallery + $ pip install -U idr-gallery Add gallery custom app to your installed web apps: :: - $ omero config append omero.web.apps '"omero_gallery"' + $ omero config append omero.web.apps '"idr_gallery"' Now restart OMERO.web as normal. -OMERO.gallery overview -====================== - -This application supports 2 alternative views of your data in OMERO, which can -be chosen and customised via config settings: - -* Default UI (no config): Browse `Group > Project > Dataset > Image` -* Categories UI: Show categories of interest. Allow filtering by map annotations. - -For both views, public access can be enabled -`as described here `_, -otherwise users will see the standard web login screen. -Once logged-in (as a regular user or public user), the data displayed will -include all data accessible to that user via the normal OMERO permissions. - - -Default UI ----------- - -This view supports minimal functionality required for browsing the hierarchy -from Groups -> Projects -> Datasets -> Images. Screen/Plate/Well data is -not supported in this UI. - -The home page will display all the available groups that the user can access, with a random -thumbnail from each group. The number of Projects, Datasets and Images within each group -will also be displayed. - -.. image:: https://ome.github.io/omero-gallery/images/gallery.png - - -On browsing into a group, the Projects and 'orphaned' Datasets will be shown in a similar layout. - -.. image:: https://ome.github.io/omero-gallery/images/show_group.png - -Projects are shown with 5 thumbnails from each Dataset. Clicking 'All Images' will load all the remaining thumbnails -from a chosen Dataset (or you can browse to the Dataset itself by clicking the Dataset name link). - -.. image:: https://ome.github.io/omero-gallery/images/show_project.png - -Clicking a thumbnail will take you directly to the full image viewer. - -.. image:: https://ome.github.io/omero-gallery/images/webgateway_viewer.png - - -Categories UI -------------- +IDR.gallery overview +==================== -This view was originally developed for use in the IDR and can be seen at +This UI was developed for use in the IDR and can be seen at https://idr.openmicroscopy.org/. In the IDR, a "Study" is a Project or Screen and they are annotated with Key-Value data in the form of Map Annotations, for example ``Study Type: 3D-tracking``. @@ -98,8 +54,8 @@ https://github.com/ome/omero-mapr/ is installed then you can: * Find Studies containing Images that match queries on their Map Annotations. -Configuring the Categories UI ------------------------------ +Configuring the UI +------------------ **omero.web.gallery.category_queries:** To enable the Categories UI, you must set ``omero.web.gallery.category_queries``. @@ -181,16 +137,6 @@ these will be shown in a dropdown menu:: **omero.web.gallery.favicon:** Set a URL to a favicon to use for the browser. -**omero.web.gallery.subheading_html:** -Set some HTML to show as a sub-heading on the home page, within a

tag:: - - $ omero config set omero.web.gallery.subheading_html "This is an image gallery using OMERO." - -**omero.web.gallery.footer_html:** -Set some HTML to show as a footer on each page:: - - $ omero config set omero.web.gallery.footer_html "Blog" - **omero.web.gallery.study_short_name:** This specifies a short name for Screen or Project to show above the study Image in the categories or search page, instead of the default 'Project: 123'. @@ -211,6 +157,7 @@ like: ``idr0001-graml-sysgro/screenA``:: Release process --------------- +- occasionally update `totalImages` and other fallback counts in loadStudyStats() - review and update the [CHANGELOG](https://github.com/ome/omero-gallery/blob/master/CHANGELOG.md) - run ``bumpversion release`` to remove the dev suffix and create a signed tag - run ``bumpversion --no-tag patch`` to bump the version to the next dev suffix @@ -220,9 +167,9 @@ Release process License ------- -OMERO.gallery is released under the AGPL. +`idr_gallery`` is released under the AGPL. Copyright --------- -2016-2021, The Open Microscopy Environment +2016-2022, The Open Microscopy Environment diff --git a/idr_gallery/__init__.py b/idr_gallery/__init__.py new file mode 100644 index 00000000..e27e1686 --- /dev/null +++ b/idr_gallery/__init__.py @@ -0,0 +1 @@ +default_app_config = 'idr_gallery.apps.GalleryAppConfig' diff --git a/omero_gallery/apps.py b/idr_gallery/apps.py similarity index 89% rename from omero_gallery/apps.py rename to idr_gallery/apps.py index 747ae501..baa74387 100644 --- a/omero_gallery/apps.py +++ b/idr_gallery/apps.py @@ -3,7 +3,7 @@ # # # -# Copyright (c) 2016 University of Dundee. +# Copyright (c) 2016-2022 University of Dundee. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -28,5 +28,5 @@ class GalleryAppConfig(AppConfig): - name = "omero_gallery" - label = "gallery" + name = "idr_gallery" + label = "idr_gallery" diff --git a/idr_gallery/data/background_images.py b/idr_gallery/data/background_images.py new file mode 100644 index 00000000..cbd84ed5 --- /dev/null +++ b/idr_gallery/data/background_images.py @@ -0,0 +1,120 @@ + +IDR_IMAGES = [ + { + "src": "webclient/render_image/13965767/294/0/", + "title": "idr0124 Esteban: Heart morphogenesis", + "image_id": 13965767, + "thumbnail": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8KCwkMEQ8SEhEPERATFhwXExQaFRARGCEYGhwdHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCABgAGADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD4yHJwKsxWrHBf5R15q9penNOrMFG1eXkY4VR7n+laNlqemabdOYrX7bIMGJ2UcN6YOeM/Wulwp0Y80/el/Knb73br5a97HRTo31k7Lv8A5Lr+QzS9Ea6ikfzra2WP7zTPjb9R2/Gp9/hmyJDvc37gYxG21c/Xj+tPZLrUbhIdQBALbk0+3IDEnqzH+E9+efpUkkMdgI0n0SCOMNlt4LO3tmqUsRVWj5VtZaeXTX5v7zvUIQXux+crv8Nl6Mr2+t6QZwr6ChiAwvzbmJ9/X0r0G1udOsbE3Nta2liyKFnhCAMpIHYHg+tcxpGk6XdXNpqVnE0MMEuZw+Cu0Andk8DtXK65qSzaxPNZ5EG87ATnPPWudXc3z9O/fz2OqliJYJKdSKlfbbtv/XmvT0S6nsrq5RgsTsSCRjOPb6f/AFq5/U9JsJbh5g4iRm4CqODn068+tYumau0CNzhm55Xp61ag1QzvM7TLEzZKkrnoOPp0FdcW0krN2XT/AIDv951wxWDrpKaV+1v+GN+9QCCaAWNqtvGgbZHGMjjk5xwR6nrmuS1eGyeMqkGy5DEvjt/9atHUdcYRItqw81/v87gDjGcViSM7uxYl26uxPJrqwlGEqcnPWCej6t/Pdvr0S+ZxZvVoVZKFLV/hbf8AryMyaJojzyvZh0NR10NtZG/LBuEjQb26Ac8fjWVq9hJp135EhzlQw4x1rDH4H6vJuGsfy0v/AF56a7njyw81T9rb3TSvNRtYrOSx02GTMwCyTO3LDPQL2zU9rY3OlXgiLQrdMgYzZDCBeuQfXHf8BWfpEbx7r3af3bBIzjjef8B/StSeOG2eKxuGkRnKtct12gdFFcUY8see+rOmEnNcz0fTol/X/BNaxvIbezFxCohcP+628GT1Zj1PfisjVbq4vSzyTl3Zj8vOF+ldFJpiNZqrPsDgeWF5GP8AZqC30GBQJJHeUg/MM4XPccfrXq4KWHpcyqN822ltL7vV779NvM3q4fETaitkciYbswmIzMEPJQNx+IpscMcLDeNzdSOvH9K7SexsgGQ2sagdVwMkUps4oLUwwxxwiRucdfzPtSlXwtGf7qm+bu3f8OVa+v3Gf1GcnaUl+JxasCAAoBx271BIxibK4xnkVdnVYru5QD5UkIHFUrkbzhRzn8MVvim5YOnWekvu/rY4EmpOI5J4lTO3k9QKt20wij3uOQcjiqKWxI5Jz9OKszNsjRXVcEbuBg/jSo1a0VzVlZJaaaX7tAot7HV6ZCILExgCRpcPIoGDkjoMe1Zfj63SOCxm37pHDISTk4XABP61Y0G/nLRm6kP2MHYDtHyntVHxyG8y3B2/ImDgEZJJ+b8a8+pGfvSd7vfbovx6u/kfT42pSllvuLsvT/hyqk9sbm3tomcQRMAGPUknlsVs6JYNrPjyCznwyvcFpd/9xfmOfwHSuWgGydQ+QDxnrXb+FVkk1rVZbEATLpckka5Clmwudp7nr0rnmv3V+qv/AJ6/1/wPKwa+sVEmuq08tf0R6XbeV4h027RbQW8cjulpeyopI2/KNo7jNcfoWh6jpun3FpqFo8EzO7BnU5IzjI9QcZGKteAoNTFoZ9Kvxd3VqUJtCchkZdxwcgrgn25FdjoGoW/iIvHqNn5N1Yv5Nxb7io8tj/rBnoeOBz0PqK87DVakajjO73ta19nff8Pw6H1ChDFqFSaalZ2ts+/lddtGeR+FrxU1K7F+8rhYS23cPn57g+nJx7Vau5I1jmuJXwg5XB9PT37VX+J6w6P4uSfSz5eU3AjHJyQTjtn0rLj1aS4tMbirvNudgAM9+vrmvpY0niMVGlGyu0rWel/013fr1Pn5VfqnNQqbwvr3/Ez543jlbzOXb94zDnGaaVVYWZzt2kYUjqPrVjyi9xh+N7YAAyevYe1blposUJSS4dJ5nPAz8o9h6/WvZzDkwcmnG0ldRi+i1XM+uu+urWuidjzqNCVb4durMK00++vctFEEjAzufv8AhUepWNxZAee6sr57eldnCCmBIiqR82DweOtc54t8yWUHCrGEIU568814ccVWrycpSb3dtlor7eh04jB0aFK6d2WPCl1FOYobjYqomEyOp/xrX8ZaULzQ5LmPbvhUyljxlR6/hjiuJ0a9mtXZF5ikK7hj0OR9K9SjWC88GX0ttcRSr9ncScnIbafX/PNc9OLlDe9/V+dvvvs9U32O/BVI4rCzoN62/Lt/SPK0VZEY54+nSui8D6vb6VrFtPeQLK0WQjMfuqykH+f51zSgh8jGQe/SrXL7lb5JAPT8eK9WjGjjk6Uo2qW2f2v+D2/q3h0K1TDTVWHRo9j+Hekvb67dahYwH+z7uMOhA+YHk7Mjtnn8qXxg8/hjUZbzR45jPegyzrIFmUDHG0E54JHqBnvXk1jqeo6fG9us0hhkHzqHbB+uD+orrtP8WeVp9tDeQxXVrG+VeT55kXup9sYw3tXizyyrg6yqSWkXs9LeT0fZd07dT6jCZphqlL2bTj1vfZ+Xlr6r8Tz3Wb671G/kubx2eVjznsKqxSvGTtPB6j1r1Dxb4b0bU9Lg1LRnEZmVnjHl7Ux1wW7Htk8djXmV1by28rRyKVIODkYwfQ+hrN1XOTqRevXuvu6draWttsfOYvC1aE7yd79e5fXWpY3DQ29vD+68tti/f5zk5zz71r2Pi9oYkR7KJpAxLSOS27PYj09hjPfNcqiMxwBk1raXot1c3Ee6CSRNw3KnUgnHXtXRTliK3M0r9W2lp5t9PvHQxNfn91/16f5HoNjc2erWQmj+WVFCshx8rH+IHHOf/rVk+LtJuZpImEZyP3brnBB989/Udq6/RPDraXpcri1MqqCx4GSQOgPQn0rP8PJrOrTTDXbOe2VWZjNPnkEn5QOpYcfgKqvj6NHE80LWad1u/K6euqu7b2a0uetXg5RVKtpNrp+H9fgY/hrwtazIYLtCjdWcngKBk4H4da6G9sV8P/D66S4K/vo3KbU5JbgAn6Ec+1dBDp9rG3kuzRzKu7L42567QOvTHrXN/F2/itPDK2EcrGSecFl3cFUHXA49B+JrP2zk0k3Z73XTutbeWlttdtOn2FLC4eU+XVJq78/z/wCCeVRgSZVyAp74pZHx8j5eJDlR2+tV0nDqBkRuOp7N/hVgOxCpL90j5ePevUjVw+PSjL3Z9z5hOUE+XVBDP1VwSo6E8kf41YgaRCstuWDbhjacZycf5FQBIuRvJzyQDU+cglTtAx06Yr3sJh6tSk6eJnGWmnV26t9Ha3XfRPTQy5uWV4o6rwf4kay1BbS+xFabWimiVMKSTwdvQHPXHBrS8b6PbWNrBfxwi4hHKtvBJXOcFT1A9OMc4rgEcOWVGO85+h+ld/4P19b3Q5dCvL2G0uo8SW00w3ISDna/r6fSvmcyy72fLjMK9+z+9euuqfqkfQ4HG/WL0Kz1W233dv63ucamlSSbrq3h2wtkqxwq9+OvHQjHtW74e1KTTjHdXMMs0Ij2qEYDAzzk9R046d6v2/hbU7ye5kMUdnAVUi5ivAYZAD0GOo9jjFdFGvg+w1FWvNXilkljSIwgtsDDjdhcgciscPm1KdGVOdFNPezS1+eifpp08i6GEcZc9+Xze2vqlf8A4O+mujpviDTb21hMLqXJISOTICN1IPb9aknvHlV/s8allJJcNhc9MYPJ4I/Oqsup+GbW2lhklgQxgZVowp9cgEjFVdQ1KztLIalK0MMMm3Db92V9P/re9c9avU524ycYrXXV7W6q2vdddXpt7Lxt42502uq/Hv8An+BOsjiYPlAEKhmUElieOnJ/CvMvibqK3WtTQo6SRwExIygc888jqM5rsb7xVb22lxzpDLa3EsbvGSmcLnC+wLcnnouK8kvpfMmPOcVlQ5lGpWqXu9Frpru/Oy0/7e+/wc1xjdNU1K99X+n+e3QiqWO4mjAUOSo/hPI/KoqKyPATa2NKK4juW8uT9wzfdKnCZ7ZB6VPFuUkN1GVxmscVeilM4B3KHUYIJxu7ce9exlWZPC11Kev6Fv8AeRae4uRHI3P3R8uPWpRNG0Shwwkzy2eP/wBdQlv4XX8xQRG24j5OOldlJ1KU5ToSThL7L/rcV9LNamrealO1qtvIy3kBAzvG1lx6N1qpE2mkcm7Df3QyjB9elUwpU8OOnIqaMQGYSy/MioXYdMnHT865MTQpNOoo8vdf5Neq3X+RqqsptX/r79Tu7Sx0y30f7WkQkdgm3c2XLenP68cVptBa3djbTX7Wy/YpjO3G5XPZQCThc4z615tAup3yK0SiC2RiQVOyNT3Oe5qzPqxtrX7Hbzb4RHhgV435yXHfPT8q8N0JVZaPRdey/wA/6XQ9KGMhBXcNLfeQeJtUF3dytCZNjOWBdyzMT1Y5+g+g4rCp0jl3JNNrepNSdlstF6HkVajqScmf/9k=" + }, + { + "light": True, + "src": "webgateway/render_image_region/13461816/0/0/?tile=3,2,4,1024,512", + "title": "idr0096 Tratwal: Marrowquant", + "image_id": 13461816, + }, + { + "src": "webgateway/render_image_region/9846152/45/0/?tile=4,0,0,1024,512", + "title": "idr0048 Abdeladim: Chroms", + "image_id": 9846152, + }, + { + "light": True, + "src": "webgateway/render_image_region/13383922/0/0/?region=412,1224,1536,1024", + "title": "idr0043 Uhlen: Human Protein Atlas", + "image_id": 13383922, + }, + { + "src": "webclient/render_image/4990991/0/0/?c=1|144:2250$0000FF,-2|972:2528$FFFFFF,3|126:3456$FF0000,4|131:2749$00FF00", + "title": "idr0050 Springer: Cyto-skeletal systems", + "image_id": 4990991, + }, + { + "src": "webgateway/render_image/9846154/268/0/?region=1024,0,2048,1024&c=1|4283:12901$FF00FF,2|1278:8356$FFFF00", + "title": "idr0085 Walsh: MF-HREM", + "image_id": 9846154, + }, + { + "src": "webclient/render_image/9753804/0/0/", + "title": "idr0056 Stojic: Long noncoding RNA", + "image_id": 9753804, + }, + { + "src": "webgateway/render_image/9836841/0/0/", + "title": "idr0077 Valuchova: Flower lightsheet", + "image_id": 9836841, + }, +] + +CELL_IMAGES = [ + { + "src": "webgateway/render_image/13417268/34/0/?c=1|5000:13880$FF0000,2|10353:50528$00FF00,3|14416:36737$0000FF", + "title": "idr0107 Morgan: HEI10", + "image_id": 13417268, + }, + { + "src": "webgateway/render_image/12570400/0/0/?c=1|91:1391$fire.lut", + "title": "idr0093 Mueller: Genome-wide siRNA screen", + "image_id": 12570400, + }, + { + "src": "webclient/render_image/4991918/0/0/?c=1|28:178$00FF00,3|22:110$FF0000", + "title": "idr0050 Springer: Cyto-skeletal systems", + "image_id": 4991918, + }, + { + "light": True, + "src": "webgateway/render_image/9846137/92/0/?c=1|85:153$hilo.lut&m=c", + "title": "idr0086 Miron: Chromatin micrographs", + "image_id": 9846137, + }, + { + "src": "webgateway/render_image/3005394/0/0/", + "title": "idr0028 Pascual-Vargas: Rho GTPases", + "image_id": 3005394, + }, + { + "src": "webclient/render_image/9753804/0/0/", + "title": "idr0056 Stojic: Long noncoding RNA", + "image_id": 9753804, + }, + { + "src": "webclient/render_image/3231645/0/0/?c=1|464:8509$FF0000,2|518:21105$00FF00,3|519:19845$0000FF", + "title": "idr0033 Rohban: Cell painting", + "image_id": 3231645, + }, +] + +TISSUE_IMAGES = [ + { + "light": True, + "src": "webgateway/render_image_region/13461816/0/0/?tile=3,2,4,1024,512", + "title": "idr0096 Tratwal: Marrowquant", + "image_id": 13461816, + }, + { + "src": "webgateway/render_image_region/8343616/0/0/?region=2048,6072,2024,1024&c=1|0:105$red_hot.lut&m=c", + "title": "idr0066 Voigt: Meso SPIM", + "image_id": 8343616, + }, + { + "src": "webgateway/render_image_region/9846152/45/0/?tile=4,0,0,1024,512", + "title": "idr0048 Abdeladim: Chroms", + "image_id": 9846152, + }, + { + "light": True, + "src": "webgateway/render_image_region/13383922/0/0/?region=412,1224,1536,1024", + "title": "idr0043 Uhlen: Human Protein Atlas", + "image_id": 13383922, + }, + { + "src": "webgateway/render_image/9846154/268/0/?region=1024,0,2048,1024&c=1|4283:12901$FF00FF,2|1278:8356$FFFF00", + "title": "idr0085 Walsh: MF-HREM", + "image_id": 9846154, + }, + { + "src": "webgateway/render_image/9836841/0/0/", + "title": "idr0077 Valuchova: Flower lightsheet", + "image_id": 9836841, + } +] diff --git a/idr_gallery/data/tabs.py b/idr_gallery/data/tabs.py new file mode 100644 index 00000000..5535b8f0 --- /dev/null +++ b/idr_gallery/data/tabs.py @@ -0,0 +1,34 @@ +TABS = [ + { + "title": "Exploring IDR", + "text": "", + "videos": [ + { + "id": "N9Den172mHo", + "title": "From publication to IDR", + "text": "Find a specific IDR study from a publication. View images and Regions of Interest (ROIs) in IDR. Explore study metadata.", + }, + { + "id": "gjVZut7fL4E", + "title": "From gene to phenotypes", + "text": "Query images by gene. Explore retrieved images and metadata, including associated phenotypes. View images in context of a plate.", + }, + { + "id": "rG-qAHZl-p0", + "title": "From compound to analytics", + "text": "Query images by compound. Find SARS-CoV-2 dataset. Explore images in relation to analytical data submitted by authors.", + }, + ], + }, + { + "title": "Analyze Data", + "text": "

The IDR server is built with OMERO, allowing access to all image data and metadata via an open API in Python, R, Java, MATLAB and REST/JSON. See the OMERO API guide for more information.

For examples of analysis tools working with OMERO to access and analyze data, see the analysis tools guide.

", + "videos": [ + { + "id": "2qeJbudXnp4", + "title": "Compound analysis: SARS-CoV-2", + "text": "Build analysis environment. Access metadata and images. Calculate IC50 and download. Explore dose-response curves.", + } + ], + }, +] diff --git a/omero_gallery/gallery_settings.py b/idr_gallery/gallery_settings.py similarity index 54% rename from omero_gallery/gallery_settings.py rename to idr_gallery/gallery_settings.py index 4c79a614..67992f96 100644 --- a/omero_gallery/gallery_settings.py +++ b/idr_gallery/gallery_settings.py @@ -31,14 +31,24 @@ ["BASE_URL", None, str_slash, - ("Base URL to use for JSON AJAX requests." - " e.g. 'https://demo.openmicroscopy.org'." + ("Base URL to use for non-gallery JSON AJAX requests." + " e.g. 'https://idr.openmicroscopy.org/'." " This allows data to be loaded from another OMERO server." " The default behaviour is to use the current server.")], + "omero.web.gallery.gallery_index": + ["GALLERY_INDEX", + None, + str_slash, + ("Base gallery URL to use for gallery JSON AJAX requests." + " e.g. 'https://idr.openmicroscopy.org/' is gallery index on IDR." + " This allows data to be loaded from another OMERO server, e.g. run" + " locally or on test server, but load data from IDR." + " Default behaviour is to use current server idr_gallery_index")], + "omero.web.gallery.category_queries": ["CATEGORY_QUERIES", - ('{}'), + ('{"others":{ "label": "Others", "query": "LAST200:date", "index": 10 },"lightsheet":{"label":"Light-sheet imaging","index":0,"query":"Imaging Method:light sheet fluorescence microscopy OR Imaging Method:light sheet fluorescence microscopy, SPIM"},"infection":{"label":"Infection studies","index":1,"query":"Study Type:infection"},"timelapse":{"label":"Time-lapse imaging","index":2,"query":"Study Type:time OR Study Type:5D OR Study Type:3D-tracking"},"lightsheet":{"label":"Light sheet fluorescence microscopy","index":3,"query":"Imaging Method: light sheet fluorescence microscopy OR Imaging Method: light sheet fluorescence microscopy, SPIM"},"proteinlocalization":{"label":"Protein localization studies","index":4,"query":"Study Type:protein localization"},"histology":{"label":"Digital pathology imaging","index":5,"query":"Study Type:histology"},"yeast":{"label":"Yeast studies","index":6,"query":"Organism: Saccharomyces cerevisiae OR Organism:Schizosaccharomyces pombe"},"humancellscreen":{"label":"High-content screening (human)","index":7,"query":"Organism:Homo sapiens AND Study Type:high content screen"}}'), json.loads, ("If this is configured then the gallery Home Page shows a list" " of categories containing Projects and Screens that match the" @@ -51,7 +61,7 @@ "omero.web.gallery.filter_keys": ["FILTER_KEYS", - ('[]'), + ('[{"label": "Name (IDR number)", "value": "Name" }, "Imaging Method", "License", "Organism", "Publication Authors", "Publication Title", "Screen Technology Type", "Screen Type", "Study Type"]'), json.loads, ("If this is configured then we allow filtering of Screens and" " Projects by Key:Value pairs linked to them. This list allows us" @@ -60,7 +70,7 @@ "omero.web.gallery.filter_mapr_keys": ["FILTER_MAPR_KEYS", - ('[]'), + ('["antibody","cellline","compound","gene","phenotype","sirna"]'), json.loads, ("If this is configured then we allow filtering of Screens and" " Projects by OMERO.mapr. This is a list of mapr_config IDs, such" @@ -78,7 +88,7 @@ "omero.web.gallery.super_categories": ["SUPER_CATEGORIES", - ('{}'), + ('{"cell": {"label": "Cell - IDR","title": "Welcome to Cell-IDR","query": "Sample Type:cell"},"tissue": {"label": "Tissue - IDR","title": "Welcome to Tissue-IDR","query": "Sample Type:tissue"}}'), json.loads, ("Optional config to provide top-level categories, similar to" " category_queries, using the same config format and 'query' syntax." @@ -87,16 +97,12 @@ " can be used for page title, otherwise the 'label' is used.")], "omero.web.gallery.title": - ["GALLERY_TITLE", "OMERO.gallery", str, + ["GALLERY_TITLE", "IDR: Image Data Resource", str, "Page for gallery, shown when category_queries is set."], - "omero.web.gallery.heading": - ["GALLERY_HEADING", "Welcome to OMERO.gallery", str, - "Main heading on the home page shown when category_queries is set."], - "omero.web.gallery.top_right_links": ["TOP_RIGHT_LINKS", - ('[]'), + ('[{"text":"About","href":"https://idr.openmicroscopy.org/about/index.html","submenu":[{"text":"Overview","href":"https://idr.openmicroscopy.org/about/index.html"},{"text":"Published studies","href":"https://idr.openmicroscopy.org/about/studies.html"},{"text":"Linked resources","href":"https://idr.openmicroscopy.org/about/linked-resources.html"},{"text":"API Access","href":"https://idr.openmicroscopy.org/about/api.html"},{"text":"Data download","href":"https://idr.openmicroscopy.org/about/download.html"},{"text":"Image Tools Resource (ITR)","href":"https://idr.openmicroscopy.org/about/itr.html"},{"text":"Analysis Environments","href":"https://idr.openmicroscopy.org/about/analysis-environments.html"},{"text":"Deployment","href":"https://idr.openmicroscopy.org/about/deployment.html"},{"text":"FAQ","href":"https://idr.openmicroscopy.org/about/faq/"}]},{"text":"Submissions","href":"https://idr.openmicroscopy.org/about/submission.html","submenu":[{"text":"Overview","href":"https://idr.openmicroscopy.org/about/submission.html"},{"text":"Screens","href":"https://idr.openmicroscopy.org/about/screens.html"},{"text":"Experiments","href":"https://idr.openmicroscopy.org/about/experiments.html"}]}]'), json.loads, ("List of {'text':'Text','href':'www.url'} links for top-right of" " page. If a link contains 'submenu':[ ] with more links," @@ -104,38 +110,25 @@ "omero.web.gallery.top_left_logo": ["TOP_LEFT_LOGO", - ('{}'), + ('{"src": "https://idr.openmicroscopy.org/about/img/logos/logo-idr.svg","href": "/"}'), json.loads, ("Logo image and link. e.g." " {'src':'url.png','href':'www.url', 'alt':'Image alt text'}" " href can be URL name for reverse(url_name). If href is omitted," - " it will default to 'webgallery_index'")], - - "omero.web.gallery.footer_html": - ["FOOTER_HTML", - (''), - str, - ("HTML to go in the footer. If this is set to 'IDR' then" - " we show the footer for the IDR site.")], - - "omero.web.gallery.subheading_html": - ["SUBHEADING_HTML", - (''), - str, - ("HTML to show as a sub-heading, within a <p> tag.")], + " it will default to 'idr_gallery_index'")], "omero.web.gallery.favicon": ["FAVICON", - (''), + ("https://idr.openmicroscopy.org/about/img/logos/favicon-idr.ico"), str, ("URL to favicon.")], "omero.web.gallery.study_short_name": ["STUDY_SHORT_NAME", - ('[]'), + ('[{"key": "Name", "regex": "^(.*?)-.*?(.)$", "template": "$1$2"}]'), json.loads, ("Gets a short name for Screen or Project to show above the" - " study Image in the categories or search page, instead of" + " study Image in the search page, instead of" " the default 'Project: 123'. The list allows us" " to try multiple methods, using the first that works. Each object" " in the list has e.g. {'key': 'Name'}. The 'key' can be Name," @@ -143,6 +136,13 @@ " If a 'regex' and 'template' are specified, we try" " name.replace(regex, template).")], + "omero.web.gallery.idr_studies_url": + ["IDR_STUDIES_URL", + 'https://raw.githubusercontent.com/IDR/idr.openmicroscopy.org/master/_data/studies.tsv', + str, + "URL to IDR studies as a tsv table" + ], + } process_custom_settings(sys.modules[__name__], 'GALLERY_SETTINGS_MAPPING') diff --git a/omero_gallery/settings.py b/idr_gallery/settings.py similarity index 69% rename from omero_gallery/settings.py rename to idr_gallery/settings.py index 906117eb..fd9adf15 100644 --- a/omero_gallery/settings.py +++ b/idr_gallery/settings.py @@ -5,5 +5,5 @@ # We can directly manipulate the settings # E.g. link to the 'top links' in webclient page header -# 'webgallery_index' is name in urls.py -# settings.TOP_LINKS.append(["Gallery", "webgallery_index"]) +# 'idr_gallery_index' is name in urls.py +# settings.TOP_LINKS.append(["Gallery", "idr_gallery_index"]) diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css.map b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css.map similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css.map rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.css.map diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.min.css b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.min.css similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.min.css rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap-theme.min.css diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css.map b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css.map similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css.map rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.css.map diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.min.css b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.min.css similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.min.css rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/css/bootstrap.min.css diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.eot b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.eot rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.eot diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.svg b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.svg rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.svg diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.ttf b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.ttf rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.ttf diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.woff b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.woff rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/fonts/glyphicons-halflings-regular.woff diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.js b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.js similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.js rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.js diff --git a/omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.min.js b/idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.min.js similarity index 100% rename from omero_gallery/static/gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.min.js rename to idr_gallery/static/idr_gallery/3rdparty/bootstrap-3.1.1/js/bootstrap.min.js diff --git a/omero_gallery/static/gallery/3rdparty/foundation/foundation.min.css b/idr_gallery/static/idr_gallery/3rdparty/foundation/foundation.min.css similarity index 100% rename from omero_gallery/static/gallery/3rdparty/foundation/foundation.min.css rename to idr_gallery/static/idr_gallery/3rdparty/foundation/foundation.min.css diff --git a/omero_gallery/static/gallery/3rdparty/foundation/foundation.min.js b/idr_gallery/static/idr_gallery/3rdparty/foundation/foundation.min.js similarity index 100% rename from omero_gallery/static/gallery/3rdparty/foundation/foundation.min.js rename to idr_gallery/static/idr_gallery/3rdparty/foundation/foundation.min.js diff --git a/idr_gallery/static/idr_gallery/autocomplete.js b/idr_gallery/static/idr_gallery/autocomplete.js new file mode 100644 index 00000000..999342eb --- /dev/null +++ b/idr_gallery/static/idr_gallery/autocomplete.js @@ -0,0 +1,153 @@ + +// ------ AUTO-COMPLETE ------------------- + +document.getElementById('maprConfig').onchange = (event) => { + document.getElementById('maprQuery').value = ''; + let value = event.target.value.replace('mapr_', ''); + let placeholder = `Type to filter values...`; + if (mapr_settings[value]) { + placeholder = `Type ${mapr_settings[value]['default'][0]}...`; + } + document.getElementById('maprQuery').placeholder = placeholder; + // Show all autocomplete options... + $("#maprQuery").focus(); + + // render(); +} + +function showAutocomplete(event) { + var configId = document.getElementById("maprConfig").value; + var autoCompleteValue = event.target.value; + + if (configId.indexOf('mapr_') != 0) { + // If not MAPR search, show all auto-complete results + autoCompleteValue = ''; + } + + $("#maprQuery").autocomplete("search", autoCompleteValue); +} + +document.getElementById('maprQuery').onfocus = function (event) { + showAutocomplete(event); +}; + +document.getElementById('maprQuery').onclick = function (event) { + showAutocomplete(event); +}; + +function showSpinner() { + document.getElementById('spinner').style.visibility = 'visible'; +} +function hideSpinner() { + document.getElementById('spinner').style.visibility = 'hidden'; +} + +// Initial setup... +$("#maprQuery") + .keyup(event => { + if (event.which == 13) { + let configId = document.getElementById("maprConfig").value; + console.log(`${GALLERY_HOME}search/?query=${configId}:${event.target.value}`) + // document.location.href = `${GALLERY_HOME}search/?query=${configId}:${event.target.value}`; + } + }) + .autocomplete({ + autoFocus: false, + delay: 1000, + source: function (request, response) { + + // if configId is not from mapr, we filter on mapValues... + let configId = document.getElementById("maprConfig").value; + if (configId.indexOf('mapr_') != 0) { + + let matches; + if (configId === 'Name') { + matches = model.getStudiesNames(request.term); + } else if (configId === 'Group') { + matches = model.getStudiesGroups(request.term); + } else { + matches = model.getKeyValueAutoComplete(configId, request.term); + } + response(matches); + return; + } + + // Don't handle empty query for mapr + if (request.term.length == 0) { + return; + } + + // Auto-complete to filter by mapr... + configId = configId.replace('mapr_', ''); + let case_sensitive = false; + + let requestData = { + case_sensitive: case_sensitive, + } + let url; + if (request.term.length === 0) { + // Try to list all top-level values. + // This works for 'wild-card' configs where number of values is small e.g. Organism + // But will return empty list for e.g. Gene + url = `${BASE_URL}mapr/api/${configId}/`; + requestData.orphaned = true + } else { + // Find auto-complete matches + url = `${BASE_URL}mapr/api/autocomplete/${configId}/`; + requestData.value = case_sensitive ? request.term : request.term.toLowerCase(); + requestData.query = true; // use a 'like' HQL query + } + showSpinner(); + $.ajax({ + dataType: "json", + type: 'GET', + url: url, + data: requestData, + success: function (data) { + hideSpinner(); + if (request.term.length === 0) { + // Top-level terms in 'maps' + if (data.maps && data.maps.length > 0) { + let terms = data.maps.map(m => m.id); + terms.sort(); + response(terms); + } + } + else if (data.length > 0) { + response($.map(data, function (item) { + return item; + })); + } else { + response([{ label: 'No results found.', value: -1 }]); + } + }, + error: function (data) { + hideSpinner(); + response([{ label: 'Loading auto-complete terms failed. Server may be busy.', value: -1 }]); + } + }); + }, + minLength: 0, + open: function () { }, + close: function () { + // $(this).val(''); + return false; + }, + focus: function (event, ui) { }, + select: function (event, ui) { + if (ui.item.value == -1) { + // Ignore 'No results found' + return false; + } + // show temp message in case loading search page is slow + $(this).val("loading search results..."); + // Load search page... + let configId = document.getElementById("maprConfig").value; + document.location.href = `${GALLERY_HOME}search/?query=${configId}:${ui.item.value}`; + return false; + } + }).data("ui-autocomplete")._renderItem = function (ul, item) { + return $("<li>") + .append("<a>" + item.label + "</a>") + .appendTo(ul); + } diff --git a/idr_gallery/static/idr_gallery/categories.js b/idr_gallery/static/idr_gallery/categories.js new file mode 100644 index 00000000..52fbc1d3 --- /dev/null +++ b/idr_gallery/static/idr_gallery/categories.js @@ -0,0 +1,319 @@ +// Copyright (C) 2019-2022 University of Dundee & Open Microscopy Environment. +// All rights reserved. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +// NB: SOURCE FILES are under /src. Compiled files are under /static/ + +// loaded below +let mapr_settings = {}; + +// Model for loading Projects, Screens and their Map Annotations +let model = new StudiesModel(); + +model.subscribe('thumbnails', (event, data) => { + // Will get called when each batch of thumbnails is loaded + renderThumbnails(data); +}); + + +let getTooltipContent = (reference) => { + return reference.querySelector(".idr_tooltip").innerHTML; +} + +function renderStudyContainers(containers) { + return ['screen', 'project'].map(objType => { + let studies = containers[objType]; + let count = studies.length; + if (count == 0) return; + // Link to first Project or Screen + return `<a target="_blank" href="${BASE_URL}webclient/?show=${studies[studies.length - 1].objId}">${count} ${objType == 'project' ? 'Experiment' : 'Screen'}${count === 1 ? '' : 's'}</a>`; + }).filter(Boolean).join(", "); +} + +function studyHtml(study, studyObj) { + let idrId = study.Name.split("-")[0]; + let authors = model.getStudyValue(study, "Publication Authors") || " "; + authors = authors.split(",")[0]; + let title = escapeHTML(getStudyTitle(model, study)); + let pubmed = studyObj["pubmed_id"]; + return ` + <div class="studyThumb" style="${study.thumbnail ? 'background-image: url(' + study.thumbnail + ')' : ''}" data-authors="${authors}" data-title="${title}" data-idrid="${idrId}" data-obj_type="${study.type}" data-obj_id="${study.id}"> + <div class="idr_tooltip"> + <div style="float: right"> + ${pubmed ? `<a target="_blank" href="${pubmed}"> ${authors} et. al </a>` : `<b> ${authors} et. al </b>`} + </div> + <div style="margin-bottom:5px">${idrId}</div> + <div style="width: 300px; display:flex"> + <div style="width:96px; position: relative" title="Open image viewer"> + <a class="viewer_link" target="_blank" href="${ BASE_URL }webclient/img_detail/${ study.image?.id }/"> + <img class="tooltipThumb" src="${study.thumbnail ? study.thumbnail : ''}"></img> + <i class="fas fa-eye"></i> + </a> + </div> + <div style="width:204px; margin-left: 7px"> + <div style="float: left">${renderStudyContainers(studyObj)}</div> + <div style="float: right; font-weight: bold">${imageCount(idrId)}</div> + <div style="clear: both"></div> + <span title="${studyObj["description"]}"> + ${title} + </span> + </div> + </div> + </div> + </div> + `} + + +// ------------ Render ------------------------- + +function render() { + + const groupByType = document.getElementById("groupByType").checked; + document.getElementById('studies').innerHTML = ""; + + // we group by 'idr00ID' and show Screens and Experiments + let studyContainers = {}; + // go through all Screens and Experiments... + model.studies.forEach(study => { + let idrId = study.Name.split("-")[0]; + if (!studyContainers[idrId]) { + // data for each study: + studyContainers[idrId] = { + 'screen': [], 'project': [], + 'description': "", + 'pubmed_id': "" + } + } + let objType = study.objId.split("-")[0]; // 'screen' or 'project' + studyContainers[idrId][objType].push(study); + studyContainers[idrId]["description"] = model.getStudyDescription(study); + let pubmed = model.getStudyValue(study, 'PubMed ID'); + if (pubmed) { + studyContainers[idrId]["pubmed_id"] = pubmed.split(" ")[1]; + } + }); + + + let idrIds = []; + + let html = ""; + if (!groupByType) { + // Show all studies... + html = model.studies.map(study => { + let idrId = study.Name.split("-")[0]; + // Ignore multiple projects/screens from same study/publication + if (idrIds.includes(idrId)) { + return ''; + } + idrIds.push(idrId); + return studyHtml(study, studyContainers[idrId]); + }).join(""); + } else { + // group by Categories + let categories = Object.keys(CATEGORY_QUERIES); + // Sort by index + categories.sort(function (a, b) { + let idxA = CATEGORY_QUERIES[a].index; + let idxB = CATEGORY_QUERIES[b].index; + return (idxA > idxB ? 1 : idxA < idxB ? -1 : 0); + }); + + let allIds = []; + + html = categories.map(category => { + + let cat = CATEGORY_QUERIES[category]; + let query = cat.query; + + // Find matching studies + let matches = model.filterStudiesByMapQuery(query); + if (matches.length == 0) return ''; + + let catIds = []; + + let catThumbs = matches.map(study => { + let idrId = study.Name.split("-")[0]; + // Ignore multiple projects/screens from same study/publication + if (cat.label !== "Others" && catIds.includes(idrId)) { + return ''; + } + if (cat.label === "Others" && allIds.includes(idrId)) { + return ''; + } + catIds.push(idrId); + allIds.push(idrId); + return studyHtml(study, studyContainers[idrId]); + }).join(""); + + return ` + <div style="clear:left"> + <div style="color:#666">${cat.label}</div> + <div> + ${catThumbs} + </div> + </div>` + }).join(""); + } + + document.getElementById('studies').innerHTML = html; + + // tooltips - NB: updated when thumbnails loaded + tippy('.studyThumb', { + content: getTooltipContent, + trigger: 'mouseenter click', // click to show - eg. on mobile + theme: 'light-border', + offset: [0, 2], + allowHTML: true, + moveTransition: 'transform 2s ease-out', + interactive: true, // allow click + }); +} + + +// --------- Render utils ----------- + +function imageCount(idrId) { + if (!model.studyStats) return ""; + + let containers = model.studyStats[idrId]; + if (!containers) return ""; + + let imgCount = containers.map(row => row["5D Images"]) + .reduce((total, value) => total + parseInt(value, 10), 0); + return new Intl.NumberFormat().format(imgCount) + " Image" + (imgCount != "1" ? "s" : ""); +} + +function renderThumbnails(data) { + // data is {'project-1': {'image':{'id': 2}, 'thumbnail': 'data:image/jpeg;base64,/9j/4AAQSkZ...'}} + for (let id in data) { + let obj_type = id.split('-')[0]; + let obj_id = id.split('-')[1]; + let elements = document.querySelectorAll(`div[data-obj_type="${obj_type}"][data-obj_id="${obj_id}"]`); + // This updates small grid thumbnails and the tooltip images + for (let e = 0; e < elements.length; e++) { + // Find all studies matching the study ID and set src on image + let element = elements[e]; + element.style.backgroundImage = `url(${data[id].thumbnail})`; + // tooltip content is child of this element + let thumb = element.querySelector(".tooltipThumb"); + if (thumb) { + thumb.src = data[id].thumbnail; + } + // add viewer-link for tooltip + let link = element.querySelector(".viewer_link"); + if (link) { + let url = `${BASE_URL}webclient/img_detail/${data[id].image.id}/`; + link.href = url; + } + // update tooltips + if (element._tippy) { + element._tippy.setContent(getTooltipContent(element)); + } + } + } +} + + + +// ----------- Load / Filter Studies -------------------- + +model.loadStudyStats(IDR_STUDIES_URL, function (stats) { + // Load stats and show spinning counters... + + // In case studies.tsv loading from github fails, show older values + let totalImages = 12840301; + let tbTotal = 307; + let studyCount = 104; + + if (stats) { + let studyIds = Object.keys(stats); + // remove grouping of containers by idrId + let containers = Object.values(stats).flatMap(containers => containers); + + if (SUPER_CATEGORY) { + try { + // filter studies and containers by cell or tissue + let query = SUPER_CATEGORY.query.split(":"); // e.g. "Sample Type:tissue" + studyIds = studyIds.filter(studyId => stats[studyId].some(row => row[query[0]] == query[1])); + let filtered = containers.filter(row => row[query[0]] == query[1]); + if (filtered.length != 0) { + // in case we filter out everything! + containers = filtered; + } + } catch (error) { + console.log("Failed to filter studies stats by category") + } + } + let imageCounts = containers.map(row => row["5D Images"]); + totalImages = imageCounts.reduce((total, value) => total + parseInt(value, 10), 0); + let tbCounts = containers.map(row => row["Size (TB)"]); + tbTotal = tbCounts.reduce((total, value) => total + parseFloat(value, 10), 0); + studyCount = studyIds.length; + } + + animateValue(document.getElementById("imageCount"), 0, totalImages, 1500); + animateValue(document.getElementById("tbCount"), 0, tbTotal, 1500); + animateValue(document.getElementById("studyCount"), 0, studyCount, 1500); +}); + + +async function init() { + + // Do the loading and render() when done... + await model.loadStudies(); + + // Immediately filter by Super category + if (SUPER_CATEGORY && SUPER_CATEGORY.query) { + model.studies = model.filterStudiesByMapQuery(SUPER_CATEGORY.query); + } + + // start loading thumbnails in batches... triggers render() when loaded + model.loadStudiesThumbnails(); + + render(); + + document.getElementById("groupByType").addEventListener("change", function (event) { + render(); + }) + + + // Load MAPR config + fetch(BASE_URL + 'mapr/api/config/') + .then(response => response.json()) + .then(data => { + mapr_settings = data; + + let options = FILTER_MAPR_KEYS.map(key => { + let config = mapr_settings[key]; + if (config) { + return `<option value="mapr_${key}">${config.label}</option>`; + } else { + return ""; + } + }); + if (options.length > 0) { + document.getElementById('maprKeys').innerHTML = options.join("\n"); + // Show the <optgroup> and the whole form + document.getElementById('maprKeys').style.display = 'block'; + document.getElementById('search-form').style.display = 'block'; + } + }) + .catch(function (err) { + console.log("mapr not installed (config not available)"); + }); + +} + +init(); diff --git a/omero_gallery/static/gallery/css/idr.css b/idr_gallery/static/idr_gallery/css/idr.css similarity index 100% rename from omero_gallery/static/gallery/css/idr.css rename to idr_gallery/static/idr_gallery/css/idr.css diff --git a/omero_gallery/static/gallery/css/openmicroscopy.css b/idr_gallery/static/idr_gallery/css/openmicroscopy.css similarity index 100% rename from omero_gallery/static/gallery/css/openmicroscopy.css rename to idr_gallery/static/idr_gallery/css/openmicroscopy.css diff --git a/omero_gallery/static/gallery/images/favicon.ico b/idr_gallery/static/idr_gallery/images/favicon.ico similarity index 100% rename from omero_gallery/static/gallery/images/favicon.ico rename to idr_gallery/static/idr_gallery/images/favicon.ico diff --git a/idr_gallery/static/idr_gallery/images/logo-idr-dark.svg b/idr_gallery/static/idr_gallery/images/logo-idr-dark.svg new file mode 100644 index 00000000..f329dff5 --- /dev/null +++ b/idr_gallery/static/idr_gallery/images/logo-idr-dark.svg @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 288.5 112" style="enable-background:new 0 0 288.5 112;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#303030;} +</style> +<g id="text"> + <g> + <path class="st0" d="M124.4,78.4V22c0-2.9,0.7-5.1,2-6.6s3.1-2.2,5.2-2.2c2.2,0,3.9,0.7,5.3,2.2c1.4,1.4,2.5,3.7,2.5,6.6v56.4 + c0,3-1.1,5-2.5,6.4c-1.4,1.5-3.1,2.2-5.3,2.2c-2.1,0-3.8-0.7-5.2-2.2C125,83.3,124.4,81.3,124.4,78.4z"/> + <path class="st0" d="M164.1,14H183c4.9,0,9.1,0.9,12.6,1.8s6.7,2.6,9.6,5.1c7.5,6.4,11.2,16.1,11.2,29.1c0,4.3-0.4,8.2-1.1,11.8 + c-0.7,3.5-1.9,6.7-3.5,9.6s-3.6,5.4-6,7.6c-1.9,1.7-4,3.1-6.3,4.2c-2.3,1-4.7,1.8-7.3,2.2c-2.6,0.4-5.6,0.6-8.9,0.6h-18.9 + c-2.6,0-4.6-0.4-6-1.2c-1.3-0.8-2.1-1.9-2.5-3.4c-0.4-1.4-0.6-3.3-0.6-5.6V23.3c0-3.1,0.6-5.4,2-6.8S160.9,14,164.1,14z + M169.3,25.9v48.3h11.4c2.4,0,4.3-0.1,5.7-0.2s2.8-0.2,4.2-0.7c1.5-0.5,2.7-1.3,3.8-2.2c4.9-4.1,7.3-11.2,7.3-21.2 + c0-7.1-1.1-12.4-3.2-15.9s-4.8-5.8-7.9-6.7c-3.1-1-6.9-1.4-11.3-1.4L169.3,25.9L169.3,25.9z"/> + <path class="st0" d="M248.6,56h-4.3v22.4c0,3-1.5,5.3-2.8,6.7s-3.1,2.1-5.2,2.1c-2.3,0-4.1-0.7-5.4-2.2s-2.6-3.7-2.6-6.6V23.3 + c0-3.1,1.4-5.4,2.8-6.8s3.7-2.5,6.8-2.5h23.6c3.3,0,6,0.1,8.3,0.4s4.4,1.3,6.2,2.1c2.2,0.9,4.2,2.3,6,4.1c1.7,1.8,3,3.8,3.9,6.1 + s1.3,4.8,1.3,7.4c0,5.3-1.5,9.6-4.5,12.8s-7.6,5.5-13.7,6.8c2.6,1.4,5,3.4,7.4,6.1c2.3,2.7,4.4,5.5,6.3,8.5c1.8,3,3.3,5.7,4.3,8.2 + s1.5,4.1,1.5,5s-0.3,1.9-0.9,2.8s-1.4,1.7-2.5,2.2c-1,0.5-2.2,0.8-3.6,0.8c-1.6,0-3-0.4-4.1-1.1c-1.1-0.8-2.1-1.7-2.9-2.9 + s-1.9-2.9-3.2-5.2l-5.8-9.7c-2.1-3.5-3.9-6.2-5.6-8.1c-1.6-1.9-3.3-2.5-5-3.2C253.3,56.3,251.2,56,248.6,56z M256.9,26h-12.6v19 + h12.2c3.5,0,6.4-0.3,8.8-0.9c2.4-0.6,4.2-1.6,5.4-3.1c1.3-1.4,1.9-3.4,1.9-6c0-2-0.5-3.7-1.5-5.2s-2.4-2-4.2-2.8 + C265.2,26.3,261.9,26,256.9,26z"/> + </g> +</g> +<g id="logomark"> + <g> + <path class="st0" d="M40,64H8c-4.4,0-8-3.6-8-8l0,0c0-4.4,3.6-8,8-8h32c4.4,0,8,3.6,8,8l0,0C48,60.4,44.4,64,40,64z"/> + <path class="st0" d="M96,64H64c-4.4,0-8-3.6-8-8l0,0c0-4.4,3.6-8,8-8h32c4.4,0,8,3.6,8,8l0,0C104,60.4,100.4,64,96,64z"/> + <path class="st0" d="M80,40H24c-4.4,0-8-3.6-8-8l0,0c0-4.4,3.6-8,8-8h56c4.4,0,8,3.6,8,8l0,0C88,36.4,84.4,40,80,40z"/> + <path class="st0" d="M80,88H24c-4.4,0-8-3.6-8-8l0,0c0-4.4,3.6-8,8-8h56c4.4,0,8,3.6,8,8l0,0C88,84.4,84.4,88,80,88z"/> + <path class="st0" d="M64,16H40c-4.4,0-8-3.6-8-8l0,0c0-4.4,3.6-8,8-8h24c4.4,0,8,3.6,8,8l0,0C72,12.4,68.4,16,64,16z"/> + <path class="st0" d="M64,112H40c-4.4,0-8-3.6-8-8l0,0c0-4.4,3.6-8,8-8h24c4.4,0,8,3.6,8,8l0,0C72,108.4,68.4,112,64,112z"/> + </g> +</g> +</svg> diff --git a/omero_gallery/static/gallery/images/omero.svg b/idr_gallery/static/idr_gallery/images/omero.svg similarity index 100% rename from omero_gallery/static/gallery/images/omero.svg rename to idr_gallery/static/idr_gallery/images/omero.svg diff --git a/omero_gallery/static/gallery/images/transparent.png b/idr_gallery/static/idr_gallery/images/transparent.png similarity index 100% rename from omero_gallery/static/gallery/images/transparent.png rename to idr_gallery/static/idr_gallery/images/transparent.png diff --git a/idr_gallery/static/idr_gallery/model.js b/idr_gallery/static/idr_gallery/model.js new file mode 100644 index 00000000..6e4a11a1 --- /dev/null +++ b/idr_gallery/static/idr_gallery/model.js @@ -0,0 +1,648 @@ +"use strict"; + +// Copyright (C) 2019-2022 University of Dundee & Open Microscopy Environment. +// All rights reserved. +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// NB: SOURCE FILES are under /src. Compiled files are under /static/ + +class StudiesModel { + constructor() { + this.base_url = BASE_URL; + this.studies = []; + this.images = {}; + this.pubSubObject = $({}); + return this; + } + + subscribe() { + this.pubSubObject.on.apply(this.pubSubObject, arguments); + } + + unsubscribe() { + this.pubSubObject.off.apply(this.pubSubObject, arguments); + } + + publish() { + this.pubSubObject.trigger.apply(this.pubSubObject, arguments); + } + + getStudyById(typeId) { + // E.g. 'project-1', or 'screen-2' + var objType = typeId.split('-')[0]; + var id = typeId.split('-')[1]; + + for (var i = 0; i < this.studies.length; i++) { + var study = this.studies[i]; + + if (study['@id'] == id && study['@type'].split('#')[1].toLowerCase() == objType) { + return study; + } + } + } + + getStudiesNames(filterQuery) { + var names = this.studies.map(function (s) { + return s.Name; + }); + + if (filterQuery) { + names = names.filter(function (name) { + return name.toLowerCase().indexOf(filterQuery) > -1; + }); + } + + names.sort(function (a, b) { + return a.toLowerCase() > b.toLowerCase() ? 1 : -1; + }); + return names; + } + + getStudiesGroups(filterQuery) { + var names = []; + this.studies.forEach(function (study) { + var groupName = study['omero:details'].group.Name; + + if (names.indexOf(groupName) === -1) { + names.push(groupName); + } + }); + + if (filterQuery) { + names = names.filter(function (name) { + return name.toLowerCase().indexOf(filterQuery) > -1; + }); + } + + names.sort(function (a, b) { + return a.toLowerCase() > b.toLowerCase() ? 1 : -1; + }); + return names; + } + + getStudyValue(study, key) { + if (!study.mapValues) return; + + for (var i = 0; i < study.mapValues.length; i++) { + var kv = study.mapValues[i]; + + if (kv[0] === key) { + return kv[1]; + } + } + } + + getStudyTitle(study) { + var title; + + for (var i = 0; i < TITLE_KEYS.length; i++) { + title = model.getStudyValue(study, TITLE_KEYS[i]); + if (title) { + break; + } + } + if (!title) { + title = study.Name; + } + return title; + } + + getStudyDescription(study, title) { + + if (!title) { + title = this.getStudyTitle(study); + } + let desc = study.Description; + let studyDesc = ""; + if (desc) { + // If description contains title, use the text that follows + if (title.length > 0 && desc.indexOf(title) > -1) { + desc = desc.split(title)[1]; + } + // Remove blank lines (and first 'Experiment Description' line) + studyDesc = desc.split('\n').filter(function (l) { + return l.length > 0; + }).filter(function (l) { + return l !== 'Experiment Description' && l !== 'Screen Description'; + }).join('\n'); + + if (studyDesc.indexOf('Version History') > 1) { + studyDesc = studyDesc.split('Version History')[0]; + } + } + return studyDesc; + } + + getStudyValues(study, key) { + if (!study.mapValues) { + return []; + } + var matches = []; + for (var i = 0; i < study.mapValues.length; i++) { + var kv = study.mapValues[i]; + if (kv[0] === key) { + matches.push(kv[1]); + } + } + return matches; + } + + getKeyValueAutoComplete(key, inputText) { + var _this = this; + + inputText = inputText.toLowerCase(); // Get values for key from each study + + var values = []; + this.studies.forEach(function (study) { + var v = _this.getStudyValues(study, key); + + for (var i = 0; i < v.length; i++) { + values.push(v[i]); + } + }); // We want values that match inputText + // Except for "Publication Authors", where we want words + // Create dict of {lowercaseValue: origCaseValue} + + var matchCounts = values.reduce(function (prev, value) { + var matches = []; + + if (key == "Publication Authors") { + // Split surnames, ignoring AN initials. + var names = value.split(/,| and | & /).map(function (n) { + // Want the surname from e.g. 'Jan Ellenberg' or 'Held M' or 'Øyvind Ødegård-Fougner' + var words = n.split(" ").filter(function (w) { + return w.match(/[a-z]/g); + }); + if (words && words.length == 1) return words[0]; // Surname only + + return words && words.length > 1 ? words.slice(1).join(" ") : ''; + }).filter(function (w) { + return w.length > 0; + }); + matches = names.filter(function (name) { + return name.toLowerCase().indexOf(inputText) > -1; + }); + } else if (value.toLowerCase().indexOf(inputText) > -1) { + matches.push(value); + } + + matches.forEach(function (match) { + if (!prev[match.toLowerCase()]) { + // key is lowercase, value is original case + prev[match.toLowerCase()] = { + value: match, + count: 0 + }; + } // also keep count of matches + + prev[match.toLowerCase()].count++; + }); + return prev; + }, {}); // Make into list and sort by: + // match at start of phrase > match at start of word > other match + + var matchList = []; + + for (key in matchCounts) { + var matchScore = 1; + + if (key.indexOf(inputText) == 0) { + // best match if our text STARTS WITH inputText + matchScore = 3; + } else if (key.indexOf(" " + inputText) > -1) { + // next best if a WORD starts with inputText + matchScore = 2; + } // Make a list of sort score, orig text (NOT lowercase keys) and count + + matchList.push([matchScore, matchCounts[key].value, matchCounts[key].count]); + } // Sort by the matchScore (hightest first) + + + matchList.sort(function (a, b) { + if (a[0] < b[0]) return 1; + if (a[0] > b[0]) return -1; // equal score. Sort by value (lowest first) + + if (a[1].toLowerCase() > b[1].toLowerCase()) return 1; + return -1; + }); // Return the matches + + return matchList.map(function (m) { + // Auto-complete uses {label: 'X (n)', value: 'X'} + return { + label: "".concat(m[1], " (").concat(m[2], ")"), + value: m[1] + }; + }).filter(function (m) { + return m.value.length > 0; + }); + } + + async loadStudies() { + // Load Projects AND Screens, sort them and render... + await Promise.all([ + fetch(this.base_url + "api/v0/m/projects/?childCount=true"), + fetch(this.base_url + "api/v0/m/screens/?childCount=true"), + ]).then(responses => + Promise.all(responses.map(res => res.json())) + ).then(([projects, screens]) => { + this.studies = projects.data; + this.studies = this.studies.concat(screens.data); + + // ignore empty studies with no images + this.studies = this.studies.filter(study => study['omero:childCount'] > 0); + + // sort by name, reverse + this.studies.sort(function (a, b) { + var nameA = a.Name.toUpperCase(); + var nameB = b.Name.toUpperCase(); + if (nameA < nameB) { + return 1; + } + if (nameA > nameB) { + return -1; + } + + // names must be equal + return 0; + }); + + }).catch((err) => { + console.error(err); + }); + + // Load Map Annotations + await this.loadStudiesMapAnnotations(); + } + + loadStudiesThumbnails() { + let url = GALLERY_INDEX + "gallery-api/thumbnails/"; + + let toFind = this.studies.map(study => study.objId.replace("-", "=")); + let batchSize = 10; + while (toFind.length > 0) { + let data = toFind.slice(0, batchSize).join("&"); + fetch(url + '?' + data) + .then(response => response.json()) + .then(data => { + for (let studyId in data) { + let study = this.getStudyById(studyId); + if (data[studyId]) { + study.image = data[studyId].image; + study.thumbnail = data[studyId].thumbnail; + } + } + this.publish("thumbnails", data); + }); + toFind = toFind.slice(batchSize); + } + } + + async loadStudiesMapAnnotations() { + let url = this.base_url + "webclient/api/annotations/?type=map"; + let data = this.studies + .map(study => `${study['@type'].split('#')[1].toLowerCase()}=${study['@id']}`) + .join("&"); + url += '&' + data; + await fetch(url) + .then(response => response.json()) + .then(data => { + // populate the studies array... + // dict of {'project-1' : key-values} + let annsByParentId = {}; + data.annotations.forEach(ann => { + let key = ann.link.parent.class; // 'ProjectI' + key = key.substr(0, key.length - 1).toLowerCase(); + key += '-' + ann.link.parent.id; // project-1 + if (!annsByParentId[key]) { + annsByParentId[key] = []; + } + annsByParentId[key] = annsByParentId[key].concat(ann.values); + }); + // Add mapValues to studies... + this.studies = this.studies.map(study => { + // Also set 'type':'screen', 'objId': 'screen-123' + study.type = study['@type'].split('#')[1].toLowerCase(); + study.id = study['@id']; + study.objId = `${study.type}-${study['@id']}`; + let values = annsByParentId[study.objId]; + if (values) { + study.mapValues = values; + let releaseDate = this.getStudyValue(study, 'Release Date'); + if (releaseDate) { + study.date = new Date(releaseDate); + if (isNaN(study.date.getTime())) { + study.date = undefined; + } + } + } + return study; + }); + + }) + } + + filterStudiesAnyText(text) { + // Search for studies with text in their keys, values, or description. + // Returns a list of matching studies. Each study is returned along with text matches + // [study, ["key: value", "description"]] + let regexes = text.split(" ").map(token => new RegExp(token, "i")) + function matchSome(str) { + return regexes.some(re => re.test(str)); + } + const re = new RegExp(text, "i") + return this.studies.map(study => { + let mapValues = []; + if (study.mapValues) { + mapValues = study.mapValues.map(kv => kv.join(": ")); + } + let studyStrings = mapValues.concat([study.Description]); + + // we want ALL the search tokens to match at least somewhere in studyStrings + let match = regexes.every(re => studyStrings.some(str => re.test(str))) + if (!match) return; + + // return [study, "key: value string showing matching text"] + let matches = mapValues.filter(matchSome); + if (matchSome(study.Description)) { + matches.push(study.Description); + } + return [study, matches] + }).filter(Boolean); + } + + filterStudiesByMapQuery(query) { + if (query.startsWith("FIRST") || query.startsWith("LAST")) { + // E.g. query is 'FIRST10:date' sort by 'date' and return first 10 + var limit = parseInt(query.replace('FIRST', '').replace('LAST', '')); + var attr = query.split(':')[1]; + var desc = query.startsWith("FIRST") ? -1 : 1; // first filter studies, remove those that don't have 'attr' + + var sorted = this.studies.filter(function (study) { + return study[attr] !== undefined; + }).sort(function (a, b) { + var aVal = a[attr]; + var bVal = b[attr]; // If string, use lowercase + + aVal = aVal.toLowerCase ? aVal.toLowerCase() : aVal; + bVal = bVal.toLowerCase ? bVal.toLowerCase() : bVal; + return aVal < bVal ? desc : aVal > bVal ? -desc : 0; + }); + return sorted.slice(0, limit); + } + + var matches = this.studies.filter(function (study) { + // If no key-values loaded, filter out + if (!study.mapValues) { + return false; + } + + var match = false; // first split query by AND and OR + + var ors = query.split(' OR '); + ors.forEach(function (term) { + var allAnds = true; + var ands = term.split(' AND '); + ands.forEach(function (mustMatch) { + var queryKeyValue = mustMatch.split(":"); + var valueMatch = false; // check all key-values (may be duplicate keys) for value that matches + + for (var i = 0; i < study.mapValues.length; i++) { + var kv = study.mapValues[i]; + + if (kv[0] === queryKeyValue[0]) { + var value = queryKeyValue[1].trim(); + + if (value.substr(0, 4) === 'NOT ') { + value = value.replace('NOT ', ''); + + if (kv[1].toLowerCase().indexOf(value.toLowerCase()) == -1) { + valueMatch = true; + } + } else if (kv[1].toLowerCase().indexOf(value.toLowerCase()) > -1) { + valueMatch = true; + } + } + } + // if not found, then our AND term fails + if (!valueMatch) { + allAnds = false; + } + }); + + if (allAnds) { + match = true; + } + }); + return match; + }); + return matches; + } + + loadImage(obj_type, obj_id, callback) { + // Get a sample image ID for 'screen' or 'project' + let key = `${obj_type}-${obj_id}`; + + // check cache + if (this.images[key]) { + callback(this.images[key]); + return; + } + + let url = `${GALLERY_INDEX}gallery-api/${obj_type}s/${obj_id}/images/?limit=1` + fetch(url) + .then(response => response.json()) + .then(data => { + let images = data.data; + if (images.length > 0) { + this.images[key] = images[0] + } + callback(this.images[key]); + return; + }) + } + + loadStudyStats = function (url, callback) { + let self = this; + $.get(url, function (data) { + let tsvRows = data.split('\n'); + let columns; + // read tsv => dicts + let rowsAsObj = tsvRows.map(function (row, count) { + let values = row.split('\t'); + if (count == 0) { + columns = values; + return; + } + if (values.length === 0) return; + let row_data = {}; + for (let c = 0; c < values.length; c++) { + if (c < columns.length) { + row_data[columns[c]] = values[c]; + } + } + return row_data + }).filter(Boolean); + + // Group rows by Study + let stats = {}; + rowsAsObj.forEach(row => { + let studyName = row["Study"]; + if (!studyName) return; + let studyId = studyName.split("-")[0]; + if (!stats[studyId]) { + stats[studyId] = []; + } + stats[studyId].push(row); + }); + + self.studyStats = stats; + + if (callback) { + callback(stats); + } + }).fail(function () { + console.log("Failed to load studies.tsv") + if (callback) { + callback(); + } + }); + } +} + +function animateValue(obj, start, end, duration) { + // https://css-tricks.com/animating-number-counters/ + let startTimestamp = null; + const step = (timestamp) => { + if (!startTimestamp) startTimestamp = timestamp; + let progress = Math.min((timestamp - startTimestamp) / duration, 1); + // If we want easing... + // progress = Math.sin(Math.PI * progress / 2); + let number = Math.floor(progress * (end - start) + start); + obj.innerHTML = new Intl.NumberFormat().format(number); + if (progress < 1) { + window.requestAnimationFrame(step); + } + }; + window.requestAnimationFrame(step); +} + +function toTitleCase(text) { + if (!text || text.length == 0) return text; + return text[0].toUpperCase() + text.slice(1); +} + +var getStudyShortName = function getStudyShortName(study) { + var shortName = "".concat(toTitleCase(study.type), ": ").concat(study.id); + + if (STUDY_SHORT_NAME) { + for (var i = 0; i < STUDY_SHORT_NAME.length; i++) { + var key = STUDY_SHORT_NAME[i]['key']; + var value = void 0; + var newShortName = void 0; + + if (key === 'Name' || key === 'Description') { + value = study[key]; + } + + if (!value) { + value = model.getStudyValue(study, key); + } + + if (!value) { + continue; + } + + if (STUDY_SHORT_NAME[i]['regex'] && STUDY_SHORT_NAME[i]['template']) { + var re = new RegExp(STUDY_SHORT_NAME[i]['regex']); + var template = STUDY_SHORT_NAME[i]['template']; + newShortName = value.replace(re, template); + } else { + newShortName = value; + } + + if (newShortName) { + shortName = newShortName; + break; + } + } + } + + return shortName; +}; // startsWith polyfill for IE + + +if (!String.prototype.startsWith) { + String.prototype.startsWith = function (search, pos) { + return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; + }; +} // Object.assign polyfill for IE + + +if (typeof Object.assign !== 'function') { + // Must be writable: true, enumerable: false, configurable: true + Object.defineProperty(Object, "assign", { + value: function assign(target, varArgs) { + // .length of function is 2 + 'use strict'; + + if (target === null || target === undefined) { + throw new TypeError('Cannot convert undefined or null to object'); + } + + var to = Object(target); + + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + + if (nextSource !== null && nextSource !== undefined) { + for (var nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + + return to; + }, + writable: true, + configurable: true + }); +} + + +function getStudyTitle(model, study) { + let title; + for (let i = 0; i < TITLE_KEYS.length; i++) { + title = model.getStudyValue(study, TITLE_KEYS[i]); + if (title) { + break; + } + } + if (!title) { + title = study.Name; + } + return title; +} + +const escapeHTML = str => + str.replace( + /[&<>'"]/g, + tag => + ({ + '&': '&', + '<': '<', + '>': '>', + "'": ''', + '"': '"' + }[tag] || tag) + ); diff --git a/src/search.js b/idr_gallery/static/idr_gallery/search.js similarity index 58% rename from src/search.js rename to idr_gallery/static/idr_gallery/search.js index 69c82a5f..fcc833dd 100644 --- a/src/search.js +++ b/idr_gallery/static/idr_gallery/search.js @@ -18,25 +18,13 @@ // Model for loading Projects, Screens and their Map Annotations let model = new StudiesModel(); -let mapr_settings; -function renderStudyKeys() { - if (FILTER_KEYS.length > 0) { - let html = FILTER_KEYS - .map(key => { - if (key.label && key.value) { - return `<option value="${ key.value }">${ key.label }</option>` - } - return `<option value="${ key }">${ key }</option>` - }) - .join("\n"); - document.getElementById('studyKeys').innerHTML = html; - // Show the <optgroup> and the whole form - document.getElementById('studyKeys').style.display = 'block'; - document.getElementById('search-form').style.display = 'block'; - } -} -renderStudyKeys(); +model.subscribe('thumbnails', (event, data) => { + // Will get called when each batch of thumbnails is loaded + renderThumbnails(data); +}); + +let mapr_settings; // FIRST, populate forms from query string @@ -47,7 +35,7 @@ function populateInputsFromSearch() { for (var i = 0; i < searchParams.length; i++) { var paramSplit = searchParams[i].split('='); if (paramSplit[0] === 'query') { - query = paramSplit[1].replace(/%20/g, " "); + query = paramSplit[1].replace(/%20/g, " "); } } if (query) { @@ -60,7 +48,7 @@ function populateInputsFromSearch() { let key = configId.replace('mapr_', ''); let placeholder = `Type to filter values...`; if (mapr_settings && mapr_settings[key]) { - placeholder = `Type ${ mapr_settings[key]['default'][0]}...`; + placeholder = `Type ${mapr_settings[key]['default'][0]}...`; } document.getElementById('maprQuery').placeholder = placeholder; } @@ -76,33 +64,33 @@ function filterStudiesByMapr(value) { let configId = document.getElementById("maprConfig").value.replace("mapr_", ""); document.getElementById('studies').innerHTML = ""; let key = mapr_settings[value] ? mapr_settings[value].all.join(" or ") : value; - showFilterSpinner(`Finding images with ${ configId }: ${ value }...`); + showFilterSpinner(`Finding images with ${configId}: ${value}...`); // Get all terms that match (NOT case_sensitive) - let url = `${ BASE_URL }mapr/api/${ configId }/?value=${ value }&case_sensitive=false&orphaned=true`; + let url = `${BASE_URL}mapr/api/${configId}/?value=${value}&case_sensitive=false&orphaned=true`; $.getJSON(url, (data) => { let maprTerms = data.maps.map(term => term.id); - let termUrls = maprTerms.map(term => `${ BASE_URL }mapr/api/${ configId }/?value=${ term }`); + let termUrls = maprTerms.map(term => `${BASE_URL}mapr/api/${configId}/?value=${term}`); // Get results for All terms Promise.all(termUrls.map(url => fetch(url))) - .then(responses => Promise.all(responses.map(res => res.json()))) - .then((responses) => { - hideFilterSpinner(); + .then(responses => Promise.all(responses.map(res => res.json()))) + .then((responses) => { + hideFilterSpinner(); - // filter studies by each response - let studiesByTerm = responses.map(data => filterStudiesByMaprResponse(data)); + // filter studies by each response + let studiesByTerm = responses.map(data => filterStudiesByMaprResponse(data)); - renderMaprMessage(studiesByTerm, maprTerms); + renderMaprMessage(studiesByTerm, maprTerms); - // Show table for each... - studiesByTerm.forEach((studies, idx) => { - if (studies.length > 0) { - renderMaprResultsTable(studies, maprTerms[idx]); - } - }); - }) + // Show table for each... + studiesByTerm.forEach((studies, idx) => { + if (studies.length > 0) { + renderMaprResultsTable(studies, maprTerms[idx]); + } + }); + }) // .fail(() => { // document.getElementById('filterCount').innerHTML = "Request failed. Server may be busy." // }) @@ -113,8 +101,8 @@ function filterStudiesByMapr(value) { function filterStudiesByMaprResponse(data) { // filter studies by 'screens' and 'projects' let imageCounts = {}; - data.screens.forEach(s => {imageCounts[`screen-${ s.id }`] = s.extra.counter}); - data.projects.forEach(s => {imageCounts[`project-${ s.id }`] = s.extra.counter}); + data.screens.forEach(s => { imageCounts[`screen-${s.id}`] = s.extra.counter }); + data.projects.forEach(s => { imageCounts[`project-${s.id}`] = s.extra.counter }); let filterFunc = study => { let studyId = study['@type'].split('#')[1].toLowerCase() + '-' + study['@id']; @@ -149,9 +137,9 @@ function renderMaprMessage(studiesByTerm, maprTerms) { key = mapr_settings[key].label; } filterMessage = `<p class="filterMessage"> - Found <strong>${ imageCount }</strong> images with + Found <strong>${imageCount}</strong> images with <strong>${key}</strong>: <strong>${terms}</strong> - in <strong>${ studyCount }</strong> stud${ studyCount == 1 ? 'y' : 'ies' }</strong></p>`; + in <strong>${studyCount}</strong> stud${studyCount == 1 ? 'y' : 'ies'}</strong></p>`; } document.getElementById('filterCount').innerHTML = filterMessage; } @@ -161,9 +149,9 @@ function renderMaprResultsTable(maprData, term) { let configId = document.getElementById("maprConfig").value.replace("mapr_", ""); let elementId = 'maprResultsTable' + term; let html = ` - <h2>${ term }</h2> + <h2>${term}</h2> <table class='maprResultsTable' style='margin-top:20px'> - <tbody data-id='${ elementId }'> + <tbody data-id='${elementId}'> <tr> <th>Study ID</th> <th>Organism</th> @@ -185,7 +173,7 @@ document.getElementById('maprConfig').onchange = (event) => { let value = event.target.value.replace('mapr_', ''); let placeholder = `Type to filter values...`; if (mapr_settings[value]) { - placeholder = `Type ${ mapr_settings[value]['default'][0]}...`; + placeholder = `Type ${mapr_settings[value]['default'][0]}...`; } document.getElementById('maprQuery').placeholder = placeholder; // Show all autocomplete options... @@ -235,121 +223,121 @@ function hideFilterSpinner() { } $("#maprQuery") - .keyup(event => { - if (event.which == 13) { - $(event.target).autocomplete( "close" ); - filterAndRender(); - // Add to browser history. Handled by onpopstate on browser Back - let configId = document.getElementById("maprConfig").value; - window.history.pushState({}, "", `?query=${ configId }:${ event.target.value }`); - } - }) - .autocomplete({ + .keyup(event => { + if (event.which == 13) { + $(event.target).autocomplete("close"); + filterAndRender(); + // Add to browser history. Handled by onpopstate on browser Back + let configId = document.getElementById("maprConfig").value; + window.history.pushState({}, "", `?query=${configId}:${event.target.value}`); + } + }) + .autocomplete({ autoFocus: false, delay: 1000, - source: function( request, response ) { + source: function (request, response) { - // if configId is not from mapr, we filter on mapValues... - let configId = document.getElementById("maprConfig").value; - if (configId.indexOf('mapr_') != 0) { + // if configId is not from mapr, we filter on mapValues... + let configId = document.getElementById("maprConfig").value; + if (configId.indexOf('mapr_') != 0) { - let matches; - if (configId === 'Name') { - matches = model.getStudiesNames(request.term); - } else if (configId === 'Group') { - matches = model.getStudiesGroups(request.term); - } else { - matches = model.getKeyValueAutoComplete(configId, request.term); - } - response(matches); - - // When not mapr, we filter while typing - filterAndRender(); - return; + let matches; + if (configId === 'Name') { + matches = model.getStudiesNames(request.term); + } else if (configId === 'Group') { + matches = model.getStudiesGroups(request.term); + } else { + matches = model.getKeyValueAutoComplete(configId, request.term); } + response(matches); - // Don't handle empty query for mapr - if (request.term.length == 0) { - return; - } + // When not mapr, we filter while typing + filterAndRender(); + return; + } - // Auto-complete to filter by mapr... - configId = configId.replace('mapr_', ''); - let case_sensitive = false; + // Don't handle empty query for mapr + if (request.term.length == 0) { + return; + } - let requestData = { - case_sensitive: case_sensitive, - } - let url; - if (request.term.length === 0) { - // Try to list all top-level values. - // This works for 'wild-card' configs where number of values is small e.g. Organism - // But will return empty list for e.g. Gene - url = `${ BASE_URL }mapr/api/${ configId }/`; - requestData.orphaned = true - } else { - // Find auto-complete matches - url = `${ BASE_URL }mapr/api/autocomplete/${ configId }/`; - requestData.value = case_sensitive ? request.term : request.term.toLowerCase(); - requestData.query = true; // use a 'like' HQL query - } + // Auto-complete to filter by mapr... + configId = configId.replace('mapr_', ''); + let case_sensitive = false; + + let requestData = { + case_sensitive: case_sensitive, + } + let url; + if (request.term.length === 0) { + // Try to list all top-level values. + // This works for 'wild-card' configs where number of values is small e.g. Organism + // But will return empty list for e.g. Gene + url = `${BASE_URL}mapr/api/${configId}/`; + requestData.orphaned = true + } else { + // Find auto-complete matches + url = `${BASE_URL}mapr/api/autocomplete/${configId}/`; + requestData.value = case_sensitive ? request.term : request.term.toLowerCase(); + requestData.query = true; // use a 'like' HQL query + } - showSpinner(); - $.ajax({ - dataType: "json", - type : 'GET', - url: url, - data: requestData, - success: function(data) { - hideSpinner(); - if (request.term.length === 0) { - // Top-level terms in 'maps' - if (data.maps && data.maps.length > 0) { - let terms = data.maps.map(m => m.id); - terms.sort(); - response(terms); - } - } - else if (data.length > 0) { - response( $.map( data, function(item) { - return item; - })); - } else { - response([{ label: 'No results found.', value: -1 }]); - } - }, - error: function(data) { - hideSpinner(); - // E.g. status 504 for timeout - response([{ label: 'Loading auto-complete terms failed. Server may be busy.', value: -1 }]); + showSpinner(); + $.ajax({ + dataType: "json", + type: 'GET', + url: url, + data: requestData, + success: function (data) { + hideSpinner(); + if (request.term.length === 0) { + // Top-level terms in 'maps' + if (data.maps && data.maps.length > 0) { + let terms = data.maps.map(m => m.id); + terms.sort(); + response(terms); } - }); + } + else if (data.length > 0) { + response($.map(data, function (item) { + return item; + })); + } else { + response([{ label: 'No results found.', value: -1 }]); + } + }, + error: function (data) { + hideSpinner(); + // E.g. status 504 for timeout + response([{ label: 'Loading auto-complete terms failed. Server may be busy.', value: -1 }]); + } + }); }, minLength: 0, - open: function() {}, - close: function() { - // $(this).val(''); - return false; + open: function () { }, + close: function () { + // $(this).val(''); + return false; }, - focus: function(event,ui) {}, - select: function(event, ui) { - if (ui.item.value == -1) { - // Ignore 'No results found' - return false; - } - $(this).val(ui.item.value); - filterAndRender(); - // Add to browser history. Handled by onpopstate on browser Back - let configId = document.getElementById("maprConfig").value; - window.history.pushState({}, "", `?query=${ configId }:${ ui.item.value }`); - + focus: function (event, ui) { }, + select: function (event, ui) { + if (ui.item.value == -1) { + // Ignore 'No results found' return false; + } + $(this).val(ui.item.value); + filterAndRender(); + // Add to browser history. Handled by onpopstate on browser Back + let configId = document.getElementById("maprConfig").value; + window.history.pushState({}, "", `?query=${configId}:${ui.item.value}`); + + return false; } -}).data("ui-autocomplete")._renderItem = function( ul, item ) { - return $( "<li>" ) - .append( "<a>" + item.label + "</a>" ) - .appendTo( ul ); -} + }).data("ui-autocomplete")._renderItem = function (ul, item) { + return $("<li>") + .append("<a>" + item.label + "</a>") + .appendTo(ul); + } // ------------ Render ------------------------- @@ -401,14 +389,14 @@ function renderMapr(maprData, term) { let linkFunc = (studyData) => { let type = studyData['@type'].split('#')[1].toLowerCase(); let maprKey = configId.replace('mapr_', ''); - return `/mapr/${ maprKey }/?value=${ term }&show=${ type }-${ studyData['@id'] }`; + return `/mapr/${maprKey}/?value=${term}&show=${type}-${studyData['@id']}`; } - let elementSelector = `[data-id="${ elementId }"]`; + let elementSelector = `[data-id="${elementId}"]`; maprData.forEach(s => renderStudy(s, elementSelector, linkFunc, maprHtml)); // load images for each study... - $(`[data-id="${ elementId }"] tr`).each(function() { + $(`[data-id="${elementId}"] tr`).each(function () { // load children in MAPR jsTree query to get images let element = this; let studyId = element.id; @@ -420,35 +408,35 @@ function renderMapr(maprData, term) { let maprValue = term; // We want to link to the dataset or plate... let imgContainer; - let url = `${ BASE_URL }mapr/api/${ configId }/${ childType }/?value=${ maprValue }&id=${ objId }`; + let url = `${BASE_URL}mapr/api/${configId}/${childType}/?value=${maprValue}&id=${objId}`; fetch(url) .then(response => response.json()) .then(data => { let firstChild = data[childType][0]; - imgContainer = `${ firstChild.extra.node }-${ firstChild.id }`; - let imagesUrl = `${ BASE_URL }mapr/api/${ configId }/images/?value=${ maprValue }&id=${ firstChild.id }&node=${ firstChild.extra.node }`; + imgContainer = `${firstChild.extra.node}-${firstChild.id}`; + let imagesUrl = `${BASE_URL}mapr/api/${configId}/images/?value=${maprValue}&id=${firstChild.id}&node=${firstChild.extra.node}`; return fetch(imagesUrl); }) .then(response => response.json()) .then(data => { let html = data.images.slice(0, 3).map(i => ` - <a href="${ BASE_URL }webclient/img_detail/${ i.id }/" + <a href="${BASE_URL}webclient/img_detail/${i.id}/" target="_blank" title="Open image in viewer" class="maprViewerLink"> <div> - <img class="thumbnail" src="${ STATIC_DIR }images/transparent.png" - data-src="${ BASE_URL }webgateway/render_thumbnail/${ i.id }/"> + <img class="thumbnail" src="${STATIC_DIR}images/transparent.png" + data-src="${BASE_URL}webgateway/render_thumbnail/${i.id}/"> <i class="fas fa-eye"></i> </div> </a>`).join(""); - let linkHtml = `<a target="_blank" href="${ BASE_URL }mapr/${ configId }/?value=${ maprValue }&show=${ imgContainer }"> + let linkHtml = `<a target="_blank" href="${BASE_URL}mapr/${configId}/?value=${maprValue}&show=${imgContainer}"> more... </a>` // Find the container and add placeholder images html - $("#"+element.id + " .exampleImages").html(html); - $("#"+element.id + " .exampleImagesLink").append(linkHtml); + $("#" + element.id + " .exampleImages").html(html); + $("#" + element.id + " .exampleImagesLink").append(linkHtml); // Update the src to load the thumbnails. Timeout to let placeholder render while we wait for thumbs setTimeout(() => { - $('img', "#"+element.id).each((index, img) => { + $('img', "#" + element.id).each((index, img) => { img.src = img.dataset.src; }); }, 0); @@ -478,7 +466,7 @@ function render(filterFunc) { configId = (mapr_settings && mapr_settings[configId]) || configId; let maprValue = document.getElementById('maprQuery').value; filterMessage = `<p class="filterMessage"> - Found <strong>${ studiesToRender.length }</strong> studies with + Found <strong>${studiesToRender.length}</strong> studies with <strong>${configId}</strong>: <strong>${maprValue}</strong></p>`; } document.getElementById('filterCount').innerHTML = filterMessage; @@ -486,13 +474,14 @@ function render(filterFunc) { // By default, we link to the study itself in IDR... let linkFunc = (studyData) => { let type = studyData['@type'].split('#')[1].toLowerCase(); - return `${ BASE_URL }webclient/?show=${ type }-${ studyData['@id'] }`; + return `${BASE_URL}webclient/?show=${type}-${studyData['@id']}`; } let htmlFunc = studyHtml; studiesToRender.forEach(s => renderStudy(s, '#studies', linkFunc, htmlFunc)); - loadStudyThumbnails(); + // loadStudyThumbnails(); + model.loadStudiesThumbnails(); } @@ -506,11 +495,11 @@ function noStudiesMessage() { let others = []; for (let cat in SUPER_CATEGORIES) { if (SUPER_CATEGORIES[cat].label !== currLabel) { - others.push(`<a href="${GALLERY_INDEX}${ cat }/search/?query=${configId}:${maprQuery}">${ SUPER_CATEGORIES[cat].label }</a>`); + others.push(`<a href="${GALLERY_HOME}${cat}/search/?query=${configId}:${maprQuery}">${SUPER_CATEGORIES[cat].label}</a>`); } } if (others.length > 0) { - filterMessage += " Try " + others.join (" or "); + filterMessage += " Try " + others.join(" or "); } } return filterMessage; @@ -520,42 +509,19 @@ function noStudiesMessage() { function renderStudy(studyData, elementSelector, linkFunc, htmlFunc) { // Add Project or Screen to the page - let title; - for (let i=0; i<TITLE_KEYS.length; i++) { - title = model.getStudyValue(studyData, TITLE_KEYS[i]); - if (title) { - break; - } - } - if (!title) { - title = studyData.Name; - } + var title = model.getStudyTitle(studyData); + let type = studyData['@type'].split('#')[1].toLowerCase(); let studyLink = linkFunc(studyData); // save for later studyData.title = title; - let desc = studyData.Description; - let studyDesc; - if (desc) { - // If description contains title, use the text that follows - if (title.length > 0 && desc.indexOf(title) > -1) { - desc = desc.split(title)[1]; - } - // Remove blank lines (and first 'Experiment Description' line) - studyDesc = desc.split('\n') - .filter(l => l.length > 0) - .filter(l => l !== 'Experiment Description' && l !== 'Screen Description') - .join('\n'); - if (studyDesc.indexOf('Version History') > 1) { - studyDesc = studyDesc.split('Version History')[0]; - } - } + var studyDesc = model.getStudyDescription(studyData, title); let shortName = getStudyShortName(studyData); let authors = model.getStudyValue(studyData, "Publication Authors") || ""; - let div = htmlFunc({studyLink, studyDesc, shortName, title, authors, BASE_URL, type}, studyData); + let div = htmlFunc({ studyLink, studyDesc, shortName, title, authors, BASE_URL, type }, studyData); document.querySelector(elementSelector).appendChild(div); } @@ -569,24 +535,24 @@ function studyHtml(props, studyData) { } let author = props.authors.split(',')[0] || ''; if (author) { - author = `${ author } et al.`; + author = `${author} et al.`; author = author.length > 23 ? author.slice(0, 20) + '...' : author; } let html = ` <div style='white-space:nowrap'> - ${ props.shortName } - ${ pubmed ? `<a class='pubmed' target="_blank" href="${ pubmed }"> ${ author }</a>` : author} + ${props.shortName} + ${pubmed ? `<a class='pubmed' target="_blank" href="${pubmed}"> ${author}</a>` : author} </div> <div class="studyImage"> - <a target="_blank" href="${ props.studyLink }"> + <a target="_blank" href="${props.studyLink}"> <div style="height: 100%; width: 100%"> <div class="studyText"> - <p title='${ props.studyDesc }'> - ${ props.title } + <p title='${props.studyDesc}'> + ${props.title} </p> </div> <div class="studyAuthors"> - ${ props.authors } + ${props.authors} </div> </div> </a> @@ -596,7 +562,7 @@ function studyHtml(props, studyData) { </a> </div> ` - var div = document.createElement( "div" ); + var div = document.createElement("div"); div.innerHTML = html; div.id = props.type + '-' + studyData['@id']; div.dataset.obj_type = props.type; @@ -608,17 +574,17 @@ function studyHtml(props, studyData) { function maprHtml(props, studyData) { let html = ` <td> - <a target="_blank" href="${ props.studyLink }" /> - ${ props.shortName } + <a target="_blank" href="${props.studyLink}" /> + ${props.shortName} </a> </td> - <td>${ model.getStudyValue(studyData, 'Organism')}</td> - <td>${ studyData.imageCount }</td> - <td title="${ props.title }">${ props.title.slice(0,40) }${ props.title.length > 40 ? '...' : '' }</td> + <td>${model.getStudyValue(studyData, 'Organism')}</td> + <td>${studyData.imageCount}</td> + <td title="${props.title}">${props.title.slice(0, 40)}${props.title.length > 40 ? '...' : ''}</td> <td class='exampleImages'>loading...</td> <td class='exampleImagesLink'></td> ` - var tr = document.createElement( "tr" ); + var tr = document.createElement("tr"); tr.innerHTML = html; tr.id = props.type + '-' + studyData['@id']; tr.dataset.obj_type = props.type; @@ -627,54 +593,50 @@ function maprHtml(props, studyData) { } -function loadStudyThumbnails() { - - let ids = []; - // Collect study IDs 'project-1', 'screen-2' etc - $('div.study').each(function() { - let obj_id = $(this).attr('data-obj_id'); - let obj_type = $(this).attr('data-obj_type'); - if (obj_id && obj_type) { - ids.push(obj_type + '-' + obj_id); - } - }); - - // Load images - model.loadStudiesThumbnails(ids, (data) => { - // data is e.g. { project-1: {thumbnail: base64data, image: {id:1}} } - for (let id in data) { - if (!data[id]) continue; // may be null - let obj_type = id.split('-')[0]; - let obj_id = id.split('-')[1]; - let elements = document.querySelectorAll(`div[data-obj_type="${obj_type}"][data-obj_id="${obj_id}"]`); - for (let e=0; e<elements.length; e++) { - // Find all studies matching the study ID and set src on image - let element = elements[e]; - let studyImage = element.querySelector('.studyImage'); - if (data[id].thumbnail) { - studyImage.style.backgroundImage = `url(${ data[id].thumbnail })`; - } - // viewer link - if (data[id].image && data[id].image.id) { - let iid = data[id].image.id; - let link = `${ BASE_URL }webclient/img_detail/${ iid }/`; - element.querySelector('a.viewerLink').href = link; - } +function renderThumbnails(data) { + + // data is e.g. { project-1: {thumbnail: base64data, image: {id:1}} } + for (let id in data) { + if (!data[id]) continue; // may be null + let obj_type = id.split('-')[0]; + let obj_id = id.split('-')[1]; + let elements = document.querySelectorAll(`div[data-obj_type="${obj_type}"][data-obj_id="${obj_id}"]`); + for (let e = 0; e < elements.length; e++) { + // Find all studies matching the study ID and set src on image + let element = elements[e]; + let studyImage = element.querySelector('.studyImage'); + if (data[id].thumbnail) { + studyImage.style.backgroundImage = `url(${data[id].thumbnail})`; + } + // viewer link + if (data[id].image && data[id].image.id) { + let iid = data[id].image.id; + let link = `${BASE_URL}webclient/img_detail/${iid}/`; + element.querySelector('a.viewerLink').href = link; } } - }); + } } // ----------- Load / Filter Studies -------------------- -// Do the loading and render() when done... -model.loadStudies(() => { +async function init() { + // Do the loading and render() when done... + await model.loadStudies(); + // Immediately filter by Super category if (SUPER_CATEGORY && SUPER_CATEGORY.query) { model.studies = model.filterStudiesByMapQuery(SUPER_CATEGORY.query); } + + // load thumbs for all studies, even if not needed + // URL will be same each time (before filtering) so response will be cached + model.loadStudiesThumbnails(); + filterAndRender(); -}); +} + +init(); // Handle browser Back and Forwards - redo filtering window.onpopstate = (event) => { @@ -692,7 +654,7 @@ fetch(BASE_URL + 'mapr/api/config/') let options = FILTER_MAPR_KEYS.map(key => { let config = mapr_settings[key]; if (config) { - return `<option value="mapr_${ key }">${ config.label }</option>`; + return `<option value="mapr_${key}">${config.label}</option>`; } else { return ""; } @@ -704,6 +666,6 @@ fetch(BASE_URL + 'mapr/api/config/') document.getElementById('search-form').style.display = 'block'; } populateInputsFromSearch(); - }).catch(function(err) { + }).catch(function (err) { console.log("mapr not installed (config not available)"); }); diff --git a/omero_gallery/static/gallery/studies.css b/idr_gallery/static/idr_gallery/studies.css similarity index 71% rename from omero_gallery/static/gallery/studies.css rename to idr_gallery/static/idr_gallery/studies.css index d6232283..1a038989 100644 --- a/omero_gallery/static/gallery/studies.css +++ b/idr_gallery/static/idr_gallery/studies.css @@ -149,34 +149,3 @@ maprText { position: relative; border-radius: 10px; } - -/* Always show scrollbars https://gist.github.com/IceCreamYou/cd517596e5847a88e2bb0a091da43fb4 */ -::-webkit-scrollbar-track:vertical { - border-left: 1px solid #E7E7E7; - box-shadow: 1px 0 1px 0 #F6F6F6 inset, -1px 0 1px 0 #F6F6F6 inset; -} - -::-webkit-scrollbar-track:horizontal { - border-top: 1px solid #E7E7E7; - box-shadow: 0 1px 1px 0 #F6F6F6 inset, 0 -1px 1px 0 #F6F6F6 inset; -} - -::-webkit-scrollbar { - -webkit-appearance: none; - background-color: #FAFAFA; - width: 16px; -} - -::-webkit-scrollbar-thumb { - background-clip: padding-box; - background-color: #C1C1C1; - border-color: transparent; - border-radius: 9px 8px 8px 9px; - border-style: solid; - border-width: 3px 3px 3px 4px; /* Workaround because margins aren't supported */ - box-shadow: 0 0 1px rgba(255, 255, 255, 0.5); -} - -::-webkit-scrollbar-thumb:hover { - background-color: rgba(0, 0, 0, 0.5); -} diff --git a/idr_gallery/templates/idr_gallery/background_carousel.html b/idr_gallery/templates/idr_gallery/background_carousel.html new file mode 100644 index 00000000..184bda15 --- /dev/null +++ b/idr_gallery/templates/idr_gallery/background_carousel.html @@ -0,0 +1,171 @@ +<style> + .marketing-background { + position: absolute; + background-position: center; + width: 100%; + background-size: cover; + height: 400px; + height: 100%; + top: 0; + left: 0; + transition: left 1s; + } + + .prev { + left: -100% + } + + .next { + left: 100% + } + + .bg_controls { + position: absolute; + right: 5px; + top: 5px; + color: white; + font-size: 200%; + display: flex; + } + + .bg_controls div { + width: 14px; + height: 14px; + border: solid white 1px; + border-radius: 50%; + cursor: pointer; + margin: 7px; + background-color: transparent; + transition: border-color 1s, background-color 1s; + position: static; + } + + .dark .bg_controls div { + border-color: #222222; + } + + .bg_controls .selected { + background-color: rgba(255, 255, 255, .9); + } + + .dark .bg_controls .selected { + background-color: rgba(0, 0, 0, 0.5); + } + + .bg_controls div:hover { + opacity: 0.75; + } + + .bg_controls div.selected:hover { + opacity: 1; + } + + .bg_viewer_link { + display: block; + position: absolute; + right: 10px; + font-size: 24px; + color: white; + top: 24px; + visibility: hidden; + } + + a.bg_viewer_link:hover { + color: white; + } + + .dark .bg_viewer_link { + color: #222222; + } + + .bg_controls .selected .bg_viewer_link { + visibility: visible; + } +</style> + +{% for img in idr_images %} +<div class="marketing-background {% if not forloop.first %}next{% endif %}" data-src="{{ base_url }}{{ img.src }}" + style="background-image: url('{{ img.thumbnail }}');" {% if img.light %}data-light="true" {% endif %}></div> +{% endfor %} + +<div class="bg_controls"> + {% for img in idr_images %} + <div {% if forloop.first %}class="selected" {% endif %} title="{{ img.title }}"> + + <a class="bg_viewer_link" style="right:45px; font-size:20px; margin-top:1px" title="Browse background image metadata" target="_blank" + href="{{ base_url }}webclient/?show=image-{{ img.image_id }}"> + <i class="fas fa-info"></i> + </a> + + <a class="bg_viewer_link" title="Open background image in viewer" target="_blank" + href="{{ base_url }}webclient/img_detail/{{ img.image_id }}/"> + <i class="fas fa-eye"></i> + </a> + + </div> + {% endfor %} +</div> + +<script> + $(function () { + + function renderHeaderBg(clickedIndex) { + var isLight; + $(".marketing-background").each(function (index, el) { + let $bgImg = $(el); + $bgImg.css('left', (clickedIndex - index) * -100 + '%'); + if (clickedIndex == index) { + isLight = $bgImg.data("light"); + } + if (clickedIndex == index || clickedIndex + 1 == index || clickedIndex - 1 == index) { + // load the image (data-src => src) for current background 'previous' and 'next' + let src = $bgImg.attr("data-src"); + if (src) { + let i = new Image(); + $bgImg.removeAttr("data-src"); // don't process again + i.onload = function () { + // pre-load before updating background, to avoid black while loading + $bgImg.css('background-image', "url('" + src + "')") + }; + i.src = src; + } + } + }); + $(`.bg_controls div`).removeClass('selected'); + $(`.bg_controls div:nth-child(${clickedIndex + 1})`).addClass('selected'); + + if (isLight) { + $(".marketing-hero").addClass("dark"); + } else { + $(".marketing-hero").removeClass("dark"); + } + } + + // header background carousel controls + $(".bg_controls div").on("click", function (event) { + // ignore click on viewer link + if (event.target.tagName == 'I') return; + let $target = $(event.target); + let clickedIndex = $(".bg_controls div").removeClass('selected').index($target); + renderHeaderBg(clickedIndex); + }); + + function logKey(e) { + // ignore keyboard events from input elements + if (document.activeElement.tagName == "INPUT") return; + let $selected = $(".bg_controls .selected"); + let index = $(".bg_controls div").index($selected); + let count = $(".bg_controls>div").length; + if (e.code == "ArrowRight" && (index + 1) < count) { + index += 1; + } else if (e.code == "ArrowLeft" && index > 0) { + index -= 1; + } + renderHeaderBg(index); + } + document.addEventListener('keyup', logKey); + + // make sure initial state (controls) are correct + renderHeaderBg(0); + }); +</script> diff --git a/omero_gallery/templates/webgallery/categories/base.html b/idr_gallery/templates/idr_gallery/base.html similarity index 87% rename from omero_gallery/templates/webgallery/categories/base.html rename to idr_gallery/templates/idr_gallery/base.html index f4f68088..e74be5d4 100644 --- a/omero_gallery/templates/webgallery/categories/base.html +++ b/idr_gallery/templates/idr_gallery/base.html @@ -10,28 +10,26 @@ {% if favicon %} <link rel="shortcut icon" type="image/x-icon" href="{{ favicon }}"> {% else %} - <link rel="shortcut icon" type="image/x-icon" href="{% static 'gallery/images/favicon.ico' %}"> + <link rel="shortcut icon" type="image/x-icon" href="{% static 'idr_gallery/images/favicon.ico' %}?_={{VERSION}}"> {% endif %} <link rel="stylesheet" type="text/css" media="all" href="//fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic"> <link rel="stylesheet" type="text/css" media="all" href="//fonts.googleapis.com/css?family=Nunito"> - <link href="{% static 'gallery/3rdparty/foundation/foundation.min.css' %}" rel="stylesheet"> - <link href="{% static 'gallery/css/openmicroscopy.css' %}" rel="stylesheet"> - <link href="{% static 'gallery/css/idr.css' %}" rel="stylesheet"> + <link href="{% static 'idr_gallery/3rdparty/foundation/foundation.min.css' %}?_={{VERSION}}" rel="stylesheet"> + <link href="{% static 'idr_gallery/css/openmicroscopy.css' %}?_={{VERSION}}" rel="stylesheet"> + <link href="{% static 'idr_gallery/css/idr.css' %}?_={{VERSION}}" rel="stylesheet"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"> - <!-- fetch polyfill for IE --> - <script src="https://cdn.jsdelivr.net/npm/whatwg-fetch@3.0.0/dist/fetch.umd.min.js"></script> <!-- Babel polfill (Symbol, Promise) --> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.6.15/browser-polyfill.min.js"></script> <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"> - <script src="{% static 'gallery/3rdparty/foundation/foundation.min.js' %}"></script> + <script src="{% static 'idr_gallery/3rdparty/foundation/foundation.min.js' %}"></script> <script src="{{ base_url }}about/js/version.js"></script> - <script src="{% static 'gallery/model.js' %}"></script> - <link href="{% static 'gallery/studies.css' %}" rel="stylesheet"> + <script src="{% static 'idr_gallery/model.js' %}?_={{VERSION}}"></script> + <link href="{% static 'idr_gallery/studies.css' %}?_={{VERSION}}" rel="stylesheet"> </head> <body> @@ -92,10 +90,8 @@ <hr class="whitespace"> - {% if footer_html %} <div class="callout large secondary"> <div class="row"> - {% if footer_html == 'IDR' %} <div class="row small-up-2 medium-up-5 large-up-5"> <div class="column"><a href="https://www.openmicroscopy.org/" target="_blank"><img class="thumbnail their-logo" src="{{ base_url }}about/img/logos/ome-logo-200.png" alt="OME"></a></div> <div class="column"><a href="https://www.eurobioimaging.eu/" target="_blank"><img class="thumbnail their-logo" src="{{ base_url }}about/img/logos/eurobioimaging_logo.png" alt="Euro-Bioimaging"></a></div> @@ -105,7 +101,7 @@ </div> <hr class="whitespace"> <div class="large-12 columns text-center"> - <p>© 2016-2020 University of Dundee & Open Microscopy Environment. <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank">Creative Commons Attribution 4.0 International License</a>.</p> + <p>© 2016-2022 University of Dundee & Open Microscopy Environment. <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank">Creative Commons Attribution 4.0 International License</a>.</p> <p>OMERO is distributed under the terms of the GNU GPL. For more information, visit <a href="https://www.openmicroscopy.org">openmicroscopy.org</a></p> </div> <hr class="whitespace"> @@ -119,12 +115,8 @@ <a href="https://www.twitter.com/idrstatus" target="_blank"><i class="fab fa-fw fa-twitter"></i> @IDRstatus</a></li> </div> </div> - {% else %} - {{ footer_html|safe }} - {% endif %} </div> </div> - {% endif %} <script> $(document).foundation(); diff --git a/idr_gallery/templates/idr_gallery/index.html b/idr_gallery/templates/idr_gallery/index.html new file mode 100644 index 00000000..27ef0555 --- /dev/null +++ b/idr_gallery/templates/idr_gallery/index.html @@ -0,0 +1,513 @@ +{% extends "idr_gallery/base.html" %} + +{% block content %} + +<script> + // Various global constants from omero config set... + var FILTER_KEYS = {{ filter_keys| safe }}; + var FILTER_MAPR_KEYS = {{ filter_mapr_keys| safe }}; + var TITLE_KEYS = {{ TITLE_KEYS| safe }}; + var STUDY_SHORT_NAME = {{ STUDY_SHORT_NAME| safe }}; + // e.g. GALLEY_INDEX/api-gallery/thumbnails for loading from IDR + const GALLERY_INDEX = "{{ gallery_index }}"; + // this is the home of this app, e.g. for GALLERY_HOME/search/ + const GALLERY_HOME = "{% url 'idr_gallery_index' %}"; + const BASE_URL = "{{ base_url }}"; + const IDR_STUDIES_URL = "{{ IDR_STUDIES_URL }}"; + const CATEGORY_QUERIES = {{ category_queries| safe }}; + var SUPER_CATEGORY {% if super_category %} = {{ super_category | safe }} {% endif %}; +</script> + +<script src="https://unpkg.com/@popperjs/core@2"></script> +<script src="https://unpkg.com/tippy.js@6"></script> +<link rel="stylesheet" href="https://unpkg.com/tippy.js@6/dist/backdrop.css" /> +<link rel="stylesheet" href="https://unpkg.com/tippy.js@6/themes/light-border.css" /> + +<style> + body { + background-color: #f6f6f9; + } + + header div { + position: relative; + } + + .marketing-hero { + overflow: hidden; + position: relative; + padding: 40px 10px 25px; + background: black; + box-shadow: 1px 1px 3px 0px rgb(0 0 0 / 50%); + } + + a.sites-button.large { + min-width: 150px; + font-size: 1.15rem; + display: block; + width: fit-content; + margin: 15px 7px; + } + + .cats { + display: flex; + justify-content: center; + } + + #search-form { + padding-top: 10px; + } + + .hero-subheader { + margin-bottom: 5px; + font-size: 1.15rem; + transition: background-color 1s, color 1s, box-shadow 1s; + } + + .dark .hero-subheader { + color: #333333; + background-color: rgba(255, 255, 255, 0.5); + box-shadow: 0px 0px 15px 15px rgb(255 255 255 / 50%); + } + + .stats { + position: relative; + text-align: center; + font-size: 1.7rem; + color: #333; + } + + #studies { + overflow-x: hidden; + overflow-y: auto; + max-height: 350px; + } + + .studyThumb { + float: left; + position: relative; + margin: 1px 0 1px 2px; + height: 50px; + width: 50px; + overflow: hidden; + background: no-repeat center; + background-size: cover; + background-color: #eee; + } + + .studyThumb div { + height: 100%; + width: 100%; + } + + .switchLabel { + font-size: 1.0rem; + display: inline; + vertical-align: middle; + position: relative; + bottom: 1px; + color: #666; + } + + /* https://www.w3schools.com/howto/howto_css_switch.asp */ + /* The switch - the box around the slider */ + .switch { + top: 3px; + position: relative; + display: inline-block; + width: 33px; + height: 20px; + } + + /* Hide default HTML checkbox */ + .switch input { + opacity: 0; + width: 0; + height: 0; + } + + /* The slider */ + .sliderToggle { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; + } + + .sliderToggle:before { + position: absolute; + content: ""; + height: 16px; + width: 16px; + left: 2px; + bottom: 2px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; + } + + input:checked+.sliderToggle { + background-color: #333333; + } + + input:checked+.sliderToggle:before { + -webkit-transform: translateX(13px); + -ms-transform: translateX(13px); + transform: translateX(13px); + } + + /* Rounded sliders */ + .sliderToggle.round { + border-radius: 9px; + } + + .sliderToggle.round:before { + border-radius: 50%; + } + + .panel { + background: white; + -webkit-box-shadow: 1px 1px 3px 0px rgba(0, 0, 0, 0.5); + box-shadow: 1px 1px 3px 0px rgba(0, 0, 0, 0.5); + padding: 15px; + width: 100%; + } + + @media screen and (min-width: 64em) { + #tabs { + min-height: 635px; + } + } + + .panel .tabs { + border-width: 0; + border-bottom-width: 1px; + } + + .tabs-title>a[aria-selected=true] { + background: transparent; + border-bottom: solid #333 2px; + } + + .tabs-title>a:focus { + background: transparent; + } + + /* .twitter-timeline is just while loading twitter */ + .tabs-title.is-active a, + .tabs-title a, + .panel>a.twitter-timeline { + color: #292F33; + font-weight: 300; + font-family: Helvetica, Roboto, "Segoe UI", Calibri, sans-serif; + font-size: 21px; + line-height: 24px; + padding: 5px 25px 9px 25px; + margin-bottom: -1px; + } + + .tabs-content { + border: none; + } + + .tabs-panel { + padding: 15px 0 0 0; + } + + .tabs-panel .row { + margin-bottom: 15px; + } + + .tabs-panel .large-6 iframe { + height: 156px; + } + + .tabs-panel .large-12 iframe { + height: 312px; + } + + .tabs-panel .row:last-child { + margin-bottom: 0; + } + + .expandVideo { + position: absolute; + bottom: 0; + right: -5px; + background-color: white; + padding: 5px; + border-radius: 50%; + } + + .large-12 .expandVideo { + transform: rotate(180deg); + } + + .logo-hero { + opacity: 1; + transition: opacity 1s; + } + + /* hide the white logo when parent has .dark */ + .dark .logo-hero { + opacity: 0; + } + + /* tooltip content hidden */ + .studyThumb .idr_tooltip { + display: none; + } + + /* tooltip viewer link */ + .tippy-content a .fa-eye { + position: absolute; + top: 5px; + right: 5px; + color: white + } + + .tippy-content a:hover .fa-eye { + color: #1e94e6; + } + + .tooltipThumb { + float: right; + } + + mark { + background: yellow; + } + + #filterText { + display: inline; + width: 200px; + margin: 0; + } +</style> + + +<header class="marketing-hero"> + + {% include 'idr_gallery/background_carousel.html' %} + <div class="row homepage text-center"> + <div class="medium-12 columns"> + <div style="display: inline-block; position: relative; width:160px; height:62px; margin-bottom: 20px;"> + <img style="left: 0; position: absolute; width:160px; margin-bottom: 20px;" + src="{% static 'idr_gallery/images/logo-idr-dark.svg' %}" alt="IDR logo" class="logo-dark" /> + <img style="left: 0; position: absolute; width:160px; margin-bottom: 20px;" + src="https://idr.openmicroscopy.org/about/img/logos/logo-idr-white.svg" alt="IDR logo" class="logo-hero"> + </div> + <!-- <h1 class="hero-main-header">Image Data Resource</h1> --> + <h2 class="hero-subheader small-10 medium-10 large-10 small-offset-1 medium-offset-1 large-offset-1"> + The Image Data Resource (IDR) is a public repository of image datasets from published scientific studies, + where the community can submit, search and access high-quality bio-image data. + </h2> + <div class="cats"> + {% for c, data in super_categories.items %} + <a href="{% url 'gallery_super_category' super_category=c %}" class="large button sites-button" + + style="margin-right: 10px; {% if c == category %}background-color: #ffc107{% endif %}">{{ data.label }}</a> + {% endfor %} + </div> + </div> + </div> + + <div id='search-form' class="row horizontal"> + <div class="small-12 medium-4 large-4 columns"> + <select id="maprConfig"> + {% if filter_keys %} + <optgroup id="studyKeys" label="Study Attributes"> + {% for key in filter_keys %} + <option value="{% if key.value %}{{ key.value }}{% else %}{{ key }}{% endif %}"> + {% if key.label %}{{ key.label }}{% else %}{{ key }}{% endif %} + </option>` + {% endfor %} + </optgroup> + {% endif %} + <optgroup id="maprKeys" style='display:none' label="Image Attributes"> + <!-- Map-Annotation keys loaded here --> + </optgroup> + </select> + </div> + <div style="position: relative" class="small-12 medium-8 large-8 columns"> + <input id="maprQuery" type="text" placeholder="Type to filter values..."> + <svg id="spinner" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="sync" role="img" + xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="svg-inline--fa fa-sync fa-w-16 fa-spin fa-lg"> + <path fill="currentColor" + d="M440.65 12.57l4 82.77A247.16 247.16 0 0 0 255.83 8C134.73 8 33.91 94.92 12.29 209.82A12 12 0 0 0 24.09 224h49.05a12 12 0 0 0 11.67-9.26 175.91 175.91 0 0 1 317-56.94l-101.46-4.86a12 12 0 0 0-12.57 12v47.41a12 12 0 0 0 12 12H500a12 12 0 0 0 12-12V12a12 12 0 0 0-12-12h-47.37a12 12 0 0 0-11.98 12.57zM255.83 432a175.61 175.61 0 0 1-146-77.8l101.8 4.87a12 12 0 0 0 12.57-12v-47.4a12 12 0 0 0-12-12H12a12 12 0 0 0-12 12V500a12 12 0 0 0 12 12h47.35a12 12 0 0 0 12-12.6l-4.15-82.57A247.17 247.17 0 0 0 255.83 504c121.11 0 221.93-86.92 243.55-201.82a12 12 0 0 0-11.8-14.18h-49.05a12 12 0 0 0-11.67 9.26A175.86 175.86 0 0 1 255.83 432z" + class=""></path> + </svg> + </div> + </div> +</header> + +<div class="row horizontal" style="position: relative; margin-top: 25px; margin-bottom: 15px"> + <div class="small-12 medium-12 large-12 columns"> + <div class="panel" style="float: left; width: 100%; color: #333"> + <div class="stats small-12 medium-4 large-4 columns"> + <span id="studyCount"></span> Studies + </div> + <div class="stats small-12 medium-4 large-4 columns"> + <span id="imageCount"></span> Images + </div> + <div class="stats small-12 medium-4 large-4 columns"> + <span id="tbCount"></span> TB + </div> + </div> + </div> +</div> +<div class="row horizontal" style="position: relative"> + <div class="small-12 medium-12 large-12 columns"> + <div class="panel" style="float: left"> + <form> + <label class="switchLabel">Group Studies by type</label> + <label class="switch" style="margin-right: 20px"> + <input id="groupByType" type="checkbox"> + <span class="sliderToggle round"></span> + </label> + <!-- Don't show filter controls for now... --> + <div style="display:none;"> + <label class="switchLabel">or Filter by:</label> + <input type="text" id="filterText" placeholder="authors or keywords" /> + </div> + <span class="switchLabel" id="filterResults" style="margin-left: 10px"></span> + </form> + <div id="studies"> + <!-- Placeholder thumbnails - updated by render() once studies have loaded --> + <script>document.write((new Array(100)).fill(`<div class="studyThumb"></div>`).join(""))</script> + </div> + </div> + </div> +</div> + +<div class="row horizontal" style="position: relative; margin-top: 15px; margin-bottom: 15px"> + <div class="stats small-12 medium-9 large-8 columns" style="position: relative"> + </div> +</div> + +<div class="row horizontal" style="position: relative;"> + <div class="small-12 medium-12 large-8 columns" style> + <div class="panel" id="tabs"> + <ul class="tabs" data-tabs id="example-tabs"> + {% for tab in TABS %} + <li class="tabs-title {% if forloop.first %} is-active {% endif %}"> + <a href="#panel{{ forloop.counter }}" {% if forloop.first %} aria-selected="true" {% endif %}> + {{ tab.title }} + </a> + </li> + {% endfor %} + </ul> + <div class="tabs-content" data-tabs-content="example-tabs"> + {% for tab in TABS %} + <div class="tabs-panel {% if forloop.first %} is-active {% endif %}" id="panel{{ forloop.counter }}"> + {{ tab.text|safe }} + {% for video in tab.videos %} + <div class="row horizontal"> + <div class="small-6 medium-6 large-6 columns" style="position: relative;"> + <iframe id="youtube" width="100%" height="100%" src="https://www.youtube.com/embed/{{ video.id }}" + title="YouTube video player" frameborder="0" + allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> + </iframe> + <button title="Expand video" class="expandVideo"><i class="fas fa-angle-right"></i><i + class="fas fa-angle-right"></i></button> + </div> + <div class="columns small-6 medium-6 large-6"> + <h3>{{video.title}}</h3> + {{video.text}} + </div> + </div> + {% endfor %} + </div> + {% endfor %} + </div> + </div> + </div> + + <div class="small-12 medium-12 large-4 columns"> + <div class="panel" style="padding: 10px"> + <a class="twitter-timeline" data-height="610" href="https://twitter.com/IDRnews?ref_src=twsrc%5Etfw"> + Tweets by IDRnews + </a> + <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> + </div> + </div> +</div> + +</div> + +<script src="{% static 'idr_gallery/categories.js' %}?_={{VERSION}}"></script> +<script src="{% static 'idr_gallery/autocomplete.js' %}?_={{VERSION}}"></script> + +<script> + + // handle expand/collapse of videos >> + $("#tabs").on("click", ".expandVideo", function () { + let $row = $(this).closest(".row"); + // toggle from 2 columns to 1 + $('.columns', $row).toggleClass("small-12 medium-12 large-12") + .toggleClass("small-6 medium-6 large-6"); + }); + + // Handle filtering studies when user types in [filter] text input + $("#filterText").on("keyup", function (event) { + let text = event.target.value; + + if (text.length == 0) { + render(); + document.getElementById('filterResults').innerHTML = ""; + return; + } + + let results = model.filterStudiesAnyText(text); + let html = results.map(studyText => { + let [study, matchingStrings] = studyText; + + let regexes = text.split(" ").map(token => new RegExp(token, "i")) + function markup(string) { + return regexes.reduce((prev, regex) => prev.replace(regex, "<mark>$&</mark>"), string) + } + let matchingString = matchingStrings.map(markup).join('<br>'); + let idrId = study.Name.split('-')[0]; + let pubmed = model.getStudyValue(study, 'PubMed ID')?.split(" ")[1]; + let authors = model.getStudyValue(study, "Publication Authors") || " "; + authors = authors.split(",")[0]; + + return `<tr style="font-size: 13px"> + <td> + ${idrId}<br> + <span style="white-space:nowrap">${pubmed ? `<a target="_blank" href="${pubmed}"> ${authors} et. al </a>` : `<b> ${authors} et. al </b>`}</span><br> + <a target="_blank" href="${BASE_URL}webclient/?show=${study.objId}"> + <img src="${study.thumbnail}"/><br> + ${study.Name.split("/").pop()} + </a> + </td> + <td>${matchingString}</td> + </tr>` + }).join("\n"); + + if (results.length == 0) { + html = "No studies found" + if (SUPER_CATEGORY) { + if (SUPER_CATEGORY.id === "cell") { + html += ` in Cell IDR. Try searching <a href="${GALLERY_INDEX}">all Studies in IDR</a>.`; + } else if (SUPER_CATEGORY.id === "tissue") { + html += ` in Tissue IDR. Try searching <a href="${GALLERY_INDEX}">all Studies in IDR</a>.`; + } + } else { + html += ". Try searching for Image attributes above." + } + } + + let containerCount = results.length; + let idrIds = results.map(r => r[0].Name.split("-")[0]); + let studyCount = (new Set(idrIds)).size; + + document.getElementById('filterResults').innerHTML = `found ${containerCount} containers in ${studyCount} studies`; + document.getElementById('studies').innerHTML = `<table>${html}</table>`; + }); +</script> + +{% endblock %} diff --git a/omero_gallery/templates/webgallery/categories/search.html b/idr_gallery/templates/idr_gallery/search.html similarity index 77% rename from omero_gallery/templates/webgallery/categories/search.html rename to idr_gallery/templates/idr_gallery/search.html index ac19241d..5fc71751 100644 --- a/omero_gallery/templates/webgallery/categories/search.html +++ b/idr_gallery/templates/idr_gallery/search.html @@ -1,5 +1,5 @@ -{% extends "webgallery/categories/base.html" %} +{% extends "idr_gallery/base.html" %} {% block content %} @@ -57,8 +57,15 @@ <h2 class="search-by">Search by:</h2> <div style="padding:0" class="small-12 medium-4 large-3 columns"> <select id="maprConfig"> <optgroup id="studyKeys" style='display:none' label="Study Attributes"> - <!-- Map-Annotation keys loaded here --> - </optgroup> + {% if filter_keys %} + <optgroup id="studyKeys" label="Study Attributes"> + {% for key in filter_keys %} + <option value="{% if key.value %}{{ key.value }}{% else %}{{ key }}{% endif %}"> + {% if key.label %}{{ key.label }}{% else %}{{ key }}{% endif %} + </option>` + {% endfor %} + </optgroup> + {% endif %} <optgroup id="maprKeys" style='display:none' label="Image Attributes"> </optgroup> </select> @@ -72,7 +79,7 @@ <h2 class="search-by">Search by:</h2> {% if category %} href="{% url 'gallery_super_category' super_category=category %}" {% else %} - href="{% url 'webgallery_index' %}" + href="{% url 'idr_gallery_index' %}" {% endif %} >X</a> </div> @@ -97,18 +104,22 @@ <h2 class="search-by">Search by:</h2> <script> // Various global constants from omero config set... - var FILTER_KEYS = {{ filter_keys|escape|safe }}; - var FILTER_MAPR_KEYS = {{ filter_mapr_keys|escape|safe }}; - const GALLERY_INDEX = "{% url 'webgallery_index' %}"; + var FILTER_KEYS = {{ filter_keys|safe }}; + var FILTER_MAPR_KEYS = {{ filter_mapr_keys|safe }}; + // e.g. GALLEY_INDEX/api-gallery/thumbnails for loading from IDR + const GALLERY_INDEX = "{{ gallery_index }}"; + // this is the home of this app, e.g. for GALLERY_HOME/search/ + const GALLERY_HOME = "{% url 'idr_gallery_index' %}"; const BASE_URL = "{{ base_url }}"; - const CATEGORY_QUERIES = {{ category_queries|escape|safe }}; - var TITLE_KEYS = {{ TITLE_KEYS|escape|safe }}; - var STUDY_SHORT_NAME = {{ STUDY_SHORT_NAME|escape|safe }}; - var SUPER_CATEGORIES = {{ SUPER_CATEGORIES|escape|safe }}; - var SUPER_CATEGORY {% if super_category %} = {{ super_category|escape|safe }} {% endif %}; + const CATEGORY_QUERIES = {{ category_queries|safe }}; + var TITLE_KEYS = {{ TITLE_KEYS|safe }}; + var STUDY_SHORT_NAME = {{ STUDY_SHORT_NAME|safe }}; + var SUPER_CATEGORIES = {{ SUPER_CATEGORIES|safe }}; + var SUPER_CATEGORY {% if super_category %} = {{ super_category|safe }} {% endif %}; var STATIC_DIR = "{% static 'gallery/' %}"; </script> -<script src="{% static 'gallery/search.js' %}"></script> +<script src="{% static 'idr_gallery/search.js' %}?_={{VERSION}}"></script> +<script src="{% static 'idr_gallery/autocomplete.js' %}?_={{VERSION}}"></script> {% endblock %} diff --git a/idr_gallery/urls.py b/idr_gallery/urls.py new file mode 100644 index 00000000..75e09d56 --- /dev/null +++ b/idr_gallery/urls.py @@ -0,0 +1,25 @@ +from django.conf.urls import url +from .gallery_settings import SUPER_CATEGORIES + +from . import views + +urlpatterns = [ + # index 'home page' of the idr_gallery app + url(r'^$', views.index, name='idr_gallery_index'), + + # All settings as JSON + url(r'^gallery_settings/$', views.gallery_settings), + + # Search page shows Projects / Screens filtered by Map Annotation + url(r'^search/$', views.index, {'super_category': None, 'template': 'idr_gallery/search.html'}), + + # Supports e.g. ?project=1&project=2&screen=3 + url(r'^gallery-api/thumbnails/$', views.api_thumbnails, + name='idr_gallery_api_thumbnails'), +] + +for c in SUPER_CATEGORIES: + urlpatterns.append(url(r'^%s/$' % c, views.index, {'super_category': c}, + name="gallery_super_category")) + urlpatterns.append(url(r'^%s/search/$' % c, views.index, + {'super_category': c, 'template': 'idr_gallery/search.html'})) diff --git a/idr_gallery/version.py b/idr_gallery/version.py new file mode 100644 index 00000000..237b47d6 --- /dev/null +++ b/idr_gallery/version.py @@ -0,0 +1,4 @@ + +# This can be loaded via the app. +# It will be updated by bumpversion +VERSION = '3.4.2.dev0' diff --git a/idr_gallery/views.py b/idr_gallery/views.py new file mode 100644 index 00000000..d1fbd521 --- /dev/null +++ b/idr_gallery/views.py @@ -0,0 +1,178 @@ +from django.http import Http404 +from django.urls import reverse, NoReverseMatch +import json +import logging +import base64 + +import omero +from omero.rtypes import wrap, rlong +from omeroweb.webclient.decorators import login_required, render_response +from omeroweb.api.decorators import login_required as api_login_required +from omeroweb.api.api_settings import API_MAX_LIMIT + +try: + from omero_marshal import get_encoder +except ImportError: + get_encoder = None + +from . import gallery_settings as settings +from .data.background_images import IDR_IMAGES, TISSUE_IMAGES, CELL_IMAGES +from .data.tabs import TABS +from .version import VERSION + +logger = logging.getLogger(__name__) +MAX_LIMIT = max(1, API_MAX_LIMIT) + +@login_required() +@render_response() +def index(request, super_category=None, conn=None, **kwargs): + """ + Home page shows a list of groups OR a set of 'categories' from + user-configured queries. + """ + + category_queries = settings.CATEGORY_QUERIES + # template is different for '/search' page + context = {'template': kwargs.get('template', "idr_gallery/index.html")} + context['favicon'] = settings.FAVICON + context['gallery_title'] = settings.GALLERY_TITLE + context['top_right_links'] = settings.TOP_RIGHT_LINKS + context['top_left_logo'] = settings.TOP_LEFT_LOGO + context['IDR_STUDIES_URL'] = settings.IDR_STUDIES_URL + try: + href = context['top_left_logo'].get('href', 'idr_gallery_index') + context['top_left_logo']['href'] = reverse(href) + except NoReverseMatch: + pass + # used by /search page + context['SUPER_CATEGORIES'] = json.dumps(settings.SUPER_CATEGORIES) + context['filter_keys'] = settings.FILTER_KEYS + context['TITLE_KEYS'] = json.dumps(settings.TITLE_KEYS) + context['STUDY_SHORT_NAME'] = json.dumps(settings.STUDY_SHORT_NAME) + context['filter_mapr_keys'] = json.dumps( + settings.FILTER_MAPR_KEYS) + context['super_categories'] = settings.SUPER_CATEGORIES + category = settings.SUPER_CATEGORIES.get(super_category) + if category is not None: + category['id'] = super_category + context['super_category'] = json.dumps(category) + context['category'] = super_category + base_url = reverse('index') + if settings.BASE_URL is not None: + base_url = settings.BASE_URL + context['base_url'] = base_url + context['gallery_index'] = reverse('idr_gallery_index') + if settings.GALLERY_INDEX is not None: + context['gallery_index'] = settings.GALLERY_INDEX + context['category_queries'] = json.dumps(category_queries) + context["idr_images"] = IDR_IMAGES + if super_category == "cell": + context["idr_images"] = CELL_IMAGES + elif super_category == "tissue": + context["idr_images"] = TISSUE_IMAGES + context["TABS"] = TABS + context["VERSION"] = VERSION + return context + + +@render_response() +def gallery_settings(request): + """Return all settings as JSON.""" + + attrs = ['CATEGORY_QUERIES', + 'GALLERY_TITLE', + 'FILTER_KEYS', + 'TITLE_KEYS', + 'FILTER_MAPR_KEYS', + 'SUPER_CATEGORIES', + 'BASE_URL', + 'TOP_RIGHT_LINKS', + 'TOP_LEFT_LOGO', + 'FAVICON', + 'STUDY_SHORT_NAME', + ] + + context = {} + for attr in attrs: + try: + context[attr] = getattr(settings, attr) + except AttributeError: + pass + + return context + + +def _get_study_images(conn, obj_type, obj_id, limit=1, offset=0, tag_text=None): + + query_service = conn.getQueryService() + params = omero.sys.ParametersI() + params.addId(obj_id) + params.theFilter = omero.sys.Filter() + params.theFilter.limit = wrap(limit) + params.theFilter.offset = wrap(offset) + and_text_value = "" + if tag_text is not None: + params.addString("tag_text", tag_text) + and_text_value = " and annotation.textValue = :tag_text" + + if obj_type == "project": + query = "select i from Image as i"\ + " left outer join i.datasetLinks as dl"\ + " join dl.parent as dataset"\ + " left outer join dataset.projectLinks"\ + " as pl join pl.parent as project"\ + " left outer join i.annotationLinks as al"\ + " join al.child as annotation"\ + " where project.id = :id%s" % and_text_value + + elif obj_type == "screen": + query = ("select i from Image as i" + " left outer join i.wellSamples as ws" + " join ws.well as well" + " join well.plate as pt" + " left outer join pt.screenLinks as sl" + " join sl.parent as screen" + " left outer join i.annotationLinks as al"\ + " join al.child as annotation"\ + " where screen.id = :id%s" + " order by well.column, well.row" % and_text_value) + + objs = query_service.findAllByQuery(query, params, conn.SERVICE_OPTS) + + return objs + + +@render_response() +@api_login_required() # 403 JsonResponse if not logged in +def api_thumbnails(request, conn=None, **kwargs): + """ + Return data like + { project-1: {thumbnail: base64data, image: {id:1}} } + """ + project_ids = request.GET.getlist('project') + screen_ids = request.GET.getlist('screen') + + image_ids = {} + for obj_type, ids in zip(['project', 'screen'], [project_ids, screen_ids]): + for obj_id in ids: + images = _get_study_images(conn, obj_type, obj_id, tag_text="Study Example Image") + if len(images) == 0: + # None found with Tag - just load untagged image + images = _get_study_images(conn, obj_type, obj_id) + if len(images) > 0: + image_ids[images[0].id.val] = "%s-%s" % (obj_type, obj_id) + + thumbnails = conn.getThumbnailSet([rlong(i) for i in image_ids.keys()], 96) + rv = {} + for i, obj_id in image_ids.items(): + rv[obj_id] = {"image": {'id': i}} + try: + t = thumbnails[i] + if len(t) > 0: + # replace thumbnail urls by base64 encoded image + rv[obj_id]["thumbnail"] = ("data:image/jpeg;base64,%s" % + base64.b64encode(t).decode("utf-8")) + + except KeyError: + logger.error("Thumbnail not available. (img id: %d)" % i) + return rv diff --git a/omero_gallery/__init__.py b/omero_gallery/__init__.py deleted file mode 100644 index 6417a94b..00000000 --- a/omero_gallery/__init__.py +++ /dev/null @@ -1 +0,0 @@ -default_app_config = 'omero_gallery.apps.GalleryAppConfig' diff --git a/omero_gallery/static/gallery/categories.js b/omero_gallery/static/gallery/categories.js deleted file mode 100644 index a7005c3b..00000000 --- a/omero_gallery/static/gallery/categories.js +++ /dev/null @@ -1,369 +0,0 @@ -"use strict"; - -// Copyright (C) 2019-2020 University of Dundee & Open Microscopy Environment. -// All rights reserved. -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// NB: SOURCE FILES are under /src. Compiled files are under /static/ -// loaded below -var mapr_settings = {}; // Model for loading Projects, Screens and their Map Annotations - -var model = new StudiesModel(); // ----- event handling -------- - -document.getElementById('maprConfig').onchange = function (event) { - document.getElementById('maprQuery').value = ''; - var value = event.target.value.replace('mapr_', ''); - var placeholder = "Type to filter values..."; - - if (mapr_settings[value]) { - placeholder = "Type ".concat(mapr_settings[value]['default'][0], "..."); - } - - document.getElementById('maprQuery').placeholder = placeholder; // Show all autocomplete options... - - $("#maprQuery").focus(); - render(); -}; - -document.getElementById('maprQuery').onfocus = function (event) { - $("#maprQuery").autocomplete("search", event.target.value); -}; // ------ AUTO-COMPLETE ------------------- - - -function showSpinner() { - document.getElementById('spinner').style.visibility = 'visible'; -} - -function hideSpinner() { - document.getElementById('spinner').style.visibility = 'hidden'; -} - -$("#maprQuery").keyup(function (event) { - if (event.which == 13) { - var configId = document.getElementById("maprConfig").value; - document.location.href = "search/?query=".concat(configId, ":").concat(event.target.value); - } -}).autocomplete({ - autoFocus: false, - delay: 1000, - source: function source(request, response) { - // if configId is not from mapr, we filter on mapValues... - var configId = document.getElementById("maprConfig").value; - - if (configId.indexOf('mapr_') != 0) { - var matches; - - if (configId === 'Name') { - matches = model.getStudiesNames(request.term); - } else if (configId === 'Group') { - matches = model.getStudiesGroups(request.term); - } else { - matches = model.getKeyValueAutoComplete(configId, request.term); - } - - response(matches); - return; - } // Don't handle empty query for mapr - - - if (request.term.length == 0) { - return; - } // Auto-complete to filter by mapr... - - - configId = configId.replace('mapr_', ''); - var case_sensitive = false; - var requestData = { - case_sensitive: case_sensitive - }; - var url; - - if (request.term.length === 0) { - // Try to list all top-level values. - // This works for 'wild-card' configs where number of values is small e.g. Organism - // But will return empty list for e.g. Gene - url = "".concat(BASE_URL, "mapr/api/").concat(configId, "/"); - requestData.orphaned = true; - } else { - // Find auto-complete matches - url = "".concat(BASE_URL, "mapr/api/autocomplete/").concat(configId, "/"); - requestData.value = case_sensitive ? request.term : request.term.toLowerCase(); - requestData.query = true; // use a 'like' HQL query - } - - showSpinner(); - $.ajax({ - dataType: "json", - type: 'GET', - url: url, - data: requestData, - success: function success(data) { - hideSpinner(); - - if (request.term.length === 0) { - // Top-level terms in 'maps' - if (data.maps && data.maps.length > 0) { - var terms = data.maps.map(function (m) { - return m.id; - }); - terms.sort(); - response(terms); - } - } else if (data.length > 0) { - response($.map(data, function (item) { - return item; - })); - } else { - response([{ - label: 'No results found.', - value: -1 - }]); - } - }, - error: function error(data) { - hideSpinner(); - response([{ - label: 'Error occured.', - value: -1 - }]); - } - }); - }, - minLength: 0, - open: function open() {}, - close: function close() { - // $(this).val(''); - return false; - }, - focus: function focus(event, ui) {}, - select: function select(event, ui) { - if (ui.item.value == -1) { - // Ignore 'No results found' - return false; - } // show temp message in case loading search page is slow - - - $(this).val("loading search results..."); // Load search page... - - var configId = document.getElementById("maprConfig").value; - document.location.href = "search/?query=".concat(configId, ":").concat(ui.item.value); - return false; - } -}).data("ui-autocomplete")._renderItem = function (ul, item) { - return $("<li>").append("<a>" + item.label + "</a>").appendTo(ul); -}; // ------------ Render ------------------------- - - -function render() { - document.getElementById('studies').innerHTML = ""; - var categories = Object.keys(CATEGORY_QUERIES); // Sort by index - - categories.sort(function (a, b) { - var idxA = CATEGORY_QUERIES[a].index; - var idxB = CATEGORY_QUERIES[b].index; - return idxA > idxB ? 1 : idxA < idxB ? -1 : 0; - }); // Link to the study in webclient... - - var linkFunc = function linkFunc(studyData) { - var type = studyData['@type'].split('#')[1].toLowerCase(); - return "".concat(BASE_URL, "webclient/?show=").concat(type, "-").concat(studyData['@id']); - }; - - categories.forEach(function (category) { - var cat = CATEGORY_QUERIES[category]; - var query = cat.query; // Find matching studies - - var matches = model.filterStudiesByMapQuery(query); - if (matches.length == 0) return; - var elementId = cat.label; - var div = document.createElement("div"); // If only ONE category... - - if (categories.length == 1) { - // list studies in a grid, without category.label - div.innerHTML = "<div id=\"".concat(elementId, "\" class=\"row horizontal studiesLayout\"></div>"); - div.className = "row"; - } else { - div.innerHTML = "\n <h1 title=\"".concat(query, "\" style=\"margin-left:10px\">\n ").concat(cat.label, " (").concat(matches.length, ")\n </h1>\n <div class=\"category\">\n <div id=\"").concat(elementId, "\"></div>\n </div>\n "); - } - - document.getElementById('studies').appendChild(div); - matches.forEach(function (study) { - return renderStudy(study, elementId, linkFunc); - }); - }); // Now we iterate all Studies in DOM, loading image ID for link and thumbnail - - loadStudyThumbnails(); -} - -function renderStudy(studyData, elementId, linkFunc) { - // Add Project or Screen to the page - var title; - - for (var i = 0; i < TITLE_KEYS.length; i++) { - title = model.getStudyValue(studyData, TITLE_KEYS[i]); - - if (title) { - break; - } - } - - if (!title) { - title = studyData.Name; - } - - var type = studyData['@type'].split('#')[1].toLowerCase(); - var studyLink = linkFunc(studyData); // save for later - - studyData.title = title; - var desc = studyData.Description; - var studyDesc; - - if (desc) { - // If description contains title, use the text that follows - if (title.length > 0 && desc.indexOf(title) > -1) { - desc = desc.split(title)[1]; - } // Remove blank lines (and first 'Experiment Description' line) - - - studyDesc = desc.split('\n').filter(function (l) { - return l.length > 0; - }).filter(function (l) { - return l !== 'Experiment Description' && l !== 'Screen Description'; - }).join('\n'); - - if (studyDesc.indexOf('Version History') > 1) { - studyDesc = studyDesc.split('Version History')[0]; - } - } - - var shortName = getStudyShortName(studyData); - var authors = model.getStudyValue(studyData, "Publication Authors") || ""; // Function (and template) are defined where used in index.html - - var html = studyHtml({ - studyLink: studyLink, - studyDesc: studyDesc, - shortName: shortName, - title: title, - authors: authors, - BASE_URL: BASE_URL, - type: type - }, studyData); - var div = document.createElement("div"); - div.innerHTML = html; - div.className = "row study "; - div.dataset.obj_type = type; - div.dataset.obj_id = studyData['@id']; - document.getElementById(elementId).appendChild(div); -} // --------- Render utils ----------- - - -function studyHtml(props, studyData) { - var pubmed = model.getStudyValue(studyData, 'PubMed ID'); - - if (pubmed) { - pubmed = pubmed.split(" ")[1]; - } - - ; - var author = props.authors.split(',')[0] || ''; - - if (author) { - author = "".concat(author, " et al."); - author = author.length > 23 ? author.slice(0, 20) + '...' : author; - } - - return "\n <div style='white-space:nowrap'>\n ".concat(props.shortName, "\n ").concat(pubmed ? "<a class='pubmed' target=\"_blank\" href=\"".concat(pubmed, "\"> ").concat(author, "</a>") : author, "\n </div>\n <div class=\"studyImage\">\n <a target=\"_blank\" href=\"").concat(props.studyLink, "\">\n <div style=\"height: 100%; width: 100%\">\n <div class=\"studyText\">\n <p title='").concat(props.studyDesc || '', "'>\n ").concat(props.title, "\n </p>\n </div>\n <div class=\"studyAuthors\">\n ").concat(props.authors, "\n </div>\n </div>\n </a>\n <a class=\"viewerLink\" title=\"Open image in viewer\" target=\"_blank\"\n href=\"\">\n <i class=\"fas fa-eye\"></i>\n </a>\n </div>\n "); -} - -function loadStudyThumbnails() { - var ids = []; // Collect study IDs 'project-1', 'screen-2' etc - - $('div.study').each(function () { - var obj_id = $(this).attr('data-obj_id'); - var obj_type = $(this).attr('data-obj_type'); - - if (obj_id && obj_type) { - ids.push(obj_type + '-' + obj_id); - } - }); // Load images - - model.loadStudiesThumbnails(ids, function (data) { - // data is e.g. { project-1: {thumbnail: base64data, image: {id:1}} } - for (var id in data) { - var obj_type = id.split('-')[0]; - var obj_id = id.split('-')[1]; - var elements = document.querySelectorAll("div[data-obj_type=\"".concat(obj_type, "\"][data-obj_id=\"").concat(obj_id, "\"]")); - - for (var e = 0; e < elements.length; e++) { - // Find all studies matching the study ID and set src on image - var element = elements[e]; - var studyImage = element.querySelector('.studyImage'); - studyImage.style.backgroundImage = "url(".concat(data[id].thumbnail, ")"); // viewer link - - var iid = data[id].image.id; - var link = "".concat(BASE_URL, "webclient/img_detail/").concat(iid, "/"); - element.querySelector('a.viewerLink').href = link; - } - } - }); -} - -function renderStudyKeys() { - if (FILTER_KEYS.length > 0) { - var html = FILTER_KEYS.map(function (key) { - if (key.label && key.value) { - return "<option value=\"".concat(key.value, "\">").concat(key.label, "</option>"); - } - - return "<option value=\"".concat(key, "\">").concat(key, "</option>"); - }).join("\n"); - document.getElementById('studyKeys').innerHTML = html; // Show the <optgroup> and the whole form - - document.getElementById('studyKeys').style.display = 'block'; - document.getElementById('search-form').style.display = 'block'; - } -} - -renderStudyKeys(); // ----------- Load / Filter Studies -------------------- -// Do the loading and render() when done... - -model.loadStudies(function () { - // Immediately filter by Super category - if (SUPER_CATEGORY && SUPER_CATEGORY.query) { - model.studies = model.filterStudiesByMapQuery(SUPER_CATEGORY.query); - } - - render(); -}); // Load MAPR config - -fetch(BASE_URL + 'mapr/api/config/').then(function (response) { - return response.json(); -}).then(function (data) { - mapr_settings = data; - var options = FILTER_MAPR_KEYS.map(function (key) { - var config = mapr_settings[key]; - - if (config) { - return "<option value=\"mapr_".concat(key, "\">").concat(config.label, "</option>"); - } else { - return ""; - } - }); - - if (options.length > 0) { - document.getElementById('maprKeys').innerHTML = options.join("\n"); // Show the <optgroup> and the whole form - - document.getElementById('maprKeys').style.display = 'block'; - document.getElementById('search-form').style.display = 'block'; - } -})["catch"](function (err) { - console.log("mapr not installed (config not available)"); -}); \ No newline at end of file diff --git a/omero_gallery/static/gallery/model.js b/omero_gallery/static/gallery/model.js deleted file mode 100644 index 541d084d..00000000 --- a/omero_gallery/static/gallery/model.js +++ /dev/null @@ -1,627 +0,0 @@ -"use strict"; - -function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } - -function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } - -function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } - -function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } - -function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } - -function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } - -function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } - -function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } - -// Copyright (C) 2019-2020 University of Dundee & Open Microscopy Environment. -// All rights reserved. -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// NB: SOURCE FILES are under /src. Compiled files are under /static/ -var StudiesModel = function StudiesModel() { - "use strict"; - - this.base_url = BASE_URL; - this.studies = []; - this.images = {}; - return this; -}; - -StudiesModel.prototype.getStudyById = function getStudyById(typeId) { - // E.g. 'project-1', or 'screen-2' - var objType = typeId.split('-')[0]; - var id = typeId.split('-')[1]; - - for (var i = 0; i < this.studies.length; i++) { - var study = this.studies[i]; - - if (study['@id'] == id && study['@type'].split('#')[1].toLowerCase() == objType) { - return study; - } - } -}; - -StudiesModel.prototype.getStudiesNames = function getStudiesNames(filterQuery) { - var names = this.studies.map(function (s) { - return s.Name; - }); - - if (filterQuery) { - names = names.filter(function (name) { - return name.toLowerCase().indexOf(filterQuery) > -1; - }); - } - - names.sort(function (a, b) { - return a.toLowerCase() > b.toLowerCase() ? 1 : -1; - }); - return names; -}; - -StudiesModel.prototype.getStudiesGroups = function getStudiesGroups(filterQuery) { - var names = []; - this.studies.forEach(function (study) { - var groupName = study['omero:details'].group.Name; - - if (names.indexOf(groupName) === -1) { - names.push(groupName); - } - }); - - if (filterQuery) { - names = names.filter(function (name) { - return name.toLowerCase().indexOf(filterQuery) > -1; - }); - } - - names.sort(function (a, b) { - return a.toLowerCase() > b.toLowerCase() ? 1 : -1; - }); - return names; -}; - -StudiesModel.prototype.getStudyValue = function getStudyValue(study, key) { - if (!study.mapValues) return; - - for (var i = 0; i < study.mapValues.length; i++) { - var kv = study.mapValues[i]; - - if (kv[0] === key) { - return kv[1]; - } - } -}; - -StudiesModel.prototype.getStudyValues = function getStudyValues(study, key) { - if (!study.mapValues) { - return []; - } - - var matches = []; - - for (var i = 0; i < study.mapValues.length; i++) { - var kv = study.mapValues[i]; - - if (kv[0] === key) { - matches.push(kv[1]); - } - } - - return matches; -}; - -StudiesModel.prototype.getKeyValueAutoComplete = function getKeyValueAutoComplete(key, inputText) { - var _this = this; - - inputText = inputText.toLowerCase(); // Get values for key from each study - - var values = []; - this.studies.forEach(function (study) { - var v = _this.getStudyValues(study, key); - - for (var i = 0; i < v.length; i++) { - values.push(v[i]); - } - }); // We want values that match inputText - // Except for "Publication Authors", where we want words - // Create dict of {lowercaseValue: origCaseValue} - - var matchCounts = values.reduce(function (prev, value) { - var matches = []; - - if (key == "Publication Authors") { - // Split surnames, ignoring AN initials. - var names = value.split(/,| and | & /).map(function (n) { - // Want the surname from e.g. 'Jan Ellenberg' or 'Held M' or 'Øyvind Ødegård-Fougner' - var words = n.split(" ").filter(function (w) { - return w.match(/[a-z]/g); - }); - if (words && words.length == 1) return words[0]; // Surname only - - return words && words.length > 1 ? words.slice(1).join(" ") : ''; - }).filter(function (w) { - return w.length > 0; - }); - matches = names.filter(function (name) { - return name.toLowerCase().indexOf(inputText) > -1; - }); - } else if (value.toLowerCase().indexOf(inputText) > -1) { - matches.push(value); - } - - matches.forEach(function (match) { - if (!prev[match.toLowerCase()]) { - // key is lowercase, value is original case - prev[match.toLowerCase()] = { - value: match, - count: 0 - }; - } // also keep count of matches - - - prev[match.toLowerCase()].count++; - }); - return prev; - }, {}); // Make into list and sort by: - // match at start of phrase > match at start of word > other match - - var matchList = []; - - for (key in matchCounts) { - var matchScore = 1; - - if (key.indexOf(inputText) == 0) { - // best match if our text STARTS WITH inputText - matchScore = 3; - } else if (key.indexOf(" " + inputText) > -1) { - // next best if a WORD starts with inputText - matchScore = 2; - } // Make a list of sort score, orig text (NOT lowercase keys) and count - - - matchList.push([matchScore, matchCounts[key].value, matchCounts[key].count]); - } // Sort by the matchScore (hightest first) - - - matchList.sort(function (a, b) { - if (a[0] < b[0]) return 1; - if (a[0] > b[0]) return -1; // equal score. Sort by value (lowest first) - - if (a[1].toLowerCase() > b[1].toLowerCase()) return 1; - return -1; - }); // Return the matches - - return matchList.map(function (m) { - // Auto-complete uses {label: 'X (n)', value: 'X'} - return { - label: "".concat(m[1], " (").concat(m[2], ")"), - value: m[1] - }; - }).filter(function (m) { - return m.value.length > 0; - }); -}; - -StudiesModel.prototype.loadStudies = function loadStudies(callback) { - var _this2 = this; - - // Load Projects AND Screens, sort them and render... - Promise.all([fetch(this.base_url + "api/v0/m/projects/?childCount=true"), fetch(this.base_url + "api/v0/m/screens/?childCount=true")]).then(function (responses) { - return Promise.all(responses.map(function (res) { - return res.json(); - })); - }).then(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - projects = _ref2[0], - screens = _ref2[1]; - - _this2.studies = projects.data; - _this2.studies = _this2.studies.concat(screens.data); // ignore empty studies with no images - - _this2.studies = _this2.studies.filter(function (study) { - return study['omero:childCount'] > 0; - }); // sort by name, reverse - - _this2.studies.sort(function (a, b) { - var nameA = a.Name.toUpperCase(); - var nameB = b.Name.toUpperCase(); - - if (nameA < nameB) { - return 1; - } - - if (nameA > nameB) { - return -1; - } // names must be equal - - - return 0; - }); // load Map Anns for Studies... - - - _this2.loadStudiesMapAnnotations(callback); - })["catch"](function (err) { - console.error(err); - }); -}; - -StudiesModel.prototype.loadStudiesThumbnails = function loadStudiesThumbnails(ids, callback) { - var _this3 = this; - - var url = GALLERY_INDEX + "gallery-api/thumbnails/"; // remove duplicates - - ids = _toConsumableArray(new Set(ids)); // find any thumbnails we already have in hand... - - var found = {}; - var toFind = []; - ids.forEach(function (id) { - var study = _this3.getStudyById(id); - - if (study && study.image && study.thumbnail) { - found[id] = { - image: study.image, - thumbnail: study.thumbnail - }; - } else { - toFind.push(id); - } - }); - - if (Object.keys(found).length > 0) { - callback(found); - } - - toFind = toFind.map(function (id) { - return id.replace('-', '='); - }); - var batchSize = 10; - - while (toFind.length > 0) { - var data = toFind.slice(0, batchSize).join("&"); - fetch(url + '?' + data).then(function (response) { - return response.json(); - }).then(function (data) { - for (var studyId in data) { - var study = _this3.getStudyById(studyId); - - if (data[studyId]) { - study.image = data[studyId].image; - study.thumbnail = data[studyId].thumbnail; - } - } - - if (callback) { - callback(data); - } - }); - toFind = toFind.slice(batchSize); - } -}; - -StudiesModel.prototype.loadStudiesMapAnnotations = function loadStudiesMapAnnotations(callback) { - var _this4 = this; - - var url = this.base_url + "webclient/api/annotations/?type=map"; - var data = this.studies.map(function (study) { - return "".concat(study['@type'].split('#')[1].toLowerCase(), "=").concat(study['@id']); - }).join("&"); - url += '&' + data; - fetch(url).then(function (response) { - return response.json(); - }).then(function (data) { - // populate the studies array... - // dict of {'project-1' : key-values} - var annsByParentId = {}; - data.annotations.forEach(function (ann) { - var key = ann.link.parent["class"]; // 'ProjectI' - - key = key.substr(0, key.length - 1).toLowerCase(); - key += '-' + ann.link.parent.id; // project-1 - - if (!annsByParentId[key]) { - annsByParentId[key] = []; - } - - annsByParentId[key] = annsByParentId[key].concat(ann.values); - }); // Add mapValues to studies... - - _this4.studies = _this4.studies.map(function (study) { - // Also set 'type':'screen', 'objId': 'screen-123' - study.type = study['@type'].split('#')[1].toLowerCase(); - study.id = study['@id']; - study.objId = "".concat(study.type, "-").concat(study['@id']); - var values = annsByParentId[study.objId]; - - if (values) { - study.mapValues = values; - - var releaseDate = _this4.getStudyValue(study, 'Release Date'); - - if (releaseDate) { - study.date = new Date(releaseDate); - - if (isNaN(study.date.getTime())) { - study.date = undefined; - } - } - } - - return study; - }); - - if (callback) { - callback(); - } - - ; - }); -}; - -StudiesModel.prototype.filterStudiesByMapQuery = function filterStudiesByMapQuery(query) { - if (query.startsWith("FIRST") || query.startsWith("LAST")) { - // E.g. query is 'FIRST10:date' sort by 'date' and return first 10 - var limit = parseInt(query.replace('FIRST', '').replace('LAST', '')); - var attr = query.split(':')[1]; - var desc = query.startsWith("FIRST") ? -1 : 1; // first filter studies, remove those that don't have 'attr' - - var sorted = this.studies.filter(function (study) { - return study[attr] !== undefined; - }).sort(function (a, b) { - var aVal = a[attr]; - var bVal = b[attr]; // If string, use lowercase - - aVal = aVal.toLowerCase ? aVal.toLowerCase() : aVal; - bVal = bVal.toLowerCase ? bVal.toLowerCase() : bVal; - return aVal < bVal ? desc : aVal > bVal ? -desc : 0; - }); - return sorted.slice(0, limit); - } - - var matches = this.studies.filter(function (study) { - // If no key-values loaded, filter out - if (!study.mapValues) { - return false; - } - - var match = false; // first split query by AND and OR - - var ors = query.split(' OR '); - ors.forEach(function (term) { - var allAnds = true; - var ands = term.split(' AND '); - ands.forEach(function (mustMatch) { - var queryKeyValue = mustMatch.split(":"); - var valueMatch = false; // check all key-values (may be duplicate keys) for value that matches - - for (var i = 0; i < study.mapValues.length; i++) { - var kv = study.mapValues[i]; - - if (kv[0] === queryKeyValue[0]) { - var value = queryKeyValue[1].trim(); - - if (value.substr(0, 4) === 'NOT ') { - value = value.replace('NOT ', ''); - - if (kv[1].toLowerCase().indexOf(value.toLowerCase()) == -1) { - valueMatch = true; - } - } else if (kv[1].toLowerCase().indexOf(value.toLowerCase()) > -1) { - valueMatch = true; - } - } - } // if not found, then our AND term fails - - - if (!valueMatch) { - allAnds = false; - } - }); - - if (allAnds) { - match = true; - } - }); - return match; - }); - return matches; -}; - -StudiesModel.prototype.loadImage = function loadImage(obj_type, obj_id, callback) { - var _this5 = this; - - // Get a sample image ID for 'screen' or 'project' - var key = "".concat(obj_type, "-").concat(obj_id); // check cache - - if (this.images[key]) { - callback(this.images[key]); - return; - } - - var limit = 20; - - if (obj_type == 'screen') { - var url = "".concat(this.base_url, "api/v0/m/screens/").concat(obj_id, "/plates/"); - url += '?limit=1'; // just get first plate - - fetch(url).then(function (response) { - return response.json(); - }).then(function (data) { - obj = data.data[0]; // Jump into the 'middle' of plate to make sure Wells have images - // NB: Some plates don't have Well at each Row/Column spot. Well_count < Rows * Cols * 0.5 - - var offset = Math.max(0, parseInt(obj.Rows * obj.Columns * 0.25) - limit); - var url = "".concat(_this5.base_url, "api/v0/m/plates/").concat(obj['@id'], "/wells/?limit=").concat(limit, "&offset=").concat(offset); - return fetch(url); - }).then(function (response) { - return response.json(); - }).then(function (data) { - var wellSample; - - for (var w = 0; w < data.data.length; w++) { - if (data.data[w].WellSamples) { - wellSample = data.data[w].WellSamples[0]; - } - } - - if (!wellSample) { - console.log('No WellSamples in first Wells!', data); - return; - } - - _this5.images[key] = wellSample.Image; - callback(_this5.images[key]); - return; - }); - } else if (obj_type == 'project') { - var _url = "".concat(this.base_url, "api/v0/m/projects/").concat(obj_id, "/datasets/"); - - _url += '?limit=1'; // just get first plate - - fetch(_url).then(function (response) { - return response.json(); - }).then(function (data) { - obj = data.data[0]; - - if (!obj) { - // No Dataset in Project: ' + obj_id; - return; - } - - var url = "".concat(_this5.base_url, "api/v0/m/datasets/").concat(obj['@id'], "/images/?limit=1"); - return fetch(url); - }) // Handle undefined if no Datasets in Project... - .then(function (response) { - return response ? response.json() : {}; - }).then(function (data) { - if (data && data.data && data.data[0]) { - var image = data.data[0]; - _this5.images[key] = image; - callback(_this5.images[key]); - } - })["catch"](function (error) { - console.error("Error loading Image for Project: " + obj_id, error); - }); - } -}; - -StudiesModel.prototype.getStudyImage = function getStudyImage(obj_type, obj_id, callback) { - var _this6 = this; - - // Get a sample image ID for 'screen' or 'project' - var key = "".concat(obj_type, "-").concat(obj_id); // check cache - - if (this.images[key]) { - callback(this.images[key]); - return; - } - - var url = "".concat(GALLERY_INDEX, "gallery-api/").concat(obj_type, "s/").concat(obj_id, "/images/?limit=1"); - fetch(url).then(function (response) { - return response.json(); - }).then(function (data) { - var images = data.data; - - if (images.length > 0) { - _this6.images[key] = images[0]; - } - - callback(_this6.images[key]); - return; - }); -}; - -function toTitleCase(text) { - if (!text || text.length == 0) return text; - return text[0].toUpperCase() + text.slice(1); -} - -var getStudyShortName = function getStudyShortName(study) { - var shortName = "".concat(toTitleCase(study.type), ": ").concat(study.id); - - if (STUDY_SHORT_NAME) { - for (var i = 0; i < STUDY_SHORT_NAME.length; i++) { - var key = STUDY_SHORT_NAME[i]['key']; - var value = void 0; - var newShortName = void 0; - - if (key === 'Name' || key === 'Description') { - value = study[key]; - } - - if (!value) { - value = model.getStudyValue(study, key); - } - - if (!value) { - continue; - } - - if (STUDY_SHORT_NAME[i]['regex'] && STUDY_SHORT_NAME[i]['template']) { - var re = new RegExp(STUDY_SHORT_NAME[i]['regex']); - var template = STUDY_SHORT_NAME[i]['template']; - newShortName = value.replace(re, template); - } else { - newShortName = value; - } - - if (newShortName) { - shortName = newShortName; - break; - } - } - } - - return shortName; -}; // startsWith polyfill for IE - - -if (!String.prototype.startsWith) { - String.prototype.startsWith = function (search, pos) { - return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; - }; -} // Object.assign polyfill for IE - - -if (typeof Object.assign !== 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { - // .length of function is 2 - 'use strict'; - - if (target === null || target === undefined) { - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource !== null && nextSource !== undefined) { - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - - return to; - }, - writable: true, - configurable: true - }); -} \ No newline at end of file diff --git a/omero_gallery/static/gallery/search.js b/omero_gallery/static/gallery/search.js deleted file mode 100644 index fa8ff60e..00000000 --- a/omero_gallery/static/gallery/search.js +++ /dev/null @@ -1,697 +0,0 @@ -"use strict"; - -// Copyright (C) 2019-2020 University of Dundee & Open Microscopy Environment. -// All rights reserved. -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// NB: SOURCE FILES are under /src. Compiled files are under /static/ -// Model for loading Projects, Screens and their Map Annotations -var model = new StudiesModel(); -var mapr_settings; - -function renderStudyKeys() { - if (FILTER_KEYS.length > 0) { - var html = FILTER_KEYS.map(function (key) { - if (key.label && key.value) { - return "<option value=\"".concat(key.value, "\">").concat(key.label, "</option>"); - } - - return "<option value=\"".concat(key, "\">").concat(key, "</option>"); - }).join("\n"); - document.getElementById('studyKeys').innerHTML = html; // Show the <optgroup> and the whole form - - document.getElementById('studyKeys').style.display = 'block'; - document.getElementById('search-form').style.display = 'block'; - } -} - -renderStudyKeys(); // FIRST, populate forms from query string - -function populateInputsFromSearch() { - var search = window.location.search.substr(1); - var query = ''; - var searchParams = search.split('&'); - - for (var i = 0; i < searchParams.length; i++) { - var paramSplit = searchParams[i].split('='); - - if (paramSplit[0] === 'query') { - query = paramSplit[1].replace(/%20/g, " "); - } - } - - if (query) { - var splitIndex = query.indexOf(':'); - var configId = query.slice(0, splitIndex); - var value = query.slice(splitIndex + 1); - - if (configId && value) { - document.getElementById("maprConfig").value = configId; - document.getElementById("maprQuery").value = value; - var key = configId.replace('mapr_', ''); - var placeholder = "Type to filter values..."; - - if (mapr_settings && mapr_settings[key]) { - placeholder = "Type ".concat(mapr_settings[key]['default'][0], "..."); - } - - document.getElementById('maprQuery').placeholder = placeholder; - } - } -} - -populateInputsFromSearch(); // ------------ Handle MAPR searching or filtering --------------------- - -function filterStudiesByMapr(value) { - $('#studies').removeClass('studiesLayout'); - var configId = document.getElementById("maprConfig").value.replace("mapr_", ""); - document.getElementById('studies').innerHTML = ""; - var key = mapr_settings[value] ? mapr_settings[value].all.join(" or ") : value; - showFilterSpinner("Finding images with ".concat(configId, ": ").concat(value, "...")); // Get all terms that match (NOT case_sensitive) - - var url = "".concat(BASE_URL, "mapr/api/").concat(configId, "/?value=").concat(value, "&case_sensitive=false&orphaned=true"); - $.getJSON(url, function (data) { - var maprTerms = data.maps.map(function (term) { - return term.id; - }); - var termUrls = maprTerms.map(function (term) { - return "".concat(BASE_URL, "mapr/api/").concat(configId, "/?value=").concat(term); - }); // Get results for All terms - - Promise.all(termUrls.map(function (url) { - return fetch(url); - })).then(function (responses) { - return Promise.all(responses.map(function (res) { - return res.json(); - })); - }).then(function (responses) { - hideFilterSpinner(); // filter studies by each response - - var studiesByTerm = responses.map(function (data) { - return filterStudiesByMaprResponse(data); - }); - renderMaprMessage(studiesByTerm, maprTerms); // Show table for each... - - studiesByTerm.forEach(function (studies, idx) { - if (studies.length > 0) { - renderMaprResultsTable(studies, maprTerms[idx]); - } - }); - }); // .fail(() => { - // document.getElementById('filterCount').innerHTML = "Request failed. Server may be busy." - // }) - }); -} - -function filterStudiesByMaprResponse(data) { - // filter studies by 'screens' and 'projects' - var imageCounts = {}; - data.screens.forEach(function (s) { - imageCounts["screen-".concat(s.id)] = s.extra.counter; - }); - data.projects.forEach(function (s) { - imageCounts["project-".concat(s.id)] = s.extra.counter; - }); - - var filterFunc = function filterFunc(study) { - var studyId = study['@type'].split('#')[1].toLowerCase() + '-' + study['@id']; - return imageCounts.hasOwnProperty(studyId); - }; - - var filteredStudies = model.studies.filter(filterFunc).map(function (study) { - var studyId = study['@type'].split('#')[1].toLowerCase() + '-' + study['@id']; - var studyData = Object.assign({}, study); - studyData.imageCount = imageCounts[studyId]; - return studyData; - }); - return filteredStudies; -} - -function renderMaprMessage(studiesByTerm, maprTerms) { - // for each term e.g. TOP2, top2 etc sum image counts from each study - var imageCount = studiesByTerm.reduce(function (count, studies) { - return count + studies.reduce(function (count, study) { - return count + study.imageCount; - }, 0); - }, 0); - var studyCount = studiesByTerm.reduce(function (count, studies) { - return count + studies.length; - }, 0); - var terms = maprTerms.join('/'); - var filterMessage = ""; - - if (studyCount === 0) { - filterMessage = noStudiesMessage(); - } else { - var configId = document.getElementById("maprConfig").value.replace('mapr_', ''); - var key = configId; - - if (mapr_settings && mapr_settings[configId]) { - key = mapr_settings[key].label; - } - - filterMessage = "<p class=\"filterMessage\">\n Found <strong>".concat(imageCount, "</strong> images with\n <strong>").concat(key, "</strong>: <strong>").concat(terms, "</strong>\n in <strong>").concat(studyCount, "</strong> stud").concat(studyCount == 1 ? 'y' : 'ies', "</strong></p>"); - } - - document.getElementById('filterCount').innerHTML = filterMessage; -} - -function renderMaprResultsTable(maprData, term) { - var configId = document.getElementById("maprConfig").value.replace("mapr_", ""); - var elementId = 'maprResultsTable' + term; - var html = "\n <h2>".concat(term, "</h2>\n <table class='maprResultsTable' style='margin-top:20px'>\n <tbody data-id='").concat(elementId, "'>\n <tr>\n <th>Study ID</th>\n <th>Organism</th>\n <th>Image count</th>\n <th>Title</th>\n <th>Sample Images</th>\n <th>Link</th>\n </tr>\n </tbody>\n </table>"); - $('#studies').append(html); - renderMapr(maprData, term); -} // ----- event handling -------- - - -document.getElementById('maprConfig').onchange = function (event) { - document.getElementById('maprQuery').value = ''; - var value = event.target.value.replace('mapr_', ''); - var placeholder = "Type to filter values..."; - - if (mapr_settings[value]) { - placeholder = "Type ".concat(mapr_settings[value]['default'][0], "..."); - } - - document.getElementById('maprQuery').placeholder = placeholder; // Show all autocomplete options... - - $("#maprQuery").focus(); - render(); -}; // We want to show auto-complete options when user -// clicks on the field. - - -function showAutocomplete(event) { - var configId = document.getElementById("maprConfig").value; - var autoCompleteValue = event.target.value; - - if (configId.indexOf('mapr_') != 0) { - // If not MAPR search, show all auto-complete results - autoCompleteValue = ''; - } - - $("#maprQuery").autocomplete("search", autoCompleteValue); -} - -document.getElementById('maprQuery').onfocus = function (event) { - showAutocomplete(event); -}; - -document.getElementById('maprQuery').onclick = function (event) { - showAutocomplete(event); -}; // ------ AUTO-COMPLETE ------------------- - - -function showSpinner() { - document.getElementById('spinner').style.visibility = 'visible'; -} - -function hideSpinner() { - document.getElementById('spinner').style.visibility = 'hidden'; -} // timeout to avoid flash of spinner - - -var filterSpinnerTimout; - -function showFilterSpinner(message) { - filterSpinnerTimout = setTimeout(function () { - document.getElementById('filterSpinnerMessage').innerHTML = message ? message : ''; - document.getElementById('filterSpinner').style.display = 'block'; - }, 500); -} - -function hideFilterSpinner() { - clearTimeout(filterSpinnerTimout); - document.getElementById('filterSpinnerMessage').innerHTML = ''; - document.getElementById('filterSpinner').style.display = 'none'; -} - -$("#maprQuery").keyup(function (event) { - if (event.which == 13) { - $(event.target).autocomplete("close"); - filterAndRender(); // Add to browser history. Handled by onpopstate on browser Back - - var configId = document.getElementById("maprConfig").value; - window.history.pushState({}, "", "?query=".concat(configId, ":").concat(event.target.value)); - } -}).autocomplete({ - autoFocus: false, - delay: 1000, - source: function source(request, response) { - // if configId is not from mapr, we filter on mapValues... - var configId = document.getElementById("maprConfig").value; - - if (configId.indexOf('mapr_') != 0) { - var matches; - - if (configId === 'Name') { - matches = model.getStudiesNames(request.term); - } else if (configId === 'Group') { - matches = model.getStudiesGroups(request.term); - } else { - matches = model.getKeyValueAutoComplete(configId, request.term); - } - - response(matches); // When not mapr, we filter while typing - - filterAndRender(); - return; - } // Don't handle empty query for mapr - - - if (request.term.length == 0) { - return; - } // Auto-complete to filter by mapr... - - - configId = configId.replace('mapr_', ''); - var case_sensitive = false; - var requestData = { - case_sensitive: case_sensitive - }; - var url; - - if (request.term.length === 0) { - // Try to list all top-level values. - // This works for 'wild-card' configs where number of values is small e.g. Organism - // But will return empty list for e.g. Gene - url = "".concat(BASE_URL, "mapr/api/").concat(configId, "/"); - requestData.orphaned = true; - } else { - // Find auto-complete matches - url = "".concat(BASE_URL, "mapr/api/autocomplete/").concat(configId, "/"); - requestData.value = case_sensitive ? request.term : request.term.toLowerCase(); - requestData.query = true; // use a 'like' HQL query - } - - showSpinner(); - $.ajax({ - dataType: "json", - type: 'GET', - url: url, - data: requestData, - success: function success(data) { - hideSpinner(); - - if (request.term.length === 0) { - // Top-level terms in 'maps' - if (data.maps && data.maps.length > 0) { - var terms = data.maps.map(function (m) { - return m.id; - }); - terms.sort(); - response(terms); - } - } else if (data.length > 0) { - response($.map(data, function (item) { - return item; - })); - } else { - response([{ - label: 'No results found.', - value: -1 - }]); - } - }, - error: function error(data) { - hideSpinner(); // E.g. status 504 for timeout - - response([{ - label: 'Loading auto-complete terms failed. Server may be busy.', - value: -1 - }]); - } - }); - }, - minLength: 0, - open: function open() {}, - close: function close() { - // $(this).val(''); - return false; - }, - focus: function focus(event, ui) {}, - select: function select(event, ui) { - if (ui.item.value == -1) { - // Ignore 'No results found' - return false; - } - - $(this).val(ui.item.value); - filterAndRender(); // Add to browser history. Handled by onpopstate on browser Back - - var configId = document.getElementById("maprConfig").value; - window.history.pushState({}, "", "?query=".concat(configId, ":").concat(ui.item.value)); - return false; - } -}).data("ui-autocomplete")._renderItem = function (ul, item) { - return $("<li>").append("<a>" + item.label + "</a>").appendTo(ul); -}; // ------------ Render ------------------------- - - -function filterAndRender() { - var configId = document.getElementById("maprConfig").value; - var value = document.getElementById("maprQuery").value; - - if (!value) { - render(); - return; - } - - if (configId.indexOf('mapr_') != 0) { - // filter studies by Key-Value pairs - var filterFunc = function filterFunc(study) { - var toMatch = value.toLowerCase(); - - if (configId === 'Name') { - return study.Name.toLowerCase().indexOf(toMatch) > -1; - } - - if (configId === 'Group') { - var group = study['omero:details'].group; - return group.Name.toLowerCase().indexOf(toMatch) > -1; - } // Filter by Map-Annotation Key-Value - - - var show = false; - - if (study.mapValues) { - study.mapValues.forEach(function (kv) { - if (kv[0] === configId && kv[1].toLowerCase().indexOf(toMatch) > -1) { - show = true; - } - }); - } - - return show; - }; - - render(filterFunc); - } else { - filterStudiesByMapr(value); - } -} - -function renderMapr(maprData, term) { - maprData.sort(function (a, b) { - return a.Name > b.Name ? 1 : -1; - }); - var elementId = 'maprResultsTable' + term; - var configId = document.getElementById("maprConfig").value; - - var linkFunc = function linkFunc(studyData) { - var type = studyData['@type'].split('#')[1].toLowerCase(); - var maprKey = configId.replace('mapr_', ''); - return "/mapr/".concat(maprKey, "/?value=").concat(term, "&show=").concat(type, "-").concat(studyData['@id']); - }; - - var elementSelector = "[data-id=\"".concat(elementId, "\"]"); - maprData.forEach(function (s) { - return renderStudy(s, elementSelector, linkFunc, maprHtml); - }); // load images for each study... - - $("[data-id=\"".concat(elementId, "\"] tr")).each(function () { - // load children in MAPR jsTree query to get images - var element = this; - var studyId = element.id; - var objId = studyId.split("-")[1]; - var objType = studyId.split("-")[0]; - if (!objId || !objType) return; - var childType = objType === "project" ? "datasets" : "plates"; - var configId = document.getElementById("maprConfig").value.replace('mapr_', ''); - var maprValue = term; // We want to link to the dataset or plate... - - var imgContainer; - var url = "".concat(BASE_URL, "mapr/api/").concat(configId, "/").concat(childType, "/?value=").concat(maprValue, "&id=").concat(objId); - fetch(url).then(function (response) { - return response.json(); - }).then(function (data) { - var firstChild = data[childType][0]; - imgContainer = "".concat(firstChild.extra.node, "-").concat(firstChild.id); - var imagesUrl = "".concat(BASE_URL, "mapr/api/").concat(configId, "/images/?value=").concat(maprValue, "&id=").concat(firstChild.id, "&node=").concat(firstChild.extra.node); - return fetch(imagesUrl); - }).then(function (response) { - return response.json(); - }).then(function (data) { - var html = data.images.slice(0, 3).map(function (i) { - return "\n <a href=\"".concat(BASE_URL, "webclient/img_detail/").concat(i.id, "/\"\n target=\"_blank\" title=\"Open image in viewer\" class=\"maprViewerLink\">\n <div>\n <img class=\"thumbnail\" src=\"").concat(STATIC_DIR, "images/transparent.png\"\n data-src=\"").concat(BASE_URL, "webgateway/render_thumbnail/").concat(i.id, "/\">\n <i class=\"fas fa-eye\"></i>\n </div>\n </a>"); - }).join(""); - var linkHtml = "<a target=\"_blank\" href=\"".concat(BASE_URL, "mapr/").concat(configId, "/?value=").concat(maprValue, "&show=").concat(imgContainer, "\">\n more...\n </a>"); // Find the container and add placeholder images html - - $("#" + element.id + " .exampleImages").html(html); - $("#" + element.id + " .exampleImagesLink").append(linkHtml); // Update the src to load the thumbnails. Timeout to let placeholder render while we wait for thumbs - - setTimeout(function () { - $('img', "#" + element.id).each(function (index, img) { - img.src = img.dataset.src; - }); - }, 0); - }); - }); -} - -function render(filterFunc) { - $('#studies').addClass('studiesLayout'); - document.getElementById('studies').innerHTML = ""; - - if (!filterFunc) { - document.getElementById('filterCount').innerHTML = ""; - return; - } - - var studiesToRender = model.studies; - - if (filterFunc) { - studiesToRender = model.studies.filter(filterFunc); - } - - var filterMessage = ""; - - if (studiesToRender.length === 0) { - filterMessage = noStudiesMessage(); - } else if (studiesToRender.length < model.studies.length) { - var configId = document.getElementById("maprConfig").value.replace('mapr_', ''); - configId = mapr_settings && mapr_settings[configId] || configId; - var maprValue = document.getElementById('maprQuery').value; - filterMessage = "<p class=\"filterMessage\">\n Found <strong>".concat(studiesToRender.length, "</strong> studies with\n <strong>").concat(configId, "</strong>: <strong>").concat(maprValue, "</strong></p>"); - } - - document.getElementById('filterCount').innerHTML = filterMessage; // By default, we link to the study itself in IDR... - - var linkFunc = function linkFunc(studyData) { - var type = studyData['@type'].split('#')[1].toLowerCase(); - return "".concat(BASE_URL, "webclient/?show=").concat(type, "-").concat(studyData['@id']); - }; - - var htmlFunc = studyHtml; - studiesToRender.forEach(function (s) { - return renderStudy(s, '#studies', linkFunc, htmlFunc); - }); - loadStudyThumbnails(); -} // When no studies match the filter, show message/link. - - -function noStudiesMessage() { - var filterMessage = "No matching studies."; - - if (SUPER_CATEGORY) { - var currLabel = SUPER_CATEGORY.label; - var configId = document.getElementById("maprConfig").value; - var maprQuery = document.getElementById("maprQuery").value; - var others = []; - - for (var cat in SUPER_CATEGORIES) { - if (SUPER_CATEGORIES[cat].label !== currLabel) { - others.push("<a href=\"".concat(GALLERY_INDEX).concat(cat, "/search/?query=").concat(configId, ":").concat(maprQuery, "\">").concat(SUPER_CATEGORIES[cat].label, "</a>")); - } - } - - if (others.length > 0) { - filterMessage += " Try " + others.join(" or "); - } - } - - return filterMessage; -} - -function renderStudy(studyData, elementSelector, linkFunc, htmlFunc) { - // Add Project or Screen to the page - var title; - - for (var i = 0; i < TITLE_KEYS.length; i++) { - title = model.getStudyValue(studyData, TITLE_KEYS[i]); - - if (title) { - break; - } - } - - if (!title) { - title = studyData.Name; - } - - var type = studyData['@type'].split('#')[1].toLowerCase(); - var studyLink = linkFunc(studyData); // save for later - - studyData.title = title; - var desc = studyData.Description; - var studyDesc; - - if (desc) { - // If description contains title, use the text that follows - if (title.length > 0 && desc.indexOf(title) > -1) { - desc = desc.split(title)[1]; - } // Remove blank lines (and first 'Experiment Description' line) - - - studyDesc = desc.split('\n').filter(function (l) { - return l.length > 0; - }).filter(function (l) { - return l !== 'Experiment Description' && l !== 'Screen Description'; - }).join('\n'); - - if (studyDesc.indexOf('Version History') > 1) { - studyDesc = studyDesc.split('Version History')[0]; - } - } - - var shortName = getStudyShortName(studyData); - var authors = model.getStudyValue(studyData, "Publication Authors") || ""; - var div = htmlFunc({ - studyLink: studyLink, - studyDesc: studyDesc, - shortName: shortName, - title: title, - authors: authors, - BASE_URL: BASE_URL, - type: type - }, studyData); - document.querySelector(elementSelector).appendChild(div); -} // --------- Render utils ----------- - - -function studyHtml(props, studyData) { - var pubmed = model.getStudyValue(studyData, 'PubMed ID'); - - if (pubmed) { - pubmed = pubmed.split(" ")[1]; - } - - var author = props.authors.split(',')[0] || ''; - - if (author) { - author = "".concat(author, " et al."); - author = author.length > 23 ? author.slice(0, 20) + '...' : author; - } - - var html = "\n <div style='white-space:nowrap'>\n ".concat(props.shortName, "\n ").concat(pubmed ? "<a class='pubmed' target=\"_blank\" href=\"".concat(pubmed, "\"> ").concat(author, "</a>") : author, "\n </div>\n <div class=\"studyImage\">\n <a target=\"_blank\" href=\"").concat(props.studyLink, "\">\n <div style=\"height: 100%; width: 100%\">\n <div class=\"studyText\">\n <p title='").concat(props.studyDesc, "'>\n ").concat(props.title, "\n </p>\n </div>\n <div class=\"studyAuthors\">\n ").concat(props.authors, "\n </div>\n </div>\n </a>\n <a class=\"viewerLink\" title=\"Open image in viewer\" target=\"_blank\"\n href=\"\">\n <i class=\"fas fa-eye\"></i>\n </a>\n </div>\n "); - var div = document.createElement("div"); - div.innerHTML = html; - div.id = props.type + '-' + studyData['@id']; - div.dataset.obj_type = props.type; - div.dataset.obj_id = studyData['@id']; - div.className = "row study "; - return div; -} - -function maprHtml(props, studyData) { - var html = " \n <td>\n <a target=\"_blank\" href=\"".concat(props.studyLink, "\" />\n ").concat(props.shortName, "\n </a>\n </td>\n <td>").concat(model.getStudyValue(studyData, 'Organism'), "</td>\n <td>").concat(studyData.imageCount, "</td>\n <td title=\"").concat(props.title, "\">").concat(props.title.slice(0, 40)).concat(props.title.length > 40 ? '...' : '', "</td>\n <td class='exampleImages'>loading...</td>\n <td class='exampleImagesLink'></td>\n "); - var tr = document.createElement("tr"); - tr.innerHTML = html; - tr.id = props.type + '-' + studyData['@id']; - tr.dataset.obj_type = props.type; - tr.dataset.obj_id = studyData['@id']; - return tr; -} - -function loadStudyThumbnails() { - var ids = []; // Collect study IDs 'project-1', 'screen-2' etc - - $('div.study').each(function () { - var obj_id = $(this).attr('data-obj_id'); - var obj_type = $(this).attr('data-obj_type'); - - if (obj_id && obj_type) { - ids.push(obj_type + '-' + obj_id); - } - }); // Load images - - model.loadStudiesThumbnails(ids, function (data) { - // data is e.g. { project-1: {thumbnail: base64data, image: {id:1}} } - for (var id in data) { - if (!data[id]) continue; // may be null - - var obj_type = id.split('-')[0]; - var obj_id = id.split('-')[1]; - var elements = document.querySelectorAll("div[data-obj_type=\"".concat(obj_type, "\"][data-obj_id=\"").concat(obj_id, "\"]")); - - for (var e = 0; e < elements.length; e++) { - // Find all studies matching the study ID and set src on image - var element = elements[e]; - var studyImage = element.querySelector('.studyImage'); - - if (data[id].thumbnail) { - studyImage.style.backgroundImage = "url(".concat(data[id].thumbnail, ")"); - } // viewer link - - - if (data[id].image && data[id].image.id) { - var iid = data[id].image.id; - var link = "".concat(BASE_URL, "webclient/img_detail/").concat(iid, "/"); - element.querySelector('a.viewerLink').href = link; - } - } - } - }); -} // ----------- Load / Filter Studies -------------------- -// Do the loading and render() when done... - - -model.loadStudies(function () { - // Immediately filter by Super category - if (SUPER_CATEGORY && SUPER_CATEGORY.query) { - model.studies = model.filterStudiesByMapQuery(SUPER_CATEGORY.query); - } - - filterAndRender(); -}); // Handle browser Back and Forwards - redo filtering - -window.onpopstate = function (event) { - populateInputsFromSearch(); - filterAndRender(); -}; // Load MAPR config - - -fetch(BASE_URL + 'mapr/api/config/').then(function (response) { - return response.json(); -}).then(function (data) { - mapr_settings = data; - var options = FILTER_MAPR_KEYS.map(function (key) { - var config = mapr_settings[key]; - - if (config) { - return "<option value=\"mapr_".concat(key, "\">").concat(config.label, "</option>"); - } else { - return ""; - } - }); - - if (options.length > 0) { - document.getElementById('maprKeys').innerHTML = options.join("\n"); // Show the <optgroup> and the whole form - - document.getElementById('maprKeys').style.display = 'block'; - document.getElementById('search-form').style.display = 'block'; - } - - populateInputsFromSearch(); -})["catch"](function (err) { - console.log("mapr not installed (config not available)"); -}); \ No newline at end of file diff --git a/omero_gallery/templates/webgallery/base/base.html b/omero_gallery/templates/webgallery/base/base.html deleted file mode 100644 index 0449cdf2..00000000 --- a/omero_gallery/templates/webgallery/base/base.html +++ /dev/null @@ -1,82 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="description" content=""> - <meta name="author" content=""> - <link rel="shortcut icon" href="../../assets/ico/favicon.ico"> - - <title>{% block title %}{% endblock %} - - - - - - - - - - - - - - - - - - - {% block jumbotron %} - {% endblock %} - -
- - {% block body %} - {% endblock %} - -
- -
-

© Company 2014

-
-
- - - - - - - - diff --git a/omero_gallery/templates/webgallery/categories/index.html b/omero_gallery/templates/webgallery/categories/index.html deleted file mode 100644 index bd502599..00000000 --- a/omero_gallery/templates/webgallery/categories/index.html +++ /dev/null @@ -1,82 +0,0 @@ - -{% extends "webgallery/categories/base.html" %} - -{% block content %} - - - -
- -
- {% if gallery_heading %}

{{ gallery_heading }}

{% endif %} - -

- {% if not super_category %} - {{ subheading_html|safe }} - {% endif %} -

-
- -
- - - - {% if not super_category %} -
-
 
- {% for category, data in super_categories.items %} - -
- -
- {{ data.label }} -
-
-
- {% endfor %} -
-
- {% endif %} - -
-
-
- -
- Loading Studies... -
- - - - - -{% endblock %} diff --git a/omero_gallery/templates/webgallery/dataset_thumbs.html b/omero_gallery/templates/webgallery/dataset_thumbs.html deleted file mode 100644 index bb2ecc06..00000000 --- a/omero_gallery/templates/webgallery/dataset_thumbs.html +++ /dev/null @@ -1,5 +0,0 @@ -{% for i in dataset.listChildren %} - - - -{% endfor %} diff --git a/omero_gallery/templates/webgallery/index.html b/omero_gallery/templates/webgallery/index.html deleted file mode 100644 index 114b15c9..00000000 --- a/omero_gallery/templates/webgallery/index.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends "webgallery/base/base.html" %} - -{% block title %} -OMERO.web Gallery -{% endblock %} - -{% block jumbotron %} -
-
-

Welcome to OMERO Gallery

-

You can browse images below

-
-
-{% endblock %} - -{% block body %} - -
- {% for g in groups %} -
-

{{ g.name }}

-

- {% if g.image %} - - - - {% endif %} -

-
-
    -
  • Projects: {{ g.projectCount }}
  • -
  • Datasets: {{ g.datasetCount }}
  • -
  • Images: {{ g.imageCount }}
  • -
-
-

- View details » -

-
-
-
- {% endfor %} -
- - -{% endblock %} \ No newline at end of file diff --git a/omero_gallery/templates/webgallery/show_dataset.html b/omero_gallery/templates/webgallery/show_dataset.html deleted file mode 100644 index 06fe7e74..00000000 --- a/omero_gallery/templates/webgallery/show_dataset.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "webgallery/base/base.html" %} - -{% block title %} - {{ dataset.getName }} -{% endblock %} - - -{% block body %} - - {% if dataset.getParent %} - {% with p=dataset.getParent %} - Back to: {{ p.getName }} - {% endwith %} - {% endif %} - -

{{ dataset.getName }}

- -

{{ dataset.getDescription }}

- -
- - {% for i in dataset.listChildren %} - - - - {% endfor %} - -{% endblock %} \ No newline at end of file diff --git a/omero_gallery/templates/webgallery/show_group.html b/omero_gallery/templates/webgallery/show_group.html deleted file mode 100644 index 2b8c75de..00000000 --- a/omero_gallery/templates/webgallery/show_group.html +++ /dev/null @@ -1,107 +0,0 @@ -{% extends "webgallery/base/base.html" %} - -{% block title %} - OMERO.web Gallery -{% endblock %} - - -{% block body %} - -

{{ group.name }}

- -
- -
- - {% for p in projects %} -
-

{{ p.name }}

-

- {% if p.image %} - - - - {% endif %} -

-
-
    -
  • Datasets: {{ p.datasetCount }}
  • -
  • Images: {{ p.imageCount }}
  • -
-
-

- View details » -

-
-
-
- {% endfor %} -
- -
- -
- {% for p in datasets %} -
-

{{ p.name }}

-

- {% if p.image %} - - - - {% endif %} -

-
-
    -
  • Images: {{ p.imageCount }}
  • -
-
-

- View details » -

-
-
-
- {% endfor %} -
- - - - - - {% include "webgateway/base/includes/script_src_jquery.html" %} - - -{% endblock %} \ No newline at end of file diff --git a/omero_gallery/templates/webgallery/show_image.html b/omero_gallery/templates/webgallery/show_image.html deleted file mode 100644 index 3ad853f4..00000000 --- a/omero_gallery/templates/webgallery/show_image.html +++ /dev/null @@ -1,82 +0,0 @@ -{% extends "webgallery/base/base.html" %} - -{% block title %} - {{ image.getName }} -{% endblock %} - - -{% block body %} - -
- Home - Logged in as: {{ ome.user.getFullName }} -
- -
- - {% if image.getParent %} - {% with p=image.getParent %} - Back to: {{ p.getName }} - {% endwith %} - {% endif %} - -

{{ image.getName }}

- -

{{ image.getDescription }}

- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dimensions (XY):{{ image.getSizeX }} x {{ image.getSizeY }}
Pixels Type:{{ image.getPixelsType }}
Pixels Size (XYZ) (µm): - {{ image.getPixelSizeX|floatformat:4 }} x {{ image.getPixelSizeY|floatformat:4 }} - {% if image.getPixelSizeZ %} x {{ image.getPixelSizeZ|floatformat:4 }} {% endif %} -
Z-sections/Timepoints:{{ image.getSizeZ }} x {{ image.getSizeT }}
Channels: - {% for c in image.getChannels %}{% if not forloop.first %}, {% endif %}{{ c.getLabel }}{% endfor %} -
Tags: - {% for t in tags %}{% if not forloop.first %}, {% endif %}{{ t.getTextValue }}{% endfor %} -
- - - {% include "webgateway/base/includes/script_src_jquery.html" %} - - - - - - - - - - - -{% endblock %} \ No newline at end of file diff --git a/omero_gallery/templates/webgallery/show_project.html b/omero_gallery/templates/webgallery/show_project.html deleted file mode 100644 index 72f04f73..00000000 --- a/omero_gallery/templates/webgallery/show_project.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "webgallery/base/base.html" %} - -{% block title %} - {{ project.getName }} -{% endblock %} - - -{% block body %} - -
- Home - Logged in as: {{ ome.user.getFullName }} -
- -
- -

{{ project.getName }}

- -

{{ project.getDescription }}

- -
- - - - - {% include "webgateway/base/includes/script_src_jquery.html" %} - - -{% endblock %} \ No newline at end of file diff --git a/omero_gallery/urls.py b/omero_gallery/urls.py deleted file mode 100644 index 1785b90b..00000000 --- a/omero_gallery/urls.py +++ /dev/null @@ -1,55 +0,0 @@ -from django.conf.urls import url -from .gallery_settings import SUPER_CATEGORIES - -from . import views - -urlpatterns = [ - # index 'home page' of the webgallery app - url(r'^$', views.index, name='webgallery_index'), - - # All settings as JSON - url(r'^gallery_settings/$', views.gallery_settings), - - # group view - url(r'show_group/(?P[0-9]+)/$', - views.show_group, - name='webgallery_show_group'), - - # project view - url(r'show_project/(?P[0-9]+)/$', - views.show_project, - name='webgallery_show_project'), - - # dataset view - url(r'show_dataset/(?P[0-9]+)/$', - views.show_dataset, - name='webgallery_show_dataset'), - # use the same dataset view, with a different - # template that only shows thumbnails - url(r'dataset_thumbs/(?P[0-9]+)/$', - views.show_dataset, - {'template': 'webgallery/dataset_thumbs.html'}, - name='webgallery_dataset_thumbs'), - - # image view - url(r'show_image/(?P[0-9]+)/$', - views.show_image, name='webgallery_show_image'), - - # Search page shows Projects / Screens filtered by Map Annotation - url(r'^search/$', views.search, {'super_category': None}), - - # list images within container. NB: not used but potentially useful - url(r'^gallery-api/(?P[screen|project]+)s/' - r'(?P[0-9]+)/images/$', - views.study_images, name='webgallery_study_image'), - - # Supports e.g. ?project=1&project=2&screen=3 - url(r'^gallery-api/thumbnails/$', views.api_thumbnails, - name='webgallery_api_thumbnails'), -] - -for c in SUPER_CATEGORIES: - urlpatterns.append(url(r'^%s/$' % c, views.index, {'super_category': c}, - name="gallery_super_category")) - urlpatterns.append(url(r'^%s/search/$' % c, views.search, - {'super_category': c})) diff --git a/omero_gallery/views.py b/omero_gallery/views.py deleted file mode 100644 index 5d6c3e2d..00000000 --- a/omero_gallery/views.py +++ /dev/null @@ -1,433 +0,0 @@ -from django.http import Http404 -from django.urls import reverse, NoReverseMatch -import json -import logging -import base64 - -import omero -from omero.rtypes import wrap, rlong -from omeroweb.webclient.decorators import login_required, render_response -from omeroweb.api.decorators import login_required as api_login_required -from omeroweb.api.api_settings import API_MAX_LIMIT - -try: - from omero_marshal import get_encoder -except ImportError: - get_encoder = None - -from . import gallery_settings as settings - -logger = logging.getLogger(__name__) -MAX_LIMIT = max(1, API_MAX_LIMIT) - - -@login_required() -@render_response() -def index(request, super_category=None, conn=None, **kwargs): - """ - Home page shows a list of groups OR a set of 'categories' from - user-configured queries. - """ - - category_queries = settings.CATEGORY_QUERIES - if len(category_queries) > 0: - context = {'template': "webgallery/categories/index.html"} - context['favicon'] = settings.FAVICON - context['gallery_title'] = settings.GALLERY_TITLE - context['gallery_heading'] = settings.GALLERY_HEADING - context['top_right_links'] = settings.TOP_RIGHT_LINKS - context['top_left_logo'] = settings.TOP_LEFT_LOGO - try: - href = context['top_left_logo'].get('href', 'webgallery_index') - context['top_left_logo']['href'] = reverse(href) - except NoReverseMatch: - pass - context['subheading_html'] = settings.SUBHEADING_HTML - context['footer_html'] = settings.FOOTER_HTML - context['filter_keys'] = json.dumps(settings.FILTER_KEYS) - context['TITLE_KEYS'] = json.dumps(settings.TITLE_KEYS) - context['STUDY_SHORT_NAME'] = json.dumps(settings.STUDY_SHORT_NAME) - context['filter_mapr_keys'] = json.dumps( - settings.FILTER_MAPR_KEYS) - context['super_categories'] = settings.SUPER_CATEGORIES - category = settings.SUPER_CATEGORIES.get(super_category) - if category is not None: - label = category.get('label', context['gallery_heading']) - title = category.get('title', label) - context['gallery_heading'] = title - context['super_category'] = json.dumps(category) - context['category'] = super_category - base_url = reverse('index') - if settings.BASE_URL is not None: - base_url = settings.BASE_URL - context['base_url'] = base_url - context['category_queries'] = json.dumps(category_queries) - return context - - my_groups = list(conn.getGroupsMemberOf()) - - # Need a custom query to get 1 (random) image per Project - query_service = conn.getQueryService() - params = omero.sys.ParametersI() - params.theFilter = omero.sys.Filter() - params.theFilter.limit = wrap(1) - - query = "select count(obj.id) from %s as obj" - - groups = [] - for g in my_groups: - conn.SERVICE_OPTS.setOmeroGroup(g.id) - images = list(conn.getObjects("Image", params=params)) - if len(images) == 0: - continue # Don't display empty groups - p_count = query_service.projection( - query % 'Project', None, conn.SERVICE_OPTS) - d_count = query_service.projection( - query % 'Dataset', None, conn.SERVICE_OPTS) - i_count = query_service.projection( - query % 'Image', None, conn.SERVICE_OPTS) - groups.append({ - 'id': g.getId(), - 'name': g.getName(), - 'description': g.getDescription(), - 'projectCount': p_count[0][0]._val, - 'datasetCount': d_count[0][0]._val, - 'imageCount': i_count[0][0]._val, - 'image': len(images) > 0 and images[0] or None}) - - # This is used by @render_response - context = {'template': "webgallery/index.html"} - context['groups'] = groups - - return context - - -@render_response() -def gallery_settings(request): - """Return all settings as JSON.""" - - attrs = ['CATEGORY_QUERIES', - 'GALLERY_TITLE', - 'GALLERY_HEADING', - 'FILTER_KEYS', - 'TITLE_KEYS', - 'FILTER_MAPR_KEYS', - 'SUPER_CATEGORIES', - 'BASE_URL', - 'TOP_RIGHT_LINKS', - 'TOP_LEFT_LOGO', - 'FOOTER_HTML', - 'SUBHEADING_HTML', - 'FAVICON', - 'STUDY_SHORT_NAME', - ] - - context = {} - for attr in attrs: - try: - context[attr] = getattr(settings, attr) - except AttributeError: - pass - - return context - - -@login_required() -@render_response() -def show_group(request, group_id, conn=None, **kwargs): - conn.SERVICE_OPTS.setOmeroGroup(group_id) - - s = conn.groupSummary(group_id) - group_owners = s["leaders"] - group_members = s["colleagues"] - group = conn.getObject("ExperimenterGroup", group_id) - - # Get NEW user_id, OR current user_id from session OR 'All Members' (-1) - user_id = request.GET.get( - 'user_id', request.session.get('user_id', -1)) - user_ids = [u.id for u in group_owners] - user_ids.extend([u.id for u in group_members]) - user_id = int(user_id) - # Check user is in group - if user_id not in user_ids and user_id is not -1: - user_id = -1 - # save it to session - request.session['user_id'] = int(user_id) - request.session.modified = True - - query_service = conn.getQueryService() - params = omero.sys.ParametersI() - params.theFilter = omero.sys.Filter() - params.theFilter.limit = wrap(1) - # params.map = {} - query = "select i from Image as i"\ - " left outer join i.datasetLinks as dl join dl.parent as dataset"\ - " left outer join dataset.projectLinks"\ - " as pl join pl.parent as project"\ - " where project.id = :pid" - param_all = omero.sys.ParametersI() - count_images = "select count(i), count(distinct dataset) from Image as i"\ - " left outer join i.datasetLinks"\ - " as dl join dl.parent as dataset"\ - " left outer join dataset.projectLinks"\ - " as pl join pl.parent as project"\ - " where project.id = :pid" - - if user_id == -1: - user_id = None - projects = [] - # Will be from active group, owned by user_id (as perms allow) - for p in conn.listProjects(eid=user_id): - pdata = {'id': p.getId(), 'name': p.getName()} - pdata['description'] = p.getDescription() - pdata['owner'] = p.getDetails().getOwner().getOmeName() - # Look-up a single image - params.addLong('pid', p.getId()) - img = query_service.findByQuery(query, params, conn.SERVICE_OPTS) - if img is None: - continue # Ignore projects with no images - pdata['image'] = {'id': img.getId().getValue(), - 'name': img.getName().getValue()} - param_all.addLong('pid', p.getId()) - image_count = query_service.projection( - count_images, param_all, conn.SERVICE_OPTS) - pdata['imageCount'] = image_count[0][0].val - pdata['datasetCount'] = image_count[0][1].val - projects.append(pdata) - - query = "select i from Image as i"\ - " left outer join i.datasetLinks as dl"\ - " join dl.parent as dataset"\ - " where dataset.id = :did" - count_images = "select count(i) from Image as i"\ - " left outer join i.datasetLinks as dl "\ - "join dl.parent as dataset"\ - " where dataset.id = :did" - datasets = [] - for d in conn.listOrphans("Dataset", eid=user_id): - ddata = {'id': d.getId(), 'name': d.getName()} - ddata['description'] = d.getDescription() - ddata['owner'] = d.getDetails().getOwner().getOmeName() - # Look-up a single image - # params.map['did'] = wrap(d.id) - params.addLong('did', d.getId()) - img = query_service.findByQuery(query, params, conn.SERVICE_OPTS) - if img is None: - continue # ignore datasets with no images - ddata['image'] = {'id': img.getId().getValue(), - 'name': img.getName().getValue()} - param_all.addLong('did', d.getId()) - image_count = query_service.projection( - count_images, param_all, conn.SERVICE_OPTS) - ddata['imageCount'] = image_count[0][0].val - datasets.append(ddata) - context = {'template': "webgallery/show_group.html"} - context['group'] = group - context['group_owners'] = group_owners - context['group_members'] = group_members - context['projects'] = projects - context['datasets'] = datasets - - return context - - -@login_required() -@render_response() -def show_project(request, project_id, conn=None, **kwargs): - """ - Show a project - """ - - project = conn.getObject("Project", project_id) - - if project is None: - raise Http404 - - # Set a limit to grab 5 images from each Dataset - params = omero.sys.Parameters() - params.theFilter = omero.sys.Filter() - params.theFilter.limit = wrap(5) - - datasets = [] - for ds in project.listChildren(): - # want to display 5 images from each dataset - images = ds.listChildren(params=params) - datasets.append({ - "id": ds.getId(), - "name": ds.getName(), - "description": ds.getDescription(), - "images": images}) - - context = {'template': "webgallery/show_project.html"} - context['project'] = project - context['datasets'] = datasets - - return context - - -@login_required() -@render_response() -def show_dataset(request, dataset_id, conn=None, **kwargs): - """ - Show a dataset - """ - - dataset = conn.getObject("Dataset", dataset_id) - - if dataset is None: - raise Http404 - - context = {'template': "webgallery/show_dataset.html"} - context['dataset'] = dataset - - return context - - -@login_required() -@render_response() -def show_image(request, image_id, conn=None, **kwargs): - """ - Show an image - """ - - image = conn.getObject("Image", image_id) - - if image is None: - raise Http404 - - tags = [] - for ann in image.listAnnotations(): - if isinstance(ann, omero.gateway.TagAnnotationWrapper): - tags.append(ann) - - context = {'template': "webgallery/show_image.html"} - context['image'] = image - context['tags'] = tags - - return context - - -@render_response() -def search(request, super_category=None, conn=None, **kwargs): - - context = {'template': "webgallery/categories/search.html"} - context['favicon'] = settings.FAVICON - context['gallery_title'] = settings.GALLERY_TITLE - context['gallery_heading'] = settings.GALLERY_HEADING - context['top_right_links'] = settings.TOP_RIGHT_LINKS - context['top_left_logo'] = settings.TOP_LEFT_LOGO - try: - href = context['top_left_logo'].get('href', 'webgallery_index') - context['top_left_logo']['href'] = reverse(href) - except NoReverseMatch: - pass - context['subheading_html'] = settings.SUBHEADING_HTML - context['footer_html'] = settings.FOOTER_HTML - context['filter_keys'] = json.dumps(settings.FILTER_KEYS) - context['super_categories'] = settings.SUPER_CATEGORIES - context['SUPER_CATEGORIES'] = json.dumps(settings.SUPER_CATEGORIES) - context['TITLE_KEYS'] = json.dumps(settings.TITLE_KEYS) - context['STUDY_SHORT_NAME'] = json.dumps(settings.STUDY_SHORT_NAME) - context['filter_mapr_keys'] = json.dumps( - settings.FILTER_MAPR_KEYS) - category = settings.SUPER_CATEGORIES.get(super_category) - if category is not None: - label = category.get('label', context['gallery_heading']) - title = category.get('title', label) - context['gallery_heading'] = title - context['super_category'] = json.dumps(category) - context['category'] = super_category - base_url = reverse('index') - if settings.BASE_URL is not None: - base_url = settings.BASE_URL - context['base_url'] = base_url - context['category_queries'] = json.dumps(settings.CATEGORY_QUERIES) - return context - - -def _get_study_images(conn, obj_type, obj_id, limit=1, offset=0): - - query_service = conn.getQueryService() - params = omero.sys.ParametersI() - params.addId(obj_id) - params.theFilter = omero.sys.Filter() - params.theFilter.limit = wrap(limit) - params.theFilter.offset = wrap(offset) - - if obj_type == "project": - query = "select i from Image as i"\ - " left outer join i.datasetLinks as dl"\ - " join dl.parent as dataset"\ - " left outer join dataset.projectLinks"\ - " as pl join pl.parent as project"\ - " where project.id = :id" - - elif obj_type == "screen": - query = ("select i from Image as i" - " left outer join i.wellSamples as ws" - " join ws.well as well" - " join well.plate as pt" - " left outer join pt.screenLinks as sl" - " join sl.parent as screen" - " where screen.id = :id" - " order by well.column, well.row") - - objs = query_service.findAllByQuery(query, params, conn.SERVICE_OPTS) - - return objs - - -@render_response() -@login_required() -def study_images(request, obj_type, obj_id, conn=None, **kwargs): - limit = int(request.REQUEST.get('limit', 1)) - limit = min(limit, MAX_LIMIT) - offset = int(request.REQUEST.get('offset', 0)) - images = _get_study_images(conn, obj_type, obj_id, limit, offset) - json_data = [] - for image in images: - if get_encoder is not None: - encoder = get_encoder(image.__class__) - if encoder is not None: - json_data.append(encoder.encode(image)) - continue - json_data.append({'@id': image.id.val, 'Name': image.name.val}) - meta = {} - meta['offset'] = offset - meta['limit'] = limit - meta['maxLimit'] = MAX_LIMIT - # Same format as OMERO.api app - return {'data': json_data, 'meta': meta} - - -@render_response() -@api_login_required() # 403 JsonResponse if not logged in -def api_thumbnails(request, conn=None, **kwargs): - """ - Return data like - { project-1: {thumbnail: base64data, image: {id:1}} } - """ - project_ids = request.GET.getlist('project') - screen_ids = request.GET.getlist('screen') - - image_ids = {} - for obj_type, ids in zip(['project', 'screen'], [project_ids, screen_ids]): - for obj_id in ids: - images = _get_study_images(conn, obj_type, obj_id) - if len(images) > 0: - image_ids[images[0].id.val] = "%s-%s" % (obj_type, obj_id) - - thumbnails = conn.getThumbnailSet([rlong(i) for i in image_ids.keys()], 96) - rv = {} - for i, obj_id in image_ids.items(): - rv[obj_id] = {"image": {'id': i}} - try: - t = thumbnails[i] - if len(t) > 0: - # replace thumbnail urls by base64 encoded image - rv[obj_id]["thumbnail"] = ("data:image/jpeg;base64,%s" % - base64.b64encode(t).decode("utf-8")) - - except KeyError: - logger.error("Thumbnail not available. (img id: %d)" % i) - return rv diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 1bfe0aae..00000000 --- a/package-lock.json +++ /dev/null @@ -1,5650 +0,0 @@ -{ - "name": "omero-gallery", - "version": "3.2.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/cli": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.4.4.tgz", - "integrity": "sha512-XGr5YjQSjgTa6OzQZY57FAJsdeVSAKR/u/KA5exWIz66IKtv/zXtHy+fIZcMry/EgYegwuHE7vzGnrFhjdIAsQ==", - "dev": true, - "requires": { - "chokidar": "^2.0.4", - "commander": "^2.8.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", - "lodash": "^4.17.11", - "mkdirp": "^0.5.1", - "output-file-sync": "^2.0.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - } - } - }, - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", - "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helpers": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.5", - "@babel/types": "^7.4.4", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", - "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-define-map": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz", - "integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.4.4", - "lodash": "^4.17.11" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", - "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-module-transforms": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz", - "integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.4.4", - "lodash": "^4.17.11" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz", - "integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-replace-supers": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz", - "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", - "dev": true, - "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" - } - }, - "@babel/helpers": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", - "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", - "dev": true, - "requires": { - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", - "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", - "dev": true - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", - "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz", - "integrity": "sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", - "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", - "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.0.2", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - } - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", - "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", - "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", - "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz", - "integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", - "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz", - "integrity": "sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.11" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz", - "integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.4.4", - "@babel/helper-split-export-declaration": "^7.4.4", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", - "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz", - "integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", - "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", - "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.0.2", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - } - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", - "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", - "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", - "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", - "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", - "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", - "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz", - "integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz", - "integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz", - "integrity": "sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg==", - "dev": true, - "requires": { - "regexp-tree": "^0.1.6" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", - "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", - "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", - "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", - "dev": true, - "requires": { - "@babel/helper-call-delegate": "^7.4.4", - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", - "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.0" - }, - "dependencies": { - "regenerator-transform": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.0.tgz", - "integrity": "sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==", - "dev": true, - "requires": { - "private": "^0.1.6" - } - } - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", - "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", - "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", - "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", - "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", - "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", - "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", - "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", - "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.0.2", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - } - } - }, - "@babel/preset-env": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", - "integrity": "sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.4.4", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.4.4", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.4.4", - "@babel/plugin-transform-classes": "^7.4.4", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/plugin-transform-duplicate-keys": "^7.2.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.4.4", - "@babel/plugin-transform-function-name": "^7.4.4", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-member-expression-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.2.0", - "@babel/plugin-transform-modules-commonjs": "^7.4.4", - "@babel/plugin-transform-modules-systemjs": "^7.4.4", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", - "@babel/plugin-transform-new-target": "^7.4.4", - "@babel/plugin-transform-object-super": "^7.2.0", - "@babel/plugin-transform-parameters": "^7.4.4", - "@babel/plugin-transform-property-literals": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.4.5", - "@babel/plugin-transform-reserved-words": "^7.2.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.4.4", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.5.0" - } - }, - "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/traverse": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", - "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/types": "^7.4.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", - "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } - } - }, - "@webassemblyjs/ast": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", - "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", - "requires": { - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", - "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==" - }, - "@webassemblyjs/helper-api-error": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", - "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==" - }, - "@webassemblyjs/helper-buffer": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", - "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==" - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", - "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", - "requires": { - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", - "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==" - }, - "@webassemblyjs/helper-module-context": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", - "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "mamacro": "^0.0.3" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", - "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==" - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", - "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", - "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", - "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", - "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==" - }, - "@webassemblyjs/wasm-edit": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", - "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/helper-wasm-section": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-opt": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", - "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", - "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", - "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", - "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/floating-point-hex-parser": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-code-frame": "1.8.5", - "@webassemblyjs/helper-fsm": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", - "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" - }, - "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" - }, - "ajv-keywords": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", - "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==" - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-loader": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", - "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", - "requires": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "requires": { - "find-up": "^2.1.0" - } - } - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "requires": { - "regenerator-transform": "^0.10.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-preset-es2015": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", - "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", - "requires": { - "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.24.1", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-destructuring": "^6.22.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", - "babel-plugin-transform-es2015-for-of": "^6.22.0", - "babel-plugin-transform-es2015-function-name": "^6.24.1", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-umd": "^6.24.1", - "babel-plugin-transform-es2015-object-super": "^6.24.1", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", - "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.24.1", - "babel-plugin-transform-regenerator": "^6.24.1" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" - }, - "bluebird": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", - "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==" - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "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" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.1.tgz", - "integrity": "sha512-1MC18ooMPRG2UuVFJTHFIAkk6mpByJfxCrnUyvSlu/hyQSFHMrlhM02SzNuCV+quTP4CKmqtOMAIjrifrpBJXQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000971", - "electron-to-chromium": "^1.3.137", - "node-releases": "^1.1.21" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "cacache": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", - "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", - "requires": { - "bluebird": "^3.5.3", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "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" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "caniuse-lite": { - "version": "1.0.30000973", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000973.tgz", - "integrity": "sha512-/F3t/Yo8LEdRSEPCmI15fLu5vepVh9UCg/9inJXF5AAfW7xRRJkbaM2ut52iRMQMnGCLQouLbFdbOA+VEFOIsg==", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "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": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", - "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" - }, - "chrome-trace-event": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz", - "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", - "requires": { - "tslib": "^1.9.0" - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "requires": { - "date-now": "^0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" - }, - "core-js-compat": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.1.3.tgz", - "integrity": "sha512-EP018pVhgwsKHz3YoN1hTq49aRe+h017Kjz0NQz3nXV0cCRMvH3fLQl+vEPGr4r4J5sk4sU3tUC7U1aqTCeJeA==", - "dev": true, - "requires": { - "browserslist": "^4.6.0", - "core-js-pure": "3.1.3", - "semver": "^6.1.0" - }, - "dependencies": { - "semver": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", - "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", - "dev": true - } - } - }, - "core-js-pure": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.1.3.tgz", - "integrity": "sha512-k3JWTrcQBKqjkjI0bkfXS0lbpWPxYuHWfMMjC1VDmzU4Q58IwSbuXSo99YO/hUHlw/EB4AlfA2PVxOGkrIq6dA==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "electron-to-chromium": { - "version": "1.3.144", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.144.tgz", - "integrity": "sha512-jNRFJpfNrYm5uJ4x0q9oYMOfbL0JPOlkNli8GS/5zEmCjnE5jAtoCo4BYajHiqSPqEeAjtTdItL4p7EZw+jSfg==", - "dev": true - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - } - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "requires": { - "prr": "~1.0.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "figgy-pudding": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "optional": true - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "optional": true - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "optional": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "optional": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "optional": true, - "requires": { - "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" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "optional": true, - "requires": { - "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" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true - }, - "minipass": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", - "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "optional": true - }, - "needle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz", - "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", - "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", - "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "optional": true, - "requires": { - "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": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "optional": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "optional": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "optional": true - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "optional": true, - "requires": { - "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" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "optional": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "optional": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "optional": true - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "optional": true - }, - "tar": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "optional": true - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "optional": true - } - } - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "requires": { - "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" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "requires": { - "invert-kv": "^2.0.0" - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "requires": { - "minimist": "^1.2.0" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "mamacro": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "requires": { - "p-defer": "^1.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "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" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nan": { - "version": "2.13.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", - "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "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-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" - } - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node-libs-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", - "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "0.0.4" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } - } - }, - "node-releases": { - "version": "1.1.22", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.22.tgz", - "integrity": "sha512-O6XpteBuntW1j86mw6LlovBIwTe+sO2+7vi9avQffNeIW4upgnaCVm6xrBWH+KATz7mNNRNNeEpuWB7dT6Cr3w==", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "output-file-sync": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", - "integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "is-plain-obj": "^1.1.0", - "mkdirp": "^0.5.1" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" - }, - "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "parse-asn1": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", - "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "requires": { - "find-up": "^3.0.0" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "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" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" - }, - "regenerate-unicode-properties": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", - "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp-tree": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.10.tgz", - "integrity": "sha512-K1qVSbcedffwuIslMwpe6vGlj+ZXRnGkvjAtFHfDZZZuEdA/h0dxljAPu9vhUo6Rrx2U2AwJ+nSQ6hK+lrP5MQ==", - "dev": true - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "requires": { - "aproba": "^1.1.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" - }, - "serialize-javascript": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", - "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" - }, - "terser": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", - "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", - "requires": { - "commander": "^2.19.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.10" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "terser-webpack-plugin": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz", - "integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==", - "requires": { - "cacache": "^11.0.2", - "find-cache-dir": "^2.0.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "terser": "^3.16.1", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", - "requires": { - "setimmediate": "^1.0.4" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" - }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", - "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", - "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", - "dev": true - }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", - "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, - "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "requires": { - "inherits": "2.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "v8-compile-cache": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", - "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==" - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "requires": { - "indexof": "0.0.1" - } - }, - "watchpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", - "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", - "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - } - }, - "webpack": { - "version": "4.31.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.31.0.tgz", - "integrity": "sha512-n6RVO3X0LbbipoE62akME9K/JI7qYrwwufs20VvgNNpqUoH4860KkaxJTbGq5bgkVZF9FqyyTG/0WPLH3PVNJA==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/wasm-edit": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.0.5", - "acorn-dynamic-import": "^4.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^1.0.0", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" - } - }, - "webpack-cli": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.2.tgz", - "integrity": "sha512-FLkobnaJJ+03j5eplxlI0TUxhGCOdfewspIGuvDVtpOlrAuKMFC57K42Ukxqs1tn8947/PM6tP95gQc0DCzRYA==", - "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.0", - "findup-sync": "^2.0.0", - "global-modules": "^1.0.0", - "import-local": "^2.0.0", - "interpret": "^1.1.0", - "loader-utils": "^1.1.0", - "supports-color": "^5.5.0", - "v8-compile-cache": "^2.0.2", - "yargs": "^12.0.5" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "webpack-sources": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", - "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index b57ac862..00000000 --- a/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "omero-gallery", - "version": "3.2.0", - "description": "OMERO.web app for browsing images", - "main": "index.js", - "dependencies": { - "babel-core": "^6.26.3", - "babel-loader": "^7.1.5", - "babel-preset-es2015": "^6.24.1", - "webpack-cli": "^3.3.2", - "webpack": "^4.31.0" - }, - "devDependencies": { - "@babel/cli": "^7.4.4", - "@babel/core": "^7.4.5", - "@babel/preset-env": "^7.4.5" - }, - "scripts": { - "build": "babel src -d omero_gallery/static/gallery --watch" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/ome/omero-gallery.git" - }, - "keywords": [ - "OMERO", - "images" - ], - "author": "OME", - "license": "AGPL-3.0", - "bugs": { - "url": "https://github.com/ome/omero-gallery/issues" - }, - "homepage": "https://github.com/ome/omero-gallery#readme" -} diff --git a/setup.py b/setup.py index 7e8cb187..6863f6de 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (c) 2016 University of Dundee. +# Copyright (c) 2016-2022 University of Dundee. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -22,7 +22,7 @@ import os from setuptools import setup, find_packages - +from idr_gallery.version import VERSION # Utility function to read the README file. # Used for the long_description. It's nice, because now 1) we have a top level @@ -32,10 +32,9 @@ def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() -VERSION = '3.4.2.dev0' -HOMEPAGE = "https://github.com/ome/omero-gallery" +HOMEPAGE = "https://github.com/IDR/idr-gallery" -setup(name="omero-gallery", +setup(name="idr-gallery", packages=find_packages(exclude=['ez_setup']), version=VERSION, description="A Python plugin for OMERO.web", @@ -62,7 +61,7 @@ def read(fname): author='The Open Microscopy Team', author_email='ome-devel@lists.openmicroscopy.org.uk', license='AGPL-3.0', - url="https://github.com/ome/omero-gallery", + url=HOMEPAGE, download_url='%s/archive/v%s.tar.gz' % (HOMEPAGE, VERSION), keywords=['OMERO.web', 'plugin'], install_requires=['omero-web>=5.6.0'], diff --git a/src/categories.js b/src/categories.js deleted file mode 100644 index 0d057ab1..00000000 --- a/src/categories.js +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright (C) 2019-2020 University of Dundee & Open Microscopy Environment. -// All rights reserved. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -// NB: SOURCE FILES are under /src. Compiled files are under /static/ - -// loaded below -let mapr_settings = {}; - -// Model for loading Projects, Screens and their Map Annotations -let model = new StudiesModel(); - - -// ----- event handling -------- - -document.getElementById('maprConfig').onchange = (event) => { - document.getElementById('maprQuery').value = ''; - let value = event.target.value.replace('mapr_', ''); - let placeholder = `Type to filter values...`; - if (mapr_settings[value]) { - placeholder = `Type ${ mapr_settings[value]['default'][0]}...`; - } - document.getElementById('maprQuery').placeholder = placeholder; - // Show all autocomplete options... - $("#maprQuery").focus(); - render(); -} - -document.getElementById('maprQuery').onfocus = (event) => { - $("#maprQuery").autocomplete("search", event.target.value); -} - -// ------ AUTO-COMPLETE ------------------- - -function showSpinner() { - document.getElementById('spinner').style.visibility = 'visible'; -} -function hideSpinner() { - document.getElementById('spinner').style.visibility = 'hidden'; -} - -$("#maprQuery") - .keyup(event => { - if (event.which == 13) { - let configId = document.getElementById("maprConfig").value; - document.location.href = `search/?query=${ configId }:${ event.target.value }`; - } - }) - .autocomplete({ - autoFocus: false, - delay: 1000, - source: function( request, response ) { - - // if configId is not from mapr, we filter on mapValues... - let configId = document.getElementById("maprConfig").value; - if (configId.indexOf('mapr_') != 0) { - - let matches; - if (configId === 'Name') { - matches = model.getStudiesNames(request.term); - } else if (configId === 'Group') { - matches = model.getStudiesGroups(request.term); - } else { - matches = model.getKeyValueAutoComplete(configId, request.term); - } - response(matches); - return; - } - - // Don't handle empty query for mapr - if (request.term.length == 0) { - return; - } - - // Auto-complete to filter by mapr... - configId = configId.replace('mapr_', ''); - let case_sensitive = false; - - let requestData = { - case_sensitive: case_sensitive, - } - let url; - if (request.term.length === 0) { - // Try to list all top-level values. - // This works for 'wild-card' configs where number of values is small e.g. Organism - // But will return empty list for e.g. Gene - url = `${ BASE_URL }mapr/api/${ configId }/`; - requestData.orphaned = true - } else { - // Find auto-complete matches - url = `${ BASE_URL }mapr/api/autocomplete/${ configId }/`; - requestData.value = case_sensitive ? request.term : request.term.toLowerCase(); - requestData.query = true; // use a 'like' HQL query - } - showSpinner(); - $.ajax({ - dataType: "json", - type : 'GET', - url: url, - data: requestData, - success: function(data) { - hideSpinner(); - if (request.term.length === 0) { - // Top-level terms in 'maps' - if (data.maps && data.maps.length > 0) { - let terms = data.maps.map(m => m.id); - terms.sort(); - response(terms); - } - } - else if (data.length > 0) { - response( $.map( data, function(item) { - return item; - })); - } else { - response([{ label: 'No results found.', value: -1 }]); - } - }, - error: function(data) { - hideSpinner(); - response([{ label: 'Error occured.', value: -1 }]); - } - }); - }, - minLength: 0, - open: function() {}, - close: function() { - // $(this).val(''); - return false; - }, - focus: function(event,ui) {}, - select: function(event, ui) { - if (ui.item.value == -1) { - // Ignore 'No results found' - return false; - } - // show temp message in case loading search page is slow - $(this).val("loading search results..."); - // Load search page... - let configId = document.getElementById("maprConfig").value; - document.location.href = `search/?query=${ configId }:${ ui.item.value }`; - return false; - } -}).data("ui-autocomplete")._renderItem = function( ul, item ) { - return $( "
  • " ) - .append( "" + item.label + "" ) - .appendTo( ul ); -} - -// ------------ Render ------------------------- - -function render() { - document.getElementById('studies').innerHTML = ""; - - let categories = Object.keys(CATEGORY_QUERIES); - // Sort by index - categories.sort(function(a, b) { - let idxA = CATEGORY_QUERIES[a].index; - let idxB = CATEGORY_QUERIES[b].index; - return (idxA > idxB ? 1 : idxA < idxB ? -1 : 0); - }); - - // Link to the study in webclient... - let linkFunc = (studyData) => { - let type = studyData['@type'].split('#')[1].toLowerCase(); - return `${ BASE_URL }webclient/?show=${ type }-${ studyData['@id'] }`; - } - - categories.forEach(category => { - let cat = CATEGORY_QUERIES[category]; - let query = cat.query; - - // Find matching studies - let matches = model.filterStudiesByMapQuery(query); - if (matches.length == 0) return; - - let elementId = cat.label; - - var div = document.createElement( "div" ); - - // If only ONE category... - if (categories.length == 1) { - // list studies in a grid, without category.label - div.innerHTML = `
    `; - div.className = "row" - } else { - div.innerHTML = ` -

    - ${cat.label} (${ matches.length }) -

    -
    -
    -
    - `; - } - document.getElementById('studies').appendChild(div); - - matches.forEach(study => renderStudy(study, elementId, linkFunc)); - }); - - // Now we iterate all Studies in DOM, loading image ID for link and thumbnail - loadStudyThumbnails(); -} - - -function renderStudy(studyData, elementId, linkFunc) { - - // Add Project or Screen to the page - let title; - for (let i=0; i 0 && desc.indexOf(title) > -1) { - desc = desc.split(title)[1]; - } - // Remove blank lines (and first 'Experiment Description' line) - studyDesc = desc.split('\n') - .filter(l => l.length > 0) - .filter(l => l !== 'Experiment Description' && l !== 'Screen Description') - .join('\n'); - if (studyDesc.indexOf('Version History') > 1) { - studyDesc = studyDesc.split('Version History')[0]; - } - } - - let shortName = getStudyShortName(studyData); - let authors = model.getStudyValue(studyData, "Publication Authors") || ""; - - // Function (and template) are defined where used in index.html - let html = studyHtml({studyLink, studyDesc, shortName, title, authors, BASE_URL, type}, studyData) - - var div = document.createElement( "div" ); - div.innerHTML = html; - div.className = "row study "; - div.dataset.obj_type = type; - div.dataset.obj_id = studyData['@id']; - document.getElementById(elementId).appendChild(div); -} - -// --------- Render utils ----------- - -function studyHtml(props, studyData) { - let pubmed = model.getStudyValue(studyData, 'PubMed ID'); - if (pubmed) { - pubmed = pubmed.split(" ")[1]; - }; - let author = props.authors.split(',')[0] || ''; - if (author) { - author = `${ author } et al.`; - author = author.length > 23 ? author.slice(0, 20) + '...' : author; - } - return ` -
    - ${ props.shortName } - ${ pubmed ? ` ${ author }` : author } -
    - - ` -} - - -function loadStudyThumbnails() { - - let ids = []; - // Collect study IDs 'project-1', 'screen-2' etc - $('div.study').each(function() { - let obj_id = $(this).attr('data-obj_id'); - let obj_type = $(this).attr('data-obj_type'); - if (obj_id && obj_type) { - ids.push(obj_type + '-' + obj_id); - } - }); - - // Load images - model.loadStudiesThumbnails(ids, (data) => { - // data is e.g. { project-1: {thumbnail: base64data, image: {id:1}} } - for (let id in data) { - let obj_type = id.split('-')[0]; - let obj_id = id.split('-')[1]; - let elements = document.querySelectorAll(`div[data-obj_type="${obj_type}"][data-obj_id="${obj_id}"]`); - for (let e=0; e 0) { - let html = FILTER_KEYS - .map(key => { - if (key.label && key.value) { - return `` - } - return `` - }) - .join("\n"); - document.getElementById('studyKeys').innerHTML = html; - // Show the and the whole form - document.getElementById('studyKeys').style.display = 'block'; - document.getElementById('search-form').style.display = 'block'; - } -} -renderStudyKeys(); - - -// ----------- Load / Filter Studies -------------------- - -// Do the loading and render() when done... -model.loadStudies(() => { - // Immediately filter by Super category - if (SUPER_CATEGORY && SUPER_CATEGORY.query) { - model.studies = model.filterStudiesByMapQuery(SUPER_CATEGORY.query); - } - render(); -}); - - -// Load MAPR config -fetch(BASE_URL + 'mapr/api/config/') - .then(response => response.json()) - .then(data => { - mapr_settings = data; - - let options = FILTER_MAPR_KEYS.map(key => { - let config = mapr_settings[key]; - if (config) { - return ``; - } else { - return ""; - } - }); - if (options.length > 0) { - document.getElementById('maprKeys').innerHTML = options.join("\n"); - // Show the and the whole form - document.getElementById('maprKeys').style.display = 'block'; - document.getElementById('search-form').style.display = 'block'; - } - }) - .catch(function(err) { - console.log("mapr not installed (config not available)"); - }); \ No newline at end of file diff --git a/src/model.js b/src/model.js deleted file mode 100644 index d8fe185b..00000000 --- a/src/model.js +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright (C) 2019-2020 University of Dundee & Open Microscopy Environment. -// All rights reserved. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -// NB: SOURCE FILES are under /src. Compiled files are under /static/ - -var StudiesModel = function() { - - "use strict" - - this.base_url = BASE_URL; - - this.studies = []; - - this.images = {} - - return this; -} - -StudiesModel.prototype.getStudyById = function getStudyById(typeId) { - // E.g. 'project-1', or 'screen-2' - let objType = typeId.split('-')[0]; - let id = typeId.split('-')[1]; - for (let i=0; i s.Name); - if (filterQuery) { - names = names.filter(name => name.toLowerCase().indexOf(filterQuery) > -1); - } - names.sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1: -1); - return names; -} - -StudiesModel.prototype.getStudiesGroups = function getStudiesGroups(filterQuery) { - let names = []; - this.studies.forEach(study => { - var groupName = study['omero:details'].group.Name; - if (names.indexOf(groupName) === -1) { - names.push(groupName); - } - }); - if (filterQuery) { - names = names.filter(name => name.toLowerCase().indexOf(filterQuery) > -1); - } - names.sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1); - return names; -} - -StudiesModel.prototype.getStudyValue = function getStudyValue(study, key) { - if (!study.mapValues) return; - for (let i=0; i { - let v = this.getStudyValues(study, key); - for (let i=0; i { - let matches = []; - if (key == "Publication Authors") { - // Split surnames, ignoring AN initials. - let names = value.split(/,| and | & /) - .map(n => { - // Want the surname from e.g. 'Jan Ellenberg' or 'Held M' or 'Øyvind Ødegård-Fougner' - let words = n.split(" ").filter(w => w.match(/[a-z]/g)); - if (words && words.length == 1) return words[0]; // Surname only - return (words && words.length > 1) ? words.slice(1).join(" ") : ''; - }).filter(w => w.length > 0); - matches = names.filter(name => name.toLowerCase().indexOf(inputText) > -1); - } else if (value.toLowerCase().indexOf(inputText) > -1) { - matches.push(value); - } - matches.forEach(match => { - if (!prev[match.toLowerCase()]) { - // key is lowercase, value is original case - prev[match.toLowerCase()] = {value: match, count: 0}; - } - // also keep count of matches - prev[match.toLowerCase()].count++; - }); - - return prev; - }, {}); - - // Make into list and sort by: - // match at start of phrase > match at start of word > other match - let matchList = []; - for (key in matchCounts) { - let matchScore = 1; - if (key.indexOf(inputText) == 0) { - // best match if our text STARTS WITH inputText - matchScore = 3; - } else if (key.indexOf(" " + inputText) > -1) { - // next best if a WORD starts with inputText - matchScore = 2; - } - // Make a list of sort score, orig text (NOT lowercase keys) and count - matchList.push([matchScore, - matchCounts[key].value, - matchCounts[key].count]); - } - - // Sort by the matchScore (hightest first) - matchList.sort(function(a, b) { - if (a[0] < b[0]) return 1; - if (a[0] > b[0]) return -1; - // equal score. Sort by value (lowest first) - if (a[1].toLowerCase() > b[1].toLowerCase()) return 1; - return -1; - }); - - // Return the matches - return matchList - .map(m => { - // Auto-complete uses {label: 'X (n)', value: 'X'} - return {label: `${ m[1] } (${ m[2] })`, value: m[1]} - }) - .filter(m => m.value.length > 0); -} - - -StudiesModel.prototype.loadStudies = function loadStudies(callback) { - - // Load Projects AND Screens, sort them and render... - Promise.all([ - fetch(this.base_url + "api/v0/m/projects/?childCount=true"), - fetch(this.base_url + "api/v0/m/screens/?childCount=true"), - ]).then(responses => - Promise.all(responses.map(res => res.json())) - ).then(([projects, screens]) => { - this.studies = projects.data; - this.studies = this.studies.concat(screens.data); - - // ignore empty studies with no images - this.studies = this.studies.filter(study => study['omero:childCount'] > 0); - - // sort by name, reverse - this.studies.sort(function(a, b) { - var nameA = a.Name.toUpperCase(); - var nameB = b.Name.toUpperCase(); - if (nameA < nameB) { - return 1; - } - if (nameA > nameB) { - return -1; - } - - // names must be equal - return 0; - }); - - // load Map Anns for Studies... - this.loadStudiesMapAnnotations(callback); - - }).catch((err) => { - console.error(err); - }); -} - - -StudiesModel.prototype.loadStudiesThumbnails = function loadStudiesThumbnails(ids, callback) { - let url = GALLERY_INDEX + "gallery-api/thumbnails/"; - // remove duplicates - ids = [...new Set(ids)]; - // find any thumbnails we already have in hand... - let found = {}; - let toFind = []; - ids.forEach(id => { - let study = this.getStudyById(id); - if (study && study.image && study.thumbnail) { - found[id] = {image: study.image, thumbnail: study.thumbnail} - } else { - toFind.push(id); - } - }); - if (Object.keys(found).length > 0) { - callback(found); - } - - toFind = toFind.map(id => id.replace('-', '=')); - let batchSize = 10; - while (toFind.length > 0) { - let data = toFind.slice(0, batchSize).join("&"); - fetch(url + '?' + data) - .then(response => response.json()) - .then(data => { - for (let studyId in data) { - let study = this.getStudyById(studyId); - if (data[studyId]) { - study.image = data[studyId].image; - study.thumbnail = data[studyId].thumbnail; - } - } - if (callback) { - callback(data); - } - }); - toFind = toFind.slice(batchSize); - } -} - - -StudiesModel.prototype.loadStudiesMapAnnotations = function loadStudiesMapAnnotations(callback) { - let url = this.base_url + "webclient/api/annotations/?type=map"; - let data = this.studies - .map(study => `${ study['@type'].split('#')[1].toLowerCase() }=${ study['@id'] }`) - .join("&"); - url += '&' + data; - fetch(url) - .then(response => response.json()) - .then(data => { - // populate the studies array... - // dict of {'project-1' : key-values} - let annsByParentId = {}; - data.annotations.forEach(ann => { - let key = ann.link.parent.class; // 'ProjectI' - key = key.substr(0, key.length-1).toLowerCase(); - key += '-' + ann.link.parent.id; // project-1 - if (!annsByParentId[key]) { - annsByParentId[key] = []; - } - annsByParentId[key] = annsByParentId[key].concat(ann.values); - }); - // Add mapValues to studies... - this.studies = this.studies.map(study => { - // Also set 'type':'screen', 'objId': 'screen-123' - study.type = study['@type'].split('#')[1].toLowerCase(); - study.id = study['@id']; - study.objId = `${ study.type }-${ study['@id'] }`; - let values = annsByParentId[study.objId]; - if (values) { - study.mapValues = values; - let releaseDate = this.getStudyValue(study, 'Release Date'); - if (releaseDate) { - study.date = new Date(releaseDate); - if (isNaN(study.date.getTime())) { - study.date = undefined; - } - } - } - return study; - }); - - if (callback) { - callback(); - }; - }) -} - - -StudiesModel.prototype.filterStudiesByMapQuery = function filterStudiesByMapQuery(query) { - - if (query.startsWith("FIRST") || query.startsWith("LAST")) { - // E.g. query is 'FIRST10:date' sort by 'date' and return first 10 - let limit = parseInt(query.replace('FIRST', '').replace('LAST', '')); - let attr = query.split(':')[1]; - let desc = query.startsWith("FIRST") ? -1 : 1; - // first filter studies, remove those that don't have 'attr' - let sorted = this.studies - .filter(study => study[attr] !== undefined) - .sort((a, b) => { - let aVal = a[attr]; - let bVal = b[attr]; - // If string, use lowercase - aVal = aVal.toLowerCase ? aVal.toLowerCase() : aVal; - bVal = bVal.toLowerCase ? bVal.toLowerCase() : bVal; - return aVal < bVal ? desc : aVal > bVal ? -desc : 0; - }); - return sorted.slice(0, limit); - } - - let matches = this.studies.filter(study => { - // If no key-values loaded, filter out - if (!study.mapValues) { - return false; - } - let match = false; - // first split query by AND and OR - let ors = query.split(' OR '); - ors.forEach(term => { - let allAnds = true; - let ands = term.split(' AND '); - ands.forEach(mustMatch => { - let queryKeyValue = mustMatch.split(":"); - let valueMatch = false; - // check all key-values (may be duplicate keys) for value that matches - for (let i=0; i -1) { - valueMatch = true; - } - } - } - // if not found, then our AND term fails - if (!valueMatch) { - allAnds = false; - } - }); - if (allAnds) { - match = true; - } - }); - return match; - }); - return matches; -} - - -StudiesModel.prototype.loadImage = function loadImage(obj_type, obj_id, callback) { - // Get a sample image ID for 'screen' or 'project' - let key = `${obj_type}-${obj_id}`; - - // check cache - if (this.images[key]) { - callback(this.images[key]); - return; - } - - let limit = 20; - if (obj_type == 'screen') { - let url = `${ this.base_url }api/v0/m/screens/${ obj_id }/plates/`; - url += '?limit=1' // just get first plate - fetch(url) - .then(response => response.json()) - .then(data => { - obj = data.data[0]; - // Jump into the 'middle' of plate to make sure Wells have images - // NB: Some plates don't have Well at each Row/Column spot. Well_count < Rows * Cols * 0.5 - let offset = Math.max(0, parseInt(obj.Rows * obj.Columns * 0.25) - limit); - let url = `${ this.base_url }api/v0/m/plates/${ obj['@id'] }/wells/?limit=${limit}&offset=${offset}`; - return fetch(url) - }) - .then(response => response.json()) - .then(data => { - let wellSample; - for (let w=0; w response.json()) - .then(data => { - obj = data.data[0]; - if (!obj) { - // No Dataset in Project: ' + obj_id; - return; - } - let url = `${ this.base_url }api/v0/m/datasets/${ obj['@id'] }/images/?limit=1`; - return fetch(url) - }) - // Handle undefined if no Datasets in Project... - .then(response => response ? response.json() : {}) - .then(data => { - if (data && data.data && data.data[0]) { - let image = data.data[0]; - this.images[key] = image; - callback(this.images[key]); - } - }) - .catch(error => { - console.error("Error loading Image for Project: " + obj_id, error); - }); - } -} - - - -StudiesModel.prototype.getStudyImage = function getStudyImage(obj_type, obj_id, callback) { - // Get a sample image ID for 'screen' or 'project' - let key = `${obj_type}-${obj_id}`; - - // check cache - if (this.images[key]) { - callback(this.images[key]); - return; - } - - let url = `${ GALLERY_INDEX }gallery-api/${obj_type}s/${ obj_id }/images/?limit=1` - fetch(url) - .then(response => response.json()) - .then(data => { - let images = data.data; - if (images.length > 0) { - this.images[key] = images[0] - } - callback(this.images[key]); - return; - }) - -} - - -function toTitleCase(text) { - if (!text || text.length == 0) return text; - return text[0].toUpperCase() + text.slice(1); -} - - -let getStudyShortName = function (study) { - let shortName = `${toTitleCase(study.type)}: ${study.id}`; - if (STUDY_SHORT_NAME) { - for (let i=0; i < STUDY_SHORT_NAME.length; i++) { - let key = STUDY_SHORT_NAME[i]['key']; - let value; - let newShortName; - if (key === 'Name' || key === 'Description') { - value = study[key]; - } - if (!value) { - value = model.getStudyValue(study, key); - } - if (!value) { - continue; - } - if (STUDY_SHORT_NAME[i]['regex'] && STUDY_SHORT_NAME[i]['template']) { - let re = new RegExp(STUDY_SHORT_NAME[i]['regex']); - let template = STUDY_SHORT_NAME[i]['template']; - newShortName = value.replace(re, template); - } else { - newShortName = value; - } - if (newShortName) { - shortName = newShortName; - break; - } - } - } - return shortName; -} - -// startsWith polyfill for IE -if (!String.prototype.startsWith) { - String.prototype.startsWith = function(search, pos) { - return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; - }; -} - -// Object.assign polyfill for IE -if (typeof Object.assign !== 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target === null || target === undefined) { - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource !== null && nextSource !== undefined) { - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -}