Compare commits

...

62 Commits

Author SHA1 Message Date
Adam Butterworth
2a0b2d40bf stuff 2020-04-01 15:07:56 -04:00
David Joy
d59875c45d Only redirect if the user has no access and isn’t staff (#37)
TNL-7129

This adds a third clause to our useAccessDeniedRedirect hook, which makes sure the user doesn’t have staff access (instead of normal, enrolled access) prior to redirecting.

As an aside, this redirection approach - irrespective of this PR - is not great.  The UI mostly renders prior to this redirect happening.  It would be better of this hook returned something that would help prevent the UI from rendering while the redirect is in progress.  As it stands, a redirected user will see a flash of the page content prior to being booted.  Not wonderful.
2020-04-01 10:18:54 -04:00
David Joy
834b922aff Create 0005-components-own-their-loading-state.md 2020-04-01 10:13:59 -04:00
Dave St.Germain
a1776f4366 Added calculator component (#33)
TNL-7138
2020-03-30 11:59:31 -04:00
Adam Butterworth
f8ff2e7860 Add sequence-container (#36) 2020-03-25 15:26:51 -04:00
David Joy
a923f3d8e7 fix: use history.push to preserve history for user navigation (#35)
We continue to use history.replace for building the MFE URL, which we don’t want saved in history.
2020-03-24 11:09:45 -04:00
David Joy
8f4ff79351 Rename courseUsageKey to courseId 2020-03-23 17:26:33 -04:00
David Joy
c8be4c401f Allow loading with no unit, and of sequences with no unitIds. (#34)
This requires some defensive programming here and there to let things load in a minimal state.
2020-03-23 16:40:50 -04:00
David Joy
781508dd03 fix: Sometimes a course won’t have units.
If a sequence has no unitIds, bail on changing the URL.
2020-03-23 14:15:25 -04:00
David Joy
57ca2948eb fix: unit object not always ready when course loaded
If we don’t yet have the course blocks API loaded when the course metadata finishes, `unit` will be undefined still, and `unit.id` will fail.
2020-03-23 11:59:34 -04:00
David Joy
9cbb765f8a Extensive refactor of application data management. (#32)
* Extensive refactor of application data management.

- “course-blocks” and “course-meta” are replaced with “courseware” module.  This obscures the difference between the two from the application itself.
- a generic “model-store” module is used to store all course, section, sequence, and unit data in a normalized way, agnostic to the metadata vs. blocks APIs.
- SequenceContainer has been removed, and it’s work is just done in CourseContainer instead.
- UI components are - in general - more responsible for deciding their own behavior during data loading.  If they want to show a spinner or nothing, it’s up to their discretion.
- The API layer is responsible for normalizing data into a form the app will want to use, prior to putting it into the model store.

* Organizing into some more sub-modules.

- Bookmarks becomes it’s own module.
- SequenceNavigation becomes another one.

* More modularization of data directories.

- Moving model-store up to the top.
- Moving fetchCourse and fetchSequence up to the top-level data directory, since they’re used by both courseware and outline.
- Moving getBlockCompletion and updateSequencePosition into the courseware/data directory, since they pertain to that page.

* Normalizing on using the word “title”

* Using history.replace instead of history.push

This fixes TNL-7125

* Allowing sub-components to use hooks and redux

This reduces the amount of data we need to pass around, and lets us move some complexity to more natural modules.

* Fixing bug where enrollment alert is shown for undefined isEnrolled

The enrollment alert would inadvertently be shown if a user navigated from the outline to the course.  This was because it interpreted an undefined “isEnrolled” flag as false.  Instead, we should wait for the isEnrolled flag to be explicitly true or false.

* Organizing modules.

- Renaming “outline” to “course-home”.
- Moving sequence and sequence-navigation modules under the course module.

* Some final application organization and ADR write-ups.

* Final refactoring

- Favoring passing data by ID and looking it up in the store with useModel.
- Moving headers into course-header directory.

* Updating ADRs.  Splitting model-store information out into its own ADR.
2020-03-23 11:31:09 -04:00
Adam Butterworth
720594a7cf Update index.scss
Fix media query
2020-03-16 14:29:23 -04:00
Adam Butterworth
94d11bc7c2 fix header on desktop (#31) 2020-03-16 14:21:28 -04:00
Adam Butterworth
fb83d881f6 Make header mobile responsive (#30)
TNL-7072
2020-03-13 16:46:35 -04:00
Adam Butterworth
da4711581a Responsive instructor toolbar and progressive disclosure (#29)
TNL-7072
2020-03-13 14:55:48 -04:00
Adam Butterworth
a4c978a303 Mobile responsive sequence navigation (#28)
[TNL-7072] When a sequence navigation would overflow, convert it to a dropdown.
2020-03-13 12:57:08 -04:00
Adam Butterworth
24ca1aa730 Improve sequence padding and containers on mobile (#27)
TNL-7072.
- Refactors some of the css container/content class naming
- Moved UnitNavigation out of the Sequence and into its own component.
- Fixes an issue with course tabs where multi-word titles would wrap text.
2020-03-11 11:43:17 -04:00
Adam Butterworth
a0839f0a63 Mobile layout for breadcrumbs and tabs (#26)
TNL-7072 mobile layout updates. Breadcrumbs truncate section and subsection titles with ellipsis. Tabs that would overflow are tucked under a "more" dropdown.
2020-03-11 09:37:54 -04:00
David Joy
d145c45a3b feat: Only showing instructor toolbar for course staff. (#25) 2020-03-10 09:33:36 -04:00
Adam Butterworth
fcddc2d639 Log api request errors to New Relic and display load error (#24)
TNL-7114 Logs any failed api request to New Relic. Show error in CourseContainer instead of a spinner when a course fails to load.
2020-03-09 12:43:02 -04:00
David Joy
6082ade9e0 Disabling next/previous buttons at course beginning and end (#23)
At the end, the “next” button at the bottom of the page is replaced with a friendly message.

This PR also alphabetizes some props for SequenceNavigation and Sequence, as I was adding two new ones - isFirst and isLast.
2020-03-06 16:38:47 -05:00
stvn
8358a2589e Merge PR #15 analytics/sequence-events
* Commits:
  Add logging events for sequence navigation
2020-03-06 16:16:47 -05:00
David Joy
6ba8929c97 Initial version of Course Home page (#20)
* refactor: Moving PageLoading up to the top

This way it can be used on both the courseware and outline pages.

* Adding index.js files to data directories, and PropTypes data shapes

- The course-blocks and course-meta data directories now have index files so their exports can be imported from that, rather than reaching into specific files in the directories.
- Also added “shapes” for use in React Components that use PropTypes for the course blocks data structure, and the course metadata data structure.

* Simplifying/refactoring CourseContainer rendering a bit.

* Adding course outline page.

This page is not complete.

- It contains the ‘outline’ itself with links to the Sequences in the course.
- It contains a very basic stab at displaying dates - they’re not even formatted.
- It shows logistration and enrollment alerts for anonymous and unenrolled users.

It does not include any other content in the right-hand sidebar.  It also doesn’t include a welcome message, or perhaps any number of other features on the page.  This is effectively an initial implementation for discovering how much data we’re missing from our APIs.  It should not be used as-is by any means.
2020-03-06 13:21:18 -05:00
stvn
39a0e50745 Add logging events for sequence navigation
to mirror existing behavior in `edx-platform` [2][3][4].

This adds support for the following events:
- `edx.ui.lms.sequence.next_selected`
- `edx.ui.lms.sequence.previous_selected`
- `edx.ui.lms.sequence.tab_selected`

** Outstanding Events
- `edx.ui.lms.outline.*`
- `edx.ui.lms.link_clicked`

** References
- [1] https://openedx.atlassian.net/browse/TNL-7066
- [2] https://edx.readthedocs.io/projects/devdata/en/latest/internal_data_formats/tracking_logs/student_event_types.html#course-navigation-events
- [3] https://github.com/edx/edx-platform/blob/master/common/lib/xmodule/xmodule/js/src/sequence/display.js#L315-321
- [4] https://github.com/edx/edx-platform/blob/master/common/lib/xmodule/xmodule/js/src/sequence/display.js#L373-378
2020-03-06 13:00:16 -05:00
Adam Butterworth
5a3597ac4b Remove edX from preview message 2020-03-06 12:18:46 -05:00
Adam Butterworth
ca15a0af7f Add preview message for instructors (#21)
TNL-7106
2020-03-06 12:10:50 -05:00
Adam Butterworth
8347a66375 Update minor style and visual loading (#19) 2020-03-06 09:20:34 -05:00
Adam Butterworth
31dd6b81b8 Minor style update (#18)
Basic design changes described in TNL-7105
2020-03-05 14:36:13 -05:00
David Joy
1ca797f6e8 fix: removing unused/duplicate functions from course-meta/api.js
The two functions removed here are duplicated (and actually used from) course-blocks/api.js.  Think it was just a refactoring oversight from a few weeks ago.
2020-03-05 10:52:33 -05:00
David Joy
f3e559ad9d Adding a TODO about removing the course links route. 2020-03-05 10:40:09 -05:00
David Joy
c3d0ac1417 Custom alerts for anonymous and unenrolled users. (#17)
* build: bumping version of frontend-platform

We’re going to need to use the new getLoginRedirectUrl helper.

* Adding custom alerts for anonymous and unenrolled users.

- Anonymous users are prompted to sign in or register.
- Unenrolled users are prompted to enroll.

The alerts themselves are lazy-loaded as necessary, like the ContentLock component.

This PR also adds `customAlerts` to the AlertList, allowing an application to specify custom components to be shown as Alerts for a given alert code.

* refactor: Renaming enrollmentIsActive to isEnrolled

As per review feedback that the former wasn’t clear.
2020-03-05 10:23:47 -05:00
Adam Butterworth
bda738c9d1 Add next and previous buttons below unit (#16) 2020-03-04 15:20:11 -05:00
Dave St.Germain
7824f58777 Added a verified upgrade component (#14)
* Added a verified upgrade component

* Internationalize course sock
2020-03-04 13:06:09 -05:00
David Joy
4c09d49532 Adding userHasAccess to redux so we can use it in our components. 2020-02-28 13:54:35 -05:00
David Joy
2f90b78814 If the user does not have access to the course, then redirect to the course outline. (#13)
* If the user does not have access to the course, then redirect to the course outline.

In a subsequent PR, if this API call is made on the course outline page in the MFE, we’ll need to be able to prevent the redirect.  But that view of the MFE doesn’t exist yet.

* Moving course outline redirect logic into CourseContainer.

This way, depending on the page calling fetchCourseMetadata, we can make an intelligent choice about whether we want to redirect, show a message, etc.  By redirecting in the API call handler, then we took that choice away from ourselves.
2020-02-28 12:25:03 -05:00
Adam Butterworth
ba6764de43 feat: add link to unit in existing experience (#12)
* feat: add instructor toolbar with link to lms

* fix: right align user account menu dropdown
2020-02-14 13:05:25 -05:00
Adam Butterworth
46cd511e15 feat: add bookmarking for units (#11)
* feat: add bookmarking for units

* refactor: add redux for state management
2020-02-14 09:10:43 -07:00
David Joy
ab3d3e8834 fix: updating URL when unit changes. 2020-02-04 15:00:21 -05:00
David Joy
ec7166ad5d fix: lint both js and jsx files.
Updating jsx to pass linter, too.
2020-02-04 14:58:19 -05:00
David Joy
ee4908565f Updating to use frontend-build 3.0.0. 2020-02-04 14:38:19 -05:00
David Joy
437f50b261 Fixing linting errors. 2020-01-30 18:14:47 -05:00
Dave St.Germain
dc2971870f Use the new API urls (#10) 2020-01-29 12:50:28 -05:00
Adam Butterworth
5d4d196e0b fix: make iframe width better match parent page (#9) 2020-01-29 12:45:44 -05:00
David Joy
304850b7d1 Listen for iframe resize messages from vertical xblock. 2020-01-27 17:01:40 -05:00
Adam Butterworth
3afac3bcdc Allow fullscreen on unit iframe 2020-01-23 17:23:40 -05:00
David Joy
cf4d63ac99 Removing stub “resume your last course” link for now.
Will be added in TNL-7062
2020-01-17 13:00:52 -05:00
David Joy
637af82873 Passing org, course number, and course name to the CourseHeader. 2020-01-17 11:23:27 -05:00
David Joy
740e22e4c8 Getting course tabs working. 2020-01-16 17:05:03 -05:00
David Joy
83f69dcbfc Connect to courses endpoint and print out the result. 2020-01-16 16:30:49 -05:00
David Joy
3cf204fad3 Bit of styling and propTypes 2020-01-16 15:11:14 -05:00
David Joy
e104674bd1 Adding some missing propTypes 2020-01-16 10:45:33 -05:00
David Joy
869eb9da38 Fixing disabled-when-active unit button. 2020-01-16 10:35:30 -05:00
David Joy
501500f116 Adding hard-coded application header. 2020-01-15 15:51:18 -05:00
David Joy
ed2a14de95 Sequence level messaging works from bannerText. 2020-01-15 14:10:14 -05:00
David Joy
d36b5bd0b0 Adding user-messages module and implementing course-level messaging. 2020-01-15 13:59:05 -05:00
David Joy
2fba819c34 Assume a position of 0 if position is null. 2020-01-15 12:44:30 -05:00
David Joy
c48d2ab9a2 Getting ready to deploy to staging.
Adding a staging course link.
Fixing some errors that occurred when using the demo/staging course links.
2020-01-15 12:29:07 -05:00
David Joy
a19903c0b1 Route and breadcrumb cleanup. 2020-01-15 12:00:29 -05:00
David Joy
9d9b65ceb9 Cleaning up old implementation code. 2020-01-15 11:08:01 -05:00
David Joy
41ab9fc68e Fixing breadcrumbs so they contain the unit. 2020-01-14 17:21:48 -05:00
David Joy
0b171ac9f9 Adding the exam redirect back in. 2020-01-14 17:18:03 -05:00
David Joy
89830af45a Refactoring to use containers and components 2020-01-14 17:11:03 -05:00
103 changed files with 6562 additions and 1861 deletions

View File

@@ -0,0 +1,50 @@
# Courseware Page Decisions
## Courseware data loading
Today we have strictly hierarchical courses - a course contains sections, which contain sequences, which contain units, which contain components.
In creating the courseware pages of this app, we needed to choose how often we fetch data from the server. If we fetch it once and try to get the whole course, including all the data we need in its entire hierarchy, then the request will take 30+ seconds and be a horrible UX. If we try to fetch too granularly, we risk making hundreds of calls to the LMS, incuring both request overhead and common server-side processing that needs to occur for each of those requests.
Instead, we've chosen to load data via the following:
- The course blocks API (/api/courses/v2/blocks) for getting the overall structure of the course (limited data on the whole hierarchy)
- The course metadata API (/api/courseware/course) for detailed top-level data, such as dates, enrollment status, info for tabs across the top of the page, etc.
- The sequence metadata API (/api/courseware/sequence) for detailed information on a sequence, such as which unit to display, any banner messages, whether or not the sequence has a prerequisite, if it's an exam, etc.
- The xblock endpoint (http://localhost:18000/xblock/:block_id) which renders HTML for an xBlock by ID, used to render Unit contents. This HTML is loaded into the application via an iFrame.
These APIs aren't perfect for our usage, but they're getting the job done for now. They weren't built for our purposes and thus load more information than we strictly need, and aren't as performant as we'd like. Future milestones of the application may rely on new, more performant APIs (possibly BFFs)
## Unit iframing
We determined, as part of our project discovery, that in order to deliver value to users sooner, we would iframe in content of units. This allowed us to avoid rebuilding the UI for unit/component xblocks in the micro-frontend, which is a daunting task. It also allows existing custom xblocks to continue to work for now, as they wouldn't have to be re-written.
A future iteration of the project may go back and pull the unit rendering into the MFE.
## Strictly hierarchical courses
We've also made the assumption that courses are strictly hierarchical - a given section, sequence, or unit doesn't have multiple parents. This is important, as it allows us to navigate the tree in the client in a deterministic way. If we need to find out who the parent section of a sequence is, there's only one answer to that question.
## Determining which sequences and units to show
The courseware URL scheme:
`/course/:courseId(/:sequenceId(/:unitId))`
Sequence ID and unit ID are optional.
Today, if the URL only specifies the course ID, we need to pick a sequence to show. We do this by picking the first sequence of the course (as dictated by the course blocks API) and update the URL to match. _After_ the URL has been updated, the application will attempt to load that sequence.
Similarly, if the URL doesn't contain a unit ID, we use the `position` field of the sequence to determine which unit we want to display from that sequence. If the position isn't specified in the sequence, we choose the first unit of the sequence. After determining which unit to display, we update the URL to match. After the URL is updated, the application will attempt to load that unit via an iFrame.
## "Container" components vs. display components
This application makes use of a few "container" components at the top level - CoursewareContainer and CourseHomeContainer.
The point of these containers is to introduce a layer of abstraction between the UI representation of the pages and the way their data was loaded, as described above.
We don't want our Course.jsx component to be intimately aware - for example - that it's data is loaded via two separate APIs that are then merged together. That's not useful information - it just needs to know where it's data is and if it's loaded. Furthermore, this layer of abstraction lets us normalize field names between the various APIs to let our MFE code be more consistent and readable. This normalization is done in the src/data/api.js layer.
## Navigation
Course navigation in a hierarchical course happens primarily via the "sequence navigation". This component lets users navigate to the next and previous unit in the course, and also select specific units within the sequence directly. The next and previous buttons (SequenceNavigation and UnitNavigation) delegate decision making up the tree to CoursewareContainer. This is an intentional separation of concerns which should allow different CoursewareContainer-like components to make different decisions about what it means to go to the "next" or "previous" sequence. This is in support of future course types such as "pathway" courses and adaptive learning sequences. There is no actual code written for these course types, but it felt like a good separation of concerns.

View File

@@ -0,0 +1,7 @@
# Course Home Decisions
The course home page is not complete as of this writing.
It was added to the MFE as a proof of concept for the Engagement theme's Always Available squad, as they were intending to do some work in the legacy course home page in the LMS, and we wanted to understand whether it would be more easily done in this application.
It uses the same APIs as the courseware page, for the most part. This may not always be the case, but it is for now. Differing API shapes may be faster for both pages.

View File

@@ -0,0 +1,7 @@
## Model Store
Because we have a variety of models in this app (course, section, sequence, unit), we use a set of generic 'model store' reducers in redux to manage this data. Once loaded from the APIs, the data is put into the model store by type and by ID, which allows us to quickly access it in the application. Furthermore, any sub-trees of model children (like "items" in the sequence metadata API) are flattened out and stored by ID in the model-store, and their arrays replaced by arrays of IDs. This is a recommended way to store data in redux as documented here:
https://redux.js.org/faq/organizing-state#how-do-i-organize-nested-or-duplicate-data-in-my-state
(As an additional data point, djoy has stored data in this format in multiple projects over the years and found it to be very effective)

View File

@@ -0,0 +1,17 @@
# Components Own Their Own Loading State
Currently, the majority of the components in the component tree for both Courseware and CourseHome own their own loading state. This means that they're _aware_ of the loading status (loading, loaded, failed) of the resources they depend on, and are expected to adjust their own rendering based on that state.
The alternative is for a given component's parent to be responsible for this logic. Under normal circumstances, if the parents were responsible, it would probably result in simpler code in general. A component could just take for granted that if it's being rendered, all it's data must be ready.
*We think that that approach (giving the parents responsibility) isn't appropriate for this application.*
We expect - in the longer term - that different courses/course staff may switch out component implementations. Use a different form of SequenceNavigation, for instance. Because of this, we didn't want parent components to be too aware of the nature of their children. The children are more self-contained this way, though we sacrifice some simplicity for it.
If, for instance, the Sequence component renders a skeleton of the SequenceNavigation, the look of that skeleton is going to be based on an understanding of how the SequenceNavigation renders itself. If the SequenceNavigation implementation is switched out, that loading code in the Sequence may be wrong/misleading to the user. If we leave the loading logic in the parent, we then have to branch it for all the types of SequenceNavigations that may exist - this violates the Open/Closed principle by forcing us to update our application when we try to make a new extension/implementation of a sub-component (assuming we have a plugin/extension/component replacement framework in place).
By moving the loading logic into the components themselves, the idea is to allow a given component to render as much of itself as it reasonably can - this may mean just a spinner, or it may mean a "skeleton" UI while the resources are loading. The parent doesn't need to be aware of the details.
## Under what circumstances would we reverse this decision?
If we find, in time, that we aren't seeing that "switching out component implementations" is a thing that's happening, then we can probably simplify the application code by giving parents the responsibility of deciding when to render their children, rather than keeping that responsibility with the children themselves.

View File

@@ -1,30 +0,0 @@
# Perf test courses
These courses have some large xblocks and small ones. One course has many sequences, the other has fewer.
## Big course: course-v1:MITx+CTL.SC0x+3T2016
- MFE URL: https://learning.edx.org/course/course-v1%3AMITx%2BCTL.SC0x%2B3T2016/0
- URL: https://courses.edx.org/courses/course-v1:MITx+CTL.SC0x+3T2016/course/
### Small xblock
- ID: block-v1:MITx+CTL.SC0x+3T2016+type@vertical+block@0586b59f1cf74e3c982f0b9070e7ad33
- URL: https://courses.edx.org/courses/course-v1:MITx+CTL.SC0x+3T2016/courseware/6a31d02d958e45a398d8a5f1592bdd78/b1ede7bf43c248e19894040718443750/1?activate_block_id=block-v1%3AMITx%2BCTL.SC0x%2B3T2016%2Btype%40vertical%2Bblock%400586b59f1cf74e3c982f0b9070e7ad33
### Big xblock
- ID: block-v1:MITx+CTL.SC0x+3T2016+type@vertical+block@84d6e785f548431a9e82e58d2df4e971
- URL: https://courses.edx.org/courses/course-v1:MITx+CTL.SC0x+3T2016/courseware/b77abc02967e401ca615b23dacf8d115/4913db3e36f14ccd8c98c374b9dae809/2?activate_block_id=block-v1%3AMITx%2BCTL.SC0x%2B3T2016%2Btype%40vertical%2Bblock%4084d6e785f548431a9e82e58d2df4e971
## Small course: course-v1:edX+DevSec101+3T2018
- URL: https://courses.edx.org/courses/course-v1:edX+DevSec101+3T2018/course/
- MFE URL: https://learning.edx.org/course/course-v1%3AedX%2BDevSec101%2B3T2018/0
### Small xblock
- ID: block-v1:edX+DevSec101+3T2018+type@vertical+block@931f96d1822a4fe5b521fcda19245dca
- URL: https://courses.edx.org/courses/course-v1:edX+DevSec101+3T2018/courseware/ee898e64bd174e4aba4c07cd2673e5d3/1a37309647814ab8b333c7a17d50abc4/1?activate_block_id=block-v1%3AedX%2BDevSec101%2B3T2018%2Btype%40vertical%2Bblock%40931f96d1822a4fe5b521fcda19245dca
### Big-ish xblock
- ID: block-v1:edX+DevSec101+3T2018+type@vertical+block@d88210fbc2b74ceab167a52def04e2a0
- URL: https://courses.edx.org/courses/course-v1:edX+DevSec101+3T2018/courseware/b0e2c2b78b5d49308e1454604a255403/38c7049bc8e44d309ab3bdb7f54ae6ae/2?activate_block_id=block-v1%3AedX%2BDevSec101%2B3T2018%2Btype%40vertical%2Bblock%40d88210fbc2b74ceab167a52def04e2a0

3616
package-lock.json generated
View File

@@ -105,88 +105,540 @@
}
},
"@babel/helper-annotate-as-pure": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz",
"integrity": "sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz",
"integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==",
"dev": true,
"requires": {
"@babel/types": "^7.7.4"
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-builder-binary-assignment-operator-visitor": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz",
"integrity": "sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz",
"integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==",
"dev": true,
"requires": {
"@babel/helper-explode-assignable-expression": "^7.7.4",
"@babel/types": "^7.7.4"
"@babel/helper-explode-assignable-expression": "^7.8.3",
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-builder-react-jsx": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.7.4.tgz",
"integrity": "sha512-kvbfHJNN9dg4rkEM4xn1s8d1/h6TYNvajy9L1wx4qLn9HFg0IkTsQi4rfBe92nxrPUFcMsHoMV+8rU7MJb3fCA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz",
"integrity": "sha512-JT8mfnpTkKNCboTqZsQTdGo3l3Ik3l7QIt9hh0O9DYiwVel37VoJpILKM4YFbP2euF32nkQSb+F9cUk9b7DDXQ==",
"dev": true,
"requires": {
"@babel/types": "^7.7.4",
"@babel/types": "^7.8.3",
"esutils": "^2.0.0"
},
"dependencies": {
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-call-delegate": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz",
"integrity": "sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz",
"integrity": "sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==",
"dev": true,
"requires": {
"@babel/helper-hoist-variables": "^7.7.4",
"@babel/traverse": "^7.7.4",
"@babel/types": "^7.7.4"
"@babel/helper-hoist-variables": "^7.8.3",
"@babel/traverse": "^7.8.3",
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/generator": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
"integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.13",
"source-map": "^0.5.0"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/traverse": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
"integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/generator": "^7.8.4",
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3",
"@babel/parser": "^7.8.4",
"@babel/types": "^7.8.3",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.13"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
},
"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"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"@babel/helper-create-class-features-plugin": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.4.tgz",
"integrity": "sha512-l+OnKACG4uiDHQ/aJT8dwpR+LhCJALxL0mJ6nzjB25e5IPwqV1VOsY7ah6UB1DG+VOXAIMtuC54rFJGiHkxjgA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz",
"integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.7.4",
"@babel/helper-member-expression-to-functions": "^7.7.4",
"@babel/helper-optimise-call-expression": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-replace-supers": "^7.7.4",
"@babel/helper-split-export-declaration": "^7.7.4"
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-member-expression-to-functions": "^7.8.3",
"@babel/helper-optimise-call-expression": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/helper-replace-supers": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-create-regexp-features-plugin": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz",
"integrity": "sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz",
"integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==",
"dev": true,
"requires": {
"@babel/helper-regex": "^7.4.4",
"@babel/helper-regex": "^7.8.3",
"regexpu-core": "^4.6.0"
}
},
"@babel/helper-define-map": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz",
"integrity": "sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz",
"integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.7.4",
"@babel/types": "^7.7.4",
"@babel/helper-function-name": "^7.8.3",
"@babel/types": "^7.8.3",
"lodash": "^4.17.13"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-explode-assignable-expression": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz",
"integrity": "sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz",
"integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==",
"dev": true,
"requires": {
"@babel/traverse": "^7.7.4",
"@babel/types": "^7.7.4"
"@babel/traverse": "^7.8.3",
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/generator": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
"integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.13",
"source-map": "^0.5.0"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/traverse": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
"integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/generator": "^7.8.4",
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3",
"@babel/parser": "^7.8.4",
"@babel/types": "^7.8.3",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.13"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
},
"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"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"@babel/helper-function-name": {
@@ -210,53 +662,164 @@
}
},
"@babel/helper-hoist-variables": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz",
"integrity": "sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz",
"integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==",
"dev": true,
"requires": {
"@babel/types": "^7.7.4"
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-member-expression-to-functions": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz",
"integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz",
"integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==",
"dev": true,
"requires": {
"@babel/types": "^7.7.4"
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-module-imports": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz",
"integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz",
"integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==",
"dev": true,
"requires": {
"@babel/types": "^7.7.4"
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-module-transforms": {
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz",
"integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz",
"integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.7.4",
"@babel/helper-simple-access": "^7.7.4",
"@babel/helper-split-export-declaration": "^7.7.4",
"@babel/template": "^7.7.4",
"@babel/types": "^7.7.4",
"@babel/helper-module-imports": "^7.8.3",
"@babel/helper-simple-access": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3",
"lodash": "^4.17.13"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-optimise-call-expression": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz",
"integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz",
"integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==",
"dev": true,
"requires": {
"@babel/types": "^7.7.4"
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-plugin-utils": {
@@ -266,47 +829,355 @@
"dev": true
},
"@babel/helper-regex": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz",
"integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz",
"integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==",
"dev": true,
"requires": {
"lodash": "^4.17.13"
}
},
"@babel/helper-remap-async-to-generator": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz",
"integrity": "sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz",
"integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.7.4",
"@babel/helper-wrap-function": "^7.7.4",
"@babel/template": "^7.7.4",
"@babel/traverse": "^7.7.4",
"@babel/types": "^7.7.4"
"@babel/helper-annotate-as-pure": "^7.8.3",
"@babel/helper-wrap-function": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/traverse": "^7.8.3",
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/generator": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
"integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.13",
"source-map": "^0.5.0"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/traverse": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
"integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/generator": "^7.8.4",
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3",
"@babel/parser": "^7.8.4",
"@babel/types": "^7.8.3",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.13"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
},
"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"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"@babel/helper-replace-supers": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz",
"integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz",
"integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==",
"dev": true,
"requires": {
"@babel/helper-member-expression-to-functions": "^7.7.4",
"@babel/helper-optimise-call-expression": "^7.7.4",
"@babel/traverse": "^7.7.4",
"@babel/types": "^7.7.4"
"@babel/helper-member-expression-to-functions": "^7.8.3",
"@babel/helper-optimise-call-expression": "^7.8.3",
"@babel/traverse": "^7.8.3",
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/generator": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
"integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.13",
"source-map": "^0.5.0"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/traverse": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
"integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/generator": "^7.8.4",
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3",
"@babel/parser": "^7.8.4",
"@babel/types": "^7.8.3",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.13"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
},
"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"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"@babel/helper-simple-access": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz",
"integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz",
"integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==",
"dev": true,
"requires": {
"@babel/template": "^7.7.4",
"@babel/types": "^7.7.4"
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-split-export-declaration": {
@@ -319,15 +1190,144 @@
}
},
"@babel/helper-wrap-function": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz",
"integrity": "sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz",
"integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.7.4",
"@babel/template": "^7.7.4",
"@babel/traverse": "^7.7.4",
"@babel/types": "^7.7.4"
"@babel/helper-function-name": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/traverse": "^7.8.3",
"@babel/types": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/generator": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
"integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.13",
"source-map": "^0.5.0"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/traverse": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
"integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/generator": "^7.8.4",
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3",
"@babel/parser": "^7.8.4",
"@babel/types": "^7.8.3",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.13"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
},
"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"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"@babel/helpers": {
@@ -359,14 +1359,22 @@
"dev": true
},
"@babel/plugin-proposal-async-generator-functions": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz",
"integrity": "sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz",
"integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-remap-async-to-generator": "^7.7.4",
"@babel/plugin-syntax-async-generators": "^7.7.4"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/helper-remap-async-to-generator": "^7.8.3",
"@babel/plugin-syntax-async-generators": "^7.8.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-proposal-class-properties": {
@@ -380,34 +1388,48 @@
}
},
"@babel/plugin-proposal-dynamic-import": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz",
"integrity": "sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz",
"integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.7.4"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/plugin-syntax-dynamic-import": "^7.8.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
},
"@babel/plugin-syntax-dynamic-import": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz",
"integrity": "sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
"integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.0"
}
}
}
},
"@babel/plugin-proposal-json-strings": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz",
"integrity": "sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz",
"integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-json-strings": "^7.7.4"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/plugin-syntax-json-strings": "^7.8.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-proposal-object-rest-spread": {
@@ -421,32 +1443,56 @@
}
},
"@babel/plugin-proposal-optional-catch-binding": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz",
"integrity": "sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz",
"integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-optional-catch-binding": "^7.7.4"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/plugin-syntax-optional-catch-binding": "^7.8.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-proposal-unicode-property-regex": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz",
"integrity": "sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz",
"integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==",
"dev": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-create-regexp-features-plugin": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-syntax-async-generators": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz",
"integrity": "sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g==",
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
"integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-syntax-dynamic-import": {
@@ -459,21 +1505,37 @@
}
},
"@babel/plugin-syntax-json-strings": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz",
"integrity": "sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
"integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-syntax-jsx": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz",
"integrity": "sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz",
"integrity": "sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-syntax-object-rest-spread": {
@@ -486,368 +1548,814 @@
}
},
"@babel/plugin-syntax-optional-catch-binding": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz",
"integrity": "sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
"integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-arrow-functions": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz",
"integrity": "sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz",
"integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-async-to-generator": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz",
"integrity": "sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz",
"integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-remap-async-to-generator": "^7.7.4"
"@babel/helper-module-imports": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/helper-remap-async-to-generator": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-block-scoped-functions": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz",
"integrity": "sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz",
"integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-block-scoping": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz",
"integrity": "sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz",
"integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-plugin-utils": "^7.8.3",
"lodash": "^4.17.13"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-classes": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz",
"integrity": "sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz",
"integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.7.4",
"@babel/helper-define-map": "^7.7.4",
"@babel/helper-function-name": "^7.7.4",
"@babel/helper-optimise-call-expression": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-replace-supers": "^7.7.4",
"@babel/helper-split-export-declaration": "^7.7.4",
"@babel/helper-annotate-as-pure": "^7.8.3",
"@babel/helper-define-map": "^7.8.3",
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-optimise-call-expression": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/helper-replace-supers": "^7.8.3",
"@babel/helper-split-export-declaration": "^7.8.3",
"globals": "^11.1.0"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
},
"@babel/helper-split-export-declaration": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
"integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/plugin-transform-computed-properties": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz",
"integrity": "sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz",
"integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-destructuring": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz",
"integrity": "sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz",
"integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-dotall-regex": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz",
"integrity": "sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz",
"integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==",
"dev": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-create-regexp-features-plugin": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-duplicate-keys": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz",
"integrity": "sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz",
"integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-exponentiation-operator": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz",
"integrity": "sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz",
"integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==",
"dev": true,
"requires": {
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-for-of": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz",
"integrity": "sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA==",
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz",
"integrity": "sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-function-name": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz",
"integrity": "sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz",
"integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-function-name": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.8.3"
}
},
"@babel/helper-function-name": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
"integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
},
"@babel/highlight": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
"integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
"dev": true
},
"@babel/template": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
"integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/types": "^7.8.3"
}
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/plugin-transform-literals": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz",
"integrity": "sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz",
"integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-member-expression-literals": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz",
"integrity": "sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz",
"integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-modules-amd": {
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz",
"integrity": "sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz",
"integrity": "sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==",
"dev": true,
"requires": {
"@babel/helper-module-transforms": "^7.7.5",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-module-transforms": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3",
"babel-plugin-dynamic-import-node": "^2.3.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-modules-commonjs": {
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz",
"integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz",
"integrity": "sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==",
"dev": true,
"requires": {
"@babel/helper-module-transforms": "^7.7.5",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-simple-access": "^7.7.4",
"@babel/helper-module-transforms": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/helper-simple-access": "^7.8.3",
"babel-plugin-dynamic-import-node": "^2.3.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-modules-systemjs": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz",
"integrity": "sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz",
"integrity": "sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==",
"dev": true,
"requires": {
"@babel/helper-hoist-variables": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-hoist-variables": "^7.8.3",
"@babel/helper-module-transforms": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3",
"babel-plugin-dynamic-import-node": "^2.3.0"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-modules-umd": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz",
"integrity": "sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz",
"integrity": "sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==",
"dev": true,
"requires": {
"@babel/helper-module-transforms": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-module-transforms": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-named-capturing-groups-regex": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz",
"integrity": "sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz",
"integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==",
"dev": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.7.4"
"@babel/helper-create-regexp-features-plugin": "^7.8.3"
}
},
"@babel/plugin-transform-new-target": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz",
"integrity": "sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz",
"integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-object-super": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz",
"integrity": "sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz",
"integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-replace-supers": "^7.7.4"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/helper-replace-supers": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-parameters": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz",
"integrity": "sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw==",
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz",
"integrity": "sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA==",
"dev": true,
"requires": {
"@babel/helper-call-delegate": "^7.7.4",
"@babel/helper-get-function-arity": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-call-delegate": "^7.8.3",
"@babel/helper-get-function-arity": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-get-function-arity": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
"integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
"dev": true,
"requires": {
"@babel/types": "^7.8.3"
}
},
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
},
"@babel/types": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
"integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/plugin-transform-property-literals": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz",
"integrity": "sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz",
"integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-react-constant-elements": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.7.4.tgz",
"integrity": "sha512-U6XkHZ8RnmeEb8jBUOpeo6oFka5RhLgxAVvK4/fBbwoYlsHQYLb8I37ymTPDVsrWjqb94+hueuWQA/1OAA4rAQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.8.3.tgz",
"integrity": "sha512-glrzN2U+egwRfkNFtL34xIBYTxbbUF2qJTP8HD3qETBBqzAWSeNB821X0GjU06+dNpq/UyCIjI72FmGE5NNkQQ==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-annotate-as-pure": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-react-display-name": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.7.4.tgz",
"integrity": "sha512-sBbIvqYkthai0X0vkD2xsAwluBp+LtNHH+/V4a5ydifmTtb8KOVOlrMIk/MYmIc4uTYDnjZUHQildYNo36SRJw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz",
"integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-react-jsx": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.7.4.tgz",
"integrity": "sha512-LixU4BS95ZTEAZdPaIuyg/k8FiiqN9laQ0dMHB4MlpydHY53uQdWCUrwjLr5o6ilS6fAgZey4Q14XBjl5tL6xw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz",
"integrity": "sha512-r0h+mUiyL595ikykci+fbwm9YzmuOrUBi0b+FDIKmi3fPQyFokWVEMJnRWHJPPQEjyFJyna9WZC6Viv6UHSv1g==",
"dev": true,
"requires": {
"@babel/helper-builder-react-jsx": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.7.4"
"@babel/helper-builder-react-jsx": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-react-jsx-self": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.7.4.tgz",
"integrity": "sha512-PWYjSfqrO273mc1pKCRTIJXyqfc9vWYBax88yIhQb+bpw3XChVC7VWS4VwRVs63wFHKxizvGSd00XEr+YB9Q2A==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.8.3.tgz",
"integrity": "sha512-01OT7s5oa0XTLf2I8XGsL8+KqV9lx3EZV+jxn/L2LQ97CGKila2YMroTkCEIE0HV/FF7CMSRsIAybopdN9NTdg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.7.4"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-react-jsx-source": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.7.4.tgz",
"integrity": "sha512-5ZU9FnPhqtHsOXxutRtXZAzoEJwDaP32QcobbMP1/qt7NYcsCNK8XgzJcJfoEr/ZnzVvUNInNjIW22Z6I8p9mg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz",
"integrity": "sha512-PLMgdMGuVDtRS/SzjNEQYUT8f4z1xb2BAT54vM1X5efkVuYBf5WyGUMbpmARcfq3NaglIwz08UVQK4HHHbC6ag==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.7.4"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-regenerator": {
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz",
"integrity": "sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz",
"integrity": "sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==",
"dev": true,
"requires": {
"regenerator-transform": "^0.14.0"
}
},
"@babel/plugin-transform-reserved-words": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz",
"integrity": "sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz",
"integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-shorthand-properties": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz",
"integrity": "sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz",
"integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-spread": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz",
"integrity": "sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz",
"integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-sticky-regex": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz",
"integrity": "sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz",
"integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-regex": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3",
"@babel/helper-regex": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-template-literals": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz",
"integrity": "sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz",
"integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-annotate-as-pure": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-typeof-symbol": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz",
"integrity": "sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg==",
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz",
"integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/plugin-transform-unicode-regex": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz",
"integrity": "sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz",
"integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==",
"dev": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0"
"@babel/helper-create-regexp-features-plugin": "^7.8.3",
"@babel/helper-plugin-utils": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
"dev": true
}
}
},
"@babel/preset-env": {
@@ -936,6 +2444,16 @@
}
}
},
"@babel/runtime-corejs3": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.8.4.tgz",
"integrity": "sha512-+wpLqy5+fbQhvbllvlJEVRIpYj+COUWnnsm+I4jZlA8Lo7/MJmBhGTCHyk1/RWfOqBRJ2MbadddG6QltTKTlrg==",
"dev": true,
"requires": {
"core-js-pure": "^3.0.0",
"regenerator-runtime": "^0.13.2"
}
},
"@babel/template": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz",
@@ -1011,14 +2529,20 @@
}
},
"@cospired/i18n-iso-languages": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@cospired/i18n-iso-languages/-/i18n-iso-languages-2.1.0.tgz",
"integrity": "sha512-r+bqdtVTkO8R07JiBxEc7ckbkXgeIP/X51MxqxODv9gZovc/MBDS6uJVCHg+mtJuldwvSD6L0XF5RzH6qyAacQ=="
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@cospired/i18n-iso-languages/-/i18n-iso-languages-2.1.1.tgz",
"integrity": "sha512-dmlPmVw51tQzCJkYvtWWXxuvsAkNvCmUnvjMWyo7Qd318YeEZalCUInUgdhKU985gk2wkITtdakPYqk5GrJ99A=="
},
"@edx/eslint-config": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@edx/eslint-config/-/eslint-config-1.1.4.tgz",
"integrity": "sha512-CKPvyEnOGKWT15VNUmyzhqU3GxVkrCzUekI6XxdbF21oU9bICsHh/rXTtLDdz0EfzK5XvYAhk1OmCu47o6nG8A==",
"dev": true
},
"@edx/frontend-build": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-2.0.5.tgz",
"integrity": "sha512-3m+fKAkYliVz9QKuU4xkU4dGu5XqfSJuwYU6aH+pDBtaVj0+wz6srbei6iPoNx9A96rVwJU4aIqDwzmrlx3zgQ==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-3.0.0.tgz",
"integrity": "sha512-vYsDROEEgN2Ko2aPvWUQudhaNR4B4Mv57IJf8hVdF5WqQBvJ7JIddJjQV2Wng2kMjhlqkGbof/BPeVSsr3RugQ==",
"dev": true,
"requires": {
"@babel/cli": "7.6.0",
@@ -1028,6 +2552,7 @@
"@babel/plugin-syntax-dynamic-import": "7.2.0",
"@babel/preset-env": "7.6.0",
"@babel/preset-react": "7.0.0",
"@edx/eslint-config": "1.1.4",
"@svgr/webpack": "4.3.2",
"autoprefixer": "9.6.1",
"babel-eslint": "10.0.3",
@@ -1042,8 +2567,12 @@
"cssnano": "4.1.10",
"dotenv": "8.1.0",
"dotenv-webpack": "1.7.0",
"eslint": "6.4.0",
"eslint-config-edx": "4.0.4",
"eslint": "6.8.0",
"eslint-config-airbnb": "18.0.1",
"eslint-plugin-import": "2.20.0",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-react": "7.18.0",
"eslint-plugin-react-hooks": "1.7.0",
"file-loader": "4.2.0",
"glob": "7.1.4",
"html-webpack-harddisk-plugin": "1.0.1",
@@ -1055,7 +2584,7 @@
"lodash.defaultsdeep": "4.6.1",
"mini-css-extract-plugin": "0.8.0",
"new-relic-source-map-webpack-plugin": "1.2.0",
"node-sass": "4.12.0",
"node-sass": "4.13.1",
"postcss-loader": "3.0.0",
"postcss-rtl": "1.5.0",
"react-dev-utils": "9.0.3",
@@ -1136,13 +2665,13 @@
}
},
"@edx/frontend-platform": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-1.1.11.tgz",
"integrity": "sha512-Nx1nj/WSZ6ELUUOyjAWfHVTJIkWt7MUhN8cHKCwrnvNcXsAAqKkG3ZiLWErmdg+asfvXcn6E6Ipzej6E7t91PA==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-1.3.1.tgz",
"integrity": "sha512-RAJ6IciIX+ZwXhlBfxOOB0sjNNpBQaN/eDLsgztL9MxEmuAvQtbvQBBJAum6qsVZpKzOZYhtRYFyWoHTuyzFZA==",
"requires": {
"@cospired/i18n-iso-languages": "2.1.0",
"@cospired/i18n-iso-languages": "2.1.1",
"axios": "0.18.1",
"form-urlencoded": "4.1.0",
"form-urlencoded": "4.1.3",
"glob": "7.1.6",
"history": "4.10.1",
"i18n-iso-countries": "4.3.1",
@@ -1153,7 +2682,7 @@
"lodash.snakecase": "4.1.1",
"pubsub-js": "1.7.0",
"react-intl": "2.9.0",
"universal-cookie": "4.0.2"
"universal-cookie": "4.0.3"
}
},
"@edx/paragon": {
@@ -1190,18 +2719,18 @@
}
},
"@formatjs/intl-unified-numberformat": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@formatjs/intl-unified-numberformat/-/intl-unified-numberformat-2.2.0.tgz",
"integrity": "sha512-A9ov4uO04pSHG5Iqcrc457hvsq3lz/oWQ3B0I03zbL1rnBC8ttrZEobw3X3k/tWYPXeNJbRtsSbXqzJo55NeBw==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@formatjs/intl-unified-numberformat/-/intl-unified-numberformat-3.2.0.tgz",
"integrity": "sha512-SZMTV/tR0h7nYhS2x69S7zhHXaBmE0ZTR2OIiakt8W7uYWVgcRhu/LgUeVtGzpwPI2ChcOjNMtX/k6y1M9aDNA==",
"dev": true,
"requires": {
"@formatjs/intl-utils": "^1.6.0"
"@formatjs/intl-utils": "^2.2.0"
}
},
"@formatjs/intl-utils": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@formatjs/intl-utils/-/intl-utils-1.6.0.tgz",
"integrity": "sha512-5D0C4tQgNFJNaJ17BYum0GfAcKNK3oa1VWzgkv/AN7i52fg4r69ZLcpEGpf6tZiX9Qld8CDwTQOeFt6fuOqgVw==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@formatjs/intl-utils/-/intl-utils-2.2.0.tgz",
"integrity": "sha512-+Az7tR1av1DHZu9668D8uh9atT6vp+FFmEF8BrEssv0OqzpVjpVBGVmcgPzQP8k2PQjVlm/h2w8cTt0knn132w==",
"dev": true
},
"@fortawesome/fontawesome-common-types": {
@@ -1657,6 +3186,26 @@
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
"dev": true
},
"@reduxjs/toolkit": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.2.3.tgz",
"integrity": "sha512-CgeZl41Bmz1rFkASt5gA9egCy9YWXzy485EsEXoGd2Xm1o63UQCxfuCLTH+XlTs25WqtGjSmn5H4xu7n86ytYw==",
"requires": {
"immer": "^4.0.1",
"redux": "^4.0.0",
"redux-devtools-extension": "^2.13.8",
"redux-immutable-state-invariant": "^2.1.0",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0"
},
"dependencies": {
"immer": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/immer/-/immer-4.0.2.tgz",
"integrity": "sha512-Q/tm+yKqnKy4RIBmmtISBlhXuSDrB69e9EKTYiIenIKQkXBQir43w+kN/eGiax3wt1J0O1b2fYcNqLSbEcXA7w=="
}
}
},
"@sindresorhus/is": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
@@ -1881,9 +3430,9 @@
"dev": true
},
"@types/node": {
"version": "12.12.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.17.tgz",
"integrity": "sha512-Is+l3mcHvs47sKy+afn2O1rV4ldZFU7W8101cNlOd+MRbjM4Onida8jSZnJdTe/0Pcf25g9BNIUsuugmE6puHA==",
"version": "13.7.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz",
"integrity": "sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==",
"dev": true
},
"@types/normalize-package-data": {
@@ -2403,9 +3952,9 @@
"dev": true
},
"aria-query": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.1.tgz",
"integrity": "sha1-Jsu1r/ZBRLCoJb4YRuCxbPoAsR4=",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
"integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
"dev": true,
"requires": {
"ast-types-flow": "0.0.7",
@@ -2461,32 +4010,68 @@
"dev": true
},
"array-includes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.0.tgz",
"integrity": "sha512-ONOEQoKrvXPKk7Su92Co0YMqYO32FfqJTzkKU9u2UpIXyYZIzLSvpdg4AwvSw4mSUW0czu6inK+zby6Oj6gDjQ==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz",
"integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.0"
"es-abstract": "^1.17.0",
"is-string": "^1.0.5"
},
"dependencies": {
"es-abstract": {
"version": "1.17.0-next.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz",
"integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==",
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.4",
"is-regex": "^1.0.4",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.0",
"string.prototype.trimright": "^2.1.0"
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
}
}
@@ -2543,22 +4128,57 @@
},
"dependencies": {
"es-abstract": {
"version": "1.17.0-next.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz",
"integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==",
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.4",
"is-regex": "^1.0.4",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.0",
"string.prototype.trimright": "^2.1.0"
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
}
}
@@ -2703,12 +4323,13 @@
}
},
"axobject-query": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz",
"integrity": "sha1-YvWdvFnJ+SQnWco0mWDnov48NsA=",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.1.tgz",
"integrity": "sha512-lF98xa/yvy6j3fBHAgQXIYl+J4eZadOSqsPojemUqClzNbBV38wWGpUbQbVEyf4eUF5yF7eHmGgGA2JiHyjeqw==",
"dev": true,
"requires": {
"ast-types-flow": "0.0.7"
"@babel/runtime": "^7.7.4",
"@babel/runtime-corejs3": "^7.7.4"
}
},
"babel-code-frame": {
@@ -2863,12 +4484,12 @@
},
"dependencies": {
"intl-messageformat-parser": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-3.5.1.tgz",
"integrity": "sha512-aCUjbLCZYhWJzC5gJiXKYR+OCE8rIegRBsjm1irJSH0AmeC7dIOp3nzOCc84BcyFX5baoXJfijV6SWqYUrN27w==",
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-3.6.4.tgz",
"integrity": "sha512-RgPGwue0mJtoX2Ax8EmMzJzttxjnva7gx0Q7mKJ4oALrTZvtmCeAw5Msz2PcjW4dtCh/h7vN/8GJCxZO1uv+OA==",
"dev": true,
"requires": {
"@formatjs/intl-unified-numberformat": "^2.2.0"
"@formatjs/intl-unified-numberformat": "^3.2.0"
}
}
}
@@ -3353,9 +4974,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -3622,14 +5243,14 @@
}
},
"browserslist": {
"version": "4.8.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz",
"integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==",
"version": "4.8.6",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz",
"integrity": "sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001015",
"electron-to-chromium": "^1.3.322",
"node-releases": "^1.1.42"
"caniuse-lite": "^1.0.30001023",
"electron-to-chromium": "^1.3.341",
"node-releases": "^1.1.47"
}
},
"bser": {
@@ -3892,9 +5513,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001015",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz",
"integrity": "sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ==",
"version": "1.0.30001025",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001025.tgz",
"integrity": "sha512-SKyFdHYfXUZf5V85+PJgLYyit27q4wgvZuf8QTOk1osbypcROihMBlx9GRar2/pIcKH2r4OehdlBr9x6PXetAQ==",
"dev": true
},
"caporal": {
@@ -4076,12 +5697,6 @@
"safe-buffer": "^5.0.1"
}
},
"circular-json": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
"integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
"dev": true
},
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@@ -4111,9 +5726,9 @@
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
},
"clean-css": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
"integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
"integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
"dev": true,
"requires": {
"source-map": "~0.6.0"
@@ -4129,12 +5744,12 @@
}
},
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
"integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
"dev": true,
"requires": {
"restore-cursor": "^2.0.0"
"restore-cursor": "^3.1.0"
}
},
"cli-table3": {
@@ -4354,12 +5969,20 @@
}
},
"compressible": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
"integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==",
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
"integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
"dev": true,
"requires": {
"mime-db": ">= 1.40.0 < 2"
"mime-db": ">= 1.43.0 < 2"
},
"dependencies": {
"mime-db": {
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
"dev": true
}
}
},
"compression": {
@@ -4465,6 +6088,12 @@
"proto-list": "~1.2.1"
}
},
"confusing-browser-globals": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz",
"integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==",
"dev": true
},
"connect-history-api-fallback": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
@@ -4604,23 +6233,29 @@
"integrity": "sha512-hIE5dXkRzRvnZ5vhkRfQxUvDxQZmD9oueA08jDYRBKJHx+VIl/Pne/e0A4x9LObEEthC/TqiZybUoNM4tRgnKg=="
},
"core-js-compat": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.5.0.tgz",
"integrity": "sha512-E7iJB72svRjJTnm9HDvujzNVMCm3ZcDYEedkJ/sDTNsy/0yooCd9Cg7GSzE7b4e0LfIkjijdB1tqg0pGwxWeWg==",
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz",
"integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==",
"dev": true,
"requires": {
"browserslist": "^4.8.2",
"semver": "^6.3.0"
"browserslist": "^4.8.3",
"semver": "7.0.0"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
"integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
"dev": true
}
}
},
"core-js-pure": {
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz",
"integrity": "sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw==",
"dev": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -4757,9 +6392,9 @@
},
"dependencies": {
"schema-utils": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz",
"integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==",
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
"integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
"dev": true,
"requires": {
"ajv": "^6.10.2",
@@ -4968,9 +6603,9 @@
}
},
"damerau-levenshtein": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz",
"integrity": "sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA==",
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
"integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==",
"dev": true
},
"dashdash": {
@@ -5524,9 +7159,9 @@
"dev": true
},
"dotenv-defaults": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-1.0.2.tgz",
"integrity": "sha512-iXFvHtXl/hZPiFj++1hBg4lbKwGM+t/GlvELDnRtOFdjXyWP7mubkVr+eZGWG62kdsbulXAef6v/j6kiWc/xGA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-1.1.1.tgz",
"integrity": "sha512-6fPRo9o/3MxKvmRZBD3oNFdxODdhJtIy1zcJeUSCs6HCy4tarUpd+G67UTU9tF6OWXeSPqsm4fPAB+2eY9Rt9Q==",
"dev": true,
"requires": {
"dotenv": "^6.2.0"
@@ -5622,9 +7257,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -5676,9 +7311,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.322",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz",
"integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==",
"version": "1.3.345",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.345.tgz",
"integrity": "sha512-f8nx53+Z9Y+SPWGg3YdHrbYYfIJAtbUjpFfW4X1RwTZ94iUG7geg9tV8HqzAXX7XTNgyWgAFvce4yce8ZKxKmg==",
"dev": true
},
"elliptic": {
@@ -5764,9 +7399,9 @@
}
},
"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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -5944,9 +7579,9 @@
}
},
"eslint": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz",
"integrity": "sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==",
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
"integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
@@ -5956,19 +7591,19 @@
"debug": "^4.0.1",
"doctrine": "^3.0.0",
"eslint-scope": "^5.0.0",
"eslint-utils": "^1.4.2",
"eslint-utils": "^1.4.3",
"eslint-visitor-keys": "^1.1.0",
"espree": "^6.1.1",
"espree": "^6.1.2",
"esquery": "^1.0.1",
"esutils": "^2.0.2",
"file-entry-cache": "^5.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
"globals": "^11.7.0",
"globals": "^12.1.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"inquirer": "^6.4.1",
"inquirer": "^7.0.0",
"is-glob": "^4.0.0",
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
@@ -5977,7 +7612,7 @@
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"optionator": "^0.8.3",
"progress": "^2.0.0",
"regexpp": "^2.0.1",
"semver": "^6.1.2",
@@ -6006,6 +7641,15 @@
"is-glob": "^4.0.1"
}
},
"globals": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz",
"integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==",
"dev": true,
"requires": {
"type-fest": "^0.8.1"
}
},
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -6039,329 +7683,45 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
}
}
},
"eslint-config-airbnb": {
"version": "16.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz",
"integrity": "sha512-zLyOhVWhzB/jwbz7IPSbkUuj7X2ox4PHXTcZkEmDqTvd0baJmJyuxlFPDlZOE/Y5bC+HQRaEkT3FoHo9wIdRiw==",
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.0.1.tgz",
"integrity": "sha512-hLb/ccvW4grVhvd6CT83bECacc+s4Z3/AEyWQdIT2KeTsG9dR7nx1gs7Iw4tDmGKozCNHFn4yZmRm3Tgy+XxyQ==",
"dev": true,
"requires": {
"eslint-config-airbnb-base": "^12.1.0"
"eslint-config-airbnb-base": "^14.0.0",
"object.assign": "^4.1.0",
"object.entries": "^1.1.0"
}
},
"eslint-config-airbnb-base": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz",
"integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==",
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz",
"integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==",
"dev": true,
"requires": {
"eslint-restricted-globals": "^0.1.1"
}
},
"eslint-config-edx": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/eslint-config-edx/-/eslint-config-edx-4.0.4.tgz",
"integrity": "sha512-4xm13P14kcm3IppkjL8X3HDxLgA064l3F50sy7z8ioyB4kDLRepSSXhyDHR8vHDd46yztmnuIPXbEEgVNOL4xg==",
"dev": true,
"requires": {
"eslint": "^4.5.0",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-dollar-sign": "^1.0.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "6.0.3",
"eslint-plugin-react": "^7.5.1"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
"dev": true
},
"acorn-jsx": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
"integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
"dev": true,
"requires": {
"acorn": "^3.0.4"
},
"dependencies": {
"acorn": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
"dev": true
}
}
},
"ajv": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"dev": true,
"requires": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.3.0"
}
},
"ajv-keywords": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
"integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
"dev": true
},
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true
},
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"dev": true,
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"requires": {
"esutils": "^2.0.2"
}
},
"eslint": {
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
"integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
"dev": true,
"requires": {
"ajv": "^5.3.0",
"babel-code-frame": "^6.22.0",
"chalk": "^2.1.0",
"concat-stream": "^1.6.0",
"cross-spawn": "^5.1.0",
"debug": "^3.1.0",
"doctrine": "^2.1.0",
"eslint-scope": "^3.7.1",
"eslint-visitor-keys": "^1.0.0",
"espree": "^3.5.4",
"esquery": "^1.0.0",
"esutils": "^2.0.2",
"file-entry-cache": "^2.0.0",
"functional-red-black-tree": "^1.0.1",
"glob": "^7.1.2",
"globals": "^11.0.1",
"ignore": "^3.3.3",
"imurmurhash": "^0.1.4",
"inquirer": "^3.0.6",
"is-resolvable": "^1.0.0",
"js-yaml": "^3.9.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.3.0",
"lodash": "^4.17.4",
"minimatch": "^3.0.2",
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"path-is-inside": "^1.0.2",
"pluralize": "^7.0.0",
"progress": "^2.0.0",
"regexpp": "^1.0.1",
"require-uncached": "^1.0.3",
"semver": "^5.3.0",
"strip-ansi": "^4.0.0",
"strip-json-comments": "~2.0.1",
"table": "4.0.2",
"text-table": "~0.2.0"
}
},
"eslint-scope": {
"version": "3.7.3",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz",
"integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==",
"dev": true,
"requires": {
"esrecurse": "^4.1.0",
"estraverse": "^4.1.1"
}
},
"espree": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
"integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
"dev": true,
"requires": {
"acorn": "^5.5.0",
"acorn-jsx": "^3.0.0"
}
},
"external-editor": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"dev": true,
"requires": {
"chardet": "^0.4.0",
"iconv-lite": "^0.4.17",
"tmp": "^0.0.33"
}
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
"dev": true
},
"file-entry-cache": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
"integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
"dev": true,
"requires": {
"flat-cache": "^1.2.1",
"object-assign": "^4.0.1"
}
},
"flat-cache": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
"integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==",
"dev": true,
"requires": {
"circular-json": "^0.3.1",
"graceful-fs": "^4.1.2",
"rimraf": "~2.6.2",
"write": "^0.2.1"
}
},
"inquirer": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
"integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
"dev": true,
"requires": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^2.0.4",
"figures": "^2.0.0",
"lodash": "^4.3.0",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rx-lite": "^4.0.8",
"rx-lite-aggregates": "^4.0.8",
"string-width": "^2.1.0",
"strip-ansi": "^4.0.0",
"through": "^2.3.6"
}
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
"dev": true
},
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"dev": true,
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"regexpp": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
"integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
"dev": true
},
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
},
"slice-ansi": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
"integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "^3.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=",
"dev": true
},
"table": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
"integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
"dev": true,
"requires": {
"ajv": "^5.2.3",
"ajv-keywords": "^2.1.0",
"chalk": "^2.1.0",
"lodash": "^4.17.4",
"slice-ansi": "1.0.0",
"string-width": "^2.1.1"
}
},
"write": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
"integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
"dev": true,
"requires": {
"mkdirp": "^0.5.1"
}
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
}
"confusing-browser-globals": "^1.0.7",
"object.assign": "^4.1.0",
"object.entries": "^1.1.0"
}
},
"eslint-import-resolver-node": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz",
"integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==",
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz",
"integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==",
"dev": true,
"requires": {
"debug": "^2.6.9",
"resolve": "^1.5.0"
"resolve": "^1.13.1"
},
"dependencies": {
"debug": {
@@ -6376,9 +7736,9 @@
}
},
"eslint-module-utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz",
"integrity": "sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==",
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz",
"integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==",
"dev": true,
"requires": {
"debug": "^2.6.9",
@@ -6448,22 +7808,10 @@
}
}
},
"eslint-plugin-dollar-sign": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-dollar-sign/-/eslint-plugin-dollar-sign-1.0.2.tgz",
"integrity": "sha512-AtA5MJpMAh0kKzSx/u7DuDbPRijIZmlt6n75CR8Q3UQ18Fo4QFfYK15lJ8OhXQQUYR7zTMMB2x37KyP3LnAC/g==",
"dev": true
},
"eslint-plugin-eslint-plugin": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-2.1.0.tgz",
"integrity": "sha512-kT3A/ZJftt28gbl/Cv04qezb/NQ1dwYIbi8lyf806XMxkus7DvOVCLIfTXMrorp322Pnoez7+zabXH29tADIDg==",
"dev": true
},
"eslint-plugin-import": {
"version": "2.19.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz",
"integrity": "sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw==",
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz",
"integrity": "sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==",
"dev": true,
"requires": {
"array-includes": "^3.0.3",
@@ -6608,44 +7956,37 @@
}
},
"eslint-plugin-jsx-a11y": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.3.tgz",
"integrity": "sha1-VFg9GuRCSDFi4EDhPMMYZUZRAOU=",
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz",
"integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==",
"dev": true,
"requires": {
"aria-query": "^0.7.0",
"@babel/runtime": "^7.4.5",
"aria-query": "^3.0.0",
"array-includes": "^3.0.3",
"ast-types-flow": "0.0.7",
"axobject-query": "^0.1.0",
"damerau-levenshtein": "^1.0.0",
"emoji-regex": "^6.1.0",
"jsx-ast-utils": "^2.0.0"
},
"dependencies": {
"emoji-regex": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
"integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==",
"dev": true
}
"ast-types-flow": "^0.0.7",
"axobject-query": "^2.0.2",
"damerau-levenshtein": "^1.0.4",
"emoji-regex": "^7.0.2",
"has": "^1.0.3",
"jsx-ast-utils": "^2.2.1"
}
},
"eslint-plugin-react": {
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.17.0.tgz",
"integrity": "sha512-ODB7yg6lxhBVMeiH1c7E95FLD4E/TwmFjltiU+ethv7KPdCwgiFuOZg9zNRHyufStTDLl/dEFqI2Q1VPmCd78A==",
"version": "7.18.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz",
"integrity": "sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ==",
"dev": true,
"requires": {
"array-includes": "^3.0.3",
"array-includes": "^3.1.1",
"doctrine": "^2.1.0",
"eslint-plugin-eslint-plugin": "^2.1.0",
"has": "^1.0.3",
"jsx-ast-utils": "^2.2.3",
"object.entries": "^1.1.0",
"object.fromentries": "^2.0.1",
"object.values": "^1.1.0",
"object.entries": "^1.1.1",
"object.fromentries": "^2.0.2",
"object.values": "^1.1.1",
"prop-types": "^15.7.2",
"resolve": "^1.13.1"
"resolve": "^1.14.2"
},
"dependencies": {
"doctrine": {
@@ -6656,13 +7997,88 @@
"requires": {
"esutils": "^2.0.2"
}
},
"es-abstract": {
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"object.entries": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz",
"integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.1",
"function-bind": "^1.1.1",
"has": "^1.0.3"
}
},
"resolve": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz",
"integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
}
}
},
"eslint-restricted-globals": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz",
"integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=",
"eslint-plugin-react-hooks": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz",
"integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==",
"dev": true
},
"eslint-scope": {
@@ -6750,9 +8166,9 @@
"dev": true
},
"events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
"integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
"integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==",
"dev": true
},
"eventsource": {
@@ -7238,9 +8654,9 @@
"dev": true
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz",
"integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5"
@@ -7266,9 +8682,9 @@
},
"dependencies": {
"schema-utils": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz",
"integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==",
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
"integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
"dev": true,
"requires": {
"ajv": "^6.10.2",
@@ -7459,9 +8875,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -7552,9 +8968,9 @@
}
},
"form-urlencoded": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/form-urlencoded/-/form-urlencoded-4.1.0.tgz",
"integrity": "sha512-1F/gR6Lx+KX1PtV2l0Gg+PcJ61h5NLNJBgIK4p+L1V958h5bmPi8GD8enlT1a7Sr32EVzea+qOzpO/gl3mOgZA=="
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/form-urlencoded/-/form-urlencoded-4.1.3.tgz",
"integrity": "sha512-z0YJtPuq0BSOrErlpj+o1KHTRaOH6LN16043ZVK2Wk5uUGpX308PJ5ZJDtU++ndoZkzASHVclUTD2mb1jHzqlA=="
},
"formidable": {
"version": "1.2.1",
@@ -7600,9 +9016,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -7673,9 +9089,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -8504,9 +9920,9 @@
}
},
"globule": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
"integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz",
"integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==",
"dev": true,
"requires": {
"glob": "~7.1.1",
@@ -8823,9 +10239,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -9500,24 +10916,81 @@
"dev": true
},
"inquirer": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
"integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz",
"integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==",
"dev": true,
"requires": {
"ansi-escapes": "^3.2.0",
"ansi-escapes": "^4.2.1",
"chalk": "^2.4.2",
"cli-cursor": "^2.1.0",
"cli-cursor": "^3.1.0",
"cli-width": "^2.0.0",
"external-editor": "^3.0.3",
"figures": "^2.0.0",
"lodash": "^4.17.12",
"mute-stream": "0.0.7",
"figures": "^3.0.0",
"lodash": "^4.17.15",
"mute-stream": "0.0.8",
"run-async": "^2.2.0",
"rxjs": "^6.4.0",
"string-width": "^2.1.0",
"rxjs": "^6.5.3",
"string-width": "^4.1.0",
"strip-ansi": "^5.1.0",
"through": "^2.3.6"
},
"dependencies": {
"ansi-escapes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz",
"integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==",
"dev": true,
"requires": {
"type-fest": "^0.8.1"
}
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
}
}
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
}
}
},
"internal-ip": {
@@ -9973,6 +11446,12 @@
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true
},
"is-string": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
"integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
"dev": true
},
"is-svg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz",
@@ -10700,8 +12179,7 @@
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json3": {
"version": "3.3.3",
@@ -11194,12 +12672,6 @@
"p-is-promise": "^2.0.0"
},
"dependencies": {
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
"p-is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
@@ -11225,9 +12697,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -11490,9 +12962,9 @@
}
},
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
"mimic-response": {
@@ -11686,9 +13158,9 @@
"dev": true
},
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
"dev": true
},
"nan": {
@@ -11865,9 +13337,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -11935,9 +13407,9 @@
}
},
"node-releases": {
"version": "1.1.42",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.42.tgz",
"integrity": "sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==",
"version": "1.1.47",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz",
"integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==",
"dev": true,
"requires": {
"semver": "^6.3.0"
@@ -11952,9 +13424,9 @@
}
},
"node-sass": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz",
"integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==",
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz",
"integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==",
"dev": true,
"requires": {
"async-foreach": "^0.1.3",
@@ -11964,7 +13436,7 @@
"get-stdin": "^4.0.1",
"glob": "^7.0.3",
"in-publish": "^2.0.0",
"lodash": "^4.17.11",
"lodash": "^4.17.15",
"meow": "^3.7.0",
"mkdirp": "^0.5.1",
"nan": "^2.13.2",
@@ -12246,15 +13718,71 @@
}
},
"object.fromentries": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.1.tgz",
"integrity": "sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz",
"integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.15.0",
"es-abstract": "^1.17.0-next.1",
"function-bind": "^1.1.1",
"has": "^1.0.3"
},
"dependencies": {
"es-abstract": {
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
}
}
},
"object.getownpropertydescriptors": {
@@ -12277,15 +13805,71 @@
}
},
"object.values": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz",
"integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz",
"integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.12.0",
"es-abstract": "^1.17.0-next.1",
"function-bind": "^1.1.1",
"has": "^1.0.3"
},
"dependencies": {
"es-abstract": {
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
}
}
},
"obuf": {
@@ -12318,12 +13902,12 @@
}
},
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
"integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
"integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
"dev": true,
"requires": {
"mimic-fn": "^1.0.0"
"mimic-fn": "^2.1.0"
}
},
"open": {
@@ -12575,9 +14159,9 @@
"dev": true
},
"pako": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
"integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==",
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"dev": true
},
"parallel-transform": {
@@ -12598,9 +14182,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -12891,12 +14475,6 @@
"semver-compare": "^1.0.0"
}
},
"pluralize": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
"dev": true
},
"pn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
@@ -13917,6 +15495,15 @@
"node-releases": "^1.1.25"
}
},
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
"integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
"dev": true,
"requires": {
"restore-cursor": "^2.0.0"
}
},
"dir-glob": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz",
@@ -13927,6 +15514,15 @@
"path-type": "^3.0.0"
}
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5"
}
},
"globby": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz",
@@ -13963,6 +15559,37 @@
"through": "^2.3.6"
}
},
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true
},
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
"dev": true
},
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
"integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
"dev": true,
"requires": {
"mimic-fn": "^1.0.0"
}
},
"restore-cursor": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
"integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
"dev": true,
"requires": {
"onetime": "^2.0.0",
"signal-exit": "^3.0.2"
}
},
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
@@ -13983,9 +15610,9 @@
}
},
"react-error-overlay": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.4.tgz",
"integrity": "sha512-ueZzLmHltszTshDMwyfELDq8zOA803wQ1ZuzCccXa1m57k1PxSHfflPD5W9YIiTXLs0JTLzoj6o1LuM5N6zzNA==",
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.5.tgz",
"integrity": "sha512-+DMR2k5c6BqMDSMF8hLH0vYKtKTeikiFW+fj0LClN+XZg4N9b8QUAdHC62CGWNLTi/gnuuemNcNcTFrCvK1f+A==",
"dev": true
},
"react-intl": {
@@ -14131,9 +15758,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -14191,14 +15818,33 @@
}
},
"redux": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.4.tgz",
"integrity": "sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==",
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
"integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
"requires": {
"loose-envify": "^1.4.0",
"symbol-observable": "^1.2.0"
}
},
"redux-devtools-extension": {
"version": "2.13.8",
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz",
"integrity": "sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg=="
},
"redux-immutable-state-invariant": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/redux-immutable-state-invariant/-/redux-immutable-state-invariant-2.1.0.tgz",
"integrity": "sha512-3czbDKs35FwiBRsx/3KabUk5zSOoTXC+cgVofGkpBNv3jQcqIe5JrHcF5AmVt7B/4hyJ8MijBIpCJ8cife6yJg==",
"requires": {
"invariant": "^2.1.0",
"json-stringify-safe": "^5.0.1"
}
},
"redux-thunk": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
"integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
},
"reflect.ownkeys": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz",
@@ -14250,12 +15896,69 @@
"dev": true
},
"regexp.prototype.flags": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz",
"integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
"integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
"dev": true,
"requires": {
"define-properties": "^1.1.2"
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.1"
},
"dependencies": {
"es-abstract": {
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
}
}
},
"regexpp": {
@@ -14285,9 +15988,9 @@
"dev": true
},
"regjsparser": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz",
"integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==",
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz",
"integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
@@ -14476,45 +16179,17 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
"require-uncached": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
"integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
"dev": true,
"requires": {
"caller-path": "^0.1.0",
"resolve-from": "^1.0.0"
},
"dependencies": {
"caller-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
"integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
"dev": true,
"requires": {
"callsites": "^0.2.0"
}
},
"callsites": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
"dev": true
},
"resolve-from": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
"dev": true
}
}
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
},
"reselect": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
},
"resolve": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz",
@@ -14657,12 +16332,12 @@
}
},
"restore-cursor": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
"integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
"integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
"dev": true,
"requires": {
"onetime": "^2.0.0",
"onetime": "^5.1.0",
"signal-exit": "^3.0.2"
}
},
@@ -14801,25 +16476,10 @@
"integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=",
"dev": true
},
"rx-lite": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
"integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
"dev": true
},
"rx-lite-aggregates": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
"integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
"dev": true,
"requires": {
"rx-lite": "*"
}
},
"rxjs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
"integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",
"integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
@@ -16068,9 +17728,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -16122,9 +17782,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -16183,9 +17843,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -16366,9 +18026,9 @@
},
"dependencies": {
"schema-utils": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz",
"integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==",
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
"integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
"dev": true,
"requires": {
"ajv": "^6.10.2",
@@ -16426,9 +18086,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -16466,9 +18126,9 @@
}
},
"svg-parser": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.2.tgz",
"integrity": "sha512-1gtApepKFweigFZj3sGO8KT8LvVZK8io146EzXrpVuWCDAbISz/yMucco3hWTkpZNoPabM+dnMOpy6Swue68Zg==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.3.tgz",
"integrity": "sha512-fnCWiifNhK8i2Z7b9R5tbNahpxrRdAaQbnoxKlT2KrSCj9Kq/yBSgulCRgBJRhy1dPnSY5slg5ehPUnzpEcHlg==",
"dev": true
},
"svgo": {
@@ -16773,9 +18433,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -16832,9 +18492,9 @@
}
},
"terser": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.4.2.tgz",
"integrity": "sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ==",
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz",
"integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==",
"dev": true,
"requires": {
"commander": "^2.20.0",
@@ -16906,9 +18566,9 @@
"dev": 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==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -17279,9 +18939,9 @@
}
},
"universal-cookie": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.2.tgz",
"integrity": "sha512-n14lhA//lQeYRweP9j9uXsshN9Cs4LunVSnvAGmnA69SofwsjpUU03geaCaPC9LlsH2rkBy99o3zxQyVOldGvA==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.3.tgz",
"integrity": "sha512-YbEHRs7bYOBTIWedTR9koVEe2mXrq+xdjTJZcoKJK/pQaE6ni28ak2AKXFpevb+X6w3iU5SXzWDiJkmpDRb9qw==",
"requires": {
"@types/cookie": "^0.3.3",
"@types/object-assign": "^4.0.30",
@@ -17416,9 +19076,9 @@
"dev": true
},
"schema-utils": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz",
"integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==",
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
"integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
"dev": true,
"requires": {
"ajv": "^6.10.2",
@@ -17542,9 +19202,9 @@
"dev": true
},
"vendors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz",
"integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
"integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==",
"dev": true
},
"verror": {

View File

@@ -14,7 +14,7 @@
"build": "fedx-scripts webpack",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"is-es5": "es-check es5 ./dist/*.js",
"lint": "fedx-scripts eslint",
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
"snapshot": "fedx-scripts jest --updateSnapshot",
"start": "fedx-scripts webpack-dev-server --progress",
"test": "fedx-scripts jest --coverage --passWithNoTests"
@@ -36,13 +36,15 @@
"dependencies": {
"@edx/frontend-component-footer": "^10.0.6",
"@edx/frontend-component-header": "^2.0.3",
"@edx/frontend-platform": "^1.1.11",
"@edx/frontend-platform": "^1.3.1",
"@edx/paragon": "^7.2.0",
"@fortawesome/fontawesome-svg-core": "^1.2.26",
"@fortawesome/free-brands-svg-icons": "^5.12.0",
"@fortawesome/free-regular-svg-icons": "^5.12.0",
"@fortawesome/free-solid-svg-icons": "^5.12.0",
"@fortawesome/react-fontawesome": "^0.1.8",
"@reduxjs/toolkit": "^1.2.3",
"classnames": "^2.2.6",
"core-js": "^3.6.2",
"prop-types": "^15.7.2",
"react": "^16.12.0",
@@ -50,11 +52,11 @@
"react-redux": "^7.1.3",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"redux": "^4.0.4",
"redux": "^4.0.5",
"regenerator-runtime": "^0.13.3"
},
"devDependencies": {
"@edx/frontend-build": "^2.0.5",
"@edx/frontend-build": "^3.0.0",
"codecov": "^3.6.1",
"es-check": "^5.1.0",
"glob": "^7.1.6",

30
src/CourseContainer.jsx Normal file
View File

@@ -0,0 +1,30 @@
import React from 'react';
import {
Route, Switch, useParams, useRouteMatch,
} from 'react-router-dom';
import SequenceContainer from './SequenceContainer';
export default (props) => {
const { path } = useRouteMatch();
const { courseId } = useParams();
return (
<>
<div>CourseContainer</div>
<Switch>
<Route exact path={path}>
<h3>{path} find the sequence and redirect</h3>
</Route>
<Route exact path={`${path}/home`}>
<h3>Course Home</h3>
</Route>
{/* CoursewareContainer ???? */}
<Route
path={`${path}/sequence/:sequenceId`}
component={SequenceContainer}
/>
</Switch>
</>
);
};

34
src/SequenceContainer.jsx Normal file
View File

@@ -0,0 +1,34 @@
import React from 'react';
import {
Route, Switch, useParams, useRouteMatch,
} from 'react-router-dom';
export default (props) => {
const { path } = useRouteMatch();
const { courseId, sequenceId } = useParams();
// const { courseId } = props;
return (
<>
<div>SequenceContainer</div>
{courseId} <br />
{sequenceId}
<Switch>
<Route exact path={path}>
<h3>{path} find the unit and redirect</h3>
</Route>
<Route exact path={`${path}/home`}>
<h3>Course Home</h3>
</Route>
<Route
path={`${path}/sequence/:sequenceId`}
render={(routeProps) => (
<SequenceContainer {...routeProps} courseId={courseId} />
)}
/>
</Switch>
{props.children}
</>
);
};

View File

@@ -1,74 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
import NavTab from './NavTab';
function CourseTabsNavigation({ activeTabSlug, courseTabs, intl }) {
const courseNavTabs = courseTabs.map(({ slug, ...courseTab }) => (
<NavTab
isActive={slug === activeTabSlug}
key={slug}
{...courseTab}
/>
));
return (
<nav
aria-label={intl.formatMessage(messages['learn.navigation.course.tabs.label'])}
className="nav nav-underline-tabs"
>
{courseNavTabs}
</nav>
);
}
CourseTabsNavigation.propTypes = {
activeTabSlug: PropTypes.string,
courseTabs: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string.isRequired,
priority: PropTypes.number.isRequired,
slug: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
})),
intl: intlShape.isRequired,
};
CourseTabsNavigation.defaultProps = {
activeTabSlug: undefined,
courseTabs: [
{
title: 'Course',
slug: 'course',
priority: 1,
url: 'http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/course/',
},
{
title: 'Discussion',
slug: 'discussion',
priority: 2,
url: 'http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/discussion/forum/',
},
{
title: 'Wiki',
slug: 'wiki',
priority: 3,
url: 'http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/course_wiki',
},
{
title: 'Progress',
slug: 'progress',
priority: 4,
url: 'http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/progress',
},
{
title: 'Instructor',
slug: 'instructor',
priority: 5,
url: 'http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/instructor',
},
],
};
export default injectIntl(CourseTabsNavigation);

View File

@@ -1,30 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
export default function NavTab(props) {
const {
isActive, url, title, ...attrs
} = props;
const className = classNames(
'nav-item nav-link',
{ active: isActive },
attrs.className,
);
return <a {...attrs} className={className} href={url}>{title}</a>;
}
NavTab.propTypes = {
className: PropTypes.string,
isActive: PropTypes.bool,
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
};
NavTab.defaultProps = {
className: undefined,
isActive: false,
};

View File

@@ -0,0 +1,50 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import classNames from 'classnames';
import messages from './messages';
import Tabs from '../tabs/Tabs';
function CourseTabsNavigation({
activeTabSlug, tabs, intl,
}) {
return (
<div className="course-tabs-navigation">
<div className="container-fluid">
<Tabs
className="nav-underline-tabs"
aria-label={intl.formatMessage(messages['learn.navigation.course.tabs.label'])}
>
{tabs.map(({ url, title, slug }) => (
<a
key={slug}
className={classNames('nav-item flex-shrink-0 nav-link', { active: slug === activeTabSlug })}
href={`${getConfig().LMS_BASE_URL}${url}`}
>
{title}
</a>
))}
</Tabs>
</div>
</div>
);
}
CourseTabsNavigation.propTypes = {
activeTabSlug: PropTypes.string,
tabs: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string.isRequired,
priority: PropTypes.number.isRequired,
slug: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
})).isRequired,
intl: intlShape.isRequired,
};
CourseTabsNavigation.defaultProps = {
activeTabSlug: undefined,
};
export default injectIntl(CourseTabsNavigation);

View File

@@ -0,0 +1,74 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { Dropdown } from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform';
import { AppContext } from '@edx/frontend-platform/react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
import logo from './assets/logo.svg';
function LinkedLogo({
href,
src,
alt,
...attributes
}) {
return (
<a href={href} {...attributes}>
<img className="d-block" src={src} alt={alt} />
</a>
);
}
LinkedLogo.propTypes = {
href: PropTypes.string.isRequired,
src: PropTypes.string.isRequired,
alt: PropTypes.string.isRequired,
};
export default function Header({
courseOrg, courseNumber, courseTitle,
}) {
const { authenticatedUser } = useContext(AppContext);
return (
<header className="course-header">
<div className="container-fluid py-2 d-flex align-items-center ">
<LinkedLogo
className="logo"
href={`${getConfig().LMS_BASE_URL}/dashboard`}
src={logo}
alt={getConfig().SITE_NAME}
/>
<div className="flex-grow-1 course-title-lockup" style={{ lineHeight: 1 }}>
<span className="d-block small m-0">{courseOrg} {courseNumber}</span>
<span className="d-block m-0 font-weight-bold course-title">{courseTitle}</span>
</div>
<Dropdown className="user-dropdown">
<Dropdown.Button>
<FontAwesomeIcon icon={faUserCircle} className="d-md-none" size="lg" />
<span className="d-none d-md-inline">
{authenticatedUser.username}
</span>
</Dropdown.Button>
<Dropdown.Menu className="dropdown-menu-right">
<Dropdown.Item href={`${getConfig().LMS_BASE_URL}/dashboard`}>Dashboard</Dropdown.Item>
<Dropdown.Item href={`${getConfig().LMS_BASE_URL}/u/${authenticatedUser.username}`}>Profile</Dropdown.Item>
<Dropdown.Item href={`${getConfig().LMS_BASE_URL}/account/settings`}>Account</Dropdown.Item>
<Dropdown.Item href={getConfig().ORDER_HISTORY_URL}>Order History</Dropdown.Item>
<Dropdown.Item href={getConfig().LOGOUT_URL}>Sign Out</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
</header>
);
}
Header.propTypes = {
courseOrg: PropTypes.string.isRequired,
courseNumber: PropTypes.string.isRequired,
courseTitle: PropTypes.string.isRequired,
};

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1168px" height="540px" viewBox="0 0 1168 540" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 53.2 (72643) - https://sketchapp.com -->
<title>logo</title>
<desc>Created with Sketch.</desc>
<g id="logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon id="Path" fill="#209FDA" fill-rule="nonzero" points="1166.81993 85.5 1166.81993 2.84217094e-14 953.759925 2.84217094e-14 953.759925 85.5 1002.17993 85.5 915.859925 191.98 829.459925 85.5 878.099925 85.5 878.099925 2.84217094e-14 718.919925 2.84217094e-14 718.919925 95.72 856.479925 265.26 718.919925 434.96 718.919925 452.02 784.499925 452.02 784.499925 539.64 878.099925 539.64 878.099925 452.02 823.919925 452.02 915.919925 338.52 915.939925 338.52 1008.03993 452.02 953.759925 452.02 953.759925 539.64 1166.81993 539.64 1166.81993 452.02 1126.85993 452.02 975.319925 265.26 1121.01993 85.5"></polygon>
<polygon id="Path" fill="#026BA4" fill-rule="nonzero" points="664.019925 7.10542736e-15 664.019925 85.5 710.619925 85.5 718.919925 95.72 718.919925 7.10542736e-15"></polygon>
<polygon id="Path" fill="#026BA4" fill-rule="nonzero" points="718.919925 452.02 718.919925 434.96 705.079925 452.02 664.019925 452.02 664.019925 539.64 784.499925 539.64 784.499925 452.02"></polygon>
<path d="M321.999925,411.86 L397.659925,411.86 C388.805702,433.829527 376.258024,454.122269 360.559925,471.86 C344.364089,454.216816 331.320914,433.921419 321.999925,411.86" id="Path" fill="#78212E" fill-rule="nonzero"></path>
<path d="M360.559925,189.28 C338.58337,213.190393 322.501981,241.908137 313.599925,273.14 C317.134915,280.039338 320.007771,287.25831 322.179925,294.7 L397.059925,294.7 C399.306706,287.354671 402.25356,280.242036 405.859925,273.46 C397.464721,242.277678 381.959326,213.464341 360.559925,189.28 Z M322.179925,294.7 C328.784599,317.438017 328.978396,341.558795 322.739925,364.4 L396.399925,364.4 C389.855554,341.597488 390.06397,317.386469 396.999925,294.7 L322.179925,294.7 Z M322.179925,294.7 L308.679925,294.7 C304.690779,317.752715 304.575868,341.309464 308.339925,364.4 L322.739925,364.4 C328.978396,341.558795 328.784599,317.438017 322.179925,294.7 L322.179925,294.7 Z" id="Shape" fill="#78212E" fill-rule="nonzero"></path>
<path d="M710.619925,85.5 L664.019925,85.5 L664.019925,0.02 L576.019925,0.02 L576.019925,85.5 L632.859925,85.5 L632.859925,159.2 C598.417874,134.487772 557.04992,121.286425 514.659925,121.48 C456.044663,121.405246 400.107354,146.01621 360.559925,189.28 C381.937732,213.470272 397.422343,242.283149 405.799925,273.46 C426.944121,233.500977 468.451514,208.51034 513.659925,208.52 C581.059925,208.52 632.879925,263.16 632.879925,330.52 L632.879925,331.2 C632.539925,398.28 580.879925,452.56 513.659925,452.56 C468.477451,452.593197 426.976426,427.652566 405.799925,387.74 L405.799925,387.74 C401.869213,380.340239 398.718926,372.551658 396.399925,364.5 L308.399925,364.5 C309.686934,372.450225 311.443338,380.317312 313.659925,388.06 C315.970162,396.190434 318.775397,404.171995 322.059925,411.96 L397.659925,411.96 C388.805702,433.929527 376.258024,454.222269 360.559925,471.96 C400.107354,515.22379 456.044663,539.834754 514.659925,539.76 C571.465111,540.091874 625.745998,516.316729 664.019925,474.34 L664.019925,452.04 L705.059925,452.04 L718.899925,434.96 L718.899925,95.74 L710.619925,85.5 Z M632.879925,501.9 L632.879925,539.74 L664.019925,539.74 L664.019925,474.18 C654.623775,484.469293 644.18821,493.758755 632.879925,501.9 L632.879925,501.9 Z M313.599925,273.14 C311.569597,280.231983 309.927163,287.429316 308.679925,294.7 L322.179925,294.7 C320.007771,287.25831 317.134915,280.039338 313.599925,273.14 L313.599925,273.14 Z" id="Shape" fill="#8A8C8F" fill-rule="nonzero"></path>
<path d="M410.399925,294.7 C409.199925,287.5 407.659925,280.4 405.799925,273.46 C402.19356,280.242036 399.246706,287.354671 396.999925,294.7 C390.06397,317.386469 389.855554,341.597488 396.399925,364.4 L410.719925,364.4 C414.264276,341.293291 414.156293,317.77319 410.399925,294.7 L410.399925,294.7 Z M209.059925,121.48 C107.422724,121.487508 20.5081632,194.571683 3.05992537,294.7 L91.3999254,294.7 C107.135726,243.467257 154.465065,208.503753 208.059925,208.52 C252.638644,208.335148 293.496156,233.351373 313.599925,273.14 C322.501981,241.908137 338.58337,213.190393 360.559925,189.28 C322.206855,145.880863 266.976617,121.163964 209.059925,121.48 L209.059925,121.48 Z M297.479925,411.86 C275.077969,437.877726 242.392659,452.761934 208.059925,452.58 C153.691226,452.598435 105.87164,416.63791 90.7999254,364.4 L308.339925,364.4 C304.575868,341.309464 304.690779,317.752715 308.679925,294.7 L3.05992537,294.7 C-0.902504563,317.755068 -1.01739385,341.307372 2.71992537,364.4 L2.71992537,364.4 C19.3292424,465.441984 106.661918,539.594765 209.059925,539.6 C266.986094,539.900862 322.217868,515.161403 360.559925,471.74 C344.364089,454.096816 331.320914,433.801419 321.999925,411.74 L297.479925,411.86 Z" id="Shape" fill="#B72768" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,2 @@
export { default as Header } from './Header';
export { default as CourseTabsNavigation } from './CourseTabsNavigation';

View File

@@ -0,0 +1,41 @@
import React from 'react';
import PropTypes from 'prop-types';
export default function CourseDates({
start,
end,
enrollmentStart,
enrollmentEnd,
enrollmentMode,
isEnrolled,
}) {
return (
<section>
<h4>Upcoming Dates</h4>
<div><strong>Course Start:</strong><br />{start}</div>
<div><strong>Course End:</strong><br />{end}</div>
<div><strong>Enrollment Start:</strong><br />{enrollmentStart}</div>
<div><strong>Enrollment End:</strong><br />{enrollmentEnd}</div>
<div><strong>Mode:</strong><br />{enrollmentMode}</div>
<div>{isEnrolled ? 'Active Enrollment' : 'Inactive Enrollment'}</div>
</section>
);
}
CourseDates.propTypes = {
start: PropTypes.string,
end: PropTypes.string,
enrollmentStart: PropTypes.string,
enrollmentEnd: PropTypes.string,
enrollmentMode: PropTypes.string,
isEnrolled: PropTypes.bool,
};
CourseDates.defaultProps = {
start: null,
end: null,
enrollmentStart: null,
enrollmentEnd: null,
enrollmentMode: null,
isEnrolled: false,
};

View File

@@ -0,0 +1,92 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from '@edx/paragon';
import AlertList from '../user-messages/AlertList';
import { Header, CourseTabsNavigation } from '../course-header';
import { useLogistrationAlert } from '../logistration-alert';
import { useEnrollmentAlert } from '../enrollment-alert';
import CourseDates from './CourseDates';
import Section from './Section';
import { useModel } from '../model-store';
const EnrollmentAlert = React.lazy(() => import('../enrollment-alert'));
const LogistrationAlert = React.lazy(() => import('../logistration-alert'));
export default function CourseHome({
courseId,
}) {
useLogistrationAlert();
useEnrollmentAlert(courseId);
const {
org,
number,
title,
start,
end,
enrollmentStart,
enrollmentEnd,
enrollmentMode,
isEnrolled,
tabs,
sectionIds,
} = useModel('courses', courseId);
return (
<>
<Header
courseOrg={org}
courseNumber={number}
courseTitle={title}
/>
<main className="d-flex flex-column flex-grow-1">
<div className="container-fluid">
<CourseTabsNavigation tabs={tabs} className="mb-3" activeTabSlug="courseware" />
<AlertList
topic="outline"
className="mb-3"
customAlerts={{
clientEnrollmentAlert: EnrollmentAlert,
clientLogistrationAlert: LogistrationAlert,
}}
/>
</div>
<div className="flex-grow-1">
<div className="container-fluid">
<div className="d-flex justify-content-between mb-3">
<h2>{title}</h2>
<Button className="btn-primary" type="button">Resume Course</Button>
</div>
<div className="row">
<div className="col col-8">
{sectionIds.map((sectionId) => (
<Section
key={sectionId}
id={sectionId}
courseId={courseId}
/>
))}
</div>
<div className="col col-4">
<CourseDates
start={start}
end={end}
enrollmentStart={enrollmentStart}
enrollmentEnd={enrollmentEnd}
enrollmentMode={enrollmentMode}
isEnrolled={isEnrolled}
/>
</div>
</div>
</div>
</div>
</main>
</>
);
}
CourseHome.propTypes = {
courseId: PropTypes.string.isRequired,
};

View File

@@ -0,0 +1,54 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
import PageLoading from '../PageLoading';
import CourseHome from './CourseHome';
import { fetchCourse } from '../data';
function CourseHomeContainer(props) {
const {
intl,
match,
} = props;
const dispatch = useDispatch();
useEffect(() => {
// The courseId from the URL is the course we WANT to load.
dispatch(fetchCourse(match.params.courseId));
}, [match.params.courseId]);
// The courseId from the store is the course we HAVE loaded. If the URL changes,
// we don't want the application to adjust to it until it has actually loaded the new data.
const {
courseId,
courseStatus,
} = useSelector(state => state.courseware);
return (
<>
{courseStatus === 'loaded' ? (
<CourseHome
courseId={courseId}
/>
) : (
<PageLoading
srMessage={intl.formatMessage(messages['learn.loading.outline'])}
/>
)}
</>
);
}
CourseHomeContainer.propTypes = {
intl: intlShape.isRequired,
match: PropTypes.shape({
params: PropTypes.shape({
courseId: PropTypes.string.isRequired,
}).isRequired,
}).isRequired,
};
export default injectIntl(CourseHomeContainer);

View File

@@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Collapsible } from '@edx/paragon';
import { faChevronRight, faChevronDown } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import SequenceLink from './SequenceLink';
import { useModel } from '../model-store';
export default function Section({ id, courseId }) {
const section = useModel('sections', id);
const { title, sequenceIds } = section;
return (
<Collapsible.Advanced className="collapsible-card mb-2">
<Collapsible.Trigger className="collapsible-trigger d-flex align-items-start">
<Collapsible.Visible whenClosed>
<div style={{ minWidth: '1rem' }}>
<FontAwesomeIcon icon={faChevronRight} />
</div>
</Collapsible.Visible>
<Collapsible.Visible whenOpen>
<div style={{ minWidth: '1rem' }}>
<FontAwesomeIcon icon={faChevronDown} />
</div>
</Collapsible.Visible>
<div className="ml-2 flex-grow-1">{title}</div>
</Collapsible.Trigger>
<Collapsible.Body className="collapsible-body">
{sequenceIds.map((sequenceId) => (
<SequenceLink
key={sequenceId}
id={sequenceId}
courseId={courseId}
/>
))}
</Collapsible.Body>
</Collapsible.Advanced>
);
}
Section.propTypes = {
id: PropTypes.string.isRequired,
courseId: PropTypes.string.isRequired,
};

View File

@@ -0,0 +1,18 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { useModel } from '../model-store';
export default function SequenceLink({ id, courseId }) {
const sequence = useModel('sequences', id);
return (
<div className="ml-4">
<Link to={`/course/${courseId}/${id}`}>{sequence.title}</Link>
</div>
);
}
SequenceLink.propTypes = {
id: PropTypes.string.isRequired,
courseId: PropTypes.string.isRequired,
};

1
src/course-home/index.js Normal file
View File

@@ -0,0 +1 @@
export { default } from './CourseHomeContainer';

View File

@@ -0,0 +1,11 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learn.loading.outline': {
id: 'learn.loading.learning.sequence',
defaultMessage: 'Loading learning sequence...',
description: 'Message when learning sequence is being loaded',
},
});
export default messages;

View File

@@ -0,0 +1,203 @@
import React, { useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import { history, getConfig } from '@edx/frontend-platform';
import { useRouteMatch } from 'react-router';
import {
fetchCourse,
fetchSequence,
} from '../data';
import {
checkBlockCompletion,
saveSequencePosition,
} from './data/thunks';
import { useModel } from '../model-store';
import Course from './course';
import { sequenceIdsSelector, firstSequenceIdSelector } from './data/selectors';
function useUnitNavigationHandler(courseId, sequenceId, unitId) {
const dispatch = useDispatch();
return useCallback((nextUnitId) => {
dispatch(checkBlockCompletion(courseId, sequenceId, unitId));
history.push(`/course/${courseId}/${sequenceId}/${nextUnitId}`);
}, [courseId, sequenceId]);
}
function usePreviousSequence(sequenceId) {
const sequenceIds = useSelector(sequenceIdsSelector);
const sequences = useSelector(state => state.models.sequences);
if (!sequenceId || sequenceIds.length === 0) {
return null;
}
const sequenceIndex = sequenceIds.indexOf(sequenceId);
const previousSequenceId = sequenceIndex > 0 ? sequenceIds[sequenceIndex - 1] : null;
return previousSequenceId !== null ? sequences[previousSequenceId] : null;
}
function useNextSequence(sequenceId) {
const sequenceIds = useSelector(sequenceIdsSelector);
const sequences = useSelector(state => state.models.sequences);
if (!sequenceId || sequenceIds.length === 0) {
return null;
}
const sequenceIndex = sequenceIds.indexOf(sequenceId);
const nextSequenceId = sequenceIndex < sequenceIds.length - 1 ? sequenceIds[sequenceIndex + 1] : null;
return nextSequenceId !== null ? sequences[nextSequenceId] : null;
}
function useNextSequenceHandler(courseId, sequenceId) {
const nextSequence = useNextSequence(sequenceId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
return useCallback(() => {
if (nextSequence !== null) {
const nextUnitId = nextSequence.unitIds[0];
history.push(`/course/${courseId}/${nextSequence.id}/${nextUnitId}`);
}
}, [courseStatus, sequenceStatus, sequenceId]);
}
function usePreviousSequenceHandler(courseId, sequenceId) {
const previousSequence = usePreviousSequence(sequenceId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
return useCallback(() => {
if (previousSequence !== null) {
const previousUnitId = previousSequence.unitIds[previousSequence.unitIds.length - 1];
history.push(`/course/${courseId}/${previousSequence.id}/${previousUnitId}`);
}
}, [courseStatus, sequenceStatus, sequenceId]);
}
function useExamRedirect(sequenceId) {
const sequence = useModel('sequences', sequenceId);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
useEffect(() => {
if (sequenceStatus === 'loaded' && sequence.isTimeLimited) {
global.location.assign(sequence.lmsWebUrl);
}
}, [sequenceStatus, sequence]);
}
function useContentRedirect(courseStatus, sequenceStatus) {
const match = useRouteMatch();
const { courseId, sequenceId, unitId } = match.params;
const sequence = useModel('sequences', sequenceId);
const firstSequenceId = useSelector(firstSequenceIdSelector);
useEffect(() => {
if (courseStatus === 'loaded' && !sequenceId) {
// This is a replace because we don't want this change saved in the browser's history.
history.replace(`/course/${courseId}/${firstSequenceId}`);
}
}, [courseStatus, sequenceId]);
useEffect(() => {
if (sequenceStatus === 'loaded' && sequenceId && !unitId) {
// The position may be null, in which case we'll just assume 0.
if (sequence.unitIds !== undefined && sequence.unitIds.length > 0) {
const unitIndex = sequence.position || 0;
const nextUnitId = sequence.unitIds[unitIndex];
// This is a replace because we don't want this change saved in the browser's history.
history.replace(`/course/${courseId}/${sequence.id}/${nextUnitId}`);
}
}
}, [sequenceStatus, sequenceId, unitId]);
}
function useSavedSequencePosition(courseId, sequenceId, unitId) {
const dispatch = useDispatch();
const sequence = useModel('sequences', sequenceId);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
useEffect(() => {
if (sequenceStatus === 'loaded' && sequence.savePosition) {
const activeUnitIndex = sequence.unitIds.indexOf(unitId);
dispatch(saveSequencePosition(courseId, sequenceId, activeUnitIndex));
}
}, [unitId]);
}
/**
* Redirects the user away from the app if they don't have access to view this course.
*
* @param {*} courseStatus
* @param {*} course
*/
function useAccessDeniedRedirect(courseStatus, courseId) {
const course = useModel('courses', courseId);
useEffect(() => {
if (courseStatus === 'loaded' && !course.userHasAccess && !course.isStaff) {
global.location.assign(`${getConfig().LMS_BASE_URL}/courses/${course.id}/course/`);
}
}, [courseStatus, course]);
}
export default function CoursewareContainer() {
const { params } = useRouteMatch();
const {
courseId: routeCourseUsageKey,
sequenceId: routeSequenceId,
unitId: routeUnitId,
} = params;
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchCourse(routeCourseUsageKey));
}, [routeCourseUsageKey]);
useEffect(() => {
if (routeSequenceId) {
dispatch(fetchSequence(routeSequenceId));
}
}, [routeSequenceId]);
// The courseId and sequenceId in the store are the entities we currently have loaded.
// We get these two IDs from the store because until fetchCourse and fetchSequence below have
// finished their work, the IDs in the URL are not representative of what we should actually show.
// This is important particularly when switching sequences. Until a new sequence is fully loaded,
// there's information that we don't have yet - if we use the URL's sequence ID to tell the app
// which sequence is loaded, we'll instantly try to pull it out of the store and use it, before
// the sequenceStatus flag has even switched back to "loading", which will put our app into an
// invalid state.
const {
courseId,
sequenceId,
courseStatus,
sequenceStatus,
} = useSelector(state => state.courseware);
const nextSequenceHandler = useNextSequenceHandler(courseId, sequenceId);
const previousSequenceHandler = usePreviousSequenceHandler(courseId, sequenceId);
const unitNavigationHandler = useUnitNavigationHandler(courseId, sequenceId, routeUnitId);
useAccessDeniedRedirect(courseStatus, courseId);
useContentRedirect(courseStatus, sequenceStatus);
useExamRedirect(sequenceId);
useSavedSequencePosition(courseId, sequenceId, routeUnitId);
return (
<main className="flex-grow-1 d-flex flex-column">
<Course
courseId={courseId}
sequenceId={sequenceId}
unitId={routeUnitId}
nextSequenceHandler={nextSequenceHandler}
previousSequenceHandler={previousSequenceHandler}
unitNavigationHandler={unitNavigationHandler}
/>
</main>
);
}
CoursewareContainer.propTypes = {
match: PropTypes.shape({
params: PropTypes.shape({
courseId: PropTypes.string.isRequired,
sequenceId: PropTypes.string,
unitId: PropTypes.string,
}).isRequired,
}).isRequired,
};

View File

@@ -0,0 +1,123 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
import AlertList from '../../user-messages/AlertList';
import { useLogistrationAlert } from '../../logistration-alert';
import { useEnrollmentAlert } from '../../enrollment-alert';
import PageLoading from '../../PageLoading';
import InstructorToolbar from './InstructorToolbar';
import Sequence from './sequence';
import CourseBreadcrumbs from './CourseBreadcrumbs';
import { Header, CourseTabsNavigation } from '../../course-header';
import CourseSock from './course-sock';
import Calculator from './calculator';
import messages from './messages';
import { useModel } from '../../model-store';
const EnrollmentAlert = React.lazy(() => import('../../enrollment-alert'));
const LogistrationAlert = React.lazy(() => import('../../logistration-alert'));
function Course({
courseId,
sequenceId,
unitId,
nextSequenceHandler,
previousSequenceHandler,
unitNavigationHandler,
intl,
}) {
const course = useModel('courses', courseId);
const sequence = useModel('sequences', sequenceId);
const section = useModel('sections', sequence ? sequence.sectionId : null);
useLogistrationAlert();
useEnrollmentAlert(courseId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
if (courseStatus === 'loading') {
return (
<PageLoading
srMessage={intl.formatMessage(messages['learn.loading.learning.sequence'])}
/>
);
}
if (courseStatus === 'loaded') {
const {
org, number, title, isStaff, tabs, verifiedMode, showCalculator,
} = course;
return (
<>
<Header
courseOrg={org}
courseNumber={number}
courseTitle={title}
/>
{isStaff && (
<InstructorToolbar
unitId={unitId}
/>
)}
<CourseTabsNavigation tabs={tabs} activeTabSlug="courseware" />
<div className="container-fluid">
<AlertList
className="my-3"
topic="course"
customAlerts={{
clientEnrollmentAlert: EnrollmentAlert,
clientLogistrationAlert: LogistrationAlert,
}}
/>
<CourseBreadcrumbs
courseId={courseId}
sectionId={section ? section.id : null}
sequenceId={sequenceId}
/>
<AlertList topic="sequence" />
</div>
<div className="flex-grow-1 d-flex flex-column">
<Sequence
unitId={unitId}
sequenceId={sequenceId}
courseId={courseId}
unitNavigationHandler={unitNavigationHandler}
nextSequenceHandler={nextSequenceHandler}
previousSequenceHandler={previousSequenceHandler}
/>
{verifiedMode && <CourseSock verifiedMode={verifiedMode} />}
{showCalculator && <Calculator />}
</div>
</>
);
}
// courseStatus 'failed' and any other unexpected course status.
return (
<p className="text-center py-5 mx-auto" style={{ maxWidth: '30em' }}>
{intl.formatMessage(messages['learn.course.load.failure'])}
</p>
);
}
Course.propTypes = {
courseId: PropTypes.string,
sequenceId: PropTypes.string,
unitId: PropTypes.string,
nextSequenceHandler: PropTypes.func.isRequired,
previousSequenceHandler: PropTypes.func.isRequired,
unitNavigationHandler: PropTypes.func.isRequired,
intl: intlShape.isRequired,
};
Course.defaultProps = {
courseId: null,
sequenceId: null,
unitId: null,
};
export default injectIntl(Course);

View File

@@ -0,0 +1,99 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faHome } from '@fortawesome/free-solid-svg-icons';
import { useSelector } from 'react-redux';
import { useModel } from '../../model-store';
function CourseBreadcrumb({
url, children, withSeparator, ...attrs
}) {
return (
<>
{withSeparator && (
<li className="mx-2 text-gray-300" role="presentation" aria-hidden>/</li>
)}
<li {...attrs}>
<a href={url}>{children}</a>
</li>
</>
);
}
CourseBreadcrumb.propTypes = {
url: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
withSeparator: PropTypes.bool,
};
CourseBreadcrumb.defaultProps = {
withSeparator: false,
};
export default function CourseBreadcrumbs({
courseId,
sectionId,
sequenceId,
}) {
const course = useModel('courses', courseId);
const sequence = useModel('sequences', sequenceId);
const section = useModel('sections', sectionId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
const links = useMemo(() => {
if (courseStatus === 'loaded' && sequenceStatus === 'loaded') {
return [section, sequence].filter(node => !!node).map((node) => ({
id: node.id,
label: node.title,
url: `${getConfig().LMS_BASE_URL}/courses/${course.id}/course/#${node.id}`,
}));
}
return [];
}, [courseStatus, sequenceStatus]);
return (
<nav aria-label="breadcrumb" className="my-4">
<ol className="list-unstyled d-flex m-0">
<CourseBreadcrumb
url={`${getConfig().LMS_BASE_URL}/courses/${course.id}/course/`}
className="flex-shrink-0"
>
<FontAwesomeIcon icon={faHome} className="mr-2" />
<FormattedMessage
id="learn.breadcrumb.navigation.course.home"
description="The course home link in breadcrumbs nav"
defaultMessage="Course"
/>
</CourseBreadcrumb>
{links.map(({ id, url, label }) => (
<CourseBreadcrumb
key={id}
url={url}
withSeparator
style={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
{label}
</CourseBreadcrumb>
))}
</ol>
</nav>
);
}
CourseBreadcrumbs.propTypes = {
courseId: PropTypes.string.isRequired,
sectionId: PropTypes.string,
sequenceId: PropTypes.string,
};
CourseBreadcrumbs.defaultProps = {
sectionId: null,
sequenceId: null,
};

View File

@@ -0,0 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Collapsible } from '@edx/paragon';
function InstructorToolbar(props) {
// TODO: Only render this toolbar if the user is course staff
if (!props.activeUnitLmsWebUrl) {
return null;
}
return (
<div className="bg-primary text-light">
<div className="container-fluid py-3 d-md-flex justify-content-end align-items-center">
<div className="flex-grow-1">
<Collapsible.Advanced className="mr-5 mb-md-0">
You are currently previewing the new learning sequence experience.
<Collapsible.Trigger className="d-inline-block ml-2" style={{ cursor: 'pointer' }}>
<Collapsible.Visible whenClosed>
<span style={{ borderBottom: 'solid 1px white' }}>More info</span> &rarr;
</Collapsible.Visible>
</Collapsible.Trigger>
<Collapsible.Body>
This preview is to allow for early content testing, especially for custom content blocks, with the goal of ensuring it renders as expected in the next experience. You can learn more through the following <a className="text-white" style={{ textDecoration: 'underline' }} href="https://partners.edx.org/announcements/author-preview-learning-sequence-experience-update" target="blank" rel="noopener">Partner Portal post</a>. Please report any issues or provide <a className="text-white" style={{ textDecoration: 'underline' }} target="blank" rel="noopener" href="https://forms.gle/R6jMYJNTCj1vgC1D6">feedback using the linked form</a>.
<Collapsible.Trigger className="d-inline-block ml-2" style={{ cursor: 'pointer' }}>
<Collapsible.Visible whenOpen>
<span style={{ borderBottom: 'solid 1px white' }}>Close</span> &times;
</Collapsible.Visible>
</Collapsible.Trigger>
</Collapsible.Body>
</Collapsible.Advanced>
</div>
<div className="flex-shrink-0">
<a className="btn d-block btn-outline-light" href={props.activeUnitLmsWebUrl}>View unit in the existing experience</a>
</div>
</div>
</div>
);
}
InstructorToolbar.propTypes = {
activeUnitLmsWebUrl: PropTypes.string,
};
InstructorToolbar.defaultProps = {
activeUnitLmsWebUrl: undefined,
};
const mapStateToProps = (state, props) => {
if (!props.unitId) {
return {};
}
const activeUnit = state.models.units[props.unitId];
return {
activeUnitLmsWebUrl: activeUnit ? activeUnit.lmsWebUrl : undefined,
};
};
export default connect(mapStateToProps)(InstructorToolbar);

View File

@@ -0,0 +1,71 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { StatefulButton } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { useDispatch } from 'react-redux';
import BookmarkOutlineIcon from './BookmarkOutlineIcon';
import BookmarkFilledIcon from './BookmarkFilledIcon';
import { removeBookmark, addBookmark } from './data/thunks';
const addBookmarkLabel = (
<FormattedMessage
id="unit.bookmark.button.add.bookmark"
defaultMessage="Bookmark this page"
description="The button to bookmark a page"
/>
);
const hasBookmarkLabel = (
<FormattedMessage
id="unit.bookmark.button.remove.bookmark"
defaultMessage="Bookmarked"
description="The button to show a page is bookmarked and the button to remove that bookmark"
/>
);
export default function BookmarkButton({
isBookmarked, isProcessing, unitId,
}) {
const bookmarkState = isBookmarked ? 'bookmarked' : 'default';
const state = isProcessing ? `${bookmarkState}Processing` : bookmarkState;
const dispatch = useDispatch();
const toggleBookmark = useCallback(() => {
if (isBookmarked) {
dispatch(removeBookmark(unitId));
} else {
dispatch(addBookmark(unitId));
}
}, [isBookmarked, unitId]);
return (
<StatefulButton
className="btn-link px-1 ml-n1 btn-sm"
onClick={toggleBookmark}
state={state}
disabledStates={['defaultProcessing', 'bookmarkedProcessing']}
labels={{
default: addBookmarkLabel,
defaultProcessing: addBookmarkLabel,
bookmarked: hasBookmarkLabel,
bookmarkedProcessing: hasBookmarkLabel,
}}
icons={{
default: <BookmarkOutlineIcon className="text-primary" />,
defaultProcessing: <BookmarkOutlineIcon className="text-primary" />,
bookmarked: <BookmarkFilledIcon className="text-primary" />,
bookmarkedProcessing: <BookmarkFilledIcon className="text-primary" />,
}}
/>
);
}
BookmarkButton.propTypes = {
unitId: PropTypes.string.isRequired,
isBookmarked: PropTypes.bool,
isProcessing: PropTypes.bool.isRequired,
};
BookmarkButton.defaultProps = {
isBookmarked: false,
};

View File

@@ -0,0 +1,7 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBookmark } from '@fortawesome/free-solid-svg-icons';
export default function BookmarkFilledIcon(props) {
return <FontAwesomeIcon icon={faBookmark} {...props} />;
}

View File

@@ -0,0 +1,7 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBookmark } from '@fortawesome/free-regular-svg-icons';
export default function BookmarkOutlineIcon(props) {
return <FontAwesomeIcon icon={faBookmark} {...props} />;
}

View File

@@ -0,0 +1,13 @@
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient, getAuthenticatedUser } from '@edx/frontend-platform/auth';
const bookmarksBaseUrl = `${getConfig().LMS_BASE_URL}/api/bookmarks/v1/bookmarks/`;
export async function createBookmark(usageId) {
return getAuthenticatedHttpClient().post(bookmarksBaseUrl, { usage_id: usageId });
}
export async function deleteBookmark(usageId) {
const { username } = getAuthenticatedUser();
return getAuthenticatedHttpClient().delete(`${bookmarksBaseUrl}${username},${usageId}/`);
}

View File

@@ -0,0 +1,78 @@
import { logError } from '@edx/frontend-platform/logging';
import {
createBookmark,
deleteBookmark,
} from './api';
import { updateModel } from '../../../../model-store';
export function addBookmark(unitId) {
return async (dispatch) => {
// Optimistically update the bookmarked flag.
dispatch(updateModel({
modelType: 'units',
model: {
id: unitId,
bookmarked: true,
bookmarkedUpdateState: 'loading',
},
}));
try {
await createBookmark(unitId);
dispatch(updateModel({
modelType: 'units',
model: {
id: unitId,
bookmarked: true,
bookmarkedUpdateState: 'loaded',
},
}));
} catch (error) {
logError(error);
dispatch(updateModel({
modelType: 'units',
model: {
id: unitId,
bookmarked: false,
bookmarkedUpdateState: 'failed',
},
}));
}
};
}
export function removeBookmark(unitId) {
return async (dispatch) => {
// Optimistically update the bookmarked flag.
dispatch(updateModel({
modelType: 'units',
model: {
id: unitId,
bookmarked: false,
bookmarkedUpdateState: 'loading',
},
}));
try {
await deleteBookmark(unitId);
dispatch(updateModel({
modelType: 'units',
model: {
id: unitId,
bookmarked: false,
bookmarkedUpdateState: 'loaded',
},
}));
} catch (error) {
logError(error);
dispatch(updateModel({
modelType: 'units',
model: {
id: unitId,
bookmarked: true,
bookmarkedUpdateState: 'failed',
},
}));
}
};
}

View File

@@ -0,0 +1,3 @@
export { default as BookmarkButton } from './BookmarkButton';
export { default as BookmarkFilledIcon } from './BookmarkFilledIcon';
export { default as BookmarkOutlineIcon } from './BookmarkFilledIcon';

View File

@@ -0,0 +1,27 @@
.calculator {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
.calculator-trigger {
cursor: pointer;
display: inline-block;
position: relative;
z-index: 2;
background-color: #f1f1f1;
border: solid 1px #ddd;
border-bottom: none;
border-top-left-radius: .3rem;
border-top-right-radius: .3rem;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
&:before {
border-radius: .5rem;
}
}
.calculator-content {
background-color: #f1f1f1;
box-shadow: 0 -1px 0 0 #ddd;
}
}

View File

@@ -0,0 +1,393 @@
import React, { Component } from 'react';
import { Collapsible } from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import {
FormattedMessage, injectIntl, intlShape,
} from '@edx/frontend-platform/i18n';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faCalculator, faQuestionCircle, faTimesCircle, faEquals,
} from '@fortawesome/free-solid-svg-icons';
import messages from './messages';
import './calculator.scss';
class Calculator extends Component {
constructor(props) {
super(props);
this.state = {
equation: '',
result: '',
};
this.handleSubmit = this.handleSubmit.bind(this);
}
async handleSubmit(event) {
event.preventDefault();
event.stopPropagation();
const urlEncoded = new URLSearchParams();
urlEncoded.append('equation', this.state.equation);
const response = await getAuthenticatedHttpClient().get(
`${getConfig().LMS_BASE_URL}/calculate?${urlEncoded.toString()}`,
);
this.setState(() => ({ result: response.data.result }));
}
changeEquation(value) {
this.setState(() => ({ equation: value }));
}
render() {
return (
<Collapsible.Advanced className="calculator">
<div className="container-fluid text-right">
<Collapsible.Trigger tag="a" className="calculator-trigger btn">
<Collapsible.Visible whenOpen>
<FontAwesomeIcon icon={faTimesCircle} aria-hidden="true" className="mr-2" />
</Collapsible.Visible>
<Collapsible.Visible whenClosed>
<FontAwesomeIcon icon={faCalculator} aria-hidden="true" className="mr-2" />
</Collapsible.Visible>
{this.props.intl.formatMessage(messages['calculator.button.label'])}
</Collapsible.Trigger>
</div>
<Collapsible.Body className="calculator-content pt-4">
<form onSubmit={this.handleSubmit} className="container-fluid form-inline flex-nowrap">
<input
type="text"
placeholder={this.props.intl.formatMessage(messages['calculator.input.field.label'])}
aria-label={this.props.intl.formatMessage(messages['calculator.input.field.label'])}
className="form-control w-100"
onChange={(event) => this.changeEquation(event.target.value)}
/>
<button
className="btn btn-primary mx-3"
aria-label={this.props.intl.formatMessage(messages['calculator.submit.button.label'])}
type="submit"
>
<FontAwesomeIcon icon={faEquals} aria-hidden="true" />
</button>
<input
type="text"
tabIndex="-1"
readOnly
aria-live="polite"
placeholder={this.props.intl.formatMessage(messages['calculator.result.field.placeholder'])}
aria-label={this.props.intl.formatMessage(messages['calculator.result.field.label'])}
className="form-control w-50"
value={this.state.result}
/>
</form>
<Collapsible.Advanced>
<div className="container-fluid">
<Collapsible.Trigger className="btn btn-link btn-sm px-0 d-inline-flex align-items-center">
<Collapsible.Visible whenOpen>
<FontAwesomeIcon icon={faTimesCircle} aria-hidden="true" className="mr-2" />
</Collapsible.Visible>
<Collapsible.Visible whenClosed>
<FontAwesomeIcon icon={faQuestionCircle} aria-hidden="true" className="mr-2" />
</Collapsible.Visible>
<FormattedMessage
id="calculator.instructions.button.label"
defaultMessage="Calculator Instructions"
/>
</Collapsible.Trigger>
</div>
<Collapsible.Body className="container-fluid pt-3" style={{ maxHeight: '50vh', overflow: 'auto' }}>
<FormattedMessage
tagName="h6"
id="calculator.instructions"
defaultMessage="For detailed information, see {expressions_link} in the {edx_guide}."
values={{
expressions_link: (
<a href="https://edx.readthedocs.io/projects/edx-guide-for-students/en/latest/completing_assignments/SFD_mathformatting.html#math-formatting">
<FormattedMessage
id="calculator.instructions.expressions.link.title"
defaultMessage="Entering Mathematical and Scientific Expressions"
/>
</a>
),
edx_guide: (
<a href="https://edx-guide-for-students.readthedocs.io/en/latest/index.html">
<FormattedMessage
id="calculator.instructions.edx.guide.link.title"
defaultMessage="edX Guide for Students"
/>
</a>
),
}}
/>
<p>
<strong>
<FormattedMessage
id="calculator.instructions.useful.tips"
defaultMessage="Useful tips:"
/>
</strong>
</p>
<ul>
<li className="hint-item" id="hint-paren">
<FormattedMessage
id="calculator.hint1"
defaultMessage="Use parentheses () to make expressions clear. You can use parentheses inside other parentheses."
/>
</li>
<li className="hint-item" id="hint-spaces">
<FormattedMessage
id="calculator.hint2"
defaultMessage="Do not use spaces in expressions."
/>
</li>
<li className="hint-item" id="hint-howto-constants">
<FormattedMessage
id="calculator.hint3"
defaultMessage="For constants, indicate multiplication explicitly (example: 5*c)."
/>
</li>
<li className="hint-item" id="hint-howto-maffixes">
<FormattedMessage
id="calculator.hint4"
defaultMessage="For affixes, type the number and affix without a space (example: 5c)."
/>
</li>
<li className="hint-item" id="hint-howto-functions">
<FormattedMessage
id="calculator.hint5"
defaultMessage="For functions, type the name of the function, then the expression in parentheses."
/>
</li>
</ul>
<table className="table small">
<thead>
<tr>
<th scope="col">
<FormattedMessage
id="calculator.instruction.table.to.use.heading"
defaultMessage="To Use"
/>
</th>
<th scope="col">
<FormattedMessage
id="calculator.instruction.table.type.heading"
defaultMessage="Type"
/>
</th>
<th scope="col">
<FormattedMessage
id="calculator.instruction.table.examples.heading"
defaultMessage="Examples"
/>
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.numbers"
defaultMessage="Numbers"
/>
</th>
<td>
<ul className="list-unstyled m-0">
<li>
<FormattedMessage
id="calculator.instruction.table.to.use.numbers.type1"
defaultMessage="Integers"
/>
</li>
<li>
<FormattedMessage
id="calculator.instruction.table.to.use.numbers.type2"
defaultMessage="Fractions"
/>
</li>
<li>
<FormattedMessage
id="calculator.instruction.table.to.use.numbers.type3"
defaultMessage="Decimals"
/>
</li>
</ul>
</td>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>2520</li>
<li>2/3</li>
<li>3.14, .98</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.operators"
defaultMessage="Operators"
/>
</th>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>
{' + - * / '}
<FormattedMessage
id="calculator.instruction.table.to.use.operators.type1"
defaultMessage="(add, subtract, multiply, divide)"
/>
</li>
<li>
{'^ '}
<FormattedMessage
id="calculator.instruction.table.to.use.operators.type2"
defaultMessage="(raise to a power)"
/>
</li>
<li>
{'|| '}
<FormattedMessage
id="calculator.instruction.table.to.use.operators.type3"
defaultMessage="(parallel resistors)"
/>
</li>
</ul>
</td>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>x+(2*y)/x-1</li>
<li>x^(n+1)</li>
<li>v_IN+v_OUT</li>
<li>1||2</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.constants"
defaultMessage="Constants"
/>
</th>
<td dir="auto">c, e, g, i, j, k, pi, q, T</td>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>20*c</li>
<li>418*T</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.affixes"
defaultMessage="Affixes"
/>
</th>
<td dir="auto">
<FormattedMessage
id="calculator.instruction.table.to.use.affixes.type"
defaultMessage="Percent sign (%) and metric affixes ({affixes})"
values={{
affixes: 'd, c, m, u, n, p, k, M, G, T',
}}
/>
</td>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>20%</li>
<li>20c</li>
<li>418T</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.basic.functions"
defaultMessage="Basic functions"
/>
</th>
<td dir="auto">abs, exp, fact, factorial, ln, log2, log10, sqrt</td>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>abs(x+y)</li>
<li>sqrt(x^2-y)</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.trig.functions"
defaultMessage="Trigonometric functions"
/>
</th>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>sin, cos, tan, sec, csc, cot</li>
<li>arcsin, sinh, arcsinh</li>
</ul>
</td>
<td dir="auto">
<ul className="list-unstyled m-0">
<li>sin(4x+y)</li>
<li>arccsch(4x+y)</li>
</ul>
</td>
<td dir="auto" />
</tr>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.scientific.notation"
defaultMessage="Scientific notation"
/>
</th>
<td dir="auto">
<FormattedMessage
id="calculator.instruction.table.to.use.scientific.notation.type"
defaultMessage="{exponentSyntax} and the exponent"
values={{
exponentSyntax: '10^',
}}
/>
</td>
<td dir="auto">10^-9</td>
</tr>
<tr>
<th scope="row">
<FormattedMessage
id="calculator.instruction.table.to.use.scientific.notation.type"
defaultMessage="{notationSyntax} notation"
values={{
notationSyntax: 'e',
}}
/>
</th>
<td dir="auto">
<FormattedMessage
id="calculator.instruction.table.to.use.scientific.notation.type"
defaultMessage="{notationSyntax} and the exponent"
values={{
notationSyntax: '1e',
}}
/>
</td>
<td dir="auto">1e-9</td>
</tr>
</tbody>
</table>
</Collapsible.Body>
</Collapsible.Advanced>
</Collapsible.Body>
</Collapsible.Advanced>
);
}
}
Calculator.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(Calculator);

View File

@@ -0,0 +1,31 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'calculator.button.label': {
id: 'calculator.button.label',
defaultMessage: 'Calculator',
description: 'Button label to expand or close the calculator',
},
'calculator.input.field.label': {
id: 'calculator.input.field.label',
defaultMessage: 'Calculator Input',
description: 'label for calculator input',
},
'calculator.submit.button.label': {
id: 'calculator.submit.button.label',
defaultMessage: 'Calculate',
description: 'Submit button label to execute the calculator',
},
'calculator.result.field.label': {
id: 'calculator.result.field.label',
defaultMessage: 'Calculator Result',
description: 'label for calculator result',
},
'calculator.result.field.placeholder': {
id: 'calculator.result.field.placeholder',
defaultMessage: 'Result',
description: 'placeholder for calculator result',
},
});
export default messages;

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,175 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import LearnerQuote1 from './assets/learner-quote.png';
import LearnerQuote2 from './assets/learner-quote2.png';
import VerifiedCert from './assets/verified-cert.png';
export default class CourseSock extends Component {
constructor(props) {
super(props);
this.verifiedMode = props.verifiedMode;
this.state = { showUpsell: false };
}
handleClick = () => {
this.setState(state => ({
showUpsell: !state.showUpsell,
}));
}
render() {
const buttonClass = this.state.showUpsell ? 'btn-success' : 'btn-outline-success';
return (
<div className="verification-sock container py-5">
<div className="d-flex justify-content-center">
<button type="button" aria-expanded="false" className={`btn ${buttonClass}`} onClick={this.handleClick}>
<FormattedMessage
id="coursesock.upsell.heading"
defaultMessage="Learn About Verified Certificates"
description="The heading for the upsell dialog"
/>
</button>
</div>
{this.state.showUpsell && (
<div className="d-flex justify-content-around">
<div className="mt-3">
<h2 className="font-weight-lighter">
<FormattedMessage
id="coursesock.upsell.verifiedcert"
defaultMessage="edX Verified Certificate"
/>
</h2>
<h3>
<FormattedMessage
id="coursesock.upsell.why"
defaultMessage="Why upgrade?"
/>
</h3>
<ul>
<li><FormattedMessage
id="coursesock.upsell.reason1"
defaultMessage="Official proof of completion"
/>
</li>
<li><FormattedMessage
id="coursesock.upsell.reason2"
defaultMessage="Easily shareable certificate"
/>
</li>
<li><FormattedMessage
id="coursesock.upsell.reason3"
defaultMessage="Proven motivator to complete the course"
/>
</li>
<li><FormattedMessage
id="coursesock.upsell.reason4"
defaultMessage="Certificate purchases help edX continue to offer free courses"
/>
</li>
</ul>
<h3><FormattedMessage
id="coursesock.upsell.howtitle"
defaultMessage="How it works"
/>
</h3>
<ul>
<li><FormattedMessage
id="coursesock.upsell.how1"
defaultMessage="Pay the Verified Certificate upgrade fee"
/>
</li>
<li><FormattedMessage
id="coursesock.upsell.how2"
defaultMessage="Verify your identity with a webcam and government-issued ID"
/>
</li>
<li><FormattedMessage
id="coursesock.upsell.how3"
defaultMessage="Study hard and pass the course"
/>
</li>
<li><FormattedMessage
id="coursesock.upsell.how4"
defaultMessage="Share your certificate with friends, employers, and others"
/>
</li>
</ul>
<h3><FormattedMessage
id="coursesock.upsell.storytitle"
defaultMessage="edX Learner Stories"
/>
</h3>
<div className="d-flex align-items-center my-4">
<img style={{ maxWidth: '4rem' }} alt="Christina Fong" src={LearnerQuote1} />
<div className="w-50 px-4">
<FormattedMessage
id="coursesock.upsell.story1"
defaultMessage="My certificate has helped me showcase my knowledge on my
resume - I feel like this certificate could really help me land
my dream job!"
/>
<br />
<strong>&mdash; <FormattedMessage
id="coursesock.upsell.learner"
description="Name of learner"
defaultMessage="{ name }, edX Learner"
values={{ name: 'Christina Fong' }}
/>
</strong>
</div>
</div>
<div className="d-flex align-items-center my-2">
<img style={{ maxWidth: '4rem' }} alt="Chery Troell" src={LearnerQuote2} />
<div className="w-50 px-4">
<FormattedMessage
id="coursesock.upsell.story2"
defaultMessage="I wanted to include a verified certificate on my resume and my profile to
illustrate that I am working towards this goal I have and that I have
achieved something while I was unemployed."
/>
<br />
<strong>&mdash; <FormattedMessage
id="coursesock.upsell.learner"
description="Name of learner"
defaultMessage="{ name }, edX Learner"
values={{ name: 'Cheryl Troell' }}
/>
</strong>
</div>
</div>
</div>
<div className="d-flex flex-column justify-content-between">
<img alt="Example Certificate" src={VerifiedCert} />
<a href={this.verifiedMode.upgradeUrl} className="btn btn-success btn-lg btn-upgrade focusable" data-creative="original_sock" data-position="sock">
<FormattedMessage
id="coursesock.upsell.upgrade"
defaultMessage="Upgrade ({symbol}{price} {currency})"
values={{
symbol: this.verifiedMode.currencySymbol,
price: this.verifiedMode.price,
currency: this.verifiedMode.currency,
}}
/>
</a>
</div>
</div>
)}
</div>
);
}
}
CourseSock.propTypes = {
verifiedMode: PropTypes.shape({
price: PropTypes.number,
currency: PropTypes.string,
currencySymbol: PropTypes.string,
sku: PropTypes.string,
upgradeUrl: PropTypes.string,
}),
};
CourseSock.defaultProps = {
verifiedMode: null,
};

View File

@@ -0,0 +1 @@
export { default } from './Course';

View File

@@ -6,10 +6,10 @@ const messages = defineMessages({
defaultMessage: 'Loading learning sequence...',
description: 'Message when learning sequence is being loaded',
},
'learn.loading.error': {
id: 'learn.loading.error',
defaultMessage: 'Error: {error}',
description: 'Message when learning sequence fails to load',
'learn.course.load.failure': {
id: 'learn.course.load.failure',
defaultMessage: 'There was an error loading this course.',
description: 'Message when a course fails to load',
},
});

View File

@@ -0,0 +1,201 @@
/* eslint-disable no-use-before-define */
import React, {
useEffect, useContext, Suspense, useState,
} from 'react';
import PropTypes from 'prop-types';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
import Unit from './Unit';
import { SequenceNavigation, UnitNavigation } from './sequence-navigation';
import PageLoading from '../../../PageLoading';
import messages from './messages';
import UserMessagesContext from '../../../user-messages/UserMessagesContext';
import { useModel } from '../../../model-store';
const ContentLock = React.lazy(() => import('./content-lock'));
function Sequence({
unitId,
sequenceId,
courseId,
unitNavigationHandler,
nextSequenceHandler,
previousSequenceHandler,
intl,
}) {
const sequence = useModel('sequences', sequenceId);
const unit = useModel('units', unitId);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
const handleNext = () => {
const nextIndex = sequence.unitIds.indexOf(unitId) + 1;
if (nextIndex < sequence.unitIds.length) {
const newUnitId = sequence.unitIds[nextIndex];
handleNavigate(newUnitId);
} else {
nextSequenceHandler();
}
};
const handlePrevious = () => {
const previousIndex = sequence.unitIds.indexOf(unitId) - 1;
if (previousIndex >= 0) {
const newUnitId = sequence.unitIds[previousIndex];
handleNavigate(newUnitId);
} else {
previousSequenceHandler();
}
};
const handleNavigate = (destinationUnitId) => {
unitNavigationHandler(destinationUnitId);
};
const logEvent = (eventName, widgetPlacement, targetUnitId) => {
// Note: tabs are tracked with a 1-indexed position
// as opposed to a 0-index used throughout this MFE
const currentIndex = sequence.unitIds.length > 0 ? sequence.unitIds.indexOf(unitId) : 0;
const payload = {
current_tab: currentIndex + 1,
id: unitId,
tab_count: sequence.unitIds.length,
widget_placement: widgetPlacement,
};
if (targetUnitId) {
const targetIndex = sequence.unitIds.indexOf(targetUnitId);
payload.target_tab = targetIndex + 1;
}
sendTrackEvent(eventName, payload);
};
const { add, remove } = useContext(UserMessagesContext);
useEffect(() => {
let id = null;
if (sequenceStatus === 'loaded') {
if (sequence.bannerText) {
id = add({
code: null,
dismissible: false,
text: sequence.bannerText,
type: 'info',
topic: 'sequence',
});
}
}
return () => {
if (id) {
remove(id);
}
};
}, [sequenceStatus, sequence]);
const [unitHasLoaded, setUnitHasLoaded] = useState(false);
const handleUnitLoaded = () => {
setUnitHasLoaded(true);
};
useEffect(() => {
if (unit) {
setUnitHasLoaded(false);
}
}, [unit]);
if (sequenceStatus === 'loading') {
return (
<PageLoading
srMessage={intl.formatMessage(messages['learn.loading.learning.sequence'])}
/>
);
}
const gated = sequence.gatedContent !== undefined && sequence.gatedContent.gated;
if (sequenceStatus === 'loaded') {
return (
<div className="sequence-container">
<div className="sequence">
<SequenceNavigation
sequenceId={sequenceId}
unitId={unitId}
className="mb-4"
nextSequenceHandler={() => {
logEvent('edx.ui.lms.sequence.next_selected', 'top');
handleNext();
}}
onNavigate={(destinationUnitId) => {
logEvent('edx.ui.lms.sequence.tab_selected', 'top', destinationUnitId);
handleNavigate(destinationUnitId);
}}
previousSequenceHandler={() => {
logEvent('edx.ui.lms.sequence.previous_selected', 'top');
handlePrevious();
}}
/>
<div className="unit-container flex-grow-1">
{gated && (
<Suspense
fallback={(
<PageLoading
srMessage={intl.formatMessage(messages['learn.loading.content.lock'])}
/>
)}
>
<ContentLock
courseId={courseId}
sequenceTitle={sequence.title}
prereqSectionName={sequence.gatedContent.gatedSectionName}
prereqId={sequence.gatedContent.prereqId}
/>
</Suspense>
)}
{!gated && unitId !== null && (
<Unit
key={unitId}
id={unitId}
onLoaded={handleUnitLoaded}
/>
)}
{unitHasLoaded && (
<UnitNavigation
sequenceId={sequenceId}
unitId={unitId}
onClickPrevious={() => {
logEvent('edx.ui.lms.sequence.previous_selected', 'bottom');
handlePrevious();
}}
onClickNext={() => {
logEvent('edx.ui.lms.sequence.next_selected', 'bottom');
handleNext();
}}
/>
)}
</div>
</div>
</div>
);
}
// sequence status 'failed' and any other unexpected sequence status.
return (
<p className="text-center py-5 mx-auto" style={{ maxWidth: '30em' }}>
{intl.formatMessage(messages['learn.course.load.failure'])}
</p>
);
}
Sequence.propTypes = {
unitId: PropTypes.string,
sequenceId: PropTypes.string,
courseId: PropTypes.string.isRequired,
unitNavigationHandler: PropTypes.func.isRequired,
nextSequenceHandler: PropTypes.func.isRequired,
previousSequenceHandler: PropTypes.func.isRequired,
intl: intlShape.isRequired,
};
Sequence.defaultProps = {
sequenceId: null,
unitId: null,
};
export default injectIntl(Sequence);

View File

@@ -0,0 +1,66 @@
import React, { useRef, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import BookmarkButton from '../bookmark/BookmarkButton';
import { useModel } from '../../../model-store';
export default function Unit({
onLoaded,
id,
}) {
const iframeRef = useRef(null);
const iframeUrl = `${getConfig().LMS_BASE_URL}/xblock/${id}?show_title=0&show_bookmark_button=0`;
const [iframeHeight, setIframeHeight] = useState(0);
const [hasLoaded, setHasLoaded] = useState(false);
const unit = useModel('units', id);
useEffect(() => {
global.onmessage = (event) => {
const { type, payload } = event.data;
if (type === 'plugin.resize') {
setIframeHeight(payload.height);
if (!hasLoaded && iframeHeight === 0 && payload.height > 0) {
setHasLoaded(true);
if (onLoaded) {
onLoaded();
}
}
}
};
}, []);
return (
<div className="unit">
<h2 className="mb-0 h4">{unit.title}</h2>
<BookmarkButton
unitId={unit.id}
isBookmarked={unit.bookmarked}
isProcessing={unit.bookmarkedUpdateState === 'loading'}
/>
<div className="unit-iframe-wrapper">
<iframe
id="unit-iframe"
title={unit.title}
ref={iframeRef}
src={iframeUrl}
allowFullScreen
height={iframeHeight}
scrolling="no"
referrerPolicy="origin"
/>
</div>
</div>
);
}
Unit.propTypes = {
id: PropTypes.string.isRequired,
onLoaded: PropTypes.func,
};
Unit.defaultProps = {
onLoaded: undefined,
};

View File

@@ -1,34 +1,32 @@
import React, { useContext, useCallback } from 'react';
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faLock } from '@fortawesome/free-solid-svg-icons';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { history } from '@edx/frontend-platform';
import { Button } from '@edx/paragon';
import SubSectionMetadataContext from '../SubSectionMetadataContext';
import messages from './messages';
import { useCurrentSubSection } from '../../data/hooks';
import CourseStructureContext from '../../CourseStructureContext';
function ContentLock({ intl }) {
const { courseId } = useContext(CourseStructureContext);
const metadata = useContext(SubSectionMetadataContext);
const subSection = useCurrentSubSection();
function ContentLock({
intl, courseId, prereqSectionName, prereqId, sequenceTitle,
}) {
const handleClick = useCallback(() => {
history.push(`/course/${courseId}/${metadata.gatedContent.prereqId}`);
history.push(`/course/${courseId}/${prereqId}`);
});
return (
<>
<h3>
<FontAwesomeIcon icon={faLock} />{' '}
{subSection.displayName}
<FontAwesomeIcon icon={faLock} />
{' '}
{sequenceTitle}
</h3>
<h4>{intl.formatMessage(messages['learn.contentLock.content.locked'])}</h4>
<p>{intl.formatMessage(messages['learn.contentLock.complete.prerequisite'], {
prereqSectionName: metadata.gatedContent.prereqSectionName,
})}
<p>
{intl.formatMessage(messages['learn.contentLock.complete.prerequisite'], {
prereqSectionName,
})}
</p>
<p>
<Button className="btn-primary" onClick={handleClick}>{intl.formatMessage(messages['learn.contentLock.goToSection'])}</Button>
@@ -36,9 +34,11 @@ function ContentLock({ intl }) {
</>
);
}
ContentLock.propTypes = {
intl: intlShape.isRequired,
courseId: PropTypes.string.isRequired,
prereqSectionName: PropTypes.string.isRequired,
prereqId: PropTypes.string.isRequired,
sequenceTitle: PropTypes.string.isRequired,
};
export default injectIntl(ContentLock);

View File

@@ -0,0 +1 @@
export { default } from './Sequence';

View File

@@ -0,0 +1,21 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learn.loading.content.lock': {
id: 'learn.loading.content.lock',
defaultMessage: 'Loading locked content messaging...',
description: 'Message shown when an interface about locked content is being loaded',
},
'learn.loading.learning.sequence': {
id: 'learn.loading.learning.sequence',
defaultMessage: 'Loading learning sequence...',
description: 'Message when learning sequence is being loaded',
},
'learn.course.load.failure': {
id: 'learn.course.load.failure',
defaultMessage: 'There was an error loading this course.',
description: 'Message when a course fails to load',
},
});
export default messages;

View File

@@ -0,0 +1,7 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCheck } from '@fortawesome/free-solid-svg-icons';
export default function CompleteIcon(props) {
return <FontAwesomeIcon icon={faCheck} {...props} />;
}

View File

@@ -0,0 +1,84 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from '@edx/paragon';
import classNames from 'classnames';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
import UnitButton from './UnitButton';
import SequenceNavigationTabs from './SequenceNavigationTabs';
import { useSequenceNavigationMetadata } from './hooks';
import { useModel } from '../../../../model-store';
export default function SequenceNavigation({
unitId,
sequenceId,
className,
onNavigate,
nextSequenceHandler,
previousSequenceHandler,
}) {
const sequence = useModel('sequences', sequenceId);
const { isFirstUnit, isLastUnit } = useSequenceNavigationMetadata(sequenceId, unitId);
const isLocked = sequence.gatedContent !== undefined && sequence.gatedContent.gated;
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
const renderUnitButtons = () => {
if (isLocked) {
return (
<UnitButton unitId={unitId} title="" contentType="lock" isActive onClick={() => {}} />
);
}
if (sequence.unitIds.length === 0 || unitId === null) {
return (
<div style={{ flexBasis: '100%', minWidth: 0, borderBottom: 'solid 1px #EAEAEA' }} />
);
}
return (
<SequenceNavigationTabs
unitIds={sequence.unitIds}
unitId={unitId}
showCompletion={sequence.showCompletion}
onNavigate={onNavigate}
/>
);
};
return sequenceStatus === 'loaded' && (
<nav className={classNames('sequence-navigation', className)}>
<Button className="previous-btn" onClick={previousSequenceHandler} disabled={isFirstUnit}>
<FontAwesomeIcon icon={faChevronLeft} className="mr-2" size="sm" />
<FormattedMessage
defaultMessage="Previous"
id="learn.sequence.navigation.previous.button"
description="The Previous button in the sequence nav"
/>
</Button>
{renderUnitButtons()}
<Button className="next-btn" onClick={nextSequenceHandler} disabled={isLastUnit}>
<FormattedMessage
defaultMessage="Next"
id="learn.sequence.navigation.next.button"
description="The Next button in the sequence nav"
/>
<FontAwesomeIcon icon={faChevronRight} className="ml-2" size="sm" />
</Button>
</nav>
);
}
SequenceNavigation.propTypes = {
sequenceId: PropTypes.string.isRequired,
unitId: PropTypes.string,
className: PropTypes.string,
onNavigate: PropTypes.func.isRequired,
nextSequenceHandler: PropTypes.func.isRequired,
previousSequenceHandler: PropTypes.func.isRequired,
};
SequenceNavigation.defaultProps = {
className: null,
unitId: null,
};

View File

@@ -0,0 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Dropdown } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import UnitButton from './UnitButton';
export default function SequenceNavigationDropdown({
unitId,
onNavigate,
showCompletion,
unitIds,
}) {
return (
<Dropdown className="sequence-navigation-dropdown">
<Dropdown.Button className="dropdown-button font-weight-normal w-100 border-right-0">
<FormattedMessage
defaultMessage="{current} of {total}"
description="The title of the mobile menu for sequence navigation of units"
id="learn.course.sequence.navigation.mobile.menu"
values={{
current: unitIds.indexOf(unitId) + 1,
total: unitIds.length,
}}
/>
</Dropdown.Button>
<Dropdown.Menu className="w-100">
{unitIds.map(buttonUnitId => (
<UnitButton
className="w-100"
isActive={unitId === buttonUnitId}
key={buttonUnitId}
onClick={onNavigate}
showCompletion={showCompletion}
showTitle
unitId={buttonUnitId}
/>
))}
</Dropdown.Menu>
</Dropdown>
);
}
SequenceNavigationDropdown.propTypes = {
unitId: PropTypes.string.isRequired,
onNavigate: PropTypes.func.isRequired,
showCompletion: PropTypes.bool.isRequired,
unitIds: PropTypes.arrayOf(PropTypes.string).isRequired,
};

View File

@@ -0,0 +1,53 @@
import React from 'react';
import PropTypes from 'prop-types';
import UnitButton from './UnitButton';
import SequenceNavigationDropdown from './SequenceNavigationDropdown';
import useIndexOfLastVisibleChild from '../../../../tabs/useIndexOfLastVisibleChild';
export default function SequenceNavigationTabs({
unitIds, unitId, showCompletion, onNavigate,
}) {
const [
indexOfLastVisibleChild,
containerRef,
invisibleStyle,
] = useIndexOfLastVisibleChild();
const shouldDisplayDropdown = indexOfLastVisibleChild === -1;
return (
<div style={{ flexBasis: '100%', minWidth: 0 }}>
<div className="sequence-navigation-tabs-container" ref={containerRef}>
<div
className="sequence-navigation-tabs d-flex flex-grow-1"
style={shouldDisplayDropdown ? invisibleStyle : null}
>
{unitIds.map(buttonUnitId => (
<UnitButton
key={buttonUnitId}
unitId={buttonUnitId}
isActive={unitId === buttonUnitId}
showCompletion={showCompletion}
onClick={onNavigate}
/>
))}
</div>
</div>
{shouldDisplayDropdown && (
<SequenceNavigationDropdown
unitId={unitId}
onNavigate={onNavigate}
showCompletion={showCompletion}
unitIds={unitIds}
/>
)}
</div>
);
}
SequenceNavigationTabs.propTypes = {
unitId: PropTypes.string.isRequired,
onNavigate: PropTypes.func.isRequired,
showCompletion: PropTypes.bool.isRequired,
unitIds: PropTypes.arrayOf(PropTypes.string).isRequired,
};

View File

@@ -0,0 +1,75 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import classNames from 'classnames';
import { Button } from '@edx/paragon';
import UnitIcon from './UnitIcon';
import CompleteIcon from './CompleteIcon';
import BookmarkFilledIcon from '../../bookmark/BookmarkFilledIcon';
function UnitButton({
onClick,
title,
contentType,
isActive,
bookmarked,
complete,
showCompletion,
unitId,
className,
showTitle,
}) {
const handleClick = useCallback(() => {
onClick(unitId);
});
return (
<Button
className={classNames({
active: isActive,
complete: showCompletion && complete,
}, className)}
onClick={handleClick}
title={title}
>
<UnitIcon type={contentType} />
{showTitle && <span className="unit-title">{title}</span>}
{showCompletion && complete ? <CompleteIcon size="sm" className="text-success ml-2" /> : null}
{bookmarked ? (
<BookmarkFilledIcon
className="text-primary small position-absolute"
style={{ top: '-3px', right: '5px' }}
/>
) : null}
</Button>
);
}
UnitButton.propTypes = {
bookmarked: PropTypes.bool,
className: PropTypes.string,
complete: PropTypes.bool,
contentType: PropTypes.string.isRequired,
isActive: PropTypes.bool,
onClick: PropTypes.func.isRequired,
showCompletion: PropTypes.bool,
showTitle: PropTypes.bool,
title: PropTypes.string.isRequired,
unitId: PropTypes.string.isRequired,
};
UnitButton.defaultProps = {
className: undefined,
isActive: false,
bookmarked: false,
complete: false,
showTitle: false,
showCompletion: true,
};
const mapStateToProps = (state, props) => ({
...state.models.units[props.unitId],
});
export default connect(mapStateToProps)(UnitButton);

View File

@@ -0,0 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faFilm, faBook, faEdit, faTasks, faLock,
} from '@fortawesome/free-solid-svg-icons';
export default function UnitIcon({ type }) {
let icon = null;
switch (type) {
case 'video':
icon = faFilm;
break;
case 'other':
icon = faBook;
break;
case 'vertical':
icon = faTasks;
break;
case 'problem':
icon = faEdit;
break;
case 'lock':
icon = faLock;
break;
default:
icon = faBook;
}
return (
<FontAwesomeIcon icon={icon} />
);
}
UnitIcon.propTypes = {
type: PropTypes.oneOf(['video', 'other', 'vertical', 'problem', 'lock']).isRequired,
};

View File

@@ -0,0 +1,66 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from '@edx/paragon';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { useSequenceNavigationMetadata } from './hooks';
export default function UnitNavigation(props) {
const {
sequenceId,
unitId,
onClickPrevious,
onClickNext,
} = props;
const { isFirstUnit, isLastUnit } = useSequenceNavigationMetadata(sequenceId, unitId);
return (
<div className="unit-navigation d-flex">
<Button
className="btn-outline-secondary previous-button mr-2"
disabled={isFirstUnit}
onClick={onClickPrevious}
>
<FontAwesomeIcon icon={faChevronLeft} className="mr-2" size="sm" />
<FormattedMessage
id="learn.sequence.navigation.after.unit.previous"
description="The button to go to the previous unit"
defaultMessage="Previous"
/>
</Button>
{isLastUnit ? (
<div className="m-2">
<span role="img" aria-hidden="true">&#129303;</span> {/* This is a hugging face emoji */}
{' '}
<FormattedMessage
id="learn.end.of.course"
description="Message shown to students in place of a 'Next' button when they're at the end of a course."
defaultMessage="You've reached the end of this course!"
/>
</div>
) : (
<Button
className="btn-outline-primary next-button"
onClick={onClickNext}
disabled={isLastUnit}
>
<FormattedMessage
id="learn.sequence.navigation.after.unit.next"
description="The button to go to the next unit"
defaultMessage="Next"
/>
<FontAwesomeIcon icon={faChevronRight} className="ml-2" size="sm" />
</Button>
)}
</div>
);
}
UnitNavigation.propTypes = {
sequenceId: PropTypes.string.isRequired,
unitId: PropTypes.string.isRequired,
onClickPrevious: PropTypes.func.isRequired,
onClickNext: PropTypes.func.isRequired,
};

View File

@@ -0,0 +1,24 @@
/* eslint-disable import/prefer-default-export */
import { useSelector } from 'react-redux';
import { useModel } from '../../../../model-store';
import { sequenceIdsSelector } from '../../../data/selectors';
export function useSequenceNavigationMetadata(currentSequenceId, currentUnitId) {
const sequenceIds = useSelector(sequenceIdsSelector);
const sequence = useModel('sequences', currentSequenceId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
// If we don't know the sequence and unit yet, then assume no.
if (courseStatus !== 'loaded' || !currentSequenceId || !currentUnitId) {
return { isFirstUnit: false, isLastUnit: false };
}
const isFirstSequence = sequenceIds.indexOf(currentSequenceId) === 0;
const isFirstUnitInSequence = sequence.unitIds.indexOf(currentUnitId) === 0;
const isFirstUnit = isFirstSequence && isFirstUnitInSequence;
const isLastSequence = sequenceIds.indexOf(currentSequenceId) === sequenceIds.length - 1;
const isLastUnitInSequence = sequence.unitIds.indexOf(currentUnitId) === sequence.unitIds.length - 1;
const isLastUnit = isLastSequence && isLastUnitInSequence;
return { isFirstUnit, isLastUnit };
}

View File

@@ -0,0 +1,2 @@
export { default as SequenceNavigation } from './SequenceNavigation';
export { default as UnitNavigation } from './UnitNavigation';

View File

@@ -0,0 +1,47 @@
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
const getSequenceXModuleHandlerUrl = (courseId, sequenceId) => `${getConfig().LMS_BASE_URL}/courses/${courseId}/xblock/${sequenceId}/handler/xmodule_handler`;
export async function getBlockCompletion(courseId, sequenceId, usageKey) {
// Post data sent to this endpoint must be url encoded
// TODO: Remove the need for this to be the case.
// TODO: Ensure this usage of URLSearchParams is working in Internet Explorer
const urlEncoded = new URLSearchParams();
urlEncoded.append('usage_key', usageKey);
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
};
const { data } = await getAuthenticatedHttpClient().post(
`${getSequenceXModuleHandlerUrl(courseId, sequenceId)}/get_completion`,
urlEncoded.toString(),
requestConfig,
);
if (data.complete) {
return true;
}
return false;
}
export async function updateSequencePosition(courseId, sequenceId, position) {
// Post data sent to this endpoint must be url encoded
// TODO: Remove the need for this to be the case.
// TODO: Ensure this usage of URLSearchParams is working in Internet Explorer
const urlEncoded = new URLSearchParams();
// Position is 1-indexed on the server and 0-indexed in this app. Adjust here.
urlEncoded.append('position', position + 1);
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
};
const { data } = await getAuthenticatedHttpClient().post(
`${getSequenceXModuleHandlerUrl(courseId, sequenceId)}/goto_position`,
urlEncoded.toString(),
requestConfig,
);
return data;
}

View File

@@ -0,0 +1,20 @@
/* eslint-disable import/prefer-default-export */
export function sequenceIdsSelector(state) {
if (state.courseware.courseStatus !== 'loaded') {
return [];
}
const { sectionIds } = state.models.courses[state.courseware.courseId];
let sequenceIds = [];
sectionIds.forEach(sectionId => {
sequenceIds = [...sequenceIds, ...state.models.sections[sectionId].sequenceIds];
});
return sequenceIds;
}
export function firstSequenceIdSelector(state) {
if (state.courseware.courseStatus !== 'loaded') {
return null;
}
const sectionId = state.models.courses[state.courseware.courseId].sectionIds[0];
return state.models.sections[sectionId].sequenceIds[0];
}

View File

@@ -0,0 +1,66 @@
import { logError } from '@edx/frontend-platform/logging';
import {
getBlockCompletion,
updateSequencePosition,
} from './api';
import {
updateModel,
} from '../../model-store';
export function checkBlockCompletion(courseId, sequenceId, unitId) {
return async (dispatch, getState) => {
const { models } = getState();
if (models.units[unitId].complete) {
return; // do nothing. Things don't get uncompleted after they are completed.
}
try {
const isComplete = await getBlockCompletion(courseId, sequenceId, unitId);
dispatch(updateModel({
modelType: 'units',
model: {
id: unitId,
complete: isComplete,
},
}));
} catch (error) {
logError(error);
}
};
}
export function saveSequencePosition(courseId, sequenceId, position) {
return async (dispatch, getState) => {
const { models } = getState();
const initialPosition = models.sequences[sequenceId].position;
// Optimistically update the position.
dispatch(updateModel({
modelType: 'sequences',
model: {
id: sequenceId,
position,
},
}));
try {
await updateSequencePosition(courseId, sequenceId, position);
// Update again under the assumption that the above call succeeded, since it doesn't return a
// meaningful response.
dispatch(updateModel({
modelType: 'sequences',
model: {
id: sequenceId,
position,
},
}));
} catch (error) {
logError(error);
dispatch(updateModel({
modelType: 'sequences',
model: {
id: sequenceId,
position: initialPosition,
},
}));
}
};
}

1
src/courseware/index.js Normal file
View File

@@ -0,0 +1 @@
export { default } from './CoursewareContainer';

View File

@@ -0,0 +1,11 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learn.loading.error': {
id: 'learn.loading.error',
defaultMessage: 'Error: {error}',
description: 'Message when learning sequence fails to load',
},
});
export default messages;

147
src/data/api.js Normal file
View File

@@ -0,0 +1,147 @@
/* eslint-disable import/prefer-default-export */
import { getConfig, camelCaseObject } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient, getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { logError } from '@edx/frontend-platform/logging';
function normalizeMetadata(metadata) {
return {
id: metadata.id,
title: metadata.name,
number: metadata.number,
org: metadata.org,
enrollmentStart: metadata.enrollment_start,
enrollmentEnd: metadata.enrollment_end,
end: metadata.end,
start: metadata.start,
enrollmentMode: metadata.enrollment.mode,
isEnrolled: metadata.enrollment.is_active,
userHasAccess: metadata.user_has_access,
isStaff: metadata.user_has_staff_access,
verifiedMode: camelCaseObject(metadata.verified_mode),
tabs: camelCaseObject(metadata.tabs),
showCalculator: metadata.show_calculator,
};
}
export async function getCourseMetadata(courseId) {
const url = `${getConfig().LMS_BASE_URL}/api/courseware/course/${courseId}`;
const { data } = await getAuthenticatedHttpClient().get(url);
return normalizeMetadata(data);
}
function normalizeBlocks(courseId, blocks) {
const models = {
courses: {},
sections: {},
sequences: {},
units: {},
};
Object.values(blocks).forEach(block => {
switch (block.type) {
case 'course':
models.courses[block.id] = {
id: courseId,
title: block.display_name,
sectionIds: block.children || [],
};
break;
case 'chapter':
models.sections[block.id] = {
id: block.id,
title: block.display_name,
sequenceIds: block.children || [],
};
break;
case 'sequential':
models.sequences[block.id] = {
id: block.id,
title: block.display_name,
lmsWebUrl: block.lms_web_url,
unitIds: block.children || [],
};
break;
case 'vertical':
models.units[block.id] = {
id: block.id,
title: block.display_name,
};
break;
default:
logError(`Unexpected course block type: ${block.type} with ID ${block.id}. Expected block types are course, chapter, sequential, and vertical.`);
}
});
// Next go through each list and use their child lists to decorate those children with a
// reference back to their parent.
Object.values(models.courses).forEach(course => {
if (Array.isArray(course.sectionIds)) {
course.sectionIds.forEach(sectionId => {
const section = models.sections[sectionId];
section.courseId = course.id;
});
}
});
Object.values(models.sections).forEach(section => {
if (Array.isArray(section.sequenceIds)) {
section.sequenceIds.forEach(sequenceId => {
models.sequences[sequenceId].sectionId = section.id;
});
}
});
Object.values(models.sequences).forEach(sequence => {
if (Array.isArray(sequence.unitIds)) {
sequence.unitIds.forEach(unitId => {
models.units[unitId].sequenceId = sequence.id;
});
}
});
return models;
}
export async function getCourseBlocks(courseId) {
const { username } = getAuthenticatedUser();
const url = new URL(`${getConfig().LMS_BASE_URL}/api/courses/v2/blocks/`);
url.searchParams.append('course_id', courseId);
url.searchParams.append('username', username);
url.searchParams.append('depth', 3);
url.searchParams.append('requested_fields', 'children,show_gated_sections');
const { data } = await getAuthenticatedHttpClient().get(url.href, {});
return normalizeBlocks(courseId, data.blocks);
}
function normalizeSequenceMetadata(sequence) {
return {
sequence: {
id: sequence.item_id,
unitIds: sequence.items.map(unit => unit.id),
bannerText: sequence.banner_text,
title: sequence.display_name,
gatedContent: camelCaseObject(sequence.gated_content),
isTimeLimited: sequence.is_time_limited,
// Position comes back from the server 1-indexed. Adjust here.
activeUnitIndex: sequence.position ? sequence.position - 1 : 0,
saveUnitPosition: sequence.save_position,
showCompletion: sequence.show_completion,
},
units: sequence.items.map(unit => ({
id: unit.id,
sequenceId: sequence.item_id,
bookmarked: unit.bookmarked,
complete: unit.complete,
title: unit.page_title,
contentType: unit.type,
})),
};
}
export async function getSequenceMetadata(sequenceId) {
const { data } = await getAuthenticatedHttpClient()
.get(`${getConfig().LMS_BASE_URL}/api/courseware/sequence/${sequenceId}`, {});
return normalizeSequenceMetadata(data);
}

6
src/data/index.js Normal file
View File

@@ -0,0 +1,6 @@
export {
fetchCourse,
fetchSequence,
} from './thunks';
export { reducer } from './slice';

55
src/data/slice.js Normal file
View File

@@ -0,0 +1,55 @@
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';
export const LOADING = 'loading';
export const LOADED = 'loaded';
export const FAILED = 'failed';
const slice = createSlice({
name: 'courseware',
initialState: {
courseStatus: 'loading',
courseId: null,
sequenceStatus: 'loading',
sequenceId: null,
},
reducers: {
fetchCourseRequest: (state, { payload }) => {
state.courseId = payload.courseId;
state.courseStatus = LOADING;
},
fetchCourseSuccess: (state, { payload }) => {
state.courseId = payload.courseId;
state.courseStatus = LOADED;
},
fetchCourseFailure: (state, { payload }) => {
state.courseId = payload.courseId;
state.courseStatus = FAILED;
},
fetchSequenceRequest: (state, { payload }) => {
state.sequenceId = payload.sequenceId;
state.sequenceStatus = LOADING;
},
fetchSequenceSuccess: (state, { payload }) => {
state.sequenceId = payload.sequenceId;
state.sequenceStatus = LOADED;
},
fetchSequenceFailure: (state, { payload }) => {
state.sequenceId = payload.sequenceId;
state.sequenceStatus = FAILED;
},
},
});
export const {
fetchCourseRequest,
fetchCourseSuccess,
fetchCourseFailure,
fetchSequenceRequest,
fetchSequenceSuccess,
fetchSequenceFailure,
} = slice.actions;
export const {
reducer,
} = slice;

79
src/data/thunks.js Normal file
View File

@@ -0,0 +1,79 @@
import { logError } from '@edx/frontend-platform/logging';
import {
getCourseMetadata,
getCourseBlocks,
getSequenceMetadata,
} from './api';
import {
addModelsMap, updateModel, updateModels, updateModelsMap,
} from '../model-store';
import {
fetchCourseRequest,
fetchCourseSuccess,
fetchCourseFailure,
fetchSequenceRequest,
fetchSequenceSuccess,
fetchSequenceFailure,
} from './slice';
export function fetchCourse(courseId) {
return async (dispatch) => {
dispatch(fetchCourseRequest({ courseId }));
Promise.all([
getCourseBlocks(courseId),
getCourseMetadata(courseId),
]).then(([
{
courses, sections, sequences, units,
},
course,
]) => {
dispatch(addModelsMap({
modelType: 'courses',
modelsMap: courses,
}));
dispatch(updateModel({
modelType: 'courses',
model: course,
}));
dispatch(addModelsMap({
modelType: 'sections',
modelsMap: sections,
}));
// We update for sequences and units because the sequence metadata may have come back first.
dispatch(updateModelsMap({
modelType: 'sequences',
modelsMap: sequences,
}));
dispatch(updateModelsMap({
modelType: 'units',
modelsMap: units,
}));
dispatch(fetchCourseSuccess({ courseId }));
}).catch((error) => {
logError(error);
dispatch(fetchCourseFailure({ courseId }));
});
};
}
export function fetchSequence(sequenceId) {
return async (dispatch) => {
dispatch(fetchSequenceRequest({ sequenceId }));
try {
const { sequence, units } = await getSequenceMetadata(sequenceId);
dispatch(updateModel({
modelType: 'sequences',
model: sequence,
}));
dispatch(updateModels({
modelType: 'units',
models: units,
}));
dispatch(fetchSequenceSuccess({ sequenceId }));
} catch (error) {
logError(error);
dispatch(fetchSequenceFailure({ sequenceId }));
}
};
}

View File

@@ -0,0 +1,24 @@
import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import Alert from '../user-messages/Alert';
import messages from './messages';
function EnrollmentAlert({ intl }) {
return (
<Alert type="error">
{intl.formatMessage(messages['learning.enrollment.alert'])}
{' '}
<a href={`${getConfig().LMS_BASE_URL}/api/enrollment/v1/enrollment`}>
{intl.formatMessage(messages['learning.enrollment.enroll.now'])}
</a>
</Alert>
);
}
EnrollmentAlert.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(EnrollmentAlert);

View File

@@ -0,0 +1,31 @@
/* eslint-disable import/prefer-default-export */
import { useContext, useState, useEffect } from 'react';
import UserMessagesContext from '../user-messages/UserMessagesContext';
import { useModel } from '../model-store';
export function useEnrollmentAlert(courseId) {
const course = useModel('courses', courseId);
const { add, remove } = useContext(UserMessagesContext);
const [alertId, setAlertId] = useState(null);
const isEnrolled = course && course.isEnrolled;
useEffect(() => {
if (course && course.isEnrolled !== undefined) {
if (!course.isEnrolled) {
setAlertId(add({
code: 'clientEnrollmentAlert',
dismissible: false,
type: 'error',
topic: 'course',
}));
} else if (alertId !== null) {
remove(alertId);
setAlertId(null);
}
}
return () => {
if (alertId !== null) {
remove(alertId);
}
};
}, [course, isEnrolled]);
}

View File

@@ -0,0 +1,2 @@
export { default } from './EnrollmentAlert';
export { useEnrollmentAlert } from './hooks';

View File

@@ -0,0 +1,16 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learning.enrollment.alert': {
id: 'learning.enrollment.alert',
defaultMessage: 'You must be enrolled in the course to see course content.',
description: 'Message shown to indicate that a user needs to enroll in a course prior to viewing the course content. Shown as part of an alert, along with a link to enroll.',
},
'learning.enrollment.enroll.now': {
id: 'learning.enrollment.enroll.now',
defaultMessage: 'Enroll Now',
description: 'A link prompting the user to click on it to enroll in the currently viewed course.',
},
});
export default messages;

View File

@@ -1,41 +1,37 @@
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import { APP_INIT_ERROR, APP_READY, subscribe, initialize } from '@edx/frontend-platform';
import {
APP_INIT_ERROR, APP_READY, subscribe, initialize,
} from '@edx/frontend-platform';
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Switch, Link } from 'react-router-dom';
import { Route, Switch } from 'react-router-dom';
import Header, { messages as headerMessages } from '@edx/frontend-component-header';
import { messages as headerMessages } from '@edx/frontend-component-header';
import Footer, { messages as footerMessages } from '@edx/frontend-component-footer';
import appMessages from './i18n';
import CourseTabsNavigation from './components/CourseTabsNavigation';
import LearningSequencePage from './learning-sequence/LearningSequencePage';
import UserMessagesProvider from './user-messages/UserMessagesProvider';
import './index.scss';
import './assets/favicon.ico';
import CoursewareContainer from './courseware';
import CourseHomeContainer from './course-home';
import CourseContainer from './CourseContainer';
import store from './store';
subscribe(APP_READY, () => {
ReactDOM.render(
<AppProvider>
<Header />
<div className="container pt-2">
<CourseTabsNavigation activeTabSlug="course" />
</div>
<Switch>
{/* Staging: course-v1:UBCx+Water201x_2+2T2015 */}
<Route
exact
path="/"
render={() => <Link to="/course/course-v1%3AedX%2BDemoX%2BDemo_Course/block-v1:edX+DemoX+Demo_Course+type@sequential+block@edx_introduction/block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_0270f6de40fc">Visit Demo Course</Link>}
/>
<Route path="/course/:courseId/:subSectionId/:unitId" component={LearningSequencePage} />
<Route path="/course/:courseId/:subSectionId" component={LearningSequencePage} />
<Route path="/course/:courseId" component={LearningSequencePage} />
</Switch>
<Footer />
<AppProvider store={store}>
<UserMessagesProvider>
<Switch>
<Route path="/course/:courseId" component={CourseContainer} />
</Switch>
<Footer />
</UserMessagesProvider>
</AppProvider>,
document.getElementById('root'),
);

View File

@@ -1,17 +1,51 @@
$primary: #1176B2;
@import '~@edx/paragon/scss/edx/theme.scss';
@import './learning-sequence/index';
@import "~@edx/frontend-component-header/dist/index";
@import "~@edx/frontend-component-footer/dist/footer";
// TODO: Fix .btn-outline-light style in paragon
.btn-outline-light {
&:hover, &:focus {
color: $primary;
border-color: $white;
background-color: $white;
}
&:not(:disabled):not(.disabled):active {
border-color: $white;
}
}
// TODO: Fix .container-fluid for mobile in paragon
.container-fluid {
@media (max-width: -1 + map-get($grid-breakpoints, 'sm')) {
padding-left: $grid-gutter-width/2;
padding-right: $grid-gutter-width/2;
}
}
#root {
display: flex;
flex-direction: column;
height: 100vh;
min-height: 100vh;
main {
flex-grow: 1;
}
header {
flex: 0;
.logo {
display: block;
box-sizing: content-box;
position: relative;
top: .10em;
height: 1.75rem;
margin-right: 1rem;
img {
display: block;
height: 100%;
}
}
}
footer {
@@ -19,17 +53,257 @@
}
}
.course-header {
min-width: 0;
.course-title-lockup {
min-width: 0;
span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.user-dropdown {
.btn {
height: 3rem;
@media (max-width: -1 + map-get($grid-breakpoints, 'sm')) {
padding: 0 .5rem;
}
}
}
}
.course-tabs-navigation {
border-bottom: solid 1px #EAEAEA;
}
.nav-underline-tabs {
margin: 0 0 -1px;
.nav-link {
border-bottom: 4px solid transparent;
color: theme-color('gray', 700);
border-top: 4px solid transparent;
color: theme-color('gray', 400);
// temporary until we can remove .btn class from dropdowns
border-left: 0;
border-right: 0;
border-radius: 0;
&:hover,
&:focus,
&.active {
font-weight: $font-weight-normal;
color: theme-color('primary', 500);
border-color: theme-color('primary', 500);
border-bottom-color: theme-color('primary', 500);
}
}
}
.sequence-container {
display: flex;
flex-direction: column;
flex-grow: 1;
margin-bottom: 4rem;
// On mobile, the unit container will be responsible
// for container padding.
@media (min-width: map-get($grid-breakpoints, 'sm')) {
max-width: 1440px;
width: 100%;
padding: 0 $grid-gutter-width;
margin-right: auto;
margin-left: auto;
}
}
.sequence {
@media (min-width: map-get($grid-breakpoints, 'sm')) {
border: solid 1px #EAEAEA;
border-radius: 4px;
}
}
.sequence-navigation {
display: flex;
@media (min-width: map-get($grid-breakpoints, 'sm')) {
margin: -1px -1px 0;
}
.btn {
flex-grow: 1;
display: inline-flex;
border-radius: 0;
border: solid 1px #EAEAEA;
border-left-width: 0;
position: relative;
font-weight: 400;
padding: 0 .375rem;
height: 3rem;
justify-content: center;
align-items: center;
color: theme-color('gray', 400);
white-space: nowrap;
&:hover,
&:focus,
&.active {
color: theme-color('gray', 700);
}
&:focus {
z-index: 1;
}
&.active {
&:after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
right: 0;
height: 2px;
background: $primary;
}
}
&.complete {
background-color: #EEF7E5;
color: $success;
}
&:first-child {
border-left-width: 0;
}
&:last-child {
border-right-width: 0;
}
}
.sequence-navigation-tabs-container {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 100%;
display: flex;
// min-width 0 prevents the flex item from overflowing the parent container
// https://dev.to/martyhimmel/quick-tip-to-stop-flexbox-from-overflowing-peb
min-width: 0;
}
.sequence-navigation-tabs {
.btn {
flex-basis: 100%;
min-width: 4rem;
}
}
.sequence-navigation-dropdown {
.dropdown-menu .btn {
flex-basis: 100%;
min-width: 4rem;
padding-left: 1rem;
padding-right: 1rem;
display: inline-flex;
align-items: center;
justify-content: flex-start;
border-right: 0;
& + .btn {
border-top: 0;
}
.unit-title {
flex-grow: 1;
text-align: left;
overflow: hidden;
min-width: 0;
margin: 0 1rem;
text-overflow: ellipsis;
}
&.active {
&:after {
content: '';
position: absolute;
bottom: 0px;
left: -1px;
top: 0;
right: auto;
width: 2px;
height: auto;
background: $primary;
}
}
}
}
.previous-btn, .next-btn {
min-width: 4rem;
color: theme-color('gray', 700);
display: inline-flex;
justify-content: center;
align-items: center;
@media (max-width: -1 + map-get($grid-breakpoints, 'sm')) {
padding-top: 1rem;
padding-bottom: 1rem;
span {
@include sr-only();
}
}
@media (min-width: map-get($grid-breakpoints, 'sm')) {
min-width: 10rem;
}
}
.previous-btn {
border-left-width: 0;
margin-left: 0;
@media (min-width: map-get($grid-breakpoints, 'sm')) {
border-left-width: 1px;
border-top-left-radius: 4px;
}
}
.next-btn {
border-left-width: 1px;
border-right-width: 0;
@media (min-width: map-get($grid-breakpoints, 'sm')) {
border-top-right-radius: 4px;
border-right-width: 1px;
}
}
}
.unit-container {
padding: 0 $grid-gutter-width 2rem;
max-width: 1024px;
margin-left: auto;
margin-right: auto;
@media (min-width: 830px) {
padding-left: 40px;
padding-right: 40px;
}
}
.unit-iframe-wrapper {
margin: 0 -20px 2rem;
@media (min-width: 830px) {
margin: 0 -40px 2rem;
}
}
#unit-iframe {
width: 100%;
border: none;
display: block;
}
.unit-navigation {
display: flex;
justify-content: center;
max-width: 640px;
margin: 0 auto;
.previous-button,
.next-button {
white-space: nowrap;
border-radius: 4px;
&:focus:before {
border-radius: 6px;
}
}
.next-button {
flex-basis: 75%;
}
.previous-button {
flex-basis: 25%;
}
}

View File

@@ -1,54 +0,0 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronRight } from '@fortawesome/free-solid-svg-icons';
import { getConfig } from '@edx/frontend-platform';
import CourseStructureContext from './CourseStructureContext';
import { useBlockAncestry } from './data/hooks';
const CourseBreadcrumbs = () => {
const { courseId, unitId } = useContext(CourseStructureContext);
const ancestry = useBlockAncestry(unitId);
const links = ancestry.map(ancestor => ({
id: ancestor.id,
label: ancestor.displayName,
url: `${getConfig().LMS_BASE_URL}/courses/${courseId}/course/#${ancestor.id}`,
}));
return (
<nav aria-label="breadcrumb">
<ol className="list-inline">
{links.map(({ id, url, label }, i) => (
<CourseBreadcrumb key={id} url={url} label={label} last={i === links.length - 1} />
))}
</ol>
</nav>
);
};
export default CourseBreadcrumbs;
function CourseBreadcrumb({ url, label, last }) {
return (
<React.Fragment key={`${label}-${url}`}>
<li className="list-inline-item">
{last ? label : (<a href={url}>{label}</a>)}
</li>
{!last &&
<li className="list-inline-item" role="presentation" aria-label="spacer">
<FontAwesomeIcon icon={faChevronRight} />
</li>
}
</React.Fragment>
);
}
CourseBreadcrumb.propTypes = {
url: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
last: PropTypes.bool.isRequired,
};

View File

@@ -1,5 +0,0 @@
import React from 'react';
const CourseStructureContext = React.createContext({});
export default CourseStructureContext;

View File

@@ -1,58 +0,0 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import PageLoading from './PageLoading';
import messages from './messages';
import CourseBreadcrumbs from './CourseBreadcrumbs';
import CourseStructureContext from './CourseStructureContext';
import { useLoadCourseStructure, useMissingSubSectionRedirect } from './data/hooks';
import SubSection from './sub-section/SubSection';
import { history } from '@edx/frontend-platform';
function LearningSequencePage({ match, intl }) {
const {
courseId,
subSectionId,
unitId,
} = match.params;
const { blocks, loaded, courseBlockId } = useLoadCourseStructure(courseId);
useMissingSubSectionRedirect(loaded, blocks, courseId, courseBlockId, subSectionId);
return (
<main className="container-fluid d-flex flex-column flex-grow-1">
<CourseStructureContext.Provider value={{
courseId,
courseBlockId,
subSectionId,
unitId,
blocks,
loaded,
}}
>
{!loaded && <PageLoading
srMessage={intl.formatMessage(messages['learn.loading.learning.sequence'])}
/>}
{loaded && unitId && <CourseBreadcrumbs />}
{subSectionId && <SubSection />}
</CourseStructureContext.Provider>
</main>
);
}
export default injectIntl(LearningSequencePage);
LearningSequencePage.propTypes = {
match: PropTypes.shape({
params: PropTypes.shape({
courseId: PropTypes.string.isRequired,
subSectionId: PropTypes.string,
unitId: PropTypes.string,
}).isRequired,
}).isRequired,
intl: intlShape.isRequired,
};

View File

@@ -1,15 +0,0 @@
/* eslint-disable import/prefer-default-export */
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig } from '@edx/frontend-platform';
export async function getCourseBlocks(courseId, username) {
const url = new URL(`${getConfig().LMS_BASE_URL}/api/courses/v2/blocks/`);
url.searchParams.append('course_id', decodeURIComponent(courseId));
url.searchParams.append('username', username);
url.searchParams.append('depth', 3);
url.searchParams.append('requested_fields', 'children,show_gated_sections');
const { data } = await getAuthenticatedHttpClient().get(url.href, {});
return data;
}

View File

@@ -1,136 +0,0 @@
import { useContext, useMemo, useState, useEffect } from 'react';
import { history } from '@edx/frontend-platform';
import { AppContext } from '@edx/frontend-platform/react';
import CourseStructureContext from '../CourseStructureContext';
import { getCourseBlocks } from './api';
import { findBlockAncestry, createBlocksMap, createSubSectionIdList, createUnitIdList } from './utils';
export function useBlockAncestry(blockId) {
const { blocks, loaded } = useContext(CourseStructureContext);
return useMemo(() => {
if (!loaded) {
return [];
}
return findBlockAncestry(
blocks,
blockId,
);
}, [blocks, blockId, loaded]);
}
export function useMissingSubSectionRedirect(
loaded,
blocks,
courseId,
courseBlockId,
subSectionId,
) {
useEffect(() => {
if (loaded && !subSectionId) {
const course = blocks[courseBlockId];
const nextSectionId = course.children[0];
const nextSection = blocks[nextSectionId];
const nextSubSectionId = nextSection.children[0];
const nextSubSection = blocks[nextSubSectionId];
const nextUnitId = nextSubSection.children[0];
history.push(`/course/${courseId}/${nextSubSectionId}/${nextUnitId}`);
}
}, [loaded, subSectionId]);
}
export function useLoadCourseStructure(courseId) {
const { authenticatedUser } = useContext(AppContext);
const [blocks, setBlocks] = useState(null);
const [loaded, setLoaded] = useState(false);
const [courseBlockId, setCourseBlockId] = useState();
useEffect(() => {
setLoaded(false);
getCourseBlocks(courseId, authenticatedUser.username).then((blocksData) => {
setBlocks(createBlocksMap(blocksData.blocks));
setCourseBlockId(blocksData.root);
setLoaded(true);
});
}, [courseId]);
return {
blocks, loaded, courseBlockId,
};
}
export function useCurrentCourse() {
const { loaded, courseBlockId, blocks } = useContext(CourseStructureContext);
return loaded ? blocks[courseBlockId] : null;
}
export function useCurrentSubSection() {
const { loaded, blocks, subSectionId } = useContext(CourseStructureContext);
return loaded && subSectionId ? blocks[subSectionId] : null;
}
export function useCurrentSection() {
const { loaded, blocks } = useContext(CourseStructureContext);
const subSection = useCurrentSubSection();
return loaded ? blocks[subSection.parentId] : null;
}
export function useCurrentUnit() {
const { loaded, blocks, unitId } = useContext(CourseStructureContext);
return loaded && unitId ? blocks[unitId] : null;
}
export function useUnitIds() {
const { loaded, blocks, courseBlockId } = useContext(CourseStructureContext);
return useMemo(
() => (loaded ? createUnitIdList(blocks, courseBlockId) : []),
[loaded, blocks, courseBlockId],
);
}
export function usePreviousUnit() {
const { loaded, blocks, unitId } = useContext(CourseStructureContext);
const unitIds = useUnitIds();
const currentUnitIndex = unitIds.indexOf(unitId);
if (currentUnitIndex === 0) {
return null;
}
return loaded ? blocks[unitIds[currentUnitIndex - 1]] : null;
}
export function useNextUnit() {
const { loaded, blocks, unitId } = useContext(CourseStructureContext);
const unitIds = useUnitIds();
const currentUnitIndex = unitIds.indexOf(unitId);
if (currentUnitIndex === unitIds.length - 1) {
return null;
}
return loaded ? blocks[unitIds[currentUnitIndex + 1]] : null;
}
export function useCurrentSubSectionUnits() {
const { loaded, blocks } = useContext(CourseStructureContext);
const subSection = useCurrentSubSection();
return loaded ? subSection.children.map(id => blocks[id]) : [];
}
export function useSubSectionIdList() {
const { loaded, blocks, courseBlockId } = useContext(CourseStructureContext);
const subSectionIdList = useMemo(
() => (loaded ? createSubSectionIdList(blocks, courseBlockId) : []),
[blocks, courseBlockId],
);
return subSectionIdList;
}

View File

@@ -1,67 +0,0 @@
/* eslint-disable no-plusplus */
import { camelCaseObject } from '@edx/frontend-platform';
export function createBlocksMap(blocksData) {
const blocks = {};
const blocksList = Object.values(blocksData);
// First go through the list and flesh out our blocks map, camelCasing the objects as we go.
for (let i = 0; i < blocksList.length; i++) {
const block = blocksList[i];
blocks[block.id] = camelCaseObject(block);
}
// Next go through the blocksList again - now that we've added them all to the blocks map - and
// append a parent ID to every child found in every `children` list, using the blocks map to find
// them.
for (let i = 0; i < blocksList.length; i++) {
const block = blocksList[i];
if (Array.isArray(block.children)) {
for (let j = 0; j < block.children.length; j++) {
const childId = block.children[j];
const child = blocks[childId];
child.parentId = block.id;
}
}
}
return blocks;
}
export function createSubSectionIdList(blocks, entryPointId, subSections = []) {
const block = blocks[entryPointId];
if (block.type === 'sequential') {
subSections.push(block.id);
}
if (Array.isArray(block.children)) {
for (let i = 0; i < block.children.length; i++) {
const childId = block.children[i];
createSubSectionIdList(blocks, childId, subSections);
}
}
return subSections;
}
export function createUnitIdList(blocks, entryPointId, units = []) {
const block = blocks[entryPointId];
if (block.type === 'vertical') {
units.push(block.id);
}
if (Array.isArray(block.children)) {
for (let i = 0; i < block.children.length; i++) {
const childId = block.children[i];
createUnitIdList(blocks, childId, units);
}
}
return units;
}
export function findBlockAncestry(blocks, blockId, descendents = []) {
const block = blocks[blockId];
descendents.unshift(block);
if (block.parentId === undefined) {
return descendents;
}
return findBlockAncestry(blocks, block.parentId, descendents);
}

View File

@@ -1,4 +0,0 @@
iframe {
border: 0;
width: 100%;
}

View File

@@ -1,65 +0,0 @@
import React, { useContext, Suspense } from 'react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import SubSectionNavigation from './SubSectionNavigation';
import CourseStructureContext from '../CourseStructureContext';
import Unit from './Unit';
import {
useLoadSubSectionMetadata,
useExamRedirect,
usePersistentUnitPosition,
useMissingUnitRedirect,
} from './data/hooks';
import SubSectionMetadataContext from './SubSectionMetadataContext';
import PageLoading from '../PageLoading';
import messages from './messages';
import { useCurrentUnit } from '../data/hooks';
const ContentLock = React.lazy(() => import('./content-lock'));
function SubSection({ intl }) {
const {
courseId,
subSectionId,
unitId,
blocks,
} = useContext(CourseStructureContext);
const { metadata, loaded } = useLoadSubSectionMetadata(courseId, subSectionId);
usePersistentUnitPosition(courseId, subSectionId, unitId, metadata);
useExamRedirect(metadata, blocks);
useMissingUnitRedirect(metadata, loaded);
const unit = useCurrentUnit();
const ready = blocks !== null && metadata !== null && unitId && unit;
if (!ready) {
return null;
}
const isGated = metadata.gatedContent.gated;
return (
<SubSectionMetadataContext.Provider value={metadata}>
<section className="d-flex flex-column flex-grow-1">
<SubSectionNavigation />
{isGated && (
<Suspense fallback={<PageLoading
srMessage={intl.formatMessage(messages['learn.loading.content.lock'])}
/>}
>
<ContentLock />
</Suspense>
)}
{!isGated && <Unit id={unitId} unit={unit} />}
</section>
</SubSectionMetadataContext.Provider>
);
}
SubSection.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(SubSection);

View File

@@ -1,5 +0,0 @@
import React from 'react';
const SubSectionMetadataContext = React.createContext({});
export default SubSectionMetadataContext;

View File

@@ -1,144 +0,0 @@
import React, { useCallback, useContext } from 'react';
import PropTypes from 'prop-types';
import { history } from '@edx/frontend-platform';
import { Button } from '@edx/paragon';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faFilm, faBook, faPencilAlt, faTasks, faLock } from '@fortawesome/free-solid-svg-icons';
import { usePreviousUnit, useNextUnit, useCurrentSubSectionUnits, useCurrentUnit } from '../data/hooks';
import CourseStructureContext from '../CourseStructureContext';
import SubSectionMetadataContext from './SubSectionMetadataContext';
function UnitIcon({ type }) {
let icon = null;
switch (type) {
case 'video':
icon = faFilm;
break;
case 'other':
icon = faBook;
break;
case 'vertical':
icon = faTasks;
break;
case 'problem':
icon = faPencilAlt;
break;
case 'lock':
icon = faLock;
break;
default:
icon = faBook;
}
return (
<FontAwesomeIcon icon={icon} />
);
}
UnitIcon.propTypes = {
type: PropTypes.oneOf(['video', 'other', 'vertical', 'problem', 'lock']).isRequired,
};
export default function SubSectionNavigation() {
const { courseId, unitId } = useContext(CourseStructureContext);
const previousUnit = usePreviousUnit();
const nextUnit = useNextUnit();
const handlePreviousClick = useCallback(() => {
if (previousUnit) {
history.push(`/course/${courseId}/${previousUnit.parentId}/${previousUnit.id}`);
}
});
const handleNextClick = useCallback(() => {
if (nextUnit) {
history.push(`/course/${courseId}/${nextUnit.parentId}/${nextUnit.id}`);
}
});
const handleUnitClick = useCallback((unit) => {
history.push(`/course/${courseId}/${unit.parentId}/${unit.id}`);
});
if (!unitId) {
return null;
}
return (
<nav className="flex-grow-0 d-flex w-100 mb-3">
<Button
key="previous"
className="btn-outline-primary"
onClick={handlePreviousClick}
>
Previous
</Button>
<UnitNavigation clickHandler={handleUnitClick} />
<Button
key="next"
className="btn-outline-primary"
onClick={handleNextClick}
>
Next
</Button>
</nav>
);
}
function UnitNavigation({ clickHandler }) {
const currentUnit = useCurrentUnit();
const units = useCurrentSubSectionUnits();
const metadata = useContext(SubSectionMetadataContext);
const isGated = metadata.gatedContent.gated;
return (
<div className="btn-group ml-2 mr-2 flex-grow-1 d-flex" role="group">
{!isGated && units.map(unit => (
<UnitButton key={unit.id} unit={unit} disabled={unit.id === currentUnit.id} clickHandler={clickHandler} />
))}
{isGated && <UnitButton key={currentUnit.id} unit={currentUnit} disabled locked />}
</div>
);
}
UnitNavigation.propTypes = {
clickHandler: PropTypes.func.isRequired,
};
function UnitButton({
unit, disabled, locked, clickHandler,
}) {
const { id, type } = unit;
const handleClick = useCallback(() => {
if (clickHandler !== null) {
clickHandler(unit);
}
}, [unit]);
return (
<Button
key={id}
className="btn-outline-secondary unit-button flex-grow-1"
onClick={handleClick}
disabled={disabled}
>
<UnitIcon type={locked ? 'lock' : type} />
</Button>
);
}
UnitButton.propTypes = {
unit: PropTypes.shape({
id: PropTypes.string.isRequired,
type: PropTypes.oneOf(['video', 'other', 'vertical', 'problem']).isRequired,
}).isRequired,
disabled: PropTypes.bool.isRequired, // Whether or not the button will function.
locked: PropTypes.bool, // Whether the unit is semantically "locked" and unnavigable.
clickHandler: PropTypes.func,
};
UnitButton.defaultProps = {
clickHandler: null,
locked: false,
};

View File

@@ -1,24 +0,0 @@
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
export default function Unit({ id, unit }) {
const iframeRef = useRef(null);
const iframeUrl = `${getConfig().LMS_BASE_URL}/xblock/${id}`;
const { displayName } = unit;
return (
<iframe
className="flex-grow-1"
title={displayName}
ref={iframeRef}
src={iframeUrl}
/>
);
}
Unit.propTypes = {
id: PropTypes.string.isRequired,
unit: PropTypes.shape({
displayName: PropTypes.string.isRequired,
}).isRequired,
};

View File

@@ -1,33 +0,0 @@
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
/* eslint-disable import/prefer-default-export */
const getSubSectionXModuleHandlerUrl = (courseId, subSectionId) =>
`${getConfig().LMS_BASE_URL}/courses/${courseId}/xblock/${subSectionId}/handler/xmodule_handler`;
export async function getSubSectionMetadata(courseId, subSectionId) {
const { data } = await getAuthenticatedHttpClient()
.get(`${getSubSectionXModuleHandlerUrl(courseId, subSectionId)}/metadata`, {});
return data;
}
export async function saveSubSectionPosition(courseId, subSectionId, position) {
// Post data sent to this endpoint must be url encoded
// TODO: Remove the need for this to be the case.
// TODO: Ensure this usage of URLSearchParams is working in Internet Explorer
const urlEncoded = new URLSearchParams();
urlEncoded.append('position', position);
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
};
const { data } = await getAuthenticatedHttpClient().post(
`${getSubSectionXModuleHandlerUrl(courseId, subSectionId)}/goto_position`,
urlEncoded.toString(),
requestConfig,
);
return data;
}

View File

@@ -1,75 +0,0 @@
import { useState, useEffect, useContext } from 'react';
import { camelCaseObject, history } from '@edx/frontend-platform';
import { getSubSectionMetadata, saveSubSectionPosition } from './api';
import CourseStructureContext from '../../CourseStructureContext';
export function useLoadSubSectionMetadata(courseId, subSectionId) {
const [metadata, setMetadata] = useState(null);
const [loaded, setLoaded] = useState(false);
useEffect(() => {
setLoaded(false);
setMetadata(null);
getSubSectionMetadata(courseId, subSectionId).then((data) => {
setMetadata(camelCaseObject(data));
setLoaded(true);
});
}, [courseId, subSectionId]);
return {
metadata,
loaded,
};
}
export function useExamRedirect(metadata, blocks) {
useEffect(() => {
if (metadata !== null && blocks !== null) {
if (metadata.isTimeLimited) {
global.location.href = blocks[metadata.itemId].lmsWebUrl;
}
}
}, [metadata, blocks]);
}
/**
* Save the position of current unit the subsection
*/
export function usePersistentUnitPosition(courseId, subSectionId, unitId, subSectionMetadata) {
useEffect(() => {
// All values must be defined to function
const hasNeededData = courseId && subSectionId && unitId && subSectionMetadata;
if (!hasNeededData) {
return;
}
const { items, savePosition } = subSectionMetadata;
// A sub-section can individually specify whether positions should be saved
if (!savePosition) {
return;
}
const unitIndex = items.findIndex(({ id }) => unitId === id);
// "position" is a 1-indexed value due to legacy compatibility concerns.
// TODO: Make this value 0-indexed
const newPosition = unitIndex + 1;
// TODO: update the local understanding of the position and
// don't make requests to update the position if they still match?
saveSubSectionPosition(courseId, subSectionId, newPosition);
}, [courseId, subSectionId, unitId, subSectionMetadata]);
}
export function useMissingUnitRedirect(metadata, loaded) {
const { courseId, subSectionId, unitId } = useContext(CourseStructureContext);
useEffect(() => {
if (loaded && metadata.itemId === subSectionId && !unitId) {
// Position comes from the server as a 1-indexed array index. Convert it to 0-indexed.
const position = metadata.position - 1;
const nextUnitId = metadata.items[position].id;
history.push(`/course/${courseId}/${subSectionId}/${nextUnitId}`);
}
}, [loaded, metadata, unitId]);
}

View File

@@ -1,11 +0,0 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learn.loading.content.lock': {
id: 'learn.loading.content.lock',
defaultMessage: 'Loading locked content messaging...',
description: 'Message shown when an interface about locked content is being loaded',
},
});
export default messages;

View File

@@ -0,0 +1,43 @@
import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
import { getLoginRedirectUrl } from '@edx/frontend-platform/auth';
import Alert from '../user-messages/Alert';
import messages from './messages';
function LogistrationAlert({ intl }) {
const signIn = (
<a href={`${getLoginRedirectUrl(global.location.href)}`}>
{intl.formatMessage(messages['learning.logistration.login'])}
</a>
);
// TODO: Pull this registration URL building out into a function, like the login one above.
// This is complicated by the fact that we don't have a REGISTER_URL env variable available.
const register = (
<a href={`${getConfig().LMS_BASE_URL}/register?next=${encodeURIComponent(global.location.href)}`}>
{intl.formatMessage(messages['learning.logistration.register'])}
</a>
);
return (
<Alert type="error">
<FormattedMessage
id="learning.logistration.alert"
description="Prompts the user to sign in or register to see course content."
defaultMessage="Please {signIn} or {register} to see course content."
values={{
signIn,
register,
}}
/>
</Alert>
);
}
LogistrationAlert.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(LogistrationAlert);

View File

@@ -0,0 +1,28 @@
/* eslint-disable import/prefer-default-export */
import { useContext, useState, useEffect } from 'react';
import { AppContext } from '@edx/frontend-platform/react';
import UserMessagesContext from '../user-messages/UserMessagesContext';
export function useLogistrationAlert() {
const { authenticatedUser } = useContext(AppContext);
const { add, remove } = useContext(UserMessagesContext);
const [alertId, setAlertId] = useState(null);
useEffect(() => {
if (authenticatedUser === null) {
setAlertId(add({
code: 'clientLogistrationAlert',
dismissible: false,
type: 'error',
topic: 'course',
}));
} else if (alertId !== null) {
remove(alertId);
setAlertId(null);
}
return () => {
if (alertId !== null) {
remove(alertId);
}
};
}, [authenticatedUser]);
}

View File

@@ -0,0 +1,2 @@
export { default } from './LogistrationAlert';
export { useLogistrationAlert } from './hooks';

View File

@@ -0,0 +1,16 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learning.logistration.login': {
id: 'learning.logistration.login',
defaultMessage: 'sign in',
description: 'Text in a link, prompting the user to log in. Used in "learning.logistration.alert"',
},
'learning.logistration.register': {
id: 'learning.logistration.register',
defaultMessage: 'register',
description: 'Text in a link, prompting the user to create an account. Used in "learning.logistration.alert"',
},
});
export default messages;

17
src/model-store/hooks.js Normal file
View File

@@ -0,0 +1,17 @@
import { useSelector, shallowEqual } from 'react-redux';
export function useModel(type, id) {
return useSelector(
state => (state.models[type] !== undefined ? state.models[type][id] : undefined),
shallowEqual,
);
}
export function useModels(type, ids) {
return useSelector(
state => ids.map(
id => (state.models[type] !== undefined ? state.models[type][id] : undefined),
),
shallowEqual,
);
}

16
src/model-store/index.js Normal file
View File

@@ -0,0 +1,16 @@
export {
reducer,
addModel,
addModels,
addModelsMap,
updateModel,
updateModels,
updateModelsMap,
removeModel,
removeModels,
} from './slice';
export {
useModel,
useModels,
} from './hooks';

77
src/model-store/slice.js Normal file
View File

@@ -0,0 +1,77 @@
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';
function add(state, modelType, model) {
const { id } = model;
if (state[modelType] === undefined) {
state[modelType] = {};
}
state[modelType][id] = model;
}
function update(state, modelType, model) {
if (state[modelType] === undefined) {
state[modelType] = {};
}
state[modelType][model.id] = { ...state[modelType][model.id], ...model };
}
function remove(state, modelType, id) {
if (state[modelType] === undefined) {
state[modelType] = {};
}
delete state[modelType][id];
}
const slice = createSlice({
name: 'models',
initialState: {},
reducers: {
addModel: (state, { payload }) => {
const { modelType, model } = payload;
add(state, modelType, model);
},
addModels: (state, { payload }) => {
const { modelType, models } = payload;
models.forEach(model => add(state, modelType, model));
},
addModelsMap: (state, { payload }) => {
const { modelType, modelsMap } = payload;
Object.values(modelsMap).forEach(model => add(state, modelType, model));
},
updateModel: (state, { payload }) => {
const { modelType, model } = payload;
update(state, modelType, model);
},
updateModels: (state, { payload }) => {
const { modelType, models } = payload;
models.forEach(model => update(state, modelType, model));
},
updateModelsMap: (state, { payload }) => {
const { modelType, modelsMap } = payload;
Object.values(modelsMap).forEach(model => update(state, modelType, model));
},
removeModel: (state, { payload }) => {
const { modelType, id } = payload;
remove(state, modelType, id);
},
removeModels: (state, { payload }) => {
const { modelType, ids } = payload;
ids.forEach(id => remove(state, modelType, id));
},
},
});
export const {
addModel,
addModels,
addModelsMap,
updateModel,
updateModels,
updateModelsMap,
removeModel,
removeModels,
} = slice.actions;
export const { reducer } = slice;

12
src/store.js Normal file
View File

@@ -0,0 +1,12 @@
import { configureStore } from '@reduxjs/toolkit';
import { reducer as coursewareReducer } from './data';
import { reducer as modelsReducer } from './model-store';
const store = configureStore({
reducer: {
models: modelsReducer,
courseware: coursewareReducer,
},
});
export default store;

72
src/tabs/Tabs.jsx Normal file
View File

@@ -0,0 +1,72 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { Dropdown } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import classNames from 'classnames';
import useIndexOfLastVisibleChild from './useIndexOfLastVisibleChild';
export default function Tabs({ children, className, ...attrs }) {
const [
indexOfLastVisibleChild,
containerElementRef,
invisibleStyle,
overflowElementRef,
] = useIndexOfLastVisibleChild();
const tabChildren = useMemo(() => {
const childrenArray = React.Children.toArray(children);
const indexOfOverflowStart = indexOfLastVisibleChild + 1;
// All tabs will be rendered. Those that would overflow are set to invisible.
const wrappedChildren = childrenArray.map((child, index) => React.cloneElement(child, {
style: index > indexOfLastVisibleChild ? invisibleStyle : null,
}));
// Build the list of items to put in the overflow menu
const overflowChildren = childrenArray.slice(indexOfOverflowStart)
.map(overflowChild => React.cloneElement(overflowChild, { className: 'dropdown-item' }));
// Insert the overflow menu at the cut off index (even if it will be hidden
// it so it can be part of measurements)
wrappedChildren.splice(indexOfOverflowStart, 0, (
<div
className="nav-item flex-shrink-0"
style={indexOfOverflowStart >= React.Children.count(children) ? invisibleStyle : null}
ref={overflowElementRef}
key="overflow"
>
<Dropdown>
<Dropdown.Button className="nav-link font-weight-normal">
<FormattedMessage
id="learn.course.tabs.navigation.overflow.menu"
description="The title of the overflow menu for course tabs"
defaultMessage="More..."
/>
</Dropdown.Button>
<Dropdown.Menu className="dropdown-menu-right">{overflowChildren}</Dropdown.Menu>
</Dropdown>
</div>
));
return wrappedChildren;
}, [children, indexOfLastVisibleChild]);
return (
<nav
{...attrs}
className={classNames('nav flex-nowrap', className)}
ref={containerElementRef}
>
{tabChildren}
</nav>
);
}
Tabs.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
};
Tabs.defaultProps = {
children: null,
className: undefined,
};

View File

@@ -0,0 +1,77 @@
import { useLayoutEffect, useRef, useState } from 'react';
import useWindowSize from './useWindowSize';
const invisibleStyle = {
position: 'absolute',
left: 0,
pointerEvents: 'none',
visibility: 'hidden',
};
/**
* This hook will find the index of the last child of a containing element
* that fits within its bounding rectangle. This is done by summing the widths
* of the children until they exceed the width of the container.
*
* The hook returns an array containing:
* [indexOfLastVisibleChild, containerElementRef, invisibleStyle, overflowElementRef]
*
* indexOfLastVisibleChild - the index of the last visible child
* containerElementRef - a ref to be added to the containing html node
* invisibleStyle - a set of styles to be applied to child of the containing node
* if it needs to be hidden. These styles remove the element visually, from
* screen readers, and from normal layout flow. But, importantly, these styles
* preserve the width of the element, so that future width calculations will
* still be accurate.
* overflowElementRef - a ref to be added to an html node inside the container
* that is likely to be used to contain a "More" type dropdown or other
* mechanism to reveal hidden children. The width of this element is always
* included when determining which children will fit or not. Usage of this ref
* is optional.
*/
export default function useIndexOfLastVisibleChild() {
const containerElementRef = useRef(null);
const overflowElementRef = useRef(null);
const containingRectRef = useRef({});
const [indexOfLastVisibleChild, setIndexOfLastVisibleChild] = useState(-1);
const windowSize = useWindowSize();
useLayoutEffect(() => {
const containingRect = containerElementRef.current.getBoundingClientRect();
// No-op if the width is unchanged.
// (Assumes tabs themselves don't change count or width).
if (!containingRect.width === containingRectRef.current.width) {
return;
}
// Update for future comparison
containingRectRef.current = containingRect;
// Get array of child nodes from NodeList form
const childNodesArr = Array.prototype.slice.call(containerElementRef.current.children);
const { nextIndexOfLastVisibleChild } = childNodesArr
// filter out the overflow element
.filter(childNode => childNode !== overflowElementRef.current)
// sum the widths to find the last visible element's index
.reduce((acc, childNode, index) => {
// use floor to prevent rounding errors
acc.sumWidth += Math.floor(childNode.getBoundingClientRect().width);
if (acc.sumWidth <= containingRect.width) {
acc.nextIndexOfLastVisibleChild = index;
}
return acc;
}, {
// Include the overflow element's width to begin with. Doing this means
// sometimes we'll show a dropdown with one item in it when it would fit,
// but allowing this case dramatically simplifies the calculations we need
// to do above.
sumWidth: overflowElementRef.current ? overflowElementRef.current.getBoundingClientRect().width : 0,
nextIndexOfLastVisibleChild: -1,
});
setIndexOfLastVisibleChild(nextIndexOfLastVisibleChild);
}, [windowSize, containerElementRef.current]);
return [indexOfLastVisibleChild, containerElementRef, invisibleStyle, overflowElementRef];
}

26
src/tabs/useWindowSize.js Normal file
View File

@@ -0,0 +1,26 @@
import { useState, useEffect } from 'react';
export default function useWindowSize() {
const isClient = typeof global === 'object';
const getSize = () => ({
width: isClient ? global.innerWidth : undefined,
height: isClient ? global.innerHeight : undefined,
});
const [windowSize, setWindowSize] = useState(getSize);
useEffect(() => {
if (!isClient) {
return false;
}
const handleResize = () => {
setWindowSize(getSize());
};
global.addEventListener('resize', handleResize);
return () => global.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}

View File

@@ -0,0 +1,69 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {
faExclamationTriangle, faInfoCircle, faCheckCircle, faMinusCircle, faTimes,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button } from '@edx/paragon';
function getAlertClass(type) {
if (type === 'error') {
return 'alert-warning';
}
if (type === 'danger') {
return 'alert-danger';
}
if (type === 'success') {
return 'alert-success';
}
return 'alert-info';
}
function getAlertIcon(type) {
if (type === 'error') {
return faExclamationTriangle;
}
if (type === 'danger') {
return faMinusCircle;
}
if (type === 'success') {
return faCheckCircle;
}
return faInfoCircle;
}
function Alert({
type, dismissible, children, onDismiss,
}) {
return (
<div className={classNames('alert', { 'alert-dismissible': dismissible }, getAlertClass(type))}>
<div className="d-flex align-items-start">
<div className="mr-2">
<FontAwesomeIcon icon={getAlertIcon(type)} />
</div>
<div role="alert" className="flex-grow-1">
{children}
</div>
</div>
{dismissible && <Button className="close" onClick={onDismiss}><FontAwesomeIcon size="sm" icon={faTimes} /></Button>}
</div>
);
}
Alert.propTypes = {
type: PropTypes.oneOf(['error', 'danger', 'info', 'success']).isRequired,
dismissible: PropTypes.bool,
children: PropTypes.node,
onDismiss: PropTypes.func,
};
Alert.defaultProps = {
dismissible: false,
children: undefined,
onDismiss: null,
};
export default Alert;

Some files were not shown because too many files have changed in this diff Show More